#define USE_NEW_AMOEBA_CODE FALSE
/* EXPERIMENTAL STUFF */
-#define USE_NEW_STUFF TRUE * 1
+#define USE_NEW_STUFF (TRUE * 1)
-#define USE_NEW_MOVE_STYLE TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_MOVE_DELAY TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_PUSH_DELAY TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_BLOCK_STYLE TRUE * USE_NEW_STUFF * 1 * 1
-#define USE_NEW_SP_SLIPPERY TRUE * USE_NEW_STUFF * 1
-#define USE_NEW_RANDOMIZE TRUE * USE_NEW_STUFF * 1
+#define USE_NEW_MOVE_STYLE (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_MOVE_DELAY (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_PUSH_DELAY (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_BLOCK_STYLE (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_SP_SLIPPERY (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_RANDOMIZE (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_PUSH_BUGFIX (TRUE * USE_NEW_STUFF * 1)
+
+#define USE_CAN_MOVE_NOT_MOVING (TRUE * USE_NEW_STUFF * 1)
+#define USE_PREVIOUS_MOVE_DIR (TRUE * USE_NEW_STUFF * 1)
-#define USE_PUSH_BUGFIX TRUE * USE_NEW_STUFF * 1
/* for DigField() */
#define DF_NO_PUSH 0
DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
}
-inline void DrawGameValue_Keys(struct PlayerInfo *player)
+inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS])
{
int i;
- for (i = 0; i < MAX_KEYS; i++)
- if (player->key[i])
+ /* currently only 4 of 8 possible keys are displayed */
+ for (i = 0; i < STD_NUM_KEYS; i++)
+ if (key[i])
DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
el2edimg(EL_KEY_1 + i));
}
}
}
-void DrawGameDoorValues()
+void DrawAllGameValues(int emeralds, int dynamite, int score, int time,
+ int key_bits)
{
+ int key[MAX_NUM_KEYS];
int i;
+ for (i = 0; i < MAX_NUM_KEYS; i++)
+ key[i] = key_bits & (1 << i);
+
DrawGameValue_Level(level_nr);
- for (i = 0; i < MAX_PLAYERS; i++)
- DrawGameValue_Keys(&stored_player[i]);
+ DrawGameValue_Emeralds(emeralds);
+ DrawGameValue_Dynamite(dynamite);
+ DrawGameValue_Score(score);
+ DrawGameValue_Time(time);
+
+ DrawGameValue_Keys(key);
+}
+
+void DrawGameDoorValues()
+{
+ int i;
+
+ if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+ {
+ DrawGameDoorValues_EM();
+
+ return;
+ }
+
+ DrawGameValue_Level(level_nr);
DrawGameValue_Emeralds(local_player->gems_still_needed);
DrawGameValue_Dynamite(local_player->inventory_size);
DrawGameValue_Score(local_player->score);
DrawGameValue_Time(TimeLeft);
-}
-void DrawGameDoorValues_EM(int emeralds, int dynamite, int score, int time)
-{
- DrawGameValue_Emeralds(emeralds);
- DrawGameValue_Dynamite(dynamite);
- DrawGameValue_Score(score);
- DrawGameValue_Time(time);
+ for (i = 0; i < MAX_PLAYERS; i++)
+ DrawGameValue_Keys(stored_player[i].key);
}
static void resolve_group_element(int group_element, int recursion_depth)
player->lights_still_needed = 0;
player->friends_still_needed = 0;
- for (j = 0; j < MAX_KEYS; j++)
+ for (j = 0; j < MAX_NUM_KEYS; j++)
player->key[j] = FALSE;
player->dynabomb_count = 0;
#endif
ZX = ZY = -1;
+ ExitX = ExitY = -1;
FrameCounter = 0;
TimeFrames = 0;
#endif
}
+void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y)
+{
+ /* this is used for non-R'n'D game engines to update certain engine values */
+
+ /* needed to determine if sounds are played within the visible screen area */
+ scroll_x = actual_scroll_x;
+ scroll_y = actual_scroll_y;
+}
+
void InitMovDir(int x, int y)
{
int i, element = Feld[x][y];
}
/* close exit door after last player */
- if ((Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
- Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN) && AllPlayersGone)
+ if (AllPlayersGone && ExitX >= 0 && ExitY >= 0 &&
+ (Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
+ Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN))
{
int element = Feld[ExitX][ExitY];
}
/* Hero disappears */
- DrawLevelField(ExitX, ExitY);
+ if (ExitX >= 0 && ExitY >= 0)
+ DrawLevelField(ExitX, ExitY);
+
BackToFront();
if (tape.playing)
return position;
}
+inline static int getElementMoveStepsize(int x, int y)
+{
+ int element = Feld[x][y];
+ int direction = MovDir[x][y];
+ int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+ int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
+ int horiz_move = (dx != 0);
+ int sign = (horiz_move ? dx : dy);
+ int step = sign * element_info[element].move_stepsize;
+
+ /* special values for move stepsize for spring and things on conveyor belt */
+ if (horiz_move)
+ {
+#if 0
+ if (element == EL_SPRING)
+ step = sign * MOVE_STEPSIZE_NORMAL * 2;
+ else if (CAN_FALL(element) && !CAN_MOVE(element) &&
+ y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+ step = sign * MOVE_STEPSIZE_NORMAL / 2;
+#else
+ if (CAN_FALL(element) &&
+ y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+ step = sign * MOVE_STEPSIZE_NORMAL / 2;
+ else if (element == EL_SPRING)
+ step = sign * MOVE_STEPSIZE_NORMAL * 2;
+#endif
+ }
+
+ return step;
+}
+
void InitPlayerGfxAnimation(struct PlayerInfo *player, int action, int dir)
{
if (player->GfxAction != action || player->GfxDir != dir)
if (!WasJustMoving[x][y] || direction != MovDir[x][y])
ResetGfxAnimation(x, y);
+#if USE_CAN_MOVE_NOT_MOVING
+
+ MovDir[x][y] = direction;
+ GfxDir[x][y] = direction;
+ GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
+ ACTION_FALLING : ACTION_MOVING);
+
+ if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */
+ {
+ if (Feld[newx][newy] == EL_EMPTY)
+ Feld[newx][newy] = EL_BLOCKED;
+
+ MovDir[newx][newy] = MovDir[x][y];
+ GfxFrame[newx][newy] = GfxFrame[x][y];
+ GfxRandom[newx][newy] = GfxRandom[x][y];
+ GfxAction[newx][newy] = GfxAction[x][y];
+ GfxDir[newx][newy] = GfxDir[x][y];
+ }
+
+#else
+
MovDir[newx][newy] = MovDir[x][y] = direction;
GfxDir[x][y] = direction;
GfxRandom[newx][newy] = GfxRandom[x][y];
GfxAction[newx][newy] = GfxAction[x][y];
GfxDir[newx][newy] = GfxDir[x][y];
+#endif
}
void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
return;
#endif
+#if 1
+ if (mode == EX_TYPE_NORMAL ||
+ mode == EX_TYPE_CENTER ||
+ mode == EX_TYPE_CROSS)
+ PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
+#else
if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER)
PlayLevelSoundAction(ex, ey, ACTION_EXPLODING);
+#endif
/* remove things displayed in background while burning dynamite */
if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey]))
Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
DrawLevelField(x, y);
+
+ /* uncrumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
}
else if (element == EL_INVISIBLE_STEELWALL_ACTIVE ||
element == EL_INVISIBLE_WALL_ACTIVE ||
Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
DrawLevelField(x, y);
+
+ /* re-crumble neighbour fields, if needed */
+ if (element == EL_INVISIBLE_SAND)
+ DrawLevelFieldCrumbledSandNeighbours(x, y);
}
}
}
Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
}
-inline static int getElementMoveStepsize(int x, int y)
-{
- int element = Feld[x][y];
- int direction = MovDir[x][y];
- int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
- int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
- int horiz_move = (dx != 0);
- int sign = (horiz_move ? dx : dy);
- int step = sign * element_info[element].move_stepsize;
-
- /* special values for move stepsize for spring and things on conveyor belt */
- if (horiz_move)
- {
-#if 0
- if (element == EL_SPRING)
- step = sign * MOVE_STEPSIZE_NORMAL * 2;
- else if (CAN_FALL(element) && !CAN_MOVE(element) &&
- y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
- step = sign * MOVE_STEPSIZE_NORMAL / 2;
-#else
- if (CAN_FALL(element) &&
- y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
- step = sign * MOVE_STEPSIZE_NORMAL / 2;
- else if (element == EL_SPRING)
- step = sign * MOVE_STEPSIZE_NORMAL * 2;
-#endif
- }
-
- return step;
-}
-
void Impact(int x, int y)
{
boolean lastline = (y == lev_fieldy-1);
boolean can_turn_right =
CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, right_x,right_y);
+#if USE_CAN_MOVE_NOT_MOVING
+ if (element_info[element].move_stepsize == 0) /* not moving */
+ return;
+#endif
+
if (move_pattern == MV_TURNING_LEFT)
MovDir[x][y] = left_dir;
else if (move_pattern == MV_TURNING_RIGHT)
boolean first_horiz = RND(2);
int new_move_dir = MovDir[x][y];
+#if USE_CAN_MOVE_NOT_MOVING
+ if (element_info[element].move_stepsize == 0) /* not moving */
+ {
+ first_horiz = (ABS(attr_x - x) >= ABS(attr_y - y));
+ MovDir[x][y] &= (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
+
+ return;
+ }
+#endif
+
MovDir[x][y] =
new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
Moving2Blocked(x, y, &newx, &newy);
#endif
Store[x][y] = EL_EMPTY;
- MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
+ MovPos[x][y] = 0;
+ MovDir[x][y] = 0;
+ MovDelay[x][y] = 0;
MovDelay[newx][newy] = 0;
if (CAN_CHANGE(element))
Pushed[x][y] = Pushed[newx][newy] = FALSE;
+#if 0
+ /* do this after checking for left-behind element */
ResetGfxAnimation(x, y); /* reset animation values for old field */
+#endif
#if 1
/* some elements can leave other elements behind after moving */
int move_leave_element = ei->move_leave_element;
Feld[x][y] = move_leave_element;
+
+#if USE_PREVIOUS_MOVE_DIR
+ if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
+ MovDir[x][y] = direction;
+#endif
+
InitField(x, y, FALSE);
if (GFX_CRUMBLED(Feld[x][y]))
ei->can_leave_element = FALSE;
#endif
+#if 1
+ /* do this after checking for left-behind element */
+ ResetGfxAnimation(x, y); /* reset animation values for old field */
+#endif
+
#if 0
/* 2.1.1 (does not work correctly for spring) */
if (!CAN_MOVE(element))
return (IN_LEV_FIELD(jx, jy + 1) &&
(IS_FREE(jx, jy + 1) ||
+#if USE_NEW_BLOCK_STYLE
+ Feld[jx][jy + 1] == EL_PLAYER_IS_LEAVING ||
+#endif
(Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) &&
!IS_WALKABLE_INSIDE(Feld[jx][jy]));
/* check if DigField() has caused relocation of the player */
if (player->jx != jx || player->jy != jy)
- return MF_NO_ACTION;
+ return MF_NO_ACTION; /* <-- !!! CHECK THIS [-> MF_ACTION ?] !!! */
StorePlayer[jx][jy] = 0;
player->last_jx = jx;
return MF_NO_ACTION; /* player cannot walk here due to gravity */
#endif
- if (IS_GATE(element))
+ if (IS_RND_GATE(element))
{
- if (!player->key[element - EL_GATE_1])
+ if (!player->key[RND_GATE_NR(element)])
return MF_NO_ACTION;
}
- else if (IS_GATE_GRAY(element))
+ else if (IS_RND_GATE_GRAY(element))
{
- if (!player->key[element - EL_GATE_1_GRAY])
+ if (!player->key[RND_GATE_GRAY_NR(element)])
return MF_NO_ACTION;
}
else if (element == EL_EXIT_OPEN ||
if (IS_EM_GATE(element))
{
- if (!player->key[element - EL_EM_GATE_1])
+ if (!player->key[EM_GATE_NR(element)])
return MF_NO_ACTION;
}
else if (IS_EM_GATE_GRAY(element))
{
- if (!player->key[element - EL_EM_GATE_1_GRAY])
+ if (!player->key[EM_GATE_GRAY_NR(element)])
return MF_NO_ACTION;
}
else if (IS_SP_PORT(element))
{
player->dynabomb_xl = TRUE;
}
- else if ((element >= EL_KEY_1 && element <= EL_KEY_4) ||
- (element >= EL_EM_KEY_1 && element <= EL_EM_KEY_4))
+ else if (IS_KEY(element))
{
- int key_nr = (element >= EL_KEY_1 && element <= EL_KEY_4 ?
- element - EL_KEY_1 : element - EL_EM_KEY_1);
+ player->key[KEY_NR(element)] = TRUE;
- player->key[key_nr] = TRUE;
-
- DrawGameValue_Keys(player);
+ DrawGameValue_Keys(player->key);
redraw_mask |= REDRAW_DOOR_1;
}
PlayMusic(MAP_NOCONF_MUSIC(level_nr)); /* from music dir */
}
-void PlayLevelSound_EM(int x, int y, int element, int action)
+void PlayLevelSound_EM(int x, int y, int element_em, int sample)
{
- PlayLevelSoundElementAction(x, y, element, action);
+ int element = (element_em > -1 ? map_element_EM_to_RND(element_em) : 0);
+
+#if 0
+ if (sample == SAMPLE_bug)
+ printf("::: PlayLevelSound_EM: %d, %d: %d\n", x, y, sample);
+#endif
+
+ switch (sample)
+ {
+ case SAMPLE_blank:
+ PlayLevelSoundElementAction(x, y, element, ACTION_WALKING);
+ break;
+
+ case SAMPLE_roll:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
+ break;
+
+ case SAMPLE_stone:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_nut:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_crack:
+ PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
+ break;
+
+ case SAMPLE_bug:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_tank:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_android_clone:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+ break;
+
+ case SAMPLE_android_move:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_spring:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_slurp:
+ PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
+ break;
+
+ case SAMPLE_eater:
+ PlayLevelSoundElementAction(x, y, element, ACTION_WAITING);
+ break;
+
+ case SAMPLE_eater_eat:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
+ break;
+
+ case SAMPLE_alien:
+ PlayLevelSoundElementAction(x, y, element, ACTION_MOVING);
+ break;
+
+ case SAMPLE_collect:
+ PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
+ break;
+
+ case SAMPLE_diamond:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_squash:
+ /* !!! CHECK THIS !!! */
+#if 1
+ PlayLevelSoundElementAction(x, y, element, ACTION_BREAKING);
+#else
+ PlayLevelSoundElementAction(x, y, element, ACTION_SMASHED_BY_ROCK);
+#endif
+ break;
+
+ case SAMPLE_wonderfall:
+ PlayLevelSoundElementAction(x, y, element, ACTION_FILLING);
+ break;
+
+ case SAMPLE_drip:
+ PlayLevelSoundElementAction(x, y, element, ACTION_IMPACT);
+ break;
+
+ case SAMPLE_push:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PUSHING);
+ break;
+
+ case SAMPLE_dirt:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
+ break;
+
+ case SAMPLE_acid:
+ PlayLevelSoundElementAction(x, y, element, ACTION_SPLASHING);
+ break;
+
+ case SAMPLE_ball:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+ break;
+
+ case SAMPLE_grow:
+ PlayLevelSoundElementAction(x, y, element, ACTION_GROWING);
+ break;
+
+ case SAMPLE_wonder:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+ break;
+
+ case SAMPLE_door:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
+ break;
+
+ case SAMPLE_exit_open:
+ PlayLevelSoundElementAction(x, y, element, ACTION_OPENING);
+ break;
+
+ case SAMPLE_exit_leave:
+ PlayLevelSoundElementAction(x, y, element, ACTION_PASSING);
+ break;
+
+ case SAMPLE_dynamite:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DROPPING);
+ break;
+
+ case SAMPLE_tick:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+ break;
+
+ case SAMPLE_press:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVATING);
+ break;
+
+ case SAMPLE_wheel:
+ PlayLevelSoundElementAction(x, y, element, ACTION_ACTIVE);
+ break;
+
+ case SAMPLE_boom:
+ PlayLevelSoundElementAction(x, y, element, ACTION_EXPLODING);
+ break;
+
+ case SAMPLE_die:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DYING);
+ break;
+
+ case SAMPLE_time:
+ PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
+ break;
+
+ default:
+ PlayLevelSoundElementAction(x, y, element, ACTION_DEFAULT);
+ break;
+ }
}
void RaiseScore(int value)
case EL_KEY_2:
case EL_KEY_3:
case EL_KEY_4:
+ case EL_EM_KEY_1:
+ case EL_EM_KEY_2:
+ case EL_EM_KEY_3:
+ case EL_EM_KEY_4:
+ case EL_EMC_KEY_5:
+ case EL_EMC_KEY_6:
+ case EL_EMC_KEY_7:
+ case EL_EMC_KEY_8:
RaiseScore(level.score[SC_KEY]);
break;
default: