#include "spec.h"
#include <stdlib.h>

void Gtfo(Co c){
    TEnd();
    exit(0);
}

int DICE=5;//from a true dice throw, real randomness!!!
char Dice(){
	DICE = 7 + DICE * 13;//simple hashing technique, multiply by a prime, add another prime
	if (DICE<0)
	DICE=-DICE;
	return (DICE % 6) + 1;
}

void PrntNum(Let num, Let x, Let y, Color color){
	Let buffer[4] = {0}; 
	buffer[0] = (num/100)+'0';
	buffer[1] = ((num%100)/10)+'0';
	buffer[2] = (num%10)+'0';
	Prnt(buffer, x, y, color);
}

void AnyKey(Co c, Routine fn){
	Prnt("any Key",0,0,Green);
	Clr();
	if (Btn(Any)) c->routine = fn;
}

void QToExit(Co c, Routine fn){
	Prnt("Q to exit",0,0,Red);
	Clr();
	if (Btn(Esc)) c->routine = fn;
}

void Sqr(int col, int row, int w, int h, int c){
	for (int x=0;x<w;x++)
    for (int y=0;y<h;y++)
	Plt(col+x,row+y,c);
}


void Palette(char col,char row,char w, char h){
	for (int c = Black; c < Colors; c++) {
		Let xx = ((c-Black)%8);
		Let yy = ((c-Black)/8);
		for (int x=0; x<w; x++)
		for (int y=0; y<h; y++)
		Plt(col+(xx*w)+x,row+(yy*h)+y, c);
	}

    Let x = col;
    Let y = row + ( h * 8 ) + 1;

    for (Color c = Black; c < 8; c++ ){
        Plt(x + (c * w),y,c);
        Plt(x + (c * w),y+1,c*8);
    }

}

/*
I extract Pth from the co engine
because it have an algorithm
because it is closer to a turtle implementation
i want to devlop it further more

THE TURTLE
*/

void Pth(Let pth[],Let col, Let row, Color clr){
	Let vc=0, vr=0;
	Let rotation=0;
	Let repeat=1;
    //i explicitly dont want recursive branch
    Let scol=col, srow=row, svc=vc, svr=vr;
	while(*pth!=0){
		char c = *pth;
		if(c >= '2' && c <= '9') { repeat += *pth - '1'; }
		else if(c=='@'){ rotation+=repeat;repeat=1; }
		/*
			fucking color change, how the hell i do this ^
			anal-isis :
			white cyan magenta yellow red green blue black
			  W    C      M      Y     R    G    B     K
			these char dont seam here at all
			let take lower case and upper case
				
		*/
		else if(c=='W'){ clr = (clr & 0b01111000) | White; }
		else if(c=='K'){ clr = (clr & 0b01111000) | Black; }
		else if(c=='C'){ clr = (clr & 0b01111000) | Cyan; }
		else if(c=='M'){ clr = (clr & 0b01111000) | Magenta; }
		else if(c=='Y'){ clr = (clr & 0b01111000) | Yellow; }
		else if(c=='R'){ clr = (clr & 0b01111000) | Red; }
		else if(c=='G'){ clr = (clr & 0b01111000) | Green; }
		else if(c=='B'){ clr = (clr & 0b01111000) | Blue; }
 
		else if(c=='w'){ clr = (clr & 0b01000111) | Whiteless; }
		else if(c=='k'){ clr = (clr & 0b01000111) | Black; }
		else if(c=='c'){ clr = (clr & 0b01000111) | Cyanless; }
		else if(c=='m'){ clr = (clr & 0b01000111) | Magentaless; }
		else if(c=='y'){ clr = (clr & 0b01000111) | Yellowless; }
		else if(c=='r'){ clr = (clr & 0b01000111) | Redless; }
		else if(c=='g'){ clr = (clr & 0b01000111) | Greenless; }
		else if(c=='b'){ clr = (clr & 0b01000111) | Blueless; }
 
		else if(c=='{'){ /* save position */ scol=col; srow=row; svc=vc; svr=vr; }
		else if(c=='}'){ /* load position */ col=scol; row=srow; vc=svc; vr=svr; } 
		else if(c=='v'){ col-=vc; row-=vr; vc=0; vr=1; row+=repeat; repeat=1; }
		else if(c=='^'){ col-=vc; row-=vr; vc=0; vr=-1;row-=repeat; repeat=1; }
		else if(c=='<'){ col-=vc; row-=vr; vc=-1;vr=0; col-=repeat; repeat=1; }
		else if(c=='>'){ col-=vc; row-=vr; vc=1; vr=0; col+=repeat; repeat=1; }
		//               [reset position ] [direction] [repeat move]    [reset]
		else {
			if (vc==0 && vr==0) vc=1;
			for (int i=0;i<repeat;i++){
				if (c=='|') Sym(Vline,col,row,clr);
				else if (c=='-') Sym(Hline,col,row,clr);
				else if (c=='+') Sym(Rose,col,row,clr);
				else if (c=='L' && rotation%4==0) Sym(Lne,col,row,clr);
				else if (c=='L' && rotation%4==1) Sym(Lse,col,row,clr);
				else if (c=='L' && rotation%4==2) Sym(Lsw,col,row,clr);
				else if (c=='L' && rotation%4==3) Sym(Lnw,col,row,clr);
				else if (c=='T' && rotation%4==0) Sym(Tnn,col,row,clr);
				else if (c=='T' && rotation%4==1) Sym(Tne,col,row,clr);
				else if (c=='T' && rotation%4==2) Sym(Tns,col,row,clr);
				else if (c=='T' && rotation%4==3) Sym(Tnw,col,row,clr);
				else if (c=='O') Sym(Here,col,row,clr);
				else if (c=='#') Plt(col,row,clr);
				else if (c==' ') { /* just move forward */ }
				else {/*just do noting*/ col-=vc; row-=vr; }
				col+=vc;
				row+=vr;
                		rotation=0;
			}
			repeat = 1;
		}
		pth++;
	}
}



