#include #include #include "../config.h" #include "../compat/pgmspace.h" #include "../random/prng.h" #include "../pixel.h" #include "../games/tetris/piece.h" #include "../util.h" #ifdef RANDOM_SUPPORT #define RANDOM8() random8() #else #define RANDOM8() rand() #endif #define MAX_STONES 8 #define YSCALE 2 //y axis is scaled up, this allows for YSCALE different falling speeds //this is hackish, i'll be drunk in a couple of minutes; no comments. /* space invader 001000100 0x0044 101111101 0x017D 110111011 0x01BB 011111110 0x00FE 010000010 0x0082 */ static uint16_t const invader[] PROGMEM = {0x0044, 0x017D, 0x01BB, 0x00FE, 0x0082}; #define INV_HEIGHT (sizeof(invader) / sizeof(uint16_t)) typedef struct { uint8_t x; uint8_t y; uint8_t speed; uint8_t color; tetris_piece_t piece; } stone_t; //forward decls (not drunk yet!) //void create_stone(stone_t *stone); //void draw_stone(stone_t *stone); //create a stone at a random x pos static void create_stone(stone_t *stone) { //create stone at top position stone->y = 0; //random x //4 is piece width stone->x = RANDOM8() % (NUM_COLS - 4); //random shape at random angle (untyped enums rock! yay!) stone->piece.shape = RANDOM8() % 7; stone->piece.angle = RANDOM8() % 4; //chose a random speed from 1-2 stone->speed = (RANDOM8() % YSCALE) + 1; //chose a random color stone->color = (RANDOM8() % NUMPLANE) + 1; } //simply draw the stone at it's specified position void draw_stone(stone_t *stone) { uint8_t y, x, ydraw; uint16_t nPieceMap = tetris_piece_getBitmap(&stone->piece); for(y = 0; y < 4; y++) { // clear all bits of the piece we are not interested in and // align the remaining row to LSB // -> translates to: get the correct row out of the bitmap and right-align // shift bitmap line to current x pos (this can be done faster... BUT I WANT IT SO!) uint16_t pieceLala = (nPieceMap & 0x000F) << stone->x; nPieceMap >>= 4; //DRUUUUUUUUUUUWWWWWWWWWWWWWWW!!!!!!!!!!! eerrr /U/A/s ydraw = (stone->y / YSCALE) + y; if((ydraw < (NUM_ROWS + 4)) && (ydraw > 3)) //drawing begins @ 3, to make piece of height 4 scroll in { uint16_t mask = 0x0001; for (x = 0; x < 16; ++x) { if(pieceLala & mask) { setpixel((pixel){ x, ydraw - 4 }, stone->color); } mask <<= 1; } } } } static void draw_invader(uint8_t ypos, uint8_t xpos) { uint8_t y, x, ydraw; uint16_t pieceLala; for(y = 0; y < INV_HEIGHT; y++) { pieceLala = pgm_read_word(&invader[y]); // shift bitmap line to current x pos (this is nonsense overhead... BUT I LIKE IT!) pieceLala <<= xpos; //DRUUUUUUUUUUUWWWWWWWWWWWWWWW!!!!!!!!!!! eerrr /U/A/s ydraw = (ypos / 2) + y; if((ydraw < (NUM_ROWS + INV_HEIGHT)) && (ydraw > (INV_HEIGHT - 1))) //drawing begins @ 5, to make invader of height 6 scroll in { uint16_t mask = 0x0001; for (x = 0; x < 16; ++x) { if(pieceLala & mask) { setpixel((pixel){ x, ydraw - INV_HEIGHT }, 1); } mask <<= 1; } } } } //animation entry point void stonefly(void) { uint8_t i; stone_t stones[MAX_STONES]; uint8_t stoneCount = 0; uint16_t counter = 622; /* run 622 cycles */ uint8_t invax = 0, invay = 0, invasion = 0; uint8_t draw; //init all stones to zero for(i = 0; i < MAX_STONES; i++) { stones[i].speed = 0; } //main loop while(counter || stoneCount || invasion) { if(counter > 0) { counter--; } //see if invasion is done! if((invay / 2) >= (NUM_ROWS + INV_HEIGHT)) { invasion = 0; } //clear scruuuun! clear_screen(0); //invade screen!!! if(invasion) { draw_invader(invay, invax); //advancarrrr invay++; } //loop through all stones for(i = 0; i < stoneCount; i++) { draw = 1; //rapunzel! while(((stones[i].y / YSCALE) >= (NUM_ROWS + 4)) && (stoneCount > 0)) { //DIEEEE!! if(--stoneCount == i) { draw = 0; break; } else stones[i] = stones[stoneCount]; } if(draw) { //draw stone!! draw_stone(&stones[i]); //advance! stones[i].y += stones[i].speed; } } //if there are less than max_stones flying, there's a chance to spawn one if((stoneCount < MAX_STONES) && (counter > 0)) { if((RANDOM8() % (UINT8_MAX + 1)) < 48) { create_stone(&stones[stoneCount++]); } //invasion time!!! if((RANDOM8() < 8) && (invasion == 0)) { //9 is invader width invax = RANDOM8() % (NUM_COLS - 9); invay = 0; invasion = 1; } } //loop delay wait(60); } }