#!/usr/bin/python3
import webgame
import random
import time
import fhs

config = fhs.init({'monsters': 3, 'extra': 1, 'eggtime': 5, 'steptime': .3, 'monsterstep': 3})

num_players = 1

monday = {
		'story': (
	"You are a monster.",
	"A cute monster.",
	"Monsters are strange.",
	"They must lay eggs.",
	"If they touch their chilren, they die.",
	"You must make %d children." % config['monsters'],
	"Then you may leave.",
	"Use the space bar to lay eggs.",
	"Today is Monday.",
	"Press space to begin.  Go!"),
		'bg': 'monday.png',
		'board': (
			'############',
			'####.###.###',
			'####.###.###',
			'####.###.###',
			'####.###.###',
			'#.....@...^#',
			'####.###.###',
			'####.###.###',
			'####.###.###',
			'####.###.###',
			'############',
			'############'
			)
}
tuesday = {
		'story': (
	"You did it.",
	"Now you can rest.",
	"Tomorrow you must make %d child%s more." % (config['extra'], '' if config['extra'] == 1 else 'ren'),
	"Press space to start Tuesday."),
		'bg': 'tuesday.png',
		'board': (
			'############',
			'############',
			'###^.#######',
			'###.......##',
			'###.##.##.##',
			'###.##.##.##',
			'###.......##',
			'###.##.##.##',
			'###...@##.##',
			'############',
			'############',
			'############'
			)
}
wednesday = {
		'story': (
	"Another day survived.",
	"Regain your strength.",
	"Tomorrow you must make %d child%s more again." % (config['extra'], '' if config['extra'] == 1 else 'ren'),
	"Press space to start Wednesday."),
		'bg': 'wednesday.png',
		'board': (
			'############',
			'#..........#',
			'#.###.####.#',
			'#.###.####.#',
			'#.....####.#',
			'#.###^####.#',
			'#.###@####.#',
			'#.###......#',
			'#.###.####.#',
			'#.###.####.#',
			'#..........#',
			'############'
			)
}
thursday = {
		'story': (
	"It's getting harder every day.",
	"Tomorrow you must make %d child%s more again." % (config['extra'], '' if config['extra'] == 1 else 'ren'),
	"Do not fail.",
	"Press space to start Thursday."),
		'bg': 'thursday.png',
		'board': (
			'############',
			'####....####',
			'#####..#####',
			'##........##',
			'#####..#####',
			'##........##',
			'#####..#####',
			'##........##',
			'#####..#####',
			'##........##',
			'####.^@.####',
			'############'
			)
}
friday = {
		'story': (
	"So you made it again.",
	"You must get this work done.",
	"Work hard!",
	"Press space to start Friday."),
		'bg': 'friday.png',
		'board': (
			'############',
			'#...####...#',
			'#.#...^..#.#',
			'#...####...#',
			'##.######.##',
			'##.######.##',
			'##.######.##',
			'##.######.##',
			'#...####...#',
			'#.#..@...#.#',
			'#...####...#',
			'############'
			)
}
saturday = {
		'story': (
	"Still not dead?",
	"Good, then you can do more work.",
	"Get on with it!",
	"Press space to start Saturday."),
		'bg': 'saturday.png',
		'board': (
			'############',
			'############',
			'##........##',
			'##........##',
			'##........##',
			'##....^...##',
			'##...@....##',
			'##........##',
			'##........##',
			'##........##',
			'############',
			'############'
			)
}
sunday = {
		'story': (
	"You're doing better than the others.",
	"Don't get killed.",
	"Your parents can't afford that.",
	"Press space to start Sunday."),
		'bg': 'sunday.png',
		'board': (
			'############',
			'############',
			'#####..#####',
			'###......###',
			'###......###',
			'##....^...##',
			'##...@....##',
			'###......###',
			'###......###',
			'#####..#####',
			'############',
			'############'
			)
}
finale = {
		'story': (
	"So, you survived the week.",
	"I'll pay your parents.",
	"You're a hard worker.",
	"But you talk too much.",
	"Next week, don't talk about monsters.",
	"Just get the work done and don't get yourself killed.",
	"I'll see you tomorrow.",
	"...",
	"Congratulations, player!",
	"You finished the game.",
	"It will now restart."),
		'board': None
}

