ReflexBall Rally
All Data Structures Files Functions Variables Macros
reflexball.c
Go to the documentation of this file.
1 #include <eZ8.h> // special encore constants, macros and flash routines
2 #include <sio.h> // special encore serial i/o routines
3 #include "reflexball.h"
4 #include "time.h"
5 #include "levels.h"
6 #include "LED.h"
7 #include "ascii.h"
8 #include "asciidisplay.h"
9 
12 Brick bricks[BRICK_TABLE_HEIGHT][BRICK_TABLE_WIDTH]; // Array of brick structs
13 unsigned char strikerAngle[STRIKER_MAX_WIDTH/2-1+BALL_WIDTH/2-1]; // Deflect angle for the different striker zones
14 unsigned int bricksLives; // Stores the total number of lives of the bricks - used to detect when all the bricks are gone
15 
16 unsigned long gameTimer; // Time of last iteration
17 unsigned char gameStarted, alive; // Variables used to check if the ball is free and if the user is alive
18 
19 unsigned char x1, y1, x2, y2; // Min/max position of the corners
20 
21 unsigned int score, levelScore; // The total score and the score obtained in this level
22 unsigned char divider; // This is the difficulty set in the beginning
23 unsigned char strikerWidth; // This is the striker width determent from the selected difficulty
24 
25 unsigned char lives, level; // Current number of lives and the current level
26 volatile char runOnceBuf[50], ledBuf[50]; // We need this global buffer as the LED code creates a pointer to the memory location
27 
28 char drawCounter = 0, drawCounterMax = 1; // Used to skip a drawing
29 char drawBallNow; // Varaibled used to set if the ball should be drawn even if it should otherwise skip it
30 long lastX, lastY; // Last position of the ball - used to clear the old ball
31 
32 unsigned char restartGame; // True if the user have won the game
33 
34 void printLevel() { // Print the current level on the screen
35  gotoxy(x2-35,y2);
36  printf("Level: %d", level+1);
37 }
38 void printLives() { // Print number of lives on the screen
39  gotoxy(x2-25,y2);
40  printf("Lives: %d", lives);
41 }
42 void printScore() { // Print score of lives on the screen
43  gotoxy(x2-15,y2);
44  printf("Score: %04d$", score);
45 }
46 
47 void showScoreLED() { // Show the score on the LED display
48  sprintf(ledBuf,"%04d",score);
50 }
51 void scrollLiveInGameLED() { // Scrol the number of lives once
52  sprintf(ledBuf,"%04d",score);
53  sprintf(runOnceBuf,"%s$ Lives:%d� %s ", ledBuf, lives, ledBuf); // We have to put a space behind as the LED routine aborts when it loaded the last character in the 5th digit
54 
56 }
57 void scrollLevelUp() { // Scroll level and lives once, when the user levels up
58  sprintf(ledBuf,"%04d", score);
59  sprintf(runOnceBuf,"%s$ Level up!� Level:%d Lives:%d� %s ", ledBuf, level+1, lives, ledBuf); // We have to put a space behind as the LED routine aborts when it loaded the last character in the 5th digit
60 
62 }
63 void scrollAll() { // Scroll level and lives once
64  sprintf(ledBuf,"%04d",score);
65  sprintf(runOnceBuf,"%s$ Level:%d Lives:%d� %s ", ledBuf, level+1, lives, ledBuf); // We have to put a space behind as the LED routine aborts when it loaded the last character in the 5th digit
66 
68 }
69 
70 void dead() { // Called when the ball hit's the ground
71  if(--lives == 0) {
72  delay_ms(1000); // Wait a bit before showing Game Over ASCII string
73  sprintf(ledBuf,"%04d$ Game Over! Score:", score);
75  showGameOver();
76  restartGame = 1;
77  return;
78  } else {
80  printLives();
81  }
82 
83  alive = 0;
84  stopGame();
85 }
86 
87 unsigned char getTerminalCoordinate(long input) { // Convert 18.14 to normal value with correct rounding
88  unsigned char output = input >> FIX14_SHIFT;
89  output += (input >> (FIX14_SHIFT-1)) & 0x1; // Round correctly
90  return output;
91 }
92 
93 void gotoxyBall(long x, long y) { // Goto (x,y)-coordinates from the dongle
95 }
96 
97 void clearBigBall(long x, long y) { // Clear the ball at teh (x,y)-coordinate
98  gotoxyBall(x,y);
99  printf(" ");
100  gotoxyBall(x,y + ((long)1 << FIX14_SHIFT));
101  printf(" ");
102 }
103 
104 void drawBigBall() { // Draw the ball
105  const unsigned char top = 238, bottom = 95, slash = '/', backSlash = '\\';
106 
107  if ((++drawCounter != drawCounterMax && !drawBallNow) || !alive) // Check if we should skip the draweing in this iteration or if the game is not running
108  return;
109  drawCounter = 0;
110  drawBallNow = 0;
111 
113 
114  lastX = ball.x;
115  lastY = ball.y;
116 
117  gotoxyBall(ball.x,ball.y);
118  printf("%c%c%c%c",slash,top,top,backSlash);
119  gotoxyBall(ball.x,ball.y + ((long)1 << FIX14_SHIFT));
120  printf("%c%c%c%c",backSlash,bottom,bottom,slash);
121 }
122 
123 void drawBrick(Brick *brick) { // Draw one brick
124  unsigned char i, j, brickStyle;
125  for (i=0;i<brick->height;i++) {
126  gotoxy(brick->x,brick->y+i);
127  for (j=0;j<brick->width;j++) {
128  if (!brick->lives)
129  brickStyle = ' ';
130  else if (brick->lives == 1)
131  brickStyle = 176;
132  else if (brick->lives == 2)
133  brickStyle = 177;
134  else if (brick->lives == 3)
135  brickStyle = 178;
136  else if (brick->lives == 4)
137  brickStyle = 219;
138  else // Invisible
139  brickStyle = ' ';
140  printf("%c",brickStyle);
141  }
142  }
143 }
144 
145 void checkIteration(unsigned char x, unsigned char y) { // Check if the ball hit's one of the bricks, striker, wall etc.
146  unsigned char i, j, dontDeflectX = 0, dontDeflectY = 0, deflectedX = 0, deflectedY = 0;
147  char distance; // Distance from center to ball position on striker
148  int angle;
149 
150  if ((x > x1 && x+ball.width < x2 && y > y1 && y+ball.height-1 < y2-1) && gameStarted) {
151  for (i=0;i<BRICK_TABLE_HEIGHT;i++) {
152  for (j=0;j<BRICK_TABLE_WIDTH;j++) {
153  if (!bricks[i][j].lives) // Skip if lives == 0
154  continue;
155 
156  if (y-1 == bricks[i][j].y+bricks[i][j].height-1 || y+ball.height-1 == bricks[i][j].y-1 || x+ball.width-1 == bricks[i][j].x-1 || x-1 == bricks[i][j].x+bricks[i][j].width-1)
157  drawBallNow = 1; // Make sure it draws the ball in this iteration
158 
159  // Check if the ball hit a brick
160  if (y <= bricks[i][j].y+bricks[i][j].height-1 && y+ball.height-1 >= bricks[i][j].y && x+ball.width-1 >= bricks[i][j].x && x <= bricks[i][j].x+bricks[i][j].width-1) {
161  score++;
162  levelScore++;
163  printScore();
164  showScoreLED();
165 
166  // Check if the ball hit the top or the bottom of the brick
167  if (y <= bricks[i][j].y+bricks[i][j].height-1 && y+ball.height-1 >= bricks[i][j].y) {
168  if (!deflectedY) {
169  if (x+ball.width-1 == bricks[i][j].x || x+ball.width-2 == bricks[i][j].x || x == bricks[i][j].x+bricks[i][j].width-1 || x == bricks[i][j].x+bricks[i][j].width-2) { // Left or right side
170  if (y+ball.height-1 >= bricks[i][j].y && y <= bricks[i][j].y) { // Top left or right corner on brick
171  if (i > 0 && bricks[i-1][j].lives) { // Make sure that there can actually be a brick above it
172  dontDeflectY = 1; // Don't deflect it
173  //gotoxy(x2-20,2);
174  //printf("Alive above! %04d",dontCounter++);
175  }
176  }
177  if (y <= bricks[i][j].y+bricks[i][j].height-1 && y+ball.height-1 >= bricks[i][j].y+bricks[i][j].height-1) { // Bottom left or right corner on brick
178  if (i+1 < BRICK_TABLE_HEIGHT && bricks[i+1][j].lives) { // Make sure that there can actually be a brick underneath it
179  dontDeflectY = 1; // Don't deflect it
180  //gotoxy(x2-20,2);
181  //printf("Alive below! %04d",dontCounter++);
182  }
183  }
184  } else if (y >= bricks[i][j].y && y+ball.height-1 <= bricks[i][j].y+bricks[i][j].height-1) // Check if we hit the brick directly from the side
185  dontDeflectY = 1;
186 
187  if (y+ball.height-1 >= bricks[i][j].y && y <= bricks[i][j].y) { // Top of brick
188  if (ball.vector.y & 0x80000000) { // Negative
189  dontDeflectY = 1; // Don't deflect it
190  //gotoxy(x2-20,6);
191  //printf("Top negative! %04d",dontCounter++);
192  }
193  }
194  if (y <= bricks[i][j].y+bricks[i][j].height-1 && y+ball.height-1 >= bricks[i][j].y+bricks[i][j].height-1) { // Bottom of brick
195  //gotoxy(x2-20,6);
196  //printf("Bottom ");
197  if (!(ball.vector.y & 0x80000000)) { // Positive
198  dontDeflectY = 1; // Don't deflect it
199  //printf("positive! %04d",dontCounter++);
200  } /*else
201  printf("negative! %04d",dontCounter++);*/
202  }
203 
204  if (!dontDeflectY) {
205  deflectedY = 1;
206  ball.vector.y = -ball.vector.y;
207  ball.y += 2*ball.vector.y;
208  } /*else if (dontDeflectY) {
209  gotoxy(10,4);
210  printf("dontDeflectY: %d",dontCounter++);
211  }*/
212  }
213  }
214  // Check if the ball hit one of the sides of the brick
215  if (x+ball.width-1 == bricks[i][j].x || x+ball.width-2 == bricks[i][j].x || x == bricks[i][j].x+bricks[i][j].width-1 || x == bricks[i][j].x+bricks[i][j].width-2) {
216  if (!deflectedX) {
217  if ((y+ball.height-1 >= bricks[i][j].y && y <= bricks[i][j].y) || (y <= bricks[i][j].y+bricks[i][j].height-1 && y+ball.height-1 >= bricks[i][j].y+bricks[i][j].height-1)) { // Top or bottom of brick
218  if (x+ball.width-1 == bricks[i][j].x || x+ball.width-2 == bricks[i][j].x) { // Top or bottom left side
219  if (j > 0 && bricks[i][j-1].lives) { // Check if there is one alive to the left of the brick
220  dontDeflectX = 1; // Don't deflect it
221  //gotoxy(x2-20,4);
222  //printf("Alive left! %04d",dontCounter++);
223  }
224  }
225  if (x == bricks[i][j].x+bricks[i][j].width-1 || x == bricks[i][j].x+bricks[i][j].width-2) { // Top or bottom right side
226  if (j+1 < BRICK_TABLE_WIDTH && bricks[i][j+1].lives) { // Check if there is one alive to the right of the brick
227  dontDeflectX = 1; // Don't deflect it
228  //gotoxy(x2-20,4);
229  //printf("Alive right! %04d",dontCounter++);
230  }
231  }
232  }
233 
234  if (x+ball.width-1 == bricks[i][j].x || x+ball.width-2 == bricks[i][j].x) { // Left side
235  if (ball.vector.x & 0x80000000) { // Negative
236  dontDeflectX = 1; // Don't deflect it
237  //gotoxy(x2-20,8);
238  //printf("Left negative! %04d",dontCounter++);
239  }
240  }
241  if (x == bricks[i][j].x+bricks[i][j].width-1 || x == bricks[i][j].x+bricks[i][j].width-2) { // Right side
242  if (!(ball.vector.x & 0x80000000)) { // Positive
243  dontDeflectX = 1; // Don't deflect it
244  //gotoxy(x2-20,8);
245  //printf("Right positive! %04d",dontCounter++);
246  }
247  }
248 
249  if (y != bricks[i][j].y) { // It hasn't hit the brick directly from the side
250  if (y < bricks[i][j].y) { // Top
251  if (!(ball.vector.y & 0x80000000) && !(i > 0 && bricks[i-1][j].lives)) { // Check if it is positive and make sure there is no brick above
252  dontDeflectX = 1; // Don't deflect it
253  //gotoxy(x2-20,14);
254  //printf("Top none above! %04d",dontCounter++);
255  }
256  } else { // Bottom
257  if (ball.vector.y & 0x80000000 && !(i+1 < BRICK_TABLE_HEIGHT && bricks[i+1][j].lives)) { // Check if it is negative and make sure there is no brick below
258  dontDeflectX = 1; // Don't deflect it
259  //gotoxy(x2-20,14);
260  //printf("Bottom none below! %04d",dontCounter++);
261  }
262  }
263  }
264 
265  if (!dontDeflectX) {
266  deflectedX = 1;
267  ball.vector.x = -ball.vector.x;
268  ball.x += 2*ball.vector.x;
269  } /*else if (dontDeflectX) {
270  gotoxy(10,2);
271  printf("dontDeflectX: %d",dontCounter++);
272  }*/
273  }
274  }
275  bricks[i][j].lives--;
276  bricksLives--;
277  drawBrick(&bricks[i][j]);
278  if (!bricksLives) {
279  levelUp();
280  return;
281  }
282  ball.vector.x >>= 1; // We need to set this back again before rotating
283  angle = (int)(millis() & 0x7) - 3; // Pseudo random number from -3 to 4
284  //gotoxy(x1+10,y2-10);
285  //printf("Angle: %02d", angle);
286  rotate(&ball.vector, angle); // Slightly rotate the ball from -3 to 4, to make the game more exciting
287  ball.vector.x <<= 1; // The x vector needs to be twice as large due to the y-axis being twice as high on the screen
288  }
289  }
290  }
291 
292  if (dontDeflectX && dontDeflectY) {
293  //gotoxy(x2-20,12);
294  //printf("CornerHit: %d",dontCounter++);
295  ball.vector.y = -ball.vector.y;
296  ball.y += 2*ball.vector.y;
297  ball.vector.x = -ball.vector.x;
298  ball.x += 2*ball.vector.x;
299  }
300  }
301  else if (((y+ball.height-1 > striker.y) || (y+ball.height-1 == striker.y && (x+ball.width <= striker.x || x >= striker.x+striker.width))) && gameStarted) { // If you are below the striker then player must be dead
302  drawBallNow = 1;
303  drawBigBall();
304  dead();
305  return;
306  }
307  else if (gameStarted) {
308  if (x <= x1 || x+ball.width >= x2) {
309  ball.vector.x = -ball.vector.x;
310  ball.x += 2*ball.vector.x;
311  }
312  if ((y <= y1) || (y+ball.height-1 == striker.y && x+ball.width > striker.x && x < striker.x+striker.width)) {
313  if (y+ball.height-1 == striker.y) { // Check if we hit the striker
314  printScore();
315  showScoreLED();
316 
317  distance = x+ball.width-1 - striker.x;
318 
319  if (distance < striker.width/2-1+BALL_WIDTH/2-1) // The ball hit the left side
320  angle = strikerAngle[(((striker.width/2-1)+(BALL_WIDTH/2-1))-1)-distance];
321  else if (distance > striker.width/2+1+BALL_WIDTH/2-1) // The ball hit the right side
322  angle = -(int)strikerAngle[distance-(((striker.width/2+1)+(BALL_WIDTH/2-1))+1)]; // IMPORTANT: remember to cast to int before the minus sign
323  else
324  angle = 0;
325 
326  if (angle != 0) {
327  /*gotoxy(10,20);
328  printf(" ");
329  gotoxy(10,20);
330  printf("Rotating: %d", angle);*/
331 
332 
333  ball.vector.x >>= 1; // We need to set this back again before rotating
334  rotate(&ball.vector,angle);
335 
336  if (((ball.vector.y >> 12) & 0x7) == 0) { // Check if below 1/4 or approximately 15 degrees
337  /*gotoxy(10,16);
338  printf("BeforeY: ");
339  printFix(ball.vector.y,4);*/
340  ball.vector.y = 1 << 12; // 1/4
341  /*printf(" AfterY: ");
342  printFix(ball.vector.y,4);*/
343 
344  /*printf(" BeforeX: ");
345  printFix(ball.vector.x,4);*/
346  if (ball.vector.x & 0x80000000) // Negative
347  ball.vector.x = -(long)15864; // -(cos(arcsin(1/4)) << 14)
348  else
349  ball.vector.x = 15864; // cos(arcsin(1/4)) << 14
350  /*printf(" AfterX: ");
351  printFix(ball.vector.x,4);*/
352  }
353 
354  ball.vector.x <<= 1; // The x vector needs to be twice as large due to the y-axis being twice as high on the screen
355  }
356  /*gotoxy(10,10);
357  printf("%02d %02d",distance,angle);*/
358  }
359  ball.vector.y = -ball.vector.y;
360  ball.y += 2*ball.vector.y;
361  }
362  }
363 
364  if (x == x1+1 || x+ball.width == x2-1 || y == y1+1 || (y+ball.height-1 == striker.y-1 && x+ball.width > striker.x && x < striker.x+striker.width)) // Check if we are next to the sides, top or striker
365  drawBallNow = 1; // If so then draw the ball in this iteration
366 
367  drawBigBall();
368 }
369 
370 void setBallPos(unsigned char x, unsigned char y) { // Set the position of the ball
371  ball.x = (long)x << FIX14_SHIFT;
372  ball.y = (long)y << FIX14_SHIFT;
373 }
374 
375 void iterate() { // Iterate the game
376  if (alive && gameStarted) {
377  ball.x += ball.vector.x;
378  ball.y += ball.vector.y;
379  }
381 }
382 
383 void drawStriker() { // Draw the striker
384  const unsigned char strikerStyle = 223;
385  unsigned char i;
386  gotoxy(striker.x,striker.y);
387  if (divider == 1) // Blink striker if Chuck Norris mode is on
388  blink(1);
389  for (i=0;i<striker.width;i++)
390  printf("%c",strikerStyle);
391  if (divider == 1)
392  blink(0);
393 }
394 
395 void ballPosStriker() { // Position the ball above the striker
396  setBallPos(striker.x+striker.width/2-ball.width/2,striker.y-ball.height);
397  iterate();
398  drawStriker(); // Redraw striker in case the ball clears part of the stikers
399 }
400 
401 void moveStriker(char dir) { // Take care of moving the striker left or right
402  char absDir = dir;
403  if (!lives) // If no lives left then return
404  return;
405  if (dir < 0)
406  absDir = -dir;
407 
408  if ((int)striker.x + dir <= x1)
409  striker.x = x1+1;
410  else if (striker.x+striker.width-1 + dir >= x2)
411  striker.x = x2-striker.width;
412  else
413  striker.x += dir;
414 
415  if (dir < 0) // Left
416  gotoxy(striker.x+striker.width,striker.y);
417  else // Right
418  gotoxy(striker.x-dir,striker.y);
419 
420  for (; absDir > 0; absDir--)
421  printf(" "); // Clear old char
422 
423  drawStriker();
424 
425  if (!gameStarted) {
426  ballPosStriker();
427  if (!alive)
428  startGame();
429  }
430 }
431 
432 void initStriker(unsigned char x, unsigned y, unsigned char width) { // Initialize the striker - this will also calculate the deflect angle for the striker zones
433  unsigned char i, dAngle, strikerZones;
434 
435  if (width > STRIKER_MAX_WIDTH) // Make sure the width is not larger than the array
436  width = STRIKER_MAX_WIDTH;
437 
438  strikerZones = width/2-1+BALL_WIDTH/2-1; // The striker is split up into zones to the left and right of the striker center
439 
440  striker.x = x - width/2;
441  striker.y = y;
442  striker.width = width;
443  drawStriker();
444 
445  dAngle = STRIKER_MAX_ANGLE/strikerZones; // Delta angle between striker characters
446 
447  //gotoxy(10,8);
448  for (i = 1; i <= strikerZones; i++) {
449  strikerAngle[i-1] = dAngle*i; // Fill in the array - the longer distance from the center, the larger angle it will be reflected with
450  //printf("%d ", strikerAngle[i-1]);
451  }
452 }
453 
454 void stopGame() { // Stop the game
455  gameStarted = 0;
456 }
457 
458 void initBricks(char clear) { // Initialize all the bricks, if clear is true then all the bricks will be cleared
459  unsigned char i, j;
460 
461  bricksLives = 0; // Reset
462 
463  for (i=0;i<BRICK_TABLE_HEIGHT;i++) {
464  for (j=0;j<BRICK_TABLE_WIDTH;j++) {
465  bricks[i][j].width = 14;
466  bricks[i][j].height = 2;
467 
468  bricks[i][j].lives = levels[level][i][j]; // Get live from the level array
469  bricksLives += bricks[i][j].lives; // Increment the total number of lives of the bricks
470  bricks[i][j].x = x1+6 + (bricks[i][j].width+1)*j;
471  bricks[i][j].y = y1+3 + (bricks[i][j].height+1)*i;
472  if (bricks[i][j].lives || clear)
473  drawBrick(&bricks[i][j]);
474  }
475  }
476 }
477 
478 void startGame() { // Start a game
479  int startAngle;
480  if (!alive) { // Check if the player were Game Over
481  alive = 1;
482  if (lives == 0) {
483  score = 0;
484  levelScore = 0;
485  showScoreLED();
486  initReflexBall(x1,y1,x2,y2,1);
487 
488  gameTimer = 0;
489  printLives();
490  printScore();
491  printLevel();
492  }
493  ballPosStriker();
494  } else if (!gameStarted) { // The player is not dead yet
495  initVector(&ball.vector,1,0);
496  startAngle = (millis() & 0x7F) - 192; // Calculate a "random" angle from 0-127 (0-89.3 deg) and then subtract 192 (135 deg)
497 
498  //gotoxy(10,6);
499  //printf("Start angle: %02d",(startAngle*360)/512);
500 
501  rotate(&ball.vector, startAngle);
502 
503  /*printf(" ");
504  printFix(ball.vector.x,4);
505  printf(" ");
506  printFix(ball.vector.y,4);*/
507 
508  ball.vector.x <<= 1; // The x vector needs to be twice as large due to the y-axis being twice as high on the screen
509  gameTimer = 0;
510  gameStarted = 1;
511  updateGame();
512  }
513 }
514 
515 void updateGame() { // Update the game - this has to be called frequently
516  int speed = DEFAULT_DIFFICULTY-levelScore/divider; // Calculate teh speed using the score obtained in the current level and the divider set in the start up menu
517  if (speed < MAX_DIFFICULTY || divider == 1) // Limit maximum speed and set maximum speed as default if Chuck Norris mode is enabled
518  speed = MAX_DIFFICULTY;
519 
520  if (speed < UART_MAX_SPEED) // If it gets below this value, we will only draw it every second time or if it hits an object, this is because the UART can not send the characters fast enough
521  drawCounterMax = 2;
522  else
523  drawCounterMax = 1;
524 
525  if (millis() - gameTimer > speed && gameStarted) { // The game is updated if the delta time is larger than the speed
526  gameTimer = millis();
527  iterate();
528  }
529 }
530 
531 void initBall() { // Initialize a new ball at the center of the striker
532  setBallPos(striker.x+striker.width/2-2,striker.y-2); // Initialize the ball position to the striker position, as ballPosStriker will clear this
533  ball.width = BALL_WIDTH; // This has to be even
534  ball.height = BALL_HEIGHT;
535  initVector(&ball.vector,0,0);
536 }
537 void drawLevel(char clear) { // Draw the current level, if clear is true then all the bricks will be cleared
538  unsigned char i;
539 
540  gotoxy(striker.x,striker.y);
541  for (i=0;i<striker.width;i++)
542  printf(" "); // Clear old striker
543  initStriker((x2-x1)/2+x1,y2-1,strikerWidth); // The width of the striker should always be even
544 
545  initBall(); // Initialize to striker position
546 
547  alive = 1;
548  gameStarted = 0;
549  ballPosStriker();
550 
551  printLives();
552  printScore();
553  printLevel();
554 
555  gameTimer = 0;
556 
557  initBricks(clear);
558 }
559 
560 void levelUp() { // Called when the user finishes a level
561  level++;
562  if (level >= sizeof(levels)/sizeof(levels[0])) { // Check if the user won the game
563  showWon(); // This will block until a button is pressed
564  if (divider != 1) { // If not in Chuck Norris mode, then the user wins the game
565  restartGame = 1;
566  return;
567  }
568  initReflexBall(x1,y1,x2,y2,1);
569  return;
570  }
571  lives += 2;
572 
573  levelScore = 0;
574  scrollLevelUp();
575  drawLevel(1);
576 }
577 
578 void initReflexBall(unsigned char newX1, unsigned char newY1, unsigned char newX2, unsigned char newY2, char style) { // Initialize the game
579  unsigned char leftTop, rightTop, leftBot, rightBot, verSide, horSide, leftCross, rightCross;
580 
581  x1 = newX1;
582  y1 = newY1;
583  x2 = newX2;
584  y2 = newY2;
585 
586  if (style) { // Bold
587  leftTop = 201;
588  rightTop = 187;
589  leftBot = 200;
590  rightBot = 188;
591  verSide = 186;
592  horSide = 205;
593  leftCross = 185;
594  rightCross = 204;
595  } else { // Normal
596  leftTop = 218;
597  rightTop = 191;
598  leftBot = 192;
599  rightBot = 217;
600  verSide = 179;
601  horSide = 196;
602  leftCross = 180;
603  rightCross = 195;
604  }
605 
606  lastX = (long)((x1+x2)/2) << FIX14_SHIFT; // Sets the last ball coordinates just above striker, so it clears the ball correctly the first time
607  lastY = (long)(y2-1-BALL_HEIGHT) << FIX14_SHIFT;
608 
609  clrscr(); // Clear the screen
610 
611  // Put the title in the top of the screen - this is done when animateTitle() is called inside updateGame()
612  printAsciiXY(titleAscii1[0],sizeof(titleAscii1)/sizeof(titleAscii1[0]),(x1+x2)/2-strlen_rom(titleAscii1[0])/2,y1/2-(sizeof(titleAscii1)/sizeof(titleAscii1[0]))/2);
613 
614  drawSides(x1,y1,x2,y2,verSide);
615  drawTopBot(x1,y1,x2-x1-1,leftTop,rightTop,horSide);
616 
617  restartGame = 0;
618  level = 0;
619  score = 0;
620  levelScore = 0;
621  lives = NLIVES;
622  drawLevel(0);
623  scrollAll();
624 }