Statistics
| Branch: | Revision:

root / main.c @ 87d0c022

History | View | Annotate | Download (20.6 KB)

1
#define F_CPU 16000000L
2

    
3
#include <inttypes.h>
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7
#include <avr/pgmspace.h>
8
#include "bricks.h"
9
#include "scorefont.h"
10

    
11
//let's make our lives easier :)
12
#define PORT_(port) PORT ## port
13
#define DDR_(port)  DDR  ## port
14
#define PIN_(port)  PIN  ## port
15
#define PORT(port) PORT_(port)
16
#define DDR(port)  DDR_(port)
17
#define PIN(port)  PIN_(port)
18

    
19
// wallboard pins:
20
#define WALLBOARD_PORT         B
21
#define CLOCK_PIN         PB0
22
#define DATA_GREEN_PIN         PB3
23
#define DATA_RED_PIN         PB1
24
#define OUTPUT_ENABLE_PIN PB2
25
// address lines - please note that the address lines have to be
26
// on the same port and in the current implementation are on 0-3
27
#define ADDRESS_PORT         C
28
#define A0                 PC0
29
#define A1                 PC1
30
#define A2                 PC2
31
#define A3                 PC3
32

    
33
// note that both controllers are on the same port, the reason is
34
// controllerOffset for faster input handling
35
#define CONTROLLER0_PORT   D
36
#define CONTROLLER0_PLAYER0_LEFT   PD7
37
#define CONTROLLER0_PLAYER0_RIGHT  PD6
38
#define CONTROLLER0_PLAYER0_DOWN   PD5
39
#define CONTROLLER0_PLAYER0_ROTATE PD4
40
#define CONTROLLER1_PORT   D
41
#define CONTROLLER1_PLAYER0_LEFT   PD3
42
#define CONTROLLER1_PLAYER0_RIGHT  PD2
43
#define CONTROLLER1_PLAYER0_DOWN   PD1
44
#define CONTROLLER1_PLAYER0_ROTATE PD0
45

    
46
// control mappings for atari joystick
47
#define PLAYER0_LEFT   0b0100
48
#define PLAYER0_DOWN   0b0010 
49
#define PLAYER0_RIGHT  0b1000
50
#define PLAYER0_ROTATE 0b0001
51

    
52
#define PLAYER1_LEFT   0b1000
53
#define PLAYER1_DOWN   0b0010 
54
#define PLAYER1_RIGHT  0b0100
55
#define PLAYER1_ROTATE 0b0001
56

    
57
// note NOGAMEAREA needs has to be one pixel bigger
58
// because we are lazy in moveSpriteHorizontal (forward check)
59
#define NOGAMEAREA 0b111111111
60
#define TICKS 40
61
#define NUMBER_OF_PLAYERS 2
62

    
63
struct player;
64

    
65
typedef struct sprite {
66
        volatile int8_t offset;
67
        volatile int8_t yLowerPos;
68
        volatile uint16_t block[4];
69
        volatile uint16_t raw;
70
        volatile struct player *owner;
71
        } sprite_t;
72

    
73
typedef struct player {
74
        volatile uint16_t score;
75
        volatile int8_t gameAreaStart;
76
        volatile int8_t gameAreaEnd;
77
        volatile sprite_t sprite;
78
        volatile uint8_t mirrored;
79
        volatile uint8_t controllerOffset;
80
        volatile uint8_t controllerInputMask;
81
        volatile sprite_t nextSprite;
82
        } player_t;
