Statistics
| Branch: | Revision:

root / main.c @ master

History | View | Annotate | Download (21.3 KB)

1 5b98becf imp
#define F_CPU 16000000L
2
3 b3338b32 imp
#include <inttypes.h>
4
#include <avr/io.h>
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7 3a596f81 imp
#include <avr/pgmspace.h>
8 5b98becf imp
#include "bricks.h"
9 78b2d942 imp
#include "scorefont.h"
10 b3338b32 imp
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 a4731c3d imp
19 f6bd0c06 imp
// 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 b2179a62 imp
// 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 f6bd0c06 imp
33 517b1a45 imp
// note that both controllers are on the same port, the reason is
34
// controllerOffset for faster input handling
35 a0ab2c33 imp
#define CONTROLLER0_PORT   D
36 87d0c022 imp
#define CONTROLLER0_PLAYER0_LEFT   PD7
37
#define CONTROLLER0_PLAYER0_RIGHT  PD6
38
#define CONTROLLER0_PLAYER0_DOWN   PD5
39
#define CONTROLLER0_PLAYER0_ROTATE PD4
40 517b1a45 imp
#define CONTROLLER1_PORT   D
41 87d0c022 imp
#define CONTROLLER1_PLAYER0_LEFT   PD3
42
#define CONTROLLER1_PLAYER0_RIGHT  PD2
43
#define CONTROLLER1_PLAYER0_DOWN   PD1
44
#define CONTROLLER1_PLAYER0_ROTATE PD0
45 0db9735d imp
46 69bc3638 imp
// control mappings for atari joystick
47 87d0c022 imp
#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 0db9735d imp
57 4603a6d1 imp
// note NOGAMEAREA needs has to be one pixel bigger
58
// because we are lazy in moveSpriteHorizontal (forward check)
59
#define NOGAMEAREA 0b111111111
60 f6bd0c06 imp
#define TICKS 40
61 517b1a45 imp
#define NUMBER_OF_PLAYERS 2
62 fe52673c imp
63
struct player;
64 a4731c3d imp
65 dab6a8ea imp
typedef struct sprite {
66
        volatile int8_t offset;
67 c591189c imp
        volatile int8_t yLowerPos;
68 dab6a8ea imp
        volatile uint16_t block[4];
69
        volatile uint16_t raw;
70 fe52673c imp
        volatile struct player *owner;
71 dab6a8ea imp
        } sprite_t;
72
73 fe52673c imp
typedef struct player {
74
        volatile uint16_t score;
75 76dc4e0b imp
        volatile uint16_t oldScore;
76 e56f94bb imp
        volatile int8_t gameAreaStart;
77
        volatile int8_t gameAreaEnd;
78 fe52673c imp
        volatile sprite_t sprite;
79 ed12d037 imp
        volatile uint8_t mirrored;
80 517b1a45 imp
        volatile uint8_t controllerOffset;
81
        volatile uint8_t controllerInputMask;
82 65352f3f imp
        volatile sprite_t nextSprite;
83 fe52673c imp
        } player_t;