/*
Sprite System
Efficent because conio performance 
is worst than curses 
through ssh 
accross the web
it maintain two bitmask that tell 
witch pixel need to be redrawn to background
so we dont need to redraw the background entirely

fun to have
sprite dont redraw over another in the same frame
mean drawing from closest to farthest
and a single plot per cell
for now it is the sum of all pixel of all sprite
how?
Sprite is setting the bitmask when drawing a pixel
then he could just avoid doing anything 
if the bit is already set?
*/
#define CLEARW 40
#define CLEARH 25
char Mask[CLEARH][CLEARW/8][2] = {0};
void MaskSet(char x, char y){
	if (x>CLEARW) return;
	if (y>CLEARH) return;
	Mask[y][x/8][0] |= 1 << (x%8);
}
char MaskChgd(char x,char y){
	if (x>CLEARW) return 0;
	if (y>CLEARH) return 0;
	char bothLayer = ~(Mask[y][x/8][0] ^ Mask[y][x/8][1]);
	char isChanged = bothLayer & (1 << (x%8));
	return isChanged;
}
char MaskPltd(char x,char y){
	if (x>CLEARW) return 0;
	if (y>CLEARH) return 0;
	return Mask[y][x/8][0] & (1 << (x%8));
}
void MaskRoll(){
	for (int row=0; row<CLEARH ;row++)
	for (int col=0; col<CLEARW/8 ;col++)
	{
		Mask[row][col][1] = Mask[row][col][0];
		Mask[row][col][0] = 0;
	}
}
enum COLOR SprPal(char c){
	switch(c){
	case '.': return Colors;
	case 'k': return Black;
	case 'c': return Cyan;
	case 'b': return Blue;
	case 'w': return White;
	case 'y': return Yellow;
	case 'm': return Magenta;
	case 'g': return Green;
	case 'r': return Red;
	}
	return Colors;
}
void Spr(char ** spr, char col, char row){
	for (int row=0; spr[row] != 0; row++)
	for (int col=0; spr[row][col] != 0; col++)
	if(MaskPltd(col,row)==0)
	if(SprPal(spr[row][col])!=Colors)
	{
		Sqr(col*2,row,2,1,SprPal(spr[row][col]));
		MaskSet(col,row);
	}
}
//issue, black get over drawn
char ** _last_bg = 0;
void FixBg(char ** bg){
	for (int row=0; row<CLEARH && bg[row]!=0 ;row++)
	for (int col=0; col<CLEARW && bg[row][col]!=0 ;col++)
	if(MaskChgd(col,row)==0 || (_last_bg!=bg && MaskPltd(col,row)==0) )
	if(bg[row][col] != '.') 
	Sqr(col*2,row,2,1,SprPal(bg[row][col]));
	else Sqr(col*2,row,2,1,White);
	MaskRoll();
	if (_last_bg != bg) _last_bg = bg;
}

