###############################
#	
# Snake game library disk
# © MightyPork
# 
# Requires:
#  * touchscreen
#  * speaker
#  * data disk "snake_data"
#
# How to use:
#
#   sn.Setup("touch", "speaker");
#
# optional - after Setup
#
#   sn.Colors(snake, food, walls);
#
# restart and play
#
#   sn.Clear();
#   sn.Start();
#
# sn.Start() ends when player dies,
# returning the score.
# 
# To start, click touchscreen. 
# Use ASDW to turn.
#
##############################

# setup all the basic stuff
function sn.Setup(touch, speaker){
	global sn.ts = touch;
	global sn.snd = speaker;
	
	# colors
	global CS = color("lime");
	global CF = color("orange");
	global CB = color("silver");
}

# optional - set colors.
# Must be followed by sn.Clear
function sn.Colors(snake, food, walls){
	CS = color(snake);
	CF = color(food);
	CB = color(walls);
}

# erase and rebuild screen, init variables.
function sn.Clear(){
	w = get(sn.ts+".w");
	h = get(sn.ts+".h");

	map.snake_data.clear();
		
	global sn.len = 0;
	
	global head.x = 30;
	global head.y = 28;
	global tail.x = 25;
	global tail.y = 28;
	
	set(sn.ts, -1);
	call(sn.ts+".line", head.x, head.y, tail.x, tail.y, CS);
	sn.placeFood();
	call(sn.ts+".frame", 0, 0, w-1, h-1, CB);	
	call(sn.ts+".line", 12, 23, 45, 23, CB);

	global dir.x = 1; global dir.y = 0;
	global tdir.x = 1; global tdir.y = 0;	
	global start = false;
}

# Start snakey main loop.
# ends when player dies - you can then
# restart the game.
function sn.Start(){
	# main snakey loop
	while(1){
		pause;
		if(!start) continue;
	
		# move head
		head.x += dir.x;
		head.y += dir.y;
		
		# look what's at head pos
		snext = sn.get(head.x, head.y);
		
		if(snext == CS || snext == CB){
			
			# bumped into tail or border
			sn.play("random.glass");
			# return to caller
			return sn.len;		
			
		}else if(snext == CF){
			
			# got a food
			# draw head
			sn.set(head.x, head.y, CS);	
			# inc tail counter		
			sn.len++;
			# play bells
			sn.play("random.levelup");
			# place new food
			sn.placeFood();
			
		}else{
			
			sn.set(head.x, head.y, CS);
			
			# move tail			
			vname = "t"+tail.x+"_"+tail.y;
			# chech if there's a turn mark set
			if(map.snake_data.has(vname)){
				# get turn key used here.
				# and turn tail acordingly
				td = map.snake_data.get(vname);
				if(td == "w"){
					tdir.y = -1;
					tdir.x = 0;
				}else 
				if(td == "s"){
					tdir.y = 1;
					tdir.x = 0;
				}else 
				if(td == "a"){
					tdir.y = 0;
					tdir.x = -1;
				}else 
				if(td == "d"){
					tdir.y = 0;
					tdir.x = 1;
				}
				# remove the mark.
				map.snake_data.unset(vname);
			}
			
			# remove tail pixel
			sn.set(tail.x, tail.y, -1);
			
			# move tail coord
			tail.x += tdir.x;
			tail.y += tdir.y;
		}
	}
}

# input from TS
function touchEvent(name, event, x, y, mb, key){	
	if(name != sn.ts) return;	
	if(event == "down"){
		# play/pause
		start = !start;	
	}	
	if(event == "key") sn.handleKey(key);	
}

# private: play sound
function sn.play(sound){
	call(sn.snd+".play", sound);
}

# private: get pixel at ts
function sn.get(x, y){
	return call(sn.ts, x, y);
}

# private: set pixel at ts
function sn.set(x, y, clr){
	return call(sn.ts, x, y, clr);
}

# private: set snake direction for key ASDW
function sn.handleKey(key){
	key = tolower(key);
	map.snake_data.set("t"+head.x+"_"+head.y, key);
		
	if(key == "w"){
		dir.x = 0; dir.y = -1;
		return;
	}	
	if(key == "s"){
		dir.x = 0; dir.y = 1;
		return;
	}	
	if(key == "a"){
		dir.x = -1; dir.y = 0;
		return;
	}
	if(key == "d"){
		dir.x = 1; dir.y = 0;
		return;
	}
	
}

# private: place food to a random empty pixel
function sn.placeFood(){
	while(1){
		food.x = rnd(0, get(sn.ts+".w")-1);
		food.y = rnd(0, get(sn.ts+".h")-1);		
		if(sn.get(food.x,food.y) == -1){
			sn.set(food.x,food.y,CF);
			break;
		}
	}	
}