84
85
int main(void);
86 f6bd0c06 imp
inline void redDot(void);
87
inline void greenDot(void);
88
inline void yellowDot(void);
89 b3338b32 imp
inline void noDot(void);
90
inline void OE(void);
91
inline void ODE(void);
92 b965164d imp
void loopLines(void);
93 fe52673c imp
void rotateLeft(sprite_t* sprite);
94
void moveFlyingRowsDown(player_t* player);
95
void moveSpriteDown(sprite_t* sprite);
96
void clearCompleteLines(player_t* player);
97 91ec4a22 imp
void rawToBlock(uint16_t block[4], uint16_t raw, int8_t offset);
98 fe52673c imp
void moveSpriteToLines(sprite_t* sprite);
99 e56f94bb imp
uint8_t checkPlayerSpriteForCollision(player_t* player, uint16_t block[4], int8_t lookahead); // lookahead -1 -> look down
100 6316d02a imp
void moveSpriteHorizontal(volatile sprite_t *sprite, int8_t dir); // -1 if left, 1 if right
101 87d0c022 imp
void handleGamepadInput(player_t* player, uint8_t player_number, uint8_t input);
102 3619f712 imp
inline void printLine(int16_t line, uint8_t round, sprite_t* sprite, uint8_t player_number);
103 517b1a45 imp
static inline void drawGameArea(player_t player[NUMBER_OF_PLAYERS]);
104 9695d25c imp
void gameOver(player_t* player);
105 65352f3f imp
void setNewSprite(volatile sprite_t* sprite);
106 ed12d037 imp
void drawScore(uint16_t* score, uint8_t round);
107 b3338b32 imp
108 d68abaaf imp
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 };
109 fe52673c imp
volatile player_t player[NUMBER_OF_PLAYERS];
110 97dd3311 imp
111 fe52673c imp
volatile uint8_t keypressCounter = 0;
112 97dd3311 imp
113 b3338b32 imp
int main(){
114 97dd3311 imp
        // hardware init
115
        // clock, data and output enable
116 b2179a62 imp
        DDR(WALLBOARD_PORT) |= (1<<CLOCK_PIN) | (1<<DATA_RED_PIN) | (1<<DATA_GREEN_PIN) | (1<<OUTPUT_ENABLE_PIN);
117 97dd3311 imp
        // gamepad (PD7 is for bootloadstart):
118
        // 7...4 left down right rotate
119
        //
120
        // move > rotate > down
121 87d0c022 imp
        DDR(CONTROLLER0_PORT) &= ~((1<<CONTROLLER0_PLAYER0_LEFT) | (1<<CONTROLLER0_PLAYER0_RIGHT) | (1<<CONTROLLER0_PLAYER0_DOWN) | (1<<CONTROLLER0_PLAYER0_ROTATE));
122
        PORT(CONTROLLER0_PORT) |= (1<<CONTROLLER0_PLAYER0_LEFT) | (1<<CONTROLLER0_PLAYER0_RIGHT) | (1<<CONTROLLER0_PLAYER0_DOWN) | (1<<CONTROLLER0_PLAYER0_ROTATE);
123
        DDR(CONTROLLER1_PORT) &= ~((1<<CONTROLLER1_PLAYER0_LEFT) | (1<<CONTROLLER1_PLAYER0_RIGHT) | (1<<CONTROLLER1_PLAYER0_DOWN) | (1<<CONTROLLER1_PLAYER0_ROTATE));
124
        PORT(CONTROLLER1_PORT) |= (1<<CONTROLLER1_PLAYER0_LEFT) | (1<<CONTROLLER1_PLAYER0_RIGHT) | (1<<CONTROLLER1_PLAYER0_DOWN) | (1<<CONTROLLER1_PLAYER0_ROTATE);
125 97dd3311 imp
        // address lines:
126 b2179a62 imp
        DDR(ADDRESS_PORT) |= (1<<A3) | (1<<A2) | (1<<A1) | (1<<A0);
127 fe52673c imp
128
        // init player
129
        player[0].score = 0;
130 76dc4e0b imp
        player[0].oldScore = 0;
131 fe52673c imp
        player[0].gameAreaStart = 0;
132 118d8e09 imp
        player[0].gameAreaEnd = 28;
133 fe52673c imp
        player[0].sprite.owner = (player_t*)&player[0];
134 ad516f5c imp
        setNewSprite((sprite_t*)&(player[0].sprite));
135 ed12d037 imp
        player[0].mirrored = 0;
136 87d0c022 imp
        player[0].controllerInputMask = (1<<CONTROLLER0_PLAYER0_LEFT) | (1<<CONTROLLER0_PLAYER0_DOWN) | (1<<CONTROLLER0_PLAYER0_RIGHT) | (1<<CONTROLLER0_PLAYER0_ROTATE);
137 517b1a45 imp
        player[0].controllerOffset = 4;
138 65352f3f imp
        player[0].nextSprite.owner = (player_t*)&player[0];
139
        setNewSprite((sprite_t*)&(player[0].nextSprite));
140 517b1a45 imp
        // next one
141
        player[1].score = 0;
142 76dc4e0b imp
        player[1].oldScore = 0;
143 118d8e09 imp
        player[1].gameAreaStart = 37;
144
        player[1].gameAreaEnd = 65;
145 517b1a45 imp
        player[1].sprite.owner = (player_t*)&player[1];
146 ad516f5c imp
        setNewSprite((sprite_t*)&(player[1].sprite));
147 517b1a45 imp
        player[1].mirrored = 1;
148 87d0c022 imp
        player[1].controllerInputMask = (1<<CONTROLLER1_PLAYER0_LEFT) | (1<<CONTROLLER1_PLAYER0_DOWN) | (1<<CONTROLLER1_PLAYER0_RIGHT) | (1<<CONTROLLER1_PLAYER0_ROTATE);
149 517b1a45 imp
        player[1].controllerOffset = 0;
150 65352f3f imp
        player[1].nextSprite.owner = (player_t*)&player[1];
151
        setNewSprite((sprite_t*)&(player[1].nextSprite));
152 b3338b32 imp
        while(1){
153 517b1a45 imp
                for(uint8_t delay = 0; delay < TICKS; delay++){
154
                        drawGameArea((player_t*)player);
155 ad516f5c imp
                        if(delay%(TICKS/(NUMBER_OF_PLAYERS)) == 0){
156 517b1a45 imp
                                for(uint8_t playerNumber = 0; playerNumber < NUMBER_OF_PLAYERS; playerNumber++){ //fair handing of input
157 87d0c022 imp
                                        handleGamepadInput(&player[playerNumber], playerNumber,
158 517b1a45 imp
                                                                ((~PIN(CONTROLLER0_PORT))& player[playerNumber].controllerInputMask)
159
                                                                        >>player[playerNumber].controllerOffset);
160 fe52673c imp
                                }
161 97dd3311 imp
                        }
162 517b1a45 imp
                }
163
                for(uint8_t playerNumber = 0; playerNumber < NUMBER_OF_PLAYERS; playerNumber++){
164 e56f94bb imp
                        moveSpriteDown((sprite_t*)&(player[playerNumber].sprite));
165 fe52673c imp
                        clearCompleteLines((player_t*)&player[playerNumber]);
166
                        moveFlyingRowsDown((player_t*)&player[playerNumber]);
167 b3338b32 imp
                }
168 76dc4e0b imp
                if((player[0].score > 5)
169
                  && (player[0].score-2>=player[0].oldScore)
170
                  && (player[0].gameAreaEnd-player[0].gameAreaStart > 12)    // avoid way to small
171
                  && (player[1].gameAreaEnd-player[1].gameAreaStart > 12)){ // game areas.
172
                        player[0].gameAreaEnd++;
173
                        player[1].gameAreaStart++;
174
                }
175
                if((player[1].score > 5)
176
                  && (player[1].score-2>=player[1].oldScore)
177
                  && (player[0].gameAreaEnd-player[0].gameAreaStart > 12)    // avoid way to small
178
                  && (player[1].gameAreaEnd-player[1].gameAreaStart > 12)){ // game areas.
179
                        player[0].gameAreaEnd--;
180
                        player[1].gameAreaStart--;
181
                }
182
                player[0].oldScore = player[0].score;
183
                player[1].oldScore = player[1].score;
184 243719c7 imp
        }
185
}
186
187 65352f3f imp
void setNewSprite(volatile sprite_t* sprite){
188 fe52673c imp
        (*sprite).yLowerPos = (*((*sprite).owner)).gameAreaEnd-2;
189
        (*sprite).raw = pgm_read_word(bricks+(keypressCounter%(sizeof(bricks)/sizeof(uint16_t))));
190 4603a6d1 imp
        (*sprite).offset = 10;
191 fe52673c imp
        rawToBlock((uint16_t*)(*sprite).block, (*sprite).raw, (*sprite).offset);
192
        keypressCounter++;
193
}
194 e56f94bb imp
195 517b1a45 imp
void gameOver(player_t* player){
196
        for(int16_t line = (*player).gameAreaEnd; line >= (*player).gameAreaStart; line--){
197 5dc3c0e9 imp
                lines[line] = 0x0000;
198
        }
199 9695d25c imp
        (*player).score = 0;
200
        setNewSprite((sprite_t*)&((*player).sprite));
201 5dc3c0e9 imp
}
202
203 ed12d037 imp
void drawScore(uint16_t* score, uint8_t round){
204
        if((*score) & (1<<round)){
205
                redDot();
206
        }
207
        else{
208
                noDot();
209
        }
210
}
211
212 f8259022 imp
inline void printYellowBar(void){
213
        yellowDot();
214
}
215
216
inline void printGreenBar(void){
217
        greenDot();
218
}
219
220
inline void printRedBar(void){
221
        redDot();
222
}
223
224
inline void printEmptyBar(void){
225
        noDot();
226
}
227
228 78b2d942 imp
inline void printScoreFontLine(uint8_t scoreNibble, uint8_t step, uint8_t mirror){
229
        if(mirror){
230
                for(int8_t i = 7; i >=0; i--){
231
                        if(score_font[scoreNibble][step] & (1<<i)){
232
                                yellowDot();
233
                        }
234
                        else{
235
                                noDot();
236
                        }
237
                }
238
        }
239
        else{
240
                for(uint8_t i = 0; i < 8; i++){
241
                        if(score_font[scoreNibble][step] & (1<<i)){
242
                                yellowDot();
243
                        }
244
                        else{
245
                                noDot();
246
                        }
247
                }
248
        }
249
}
250
251 517b1a45 imp
static inline void drawGameArea(player_t player[NUMBER_OF_PLAYERS]){
252 f8259022 imp
        PORT(ADDRESS_PORT) = 0;
253
        for(uint8_t round = 0; round < 16; /*round++*/){
254
                for(int16_t line = player[1].gameAreaStart; line <= player[1].gameAreaEnd; line++){
255 3619f712 imp
                        printLine(line, 15-round/2, (sprite_t*)&(player[1].sprite), 1);
256 f8259022 imp
                }
257
                printGreenBar();
258 78b2d942 imp
                for(int16_t line = 0; line < 8 ; line++){ //player[1].gameAreaEnd; line < player[0].gameAreaStart; line--){
259
                        if(round <=15 && round >=12){
260
                                printScoreFontLine((player[1].score>>4)&0x0f,15-round, 1);
261
                                break;
262
                        }
263
                        if(round <= 10 && round >= 7){
264
                                printScoreFontLine((player[1].score)&0x0f,10-round, 1);
265
                                break;
266
                        }
267 f8259022 imp
                        if(round == 5){
268
                                printYellowBar();
269 517b1a45 imp
                        }
270
                        else{
271 65352f3f imp
                                if(round < 4){
272
                                        if(((line >= 2 && line <= 5)) && (player[1].nextSprite.block[line-2] & (1<<(14-round)))){
273
                                                yellowDot();
274
                                        }
275
                                        else{
276
                                                noDot();
277
                                        }
278
                                }
279
                                else{
280
                                        noDot();
281
                                }
282 f8259022 imp
                        }
283
                }
284
                printYellowBar();
285 78b2d942 imp
                for(int16_t line = 0; line < 8 ; line++){
286
                        if(round >=0 && round <= 3){
287
                                printScoreFontLine((player[0].score>>4)&0x0f, round, 0);
288
                                break;
289
                        }
290
                        if(round >=5 && round <= 8){
291
                                printScoreFontLine(player[0].score&0x0f, round-5, 0);
292
                                break;
293
                        }
294 f8259022 imp
                        if(round == 10){
295
                                printYellowBar();
296 517b1a45 imp
                        }
297 f8259022 imp
                        else{
298 65352f3f imp
                                if(round > 11){
299
                                        if(((line >= 2 && line <= 5)) && (player[0].nextSprite.block[5-line] & (1<<(25-round)))){
300
                                                yellowDot();
301
                                        }
302
                                        else{
303
                                                noDot();
304
                                        }
305
                                }
306
                                else{
307
                                        noDot();
308
                                }
309 f8259022 imp
                        }
310
                }
311
                printRedBar();
312
                for(int16_t line = player[0].gameAreaEnd; line >= player[0].gameAreaStart; line--){
313 3619f712 imp
                        printLine(line, 15-round/2, (sprite_t*)&(player[0].sprite), 0);
314 5dc3c0e9 imp
                }
315 f8259022 imp
316 5dc3c0e9 imp
                OE();
317 1a2d51b8 imp
                _delay_us(151);
318 5dc3c0e9 imp
                ODE();
319 f8259022 imp
                round++;
320
                PORT(ADDRESS_PORT) = round;
321
                _delay_us(10); // avoid ghosting
322 5dc3c0e9 imp
        }
323
}
324
325 3619f712 imp
inline void printLine(int16_t line, uint8_t round, sprite_t* sprite, uint8_t player_number){
326 5dc3c0e9 imp
        if((1<<round) & lines[line]){
327 f6bd0c06 imp
                yellowDot();
328 f8259022 imp
                yellowDot();
329 5dc3c0e9 imp
        }
330
        else{
331 fe52673c imp
                if((*sprite).yLowerPos <= line && (*sprite).yLowerPos+4 > line){
332
                        if((1<<round) & (*sprite).block[line-(*sprite).yLowerPos]){
333 3619f712 imp
                                switch(player_number){
334
                                        case 0:
335
                                                redDot();
336
                                                redDot();
337
                                                break;
338
                                        case 1:
339
                                                greenDot();
340
                                                greenDot();
341
                                                break;
342
                                        default:
343
                                                yellowDot();
344
                                                yellowDot();
345
                                                break;
346
                                }
347 5dc3c0e9 imp
                        }
348
                        else{
349
                                noDot();
350 f8259022 imp
                                noDot();
351 5dc3c0e9 imp
                        }
352
                }
353
                else{
354
                        noDot();
355 f8259022 imp
                        noDot();
356 5dc3c0e9 imp
                }
357
        }
358
}
359
360 87d0c022 imp
void handleGamepadInput(player_t* player, uint8_t player_number, uint8_t input){
361
        if(player_number == 0){
362
                switch(input){
363
                        // move > rotate > down
364
                        case (PLAYER0_LEFT | PLAYER0_DOWN | PLAYER0_RIGHT | PLAYER0_ROTATE):
365
                                keypressCounter+=2;
366
                        case (PLAYER0_DOWN | PLAYER0_ROTATE):
367
                                rotateLeft((sprite_t*)&((*player).sprite));
368
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
369
                                moveSpriteDown((sprite_t*)&((*player).sprite));
370
                                keypressCounter+=2;
371
                                break;
372
                        case (PLAYER0_LEFT | PLAYER0_DOWN | PLAYER0_RIGHT):
373
                                keypressCounter+=2;
374
                        case (PLAYER0_DOWN):
375
                                moveSpriteDown((sprite_t*)&((*player).sprite));
376
                                keypressCounter+=1;
377
                                break;
378
                        case (PLAYER0_RIGHT):
379
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
380
                                keypressCounter+=1;
381
                                break;
382
                        case (PLAYER0_LEFT | PLAYER0_RIGHT | PLAYER0_ROTATE):
383
                                keypressCounter+=1;
384
                        case (PLAYER0_RIGHT | PLAYER0_ROTATE):
385
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
386
                                keypressCounter+=1;
387
                        case (PLAYER0_ROTATE):
388
                                rotateLeft((sprite_t*)&((*player).sprite));
389
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
390
                                keypressCounter+=1;
391
                                break;
392
                        case (PLAYER0_DOWN | PLAYER0_RIGHT):
393
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
394
                                moveSpriteDown((sprite_t*)&((*player).sprite));
395
                                keypressCounter+=2;
396
                                break;
397
                        case (PLAYER0_DOWN | PLAYER0_RIGHT | PLAYER0_ROTATE):
398
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
399
                                rotateLeft((sprite_t*)&((*player).sprite));
400
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
401
                                moveSpriteDown((sprite_t*)&((*player).sprite));
402
                                keypressCounter+=3;
403
                                break;
404
                        case (PLAYER0_LEFT):
405
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
406
                                keypressCounter+=1;
407
                                break;
408
                        case (PLAYER0_LEFT | PLAYER0_ROTATE):
409
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
410
                                rotateLeft((sprite_t*)&((*player).sprite));
411
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
412
                                keypressCounter+=2;
413
                                break;
414
                        case (PLAYER0_LEFT | PLAYER0_DOWN):
415
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
416
                                moveSpriteDown((sprite_t*)&((*player).sprite));
417
                                keypressCounter+=2;
418
                                break;
419
                        case (PLAYER0_LEFT | PLAYER0_DOWN | PLAYER0_ROTATE):
420
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
421
                                rotateLeft((sprite_t*)&((*player).sprite));
422
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
423
                                moveSpriteDown((sprite_t*)&((*player).sprite));
424
                                keypressCounter+=3;
425
                                break;
426
                        // "nops"
427
                        case (PLAYER0_LEFT | PLAYER0_RIGHT): // left+right = no move
428
                                keypressCounter+=2;
429
                        case (0b0000): // nothing pressed
430
                                break;
431
                }
432
        }
433
        else if(player_number == 1){
434
                switch(input){
435
                        // move > rotate > down
436
                        case (PLAYER1_LEFT | PLAYER1_DOWN | PLAYER1_RIGHT | PLAYER1_ROTATE):
437
                                keypressCounter+=2;
438
                        case (PLAYER1_DOWN | PLAYER1_ROTATE):
439
                                rotateLeft((sprite_t*)&((*player).sprite));
440
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
441
                                moveSpriteDown((sprite_t*)&((*player).sprite));
442
                                keypressCounter+=2;
443
                                break;
444
                        case (PLAYER1_LEFT | PLAYER1_DOWN | PLAYER1_RIGHT):
445
                                keypressCounter+=2;
446
                        case (PLAYER1_DOWN):
447
                                moveSpriteDown((sprite_t*)&((*player).sprite));
448
                                keypressCounter+=1;
449
                                break;
450
                        case (PLAYER1_RIGHT):
451
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
452
                                keypressCounter+=1;
453
                                break;
454
                        case (PLAYER1_LEFT | PLAYER1_RIGHT | PLAYER1_ROTATE):
455
                                keypressCounter+=1;
456
                        case (PLAYER1_RIGHT | PLAYER1_ROTATE):
457
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
458
                                keypressCounter+=1;
459
                        case (PLAYER1_ROTATE):
460
                                rotateLeft((sprite_t*)&((*player).sprite));
461
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
462
                                keypressCounter+=1;
463
                                break;
464
                        case (PLAYER1_DOWN | PLAYER1_RIGHT):
465
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
466
                                moveSpriteDown((sprite_t*)&((*player).sprite));
467
                                keypressCounter+=2;
468
                                break;
469
                        case (PLAYER1_DOWN | PLAYER1_RIGHT | PLAYER1_ROTATE):
470
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), -1);
471
                                rotateLeft((sprite_t*)&((*player).sprite));
472
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
473
                                moveSpriteDown((sprite_t*)&((*player).sprite));
474
                                keypressCounter+=3;
475
                                break;
476
                        case (PLAYER1_LEFT):
477
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
478
                                keypressCounter+=1;
479
                                break;
480
                        case (PLAYER1_LEFT | PLAYER1_ROTATE):
481
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
482
                                rotateLeft((sprite_t*)&((*player).sprite));
483
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
484
                                keypressCounter+=2;
485
                                break;
486
                        case (PLAYER1_LEFT | PLAYER1_DOWN):
487
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
488
                                moveSpriteDown((sprite_t*)&((*player).sprite));
489
                                keypressCounter+=2;
490
                                break;
491
                        case (PLAYER1_LEFT | PLAYER1_DOWN | PLAYER1_ROTATE):
492
                                moveSpriteHorizontal((sprite_t*)&((*player).sprite), 1);
493
                                rotateLeft((sprite_t*)&((*player).sprite));
494
                                rawToBlock((uint16_t*)(*player).sprite.block, (*player).sprite.raw, (*player).sprite.offset);
495
                                moveSpriteDown((sprite_t*)&((*player).sprite));
496
                                keypressCounter+=3;
497
                                break;
498
                        // "nops"
499
                        case (PLAYER1_LEFT | PLAYER1_RIGHT): // left+right = no move
500
                                keypressCounter+=2;
501
                        case (0b0000): // nothing pressed
502
                                break;
503
                }