83

    
84
int main(void);
85
inline void redDot(void);
86
inline void greenDot(void);
87
inline void yellowDot(void);
88
inline void noDot(void);
89
inline void OE(void);
90
inline void ODE(void);
91
void loopLines(void);
92
void rotateLeft(sprite_t* sprite);
93
void moveFlyingRowsDown(player_t* player);
94
void moveSpriteDown(sprite_t* sprite);
95
void clearCompleteLines(player_t* player);
96
void rawToBlock(uint16_t block[4], uint16_t raw, int8_t offset);
97
void moveSpriteToLines(sprite_t* sprite);
98
uint8_t checkPlayerSpriteForCollision(player_t* player, uint16_t block[4], int8_t lookahead); // lookahead -1 -> look down
99
void moveSpriteHorizontal(volatile sprite_t *sprite, int8_t dir); // -1 if left, 1 if right
100
void handleGamepadInput(player_t* player, uint8_t player_number, uint8_t input);
101
inline void printLine(int16_t line, uint8_t round, sprite_t* sprite, uint8_t player_number);
102
static inline void drawGameArea(player_t player[NUMBER_OF_PLAYERS]);
103
void gameOver(player_t* player);
104
void setNewSprite(volatile sprite_t* sprite);
105
void drawScore(uint16_t* score, uint8_t round);
106

    
107
volatile uint16_t lines[90] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
108
volatile player_t player[NUMBER_OF_PLAYERS];
109

    
110
volatile uint8_t keypressCounter = 0;
111

    
112
int main(){
113
        // hardware init
114
        // clock, data and output enable
115
        DDR(WALLBOARD_PORT) |= (1<<CLOCK_PIN) | (1<<DATA_RED_PIN) | (1<<DATA_GREEN_PIN) | (1<<OUTPUT_ENABLE_PIN);
116
        // gamepad (PD7 is for bootloadstart):
117
        // 7...4 left down right rotate
118
        //
119
        // move > rotate > down
120
        DDR(CONTROLLER0_PORT) &= ~((1<<CONTROLLER0_PLAYER0_LEFT) | (1<<CONTROLLER0_PLAYER0_RIGHT) | (1<<CONTROLLER0_PLAYER0_DOWN) | (1<<CONTROLLER0_PLAYER0_ROTATE));
121
        PORT(CONTROLLER0_PORT) |= (1<<CONTROLLER0_PLAYER0_LEFT) | (1<<CONTROLLER0_PLAYER0_RIGHT) | (1<<CONTROLLER0_PLAYER0_DOWN) | (1<<CONTROLLER0_PLAYER0_ROTATE);
122
        DDR(CONTROLLER1_PORT) &= ~((1<<CONTROLLER1_PLAYER0_LEFT) | (1<<CONTROLLER1_PLAYER0_RIGHT) | (1<<CONTROLLER1_PLAYER0_DOWN) | (1<<CONTROLLER1_PLAYER0_ROTATE));
123
        PORT(CONTROLLER1_PORT) |= (1<<CONTROLLER1_PLAYER0_LEFT) | (1<<CONTROLLER1_PLAYER0_RIGHT) | (1<<CONTROLLER1_PLAYER0_DOWN) | (1<<CONTROLLER1_PLAYER0_ROTATE);
124
        // address lines:
125
        DDR(ADDRESS_PORT) |= (1<<A3) | (1<<A2) | (1<<A1) | (1<<A0);
126

    
127
        // init player
128
        player[0].score = 0;
129
        player[0].gameAreaStart = 0;
130
        player[0].gameAreaEnd = 28;
131
        player[0].sprite.owner = (player_t*)&player[0];
132
        setNewSprite((sprite_t*)&(player[0].sprite));
133
        player[0].mirrored = 0;
134
        player[0].controllerInputMask = (1<<CONTROLLER0_PLAYER0_LEFT) | (1<<CONTROLLER0_PLAYER0_DOWN) | (1<<CONTROLLER0_PLAYER0_RIGHT) | (1<<CONTROLLER0_PLAYER0_ROTATE);
135
        player[0].controllerOffset = 4;
136
        player[0].nextSprite.owner = (player_t*)&player[0];
137
        setNewSprite((sprite_t*)&(player[0].nextSprite));
138
        // next one
139
        player[1].score = 0;
140
        player[1].gameAreaStart = 37;
141
        player[1].gameAreaEnd = 65;
142
        player[1].sprite.owner = (player_t*)&player[1];
143
        setNewSprite((sprite_t*)&(player[1].sprite));
144
        player[1].mirrored = 1;
145
        player[1].controllerInputMask = (1<<CONTROLLER1_PLAYER0_LEFT) | (1<<CONTROLLER1_PLAYER0_DOWN) | (1<<CONTROLLER1_PLAYER0_RIGHT) | (1<<CONTROLLER1_PLAYER0_ROTATE);
146
        player[1].controllerOffset = 0;
147
        player[1].nextSprite.owner = (player_t*)&player[1];
148
        setNewSprite((sprite_t*)&(player[1].nextSprite));
149
        while(1){
150
                for(uint8_t delay = 0; delay < TICKS; delay++){
151
                        drawGameArea((player_t*)player);
152
                        if(delay%(TICKS/(NUMBER_OF_PLAYERS)) == 0){
153
                                for(uint8_t playerNumber = 0; playerNumber < NUMBER_OF_PLAYERS; playerNumber++){ //fair handing of input
154
                                        handleGamepadInput(&player[playerNumber], playerNumber,
155
                                                                ((~PIN(CONTROLLER0_PORT))& player[playerNumber].controllerInputMask)
156
                                                                        >>player[playerNumber].controllerOffset);
157
                                }
158
                        }
159
                }
160
                for(uint8_t playerNumber = 0; playerNumber < NUMBER_OF_PLAYERS; playerNumber++){
161
                        moveSpriteDown((sprite_t*)&(player[playerNumber].sprite));
162
                        clearCompleteLines((player_t*)&player[playerNumber]);
163
                        moveFlyingRowsDown((player_t*)&player[playerNumber]);
164
                }
165
        }
166
}
167

    
168
void setNewSprite(volatile sprite_t* sprite){
169
        (*sprite).yLowerPos = (*((*sprite).owner)).gameAreaEnd-2;
170
        (*sprite).raw = pgm_read_word(bricks+(keypressCounter%(sizeof(bricks)/sizeof(uint16_t))));
171
        (*sprite).offset = 10;
172
        rawToBlock((uint16_t*)(*sprite).block, (*sprite).raw, (*sprite).offset);
173
        keypressCounter++;
174
}
175

    
176
void gameOver(player_t* player){
177
        for(int16_t line = (*player).gameAreaEnd; line >= (*player).gameAreaStart; line--){
178
                lines[line] = 0x0000;
179
        }
180
        (*player).score = 0;
181
        setNewSprite((sprite_t*)&((*player).sprite));
182
}
183

    
184
void drawScore(uint16_t* score, uint8_t round){
185
        if((*score) & (1<<round)){
186
                redDot();
187
        }
188
        else{
189
                noDot();
190
        }
191
}
192

    
193
inline void printYellowBar(void){
194
        yellowDot();
195
}
196

    
197
inline void printGreenBar(void){
198
        greenDot();
199
}
200

    
201
inline void printRedBar(void){
202
        redDot();
203
}
204

    
205
inline void printEmptyBar(void){
206
        noDot();
207
}
208

    
209
inline void printScoreFontLine(uint8_t scoreNibble, uint8_t step, uint8_t mirror){
210
        if(mirror){
211
                for(int8_t i = 7; i >=0; i--){
212
                        if(score_font[scoreNibble][step] & (1<<i)){
213
                                yellowDot();
214
                        }
215
                        else{
216
                                noDot();
217
                        }
218
                }
219
        }
220
        else{
221
                for(uint8_t i = 0; i < 8; i++){
222
                        if(score_font[scoreNibble][step] & (1<<i)){
223
                                yellowDot();
224
                        }
225
                        else{
226
                                noDot();
227
                        }
228
                }
229
        }
230
}
231

    
232
static inline void drawGameArea(player_t player[NUMBER_OF_PLAYERS]){
233
        PORT(ADDRESS_PORT) = 0;
234
        for(uint8_t round = 0; round < 16; /*round++*/){
235
                for(int16_t line = player[1].gameAreaStart; line <= player[1].gameAreaEnd; line++){
236
                        printLine(line, 15-round/2, (sprite_t*)&(player[1].sprite), 1);
237
                }
238
                printGreenBar();
239
                for(int16_t line = 0; line < 8 ; line++){ //player[1].gameAreaEnd; line < player[0].gameAreaStart; line--){
240
                        if(round <=15 && round >=12){
241
                                printScoreFontLine((player[1].score>>4)&0x0f,15-round, 1);
242
                                break;
243
                        }
244
                        if(round <= 10 && round >= 7){
245
                                printScoreFontLine((player[1].score)&0x0f,10-round, 1);
246
                                break;
247
                        }
248
                        if(round == 5){
249
                                printYellowBar();
250
                        }
251
                        else{
252
                                if(round < 4){
253
                                        if(((line >= 2 && line <= 5)) && (player[1].nextSprite.block[line-2] & (1<<(14-round)))){
254
                                                yellowDot();
255
                                        }
256
                                        else{
257
                                                noDot();
258
                                        }
259
                                }
260
                                else{
261
                                        noDot();
262
                                }
263
                        }
264
                }
265
                printYellowBar();
266
                for(int16_t line = 0; line < 8 ; line++){
267
                        if(round >=0 && round <= 3){
268
                                printScoreFontLine((player[0].score>>4)&0x0f, round, 0);
269
                                break;
270
                        }
271
                        if(round >=5 && round <= 8){
272
                                printScoreFontLine(player[0].score&0x0f, round-5, 0);
273
                                break;
274
                        }
275
                        if(round == 10){
276
                                printYellowBar();
277
                        }
278
                        else{
279
                                if(round > 11){
280
                                        if(((line >= 2 && line <= 5)) && (player[0].nextSprite.block[5-line] & (1<<(25-round)))){
281
                                                yellowDot();
282
                                        }
283
                                        else{
284
                                                noDot();
285
                                        }
286
                                }
287
                                else{
288
                                        noDot();
289
                                }
290
                        }
291
                }
292
                printRedBar();
293
                for(int16_t line = player[0].gameAreaEnd; line >= player[0].gameAreaStart; line--){
294
                        printLine(line, 15-round/2, (sprite_t*)&(player[0].sprite), 0);
295
                }
296

    
297
                OE();
298
                _delay_us(151);
299
                ODE();
300
                round++;
301
                PORT(ADDRESS_PORT) = round;
302
                _delay_us(10); // avoid ghosting
303
        }
304
}
305

    
306
inline void printLine(int16_t line, uint8_t round, sprite_t* sprite, uint8_t player_number){
307
        if((1<<round) & lines[line]){
308
                yellowDot();
309
                yellowDot();
310
        }
311
        else{
312
                if((*sprite).yLowerPos <= line && (*sprite).yLowerPos+4 > line){
313
                        if((1<<round) & (*sprite).block[line-(*sprite).yLowerPos]){
314
                                switch(player_number){
315
                                        case 0:
316
                                                redDot();
317
                                                redDot();
318
                                                break;
319
                                        case 1:
320
                                                greenDot();
321
                                                greenDot();
322
                                                break;
323
                                        default:
324
                                                yellowDot();
325
                                                yellowDot();
326
                                                break;
327
                                }
328
                        }
329
                        else{
330
                                noDot();
331
                                noDot();
332
                        }
333
                }
334
                else{
335
                        noDot();
336
                        noDot();
337
                }
338
        }
339
}
340

    
341
void handleGamepadInput(player_t* player, uint8_t player_number, uint8_t input){
342
        if(player_number == 0){
343
                switch(input){
344
                        // move > rotate > down
345
                        case (PLAYER0_LEFT | PLAYER0_DOWN | PLAYER0_RIGHT | PLAYER0_ROTATE):
346
                                keypressCounter+=2;
347
                        case (PLAYER0_DOWN | PLAYER0_ROTATE):
348
                                rotateLeft((sprite_t*)&((*player).sprite));
349
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
350
                                moveSpriteDown((sprite_t*)&((*player).sprite));
351
                                keypressCounter+=2;
352
                                break;
353
                        case (PLAYER0_LEFT | PLAYER0_DOWN | PLAYER0_RIGHT):
354
                                keypressCounter+=2;
355
                        case (PLAYER0_DOWN):
356
                                moveSpriteDown((sprite_t*)&((*player).sprite));
357
                                keypressCounter+=1;
358
                                break;
359
                        case (PLAYER0_RIGHT):
360
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
361
                                keypressCounter+=1;
362
                                break;
363
                        case (PLAYER0_LEFT | PLAYER0_RIGHT | PLAYER0_ROTATE):
364
                                keypressCounter+=1;
365
                        case (PLAYER0_RIGHT | PLAYER0_ROTATE):
366
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
367
                                keypressCounter+=1;
368
                        case (PLAYER0_ROTATE):
369
                                rotateLeft((sprite_t*)&((*player).sprite));
370
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
371
                                keypressCounter+=1;
372
                                break;
373
                        case (PLAYER0_DOWN | PLAYER0_RIGHT):
374
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
375
                                moveSpriteDown((sprite_t*)&((*player).sprite));
376
                                keypressCounter+=2;
377
                                break;
378
                        case (PLAYER0_DOWN | PLAYER0_RIGHT | PLAYER0_ROTATE):
379
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
380
                                rotateLeft((sprite_t*)&((*player).sprite));
381
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
382
                                moveSpriteDown((sprite_t*)&((*player).sprite));
383
                                keypressCounter+=3;
384
                                break;
385
                        case (PLAYER0_LEFT):
386
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
387
                                keypressCounter+=1;
388
                                break;
389
                        case (PLAYER0_LEFT | PLAYER0_ROTATE):
390
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
391
                                rotateLeft((sprite_t*)&((*player).sprite));
392
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
393
                                keypressCounter+=2;
394
                                break;
395
                        case (PLAYER0_LEFT | PLAYER0_DOWN):
396
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
397
                                moveSpriteDown((sprite_t*)&((*player).sprite));
398
                                keypressCounter+=2;
399
                                break;
400
                        case (PLAYER0_LEFT | PLAYER0_DOWN | PLAYER0_ROTATE):
401
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
402
                                rotateLeft((sprite_t*)&((*player).sprite));
403
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
404
                                moveSpriteDown((sprite_t*)&((*player).sprite));
405
                                keypressCounter+=3;
406
                                break;
407
                        // "nops"
408
                        case (PLAYER0_LEFT | PLAYER0_RIGHT): // left+right = no move
409
                                keypressCounter+=2;
410
                        case (0b0000): // nothing pressed
411
                                break;
412
                }
413
        }
414
        else if(player_number == 1){
415
                switch(input){
416
                        // move > rotate > down
417
                        case (PLAYER1_LEFT | PLAYER1_DOWN | PLAYER1_RIGHT | PLAYER1_ROTATE):
418
                                keypressCounter+=2;
419
                        case (PLAYER1_DOWN | PLAYER1_ROTATE):
420
                                rotateLeft((sprite_t*)&((*player).sprite));
421
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
422
                                moveSpriteDown((sprite_t*)&((*player).sprite));
423
                                keypressCounter+=2;
424
                                break;
425
                        case (PLAYER1_LEFT | PLAYER1_DOWN | PLAYER1_RIGHT):
426
                                keypressCounter+=2;
427
                        case (PLAYER1_DOWN):
428
                                moveSpriteDown((sprite_t*)&((*player).sprite));
429
                                keypressCounter+=1;
430
                                break;
431
                        case (PLAYER1_RIGHT):
432
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
433
                                keypressCounter+=1;
434
                                break;
435
                        case (PLAYER1_LEFT | PLAYER1_RIGHT | PLAYER1_ROTATE):
436
                                keypressCounter+=1;
437
                        case (PLAYER1_RIGHT | PLAYER1_ROTATE):
438
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
439
                                keypressCounter+=1;
440
                        case (PLAYER1_ROTATE):
441
                                rotateLeft((sprite_t*)&((*player).sprite));
442
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
443
                                keypressCounter+=1;
444
                                break;
445
                        case (PLAYER1_DOWN | PLAYER1_RIGHT):
446
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
447
                                moveSpriteDown((sprite_t*)&((*player).sprite));
448
                                keypressCounter+=2;
449
                                break;
450
                        case (PLAYER1_DOWN | PLAYER1_RIGHT | PLAYER1_ROTATE):
451
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
452
                                rotateLeft((sprite_t*)&((*player).sprite));
453
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
454
                                moveSpriteDown((sprite_t*)&((*player).sprite));
455
                                keypressCounter+=3;
456
                                break;
457
                        case (PLAYER1_LEFT):
458
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
459
                                keypressCounter+=1;
460
                                break;
461
                        case (PLAYER1_LEFT | PLAYER1_ROTATE):
462
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
463
                                rotateLeft((sprite_t*)&((*player).sprite));
464
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
465
                                keypressCounter+=2;
466
                                break;
467
                        case (PLAYER1_LEFT | PLAYER1_DOWN):
468
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
469
                                moveSpriteDown((sprite_t*)&((*player).sprite));
470
                                keypressCounter+=2;
471
                                break;
472
                        case (PLAYER1_LEFT | PLAYER1_DOWN | PLAYER1_ROTATE):
473
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
474
                                rotateLeft((sprite_t*)&((*player).sprite));
475
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
476
                                moveSpriteDown((sprite_t*)&((*player).sprite));
477
                                keypressCounter+=3;
478
                                break;
479
                        // "nops"
480
                        case (PLAYER1_LEFT | PLAYER1_RIGHT): // left+right = no move
481
                                keypressCounter+=2;
482
                        case (0b0000): // nothing pressed
483
                                break;
484
                }
485
        }
486
        else{
487
                return;
488
        }
489
}
490

    
491
void rawToBlock(uint16_t block[4], uint16_t raw, int8_t offset){
492
        block[0] = raw & 0xf;
493
        block[1] = (raw>>4) & 0xf;
494
        block[2] = (raw>>8) & 0xf;
495
        block[3] = (raw>>12) & 0xf;
496

    
497
        if(offset > 0){
498
                for(uint8_t i = 0; i < 4; i++){
499
                        block[i] = block[i]<<offset;
500
                }
501
        }
502
        else if(offset < 0){
503
                for(uint8_t i = 0; i < 4; i++){
504
                        block[i] = block[i]>>(offset*-1);
505
                }
506
        }
507
}
508

    
509
void clearCompleteLines(player_t* player){
510
        for(uint8_t line = (*player).gameAreaStart; line <= (*player).gameAreaEnd; line++){
511
                if((lines[line] & (0xffff & ~(NOGAMEAREA>>1))) == (0xffff & ~(NOGAMEAREA>>1))){
512
                        lines[line] ^= (0xffff & ~(NOGAMEAREA>>1));
513
                        (*player).score++;
514
                }
515
        }
516
}
517

    
518
void moveFlyingRowsDown(player_t* player){ // TODO needs fix becase we don't want to touch nogamearea
519
        for(uint8_t line = (*player).gameAreaStart; line <= (*player).gameAreaEnd-1; line++){
520
                if(lines[line] == 0x0000){ // TODO maybe add clear effect with green line?
521
                        lines[line] = lines[line+1];
522
                        // blank line to propagate movement
523
                        lines[line+1] = 0x0000;
524
                }
525
        }
526
}
527

    
528
void moveSpriteToLines(sprite_t* sprite){
529
        for(uint8_t j = 0; j < 4; j++){ // copy sprite to lines
530
                lines[(*sprite).yLowerPos+j] |= (*sprite).block[j];
531
        }
532
}
533

    
534
uint8_t checkPlayerSpriteForCollision(player_t* player, uint16_t block[4], int8_t lookahead){
535
        for(int8_t i = 0; i < 4; i++){
536
                if((*player).sprite.yLowerPos+lookahead+i < (*player).gameAreaStart){
537
                        if((*player).sprite.block[i] == 0x0000){
538
                                continue;
539
                        }
540
                        else{
541
                                return 1;
542
                        }
543
                }
544
                else if((lines[(*player).sprite.yLowerPos+lookahead+i] & block[i]) != 0){ // collision detected
545
                        return 1;
546
                }
547
        }
548
        return 0;
549
}
550

    
551
void moveSpriteDown(sprite_t* sprite){
552
        if(checkPlayerSpriteForCollision((player_t*)(*sprite).owner, (uint16_t*)(*sprite).block, -1)){
553
                if((*sprite).yLowerPos >= (*(*sprite).owner).gameAreaEnd-4){
554
                        gameOver((player_t*)(*sprite).owner);
555
                        return;
556
                }
557
                moveSpriteToLines(sprite);
558
                *sprite = (((player_t*)(*sprite).owner)->nextSprite);
559
                setNewSprite(&(*sprite).owner->nextSprite);
560
                return;
561
        }
562
        (*sprite).yLowerPos--;
563
        if((*sprite).yLowerPos <= 0 && ((*sprite).block[-1*(*sprite).yLowerPos] != 0x00)){
564
                moveSpriteToLines(sprite);
565
                *sprite = (((player_t*)(*sprite).owner)->nextSprite);
566
                setNewSprite(&(*sprite).owner->nextSprite);
567
        }
568
}
569

    
570

    
571
void moveSpriteHorizontal(volatile sprite_t *sprite, int8_t dir){ // -1 if left, 1 if right
572
        uint16_t block[4];
573
        if(dir == 1){
574
                // check if block[*] >= 0x8000, so we cant move left
575
                for(uint8_t i = 0; i < 4; i++){
576
                        if((*sprite).block[i] >= (1<<15)){
577
                                return;
578
                        }
579
                }
580
                for(uint8_t i = 0; i < 4; i++){
581
                        block[i] = (*sprite).block[i] << 1;
582
                }
583
        }
584
        else{
585
                for(uint8_t i = 0; i < 4; i++){
586
                        if(((*sprite).block[i] & (NOGAMEAREA)) != 0x0000){
587
                                return;
588
                        }
589
                }
590
                for(uint8_t i = 0; i < 4; i++){
591
                        block[i] = (*sprite).block[i] >> 1;
592
                }
593
        }
594
        if(checkPlayerSpriteForCollision((player_t*)(*sprite).owner, block, 0)){
595
                return;
596
        }
597
        else{
598
                for(uint8_t i = 0; i < 4; i++){
599
                        (*sprite).block[i] = block[i];
600
                }
601
                (*sprite).offset = (*sprite).offset+dir;
602
        }
603
}
604

    
605
void loopLines(){
606
        uint8_t tmp = lines[0];
607
        for(uint8_t line = 0; line < 89 ; line++){
608
                lines[line] = lines[line+1];
609
        }
610
        lines[89] = tmp;
611
}
612

    
613
inline void greenDot(){
614
        PORT(WALLBOARD_PORT) |= (1<<DATA_GREEN_PIN) | (1<<CLOCK_PIN);
615
        PORT(WALLBOARD_PORT) &= ~((1<<DATA_GREEN_PIN) | (1<<CLOCK_PIN));
616
}
617
inline void redDot(){
618
        PORT(WALLBOARD_PORT) |= (1<<DATA_RED_PIN) | (1<<CLOCK_PIN);
619
        PORT(WALLBOARD_PORT) &= ~((1<<DATA_RED_PIN) | (1<<CLOCK_PIN));
620
}
621
inline void yellowDot(){
622
        PORT(WALLBOARD_PORT) |= (1<<DATA_GREEN_PIN) | (1<<DATA_RED_PIN) | (1<<CLOCK_PIN);
623
        PORT(WALLBOARD_PORT) &= ~((1<<DATA_GREEN_PIN) | (1<<DATA_RED_PIN) | (1<<CLOCK_PIN));
624
}
625
inline void noDot(){
626
        PORT(WALLBOARD_PORT) |= (1<<CLOCK_PIN);
627
        PORT(WALLBOARD_PORT) &= ~(1<<CLOCK_PIN);
628
}
629

    
630
inline void OE(){
631
        PORT(WALLBOARD_PORT) |= (1<<OUTPUT_ENABLE_PIN);
632
}
633

    
634
inline void ODE(){
635
        PORT(WALLBOARD_PORT) &= ~(1<<OUTPUT_ENABLE_PIN);
636
}
637

    
638
void rotateLeft(sprite_t* sprite){
639
        uint16_t block[4];
640
        uint16_t tmp = (*sprite).raw;
641

    
642
        tmp =((tmp&(1<<15))>>(15-3) | (tmp&(1<<14))>>(14-7) | (tmp&(1<<13))>>(13-11) | (tmp&(1<<12))<<(15-12) | (tmp&(1<<11))>>(11-2) | (tmp&(1<<10))>>(10-6) | (tmp&(1<<9))<<(10-9) | (tmp&(1<<8))<<(14-8) | (tmp&(1<<7))>>(7-1) | (tmp&(1<<6))>>(6-5) | (tmp&(1<<5))<<(9-5) | (tmp&(1<<4))<<(13-4) | (tmp&(1<<3))>>(3-0) | (tmp&(1<<2))<<(4-2) | (tmp&(1<<1))<<(8-1) | (tmp&(1<<0))<<(12-0) );
643

    
644
        rawToBlock(block, tmp, (*sprite).offset);
645

    
646
        // check if sprite violates borders // TODO needs to be updated if game area doesn't span the whole line
647
        for(uint8_t i = 0; i < 4; i++){
648
                if((*sprite).offset < 0){
649
                        if(((block[i]<<((*sprite).offset*-1)) ^ ((tmp&((0xf)<<(i*4)))>>(i*4))) != 0){
650
                                return;
651
                        }
652
                }
653
                else if((*sprite).offset > 0){
654
                        if((((block[i]>>((*sprite).offset)) ^ ((tmp&((0xf)<<(i*4)))>>(i*4))) != 0) || ((block[i] & (NOGAMEAREA>>1)) != 0x0000)){
655
                                return;
656
                        }
657
                }
658
                else{
659
                        break;
660
                }
661
        }
662

    
663
        // check first if rotated sprite crashes, if, drop to game
664
        if(checkPlayerSpriteForCollision((player_t*)(*sprite).owner, block, 0)){
665
                return;
666
        }
667
        else{
668
                (*sprite).raw = tmp;
669
                for(uint8_t i = 0; i < 4; i++){
670
                        (*sprite).block[i] = block[i];
671
                }
672
        }
673
        // TODO rotate with ifs
674
//        l = ((u&(1<<7)) ? (1<<7)>>4 : 0) | ((u&(1<<6)) ? ((1<<6)>>1) : 0) | ((u&(1<<3)) ? ((1<<3)>>1) : 0) | ((u&(1<<2)) ? ((1<<2)<<4) : 0) | ((l&(1<<6)) ? (1<<6)>>1 : 0) | ((l&(1<<2)) ? (1<<2)<<2 : 0) | ((l&(1<<3)) ? (1<<3)>>3 : 0) | ((l&(1<<7)) ? (1<<7)>>6 : 0);
675
}