levels = [ monday, tuesday, wednesday, thursday, friday, saturday, sunday, finale ]

death = (
	"You were eaten by your kid!",
	"You died.",
	"Press space to restart."
)

def do_story(s = None):
	public.story = levels[public.level]['story'] if s is None else s
	yield 'continue'
	public.story = None

# Convert direction to coordinate difference.
d = {'n': (0, 1), 'e': (1, 0), 's': (0, -1), 'w': (-1, 0)}
dirs = (d['n'], d['e'], d['s'], d['w'])

def valid_target(target):
	if not 0 <= target[0] < len(board[0]) or not 0 <= target[1] < len(board):
		return False
	if public.board[target[1]][target[0]] == 1:
		return False
	if public.egg is not None and target[0] == public.egg[0] and target[1] == public.egg[1]:
		return False
	for k in public.kids:
		if target[0] == k[0] and target[1] == k[1]:
			return False
	return True

def make_board():
	global board
	src = levels[public.level]['board']
	if src is None:
		return False
	public.kids = []
	public.egg = None
	public.kids_needed = int(config['monsters']) + public.level * int(config['extra'])
	public.bg = levels[public.level]['bg']
	board = []
	for y, row in enumerate(src):
		board.insert(0, [])
		for x, tile in enumerate(row):
			if tile == '.':
				board[0].append(0)
			elif tile == '#':
				board[0].append(1)
			elif tile == '@':
				board[0].append(0)
				public.pos = [x, len(src) - 1 - y]
			elif tile == '^':
				board[0].append(0)
				public.exit = [x, len(src) - 1 - y]
	public.board = board
	return True

def move_kid(src):
	for i in range(10):
		dir = random.randrange(4)
		target = (src[0] + dirs[dir][0], src[1] + dirs[dir][1])
		if valid_target(target):
			return target
	return src

def killcheck(i):
	if public.kids[i][0] != public.pos[0] or public.kids[i][1] != public.pos[1]:
		return False
	webgame.broadcast.die()
	yield from do_story(death)
	return True

def play_level():
	yield from do_story()
	if not make_board():
		webgame.broadcast.win()
		return False
	timer = None
	queue = []
	nextstep = time.time()
	monsterphase = 0
	while True:
		now = time.time()
		while now >= nextstep:
			nextstep += config['steptime']
			monsterphase += 1
			if monsterphase >= config['monsterstep']:
				monsterphase = 0
				for i, k in enumerate(public.kids):
					public.kids[i] = move_kid(k)
					if (yield from killcheck(i)):
						return False
			if len(queue) > 0:
				cmd = queue.pop(0)
				if cmd == 'egg':
					if public.board[public.pos[1]][public.pos[0]] != 0 or timer is not None:
						continue
					timer = time.time() + config['eggtime']
					public.egg = public.pos
					webgame.broadcast.egg()
				elif cmd in d:
					target = [public.pos[t] + d[cmd][t] for t in range(2)]
					if valid_target(target):
						public.pos = target
					if len(public.kids) >= public.kids_needed and all(public.pos[t] == public.exit[t] for t in range(2)):
						webgame.broadcast.exit()
						return True
		if timer is not None:
			if now >= timer:
				# hatch.
				timeout = nextstep - now
				timer = None
				public.kids.append(public.egg)
				public.egg = None
				if len(public.kids) >= public.kids_needed and all(public.pos[t] == public.exit[t] for t in range(2)):
					webgame.broadcast.exit()
					return True
				if len(public.kids) == public.kids_needed:
					webgame.broadcast.open()
				else:
					webgame.broadcast.hatch()
				if (yield from killcheck(len(public.kids) - 1)):
					return False
			else:
				timeout = min(timer, nextstep) - now
		else:
			timeout = nextstep - now
		cmd = (yield ('n', 'e', 's', 'w', 'egg', timeout))
		if cmd is None:
			# Timeout.
			continue
		queue.append(cmd['command'])

def play():
	public.level = 0
	while (yield from play_level()):
		public.level += 1

def main():
	while True:
		yield from play()

webgame.Game(main, cmd = {'quit': webgame.quit})