/*
just found about pico 8
virtual phantasy game console
128x128 16 colors lua
kinda cute and a lot of 8x8 sprites
this engine require that pixel be character
bare minimum character is 4x5
so it would fit a maximum of 
32x25 characters in that screen
vic20 is 22x25

a 40x25 screen with 4x5 char will need a 160x125 display
i am starting to see another potential i didnt considerer
tincity was fiting 128x128

just wondering
10x10 street figther
8x20 top gear third person
5x7 rtype sidescroller
5x5 megaman platformer

*/

char * _sprite_example[] = {
"...rrrw...wwrrr............",
"...rrrrr.wwwrrrw...........",
"..gygky..rrwwwwr...........",
"..gyyggy.rryyyyr...........",
"...gyyy..wwykykw...........",
".rrwccw....yyyy............",
"w.ccccbw.yccwwby...........",
"..g...g...gg.gg............",
"...........................",
"........",
".........",
0
}; 

/*
begin
*/


/* MAIN */

void Menu(Co c){
    Sqr(0,0,80,25,Black);
    Prnt("motherfuckin menu",20,5,White);
    Prnt("a => Artillery POC", 22, 7, Cyan);
    Prnt("d => Draw shit", 22, 8, Pink);
    Prnt("t => Tetris drawing", 22,9, Green);
    Prnt("i => Image drawing", 22,11, Yellow);//snorlax
    Prnt("s => Sprite Animation", 22, 13, Blue);//megaman
    Prnt("b => Bite", 22, 15, Magenta);//transition
    Prnt("c => City Map", 22,17, Red);//city
    Prnt("n => neon city animation", 22,19, Blue);
    Prnt("z => Zed ZetTea",22,20,Blue);
    Prnt("q => to get the fuck out", 22, 21, Red);

    if (Btn(Kq)) c->routine = 0;;
    Clr();
    if (Btn(Ka)) Do(Artillery,c->llection);
    if (Btn(Kd)) Do(Art,c->llection);
    if (Btn(Click)) Do(Art,c->llection);

    if (Btn(Kt)) Do(Tetris_Begin,c->llection);
    if (Btn(Ki)) Do(Snorlax,c->llection);
    if (Btn(Ks)) Do(Megaman,c->llection);
    if (Btn(Kb)) Do(Transition,c->llection);
    if (Btn(Kc)) Do(City,c->llection);
    if (Btn(Kn)) Do(TerminalRain,c->llection);
    if (Btn(Kz)) Do(Zzt, c->llection);
}


void test(Co c){
	Palette(30,0,3,2);
	
	Let i = 0;
	Prnt("unsigned 8 bits value", 0, 1, Blue);
	PrntNum(i, 20,1,White);

	Prnt("decrementation", 0, 2, Blue);
	PrntNum(--i, 20,2,White);

	Prnt("reincrement", 0, 3, Blue);
	PrntNum(++i, 20,3,White);


	AnyKey(c,0);
}

int main(){
	Routine routines[] = {
	    test,
        Menu,

		0
	};
	Let arr[100] = {0};
	TBegin();
	for (int i=0;routines[i]!=0;i++){
		Do(routines[i], arr);
	}
	TEnd();
	return 0;
}
