X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=a78e341f983a3e429518c8e8bff1647f0a96983b;hb=05be30e0b291803b5d1947ad04ff4c3be546ed4a;hp=2d0ae75cb36617ecb1bbd2822780fff680478a7f;hpb=476723662969279e665b95a3d57efd85e747a80e;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 2d0ae75c..a78e341f 100644 --- a/src/game.c +++ b/src/game.c @@ -25,9 +25,13 @@ #define USE_NEW_AMOEBA_CODE FALSE /* EXPERIMENTAL STUFF */ -#define USE_NEW_STUFF (TRUE * 1) +#define USE_NEW_STUFF ( * 1) -#define USE_NEW_SP_SLIPPERY (TRUE * USE_NEW_STUFF * 1) +#define USE_NEW_SP_SLIPPERY (USE_NEW_STUFF * 1) +#define USE_NEW_COLLECT_COUNT (USE_NEW_STUFF * 1) +#define USE_NEW_PLAYER_ANIM (USE_NEW_STUFF * 1) +#define USE_NEW_ALL_SLIPPERY (USE_NEW_STUFF * 1) +#define USE_NEW_PLAYER_SPEED (USE_NEW_STUFF * 1) /* for DigField() */ @@ -88,16 +92,25 @@ #define INITIAL_MOVE_DELAY_ON 0 /* values for player movement speed (which is in fact a delay value) */ +#define MOVE_DELAY_MIN_SPEED 32 #define MOVE_DELAY_NORMAL_SPEED 8 #define MOVE_DELAY_HIGH_SPEED 4 +#define MOVE_DELAY_MAX_SPEED 1 +#if 0 #define DOUBLE_MOVE_DELAY(x) (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x)) #define HALVE_MOVE_DELAY(x) (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x)) +#else +#define DOUBLE_MOVE_DELAY(x) (x = (x < MOVE_DELAY_MIN_SPEED ? x * 2 : x)) +#define HALVE_MOVE_DELAY(x) (x = (x > MOVE_DELAY_MAX_SPEED ? x / 2 : x)) +#endif #define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY((p)->move_delay_value)) #define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) /* values for other actions */ #define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED) +#define MOVE_STEPSIZE_MIN (1) +#define MOVE_STEPSIZE_MAX (TILEX) #define GET_DX_FROM_DIR(d) ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0) #define GET_DY_FROM_DIR(d) ((d) == MV_UP ? -1 : (d) == MV_DOWN ? 1 : 0) @@ -903,6 +916,10 @@ static void InitField(int x, int y, boolean init_game) } break; } + +#if USE_NEW_COLLECT_COUNT + Count[x][y] = element_info[Feld[x][y]].collect_count_initial; +#endif } static inline void InitField_WithBug1(int x, int y, boolean init_game) @@ -1644,7 +1661,9 @@ void InitGame() MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; - Count[x][y] = element_info[Feld[x][y]].collect_count_initial; +#if USE_NEW_COLLECT_COUNT + Count[x][y] = 0; /* initialized in InitField() */ +#endif Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0; AmoebaNr[x][y] = 0; WasJustMoving[x][y] = 0; @@ -1692,6 +1711,26 @@ void InitGame() emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); +#if USE_NEW_ALL_SLIPPERY + /* initialize type of slippery elements */ + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + { + if (!IS_CUSTOM_ELEMENT(i)) + { + /* default: elements slip down either to the left or right randomly */ + element_info[i].slippery_type = SLIPPERY_ANY_RANDOM; + + /* SP style elements prefer to slip down on the left side */ + if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i)) + element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; + + /* BD style elements prefer to slip down on the left side */ + if (game.emulation == EMU_BOULDERDASH) + element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT; + } + } +#endif + /* initialize explosion and ignition delay */ for (i = 0; i < MAX_NUM_ELEMENTS; i++) { @@ -2488,7 +2527,9 @@ void InitMovingField(int x, int y, int direction) MovDir[newx][newy] = MovDir[x][y]; +#if USE_NEW_COLLECT_COUNT Count[newx][newy] = Count[x][y]; +#endif GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; @@ -2571,7 +2612,9 @@ static void RemoveField(int x, int y) MovDir[x][y] = 0; MovDelay[x][y] = 0; +#if USE_NEW_COLLECT_COUNT Count[x][y] = 0; +#endif AmoebaNr[x][y] = 0; ChangeDelay[x][y] = 0; @@ -3158,7 +3201,10 @@ void Explode(int ex, int ey, int phase, int mode) GfxDir[x][y] = MV_NO_MOVING; ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; + +#if USE_NEW_COLLECT_COUNT Count[x][y] = 0; +#endif InitField_WithBug2(x, y, FALSE); @@ -4743,11 +4789,26 @@ void StartMoving(int x, int y) Feld[x + 1][y + 1] == EL_ACID)); boolean can_fall_any = (can_fall_left || can_fall_right); boolean can_fall_both = (can_fall_left && can_fall_right); + int slippery_type = element_info[Feld[x][y + 1]].slippery_type; - if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1])) +#if USE_NEW_ALL_SLIPPERY + if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM) { - int slippery_type = element_info[Feld[x][y + 1]].slippery_type; + if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both) + can_fall_right = FALSE; + else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both) + can_fall_left = FALSE; + else if (slippery_type == SLIPPERY_ONLY_LEFT) + can_fall_right = FALSE; + else if (slippery_type == SLIPPERY_ONLY_RIGHT) + can_fall_left = FALSE; + can_fall_any = (can_fall_left || can_fall_right); + can_fall_both = FALSE; + } +#else + if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1])) + { if (slippery_type == SLIPPERY_ONLY_LEFT) can_fall_right = FALSE; else if (slippery_type == SLIPPERY_ONLY_RIGHT) @@ -4760,7 +4821,10 @@ void StartMoving(int x, int y) can_fall_any = (can_fall_left || can_fall_right); can_fall_both = (can_fall_left && can_fall_right); } +#endif +#if USE_NEW_ALL_SLIPPERY +#else #if USE_NEW_SP_SLIPPERY /* !!! better use the same properties as for custom elements here !!! */ else if (game.engine_version >= VERSION_IDENT(3,1,1,0) && @@ -4770,7 +4834,19 @@ void StartMoving(int x, int y) can_fall_both = FALSE; } #endif +#endif +#if USE_NEW_ALL_SLIPPERY + if (can_fall_both) + { + if (element == EL_BD_ROCK || element == EL_BD_DIAMOND) + can_fall_right = FALSE; /* slip down on left side */ + else + can_fall_left = !(can_fall_right = RND(2)); + + can_fall_both = FALSE; + } +#else if (can_fall_both) { if (game.emulation == EMU_BOULDERDASH || @@ -4781,6 +4857,7 @@ void StartMoving(int x, int y) can_fall_both = FALSE; } +#endif if (can_fall_any) { @@ -5298,11 +5375,6 @@ void StartMoving(int x, int y) ContinueMoving(x, y); } -/* (emacs is confused here for some reason; this makes it happy again ;-) ) */ -void dummy() -{ -} - void ContinueMoving(int x, int y) { int element = Feld[x][y]; @@ -5367,6 +5439,10 @@ void ContinueMoving(int x, int y) if (!game.magic_wall_active) Feld[x][y] = EL_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; + +#if USE_NEW_COLLECT_COUNT + InitField(newx, newy, FALSE); +#endif } else if (element == EL_BD_MAGIC_WALL_FILLING) { @@ -5381,6 +5457,10 @@ void ContinueMoving(int x, int y) if (!game.magic_wall_active) Feld[x][y] = EL_BD_MAGIC_WALL_DEAD; element = Feld[newx][newy] = Store[x][y]; + +#if USE_NEW_COLLECT_COUNT + InitField(newx, newy, FALSE); +#endif } else if (element == EL_AMOEBA_DROPPING) { @@ -5403,8 +5483,6 @@ void ContinueMoving(int x, int y) MovDir[x][y] = 0; MovDelay[x][y] = 0; - Count[x][y] = 0; - MovDelay[newx][newy] = 0; if (CAN_CHANGE(element)) @@ -5414,6 +5492,10 @@ void ContinueMoving(int x, int y) ChangePage[newx][newy] = ChangePage[x][y]; Changed[newx][newy] = Changed[x][y]; ChangeEvent[newx][newy] = ChangeEvent[x][y]; + +#if USE_NEW_COLLECT_COUNT + Count[newx][newy] = Count[x][y]; +#endif } ChangeDelay[x][y] = 0; @@ -5421,6 +5503,10 @@ void ContinueMoving(int x, int y) Changed[x][y] = FALSE; ChangeEvent[x][y] = -1; +#if USE_NEW_COLLECT_COUNT + Count[x][y] = 0; +#endif + /* copy animation control values to new field */ GfxFrame[newx][newy] = GfxFrame[x][y]; GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */ @@ -6413,8 +6499,8 @@ static int getSpecialActionElement(int element, int number, int base_element) EL_EMPTY); } -static int getModifiedActionNumber(int value_old, int value_min, int value_max, - int operator, int operand) +static int getModifiedActionNumber(int value_old, int operator, int operand, + int value_min, int value_max) { int value_new = (operator == CA_MODE_ADD ? value_old + operand : operator == CA_MODE_SUBTRACT ? value_old - operand : @@ -6448,15 +6534,60 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element : EL_EMPTY); + int action_arg_number_min = + (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MIN : + CA_ARG_MIN); + + int action_arg_number_max = + (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MAX : + action_type == CA_SET_GEMS ? 999 : + action_type == CA_SET_TIME ? 9999 : + action_type == CA_SET_SCORE ? 99999 : + action_type == CA_SET_CE_SCORE ? 9999 : + action_type == CA_SET_CE_COUNT ? 9999 : + CA_ARG_MAX); + + int action_arg_number_reset = + (action_type == CA_SET_PLAYER_SPEED ? TILEX/game.initial_move_delay_value : + action_type == CA_SET_GEMS ? level.gems_needed : + action_type == CA_SET_TIME ? level.time : + action_type == CA_SET_SCORE ? 0 : + action_type == CA_SET_CE_SCORE ? 0 : + action_type == CA_SET_CE_COUNT ? ei->collect_count_initial : + 0); + + int action_arg_number_normal = + (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_NORMAL : + action_arg_number_reset); + int action_arg_number = (action_arg <= CA_ARG_MAX ? action_arg : - action_arg == CA_ARG_NUMBER_MIN ? CA_ARG_MIN : - action_arg == CA_ARG_NUMBER_MAX ? CA_ARG_MAX : + action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min : + action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max : + action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset : + action_arg == CA_ARG_NUMBER_NORMAL ? action_arg_number_normal : action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score : +#if USE_NEW_COLLECT_COUNT action_arg == CA_ARG_NUMBER_CE_COUNT ? Count[x][y] : +#else + action_arg == CA_ARG_NUMBER_CE_COUNT ? ei->collect_count_initial : +#endif action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CHANGE_DELAY(change) : -1); + int action_arg_number_old = + (action_type == CA_SET_GEMS ? local_player->gems_still_needed : + action_type == CA_SET_TIME ? TimeLeft : + action_type == CA_SET_SCORE ? local_player->score : + action_type == CA_SET_CE_SCORE ? ei->collect_score : + action_type == CA_SET_CE_COUNT ? Count[x][y] : + 0); + + int action_arg_number_new = + getModifiedActionNumber(action_arg_number_old, + action_mode, action_arg_number, + action_arg_number_min, action_arg_number_max); + /* (for explicit player choice, set invalid value to "no player") */ int action_arg_player_bits = (action_arg == CA_ARG_PLAYER_ANY ? action_arg - CA_ARG_PLAYER : @@ -6573,38 +6704,32 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { if (trigger_player_bits & (1 << i)) { - if (action_arg == CA_ARG_NUMBER_RESET) - stored_player[i].move_delay_value = game.initial_move_delay_value; - else if (action_arg == CA_ARG_NUMBER_NORMAL) - stored_player[i].move_delay_value = MOVE_DELAY_NORMAL_SPEED; - else if (action_arg == CA_ARG_NUMBER_MIN) - stored_player[i].move_delay_value = 16; - else if (action_arg == CA_ARG_NUMBER_MAX) - stored_player[i].move_delay_value = MOVE_DELAY_HIGH_SPEED; - else + int move_stepsize = TILEX / stored_player[i].move_delay_value; + + if (action_mode == CA_MODE_ADD || action_mode == CA_MODE_SUBTRACT) { -#if 0 - if (action_mode == CA_MODE_ADD) - { - action_mode = CA_MODE_DIVIDE; - action_arg_number = (1 << action_arg_number); - } - else if (action_mode == CA_MODE_SUBTRACT) - { - action_mode = CA_MODE_MULTIPLY; - action_arg_number = (1 << action_arg_number); - } + /* translate "+" and "-" to "*" and "/" with powers of two */ + action_arg_number = 1 << action_arg_number; + action_mode = (action_mode == CA_MODE_ADD ? CA_MODE_MULTIPLY : + CA_MODE_DIVIDE); + } + + move_stepsize = + getModifiedActionNumber(move_stepsize, + action_mode, + action_arg_number, + action_arg_number_min, + action_arg_number_max); + + /* make sure that value is power of 2 */ + move_stepsize = (1 << log_2(move_stepsize)); - int mode = (action_mode == CA_MODE_MULTIPLY ? CA_MODE_DIVIDE : - action_mode == CA_MODE_DIVIDE ? CA_MODE_MULTIPLY : - action_mode); + stored_player[i].move_delay_value = TILEX / move_stepsize; - stored_player[i].move_delay_value = - getModifiedActionNumber(stored_player[i].move_delay_value, - 1, 16, - action_mode, action_arg_number); +#if 0 + printf("::: move_delay_value == %d [%d]\n", + stored_player[i].move_delay_value, action_arg_number); #endif - } } } @@ -6613,9 +6738,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_GEMS: { - local_player->gems_still_needed = - getModifiedActionNumber(local_player->gems_still_needed, 0, 999, - action_mode, action_arg_number); + local_player->gems_still_needed = action_arg_number_new; DrawGameValue_Emeralds(local_player->gems_still_needed); @@ -6626,10 +6749,13 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { if (level.time > 0) /* only modify limited time value */ { - TimeLeft = getModifiedActionNumber(TimeLeft, 0, 9999, - action_mode, action_arg_number); + TimeLeft = action_arg_number_new; DrawGameValue_Time(TimeLeft); + + if (!TimeLeft && setup.time_limit) + for (i = 0; i < MAX_PLAYERS; i++) + KillHero(&stored_player[i]); } break; @@ -6637,9 +6763,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_SCORE: { - local_player->score = - getModifiedActionNumber(local_player->score, 0, 99999, - action_mode, action_arg_number); + local_player->score = action_arg_number_new; DrawGameValue_Score(local_player->score); @@ -6648,29 +6772,32 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_CE_SCORE: { - ei->collect_score = - getModifiedActionNumber(ei->collect_score, 0, 9999, - action_mode, action_arg_number); + ei->collect_score = action_arg_number_new; + break; } case CA_SET_CE_COUNT: { +#if USE_NEW_COLLECT_COUNT int count_last = Count[x][y]; - Count[x][y] = getModifiedActionNumber(Count[x][y], 0, 9999, - action_mode, action_arg_number); + Count[x][y] = action_arg_number_new; +#if 0 printf("::: Count == %d\n", Count[x][y]); +#endif if (Count[x][y] == 0 && count_last > 0) { - +#if 0 printf("::: CE_COUNT_AT_ZERO\n"); +#endif CheckElementChange(x, y, element, EL_UNDEFINED, CE_COUNT_AT_ZERO); CheckTriggeredElementChange(element, CE_COUNT_AT_ZERO_OF_X); } +#endif break; } @@ -7063,15 +7190,18 @@ static boolean CheckTriggeredElementChangeExt(int trigger_element, ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; ChangeElement(x, y, p); - - change_done = TRUE; - change_done_any = TRUE; } if (change->has_action) ExecuteCustomElementAction(x, y, element, p); } } + + if (change->can_change) + { + change_done = TRUE; + change_done_any = TRUE; + } } } } @@ -7373,12 +7503,25 @@ void AdvanceFrameAndPlayerCounters(int player_nr) for (i = 0; i < MAX_PLAYERS; i++) { boolean advance_player_counters = (player_nr == -1 || player_nr == i); - int move_frames = - MOVE_DELAY_NORMAL_SPEED / stored_player[i].move_delay_value; + int move_delay_value = stored_player[i].move_delay_value; + int move_frames = MOVE_DELAY_NORMAL_SPEED / move_delay_value; if (!advance_player_counters) /* not all players may be affected */ continue; +#if USE_NEW_PLAYER_ANIM + if (move_frames == 0) /* less than one move per game frame */ + { + int stepsize = TILEX / move_delay_value; + int delay = move_delay_value / MOVE_DELAY_NORMAL_SPEED; + int count = (stored_player[i].is_moving ? + ABS(stored_player[i].MovPos) / stepsize : FrameCounter); + + if (count % delay == 0) + move_frames = 1; + } +#endif + stored_player[i].Frame += move_frames; if (stored_player[i].MovPos != 0) @@ -7632,11 +7775,20 @@ void GameActions() if (IS_CHANGING(x, y) && (game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y])) { + int page = element_info[element].event_page_nr[CE_DELAY]; #if 0 - ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : - element_info[element].event_page_nr[CE_DELAY]); + ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page); #else - ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]); + +#if 0 + printf("::: ChangeDelay == %d\n", ChangeDelay[x][y]); +#endif + + if (CAN_CHANGE(element)) + ChangeElement(x, y, page); + + if (HAS_ACTION(element) && ChangeDelay[x][y] == 0) + ExecuteCustomElementAction(x, y, element, page); #endif element = Feld[x][y]; @@ -8350,9 +8502,17 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) int last_jx = player->last_jx, last_jy = player->last_jy; int move_stepsize = TILEX / player->move_delay_value; - if (!player->active || !player->MovPos) +#if USE_NEW_PLAYER_SPEED + if (!player->active) return; + if (player->MovPos == 0 && mode == SCROLL_GO_ON) /* player not moving */ + return; +#else + if (!player->active || player->MovPos == 0) + return; +#endif + if (mode == SCROLL_INIT) { player->actual_frame_counter = FrameCounter; @@ -8381,20 +8541,47 @@ void ScrollPlayer(struct PlayerInfo *player, int mode) MovDelay[last_jx][last_jy] = last_field_block_delay + 1; } +#if USE_NEW_PLAYER_SPEED + if (player->MovPos != 0) /* player has not yet reached destination */ + return; +#else return; +#endif } else if (!FrameReached(&player->actual_frame_counter, 1)) return; +#if 0 + printf("::: player->MovPos: %d -> %d\n", + player->MovPos, + player->MovPos + (player->MovPos > 0 ? -1 : 1) * move_stepsize); +#endif + +#if USE_NEW_PLAYER_SPEED + if (player->MovPos != 0) + { + player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; + player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); + + /* before DrawPlayer() to draw correct player graphic for this case */ + if (player->MovPos == 0) + CheckGravityMovement(player); + } +#else player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); /* before DrawPlayer() to draw correct player graphic for this case */ if (player->MovPos == 0) CheckGravityMovement(player); +#endif if (player->MovPos == 0) /* player reached destination field */ { +#if 0 + printf("::: player reached destination field\n"); +#endif + if (player->move_delay_reset_counter > 0) { player->move_delay_reset_counter--; @@ -9144,7 +9331,20 @@ int DigField(struct PlayerInfo *player, return MF_NO_ACTION; /* field has no opening in this direction */ element = Feld[x][y]; +#if USE_NEW_COLLECT_COUNT collect_count = Count[x][y]; +#else + collect_count = element_info[element].collect_count_initial; +#endif + +#if 0 + if (element != EL_BLOCKED && + Count[x][y] != element_info[element].collect_count_initial) + printf("::: %d: %d != %d\n", + element, + Count[x][y], + element_info[element].collect_count_initial); +#endif if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */ return MF_NO_ACTION;