504
        }
505
        else{
506
                return;
507 b3338b32 imp
        }
508
}
509 f07bb88b imp
510 91ec4a22 imp
void rawToBlock(uint16_t block[4], uint16_t raw, int8_t offset){
511
        block[0] = raw & 0xf;
512
        block[1] = (raw>>4) & 0xf;
513
        block[2] = (raw>>8) & 0xf;
514
        block[3] = (raw>>12) & 0xf;
515 d68abaaf imp
516 fe52673c imp
        if(offset > 0){
517 d68abaaf imp
                for(uint8_t i = 0; i < 4; i++){
518 91ec4a22 imp
                        block[i] = block[i]<<offset;
519 d68abaaf imp
                }
520
        }
521 fe52673c imp
        else if(offset < 0){
522 d68abaaf imp
                for(uint8_t i = 0; i < 4; i++){
523 2ea93514 imp
                        block[i] = block[i]>>(offset*-1);
524 d68abaaf imp
                }
525
        }
526
}
527
528 fe52673c imp
void clearCompleteLines(player_t* player){
529 ed12d037 imp
        for(uint8_t line = (*player).gameAreaStart; line <= (*player).gameAreaEnd; line++){
530 4603a6d1 imp
                if((lines[line] & (0xffff & ~(NOGAMEAREA>>1))) == (0xffff & ~(NOGAMEAREA>>1))){
531
                        lines[line] ^= (0xffff & ~(NOGAMEAREA>>1));
532 ed12d037 imp
                        (*player).score++;
533 f07bb88b imp
                }
534
        }
535
}
536
537 4603a6d1 imp
void moveFlyingRowsDown(player_t* player){ // TODO needs fix becase we don't want to touch nogamearea
538 517b1a45 imp
        for(uint8_t line = (*player).gameAreaStart; line <= (*player).gameAreaEnd-1; line++){
539 9ba219b7 imp
                if(lines[line] == 0x0000){ // TODO maybe add clear effect with green line?
540 b965164d imp
                        lines[line] = lines[line+1];
541 5dc3c0e9 imp
                        // blank line to propagate movement
542 9ba219b7 imp
                        lines[line+1] = 0x0000;
543 b965164d imp
                }
544
        }
545
}
546
547 fe52673c imp
void moveSpriteToLines(sprite_t* sprite){
548 91ec4a22 imp
        for(uint8_t j = 0; j < 4; j++){ // copy sprite to lines
549 fe52673c imp
                lines[(*sprite).yLowerPos+j] |= (*sprite).block[j];
550 91ec4a22 imp
        }
551
}
552
553 e56f94bb imp
uint8_t checkPlayerSpriteForCollision(player_t* player, uint16_t block[4], int8_t lookahead){
554
        for(int8_t i = 0; i < 4; i++){
555
                if((*player).sprite.yLowerPos+lookahead+i < (*player).gameAreaStart){
556
                        if((*player).sprite.block[i] == 0x0000){
557
                                continue;
558
                        }
559
                        else{
560
                                return 1;
561
                        }
562
                }
563
                else if((lines[(*player).sprite.yLowerPos+lookahead+i] & block[i]) != 0){ // collision detected
564 91ec4a22 imp
                        return 1;
565 f07bb88b imp
                }
566
        }
567 91ec4a22 imp
        return 0;
568
}
569
570 fe52673c imp
void moveSpriteDown(sprite_t* sprite){
571 e56f94bb imp
        if(checkPlayerSpriteForCollision((player_t*)(*sprite).owner, (uint16_t*)(*sprite).block, -1)){
572 9695d25c imp
                if((*sprite).yLowerPos >= (*(*sprite).owner).gameAreaEnd-4){
573
                        gameOver((player_t*)(*sprite).owner);
574
                        return;
575
                }
576 fe52673c imp
                moveSpriteToLines(sprite);
577 65352f3f imp
                *sprite = (((player_t*)(*sprite).owner)->nextSprite);
578
                setNewSprite(&(*sprite).owner->nextSprite);
579 91ec4a22 imp
                return;
580
        }
581 fe52673c imp
        (*sprite).yLowerPos--;
582 e56f94bb imp
        if((*sprite).yLowerPos <= 0 && ((*sprite).block[-1*(*sprite).yLowerPos] != 0x00)){
583 fe52673c imp
                moveSpriteToLines(sprite);
584 65352f3f imp
                *sprite = (((player_t*)(*sprite).owner)->nextSprite);
585
                setNewSprite(&(*sprite).owner->nextSprite);
586 c591189c imp
        }
587 f07bb88b imp
}
588 a0c9649a imp
589 b965164d imp
590 6316d02a imp
void moveSpriteHorizontal(volatile sprite_t *sprite, int8_t dir){ // -1 if left, 1 if right
591 dab6a8ea imp
        uint16_t block[4];
592 a4731c3d imp
        if(dir == 1){
593 243719c7 imp
                // check if block[*] >= 0x8000, so we cant move left
594 dab6a8ea imp
                for(uint8_t i = 0; i < 4; i++){
595
                        if((*sprite).block[i] >= (1<<15)){
596
                                return;
597
                        }
598
                }
599
                for(uint8_t i = 0; i < 4; i++){
600
                        block[i] = (*sprite).block[i] << 1;
601
                }
602
        }
603
        else{
604
                for(uint8_t i = 0; i < 4; i++){
605 4603a6d1 imp
                        if(((*sprite).block[i] & (NOGAMEAREA)) != 0x0000){
606 dab6a8ea imp
                                return;
607
                        }
608
                }
609
                for(uint8_t i = 0; i < 4; i++){
610
                        block[i] = (*sprite).block[i] >> 1;
611
                }
612
        }
613 e56f94bb imp
        if(checkPlayerSpriteForCollision((player_t*)(*sprite).owner, block, 0)){
614 dab6a8ea imp
                return;
615
        }
616
        else{
617
                for(uint8_t i = 0; i < 4; i++){
618
                        (*sprite).block[i] = block[i];
619
                }
620 a4731c3d imp
                (*sprite).offset = (*sprite).offset+dir;
621 dab6a8ea imp
        }
622
}
623
624 b965164d imp
void loopLines(){
625
        uint8_t tmp = lines[0];
626 b3338b32 imp
        for(uint8_t line = 0; line < 89 ; line++){
627
                lines[line] = lines[line+1];
628
        }
629 b965164d imp
        lines[89] = tmp;
630 b3338b32 imp
}
631
632 f6bd0c06 imp
inline void greenDot(){
633
        PORT(WALLBOARD_PORT) |= (1<<DATA_GREEN_PIN) | (1<<CLOCK_PIN);
634
        PORT(WALLBOARD_PORT) &= ~((1<<DATA_GREEN_PIN) | (1<<CLOCK_PIN));
635
}
636
inline void redDot(){
637
        PORT(WALLBOARD_PORT) |= (1<<DATA_RED_PIN) | (1<<CLOCK_PIN);
638
        PORT(WALLBOARD_PORT) &= ~((1<<DATA_RED_PIN) | (1<<CLOCK_PIN));
639
}
640
inline void yellowDot(){
641
        PORT(WALLBOARD_PORT) |= (1<<DATA_GREEN_PIN) | (1<<DATA_RED_PIN) | (1<<CLOCK_PIN);
642
        PORT(WALLBOARD_PORT) &= ~((1<<DATA_GREEN_PIN) | (1<<DATA_RED_PIN) | (1<<CLOCK_PIN));
643 b3338b32 imp
}
644
inline void noDot(){
645 f6bd0c06 imp
        PORT(WALLBOARD_PORT) |= (1<<CLOCK_PIN);
646
        PORT(WALLBOARD_PORT) &= ~(1<<CLOCK_PIN);
647 b3338b32 imp
}
648
649
inline void OE(){
650 f6bd0c06 imp
        PORT(WALLBOARD_PORT) |= (1<<OUTPUT_ENABLE_PIN);
651 b3338b32 imp
}
652
653
inline void ODE(){
654 f6bd0c06 imp
        PORT(WALLBOARD_PORT) &= ~(1<<OUTPUT_ENABLE_PIN);
655 b3338b32 imp
}
656
657 fe52673c imp
void rotateLeft(sprite_t* sprite){
658 91ec4a22 imp
        uint16_t block[4];
659 fe52673c imp
        uint16_t tmp = (*sprite).raw;
660 91ec4a22 imp
661
        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) );
