static void ProcessGameOver(struct BALL *Ball, struct PADDLE *Paddle) { char OutBuf[255]; snprintf(OutBuf, sizeof OutBuf, "GAME OVER! Score is %d. Hit ESC to exit or space to play again.", Score); Lives = 0; DrawStats(); Lives = 3; Score = 0; DrawMessage(OutBuf); cbreak(); AskAgain: switch (getch()) { case 27: /*27 is ESC.*/ endwin(); exit(0); break; case ' ': break; default: goto AskAgain; } halfdelay(1); DeleteMessage(); DeleteBall(Ball); DeletePaddle(Paddle); DeleteAllBricks(); DeleteAllCharms(); SetLevel(1); /*Set back to the default level again.*/ ResetPaddle(Paddle); ResetBricks(); DrawPaddle(Paddle); DrawAllBricks(); DrawStats(); /*Assume they want to play again.*/ WaitForUserLaunch(); ResetBall(Ball); DrawBall(Ball); DrawAllBricks(); /*Redraw to fix WaitForUserLaunch() goofing.*/ }
void DeleteBallz(ball * ballz){ ball * head = ballz; ball * next; while (head){ next = head->next; DeleteBall(head); head = next; } }
static void GameLoop(struct BALL *const Ball, struct PADDLE *const Paddle) { /*Primary loop where most events get processed.*/ struct BRICKSTRIKE Strike; int Key = 0; int SecTick = 0; Bool PaddleMovedLastTick; DirectionX PaddleMoveDir; int Inc = 0; Bool Flip = false; int SlowBallTicks = 0, BallNukeTicks = 0; while ((Key = getch()) != 27) /*27 is ESC*/ { if (SecTick == 10) { /*We get score every second for just surviving.*/ Score += 2; DrawStats(); SecTick = 0; } ++SecTick; if (Ball->Y == 1) { /*We hit the ceiling.*/ BounceBallY(Ball, DOWN); } else if (Ball->Y >= BRICKTICK_MAX_Y - 2) { /*More happens when we hit the floor.*/ if (!CheckBallHitPaddle(Ball, Paddle)) { DeleteBall(Ball); Ball->Y = BRICKTICK_MAX_Y - 1; DrawBall(Ball); if (Lives == 1) { /*We ran out of lives.*/ ProcessGameOver(Ball, Paddle); } else { --Lives; DrawStats(); WaitForUserLaunch(); DeleteBall(Ball); DeletePaddle(Paddle); ResetBall(Ball); ResetPaddle(Paddle); DrawPaddle(Paddle); DrawBall(Ball); /*Redraw but don't reset.*/ DrawAllBricks(); } } else { BounceBallY(Ball, UP); if (PaddleMovedLastTick) { /*We can "whack" the ball with our Paddle->*/ Ball->DirX = PaddleMoveDir; } else { /*We cut the paddle into thirds for the X direction after bounce.*/ #define PADDLE_THIRD (Paddle->Length / 3) if (Ball->X <= Paddle->X + PADDLE_THIRD) { Ball->DirX = LEFT; } else if (Ball->X > Paddle->X + PADDLE_THIRD && Ball->X <= Paddle->X + (PADDLE_THIRD * 2)) { /*Make whether we hit up or not as a chance.*/ Bool StraightUp = rand() & 1; if (StraightUp) Ball->DirX = X_NEUTRAL; } else { Ball->DirX = RIGHT; } } } } PaddleMovedLastTick = false; /*Bounce off left and right walls.*/ if (Ball->X >= BRICKTICK_MAX_X - 1) { Ball->X = BRICKTICK_MAX_X - 1; BounceBallX(Ball, LEFT); } else if (Ball->X <= 0) { Ball->X = 0; BounceBallX(Ball, RIGHT); } /*Check if a charm hit the paddle.*/ for (Inc = 0; Inc < BRICK_MAX_NUMLINES * BRICK_MAX_PERLINE; ++Inc) { if (Charms[Inc].Type == CHARM_NONE || !Charms[Inc].Dropped || Charms[Inc].Y != BRICKTICK_MAX_Y - 2) continue; if (CheckCharmHitPaddle(Paddle, Charms + Inc)) { void *Ptr = NULL; const char *const Strings[] = { "+1,000 Score", "+1 Lives", "10 Second Slow Ball", "3 second nuke mode" }; switch (Charms[Inc].Type) { case CHARM_SCORE: Ptr = &Score; break; case CHARM_LIFE: Ptr = &Lives; break; case CHARM_SLOW: Ptr = &SlowBallTicks; break; case CHARM_NUKE: Ptr = &BallNukeTicks; break; default: break; } if (Charms[Inc].Type != CHARM_NONE) { /*Show a message on what type of charm we have here.*/ DrawMessage(Strings[Charms[Inc].Type - 1]); fflush(NULL); usleep(500000); DeleteMessage(); DrawAllBricks(); DrawStats(); } /*Do the thing the charm does.*/ ProcessCharmAction(Charms + Inc, Ptr); } /*In any case, we're done with it.*/ DeleteCharm(Charms + Inc); Charms[Inc].Type = CHARM_NONE; } /*We hit a brick.*/ if (BallStruckBrick(Ball, &Strike)) { if (BallNukeTicks == 0) /*Nuclear ball passes through.*/ { switch (Strike.StrikeV) { case STRIKE_TOP: Ball->DirY = UP; break; case STRIKE_BOTTOM: Ball->DirY = DOWN; break; default: break; } switch (Strike.StrikeH) { case STRIKE_LEFT: Ball->DirX = LEFT; break; case STRIKE_RIGHT: Ball->DirX = RIGHT; break; default: { if (Ball->DirX != X_NEUTRAL) break; else { Bool Dir = rand() & 1; Ball->DirX = (DirectionX)Dir; } break; } } } DeleteBrick(Strike.Brick); Score += 100; DrawStats(); if (!BricksLeft()) { /*Move to next level.*/ if (SetLevel(Level + 1)) { /*We have more levels to go before we win.*/ DeleteAllBricks(); DeleteAllCharms(); DeleteBall(Ball); DeletePaddle(Paddle); DrawStats(); Score += 1000; /*Reward for making it this far.*/ Lives = BRICKTICK_NUMLIVES; ResetBall(Ball); ResetPaddle(Paddle); ResetBricks(); DrawAllBricks(); DrawPaddle(Paddle); WaitForUserLaunch(); DrawBall(Ball); DrawAllBricks(); /*Redraw to fix WaitForUserLaunch() goofing.*/ } else { /*WE WON!!!!*/ char WonBuf[256]; snprintf(WonBuf, sizeof WonBuf, "You Won! Score is %d! Hit ESC to exit or space to play again.", Score); DrawMessage(WonBuf); WinRegetch: switch (getch()) { case 27: /*27 is ESC*/ endwin(); exit(0); break; case ' ': { DeleteMessage(); SetLevel(1); Lives = BRICKTICK_NUMLIVES; Score = 0; DeleteAllBricks(); DeleteAllCharms(); DeleteBall(Ball); DeletePaddle(Paddle); DrawStats(); ResetBall(Ball); ResetPaddle(Paddle); ResetBricks(); DrawAllBricks(); DrawPaddle(Paddle); WaitForUserLaunch(); DrawBall(Ball); DrawAllBricks(); /*Redraw to fix WaitForUserLaunch() goofing.*/ continue; /*For the loop we are in.*/ } default: goto WinRegetch; } } continue; } else { /*Charm drops.*/ struct CHARM *Charm = GetCharmByBrick(Strike.Brick); if (Charm) { /*We DO have a charm for this brick.*/ PerformCharmDrop(Charm); /*Mark it dropped.*/ /*Now draw the charm.*/ DrawCharm(Charm); } } } switch (Key) { /*Paddle movement.*/ case KEY_LEFT: MovePaddle(Paddle, LEFT); PaddleMovedLastTick = true; PaddleMoveDir = LEFT; break; case KEY_RIGHT: MovePaddle(Paddle, RIGHT); PaddleMovedLastTick = true; PaddleMoveDir = RIGHT; break; case 's': /*They want to save the game.*/ if (SaveGame(Ball, Paddle)) { DrawMessage("Game saved."); } else { DrawMessage("Failed to save game."); } fflush(NULL); usleep(500000); DeleteMessage(); DrawAllBricks(); /*Redraw bricks if damaged.*/ break; case 'o': /*They want us to load a game.*/ { const Bool LoadedOk = LoadGame(Ball, Paddle); if (LoadedOk) { /*Restore the state.*/ clear(); DrawBorders(); /*Need to redraw these after clearing the screen.*/ DrawBall(Ball); DrawPaddle(Paddle); DrawStats(); DrawAllBricks(); DrawMessage("Game loaded."); } else { DrawMessage("Failed to load game."); } fflush(NULL); usleep(500000); DeleteMessage(); DrawAllBricks(); break; } case ' ': { DrawMessage("PAUSED"); cbreak(); PauseRegetch: switch (getch()) { case ' ': DeleteMessage(); DrawAllBricks(); /*Redraw to fix what deleting the message messed up.*/ halfdelay(1); break; case 27: /*27 is ESC*/ endwin(); exit(0); break; default: goto PauseRegetch; } } default: break; } Flip = !Flip; /*Ball movement, obviously. Flip is used to keep it at half speed if we got a 'slow' charm.*/ if (Flip || SlowBallTicks == 0) MoveBall(Ball); /*Decrement slow ball ticks until zero, then the ball goes fast again.*/ if (SlowBallTicks > 0) --SlowBallTicks; /*Decrement nuclear ball until ticks hit zero.*/ if (BallNukeTicks > 0) --BallNukeTicks; /*Charm movement.*/ for (Inc = 0; Inc < BRICK_MAX_NUMLINES * BRICK_MAX_PERLINE; ++Inc) { if (Charms[Inc].Type == CHARM_NONE || !Charms[Inc].Dropped) continue; if (Flip) MoveCharm(Charms + Inc); } /*Redraw borders in case of terminal resize.*/ DrawBorders(); } }
int main(int argc, char **argv) { int Inc = 1; struct BALL Ball = { 0 }; struct PADDLE Paddle = { 0 }; Bool DoLoadGame = false; int GotoLevel = 0; for (; Inc < argc; ++Inc) { /*Argument parsing.*/ if (!strcmp("--nocolor", argv[Inc])) { UseColor = false; } else if (!strcmp("--version", argv[Inc])) { printf("Bricktick brick breaker v" BRICKTICK_VERSION "\n" "By Subsentient.\n"); fflush(NULL); exit(0); } else if (!strcmp("--help", argv[Inc])) { printf("Command line options:\n\t" "--help: Show this help.\n\t" "--nocolor: Run Bricktick with no color.\n\t" "--version: Display version and exit.\n"); fflush(NULL); exit(0); } else if (!strncmp("--level=", argv[Inc], sizeof "--level=" - 1)) { GotoLevel = atoi(argv[Inc] + sizeof "--level=" - 1); if (GotoLevel > sizeof Levels / sizeof *Levels) { fprintf(stderr, "The maximum level is %d.\n", sizeof Levels / sizeof *Levels); fflush(NULL); exit(1); } } else { fprintf(stderr, "Bad command line argument \"%s\".\n" "Use --help for command line options.\n", argv[Inc]); exit(1); } } initscr(); /*Fire up ncurses.*/ if (COLS < BRICKTICK_MAX_X || LINES < BRICKTICK_MAX_Y) { endwin(); fprintf(stderr, "Please use a console with a resolution of at least %dx%d.\n", BRICKTICK_MAX_X, BRICKTICK_MAX_Y); exit(1); } /*Color not supported.*/ if (!has_colors()) UseColor = false; /*Various ncurses things.*/ noecho(); if (UseColor) { /*Color fireup.*/ start_color(); init_pair(1, COLOR_CYAN, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); init_pair(3, COLOR_BLACK, COLOR_WHITE); init_pair(4, COLOR_BLUE, COLOR_BLACK); init_pair(5, COLOR_GREEN, COLOR_BLACK); init_pair(6, COLOR_YELLOW, COLOR_BLACK); init_pair(7, COLOR_RED, COLOR_BLACK); /*Fire up colors for the bricks.*/ init_pair(BRICK_COLORS_START, COLOR_GREEN, COLOR_BLACK); init_pair(BRICK_COLORS_START + 1, COLOR_BLUE, COLOR_BLACK); init_pair(BRICK_COLORS_START + 2, COLOR_YELLOW, COLOR_BLACK); init_pair(BRICK_COLORS_START + 3, COLOR_MAGENTA, COLOR_BLACK); init_pair(BRICK_COLORS_START + 4, COLOR_CYAN, COLOR_BLACK); init_pair(BRICK_COLORS_END, COLOR_RED, COLOR_BLACK); } /*Draw borders for consoles bigger than our 80x24 playing area.*/ DrawBorders(); /*Greeting.*/ GreetAsk: if (!GotoLevel) { /*If they specified a level let them go straigth to game start.*/ DrawGreeting(); switch (getch()) { case 27: /*27 is ESC key*/ endwin(); exit(0); break; case ' ': clear(); /*Wipe the message from the screen.*/ DrawBorders(); /*Redraw borders.*/ break; case 'o': clear(); DrawBorders(); DoLoadGame = true; LoadGame(&Ball, &Paddle); break; default: goto GreetAsk; } } else { clear(); DrawBorders(); } halfdelay(1); keypad(stdscr, true); #if NCURSES_VERSION_MAJOR >= 5 && NCURSES_VERSION_MINOR >=4 set_escdelay(25); #endif curs_set(0); if (DoLoadGame) { DrawStats(); DrawBall(&Ball); DrawPaddle(&Paddle); DrawAllBricks(); } else { /*Show our initial lives count.*/ DrawStats(); /*Reset to level 1 if we haven't specified a level.*/ SetLevel(GotoLevel ? GotoLevel : 1); ResetBall(&Ball); ResetPaddle(&Paddle); DrawBall(&Ball); DrawPaddle(&Paddle); ResetBricks(); DrawAllBricks(); } /*Wait for L key.*/ WaitForUserLaunch(); DrawAllBricks(); /*Redraw to fix goofing by WaitForUserLaunch().*/ /*Set up the number generator.*/ srand(time(NULL)); /** * Main loop for the game! **/ Reloop: GameLoop(&Ball, &Paddle); DrawMessage("Really quit Bricktick? y/n"); cbreak(); /*When the game loop exits.*/ switch (getch()) { case 'y': case 'Y': break; default: DeleteMessage(); refresh(); halfdelay(1); DrawAllBricks(); /*Fix damage to brick display resulting from the message.*/ goto Reloop; break; } DeleteBall(&Ball); DeletePaddle(&Paddle); endwin(); return 0; }