X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=052239346ffc65f545296b98070c120881393cf3;hb=1e5cae5e3ab889c3bcba80a065c6d7ba1e6d28a2;hp=3eff842eb44ece2ed7c4c5efd98b0db1f0c1fc88;hpb=3bf51f147946d7080ed973f7d1fca2971e5009d2;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 3eff842e..05223934 100644 --- a/src/game.c +++ b/src/game.c @@ -34,7 +34,8 @@ #define USE_NEW_PLAYER_SPEED (USE_NEW_STUFF * 1) #define USE_NEW_DELAYED_ACTION (USE_NEW_STUFF * 1) #define USE_NEW_SNAP_DELAY (USE_NEW_STUFF * 1) -#define USE_ONLY_ONE_CHANGE_PER_FRAME (USE_NEW_STUFF * 0) +#define USE_ONLY_ONE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1) +#define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0) /* for DigField() */ #define DF_NO_PUSH 0 @@ -50,13 +51,14 @@ #define SCROLL_INIT 0 #define SCROLL_GO_ON 1 -/* for Explode() */ +/* for Bang()/Explode() */ #define EX_PHASE_START 0 #define EX_TYPE_NONE 0 #define EX_TYPE_NORMAL (1 << 0) #define EX_TYPE_CENTER (1 << 1) #define EX_TYPE_BORDER (1 << 2) #define EX_TYPE_CROSS (1 << 3) +#define EX_TYPE_DYNA (1 << 4) #define EX_TYPE_SINGLE_TILE (EX_TYPE_CENTER | EX_TYPE_BORDER) /* special positions in the game control window (relative to control window) */ @@ -131,6 +133,8 @@ RND(element_info[e].ce_value_random_initial)) #define GET_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \ RND((c)->delay_random * (c)->delay_frames)) +#define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \ + RND((c)->delay_random)) #define GET_TARGET_ELEMENT(e, ch) \ ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \ @@ -233,6 +237,8 @@ /* forward declaration for internal use */ +static void CreateField(int, int, int); + static void SetPlayerWaiting(struct PlayerInfo *, boolean); static void AdvanceFrameAndPlayerCounters(int); @@ -257,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) \ @@ -298,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 { @@ -477,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, @@ -596,6 +613,46 @@ static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS]; #define CE_PAGE(e, ce) (element_info[e].event_page[ce]) +/* static variables for playfield scan mode (scanning forward or backward) */ +static int playfield_scan_start_x = 0; +static int playfield_scan_start_y = 0; +static int playfield_scan_delta_x = 1; +static int playfield_scan_delta_y = 1; + +#define SCAN_PLAYFIELD(x, y) for ((y) = playfield_scan_start_y; \ + (y) >= 0 && (y) <= lev_fieldy - 1; \ + (y) += playfield_scan_delta_y) \ + for ((x) = playfield_scan_start_x; \ + (x) >= 0 && (x) <= lev_fieldx - 1; \ + (x) += playfield_scan_delta_x) \ + +static void InitPlayfieldScanModeVars() +{ + if (game.use_reverse_scan_direction) + { + playfield_scan_start_x = lev_fieldx - 1; + playfield_scan_start_y = lev_fieldy - 1; + + playfield_scan_delta_x = -1; + playfield_scan_delta_y = -1; + } + else + { + playfield_scan_start_x = 0; + playfield_scan_start_y = 0; + + playfield_scan_delta_x = 1; + playfield_scan_delta_y = 1; + } +} + +static void InitPlayfieldScanMode(int mode) +{ + game.use_reverse_scan_direction = + (mode == CA_ARG_SCAN_MODE_REVERSE ? TRUE : FALSE); + + InitPlayfieldScanModeVars(); +} void GetPlayerConfig() { @@ -891,6 +948,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)) @@ -932,6 +999,11 @@ static void InitField(int x, int y, boolean init_game) break; } +#if 1 + if (!init_game) + CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X); +#endif + #if 0 #if USE_NEW_CUSTOM_VALUE @@ -1138,7 +1210,7 @@ static void resolve_group_element(int group_element, int recursion_depth) static void InitGameEngine() { - int i, j, k, l; + int i, j, k, l, x, y; /* set game engine from tape file when re-playing, else from level file */ game.engine_version = (tape.playing ? tape.engine_version : @@ -1244,6 +1316,9 @@ static void InitGameEngine() /* ---------------------------------------------------------------------- */ + /* default scan direction: scan playfield from top/left to bottom/right */ + InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL); + /* dynamically adjust element properties according to game engine version */ InitElementPropertiesEngine(game.engine_version); @@ -1505,6 +1580,39 @@ static void InitGameEngine() for (i = 0; access_direction_list[i].element != EL_UNDEFINED; i++) element_info[access_direction_list[i].element].access_direction = access_direction_list[i].direction; + + /* ---------- initialize explosion content ------------------------------- */ + for (i = 0; i < MAX_NUM_ELEMENTS; i++) + { + if (IS_CUSTOM_ELEMENT(i)) + continue; + + for (y = 0; y < 3; y++) for (x = 0; x < 3; x++) + { + /* (content for EL_YAMYAM set at run-time with game.yamyam_content_nr) */ + + element_info[i].content.e[x][y] = + (i == EL_PLAYER_1 ? EL_EMERALD_YELLOW : + i == EL_PLAYER_2 ? EL_EMERALD_RED : + i == EL_PLAYER_3 ? EL_EMERALD : + i == EL_PLAYER_4 ? EL_EMERALD_PURPLE : + i == EL_MOLE ? EL_EMERALD_RED : + i == EL_PENGUIN ? EL_EMERALD_PURPLE : + i == EL_BUG ? (x == 1 && y == 1 ? EL_DIAMOND : EL_EMERALD) : + i == EL_BD_BUTTERFLY ? EL_BD_DIAMOND : + i == EL_SP_ELECTRON ? EL_SP_INFOTRON : + i == EL_AMOEBA_TO_DIAMOND ? level.amoeba_content : + i == EL_WALL_EMERALD ? EL_EMERALD : + i == EL_WALL_DIAMOND ? EL_DIAMOND : + i == EL_WALL_BD_DIAMOND ? EL_BD_DIAMOND : + i == EL_WALL_EMERALD_YELLOW ? EL_EMERALD_YELLOW : + i == EL_WALL_EMERALD_RED ? EL_EMERALD_RED : + i == EL_WALL_EMERALD_PURPLE ? EL_EMERALD_PURPLE : + i == EL_WALL_PEARL ? EL_PEARL : + i == EL_WALL_CRYSTAL ? EL_CRYSTAL : + EL_EMPTY); + } + } } int get_num_special_action(int element, int action_first, int action_last) @@ -1588,7 +1696,9 @@ void InitGame() player->StepFrame = 0; player->use_murphy = FALSE; - player->artwork_element = player->element_nr; + player->artwork_element = + (level.use_artwork_element[i] ? level.artwork_element[i] : + player->element_nr); player->block_last_field = FALSE; /* initialized in InitPlayerField() */ player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */ @@ -1709,6 +1819,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++) @@ -1720,56 +1833,58 @@ void InitGame() for (i = 0; i < MAX_NUM_AMOEBA; i++) AmoebaCnt[i] = AmoebaCnt2[i] = 0; - for (x = 0; x < lev_fieldx; x++) +#if 1 + SCAN_PLAYFIELD(x, y) +#else + for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++) +#endif { - for (y = 0; y < lev_fieldy; y++) - { - Feld[x][y] = level.field[x][y]; - MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; - ChangeDelay[x][y] = 0; - ChangePage[x][y] = -1; + Feld[x][y] = level.field[x][y]; + MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; + ChangeDelay[x][y] = 0; + ChangePage[x][y] = -1; #if USE_NEW_CUSTOM_VALUE - CustomValue[x][y] = 0; /* initialized in InitField() */ + CustomValue[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; - WasJustFalling[x][y] = 0; - CheckCollision[x][y] = 0; - Stop[x][y] = FALSE; - Pushed[x][y] = FALSE; + Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0; + AmoebaNr[x][y] = 0; + WasJustMoving[x][y] = 0; + WasJustFalling[x][y] = 0; + CheckCollision[x][y] = 0; + Stop[x][y] = FALSE; + Pushed[x][y] = FALSE; - Changed[x][y] = 0; - ChangeEvent[x][y] = -1; + ChangeCount[x][y] = 0; + ChangeEvent[x][y] = -1; - ExplodePhase[x][y] = 0; - ExplodeDelay[x][y] = 0; - ExplodeField[x][y] = EX_TYPE_NONE; + ExplodePhase[x][y] = 0; + ExplodeDelay[x][y] = 0; + ExplodeField[x][y] = EX_TYPE_NONE; - RunnerVisit[x][y] = 0; - PlayerVisit[x][y] = 0; + RunnerVisit[x][y] = 0; + PlayerVisit[x][y] = 0; - GfxFrame[x][y] = 0; - GfxRandom[x][y] = INIT_GFX_RANDOM(); - GfxElement[x][y] = EL_UNDEFINED; - GfxAction[x][y] = ACTION_DEFAULT; - GfxDir[x][y] = MV_NONE; - } + GfxFrame[x][y] = 0; + GfxRandom[x][y] = INIT_GFX_RANDOM(); + GfxElement[x][y] = EL_UNDEFINED; + GfxAction[x][y] = ACTION_DEFAULT; + GfxDir[x][y] = MV_NONE; } - for (y = 0; y < lev_fieldy; y++) +#if 1 + SCAN_PLAYFIELD(x, y) +#else + for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { - for (x = 0; x < lev_fieldx; x++) - { - if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y])) - emulate_bd = FALSE; - if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y])) - emulate_sb = FALSE; - if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y])) - emulate_sp = FALSE; + if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y])) + emulate_bd = FALSE; + if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y])) + emulate_sb = FALSE; + if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y])) + emulate_sp = FALSE; - InitField(x, y, TRUE); - } + InitField(x, y, TRUE); } InitBeltMovement(); @@ -1968,7 +2083,11 @@ void InitGame() int found_element = EL_UNDEFINED; int player_nr = local_player->index_nr; +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { int element = Feld[x][y]; int content; @@ -3026,6 +3145,7 @@ void Explode(int ex, int ey, int phase, int mode) if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */ { int center_element = Feld[ex][ey]; + int artwork_element, explosion_element; /* set these values later */ #if 0 /* --- This is only really needed (and now handled) in "Impact()". --- */ @@ -3036,10 +3156,13 @@ void Explode(int ex, int ey, int phase, int mode) return; #endif +#if 0 + /* !!! at this place, the center element may be EL_BLOCKED !!! */ if (mode == EX_TYPE_NORMAL || mode == EX_TYPE_CENTER || mode == EX_TYPE_CROSS) - PlayLevelSoundAction(ex, ey, ACTION_EXPLODING); + PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING); +#endif /* remove things displayed in background while burning dynamite */ if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey])) @@ -3053,7 +3176,35 @@ void Explode(int ex, int ey, int phase, int mode) Feld[ex][ey] = center_element; } + /* now "center_element" is finally determined -- set related values now */ + artwork_element = center_element; /* for custom player artwork */ + explosion_element = center_element; /* for custom player artwork */ + + if (IS_PLAYER(ex, ey)) + { + int player_nr = GET_PLAYER_NR(StorePlayer[ex][ey]); + + artwork_element = stored_player[player_nr].artwork_element; + + if (level.use_explosion_element[player_nr]) + { + explosion_element = level.explosion_element[player_nr]; + artwork_element = explosion_element; + } + } + +#if 1 + if (mode == EX_TYPE_NORMAL || + mode == EX_TYPE_CENTER || + mode == EX_TYPE_CROSS) + PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING); +#endif + +#if 1 + last_phase = element_info[explosion_element].explosion_delay + 1; +#else last_phase = element_info[center_element].explosion_delay + 1; +#endif for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++) { @@ -3126,6 +3277,11 @@ void Explode(int ex, int ey, int phase, int mode) if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey)) { +#if 1 + int player_nr = StorePlayer[ex][ey] - EL_PLAYER_1; + + Store[x][y] = EL_PLAYER_IS_EXPLODING_1 + player_nr; +#else switch(StorePlayer[ex][ey]) { case EL_PLAYER_2: @@ -3142,10 +3298,33 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = EL_PLAYER_IS_EXPLODING_1; break; } +#endif if (PLAYERINFO(ex, ey)->use_murphy) Store[x][y] = EL_EMPTY; } +#if 1 + /* !!! check this case -- currently needed for rnd_rado_negundo_v, + !!! levels 015 018 019 020 021 022 023 026 027 028 !!! */ + else if (ELEM_IS_PLAYER(center_element)) + Store[x][y] = EL_EMPTY; + else if (center_element == EL_YAMYAM) + Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy]; + else if (element_info[center_element].content.e[xx][yy] != EL_EMPTY) + Store[x][y] = element_info[center_element].content.e[xx][yy]; +#if 1 + /* needed because EL_BD_BUTTERFLY is not defined as "CAN_EXPLODE" + (killing EL_BD_BUTTERFLY with dynamite would result in BD diamond + otherwise) -- FIX THIS !!! */ + else if (!CAN_EXPLODE(element) && element != EL_BD_BUTTERFLY) + Store[x][y] = element_info[element].content.e[1][1]; +#else + else if (!CAN_EXPLODE(element)) + Store[x][y] = element_info[element].content.e[1][1]; +#endif + else + Store[x][y] = EL_EMPTY; +#else else if (center_element == EL_MOLE) Store[x][y] = EL_EMERALD_RED; else if (center_element == EL_PENGUIN) @@ -3183,13 +3362,14 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = element_info[element].content.e[1][1]; else Store[x][y] = EL_EMPTY; +#endif if (x != ex || y != ey || mode == EX_TYPE_BORDER || center_element == EL_AMOEBA_TO_DIAMOND) Store2[x][y] = element; Feld[x][y] = EL_EXPLOSION; - GfxElement[x][y] = center_element; + GfxElement[x][y] = artwork_element; ExplodePhase[x][y] = 1; ExplodeDelay[x][y] = last_phase; @@ -3283,12 +3463,18 @@ void Explode(int ex, int ey, int phase, int mode) /* player can escape from explosions and might therefore be still alive */ if (element >= EL_PLAYER_IS_EXPLODING_1 && element <= EL_PLAYER_IS_EXPLODING_4) - Feld[x][y] = (stored_player[element - EL_PLAYER_IS_EXPLODING_1].active ? - EL_EMPTY : - element == EL_PLAYER_IS_EXPLODING_1 ? EL_EMERALD_YELLOW : - element == EL_PLAYER_IS_EXPLODING_2 ? EL_EMERALD_RED : - element == EL_PLAYER_IS_EXPLODING_3 ? EL_EMERALD : - EL_EMERALD_PURPLE); + { + int player_nr = element - EL_PLAYER_IS_EXPLODING_1; + int explosion_element = EL_PLAYER_1 + player_nr; + int xx = MIN(MAX(0, x - stored_player[player_nr].jx + 1), 2); + int yy = MIN(MAX(0, y - stored_player[player_nr].jy + 1), 2); + + if (level.use_explosion_element[player_nr]) + explosion_element = level.explosion_element[player_nr]; + + Feld[x][y] = (stored_player[player_nr].active ? EL_EMPTY : + element_info[explosion_element].content.e[xx][yy]); + } /* restore probably existing indestructible background element */ if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y])) @@ -3396,6 +3582,7 @@ void DynaExplode(int ex, int ey) void Bang(int x, int y) { int element = MovingOrBlocked2Element(x, y); + int explosion_type = EX_TYPE_NORMAL; if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y)) { @@ -3403,6 +3590,16 @@ void Bang(int x, int y) element = Feld[x][y] = (player->use_murphy ? EL_SP_MURPHY : player->element_nr); + + if (level.use_explosion_element[player->index_nr]) + { + int explosion_element = level.explosion_element[player->index_nr]; + + if (element_info[explosion_element].explosion_type == EXPLODES_CROSS) + explosion_type = EX_TYPE_CROSS; + else if (element_info[explosion_element].explosion_type == EXPLODES_1X1) + explosion_type = EX_TYPE_CENTER; + } } switch(element) @@ -3417,8 +3614,8 @@ void Bang(int x, int y) case EL_PACMAN: case EL_MOLE: RaiseScoreElement(element); - Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL); break; + case EL_DYNABOMB_PLAYER_1_ACTIVE: case EL_DYNABOMB_PLAYER_2_ACTIVE: case EL_DYNABOMB_PLAYER_3_ACTIVE: @@ -3426,27 +3623,30 @@ void Bang(int x, int y) case EL_DYNABOMB_INCREASE_NUMBER: case EL_DYNABOMB_INCREASE_SIZE: case EL_DYNABOMB_INCREASE_POWER: - DynaExplode(x, y); + explosion_type = EX_TYPE_DYNA; break; + case EL_PENGUIN: case EL_LAMP: case EL_LAMP_ACTIVE: case EL_AMOEBA_TO_DIAMOND: - if (IS_PLAYER(x, y)) - Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL); - else - Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER); + if (!IS_PLAYER(x, y)) /* penguin and player may be at same field */ + explosion_type = EX_TYPE_CENTER; break; + default: if (element_info[element].explosion_type == EXPLODES_CROSS) - Explode(x, y, EX_PHASE_START, EX_TYPE_CROSS); + explosion_type = EX_TYPE_CROSS; else if (element_info[element].explosion_type == EXPLODES_1X1) - Explode(x, y, EX_PHASE_START, EX_TYPE_CENTER); - else - Explode(x, y, EX_PHASE_START, EX_TYPE_NORMAL); + explosion_type = EX_TYPE_CENTER; break; } + if (explosion_type == EX_TYPE_DYNA) + DynaExplode(x, y); + else + Explode(x, y, EX_PHASE_START, explosion_type); + CheckTriggeredElementChange(x, y, element, CE_EXPLOSION_OF_X); } @@ -3501,25 +3701,26 @@ static void InitBeltMovement() } } - for (y = 0; y < lev_fieldy; y++) +#if 1 + SCAN_PLAYFIELD(x, y) +#else + for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { - for (x = 0; x < lev_fieldx; x++) - { - int element = Feld[x][y]; + int element = Feld[x][y]; - for (i = 0; i < NUM_BELTS; i++) + for (i = 0; i < NUM_BELTS; i++) + { + if (IS_BELT(element) && game.belt_dir[i] != MV_NONE) { - if (IS_BELT(element) && game.belt_dir[i] != MV_NONE) - { - int e_belt_nr = getBeltNrFromBeltElement(element); - int belt_nr = i; + int e_belt_nr = getBeltNrFromBeltElement(element); + int belt_nr = i; - if (e_belt_nr == belt_nr) - { - int belt_part = Feld[x][y] - belt_base_element[belt_nr]; + if (e_belt_nr == belt_nr) + { + int belt_part = Feld[x][y] - belt_base_element[belt_nr]; - Feld[x][y] = belt_base_active_element[belt_nr] + belt_part; - } + Feld[x][y] = belt_base_active_element[belt_nr] + belt_part; } } } @@ -3584,45 +3785,46 @@ static void ToggleBeltSwitch(int x, int y) graphic_info[graphic].anim_mode |= ANIM_REVERSE; } - for (yy = 0; yy < lev_fieldy; yy++) +#if 1 + SCAN_PLAYFIELD(xx, yy) +#else + for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++) +#endif { - for (xx = 0; xx < lev_fieldx; xx++) + int element = Feld[xx][yy]; + + if (IS_BELT_SWITCH(element)) { - int element = Feld[xx][yy]; + int e_belt_nr = getBeltNrFromBeltSwitchElement(element); - if (IS_BELT_SWITCH(element)) + if (e_belt_nr == belt_nr) { - int e_belt_nr = getBeltNrFromBeltSwitchElement(element); - - if (e_belt_nr == belt_nr) - { - Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr; - DrawLevelField(xx, yy); - } + Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr; + DrawLevelField(xx, yy); } - else if (IS_BELT(element) && belt_dir != MV_NONE) - { - int e_belt_nr = getBeltNrFromBeltElement(element); + } + else if (IS_BELT(element) && belt_dir != MV_NONE) + { + int e_belt_nr = getBeltNrFromBeltElement(element); - if (e_belt_nr == belt_nr) - { - int belt_part = Feld[xx][yy] - belt_base_element[belt_nr]; + if (e_belt_nr == belt_nr) + { + int belt_part = Feld[xx][yy] - belt_base_element[belt_nr]; - Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part; - DrawLevelField(xx, yy); - } + Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part; + DrawLevelField(xx, yy); } - else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE) - { - int e_belt_nr = getBeltNrFromBeltActiveElement(element); + } + else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE) + { + int e_belt_nr = getBeltNrFromBeltActiveElement(element); - if (e_belt_nr == belt_nr) - { - int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr]; + if (e_belt_nr == belt_nr) + { + int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr]; - Feld[xx][yy] = belt_base_element[belt_nr] + belt_part; - DrawLevelField(xx, yy); - } + Feld[xx][yy] = belt_base_element[belt_nr] + belt_part; + DrawLevelField(xx, yy); } } } @@ -3634,32 +3836,33 @@ static void ToggleSwitchgateSwitch(int x, int y) game.switchgate_pos = !game.switchgate_pos; - for (yy = 0; yy < lev_fieldy; yy++) +#if 1 + SCAN_PLAYFIELD(xx, yy) +#else + for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++) +#endif { - for (xx = 0; xx < lev_fieldx; xx++) - { - int element = Feld[xx][yy]; + int element = Feld[xx][yy]; - if (element == EL_SWITCHGATE_SWITCH_UP || - element == EL_SWITCHGATE_SWITCH_DOWN) - { - Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; - DrawLevelField(xx, yy); - } - else if (element == EL_SWITCHGATE_OPEN || - element == EL_SWITCHGATE_OPENING) - { - Feld[xx][yy] = EL_SWITCHGATE_CLOSING; + if (element == EL_SWITCHGATE_SWITCH_UP || + element == EL_SWITCHGATE_SWITCH_DOWN) + { + Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos; + DrawLevelField(xx, yy); + } + else if (element == EL_SWITCHGATE_OPEN || + element == EL_SWITCHGATE_OPENING) + { + Feld[xx][yy] = EL_SWITCHGATE_CLOSING; - PlayLevelSoundAction(xx, yy, ACTION_CLOSING); - } - else if (element == EL_SWITCHGATE_CLOSED || - element == EL_SWITCHGATE_CLOSING) - { - Feld[xx][yy] = EL_SWITCHGATE_OPENING; + PlayLevelSoundAction(xx, yy, ACTION_CLOSING); + } + else if (element == EL_SWITCHGATE_CLOSED || + element == EL_SWITCHGATE_CLOSING) + { + Feld[xx][yy] = EL_SWITCHGATE_OPENING; - PlayLevelSoundAction(xx, yy, ACTION_OPENING); - } + PlayLevelSoundAction(xx, yy, ACTION_OPENING); } } } @@ -3684,7 +3887,11 @@ static void RedrawAllLightSwitchesAndInvisibleElements() { int x, y; +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { int element = Feld[x][y]; @@ -3745,7 +3952,11 @@ static void RedrawAllInvisibleElementsForLenses() { int x, y; +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { int element = Feld[x][y]; @@ -3794,7 +4005,11 @@ static void RedrawAllInvisibleElementsForMagnifier() { int x, y; +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { int element = Feld[x][y]; @@ -3854,28 +4069,29 @@ static void ActivateTimegateSwitch(int x, int y) game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND; - for (yy = 0; yy < lev_fieldy; yy++) +#if 1 + SCAN_PLAYFIELD(xx, yy) +#else + for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++) +#endif { - for (xx = 0; xx < lev_fieldx; xx++) - { - int element = Feld[xx][yy]; + int element = Feld[xx][yy]; - if (element == EL_TIMEGATE_CLOSED || - element == EL_TIMEGATE_CLOSING) - { - Feld[xx][yy] = EL_TIMEGATE_OPENING; - PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING); - } - - /* - else if (element == EL_TIMEGATE_SWITCH_ACTIVE) - { - Feld[xx][yy] = EL_TIMEGATE_SWITCH; - DrawLevelField(xx, yy); - } - */ + if (element == EL_TIMEGATE_CLOSED || + element == EL_TIMEGATE_CLOSING) + { + Feld[xx][yy] = EL_TIMEGATE_OPENING; + PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING); + } + /* + else if (element == EL_TIMEGATE_SWITCH_ACTIVE) + { + Feld[xx][yy] = EL_TIMEGATE_SWITCH; + DrawLevelField(xx, yy); } + */ + } Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE; @@ -3903,6 +4119,18 @@ void Impact(int x, int y) ABS(MovPos[x][y + 1] + getElementMoveStepsize(x, y + 1)) >= TILEX) object_hit = FALSE; +#if USE_QUICKSAND_IMPACT_BUGFIX + if (Feld[x][y + 1] == EL_QUICKSAND_EMPTYING && object_hit == FALSE) + { + RemoveMovingField(x, y + 1); + Feld[x][y + 1] = EL_QUICKSAND_EMPTY; + Feld[x][y + 2] = EL_ROCK; + DrawLevelField(x, y + 2); + + object_hit = TRUE; + } +#endif + if (object_hit) smashed = MovingOrBlocked2Element(x, y + 1); @@ -3972,10 +4200,13 @@ void Impact(int x, int y) EL_BD_MAGIC_WALL_ACTIVE); /* activate magic wall / mill */ - for (yy = 0; yy < lev_fieldy; yy++) - for (xx = 0; xx < lev_fieldx; xx++) - if (Feld[xx][yy] == smashed) - Feld[xx][yy] = activated_magic_wall; +#if 1 + SCAN_PLAYFIELD(xx, yy) +#else + for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++) +#endif + if (Feld[xx][yy] == smashed) + Feld[xx][yy] = activated_magic_wall; game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND; game.magic_wall_active = TRUE; @@ -4114,7 +4345,7 @@ inline static void TurnRoundExt(int x, int y) { static struct { - int x, y; + int dx, dy; } move_xy[] = { { 0, 0 }, @@ -4149,10 +4380,10 @@ inline static void TurnRoundExt(int x, int y) int right_dir = turn[old_move_dir].right; int back_dir = turn[old_move_dir].back; - int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y; - int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y; - int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y; - int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y; + int left_dx = move_xy[left_dir].dx, left_dy = move_xy[left_dir].dy; + int right_dx = move_xy[right_dir].dx, right_dy = move_xy[right_dir].dy; + int move_dx = move_xy[old_move_dir].dx, move_dy = move_xy[old_move_dir].dy; + int back_dx = move_xy[back_dir].dx, back_dy = move_xy[back_dir].dy; int left_x = x + left_dx, left_y = y + left_dy; int right_x = x + right_dx, right_y = y + right_dy; @@ -4305,8 +4536,8 @@ inline static void TurnRoundExt(int x, int y) else MovDir[x][y] = back_dir; - xx = x + move_xy[MovDir[x][y]].x; - yy = y + move_xy[MovDir[x][y]].y; + xx = x + move_xy[MovDir[x][y]].dx; + yy = y + move_xy[MovDir[x][y]].dy; if (!IN_LEV_FIELD(xx, yy) || (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy]))) @@ -4333,8 +4564,8 @@ inline static void TurnRoundExt(int x, int y) else MovDir[x][y] = back_dir; - xx = x + move_xy[MovDir[x][y]].x; - yy = y + move_xy[MovDir[x][y]].y; + xx = x + move_xy[MovDir[x][y]].dx; + yy = y + move_xy[MovDir[x][y]].dy; if (!IN_LEV_FIELD_AND_IS_FREE(xx, yy)) MovDir[x][y] = old_move_dir; @@ -5383,6 +5614,11 @@ void StartMoving(int x, int y) } Store[newx][newy] = EL_EMPTY; +#if 1 + /* this makes it possible to leave the removed element again */ + if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) + Store[newx][newy] = new_element; +#else if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element))) { int move_leave_element = element_info[element].move_leave_element; @@ -5391,6 +5627,7 @@ void StartMoving(int x, int y) Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ? new_element : move_leave_element); } +#endif if (move_pattern & MV_MAZE_RUNNER_STYLE) { @@ -5586,12 +5823,13 @@ void StartMoving(int x, int y) void ContinueMoving(int x, int y) { int element = Feld[x][y]; - int stored = Store[x][y]; struct ElementInfo *ei = &element_info[element]; 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 newx = x + dx, newy = y + dy; + int stored = Store[x][y]; + int stored_new = Store[newx][newy]; boolean pushed_by_player = (Pushed[x][y] && IS_PLAYER(x, y)); boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y)); boolean last_line = (newy == lev_fieldy - 1); @@ -5693,22 +5931,34 @@ void ContinueMoving(int x, int y) MovDelay[newx][newy] = 0; +#if 1 + if (CAN_CHANGE_OR_HAS_ACTION(element)) +#else if (CAN_CHANGE(element)) +#endif { /* copy element change control values to new field */ ChangeDelay[newx][newy] = ChangeDelay[x][y]; ChangePage[newx][newy] = ChangePage[x][y]; - Changed[newx][newy] = Changed[x][y]; + ChangeCount[newx][newy] = ChangeCount[x][y]; ChangeEvent[newx][newy] = ChangeEvent[x][y]; +#if 0 #if USE_NEW_CUSTOM_VALUE CustomValue[newx][newy] = CustomValue[x][y]; +#endif #endif } +#if 1 +#if USE_NEW_CUSTOM_VALUE + CustomValue[newx][newy] = CustomValue[x][y]; +#endif +#endif + ChangeDelay[x][y] = 0; ChangePage[x][y] = -1; - Changed[x][y] = 0; + ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; #if USE_NEW_CUSTOM_VALUE @@ -5730,10 +5980,16 @@ void ContinueMoving(int x, int y) { int move_leave_element = ei->move_leave_element; +#if 1 + /* this makes it possible to leave the removed element again */ + if (ei->move_leave_element == EL_TRIGGER_ELEMENT) + move_leave_element = stored; +#else /* this makes it possible to leave the removed element again */ if (ei->move_leave_type == LEAVE_TYPE_LIMITED && ei->move_leave_element == EL_TRIGGER_ELEMENT) move_leave_element = stored; +#endif Feld[x][y] = move_leave_element; @@ -5825,6 +6081,13 @@ void ContinueMoving(int x, int y) TestIfElementHitsCustomElement(newx, newy, direction); TestIfPlayerTouchesCustomElement(newx, newy); TestIfElementTouchesCustomElement(newx, newy); + +#if 1 + if (IS_CUSTOM_ELEMENT(element) && ei->move_enter_element != EL_EMPTY && + IS_EQUAL_OR_IN_GROUP(stored_new, ei->move_enter_element)) + CheckElementChangeBySide(newx, newy, element, stored_new, CE_DIGGING_X, + MV_DIR_OPPOSITE(direction)); +#endif } int AmoebeNachbarNr(int ax, int ay) @@ -5893,13 +6156,14 @@ void AmoebenVereinigen(int ax, int ay) AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr]; AmoebaCnt2[old_group_nr] = 0; - for (yy = 0; yy < lev_fieldy; yy++) +#if 1 + SCAN_PLAYFIELD(xx, yy) +#else + for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++) +#endif { - for (xx = 0; xx < lev_fieldx; xx++) - { - if (AmoebaNr[xx][yy] == old_group_nr) - AmoebaNr[xx][yy] = new_group_nr; - } + if (AmoebaNr[xx][yy] == old_group_nr) + AmoebaNr[xx][yy] = new_group_nr; } } } @@ -5922,17 +6186,19 @@ void AmoebeUmwandeln(int ax, int ay) } #endif - for (y = 0; y < lev_fieldy; y++) +#if 1 + SCAN_PLAYFIELD(x, y) +#else + for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { - for (x = 0; x < lev_fieldx; x++) + if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr) { - if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr) - { - AmoebaNr[x][y] = 0; - Feld[x][y] = EL_AMOEBA_TO_DIAMOND; - } + AmoebaNr[x][y] = 0; + Feld[x][y] = EL_AMOEBA_TO_DIAMOND; } } + PlayLevelSound(ax, ay, (IS_GEM(level.amoeba_content) ? SND_AMOEBA_TURNING_TO_GEM : SND_AMOEBA_TURNING_TO_ROCK)); @@ -5982,21 +6248,22 @@ void AmoebeUmwandelnBD(int ax, int ay, int new_element) } #endif - for (y = 0; y < lev_fieldy; y++) +#if 1 + SCAN_PLAYFIELD(x, y) +#else + for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { - for (x = 0; x < lev_fieldx; x++) + if (AmoebaNr[x][y] == group_nr && + (Feld[x][y] == EL_AMOEBA_DEAD || + Feld[x][y] == EL_BD_AMOEBA || + Feld[x][y] == EL_AMOEBA_GROWING)) { - if (AmoebaNr[x][y] == group_nr && - (Feld[x][y] == EL_AMOEBA_DEAD || - Feld[x][y] == EL_BD_AMOEBA || - Feld[x][y] == EL_AMOEBA_GROWING)) - { - AmoebaNr[x][y] = 0; - Feld[x][y] = new_element; - InitField(x, y, FALSE); - DrawLevelField(x, y); - done = TRUE; - } + AmoebaNr[x][y] = 0; + Feld[x][y] = new_element; + InitField(x, y, FALSE); + DrawLevelField(x, y); + done = TRUE; } } @@ -6339,6 +6606,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 || @@ -6387,18 +6695,19 @@ static void CloseAllOpenTimegates() { int x, y; - for (y = 0; y < lev_fieldy; y++) +#if 1 + SCAN_PLAYFIELD(x, y) +#else + for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { - for (x = 0; x < lev_fieldx; x++) - { - int element = Feld[x][y]; + int element = Feld[x][y]; - if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING) - { - Feld[x][y] = EL_TIMEGATE_CLOSING; + if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING) + { + Feld[x][y] = EL_TIMEGATE_CLOSING; - PlayLevelSoundAction(x, y, ACTION_CLOSING); - } + PlayLevelSoundAction(x, y, ACTION_CLOSING); } } } @@ -6804,7 +7113,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) #else action_arg == CA_ARG_NUMBER_CE_VALUE ? ei->custom_value_initial : #endif - action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CHANGE_DELAY(change) : + action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) : action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value : action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed : action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score : @@ -7042,7 +7351,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) int artwork_element = action_arg_element; if (action_arg == CA_ARG_ELEMENT_RESET) - artwork_element = stored_player[i].element_nr; + artwork_element = + (level.use_artwork_element[i] ? level.artwork_element[i] : + stored_player[i].element_nr); stored_player[i].artwork_element = artwork_element; @@ -7095,27 +7406,36 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } + /* ---------- engine actions ------------------------------------------ */ + + case CA_SET_ENGINE_SCAN_MODE: + { + InitPlayfieldScanMode(action_arg); + + break; + } + default: break; } } -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; } @@ -7126,7 +7446,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); @@ -7147,18 +7467,29 @@ static void ChangeElementNowExt(struct ElementChangeInfo *change, DrawLevelFieldCrumbledSandNeighbours(x, y); } - /* "Changed[][]" not set yet to allow "entered by player" change one time */ - if (ELEM_IS_PLAYER(target_element)) - RelocatePlayer(x, y, target_element); + /* "ChangeCount" not set yet to allow "entered by player" change one time */ + if (ELEM_IS_PLAYER(element)) + RelocatePlayer(x, y, element); - Changed[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; @@ -7178,10 +7509,10 @@ static boolean ChangeElementNow(int x, int y, int element, int page) } /* do not change elements more than a specified maximum number of changes */ - if (Changed[x][y] >= game.max_num_changes_per_frame) + if (ChangeCount[x][y] >= game.max_num_changes_per_frame) return FALSE; - Changed[x][y]++; /* count number of changes in the same frame */ + ChangeCount[x][y]++; /* count number of changes in the same frame */ if (change->explode) { @@ -7281,7 +7612,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; @@ -7302,7 +7633,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); @@ -7316,7 +7647,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]; @@ -7327,9 +7658,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 @@ -7394,7 +7725,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); @@ -7408,7 +7739,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]; @@ -7418,9 +7749,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 @@ -7477,7 +7808,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); @@ -7487,7 +7818,7 @@ static void ChangeElement(int x, int y, int page) #endif -static boolean CheckTriggeredElementChangeExt(int x, int y, +static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, int trigger_element, int trigger_event, int trigger_player, @@ -7525,13 +7856,17 @@ static boolean CheckTriggeredElementChangeExt(int x, int y, change->actual_trigger_element = trigger_element; change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player); change->actual_trigger_side = trigger_side; - change->actual_trigger_ce_value = CustomValue[x][y]; + change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y]; if ((change->can_change && !change_done) || change->has_action) { int x, y; +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { if (Feld[x][y] == element) { @@ -7539,7 +7874,8 @@ static boolean CheckTriggeredElementChangeExt(int x, int 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) @@ -7614,11 +7950,35 @@ static boolean CheckElementChangeExt(int x, int y, change->actual_trigger_side = trigger_side; change->actual_trigger_ce_value = CustomValue[x][y]; + /* special case: trigger element not at (x,y) position for some events */ + if (check_trigger_element) + { + static struct + { + int dx, dy; + } move_xy[] = + { + { 0, 0 }, + { -1, 0 }, + { +1, 0 }, + { 0, 0 }, + { 0, -1 }, + { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, +1 } + }; + + int xx = x + move_xy[MV_DIR_OPPOSITE(trigger_side)].dx; + int yy = y + move_xy[MV_DIR_OPPOSITE(trigger_side)].dy; + + change->actual_trigger_ce_value = CustomValue[xx][yy]; + } + if (change->can_change && !change_done) { ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; - ChangeElement(x, y, p); + + HandleElementChange(x, y, p); change_done = TRUE; } @@ -7932,6 +8292,8 @@ void GameActions() /* ---------- main game synchronization point ---------- */ + InitPlayfieldScanModeVars(); + WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value); if (network_playing && !network_player_action_received) @@ -8061,9 +8423,13 @@ void GameActions() } } +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { - Changed[x][y] = 0; + ChangeCount[x][y] = 0; ChangeEvent[x][y] = -1; /* this must be handled before main playfield loop */ @@ -8133,13 +8499,46 @@ void GameActions() #endif } +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { element = Feld[x][y]; graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]); +#if 0 + printf("::: %d,%d\n", x, y); + + if (element == EL_ROCK) + printf("::: Yo man! Rocks can fall!\n"); +#endif + if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; + else if (ANIM_MODE(graphic) == ANIM_CE_VALUE) + { + int old_gfx_frame = GfxFrame[x][y]; + + GfxFrame[x][y] = CustomValue[x][y]; + +#if 1 + if (GfxFrame[x][y] != old_gfx_frame) +#endif + DrawLevelGraphicAnimation(x, y, graphic); + } + else if (ANIM_MODE(graphic) == ANIM_CE_SCORE) + { + int old_gfx_frame = GfxFrame[x][y]; + + GfxFrame[x][y] = element_info[element].collect_score; + +#if 1 + if (GfxFrame[x][y] != old_gfx_frame) +#endif + DrawLevelGraphicAnimation(x, y, graphic); + } if (ANIM_MODE(graphic) == ANIM_RANDOM && IS_NEXT_FRAME(GfxFrame[x][y], graphic)) @@ -8163,18 +8562,23 @@ 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 printf("::: ChangeDelay == %d\n", ChangeDelay[x][y]); #endif +#if 0 + if (element == EL_CUSTOM_255) + printf("::: ChangeDelay == %d\n", ChangeDelay[x][y]); +#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); @@ -8253,6 +8657,12 @@ void GameActions() else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); +#if 0 + if (element == EL_CUSTOM_255 || + element == EL_CUSTOM_256) + DrawLevelGraphicAnimation(x, y, graphic); +#endif + if (IS_BELT_ACTIVE(element)) PlayLevelSoundAction(x, y, ACTION_ACTIVE); @@ -8312,7 +8722,11 @@ void GameActions() { game.explosions_delayed = FALSE; +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { element = Feld[x][y]; @@ -8346,7 +8760,11 @@ void GameActions() game.magic_wall_time_left--; if (!game.magic_wall_time_left) { +#if 1 + SCAN_PLAYFIELD(x, y) +#else for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++) +#endif { element = Feld[x][y]; @@ -10239,7 +10657,11 @@ int DigField(struct PlayerInfo *player, { int xx, yy; - for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++) +#if 1 + SCAN_PLAYFIELD(xx, yy) +#else + for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++) +#endif { if (Feld[xx][yy] == EL_SP_DISK_YELLOW) Bang(xx, yy); @@ -10300,6 +10722,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); @@ -10498,7 +10951,7 @@ boolean DropElement(struct PlayerInfo *player) PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING); /* needed if previous element just changed to "empty" in the last frame */ - Changed[dropx][dropy] = 0; /* allow at least one more change */ + ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ CheckElementChangeByPlayer(dropx, dropy, new_element, CE_DROPPED_BY_PLAYER, player->index_bit, drop_side); @@ -10538,7 +10991,7 @@ boolean DropElement(struct PlayerInfo *player) nextx = dropx + GET_DX_FROM_DIR(move_direction); nexty = dropy + GET_DY_FROM_DIR(move_direction); - Changed[dropx][dropy] = 0; /* allow at least one more change */ + ChangeCount[dropx][dropy] = 0; /* allow at least one more change */ CheckCollision[dropx][dropy] = 2; }