ReflexBall Rally
 All Data Structures Files Functions Variables Macros
asciidisplay.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 "asciidisplay.h"
4 #include "ansi.h"
5 #include "LED.h"
6 #include "time.h"
7 #include "buttons.h"
8 #include "gameport.h"
9 #include "ascii.h"
10 #include "reflexball.h"
11 
12 const unsigned char ballMenuYPos[4] = { 40, 48, 55, 64 };
13 const unsigned char ballXPos = 85;
14 unsigned char ballY, lastBallY;
15 
16 unsigned char menuState;
17 unsigned long timer;
19 
20 unsigned char xMin, yMin, xMax, yMax;
21 
22 const char *startString = "Press any key to continue";
23 
24 unsigned char strlen_rom(rom const char *string) { // Calculate the length of a string stored in the ROM
25  unsigned char length = 0;
26  while ((char)*string++ != '\0')
27  length++;
28  return length;
29 }
30 
31 void printAscii(rom const char *str, unsigned char size) { // Used to print an ASCII art array at the last saved cursor position
32  unsigned char i;
33 
34  for (i=1;i<=size;i++) {
36  moveCursor(DOWN,i);
37  while ((char)*str != '\0')
38  printf("%c",*str++);
39  str++; // Skip the null-terminater
40  }
42  moveCursor(DOWN,size);
43  saveCursor();
44 }
45 
46 void printAsciiXY(rom const char *str, unsigned char size, unsigned char x, unsigned char y) { // Used to print an ASCII art array at the specifid (x,y)-coordinate
47  unsigned char i, length = strlen_rom(str);
48  for (i=0;i<size;i++) {
49  gotoxy(x,y+i);
50  while ((char)*str != '\0')
51  printf("%c",*str++);
52  str++; // Skip the null-terminater
53  }
54  moveCursor(BACK,length);
55 }
56 
57 void clearMenuBall(unsigned char x, unsigned char y) { // Clear the ball in the menu
58  gotoxy(x,y);
59  printf(" ");
60  gotoxy(x,y+1);
61  printf(" ");
62 }
63 
64 void drawMenuBall(unsigned char x, unsigned char y) { // Draw the ball in the menu
65  const unsigned char top = 238, bottom = 95, slash = '/', backSlash = '\\';
66 
68 
69  lastBallY = y;
70 
71  gotoxy(x,y);
72  printf("%c%c%c%c",slash,top,top,backSlash);
73  gotoxy(x,y+1);
74  printf("%c%c%c%c",backSlash,bottom,bottom,slash);
75 }
76 
77 void moveBall(char dir) { // Move the menu ball up and down
78  if (ballY + dir >= sizeof(ballMenuYPos) || ballY + dir < 0)
79  return;
80 
81  ballY += dir;
83 }
84 
85 void showWon() { // Shown when the user wins the game
86  const char* highscoreString = "Good try! But the highscore is still held by:";
87  clrscr();
88  if (divider == 1) { // Chuck Norris mode
90  moveCursor(DOWN,1);
92  saveCursor();
94  } else {
95  gotoxy(0,0);
96  saveCursor();
97  printAscii(ladyAscii[0],sizeof(ladyAscii)/sizeof(ladyAscii[0]));
98 
100  saveCursor();
102  moveCursor(DOWN,1);
104  saveCursor();
105  printAscii(nowTryAscii[0],sizeof(nowTryAscii)/sizeof(nowTryAscii[0]));
106 
107  moveCursor(DOWN,10);
108  moveCursor(FORWARD,strlen_rom(nowTryAscii[0])/2-strlen(highscoreString)/2);
109  blink(1);
110  printf("%s",highscoreString);
111  blink(0);
112  moveCursor(DOWN,1);
113  moveCursor(BACK,strlen(highscoreString)+strlen_rom(chuckNorrisTextAscii[0])/2-strlen(highscoreString)/2);
114  saveCursor();
116  }
117 
118  while (!getGameportButtons() && !readButtons() && !kbhit()); // Wait for button press
119 }
120 
121 void showGameOver() { // Shown when the user lose
122  clrscr();
123  printAsciiXY(gameOverAscii[0],sizeof(gameOverAscii)/sizeof(gameOverAscii[0]),(xMin+xMax)/2-strlen_rom(gameOverAscii[0])/2,(yMin+yMax)/2-(sizeof(gameOverAscii)/sizeof(gameOverAscii[0]))/2-5);
124  moveCursor(DOWN,1);
125 
126  switch (millis() & 0x7) { // Pseudo random number from 0-7
127  case 0:
130  else
132  saveCursor();
133  printAscii(amigoAscii[0],sizeof(amigoAscii)/sizeof(amigoAscii[0]));
134  break;
135  case 1:
138  else
140  saveCursor();
141  printAscii(driveAscii[0],sizeof(driveAscii)/sizeof(driveAscii[0])); // Center text below "Game Over!"
142  break;
143  case 2:
146  else
148  saveCursor();
149  printAscii(havNoBallsAscii[0],sizeof(havNoBallsAscii)/sizeof(havNoBallsAscii[0])); // Center text below "Game Over!"
150  break;
151  case 3:
154  else
156  saveCursor();
157  printAscii(openEyesAscii[0],sizeof(openEyesAscii)/sizeof(openEyesAscii[0])); // Center text below "Game Over!"
158  break;
159  case 4:
162  else
164  saveCursor();
165  printAscii(patienceAscii[0],sizeof(patienceAscii)/sizeof(patienceAscii[0])); // Center text below "Game Over!"
166  break;
167  case 5:
170  else
172  saveCursor();
173  printAscii(notPassAscii[0],sizeof(notPassAscii)/sizeof(notPassAscii[0])); // Center text below "Game Over!"
174  break;
175  case 6:
178  else
180  saveCursor();
181  printAscii(thereIsNoBallAscii[0],sizeof(thereIsNoBallAscii)/sizeof(thereIsNoBallAscii[0])); // Center text below "Game Over!"
182  break;
183  case 7:
186  else
188  saveCursor();
189  printAscii(deadAscii[0],sizeof(deadAscii)/sizeof(deadAscii[0])); // Center text below "Game Over!"
190  break;
191  }
192  while (!getGameportButtons() && !readButtons() && !kbhit()); // Wait for button press
193 }
194 
195 void initStartMenu(unsigned char newX1, unsigned char newY1, unsigned char newX2, unsigned char newY2) { // Start up the screen shown at startup
196  xMin = newX1;
197  yMin = newY1;
198  xMax = newX2;
199  yMax = newY2;
200 
201  blink(1);
202  gotoxy((xMin+xMax)/2-strlen(startString)/2,(yMin+yMax)/2-10);
203  printf("%s",startString);
204  blink(0);
205 
206  printAsciiXY(wheelAscii[0],sizeof(wheelAscii)/sizeof(wheelAscii[0]),(xMin+xMax)/2-strlen_rom(wheelAscii[0])/2,yMax-sizeof(wheelAscii)/sizeof(wheelAscii[0])-15);
207 
208  gotoxy((xMin+xMax)/2-strlen_rom(titleAscii1[0])/2,(yMin+yMax)/2-25);
209  saveCursor();
210 
211  timer = 0;
212 }
213 
214 unsigned char startMenu() { // Run the animation until a button is pressed
215  if (millis() - timer > 200) {
216  timer = millis();
217 
218  switch (menuState) {
219  case 0:
220  printAscii(titleAscii1[0],sizeof(titleAscii1)/sizeof(titleAscii1[0]));
221  moveCursor(UP,sizeof(titleAscii1)/sizeof(titleAscii1[0]));
222  saveCursor();
223  menuState = 1;
224  break;
225  case 1:
226  printAscii(titleAscii2[0],sizeof(titleAscii2)/sizeof(titleAscii2[0]));
227  moveCursor(UP,sizeof(titleAscii2)/sizeof(titleAscii2[0]));
228  saveCursor();
229  menuState = 0;
230  break;
231  }
232  }
233 
234  if (getGameportButtons()) {
235  oldButtonsWheel = getGameportButtons(); // Update oldButtons value, so it doesn't skip the next menu
236  return 1;
237  } else if (readButtons()) {
238  oldButtonsWheel = readButtons(); // Update oldButtons value, so it doesn't skip the next menu
239  return 1;
240  } else if (kbhit())
241  return 1;
242 
243  return 0;
244 }
245 
246 void printMenu() { // Print the difficulty menu
247  printAsciiXY(menuAscii[0],sizeof(menuAscii)/sizeof(menuAscii[0]),(xMin+xMax)/2-strlen_rom(menuAscii[0])/2,(yMin+yMax)/2-15);
248 
250  moveCursor(DOWN,1);
251  saveCursor();
252 
253  printAscii(easyAscii[0],sizeof(easyAscii)/sizeof(easyAscii[0]));
254  printAscii(mediumAscii[0],sizeof(mediumAscii)/sizeof(mediumAscii[0]));
255  moveCursor(DOWN,1);
256  saveCursor();
257  printAscii(hardAscii[0],sizeof(hardAscii)/sizeof(hardAscii[0]));
258  moveCursor(DOWN,1);
259  saveCursor();
260 
261  menuState = 0;
262  timer = 0;
263 
264  ballY = lastBallY = 0;
266 }
267 
268 unsigned char updateMenu() { // This is run until the user selects a difficulty
269  int input;
270  unsigned char buttons, buttonsClick;
271 
272  switch (menuState) {
273  case 0:
274  if (millis() - timer > 200) {
275  timer = millis();
276  printAscii(chuckAscii1[0],sizeof(chuckAscii1)/sizeof(chuckAscii1[0]));
277  moveCursor(UP,sizeof(chuckAscii1)/sizeof(chuckAscii1[0]));
278  saveCursor();
279  menuState = 1;
280  }
281  break;
282  case 1:
283  if (millis() - timer > 200) {
284  timer = millis();
285  printAscii(chuckAscii2[0],sizeof(chuckAscii2)/sizeof(chuckAscii2[0]));
286  moveCursor(UP,sizeof(chuckAscii2)/sizeof(chuckAscii2[0]));
287  saveCursor();
288  menuState = 0;
289  }
290  break;
291  }
292  buttons = getGameportButtons();
293  if (buttons != oldButtonsWheel) {
294  buttonsClick = buttons & ~oldButtonsWheel; // Only look at the buttons that have changed
295  oldButtonsWheel = buttons;
296 
297  if (buttonsClick & 0x1) // Gear forward
298  moveBall(-1);
299  else if (buttonsClick & 0x4) // Gear backward
300  moveBall(1);
301  else if (buttonsClick & 0xA) { // Either of the wheel buttons
303  return 1;
304  }
305  } else if (kbhit()) {
306  input = getch();
307  if (input == ' ') { // Space
309  return 1;
310  } else if (input == 65) // Up
311  moveBall(-1);
312  else if (input == 66) // Down
313  moveBall(1);
314  } else {
315  buttons = readButtons();
316  if (buttons != oldButtonsBoard) {
317  buttonsClick = buttons & ~oldButtonsBoard; // Only look at the buttons that have changed
318  oldButtonsBoard = buttons;
319 
320  if (buttonsClick & 0x2) { // Center
322  return 1;
323  } else if (buttonsClick & 0x4) // Left
324  moveBall(-1);
325  else if (buttonsClick & 0x1) // Right
326  moveBall(1);
327  }
328  }
329  return 0;
330 }
331 
332 void calculateDifficulty() { // Calculate the difficulty based on the y-coordinates of the ball
333  if (ballY == 0) { // Easy
334  divider = 10;
335  strikerWidth = 30;
336  } else if (ballY == 1) { // Medium
337  divider = 5;
338  strikerWidth = 20;
339  } else if (ballY == 2) { // Hard
340  divider = 2;
341  strikerWidth = 10;
342  } else { // Chuck Norris
343  divider = 1;
344  strikerWidth = 4;
345  }
346 }