Exemple #1
0
int main()
{
    SetupAll();
    SetupBalls();
    DoTimers();
    LoadBitmaps();
    DoBlock();
    while (!key[KEY_ESC] && GoGame == 1)
    {
        CheckDead();
        CheckBlock();
        MoveBall();
        if (BallsToDrop > 0)
            DropBalls();
        if (Lives <= 0)
            GoGame = 0;
        DrawBack();
        CheckExplode();
        DrawBalls();
        MoveMouse();
        MoveStoneBlock();
        WaitTimer();
        flip();
    }
    EndOfGame();
    allegro_exit(); //Clean up allegro
    return 0;
}
void BreakOut::Update(game_info* gi, float deltatime)
{
	bool move = false;

	if (gi->state == STATE_BREAKOUT_TRANS)
	{
		gi->rot2 -= TRANSITION_SPEED * deltatime;

		if (gi->rot2 <= 0)
		{
			gi->rot2 = 0;
			engine.ChangeState(gi, STATE_TETRIS);
		}

		engine.PassMessage(MSG_ROT_BOARD2, (gi->rot2 / 180.0f) * 255.0f, 0,0);
		return;
	}

	if (engine.keys[SDLK_LEFT])
	{
		gi->fine -= BREAKOUT_PADDLE_SPEED * deltatime;

		float amt = GetLeftBounds(gi);

		if (gi->fine < amt)
		{
			gi->fine = amt;
		}

		move = true;
	}
	
	if (engine.keys[SDLK_RIGHT])
	{
		gi->fine += BREAKOUT_PADDLE_SPEED * deltatime;

		float amt = GetRightBounds(gi);

		if (gi->fine > amt)
		{
			gi->fine = amt;
		}

		move = true;
	}

	gi->break_out_time -= deltatime;

	if (gi->break_out_time <= 0)
	{
		gi->break_out_time = 0;

		engine.DisplayMessage(STR_YOUSURVIVED);
		engine.audio.PlaySound(SND_CHANGEVIEW);
		engine.ChangeState(gi, STATE_BREAKOUT_TRANS);

		gi->pos = (int)(gi->fine / 0.5f);
		gi->fine = 0;
		return;
	}

	if (gi->ball_fast > 0)
	{
		gi->ball_fast -= deltatime;

		if (gi->ball_fast < 0)
		{
			gi->ball_fast = 0;
			if (gi->ball_dx < 0)
			{
				gi->ball_dx = -BREAKOUT_BALL_SPEED_X;
			}
			else
			{
				gi->ball_dx = BREAKOUT_BALL_SPEED_X;
			}
			if (gi->ball_dy < 0)
			{
				gi->ball_dy = -BREAKOUT_BALL_SPEED_Y;
			}
			else
			{
				gi->ball_dy = BREAKOUT_BALL_SPEED_Y;
			}
		}
	}

	if (move)
	{
		engine.PassMessage(MSG_UPDATEPADDLE, (unsigned char)((gi->fine / 11.0f) * 255.0f), 0, 0);
	}

	// move ball

	// solve for all collisions!

	// wall collisions!

	if (!engine.network_thread)
	{
			if (gi->ball_dx < 0)
			{
				gi->ball_dx = -(BREAKOUT_BALL_SPEED_X + (LEVEL * 0.2));
			}
			else
			{
				gi->ball_dx = (BREAKOUT_BALL_SPEED_X + (LEVEL * 0.2));
			}
			if (gi->ball_dy < 0)
			{
				gi->ball_dy = -(BREAKOUT_BALL_SPEED_Y + (LEVEL * 0.2));
			}
			else
			{
				gi->ball_dy = (BREAKOUT_BALL_SPEED_Y + (LEVEL * 0.2));
			}
	}

	MoveBall(gi,deltatime,-1);

	engine.PassMessage(MSG_UPDATEBALL, ((float)(gi->ball_x) / 20.0f) * 255.0f, ((float)(gi->ball_y) / 20.0f) * 255.0f, 0);

	if (gi->ball_y < -1.5)
	{
		engine.GameOver();
	}
}
void BreakOut::MoveBall(game_info* gi, float t, int last_type)
{
	float cur_t = 1000.0;
	int type_t = 0;
	int board_i = -1;
	int board_j = -1;

	float up_t = CheckBallAgainst(gi, t, -5, 11.75, 10, 11.75);
	float left_t = CheckBallAgainst(gi, t, 0, 13, 0, 0);
	float right_t = CheckBallAgainst(gi, t, 4.5, 13, 4.5, 0);




	// check against borders

	if (gi->ball_dy > 0 && up_t < cur_t && !(1 != last_type))
	{
		cur_t = up_t;
		type_t |= 1;
	}

	if (gi->ball_dx > 0 && right_t < cur_t && !(2 & last_type))
	{
		cur_t = right_t;
		type_t |= 2;
	}

	if (gi->ball_dx < 0 && left_t < cur_t && !(4 & last_type))
	{
		cur_t = left_t;
		type_t |= 4;
	}






	int i,j;


	// check against the blocks

	for (i=0; i<10; i++)
	{
		for (j=0; j<24; j++)
		{
			if (gi->board[i][j] != -1)
			{
				if (CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, (float)(i * 0.5f), (float)(j+1) * 0.5f, 0))
				{
					board_i = i;
					board_j = j;

					j = 24;
					i = 10;
				}
			}
		}
	}





	// collision against paddle

	// for all of the blocks that make up the paddle... check against their edges

	float x,y;

	x = gi->fine;
	y = 0;
	
	switch (gi->curpiece)
	{
	case 0:
		if (gi->curdir % 2)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-1.0, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
		}
		else
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+1.0, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
		}
		break;
	case 1:
		if (gi->curdir % 2)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y-0.5, 1);
		}
		else
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y-0.5, 1);
		}
		break;
	case 2:
		if (gi->curdir % 2)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y-0.5, 1);
		}
		else
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y-0.5, 1);
		}
		break;
	case 3:
		CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
		CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
		CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
		CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y+0.5, 1);
		break;
	case 4:
		if (gi->curdir == 0)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y+0.5, 1);
		}
		else if (gi->curdir == 1)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y+0.5, 1);
		}
		else if (gi->curdir == 2)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y-0.5, 1);
		}
		else
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y-0.5, 1);
		}
		break;
	case 5:
		if (gi->curdir == 0)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y+0.5, 1);
		}
		else if (gi->curdir == 1)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y-0.5, 1);
		}
		else if (gi->curdir == 2)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y-0.5, 1);
		}
		else
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y+0.5, 1);
		}
		break;
	case 6:
		if (gi->curdir == 0)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
		}
		else if (gi->curdir == 1)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
		}
		else if (gi->curdir == 2)
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x+0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
		}
		else
		{
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x-0.5, y, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y+0.5, 1);
			CheckBallAgainstBlock(gi, t, cur_t, type_t, last_type, x, y-0.5, 1);
		}
		break;
	}



	// adjust ball, call again if required

	// no collisions?
	if (type_t == 0)
	{
		// use up all t!
		gi->ball_x += t * gi->ball_dx;
		gi->ball_y += t * gi->ball_dy;
		return;
	}

	// we have a collision, move as far as we can
	gi->ball_x += cur_t * gi->ball_dx;
	gi->ball_y += cur_t * gi->ball_dy;

	engine.audio.PlaySound(SND_BOUNCE);

	// then, change direction, and move the rest of the way

	t -= cur_t;

	if (type_t & ~0x7)
	{
		gi->break_out_consecutives++;
	}

	if (type_t & 1)
	{ // top
		gi->ball_dy = -gi->ball_dy;
	} 
	else if (type_t & 2)
	{ // right
		gi->ball_dx = -gi->ball_dx;
	}
	else if (type_t & 4)
	{ // left
		gi->ball_dx = -gi->ball_dx;
	}

	else if (type_t & 8)
	{ // left side block
		gi->ball_dx = -gi->ball_dx;

		// get rid of block???
		gi->board[board_i][board_j] = -1;

		engine.PassMessage(MSG_REMOVEBLOCK, board_i, board_j, 0);

		gi->score += (2 * 100);
		engine.PassMessage(MSG_APPENDSCORE, 100, 2, 0);
	}
	else if (type_t & 16)
	{ // top side block
		gi->ball_dy = -gi->ball_dy;

		// get rid of block???
		gi->board[board_i][board_j] = -1;

		engine.PassMessage(MSG_REMOVEBLOCK, board_i, board_j, 0);

		gi->score += (2 * 100);
		engine.PassMessage(MSG_APPENDSCORE, 100, 2, 0);
	}
	else if (type_t & 32)
	{ // right side block
		gi->ball_dx = -gi->ball_dx;

		// get rid of block???
		gi->board[board_i][board_j] = -1;

		engine.PassMessage(MSG_REMOVEBLOCK, board_i, board_j, 0);

		gi->score += (2 * 100);
		engine.PassMessage(MSG_APPENDSCORE, 100, 2, 0);
	}
	else if (type_t & 64)
	{ // bottom side block
		gi->ball_dy = -gi->ball_dy;

		// get rid of block???
		gi->board[board_i][board_j] = -1;

		engine.PassMessage(MSG_REMOVEBLOCK, board_i, board_j, 0);

		gi->score += (2 * 100);
		engine.PassMessage(MSG_APPENDSCORE, 100, 2, 0);
	}


		// paddle
	else if (type_t & 128)
	{ 
		if (gi->break_out_consecutives >= 7)
		{
			engine.SendAttack(3);
		}
		else if (gi->break_out_consecutives >= 5)
		{
			engine.SendAttack(2);
		}
		else if (gi->break_out_consecutives >= 4)
		{
			engine.SendAttack(1);
		}

		gi->break_out_consecutives = 0;

		gi->ball_dx = -gi->ball_dx;
	}

	else if (type_t & 256)
	{
		if (gi->break_out_consecutives >= 7)
		{
			engine.SendAttack(3);
		}
		else if (gi->break_out_consecutives >= 5)
		{
			engine.SendAttack(2);
		}
		else if (gi->break_out_consecutives >= 4)
		{
			engine.SendAttack(1);
		}

		gi->break_out_consecutives = 0;

		gi->ball_dy = -gi->ball_dy;
	}

	else if (type_t & 512)
	{
		if (gi->break_out_consecutives >= 7)
		{
			engine.SendAttack(3);
		}
		else if (gi->break_out_consecutives >= 5)
		{
			engine.SendAttack(2);
		}
		else if (gi->break_out_consecutives >= 4)
		{
			engine.SendAttack(1);
		}

		gi->break_out_consecutives = 0;

		gi->ball_dx = -gi->ball_dx;
	}

	else if (type_t & 1024)
	{
		if (gi->break_out_consecutives >= 7)
		{
			engine.SendAttack(3);
		}
		else if (gi->break_out_consecutives >= 5)
		{
			engine.SendAttack(2);
		}
		else if (gi->break_out_consecutives >= 4)
		{
			engine.SendAttack(1);
		}

		gi->break_out_consecutives = 0;

		gi->ball_dy = -gi->ball_dy;		
	}

	// call this again
	MoveBall(gi, t, type_t);
}
Exemple #4
0
/** Game event loop. */
void EventLoop() {

   struct timeval last, current;
   unsigned long elapsedTime;
   int repeat;
   XEvent event;

   SetFirstLevel();

   XSelectInput(display, mainWindow, KeyPressMask | KeyReleaseMask
      | ButtonPressMask | ButtonReleaseMask | ExposureMask);

   shouldExit = 0;

   DoStartDelay();

   gettimeofday(&last, NULL);

   while(!shouldExit) {

      if(didWin) {
         WinLoop();
         NextLevel();
         moveRight = 0;
         moveLeft = 0;
         gettimeofday(&last, NULL);
      }
      if(didLose) {
         Redraw();
         DoStartDelay();
         break;
      }

      while(XPending(display) > 0) {
         XNextEvent(display, &event);
         switch(event.type) {
         case Expose:
            HandleExposeEvent(&event.xexpose);
            break;
         case KeyPress:
            HandleKeyPressEvent(&event.xkey);
            break;
         case KeyRelease:
            HandleKeyReleaseEvent(&event.xkey);
            break;
         case ButtonPress:
            HandleButtonPressEvent();
            break;
         default:
            break;
         }
      }

      if(isPaused) {
         gettimeofday(&last, NULL);
         continue;
      }

      gettimeofday(&current, NULL);
      elapsedTime = (current.tv_sec - last.tv_sec) * 1000000;
      elapsedTime += current.tv_usec - last.tv_usec;

      if(elapsedTime >= SPEED) {
         last = current;

         EraseBall();
         repeat = (int)(((float)elapsedTime / SPEED) + 0.5);
         do {
            if(moveRight && !moveLeft) {
               MoveBallRight();
            } else if(moveLeft && !moveRight) {
               MoveBallLeft();
            }
            MoveBall();
            --repeat;
         } while(repeat);
         DrawBall();

         Redraw();

         if(didDie) {
            didDie = 0;
            DoStartDelay();
            gettimeofday(&last, NULL);
         }

      }

   }
}
Exemple #5
0
void BallScene::Update(float dt)
{
    MoveBall(dt,0,25);
    m_world.Update(dt);
}
Exemple #6
0
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();
	}
}