X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=d2e58439281ec3d5b4b6386f6af5baba3b4f8673;hb=37a06df577bbfd00f4b361f92cacb0d97036ba93;hp=1f4d8a01a378252d1d5e1b75f6d4edd756cc2668;hpb=61e7a86bf1dad5f041802e539950185eb921bd68;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 1f4d8a01..d2e58439 100644 --- a/src/game.c +++ b/src/game.c @@ -237,6 +237,8 @@ /* forward declaration for internal use */ +static void CreateField(int, int, int); + static void SetPlayerWaiting(struct PlayerInfo *, boolean); static void AdvanceFrameAndPlayerCounters(int); @@ -261,7 +263,7 @@ static void TestIfElementHitsCustomElement(int, int, int); static void TestIfElementSmashesCustomElement(int, int, int); #endif -static void ChangeElement(int, int, int); +static void HandleElementChange(int, int, int); static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int); #define CheckTriggeredElementChange(x, y, e, ev) \ @@ -302,19 +304,22 @@ static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; /* ------------------------------------------------------------------------- */ /* forward declaration for changer functions */ -static void InitBuggyBase(int x, int y); -static void WarnBuggyBase(int x, int y); +static void InitBuggyBase(int, int); +static void WarnBuggyBase(int, int); + +static void InitTrap(int, int); +static void ActivateTrap(int, int); +static void ChangeActiveTrap(int, int); -static void InitTrap(int x, int y); -static void ActivateTrap(int x, int y); -static void ChangeActiveTrap(int x, int y); +static void InitRobotWheel(int, int); +static void RunRobotWheel(int, int); +static void StopRobotWheel(int, int); -static void InitRobotWheel(int x, int y); -static void RunRobotWheel(int x, int y); -static void StopRobotWheel(int x, int y); +static void InitTimegateWheel(int, int); +static void RunTimegateWheel(int, int); -static void InitTimegateWheel(int x, int y); -static void RunTimegateWheel(int x, int y); +static void InitMagicBallDelay(int, int); +static void ActivateMagicBall(int, int); struct ChangingElementInfo { @@ -481,6 +486,14 @@ static struct ChangingElementInfo change_delay_list[] = RunTimegateWheel, NULL }, + { + EL_EMC_MAGIC_BALL_ACTIVE, + EL_EMC_MAGIC_BALL_ACTIVE, + 0, + InitMagicBallDelay, + NULL, + ActivateMagicBall + }, { EL_UNDEFINED, @@ -641,6 +654,40 @@ static void InitPlayfieldScanMode(int mode) InitPlayfieldScanModeVars(); } +static int get_move_delay_from_stepsize(int move_stepsize) +{ + move_stepsize = + MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX); + + /* make sure that stepsize value is always a power of 2 */ + move_stepsize = (1 << log_2(move_stepsize)); + + return TILEX / move_stepsize; +} + +static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize, + boolean init_game) +{ + int move_delay = get_move_delay_from_stepsize(move_stepsize); + boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE); + + /* do no immediately change move delay -- the player might just be moving */ + player->move_delay_value_next = move_delay; + + /* information if player can move must be set separately */ + player->cannot_move = cannot_move; + + if (init_game) + { + player->move_delay = game.initial_move_delay; + player->move_delay_value = game.initial_move_delay_value; + + player->move_delay_value_next = -1; + + player->move_delay_reset_counter = 0; + } +} + void GetPlayerConfig() { if (!audio.sound_available) @@ -935,6 +982,16 @@ static void InitField(int x, int y, boolean init_game) game.light_time_left = level.time_light * FRAMES_PER_SECOND; break; + case EL_EMC_MAGIC_BALL: + if (game.ball_state) + Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE; + break; + + case EL_EMC_MAGIC_BALL_SWITCH: + if (game.ball_state) + Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE; + break; + default: #if 1 if (IS_CUSTOM_ELEMENT(element)) @@ -1318,9 +1375,15 @@ static void InitGameEngine() /* ---------- initialize player's initial move delay --------------------- */ +#if 1 + /* dynamically adjust player properties according to level information */ + game.initial_move_delay_value = + get_move_delay_from_stepsize(level.initial_player_stepsize); +#else /* dynamically adjust player properties according to level information */ game.initial_move_delay_value = (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED); +#endif /* dynamically adjust player properties according to game engine version */ game.initial_move_delay = (game.engine_version <= VERSION_IDENT(2,0,1,0) ? @@ -1701,8 +1764,6 @@ void InitGame() player->is_bored = FALSE; player->is_sleeping = FALSE; - player->cannot_move = FALSE; - player->frame_counter_bored = -1; player->frame_counter_sleeping = -1; @@ -1730,6 +1791,9 @@ void InitGame() player->show_envelope = 0; +#if 1 + SetPlayerMoveSpeed(player, level.initial_player_stepsize, TRUE); +#else player->move_delay = game.initial_move_delay; player->move_delay_value = game.initial_move_delay_value; @@ -1737,6 +1801,9 @@ void InitGame() player->move_delay_reset_counter = 0; + player->cannot_move = FALSE; +#endif + player->push_delay = -1; /* initialized when pushing starts */ player->push_delay_value = game.initial_push_delay_value; @@ -1796,6 +1863,9 @@ void InitGame() game.lenses_time_left = 0; game.magnify_time_left = 0; + game.ball_state = level.ball_state_initial; + game.ball_content_nr = 0; + game.envelope_active = FALSE; for (i = 0; i < NUM_BELTS; i++) @@ -6580,6 +6650,47 @@ static void RunTimegateWheel(int x, int y) PlayLevelSound(x, y, SND_TIMEGATE_SWITCH_ACTIVE); } +static void InitMagicBallDelay(int x, int y) +{ +#if 1 + ChangeDelay[x][y] = (level.ball_time + 1) * 8 + 1; +#else + ChangeDelay[x][y] = level.ball_time * FRAMES_PER_SECOND + 1; +#endif +} + +static void ActivateMagicBall(int bx, int by) +{ + int x, y; + + if (level.ball_random) + { + int pos_border = RND(8); /* select one of the eight border elements */ + int pos_content = (pos_border > 3 ? pos_border + 1 : pos_border); + int xx = pos_content % 3; + int yy = pos_content / 3; + + x = bx - 1 + xx; + y = by - 1 + yy; + + if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY) + CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]); + } + else + { + for (y = by - 1; y <= by + 1; y++) for (x = bx - 1; x <= bx + 1; x++) + { + int xx = x - bx + 1; + int yy = y - by + 1; + + if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY) + CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]); + } + } + + game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents; +} + void CheckExit(int x, int y) { if (local_player->gems_still_needed > 0 || @@ -7007,11 +7118,11 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) MV_NONE); int action_arg_number_min = - (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MIN : + (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_NOT_MOVING : CA_ARG_MIN); int action_arg_number_max = - (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MAX : + (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_EVEN_FASTER : action_type == CA_SET_LEVEL_GEMS ? 999 : action_type == CA_SET_LEVEL_TIME ? 9999 : action_type == CA_SET_LEVEL_SCORE ? 99999 : @@ -7020,7 +7131,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) CA_ARG_MAX); int action_arg_number_reset = - (action_type == CA_SET_PLAYER_SPEED ? TILEX/game.initial_move_delay_value : + (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize : action_type == CA_SET_LEVEL_GEMS ? level.gems_needed : action_type == CA_SET_LEVEL_TIME ? level.time : action_type == CA_SET_LEVEL_SCORE ? 0 : @@ -7220,8 +7331,13 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) { int move_stepsize = TILEX / stored_player[i].move_delay_value; - if (action_arg == CA_ARG_SPEED_SLOWER || - action_arg == CA_ARG_SPEED_FASTER) + if (action_arg == CA_ARG_SPEED_FASTER && + stored_player[i].cannot_move) + { + action_arg_number = STEPSIZE_VERY_SLOW; + } + else if (action_arg == CA_ARG_SPEED_SLOWER || + action_arg == CA_ARG_SPEED_FASTER) { action_arg_number = 2; action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE : @@ -7235,6 +7351,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg_number_min, action_arg_number_max); +#if 1 + SetPlayerMoveSpeed(&stored_player[i], move_stepsize, FALSE); +#else /* make sure that value is power of 2 */ move_stepsize = (1 << log_2(move_stepsize)); @@ -7243,6 +7362,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) stored_player[i].cannot_move = (action_arg == CA_ARG_SPEED_NOT_MOVING ? TRUE : FALSE); +#endif } } @@ -7353,22 +7473,22 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) } } -static void ChangeElementNowExt(struct ElementChangeInfo *change, - int x, int y, int target_element) +static void CreateFieldExt(int x, int y, int element, boolean is_change) { int previous_move_direction = MovDir[x][y]; #if USE_NEW_CUSTOM_VALUE int last_ce_value = CustomValue[x][y]; #endif - boolean add_player = (ELEM_IS_PLAYER(target_element) && + boolean add_player = (ELEM_IS_PLAYER(element) && IS_WALKABLE(Feld[x][y])); /* check if element under player changes from accessible to unaccessible (needed for special case of dropping element which then changes) */ if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) && - IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element)) + IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(element)) { Bang(x, y); + return; } @@ -7379,7 +7499,7 @@ static void ChangeElementNowExt(struct ElementChangeInfo *change, else RemoveField(x, y); - Feld[x][y] = target_element; + Feld[x][y] = element; ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); @@ -7401,17 +7521,28 @@ static void ChangeElementNowExt(struct ElementChangeInfo *change, } /* "ChangeCount" not set yet to allow "entered by player" change one time */ - if (ELEM_IS_PLAYER(target_element)) - RelocatePlayer(x, y, target_element); + if (ELEM_IS_PLAYER(element)) + RelocatePlayer(x, y, element); - ChangeCount[x][y]++; /* count number of changes in the same frame */ + if (is_change) + ChangeCount[x][y]++; /* count number of changes in the same frame */ TestIfBadThingTouchesPlayer(x, y); TestIfPlayerTouchesCustomElement(x, y); TestIfElementTouchesCustomElement(x, y); } -static boolean ChangeElementNow(int x, int y, int element, int page) +static void CreateField(int x, int y, int element) +{ + CreateFieldExt(x, y, element, FALSE); +} + +static void CreateElementFromChange(int x, int y, int element) +{ + CreateFieldExt(x, y, element, TRUE); +} + +static boolean ChangeElement(int x, int y, int element, int page) { struct ElementChangeInfo *change = &element_info[element].change_page[page]; int target_element; @@ -7534,7 +7665,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page) content_element = change->target_content.e[xx][yy]; target_element = GET_TARGET_ELEMENT(content_element, change); - ChangeElementNowExt(change, ex, ey, target_element); + CreateElementFromChange(ex, ey, target_element); something_has_changed = TRUE; @@ -7555,7 +7686,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page) { target_element = GET_TARGET_ELEMENT(change->target_element, change); - ChangeElementNowExt(change, x, y, target_element); + CreateElementFromChange(x, y, target_element); PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page); @@ -7569,7 +7700,7 @@ static boolean ChangeElementNow(int x, int y, int element, int page) #if USE_NEW_DELAYED_ACTION -static void ChangeElement(int x, int y, int page) +static void HandleElementChange(int x, int y, int page) { int element = MovingOrBlocked2Element(x, y); struct ElementInfo *ei = &element_info[element]; @@ -7580,9 +7711,9 @@ static void ChangeElement(int x, int y, int page) !CAN_CHANGE_OR_HAS_ACTION(Back[x][y])) { printf("\n\n"); - printf("ChangeElement(): %d,%d: element = %d ('%s')\n", + printf("HandleElementChange(): %d,%d: element = %d ('%s')\n", x, y, element, element_info[element].token_name); - printf("ChangeElement(): This should never happen!\n"); + printf("HandleElementChange(): This should never happen!\n"); printf("\n\n"); } #endif @@ -7647,7 +7778,7 @@ static void ChangeElement(int x, int y, int page) if (change->can_change) { - if (ChangeElementNow(x, y, element, page)) + if (ChangeElement(x, y, element, page)) { if (change->post_change_function) change->post_change_function(x, y); @@ -7661,7 +7792,7 @@ static void ChangeElement(int x, int y, int page) #else -static void ChangeElement(int x, int y, int page) +static void HandleElementChange(int x, int y, int page) { int element = MovingOrBlocked2Element(x, y); struct ElementInfo *ei = &element_info[element]; @@ -7671,9 +7802,9 @@ static void ChangeElement(int x, int y, int page) if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y])) { printf("\n\n"); - printf("ChangeElement(): %d,%d: element = %d ('%s')\n", + printf("HandleElementChange(): %d,%d: element = %d ('%s')\n", x, y, element, element_info[element].token_name); - printf("ChangeElement(): This should never happen!\n"); + printf("HandleElementChange(): This should never happen!\n"); printf("\n\n"); } #endif @@ -7730,7 +7861,7 @@ static void ChangeElement(int x, int y, int page) return; } - if (ChangeElementNow(x, y, element, page)) + if (ChangeElement(x, y, element, page)) { if (change->post_change_function) change->post_change_function(x, y); @@ -7796,7 +7927,8 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, { ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; - ChangeElement(x, y, p); + + HandleElementChange(x, y, p); } #if USE_NEW_DELAYED_ACTION else if (change->has_action) @@ -7898,7 +8030,8 @@ static boolean CheckElementChangeExt(int x, int y, { ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; - ChangeElement(x, y, p); + + HandleElementChange(x, y, p); change_done = TRUE; } @@ -8482,7 +8615,7 @@ void GameActions() { int page = element_info[element].event_page_nr[CE_DELAY]; #if 0 - ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page); + HandleElementChange(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page); #else #if 0 @@ -8495,10 +8628,10 @@ void GameActions() #endif #if 1 - ChangeElement(x, y, page); + HandleElementChange(x, y, page); #else if (CAN_CHANGE(element)) - ChangeElement(x, y, page); + HandleElementChange(x, y, page); if (HAS_ACTION(element)) ExecuteCustomElementAction(x, y, element, page); @@ -8995,6 +9128,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, int new_jx = jx + dx, new_jy = jy + dy; int element; int can_move; + boolean player_can_move = !player->cannot_move; if (!player->active || (!dx && !dy)) return MF_NO_ACTION; @@ -9007,7 +9141,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, if (!IN_LEV_FIELD(new_jx, new_jy)) return MF_NO_ACTION; - if (player->cannot_move) + if (!player_can_move) { #if 1 if (player->MovPos == 0) @@ -9023,7 +9157,9 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, SnapField(player, 0, 0); #endif +#if 0 return MF_NO_ACTION; +#endif } if (!options.network && !AllPlayersInSight(player, new_jx, new_jy)) @@ -9031,7 +9167,7 @@ boolean MovePlayerOneStep(struct PlayerInfo *player, element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy); - if (DONT_RUN_INTO(element)) + if (player_can_move && DONT_RUN_INTO(element)) { if (element == EL_ACID && dx == 0 && dy == 1) { @@ -10089,6 +10225,7 @@ int DigField(struct PlayerInfo *player, { boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG); boolean player_was_pushing = player->is_pushing; + boolean player_can_enter = (!player->cannot_move || mode == DF_SNAP); int jx = oldx, jy = oldy; int dx = x - jx, dy = y - jy; int nextx = x + dx, nexty = y + dy; @@ -10183,7 +10320,8 @@ int DigField(struct PlayerInfo *player, !canMoveToValidFieldWithGravity(jx, jy, move_direction)) return MF_NO_ACTION; /* player cannot walk here due to gravity */ - if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) + if (player_can_enter && + IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction)) { int sound_element = SND_ELEMENT(element); int sound_action = ACTION_WALKING; @@ -10220,7 +10358,8 @@ int DigField(struct PlayerInfo *player, else PlayLevelSoundElementAction(x, y, player->artwork_element, sound_action); } - else if (IS_PASSABLE(element) && canPassField(x, y, move_direction)) + else if (player_can_enter && + IS_PASSABLE(element) && canPassField(x, y, move_direction)) { if (!ACCESS_FROM(element, opposite_direction)) return MF_NO_ACTION; /* field not accessible from this direction */ @@ -10274,7 +10413,7 @@ int DigField(struct PlayerInfo *player, PlayLevelSoundAction(x, y, ACTION_PASSING); } - else if (IS_DIGGABLE(element)) + else if (player_can_enter && IS_DIGGABLE(element)) { RemoveField(x, y); @@ -10304,7 +10443,7 @@ int DigField(struct PlayerInfo *player, player->index_bit, dig_side); } } - else if (IS_COLLECTIBLE(element)) + else if (player_can_enter && IS_COLLECTIBLE(element)) { RemoveField(x, y); @@ -10418,7 +10557,7 @@ int DigField(struct PlayerInfo *player, player->index_bit, dig_side); } } - else if (IS_PUSHABLE(element)) + else if (player_can_enter && IS_PUSHABLE(element)) { if (mode == DF_SNAP && element != EL_BD_ROCK) return MF_NO_ACTION; @@ -10642,6 +10781,37 @@ int DigField(struct PlayerInfo *player, ResetGfxAnimation(x, y); DrawLevelField(x, y); } + else if (element == EL_EMC_MAGIC_BALL_SWITCH || + element == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE) + { + int xx, yy; + + game.ball_state = !game.ball_state; + +#if 1 + SCAN_PLAYFIELD(xx, yy) +#else + for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++) +#endif + { + int e = Feld[xx][yy]; + + if (game.ball_state) + { + if (e == EL_EMC_MAGIC_BALL) + CreateField(xx, yy, EL_EMC_MAGIC_BALL_ACTIVE); + else if (e == EL_EMC_MAGIC_BALL_SWITCH) + CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE); + } + else + { + if (e == EL_EMC_MAGIC_BALL_ACTIVE) + CreateField(xx, yy, EL_EMC_MAGIC_BALL); + else if (e == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE) + CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH); + } + } + } CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X, player->index_bit, dig_side);