3
3
********
4
4
* a snake clone for the r0ket
5
5
* created by Flori4n (DrivenHoliday) & MascH (CCCHB tent)
6
+ * snake II implementation by ElSjaako and OriginalSouth
6
7
***************************************/
7
8
8
9
#include <string.h>
14
15
#include <r0ketlib/print.h>
15
16
#include <r0ketlib/keyin.h>
16
17
#include <r0ketlib/select.h>
18
+ #include <rad1olib/systick.h>
17
19
18
20
#include "invfont.c"
19
21
23
25
#define SNAKE_DIM (3)
24
26
#define MIN_SPEED (25)
25
27
#define MAX_SPEED (3)
26
- #define MIN_X 2
27
- #define MAX_X (RESX-3 )
28
- #define MIN_Y 8
29
- #define MAX_Y (RESY-2 )
28
+ #define MIN_X 3
29
+ #define MAX_X (RESX-5 )
30
+ #define MIN_Y 12
31
+ #define MAX_Y (RESY-5 )
30
32
#define SIZE_X ((MAX_X-MIN_X)/SNAKE_DIM)
31
33
#define SIZE_Y ((MAX_Y-MIN_Y)/SNAKE_DIM)
32
34
35
37
#define UP 3
36
38
#define DOWN 1
37
39
40
+ //define how long you have to hold down the button to quit
41
+ #define QUIT_DELAY 1000
42
+
43
+ typedef enum {
44
+ SNAKE_STANDARD ,
45
+ SNAKE_WRAPPING
46
+ } gametype_e ;
47
+
38
48
struct pos_s {
39
49
int x ,y ;
40
50
};
@@ -48,7 +58,7 @@ static void reset();
48
58
static void next_level ();
49
59
static void render_level ();
50
60
static void draw_block ();
51
- static void handle_input ();
61
+ static int handle_input ();
52
62
static void death_anim ();
53
63
static struct pos_s getFood (void );
54
64
static int hitWall ();
@@ -57,70 +67,114 @@ static int hitSelf();
57
67
static void renderHighscore ();
58
68
static int showHighscore ();
59
69
static uint32_t highscore_get ();
70
+ static char * highscore_filename ();
60
71
61
72
int points = 0 ;
62
73
int highscore = 0 ;
74
+ gametype_e gametype = SNAKE_STANDARD ;
63
75
struct snake_s snake = { NULL , 3 , 0 , MIN_SPEED , 2 };
64
76
struct pos_s food ;
65
77
66
78
void ram (void )
67
79
{
68
- int c = 0 , pos = 0 , del = 0 ;
80
+ while ( 1 ) {
69
81
70
- struct pos_s tail [MAX_SNAKE_LEN ];
71
- snake .tail = tail ;
82
+ int c = 0 , pos = 0 ,del = 0 ;
72
83
73
- // load the highscore
74
- highscore = highscore_get () ;
84
+ struct pos_s tail [ MAX_SNAKE_LEN ];
85
+ snake . tail = tail ;
75
86
76
- // initially reset everything
77
- reset ();
87
+ lcdClear ();
78
88
79
- while (1 ) {
80
- if (!(++ c % snake .speed )) {
81
- handle_input ();
82
-
83
- pos = (snake .t_start + 1 ) % MAX_SNAKE_LEN ;
84
- snake .tail [pos ].x = snake .tail [snake .t_start ].x ;
85
- snake .tail [pos ].y = snake .tail [snake .t_start ].y ;
86
-
87
- if (snake .dir == 0 )
88
- snake .tail [pos ].x ++ ;
89
- else if (snake .dir == 1 )
90
- snake .tail [pos ].y ++ ;
91
- else if (snake .dir == 2 )
92
- snake .tail [pos ].x -- ;
93
- else if (snake .dir == 3 )
94
- snake .tail [pos ].y -- ;
95
-
96
- snake .t_start = pos ;
97
-
98
- if (pos < snake .len ) {
99
- del = MAX_SNAKE_LEN - (snake .len - pos );
100
- } else
101
- del = pos - snake .len ;
89
+ setTextColor (0xff ,0b11100000 );
90
+ DoString (0 ,10 , " SNAKE" );
102
91
103
- // remove last, add first line
104
- draw_block ( snake . tail [ del ]. x , snake . tail [ del ]. y , 0xFF );
105
- draw_block ( snake . tail [ pos ]. x , snake . tail [ pos ]. y , 0b00011000 );
92
+ setTextColor ( 0xff , 0x00 );
93
+ DoString ( 0 , RESY / 2 - 33 , " Choose the" );
94
+ DoString ( 0 , RESY / 2 - 25 , " game type:" );
106
95
107
- // check for obstacle hit..
108
- if (hitWall () || hitSelf ()) {
109
- death_anim ();
110
- if (showHighscore ())
111
- break ;
112
- reset ();
113
- } else if (hitFood ())
114
- next_level ();
96
+ setTextColor (0xff ,0x00 );
97
+ DoString (0 , RESY /2 + 10 , " LEFT: standard" );
98
+ DoString (0 , RESY /2 + 18 , " RIGHT: wrapping " );
99
+ DoString (0 , RESY /2 + 26 , " DOWN: quit " );
115
100
116
- lcdDisplay ();
101
+ lcdDisplay ();
102
+
103
+ int key = getInputRaw ();
104
+
105
+ while (1 ) {
106
+ key = getInputWait ();
107
+ getInputWaitRelease ();
108
+
109
+ if (key & BTN_DOWN ) {
110
+ return ;
111
+ } else if (key & BTN_LEFT ) {
112
+ gametype = SNAKE_STANDARD ;
113
+ break ;
114
+ } else if (key & BTN_RIGHT ) {
115
+ gametype = SNAKE_WRAPPING ;
116
+ break ;
117
+ }
117
118
}
118
119
120
+ // load the highscore
121
+ highscore = highscore_get ();
122
+
123
+ // initially reset everything
124
+ reset ();
125
+
126
+ while (1 ) {
127
+ if (!(++ c % snake .speed )) {
128
+ if (handle_input ()) { //handle_input returns 1 to quit
129
+ break ;
130
+ }
131
+
132
+ pos = (snake .t_start + 1 ) % MAX_SNAKE_LEN ;
133
+ snake .tail [pos ].x = snake .tail [snake .t_start ].x ;
134
+ snake .tail [pos ].y = snake .tail [snake .t_start ].y ;
135
+
136
+ if (snake .dir == 0 ) {
137
+ snake .tail [pos ].x ++ ;
138
+ if (gametype == SNAKE_WRAPPING && snake .tail [pos ].x > SIZE_X ) snake .tail [pos ].x = 0 ;
139
+ } else if (snake .dir == 1 ) {
140
+ snake .tail [pos ].y ++ ;
141
+ if (gametype == SNAKE_WRAPPING && snake .tail [pos ].y > SIZE_Y ) snake .tail [pos ].y = 0 ;
142
+ } else if (snake .dir == 2 ) {
143
+ snake .tail [pos ].x -- ;
144
+ if (gametype == SNAKE_WRAPPING && snake .tail [pos ].x < 0 ) snake .tail [pos ].x = SIZE_X ;
145
+ } else if (snake .dir == 3 ) {
146
+ snake .tail [pos ].y -- ;
147
+ if (gametype == SNAKE_WRAPPING && snake .tail [pos ].y < 0 ) snake .tail [pos ].y = SIZE_Y ;
148
+ }
149
+
150
+ snake .t_start = pos ;
151
+
152
+ del = pos - snake .len ;
153
+ if (pos < snake .len ) del += MAX_SNAKE_LEN ;
154
+
155
+ // remove last, add first line
156
+ draw_block (snake .tail [del ].x , snake .tail [del ].y , 0xFF );
157
+ draw_block (snake .tail [pos ].x , snake .tail [pos ].y , 0b00011000 );
158
+
159
+ // check for obstacle hit..
160
+ if (hitWall () || hitSelf ()) {
161
+ death_anim ();
162
+ if (showHighscore ())
163
+ break ;
164
+ highscore = highscore_get ();
165
+ reset ();
166
+ } else if (hitFood ())
167
+ next_level ();
168
+
169
+ lcdDisplay ();
170
+ }
171
+
119
172
#ifdef SIMULATOR
120
- delayms (50 );
173
+ delayms (50 );
121
174
#else
122
- delayms (3 );
175
+ delayms (3 );
123
176
#endif
177
+ }
124
178
}
125
179
}
126
180
@@ -130,8 +184,8 @@ static struct pos_s getFood(void)
130
184
struct pos_s res ;
131
185
132
186
tryagain :
133
- res .x = (getRandom () % (SIZE_X - 1 )) + 1 ;
134
- res .y = (getRandom () % (SIZE_Y - 3 )) + 3 ;
187
+ res .x = (getRandom () % (SIZE_X + 1 ));
188
+ res .y = (getRandom () % (SIZE_Y + 1 )) ;
135
189
136
190
for (i = 0 ; i < snake .len ; i ++ ) {
137
191
pos = (snake .t_start < i ) ? (MAX_SNAKE_LEN - (i - snake .t_start )) : (snake .t_start - i );
@@ -148,14 +202,22 @@ static void reset()
148
202
149
203
// setup the screen
150
204
lcdClear ();
151
- for (i = MIN_X ; i < MAX_X ; i ++ ) {
152
- lcdSetPixel (i ,MIN_Y ,0b000101011 );
153
- lcdSetPixel (i ,MAX_Y ,0b000101011 );
205
+ for (i = MIN_X - 2 ; i < MAX_X + 2 ; i ++ ) {
206
+ lcdSetPixel (i ,MIN_Y - 2 ,0b000101011 );
207
+ lcdSetPixel (i ,MAX_Y + 2 ,0b000101011 );
208
+ if (gametype != SNAKE_WRAPPING ) {
209
+ lcdSetPixel (i ,MIN_Y - 1 ,0b000101011 );
210
+ lcdSetPixel (i ,MAX_Y + 1 ,0b000101011 );
211
+ }
154
212
}
155
213
156
- for (i = MIN_Y ; i < MAX_Y ; i ++ ) {
157
- lcdSetPixel (MIN_X ,i ,0b000101011 );
158
- lcdSetPixel (MAX_X ,i ,0b000101011 );
214
+ for (i = MIN_Y - 2 ; i < MAX_Y + 2 ; i ++ ) {
215
+ lcdSetPixel (MIN_X - 2 ,i ,0b000101011 );
216
+ lcdSetPixel (MAX_X + 2 ,i ,0b000101011 );
217
+ if (gametype != SNAKE_WRAPPING ) {
218
+ lcdSetPixel (MIN_X - 1 ,i ,0b000101011 );
219
+ lcdSetPixel (MAX_X + 1 ,i ,0b000101011 );
220
+ }
159
221
}
160
222
161
223
snake .speed = MIN_SPEED ;
@@ -165,8 +227,6 @@ static void reset()
165
227
166
228
points = 0 ;
167
229
168
- food = getFood ();
169
-
170
230
// create snake in the middle of the field
171
231
snake .tail [0 ].x = SIZE_X /2 ;
172
232
snake .tail [0 ].y = SIZE_Y /2 ;
@@ -175,6 +235,8 @@ static void reset()
175
235
snake .tail [2 ].x = SIZE_X /2 + 2 ;
176
236
snake .tail [2 ].y = SIZE_Y /2 ;
177
237
238
+ food = getFood ();
239
+
178
240
// print initail tail
179
241
draw_block (snake .tail [0 ].x , snake .tail [0 ].y , 0b00011000 );
180
242
draw_block (snake .tail [1 ].x , snake .tail [1 ].y , 0b00011000 );
@@ -187,7 +249,9 @@ static void reset()
187
249
static void draw_block (int x , int y , int set )
188
250
{
189
251
x *= SNAKE_DIM ;
252
+ x += MIN_X ;
190
253
y *= SNAKE_DIM ;
254
+ y += MIN_Y ;
191
255
192
256
lcdSetPixel (x , y , set );
193
257
lcdSetPixel (x + 1 , y , set );
@@ -237,14 +301,15 @@ static void render_level()
237
301
// Dark Green
238
302
setTextColor (0xff ,0b00011000 );
239
303
}
240
- DoString (0 , 0 ,points_string );
304
+ DoString (1 , 1 ,points_string );
241
305
setTextColor (0xff ,0b00000011 );
242
- DoString (MAX_X - 44 ,0 ,highscore_string );
306
+ DoString (MAX_X - 44 ,1 ,highscore_string );
243
307
}
244
308
245
- static void handle_input ()
309
+ static int handle_input ()
246
310
{
247
311
int key = getInputRaw (), dir_old = snake .dir ;
312
+ static int quitWhen = 0 ;
248
313
249
314
if (key & BTN_UP && dir_old != 1 )
250
315
snake .dir = 3 ;
@@ -254,15 +319,26 @@ static void handle_input()
254
319
snake .dir = 2 ;
255
320
else if (key & BTN_RIGHT && dir_old != 2 )
256
321
snake .dir = 0 ;
322
+ else if (key & BTN_ENTER ) {
323
+ if (quitWhen == 0 ) {
324
+ quitWhen = _timectr + QUIT_DELAY /SYSTICKSPEED ;
325
+ } else if (_timectr > quitWhen ) {
326
+ return 1 ; //indicate program should quit
327
+ }
328
+ return 0 ;
329
+ }
330
+ quitWhen = 0 ;
331
+ return 0 ; // program should continue running
257
332
}
258
333
259
334
static int hitWall ()
260
335
{
261
- return ( (snake .tail [snake .t_start ].x * 3 <= MIN_X )
262
- || (snake .tail [snake .t_start ].x * 3 >= MAX_X )
263
- || (snake .tail [snake .t_start ].y * 3 <= MIN_Y )
264
- || (snake .tail [snake .t_start ].y * 3 >= MAX_Y ) ) ?
265
- 1 : 0 ;
336
+ if (gametype == SNAKE_WRAPPING ) return false;
337
+
338
+ return ( (snake .tail [snake .t_start ].x < 0 )
339
+ || (snake .tail [snake .t_start ].x > SIZE_X )
340
+ || (snake .tail [snake .t_start ].y < 0 )
341
+ || (snake .tail [snake .t_start ].y > SIZE_Y ) );
266
342
267
343
}
268
344
@@ -300,9 +376,19 @@ static void death_anim()
300
376
301
377
}
302
378
379
+ static char * highscore_filename ()
380
+ {
381
+ switch (gametype ) {
382
+ case SNAKE_WRAPPING :
383
+ return "snake2.5cr" ;
384
+ default :
385
+ return "snake.5cr" ;
386
+ }
387
+ }
388
+
303
389
static bool highscore_set (uint32_t score )
304
390
{
305
- writeFile ("snake.5cr" , & score , sizeof (uint32_t ));
391
+ writeFile (highscore_filename () , & score , sizeof (uint32_t ));
306
392
307
393
// old r0ket code to get highscore from the world
308
394
#if 0
@@ -323,7 +409,7 @@ static bool highscore_set(uint32_t score)
323
409
static uint32_t highscore_get ()
324
410
{
325
411
uint32_t score = 0 ;
326
- readFile ("snake.5cr" , & score , sizeof (score ));
412
+ readFile (highscore_filename () , & score , sizeof (score ));
327
413
328
414
// old r0ket code to send highscore to the world
329
415
#if 0
@@ -364,9 +450,9 @@ static void renderHighscore()
364
450
setTextColor (0xff ,0b00000011 );
365
451
DoString (RESX /2 - 4 , RESY /2 - 2 , IntToStr (highscore ,6 ,0 ));
366
452
setTextColor (0xff ,0x00 );
367
- DoString (0 , RESY /2 + 18 , " UP to play " );
453
+ DoString (0 , RESY /2 + 18 , " UP to play" );
368
454
DoString (0 , RESY /2 + 26 , "RIGHT to reset HI " );
369
- DoString (0 , RESY /2 + 34 , "DOWN to quit " );
455
+ DoString (0 , RESY /2 + 34 , " DOWN to quit " );
370
456
371
457
lcdDisplay ();
372
458
}
0 commit comments