shithub: gm4s

ref: 9886b6c0b9e3ddbcb6720bd4c4a316f010a57fa2
dir: /piece.c/

View raw version
#include <u.h>
#include <libc.h>
#include <thread.h>
#include <draw.h>
#include "dat.h"
#include "fns.h"
#include "/sys/src/games/eui.h"

/* FIXME: z and s pieces definitely should not wobble when rotating */
/* FIXME: stabler rotations? */
int fours[NF][Nrot] = {
	[FI] {
		0b0000111100000000,
		0b0010001000100010,
		0b0000000011110000,
		0b0100010001000100,
	},
	[FJ] {
		0b1000111000000000,
		0b0110010001000000,
		0b0000111000100000,
		0b0100010011000000,
	},
	[FL] {
		0b0010111000000000,
		0b0100010001100000,
		0b0000111010000000,
		0b1100010001000000,
	},
	[FO] {
		0b0000011001100000,
		0b0000011001100000,
		0b0000011001100000,
		0b0000011001100000,
	},
	[FS] {
		0b1100011000000000,
		0b0010011001000000,
		0b0000110001100000,
		0b0100110010000000,
	},
	[FT] {
		0b0100111000000000,
		0b0100011001000000,
		0b0000111001000000,
		0b0100110001000000,
	},
	[FZ] {
		0b0110110000000000,
		0b0100011000100000,
		0b0000011011000000,
		0b1000110001000000,
	},
};

enum{
	Cline = 0xf5,
};

/* FIXME: draw level, line clears, score */
/* FIXME: freeze screen on game over + print message instead of immediate exit */

static void
drawbackground(void)
{
	int n, m, y;
	u32int c, *p, *pe;

	memset(pic, 0, Vheight * Vwidth * sizeof *p);
	c = palette[Cline];
	p = (u32int *)pic;
	for(y=Nrow-Wheight; y<Nrow; y++){
		p += Wside * Block;
		for(pe=p+Ncol*Block; p<pe; p++)
			*p = c;
		p += Wside * Block;
		m = y == Nrow - 1 ? Block - 2 : Block - 1;
		for(n=0; n<m; n++){
			p += Wside * Block;
			for(pe=p+Ncol*Block; p<pe; p+=Block)
				*p = c;
			p[-1] = c;
			p += Wside * Block;
		}
	}
	p += Wside * Block;
	for(pe=p+Ncol*Block; p<pe; p++)
		*p = c;
}

static void
drawplayfield(void)
{
	int n, y;
	u32int *p, *pe;
	char fc, *f, *fs, *fe;
	uchar *sp;

	p = (u32int *)pic;
	fs = playfield + Wwidth * (Nrow - Wheight);
	for(y=Nrow-Wheight; y<Nrow; y++){
		fe = fs + Ncol;
		for(n=0; n<Block; n++){
			p += Wside * Block;
			for(f=fs; f<fe; f++){
				if((fc = *f) == 0){
					p += Block;
					continue;
				}
				sp = sprites[fc - 1] + n * Block;
				for(pe=p+Block; p<pe; p++)
					*p = palette[*sp++];
			}
			p += Wside * Block;
		}
		fs += Ncol;
	}
}

static void
drawfour(int x, int y, int rot, int type)
{
	int f, n, m, k;
	uchar *sp;
	u32int *l, *s, *p, *pe;

	p = (u32int *)pic + (y - Nstartrow + Nextrarows) * Vwidth * Block;
	p += (Wside + x) * Block;
	l = p;
	f = fours[type][rot];
	for(k=0, m=1<<(Nside*Nside-1); m>0; m>>=1){
		s = p;
		if(f & m){
			sp = sprites[type];
			for(n=0; n<Block; n++){
				if(p >= (u32int *)pic)
					for(pe=p+Block; p<pe; p++)
						*p = palette[*sp++];
				else
					p += Block;
				p += Vwidth - Block;
			}
		}
		p = s + Block;
		if(++k == Nside){
			k = 0;
			l += Vwidth * Block;
			p = l;
		}
	}
}

static void
drawsides(void)
{
	int y, *p;

	if(held != -1)
		drawfour(-4, Nrow / 2, 1, held);
	for(y=1, p=next; p<next+nelem(next); p++, y+=5)
		drawfour(Wwidth, Nstartrow - Nextrarows + y, 1, *p);
}

static void
drawpiece(void)
{
	if(cur == nil)
		return;
	drawfour(cur->x, cur->y, cur->rot, cur->type);
}

static void
drawui(void)
{
}

void
redraw(void)
{
	drawbackground();
	drawplayfield();
	drawpiece();
	drawsides();
	drawui();
	flushmouse(1);
	flushscreen();
}