X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=37608e5d5152f84946ad85f2d1c5e92a344d5606;hb=b40c5be44ed492da183f29d9f2f8184391c31cf0;hp=65fff98e2ae17ea72b48b3aa81b902dbcf7aacab;hpb=20ac4856f1acb923be1793a0e9060987f15a1295;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 65fff98e..37608e5d 100644 --- a/src/game.c +++ b/src/game.c @@ -1278,7 +1278,7 @@ void CheckDynamite(int x, int y) void Explode(int ex, int ey, int phase, int mode) { int x, y; - int num_phase = 9, delay = 2; + int num_phase = 9, delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2); int last_phase = num_phase * delay; int half_phase = (num_phase / 2) * delay; int first_phase_after_start = EX_PHASE_START + 1; @@ -1463,6 +1463,9 @@ void Explode(int ex, int ey, int phase, int mode) if (CAN_MOVE(element) || COULD_MOVE(element)) InitMovDir(x, y); DrawLevelField(x, y); + + if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present) + StorePlayer[x][y] = 0; } else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { @@ -1476,7 +1479,15 @@ void Explode(int ex, int ey, int phase, int mode) if (phase == delay) ErdreichAnbroeckeln(SCREENX(x), SCREENY(y)); - DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1)); + graphic += (phase / delay - 1); + + if (IS_PFORTE(Store[x][y])) + { + DrawLevelElement(x, y, Store[x][y]); + DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic); + } + else + DrawGraphic(SCREENX(x), SCREENY(y), graphic); } } @@ -1886,6 +1897,13 @@ void Impact(int x, int y) return; } } + else if ((element == EL_SP_INFOTRON || element == EL_SP_ZONK) && + (smashed == EL_SP_SNIKSNAK || smashed == EL_SP_ELECTRON || + smashed == EL_SP_DISK_ORANGE)) + { + Bang(x, y+1); + return; + } else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK || element == EL_BD_ROCK) @@ -2049,7 +2067,7 @@ void TurnRound(int x, int y) if (element == EL_KAEFER || element == EL_BUTTERFLY) { - TestIfBadThingHitsOtherBadThing(x, y); + TestIfBadThingTouchesOtherBadThing(x, y); if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y)) @@ -2066,7 +2084,7 @@ void TurnRound(int x, int y) else if (element == EL_FLIEGER || element == EL_FIREFLY || element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) { - TestIfBadThingHitsOtherBadThing(x, y); + TestIfBadThingTouchesOtherBadThing(x, y); if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y)) @@ -2730,7 +2748,7 @@ void StartMoving(int x, int y) { #if 1 - TestIfBadThingHitsHero(x, y); + TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]); return; #else /* enemy got the player */ @@ -2920,7 +2938,7 @@ void StartMoving(int x, int y) DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL); if (DONT_TOUCH(element)) - TestIfBadThingHitsHero(x, y); + TestIfBadThingTouchesHero(x, y); return; } @@ -3062,12 +3080,12 @@ void ContinueMoving(int x, int y) if (DONT_TOUCH(element)) /* object may be nasty to player or others */ { - TestIfBadThingHitsHero(newx, newy); - TestIfBadThingHitsFriend(newx, newy); - TestIfBadThingHitsOtherBadThing(newx, newy); + TestIfBadThingTouchesHero(newx, newy); + TestIfBadThingTouchesFriend(newx, newy); + TestIfBadThingTouchesOtherBadThing(newx, newy); } else if (element == EL_PINGUIN) - TestIfFriendHitsBadThing(newx, newy); + TestIfFriendTouchesBadThing(newx, newy); if (CAN_SMASH(element) && direction == MV_DOWN && (newy == lev_fieldy-1 || !IS_FREE(x, newy+1))) @@ -3437,14 +3455,14 @@ void AmoebeAbleger(int ax, int ay) if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) || (neway == lev_fieldy - 1 && newax != ax)) { - Feld[newax][neway] = EL_AMOEBING; + Feld[newax][neway] = EL_AMOEBING; /* simple growth of new amoeba tile */ Store[newax][neway] = element; } else if (neway == ay) - Feld[newax][neway] = EL_TROPFEN; + Feld[newax][neway] = EL_TROPFEN; /* drop left or right from amoeba */ else { - InitMovingField(ax, ay, MV_DOWN); + InitMovingField(ax, ay, MV_DOWN); /* drop dripping out of amoeba */ Feld[ax][ay] = EL_AMOEBA_DRIPPING; Store[ax][ay] = EL_TROPFEN; ContinueMoving(ax, ay); @@ -4232,6 +4250,9 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) SnapField(player, 0, 0); CheckGravityMovement(player); + if (player->MovPos == 0) /* needed for tape.playing */ + player->last_move_dir = MV_NO_MOVING; + if (++player->frame_reset_delay > player->move_delay_value) player->Frame = 0; } @@ -4271,6 +4292,51 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) } } +static void sleep_milliseconds_x(unsigned long milliseconds_delay) +{ + boolean do_busy_waiting = (milliseconds_delay < 5 ? TRUE : FALSE); + +#if defined(PLATFORM_MSDOS) + /* don't use select() to perform waiting operations under DOS/Windows + environment; always use a busy loop for waiting instead */ + do_busy_waiting = TRUE; +#endif + + + + do_busy_waiting = TRUE; + + + + if (do_busy_waiting) + { + /* we want to wait only a few ms -- if we assume that we have a + kernel timer resolution of 10 ms, we would wait far to long; + therefore it's better to do a short interval of busy waiting + to get our sleeping time more accurate */ + + unsigned long base_counter = Counter(), actual_counter = Counter(); + + while (actual_counter < base_counter + milliseconds_delay && + actual_counter >= base_counter) + actual_counter = Counter(); + } + else + { +#if defined(TARGET_SDL) + SDL_Delay(milliseconds_delay); +#else + struct timeval delay; + + delay.tv_sec = milliseconds_delay / 1000; + delay.tv_usec = 1000 * (milliseconds_delay % 1000); + + if (select(0, NULL, NULL, NULL, &delay) != 0) + Error(ERR_WARN, "sleep_milliseconds(): select() failed"); +#endif + } +} + void GameActions() { static unsigned long action_delay = 0; @@ -4288,7 +4354,45 @@ void GameActions() /* ---------- main game synchronization point ---------- */ - WaitUntilDelayReached(&action_delay, action_delay_value); + + +#if 1 + WaitUntilDelayReached(&action_delay, action_delay_value); +#else + { + unsigned long count1 = SDL_GetTicks(), count2, current_ms, test; + + /* + WaitUntilDelayReached(&action_delay, action_delay_value); + */ + + /* + SDL_Delay(20); + */ + + /* + sleep_milliseconds_x(20); + */ + + current_ms = SDL_GetTicks(); + test = -1; + while (current_ms < count1 + 20) + { + current_ms = SDL_GetTicks(); /* busy wait! */ + + if (test != current_ms) + { + Error(ERR_RETURN, "current_ms == %ld", current_ms); + test = current_ms; + } + } + + count2 = SDL_GetTicks(); + Error(ERR_RETURN, "delay == %ld", count2 - count1); + } +#endif + + if (network_playing && !network_player_action_received) { @@ -4436,8 +4540,10 @@ void GameActions() AmoebeWaechst(x, y); else if (element == EL_DEAMOEBING) AmoebeSchrumpft(x, y); +#if 0 else if (IS_AMOEBALIVE(element)) AmoebeAbleger(x, y); +#endif else if (element == EL_LIFE || element == EL_LIFE_ASYNC) Life(x, y); else if (element == EL_ABLENK_EIN) @@ -4521,6 +4627,44 @@ void GameActions() } } +#if 1 + /* new experimental amoeba growth stuff*/ +#if 1 + if (!(FrameCounter % 8)) +#endif + { + static unsigned long random = 1684108901; + + for (i = 0; i < level.amoeba_speed * 28 / 8; i++) + { +#if 0 + x = (random >> 10) % lev_fieldx; + y = (random >> 20) % lev_fieldy; +#else + x = RND(lev_fieldx); + y = RND(lev_fieldy); +#endif + element = Feld[x][y]; + + if (!IS_PLAYER(x,y) && + (element == EL_LEERRAUM || + element == EL_ERDREICH || + element == EL_MORAST_LEER || + element == EL_BLURB_LEFT || + element == EL_BLURB_RIGHT)) + { + if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBE_NASS) || + (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBE_NASS) || + (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBE_NASS) || + (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBE_NASS)) + Feld[x][y] = EL_TROPFEN; + } + + random = random * 129 + 1; + } + } +#endif + #if 0 if (game.explosions_delayed) #endif @@ -4798,7 +4942,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, BuryHero(player); } else - TestIfBadThingHitsHero(new_jx, new_jy); + TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir); return MF_MOVING; } @@ -4970,7 +5114,7 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) player->last_move_dir = MV_NO_MOVING; } - TestIfHeroHitsBadThing(jx, jy); + TestIfHeroTouchesBadThing(jx, jy); if (!player->active) RemoveHero(player); @@ -5065,7 +5209,7 @@ void ScrollScreen(struct PlayerInfo *player, int mode) ScreenMovDir = MV_NO_MOVING; } -void TestIfGoodThingHitsBadThing(int goodx, int goody) +void TestIfGoodThingHitsBadThing(int goodx, int goody, int move_dir) { int i, killx = goodx, killy = goody; static int xy[4][2] = @@ -5075,7 +5219,7 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) { +1, 0 }, { 0, +1 } }; - static int harmless[4] = + static int xy_dir[4] = { MV_UP, MV_LEFT, @@ -5098,11 +5242,12 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) element = MovingOrBlocked2ElementIfNotLeaving(x, y); #endif - if (DONT_TOUCH(element)) + /* 1st case: good thing is moving towards DONT_GO_TO style bad thing; + 2nd case: DONT_TOUCH style bad thing does not move away from good thing + */ + if ((DONT_GO_TO(element) && move_dir == xy_dir[i]) || + (DONT_TOUCH(element) && MovDir[x][y] != xy_dir[i])) { - if (MovDir[x][y] == harmless[i]) - continue; - killx = x; killy = y; break; @@ -5125,9 +5270,10 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) } } -void TestIfBadThingHitsGoodThing(int badx, int bady) +void TestIfBadThingHitsGoodThing(int badx, int bady, int move_dir) { int i, killx = badx, killy = bady; + int bad_element = Feld[badx][bady]; static int xy[4][2] = { { 0, -1 }, @@ -5135,7 +5281,7 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) { +1, 0 }, { 0, +1 } }; - static int harmless[4] = + static int xy_dir[4] = { MV_UP, MV_LEFT, @@ -5143,7 +5289,7 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) MV_DOWN }; - if (Feld[badx][bady] == EL_EXPLODING) /* skip just exploding bad things */ + if (bad_element == EL_EXPLODING) /* skip just exploding bad things */ return; for (i=0; i<4; i++) @@ -5157,20 +5303,31 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) element = Feld[x][y]; - if (IS_PLAYER(x, y)) - { - killx = x; - killy = y; - break; - } - else if (element == EL_PINGUIN) + /* 1st case: good thing is moving towards DONT_GO_TO style bad thing; + 2nd case: DONT_TOUCH style bad thing does not move away from good thing + */ + if ((DONT_GO_TO(bad_element) && move_dir == xy_dir[i]) || + (DONT_TOUCH(bad_element) && MovDir[x][y] != xy_dir[i])) { - if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y)) - continue; + /* good thing is player or penguin that does not move away */ + if (IS_PLAYER(x, y)) + { + struct PlayerInfo *player = PLAYERINFO(x, y); - killx = x; - killy = y; - break; + if (bad_element == EL_ROBOT && player->last_move_dir) + continue; /* robot does not kill player if he moves */ + + killx = x; + killy = y; + break; + } + else if (element == EL_PINGUIN && + (MovDir[x][y] != xy_dir[i] || !IS_MOVING(x, y))) + { + killx = x; + killy = y; + break; + } } } @@ -5180,6 +5337,24 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) { struct PlayerInfo *player = PLAYERINFO(killx, killy); +#if 0 + int dir = player->MovDir; + int newx = player->jx + (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0); + int newy = player->jy + (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0); + + if (Feld[badx][bady] == EL_ROBOT && player->last_move_dir && + newx != badx && newy != bady) + ; /* robot does not kill player if he moves */ + else + printf("-> %d\n", player->MovDir); + + if (Feld[badx][bady] == EL_ROBOT && player->last_move_dir && + newx != badx && newy != bady) + ; /* robot does not kill player if he moves */ + else + ; +#endif + if (player->shield_active_time_left > 0) Bang(badx, bady); else if (!PLAYER_PROTECTED(killx, killy)) @@ -5190,27 +5365,37 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) } } -void TestIfHeroHitsBadThing(int x, int y) +void TestIfHeroTouchesBadThing(int x, int y) { - TestIfGoodThingHitsBadThing(x, y); + TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING); } -void TestIfBadThingHitsHero(int x, int y) +void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir) { - TestIfBadThingHitsGoodThing(x, y); + TestIfGoodThingHitsBadThing(x, y, move_dir); } -void TestIfFriendHitsBadThing(int x, int y) +void TestIfBadThingTouchesHero(int x, int y) { - TestIfGoodThingHitsBadThing(x, y); + TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING); } -void TestIfBadThingHitsFriend(int x, int y) +void TestIfBadThingRunsIntoHero(int x, int y, int move_dir) { - TestIfBadThingHitsGoodThing(x, y); + TestIfBadThingHitsGoodThing(x, y, move_dir); } -void TestIfBadThingHitsOtherBadThing(int badx, int bady) +void TestIfFriendTouchesBadThing(int x, int y) +{ + TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING); +} + +void TestIfBadThingTouchesFriend(int x, int y) +{ + TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING); +} + +void TestIfBadThingTouchesOtherBadThing(int badx, int bady) { int i, killx = badx, killy = bady; static int xy[4][2] = @@ -5290,7 +5475,8 @@ void RemoveHero(struct PlayerInfo *player) player->present = FALSE; player->active = FALSE; - StorePlayer[jx][jy] = 0; + if (!ExplodeField[jx][jy]) + StorePlayer[jx][jy] = 0; for (i=0; i