662
663 fe52673c imp
        rawToBlock(block, tmp, (*sprite).offset);
664 ec02bc61 imp
665 855dd978 imp
        // check if sprite violates borders // TODO needs to be updated if game area doesn't span the whole line
666 c591189c imp
        for(uint8_t i = 0; i < 4; i++){
667 fe52673c imp
                if((*sprite).offset < 0){
668
                        if(((block[i]<<((*sprite).offset*-1)) ^ ((tmp&((0xf)<<(i*4)))>>(i*4))) != 0){
669 ec02bc61 imp
                                return;
670
                        }
671
                }
672 fe52673c imp
                else if((*sprite).offset > 0){
673 4603a6d1 imp
                        if((((block[i]>>((*sprite).offset)) ^ ((tmp&((0xf)<<(i*4)))>>(i*4))) != 0) || ((block[i] & (NOGAMEAREA>>1)) != 0x0000)){
674 ec02bc61 imp
                                return;
675
                        }
676 c591189c imp
                }
677 855dd978 imp
                else{
678
                        break;
679
                }
680 c591189c imp
        }
681 dab6a8ea imp
682
        // check first if rotated sprite crashes, if, drop to game
683 e56f94bb imp
        if(checkPlayerSpriteForCollision((player_t*)(*sprite).owner, block, 0)){
684 91ec4a22 imp
                return;
685
        }
686
        else{
687 fe52673c imp
                (*sprite).raw = tmp;
688 91ec4a22 imp
                for(uint8_t i = 0; i < 4; i++){
689 fe52673c imp
                        (*sprite).block[i] = block[i];
690 91ec4a22 imp
                }
691
        }
692 dab6a8ea imp
        // TODO rotate with ifs
693 91ec4a22 imp
//        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);
694 b965164d imp
}