use t3x: t;
use console: con;
use rng;

const	COLS	= 80,
	LINES	= 23;

const	SPEEDUP	= 100;

const	SMOOTHNESS	= 5;

var	Sx, Sy;

var	Objects::COLS, Top::COLS, Bottom::COLS;
var	Topseed, Botseed;

var	Speed, Tick;

drawship() do
	con.move(Sx, Sy);   con.writes("|\\=- ");
	con.move(Sx, Sy+1); con.writes(">=o==");
	con.move(Sx, Sy+2); con.writes("|/=- ");
end

scrollset(coords, obj) do var i;
	for (i = 0, COLS) do
		if (coords::i \= 255) do
			ie (i > 0) do
				con.move(i-1, coords::i);
				con.wrch(obj);
				con.wrch('\s');
				coords::(i-1) := coords::i;
				coords::i := 255;
			end
			else do
				con.move(0, coords::i);
				con.wrch('\s');
			end
		end
	end
end

scroll() do
	scrollset(Objects, '@');
	Tick := Tick + 1;
	if (Tick mod Speed = 0) do
		Objects::(COLS-1) := rng.rand(Botseed - Topseed) + Topseed;
		con.move(COLS-1, Objects::(COLS-1));
		con.wrch('@');
	end
	scrollset(Top, '#');
	Top::(COLS-1) := Topseed;
	con.move(COLS-1, Top::(COLS-1));
	con.wrch('#');
	scrollset(Bottom, '#');
	Bottom::(COLS-1) := Botseed;
	con.move(COLS-1, Bottom::(COLS-1));
	con.wrch('#');
	if (Tick mod SMOOTHNESS = 0) do
		Topseed := Topseed + rng.rand(3)-1;
		if (Topseed < 0) Topseed := 0;
		if (Topseed > 5) Topseed := 5;
		Botseed := Botseed + rng.rand(3)-1;
		if (Botseed > LINES-1) Botseed := LINES-1;
		if (Botseed < LINES-5) Botseed := LINES-5;
	end
end

collision_in(coords) do var i, j;
	for (i=Sx, Sx+4)
		for (j=Sy, Sy+3)
			if (coords::i = j) return i;
	if (Coords::(Sx+4) = Sy+1) return Sx+4;
end

collision() do var x;
	x := collision_in(Objects); if (x) return x;
	x := collision_in(Top);     if (x) return x;
	x := collision_in(Bottom);  if (x) return x;
end

shipup() do
	if (Sy = 0) return;
	con.move(Sx,Sy+2);
	con.writes("\s\s\s\s\s");
	Sy := Sy - 1;
	drawship();
end

shipdown() do
	if (Sy >= LINES-3) return;
	con.move(Sx,Sy);
	con.writes("\s\s\s\s\s");
	Sy := Sy + 1;
	drawship();
end

disp(x, y, c) do
	if (x >= 0 /\ x < COLS /\ y >= 0 /\ y < LINES) do
		con.move(x, y);
		con.wrch(c);
	end
end

star(x, y, c) do var i;
	for (i=0, 10) do
		disp(x+i, y+i, c);
		disp(x-i, y+i, c);
		disp(x+i, y-i, c);
		disp(x-i, y-i, c);
		disp(x,   y+i, c);
		disp(x,   y-i, c);
		disp(x+i, y,   c);
		disp(x-i, y,   c);
		con.wait(100);
	end
end

boom() do
	star(Sx+2, Sy+1, '@');
	star(Sx+2, Sy+1, '\s');
end

play() do var k;
	while (%1) do
		scroll();
		con.move(COLS-1, LINES);
		con.wait(100);
		k := con.pollkey();
		     ie (k = 'q') leave;
		else ie (k = 'k') shipup();
		else ie (k = 'j') shipdown();
		else ;
		rng.reseed(k);
		if (collision()) do
			boom();
			leave;
		end
		if (Tick mod SPEEDUP = 0 /\ Speed > 1)
			Speed := Speed - 1;
	end
end

init() do
	con.setup([24,
		   "\e[H\e[J",
		   "\e[K",
		   "\e[%yd1;%xd1H",
		   "\eM",
		   "\e[?25l",
		   "\e[?25h",
		   "\e[7m",
		   "\e[m"]);
	con.csroff();
	con.clrscr();
	Sx := 15;
	Sy := 10;
	t.memfill(Objects, 255, COLS);
	t.memfill(Top, 255, COLS);
	t.memfill(Bottom, 255, COLS);
	Speed := 10;
	Tick := 0;
	Topseed := 0;
	Botseed := LINES-1;
end

fini() do
	con.move(0, LINES);
	con.csron();
	con.shutdown();
end

do
	init();
	drawship();
	play();
	fini();
end
