226 lines
4.5 KiB
C
226 lines
4.5 KiB
C
#include <stdlib.h>
|
|
#include <inttypes.h>
|
|
#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);
|
|
}
|
|
}
|