#!/usr/local/bin/python2.7 -u

# mop(e)snake - a simple snake game without too many features, but with
#               a one-button mode for an interesting different game
# 
# Copyright (C) 2006 Andy Balaam
# 
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
#

import pygame, os, sys, random, gc, md5
#import time
from mopelib import mopelib
from pygame.locals import * 

# ----------------------

class MyInputEvent:
	def  __init__( self, name ):
		self.pairs = []
		self.name = name

	def add_all( self, type ):
		self.pairs.append( ( type, -1 ) )

	def add( self, type, number ):
		self.pairs.append( ( type, number ) )

	def matches( self, event ):
		for p in self.pairs:
			type = p[0]
			number = p[1]
			if type == event.type:
				if number == -1:	# Any number is fine
					return True
				elif type == pygame.JOYBUTTONDOWN \
				  or type == pygame.JOYBUTTONUP \
				  or type == pygame.MOUSEBUTTONDOWN \
				  or type == pygame.MOUSEBUTTONUP:
					if number == event.button:
						return True
				elif type == pygame.KEYDOWN \
				  or type == pygame.KEYUP:
					if number == event.key:
						return True
		return False
	
	def __str__( self ):
		ans = "Input( '%s'" % self.name
		for p in self.pairs:
			ans += ", %d, %d" % ( p[0], p[1] )
		ans += " )"
		return ans

# ----------------------

class HashException( Exception ):
	pass

# ----------------------

def mkdir_if_needed( filename ):
	dr = os.path.split( filename )[0]
	if dr.strip() != "" and not os.path.isdir( dr ):
		os.mkdir( dr )

# ----------------------

class Hiscores:
	def __init__( self, hiscores_filename ):
		self.default_scores()
		self.filename = hiscores_filename
		
		try:
			self.read_scores()
		except HashException:
			print "Fiddling detected: don't trust the high scores!"
			#self.default_scores()
			# Comment this back in when you're sure it works.
		
		if len( self.scores[0] ) != 5:
			print "Creating high score table."
			self.default_scores()
		
	def read_scores( self ):
		current_array = -1
		next_hash = None
		
		try:
			f = open( self.filename, 'r' )
			ln = f.readline()
			lines_since_hash = 5
			while( ln ):
				
				if lines_since_hash == 5:	# Pathetic attempt at security
				
					lines_since_hash = 0
					if next_hash != None:
						expected_next_hash = self.hash_array(
							self.scores[current_array] )
						if expected_next_hash != next_hash:
							print expected_next_hash
							print "!="
							print next_hash
							#raise HashException()
					
					next_hash = ln.strip()
					
					current_array += 1
					
					del self.scores[current_array][:]
					
				else:
					lines_since_hash += 1
					split_ln = ln.split( ":", 1 )
					if len( split_ln ) == 2:
						self.scores[current_array].append( ( split_ln[0].strip(), int( split_ln[1] ) ) )
				
				ln = f.readline()
			f.close()
		except IOError:
			pass	# If the file didn't exist or couldn't be read, we continue
		
	
	def hash_array( self, array ):
		ans = ""
		for pair in array:
			ans += pair[0]
			ans += "."
			ans += str( pair[1] )
			ans += "|"
		
		m = md5.new()
		m.update( ans )
		return m.hexdigest()
	
	def save_array( self, f, array ):
		f.write( "%s\n" % self.hash_array( array ) );
		for pair in array:
			f.write( "%s : %d\n" % pair );
		
	def save( self ):
		mkdir_if_needed( self.filename )
		f = open( self.filename, 'w' )
		for arr in self.scores:
			self.save_array( f, arr )
		f.close()
		
	def default_scores( self ):
		self.scores = (
		  [ ( "Master",      10 ),	# Normal, Easy
			( "Of",           9 ),
			( "Pain",         8 ),
			( "(Eating)",     7 ),
			( "mop(e)snake",  6 ) ],
		  [ ( "Master",      50 ),	# Normal, Medium
			( "Of",          40 ),
			( "Pain",        30 ),
			( "(Eating)",    20 ),
			( "mop(e)snake", 10 ) ],
		  [ ( "Master",     100 ),	# Normal, Hard
			( "Of",          80 ),
			( "Pain",        60 ),
			( "(Eating)",    40 ),
			( "mop(e)snake", 20 ) ],
		  [ ( "Master",      10 ),	# Onebutton, Easy
			( "Of",           9 ),
			( "Pain",         8 ),
			( "(Eating)",     7 ),
			( "mop(e)snake",  6 ) ],
		  [ ( "Master",      50 ),	# Onebutton, Medium
			( "Of",          40 ),
			( "Pain",        30 ),
			( "(Eating)",    20 ),
			( "mop(e)snake", 10 ) ],
		  [ ( "Master",     100 ),	# Onebutton, Hard
			( "Of",          80 ),
			( "Pain",        60 ),
			( "(Eating)",    40 ),
			( "mop(e)snake", 20 ) ]
		  )

# ----------------------

class Config:
	
	def __init__( self, config_filename ):
		
		# Set the default config, and override if we find things in the
		# config file
		self.default_config()
		
		try:
			f = open( config_filename, 'r' )
			ln = f.readline()
			while( ln ):
				self.process_line( ln )
				ln = f.readline()
			f.close()
		except IOError:
			pass	# If the file didn't exist or couldn't be read, we continue
		
		# Ensure no-one tries to exploit us with a frigged config file
		self.filename = config_filename
		
	def process_line( self, ln ):
		ln = ln.strip()
		if len( ln ) > 0 and ln[0] != "#" and ln.find( '=' ) != -1:
			split_ln = ln.split( '=' )
			if len( split_ln ) == 2:
				key = split_ln[0].strip()
				value = split_ln[1]
				
				self.__dict__[key] = self.parse_value( value )
	
	def parse_value( self, value ):
		
		value = value.strip()
		if value[:5] == "Input":
			tup = self.parse_value( value[5:] )
			ret = MyInputEvent( tup[0] )
			for i in range( 1, len( tup ), 2 ):
				ret.add( tup[i], tup[i+1] )
			return ret
		
		elif value[0] == "(" and value[-1] == ")":
			return tuple( map( self.parse_value,
				value[1:-1].split( ',' ) ) )
			
		elif value[0] == "[" and value[-1] == "]":
			return map( self.parse_value,
				value[1:-1].split( ',' ) )
			
		elif ( value[0] == '"' and value[-1] == '"' ) \
		  or ( value[0] == "'" and value[-1] == "'" ):
			return value[1:-1]
		
		else:
			return (int)( value )
				
		
	def default_config( self ):
		self.colour_apple = ( 255, 255, 0 )
		self.colour_background = ( 0, 0, 64 )
		self.colour_border = ( 128, 128, 128 )
		self.colour_snake = ( 50, 255, 50 )
		self.colour_snake_arrow = ( 200, 250, 200 )
		self.colour_snake_arrow_fixed = ( 255, 255, 255 )
		self.level = LEVEL_EASY
		self.mode = MODE_NORMAL
		self.screen_size = ( 640, 480 )
		
		self.keys_menu = MyInputEvent( "Escape" )
		self.keys_menu.add( pygame.KEYDOWN, pygame.K_ESCAPE )
		self.keys_menu.add( pygame.JOYBUTTONDOWN, 8 )	# GP2X Start
		self.keys_menu.add( pygame.JOYBUTTONDOWN, 9 )	# GP2X Select
		
		self.keys_return = MyInputEvent( "Return" )
		self.keys_return.add( pygame.KEYDOWN, pygame.K_RETURN )
		self.keys_return.add( pygame.JOYBUTTONDOWN, 13 )	# GP2X B button
		
		self.keys_backspace = MyInputEvent( "Backspace" )
		self.keys_backspace.add( pygame.KEYDOWN, pygame.K_BACKSPACE )
		self.keys_backspace.add( pygame.JOYBUTTONDOWN, 2 )	# GP2X Joy left
		self.keys_backspace.add( pygame.JOYBUTTONDOWN, 11 )	# GP2X R button
		
		self.keys_startgame = MyInputEvent( "any key" )
		self.keys_startgame.add_all( pygame.KEYDOWN )
		self.keys_startgame.add_all( pygame.JOYBUTTONDOWN )
		self.keys_startgame.add_all( pygame.MOUSEBUTTONDOWN )
		
		self.keys_up = MyInputEvent( "up" )
		self.keys_up.add( pygame.KEYDOWN, ord( 'q' ) )
		self.keys_up.add( pygame.KEYDOWN, pygame.K_UP )
		self.keys_up.add( pygame.JOYBUTTONDOWN, 0 )		# GP2X Joy up
		self.keys_up.add( pygame.JOYBUTTONDOWN, 15 )	# GP2X Y button
		
		self.keys_right = MyInputEvent( "right" )
		self.keys_right.add( pygame.KEYDOWN, ord( 'p' ) )
		self.keys_right.add( pygame.KEYDOWN, pygame.K_RIGHT )
		self.keys_right.add( pygame.JOYBUTTONDOWN, 6 )	# GP2X Joy right
		self.keys_right.add( pygame.JOYBUTTONDOWN, 13 )	# GP2X B button
		
		self.keys_down = MyInputEvent( "down" )
		self.keys_down.add( pygame.KEYDOWN, ord( 'a' ) )
		self.keys_down.add( pygame.KEYDOWN, pygame.K_DOWN )
		self.keys_down.add( pygame.JOYBUTTONDOWN, 4 )	# GP2X Joy down
		self.keys_down.add( pygame.JOYBUTTONDOWN, 14 )	# GP2X X button
		
		self.keys_left = MyInputEvent( "left" )
		self.keys_left.add( pygame.KEYDOWN, ord( 'o' ) )
		self.keys_left.add( pygame.KEYDOWN, pygame.K_LEFT )
		self.keys_left.add( pygame.JOYBUTTONDOWN, 2 )	# GP2X Joy left
		self.keys_left.add( pygame.JOYBUTTONDOWN, 12 )	# GP2X A button
		
		self.keys_nextletter = MyInputEvent( "B" )
		self.keys_nextletter.add( pygame.JOYBUTTONDOWN, 6 )	# GP2X Joy right
		self.keys_nextletter.add( pygame.JOYBUTTONDOWN, 13 )# GP2X B button
		
		self.keys_finishedname = MyInputEvent( "Return" )
		self.keys_finishedname.add( pygame.KEYDOWN, pygame.K_RETURN )
		self.keys_finishedname.add( pygame.JOYBUTTONDOWN, 8 )	# GP2X Start
		
		self.keys_switchcase = MyInputEvent( "L" )
		self.keys_switchcase.add( pygame.JOYBUTTONDOWN, 10 )	# GP2X L button
		
		self.keys_volup = MyInputEvent( "+" )
		self.keys_volup.add( pygame.KEYDOWN, ord( '+' ) )
		self.keys_volup.add( pygame.KEYDOWN, ord( '=' ) )
		self.keys_volup.add( pygame.JOYBUTTONDOWN, 16 )	# GP2X volume + button
		
		self.keys_voldown = MyInputEvent( "-" )
		self.keys_voldown.add( pygame.KEYDOWN, ord( '-' ) )
		self.keys_voldown.add( pygame.JOYBUTTONDOWN, 17 ) # GP2X volume - button
		
		self.joystick_name_entry = 0
		self.loading_screen = 0
		
		self.hiscores_filename = os.path.expanduser( "~/.mopesnake/scores" )
		
		self.volume = 50
		
	
	def save( self ):
		mkdir_if_needed( self.filename )
		f = open( self.filename, 'w' )
		keys = self.__dict__.keys()
		keys.sort()
		for k in keys:
			if k != "filename" and k != "ingame_tick_time" and \
			  k != "hiscores":
				v = self.__dict__[k]
				if isinstance( v, str ):
					f.write( "%s = '%s'\n" % ( k, str(v) ) )
				else:
					f.write( "%s = %s\n" % ( k, str(v) ) )
		f.close()
		
	def init_tick_time( self ):
		if self.mode == MODE_NORMAL:
			if self.level == LEVEL_HARD:
				self.ingame_tick_time = ingame_tick_time_hard
			elif self.level == LEVEL_MEDIUM:
				self.ingame_tick_time = ingame_tick_time_medium
			else:
				self.ingame_tick_time = ingame_tick_time_easy
		else:
			if self.level == LEVEL_HARD:
				self.ingame_tick_time = ingame_tick_time_onebutton_hard
			elif self.level == LEVEL_MEDIUM:
				self.ingame_tick_time = ingame_tick_time_onebutton_medium
			else:
				self.ingame_tick_time = ingame_tick_time_onebutton_easy

# ----------------------

class MenuItem:
	def __init__( self, text, code ):
		self.code = code
		self.text = text

# ----------------------
	
class Menu:
	
	def __init__( self  ):
		self.selected_index = 0
		self.items = []
	
	def get_selected_item( self ):
		return self.items[self.selected_index]

	def add_item( self, text, code ):
		self.items.append( MenuItem( text, code ) )
	
	def move_up( self ):
		self.selected_index -= 1
		if self.selected_index == -1:
			self.selected_index = len( self.items ) - 1
	
	def move_down( self ):
		self.selected_index += 1
		if self.selected_index == len( self.items ):
			self.selected_index = 0

# ----------------------

class MopesnakeSoundManager( mopelib.SoundManager ):

	def __init__( self, volume ):
		mopelib.SoundManager.__init__( self, config,
			"the_final_rewind_loop.ogg" )
		
		self.add_sample_group( "ouches",
			["aaa1", "aei1", "eee1", "oow1", "ouch1", "ow1"] )
		
		self.add_sample_group( "mmms", ["aah2", "mmm3", "ooh1"] )

# ----------------------

def intro_draw_hiscores( config ):
	
	screen.blit( intro_surface_hiscs, (0,0) )
	
	i = 0
	lev_str = "%s Level, %s Mode" % ( lev_to_str( config.level ),
		mode_to_str( config.mode ) )
	
	write_text( lev_str, (247,235,5), 0.09, 0.36 )
	pos_start = config.level
	if config.mode == MODE_ONEBUTTON:
		pos_start += 3
	
	for pair in config.hiscores.scores[ pos_start ]:
		write_text( "%10s: %d" % pair,
			(247,235,5), 0.07, 0.5 + i*0.09 )
		i += 1
	
	intro_draw_instructions()
	
def preinit_draw_hiscores( config ):
	
	screen.fill( (0,0,0) )
	
	i = 0
	lev_str = "%s Level, %s Mode" % ( lev_to_str( config.level ),
		mode_to_str( config.mode ) )
	
	write_text( "Loading mop(e)snake ...", (255,255,255), 0.11, 0.15 )
	
	write_text( lev_str, (255,255,255), 0.09, 0.36 )
	pos_start = config.level
	if config.mode == MODE_ONEBUTTON:
		pos_start += 3
	
	for pair in config.hiscores.scores[ pos_start ]:
		write_text( "%10s: %d" % pair,
			(255,255,255), 0.07, 0.5 + i*0.09 )
		i += 1
	
	pygame.display.update()
	
# ----------------------

def intro_draw_instructions():
	write_text( "Press %s for menu, or %s to start" % (
		config.keys_menu.name, config.keys_startgame.name ),
		(0, 0, 0), 0.05, 0.99 )
	
# ----------------------

def lev_to_str( level ):
	if level == LEVEL_EASY:
		return "Easy"
	elif level == LEVEL_MEDIUM:
		return "Medium"
	else:
		return "Hard"

def mode_to_str( mode ):
	if mode == MODE_NORMAL:
		return "Normal"
	else:
		return "One-button"

# ----------------------

def general_menu_redraw( menu, gamestate ):
	screen.blit( ingame_surface_background, (0,0) )

	top_pos = 0.25
	bottom_pos = 0.75
	
	item_height = ( bottom_pos - top_pos ) / len( menu.items )
	text_height = item_height * 0.9
	
	cur_pos = top_pos
	for item in menu.items:
		if menu.get_selected_item() == item:
			write_text( item.text, (255,255,0), text_height, cur_pos )
		else:
			write_text( item.text, (0,150,0), text_height, cur_pos )
			
		cur_pos += item_height
	
	if gamestate == None:
		write_text( "mop(e)snake", (150,150,150), 0.06, 0.01 )
	else:
		write_text( "mop(e)snake paused", (150,150,150), 0.06, 0.01 )
	
	write_text( "Press %s and %s to navigate" % (
		config.keys_up.name, config.keys_down.name ), (150,150,150), 0.06, 0.9 )
	
	write_text( "and %s to select" % config.keys_return.name,
		(150,150,150), 0.06, 0.95 )
	
	pygame.display.update()

def general_menu_create_menu( menu, config, gamestate ):
	menu.items = []
	if gamestate == None:	# We are on a title screen - Start Game option
		menu.add_item( "Start game", MENU_START )
		menu.add_item( "Change level: %s" % lev_to_str( config.level ),
			MENU_LEVEL )
		menu.add_item( "Change mode: %s" % mode_to_str( config.mode ),
			MENU_MODE )
	elif gamestate.alive == INGAME_ALIVE:
		menu.add_item( "Continue game", MENU_START )
		menu.add_item( "End game", MENU_END )
	
	tmp_str = "Music: "
	if config.music_on:
		tmp_str += "on"
	else:
		tmp_str += "off"
	menu.add_item( tmp_str, MENU_MUSIC )
	
	tmp_str = "Effects: "
	if config.sound_effects_on:
		tmp_str += "on"
	else:
		tmp_str += "off"
	menu.add_item( tmp_str, MENU_SOUND_EFFECTS )
	
	#menu.add_item( "Define keys", MENU_KEYS )
	
	menu.add_item( "Quit mop(e)snake", MENU_QUIT )
	
	return menu
	
def general_menu_screen( config, gamestate ):
	
	menu = Menu()
	general_menu_create_menu( menu, config, gamestate )
	general_menu_redraw( menu, gamestate )
	
	game_start = False
	
	waiting = True
	while waiting:
		event = pygame.event.wait()
		if event.type == QUIT: 
			sys.exit(0)
		elif config.keys_menu.matches( event ):
			waiting = False
		elif config.keys_down.matches( event ):
			menu.move_down()
			general_menu_redraw( menu, gamestate )
		elif config.keys_up.matches( event ):
			menu.move_up()
			general_menu_redraw( menu, gamestate )
		elif config.keys_return.matches( event ):
			code = menu.get_selected_item().code
			if code == MENU_START:
				game_start = True
				waiting = False
			elif code == MENU_END:
				gamestate.alive = INGAME_QUIT
				waiting  = False
			elif code == MENU_MUSIC:
				if config.music_on:
					config.music_on = 0
				else:
					config.music_on = 1
				general_menu_create_menu( menu, config, gamestate )
				general_menu_redraw( menu, gamestate )
				sound_mgr.setup( gamestate )
				config.save()
			elif code == MENU_SOUND_EFFECTS:
				if config.sound_effects_on == 1:
					config.sound_effects_on = 0
				else:
					config.sound_effects_on = 1
				general_menu_create_menu( menu, config, gamestate )
				general_menu_redraw( menu, gamestate )
				sound_mgr.setup( gamestate )
				config.save()
			elif code == MENU_LEVEL:
				config.level += 1
				if config.level > LEVEL_HARD:
					config.level = LEVEL_EASY
				config.init_tick_time()
				general_menu_create_menu( menu, config, gamestate )
				general_menu_redraw( menu, gamestate )
				config.save()
			elif code == MENU_MODE:
				config.mode += 1
				if config.mode > MODE_ONEBUTTON:
					config.mode = MODE_NORMAL
				config.init_tick_time()
				general_menu_create_menu( menu, config, gamestate )
				general_menu_redraw( menu, gamestate )
				config.save()
			elif code == MENU_QUIT:
				sys.exit(0)
	
	return game_start

# ----------------------

def intro_draw_title():
	screen.blit( intro_surface_title, (0,0) )
	write_text( "Version " + mopesnake_version,
		( 0, 0, 0 ), 0.05, 0.78 )
	write_text( "by Andy Balaam", ( 0, 0, 0 ), 0.06, 0.85 )
	intro_draw_instructions()

def intro_input( event, config, intro_mode, frozen ): 
	if event.type == QUIT: 
		sys.exit(0)
	elif frozen:
		if event.type == pygame.USEREVENT:
			frozen = False
			pygame.time.set_timer( pygame.USEREVENT, title_tick_time )
	elif config.keys_volup.matches( event ):
		config.volume = sound_mgr.increase_volume()
		config.save()
	elif config.keys_voldown.matches( event ):
		config.volume = sound_mgr.decrease_volume()
		config.save()
	else:
		if event.type == pygame.USEREVENT:
			intro_mode += 1
			if intro_mode == INTRO_MODE_ENDED:
				intro_mode = INTRO_MODE_TITLE
			
			if intro_mode == INTRO_MODE_TITLE:
				intro_draw_title()
			elif intro_mode == INTRO_MODE_INSTR:
				screen.blit( intro_surface_instr, (0,0) )
				intro_draw_instructions()
			elif intro_mode == INTRO_MODE_HISCS:
				intro_draw_hiscores( config )
			elif intro_mode == INTRO_MODE_MUSIC:
				screen.blit( intro_surface_music, (0,0) )
				intro_draw_instructions()
			pygame.display.update()
		elif config.keys_menu.matches( event ):
			start_game = general_menu_screen( config, None )
			if start_game:
				intro_mode = INTRO_MODE_ENDED
			else:
				intro_draw_title()
				pygame.display.update()
		elif config.keys_startgame.matches( event ):
			intro_mode = INTRO_MODE_ENDED
	return ( intro_mode, frozen )

# ----------------------

def intro_mainloop( config, intro_mode, frozen ):
	if intro_mode == INTRO_MODE_HISCS:
		intro_draw_hiscores( config )
	else:
		intro_draw_title()
	
	pygame.display.update()
	
	if frozen:
		pygame.time.set_timer( pygame.USEREVENT, freeze_tick_time )
	else:
		pygame.time.set_timer( pygame.USEREVENT, title_tick_time )
	
	while intro_mode < INTRO_MODE_ENDED: 
		( intro_mode, frozen ) \
			= intro_input( pygame.event.wait(), config, intro_mode, frozen )
	
	pygame.time.set_timer( pygame.USEREVENT, 0 )
	pygame.event.clear( pygame.USEREVENT )	# Throw away extra events

# -------------------------------------------------------

def hits_snake( pos, snake_coords ):
	for i in snake_coords:
		if pos == i:
			return True
	return False

# -------------------------------------------------------

def rand_pos( arena_size ):
	return ( random.randint( 0, arena_size[0]-1 ),
		random.randint( 0, arena_size[1]-1 ) )

# -------------------------------------------------------

def place_apple( arena_size, snake_coords, current_pos ):
	pos = rand_pos( arena_size )
	
	# Only try 10 times to avoid landing on snake.
	# After that, just put up with it
	for i in range( 10 ):
		if hits_snake( pos, snake_coords ) or pos == current_pos:
			pos = rand_pos( arena_size )
		else:
			break
	return pos

# ----------------------

def coords_to_screen_point( coords ):
	return ( scale_factor[0] + ( coords[0] * scale_factor[0] ),
		scale_factor[1] + ( coords[1] * scale_factor[1] ) )

def coords_to_screen_rect_border( coords ):
	screen_tl = coords_to_screen_point( coords )
	return pygame.Rect( screen_tl[0], screen_tl[1],
		scale_factor[0], scale_factor[1] )

def coords_to_screen_rect_snake( coords ):
	screen_tl = coords_to_screen_point( coords )
	return pygame.Rect( screen_tl[0] + 1, screen_tl[1] + 1,
		scale_factor[0] - 2, scale_factor[1] - 2 )

# ----------------------

def draw_arrow( colour, coords, arrow_dir ):
	x_margin = 0.25
	x_middle = 0.5
	y_margin = 0.25
	y_middle = 0.5
	if arrow_dir == DIR_UP:
		pygame.draw.polygon( screen, colour,
			( coords_to_screen_point( ( coords[0] + x_margin,
				coords[1] + y_middle ) ),
			  coords_to_screen_point( ( coords[0] + x_middle,
				coords[1] + y_margin ) ),
			  coords_to_screen_point( ( coords[0] + 1 - x_margin,
				coords[1] + y_middle ) ) ) )
	elif arrow_dir == DIR_RIGHT:
		pygame.draw.polygon( screen, colour,
			( coords_to_screen_point( ( coords[0] + x_middle,
				coords[1] + y_margin ) ),
			  coords_to_screen_point( ( coords[0] + 1 - x_margin,
				coords[1] + y_middle ) ),
			  coords_to_screen_point( ( coords[0] + x_middle,
				coords[1] + 1 - y_margin ) ) ) )
	if arrow_dir == DIR_DOWN:
		pygame.draw.polygon( screen, colour,
			( coords_to_screen_point( ( coords[0] + x_margin,
				coords[1] + 1 - y_middle ) ),
			  coords_to_screen_point( ( coords[0] + x_middle,
				coords[1] + 1 - y_margin ) ),
			  coords_to_screen_point( ( coords[0] + 1 - x_margin,
				coords[1] + 1 - y_middle ) ) ) )
	elif arrow_dir == DIR_LEFT:
		pygame.draw.polygon( screen, colour,
			( coords_to_screen_point( ( coords[0] + 1 - x_middle,
				coords[1] + y_margin ) ),
			  coords_to_screen_point( ( coords[0] + x_margin,
				coords[1] + y_middle ) ),
			  coords_to_screen_point( ( coords[0] + 1 - x_middle,
				coords[1] + 1 - y_margin ) ) ) )

def ingame_draw_background( gamestate, dim = False ):
	screen.blit( ingame_surface_background, (0,0) )
	
	border_colour = dim_colour( gamestate.config.colour_border, dim )
	
	for i in range( -1, arena_size[0]+1 ):
		screen.fill( border_colour,
			coords_to_screen_rect_border( ( i, -1 ) ) )
		screen.fill( border_colour,
			coords_to_screen_rect_border( (
				i, arena_size[1] ) ) )
	for i in range( 0, arena_size[1]+1 ):
		screen.fill( border_colour,
			coords_to_screen_rect_border( ( -1, i ) ) )
		screen.fill( border_colour,
			coords_to_screen_rect_border( (
				arena_size[0], i ) ) )
	
	for coords in gamestate.snake_coords:
		screen.fill( dim_colour( gamestate.config.colour_snake, dim ),
			coords_to_screen_rect_snake( coords ) )
	
	pygame.display.update()

def dim_colour( colour, dim ):
	if dim:
		new_colour = ( colour[0] / 2, colour[1] /2, colour[2]/2 )
	else:
		new_colour = colour
	
	return new_colour
	
def ingame_draw_timestep( gamestate, dim = False ):
	
	dirty_rects = []
	
	back_of_snake = (gamestate.front_of_snake - 1) \
		% len( gamestate.snake_coords )
	
	tmp_rect = coords_to_screen_rect_snake( gamestate.behind_snake )
	screen.fill( gamestate.config.colour_background, tmp_rect )
	dirty_rects.append( tmp_rect )
	
	tmp_rect = coords_to_screen_rect_snake(
		gamestate.snake_coords[ gamestate.front_of_snake ] )
	screen.fill( dim_colour( gamestate.config.colour_snake, dim ),
		tmp_rect )
	dirty_rects.append( tmp_rect )

	if gamestate.config.mode == MODE_ONEBUTTON:
		head_coords = gamestate.snake_coords[ gamestate.front_of_snake ]
		
		next_pos_of_snake = (gamestate.front_of_snake + 1) % len( gamestate.snake_coords )
		
		tmp_rect = coords_to_screen_rect_snake(
			gamestate.snake_coords[ next_pos_of_snake ] )
		screen.fill( dim_colour( gamestate.config.colour_snake, dim ),
			tmp_rect )
		dirty_rects.append( tmp_rect )	
		
		if gamestate.dir_fixed:
			arrow_dir = gamestate.dirqueue[-1]
			col = gamestate.config.colour_snake_arrow_fixed
		else:
			arrow_dir = gamestate.get_arrow_dir()
			col = gamestate.config.colour_snake_arrow
		
		if gamestate.alive == INGAME_ALIVE:
			draw_arrow( dim_colour( col, dim ), head_coords, arrow_dir )
	
	tmp_rect = coords_to_screen_rect_snake( gamestate.apple_coords )
	pygame.draw.ellipse( screen,
		dim_colour( gamestate.config.colour_apple, dim ),
		tmp_rect )
	dirty_rects.append( tmp_rect )
	
	pygame.draw.lines( screen, (0,0,0), False, (
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.25,
			gamestate.apple_coords[1] + 0.71 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.28,
			gamestate.apple_coords[1] + 0.68 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.33,
			gamestate.apple_coords[1] + 0.65 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.51,
			gamestate.apple_coords[1] + 0.62 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.59,
			gamestate.apple_coords[1] + 0.65 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.64,
			gamestate.apple_coords[1] + 0.72 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.66,
			gamestate.apple_coords[1] + 0.78 ) ) ) )
	
	pygame.draw.line( screen, (0,0,0),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.41,
			gamestate.apple_coords[1] + 0.27 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.23,
		gamestate.apple_coords[1] + 0.34 ) ) )
	pygame.draw.line( screen, (0,0,0),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.61,
			gamestate.apple_coords[1] + 0.30 ) ),
		coords_to_screen_point( ( gamestate.apple_coords[0] + 0.76,
		gamestate.apple_coords[1] + 0.40 ) ) )
	
	if gamestate.oldscore != len( gamestate.snake_coords ):
		gamestate.oldscore = len( gamestate.snake_coords )
		tmp_rect = write_text_ingame( gamestate,
			"Score: %d    High: %d        Level: %s    Mode: %s"
			% ( len( gamestate.snake_coords ), hiscore_get_top( config ),
				lev_to_str( config.level ), mode_to_str( config.mode ) ),
			 )
		dirty_rects.append( tmp_rect )
	
	pygame.display.update( dirty_rects )


# ----------------------

def ingame_input( event, gamestate ):
	if event.type == QUIT: 
		sys.exit(0)
	elif( ( event.type == pygame.ACTIVEEVENT and event.state == 2 )
	   or config.keys_menu.matches( event ) ):
		general_menu_screen( config, gamestate )
		ingame_draw_background( gamestate )
		gamestate.oldscore = 0
		ingame_draw_timestep( gamestate )
	elif config.keys_volup.matches( event ):
		config.volume = sound_mgr.increase_volume()
		config.save()
	elif config.keys_voldown.matches( event ):
		config.volume = sound_mgr.decrease_volume()
		config.save()
	elif gamestate.config.mode == MODE_ONEBUTTON \
	  and not gamestate.dir_fixed \
	  and config.keys_startgame.matches( event ):
		gamestate.dirqueue.append( gamestate.get_arrow_dir() )
		gamestate.dir_fixed = True
		ingame_draw_timestep( gamestate )
	else:
		if len( gamestate.dirqueue ) > 0:
			last_dir = gamestate.dirqueue[-1]
		else:
			last_dir = gamestate.direction
		
		if config.keys_left.matches( event ) \
		  and last_dir != DIR_RIGHT \
		  and last_dir != DIR_LEFT:
			gamestate.dirqueue.append( DIR_LEFT )
		elif config.keys_right.matches( event ) \
		  and last_dir != DIR_LEFT \
		  and last_dir != DIR_RIGHT:
			gamestate.dirqueue.append( DIR_RIGHT )
		elif config.keys_up.matches( event ) \
		  and last_dir != DIR_DOWN \
		  and last_dir != DIR_UP:
			gamestate.dirqueue.append( DIR_UP )
		elif config.keys_down.matches( event ) \
		  and last_dir != DIR_UP \
		  and last_dir != DIR_DOWN:
			gamestate.dirqueue.append( DIR_DOWN )
		elif event.type == pygame.USEREVENT:
			gamestate.move_snake()
			ingame_draw_timestep( gamestate )
			
	

# ----------------------

def finishedgame_input( event, waiting ):
	if event.type == QUIT: 
		sys.exit(0)
	elif config.keys_volup.matches( event ):
		config.volume = sound_mgr.increase_volume()
		config.save()
	elif config.keys_voldown.matches( event ):
		config.volume = sound_mgr.decrease_volume()
		config.save()
	elif config.keys_startgame.matches( event ):
		waiting = False
	return waiting
	
# ----------------------

class GameState:
	
	def __init__( self, config ):
		self.config = config
		self.snake_coords = []
		self.front_of_snake = 0
		self.behind_snake = ( -2, -2 )
		self.oldscore = 0
		
		tmp_coord = [ arena_size[0] / 2, arena_size[1] / 2 ]
		for i in range(5):
			self.snake_coords.append( tmp_coord )
			tmp_coord = ( tmp_coord[0], tmp_coord[1] + 1 )
		
		self.apple_coords = place_apple( arena_size,
			self.snake_coords, (-1, -1) )
		self.direction = DIR_UP
		self.dirqueue = []
		self.alive = INGAME_ALIVE
		if config.mode == MODE_ONEBUTTON:
			self.arrowdir = ARROW_LEFT
			self.dir_fixed = False
	
	def get_arrow_dir( self ):
		ret = self.direction
		if self.arrowdir == ARROW_LEFT:
			ret -= 1
		else:
			ret += 1
		
		if ret < 0:
			ret = 3
		elif ret > 3:
			ret = 0
		
		return ret
	
	
	def move_snake( self ):
		
		if config.mode == MODE_ONEBUTTON and self.arrowdir == ARROW_LEFT:
			self.arrowdir = ARROW_RIGHT
		else:
			
			if config.mode == MODE_ONEBUTTON:
				self.arrowdir = ARROW_LEFT
				self.dir_fixed = False
			
			if len( self.dirqueue ) > max_dirs_in_queue:
				self.dirqueue = self.dirqueue[
					len( self.dirqueue ) - max_dirs_in_queue:]
			
			if len( self.dirqueue ) > 0:
				self.direction = self.dirqueue[0]
				self.dirqueue = self.dirqueue[1:]
			
			# Current position of head
			pos = self.snake_coords[ self.front_of_snake ]
			
			# Work out where we are moving to
			if self.direction == DIR_UP:
				pos = ( pos[0]  , pos[1]-1 )
			elif self.direction == DIR_RIGHT:
				pos = ( pos[0]+1, pos[1]   )
			elif self.direction == DIR_DOWN:
				pos = ( pos[0]  , pos[1]+1 )
			elif self.direction == DIR_LEFT:
				pos = ( pos[0]-1, pos[1]   )
			
			# Remove our tail
			self.front_of_snake -= 1
			if self.front_of_snake < 0:
				self.front_of_snake = len( self.snake_coords ) - 1
			
			# Check collision with wall
			if   pos[0] < 0 or pos[0] >= arena_size[0] \
			  or pos[1] < 0 or pos[1] >= arena_size[1]:
			  	sound_mgr.play_sample( "mmms" )
				self.alive = INGAME_DEAD
			else:
				# Remember where our tail was
				self.behind_snake = self.snake_coords[ self.front_of_snake ]
				# Move the tail piece off screen so we definitely can't hit it
				self.snake_coords[ self.front_of_snake ] = ( -2, -2 )
				
				# Check collision with snake
				if hits_snake( pos, self.snake_coords ):
					sound_mgr.play_sample( "mmms" )
					self.alive = INGAME_DEAD
				else:
					# Check collision with apple
					if pos == self.apple_coords:
						sound_mgr.play_sample( "ouches" )
						# If we hit apple, make ourselves longer
						for i in range( random.randrange(
						  score_apple_min, score_apple_max ) ):
							self.snake_coords.append( ( -2, -2 ) )
						# And re-place the apple
						self.apple_coords = place_apple(
							arena_size, self.snake_coords, self.apple_coords )
					# Place our head
					self.snake_coords[ self.front_of_snake ] = pos

# ----------------------

def ingame_mainloop( config ):
	
	gamestate = GameState( config )
	
	ingame_draw_background( gamestate )
	ingame_draw_timestep( gamestate )
	pygame.time.set_timer( pygame.USEREVENT, config.ingame_tick_time )
	
	gc.disable()
	while gamestate.alive == INGAME_ALIVE:
		ingame_input( pygame.event.wait(), gamestate )
	gc.enable()
	
	pygame.time.set_timer( pygame.USEREVENT, 0 )
	pygame.event.clear( pygame.USEREVENT )	# Throw away extra events
	
	ingame_draw_background( gamestate, True )
	ingame_draw_timestep( gamestate, True )
	
	return len( gamestate.snake_coords )

# ----------------------

def write_text( txt, colour, size, y_pos ):
	ft = pygame.font.Font( None, int( config.screen_size[1] * size ) )
	sf = ft.render( txt, True, colour )
	screen.blit( sf, ( (config.screen_size[0] - sf.get_width() )/2,
		(config.screen_size[1] - sf.get_height() ) * y_pos ) )

def write_text_ingame( gamestate, txt ):
	global ingame_font
	
	colour = (255,255,255)
	bgcolour = gamestate.config.colour_background
	y_pos = 0.99
	
	sf = ingame_font.render( txt, True, colour )
	sf_bg = pygame.Surface( ( int( sf.get_width() * 1.29 ), sf.get_height() ) )
	sf_bg.fill( bgcolour )
	
	dirty_rect = Rect( ( gamestate.config.screen_size[0]
		- sf_bg.get_width() )/2,
		( gamestate.config.screen_size[1] - sf_bg.get_height() ) * y_pos,
		sf_bg.get_width(), sf_bg.get_height() )
	screen.blit( sf_bg, dirty_rect )
	screen.blit( sf, ( (config.screen_size[0] - sf.get_width() )/2,
		(config.screen_size[1] - sf.get_height() ) * y_pos ) )
	
	return dirty_rect
	
		
def write_text_blank( bgcolour, txt, colour, size, y_pos, txt2=None,
		colour2 = None ):
	ft = pygame.font.Font( None, int( config.screen_size[1] * size ) )
	sf = ft.render( txt, True, colour )
	sf_bg = pygame.Surface( ( int( sf.get_width() * 1.29 ), sf.get_height() ) )
	sf_bg.fill( bgcolour )
	
	dirty_rect = Rect( (config.screen_size[0] - sf_bg.get_width() )/2,
		(config.screen_size[1] - sf_bg.get_height() ) * y_pos,
		sf_bg.get_width(), sf_bg.get_height() )
	screen.blit( sf_bg, dirty_rect )
	screen.blit( sf, ( (config.screen_size[0] - sf.get_width() )/2,
		(config.screen_size[1] - sf.get_height() ) * y_pos ) )
	
	if txt2 != None and txt2 != "":
		prev_width = sf.get_width()
		sf = ft.render( txt2, True, colour2 )
		screen.blit( sf, ( (config.screen_size[0] + prev_width )/2,
			(config.screen_size[1] - sf.get_height() ) * y_pos ) )

		
def hiscore_add_to_table( config, name, score ):
	pos = config.level
	if config.mode == MODE_ONEBUTTON:
		pos += 3
	hiscore_array = config.hiscores.scores[ pos ]
	for i in range( 5 ):
		if score > hiscore_array[i][1]:
			hiscore_array.insert( i, (name, score) )
			del hiscore_array[-1]
			break
	
# ----------------------

def hiscore_is_on_table( config, score ):
	pos = config.level
	if config.mode == MODE_ONEBUTTON:
		pos += 3
	hiscore_array = config.hiscores.scores[ pos ]
	return score > hiscore_array[-1][1]

# ----------------------

def hiscore_get_top( config ):
	pos = config.level
	if config.mode == MODE_ONEBUTTON:
		pos += 3
	hiscore_array = config.hiscores.scores[ pos ]
	return hiscore_array[0][1]

# ----------------------

def entername_update_screen( config, name, next_letter ):
	write_text_blank( config.colour_background,
		"Enter your name: %s" % name, (255,255,255),
		0.083, 0.69, next_letter, (0,255,0) )
	pygame.display.update()

def entername_input( event, config, waiting, name, next_letter, frozen ):
	if event.type == QUIT: 
		sys.exit(0)
	elif frozen:
		if event.type == pygame.USEREVENT:
			frozen = False
			if config.joystick_name_entry == 1:
				write_text( "Use %s/%s to select a letter, and %s to add it." %
					( config.keys_up.name, config.keys_down.name,
						config.keys_nextletter.name ),
						(255,255,255), 0.06, 0.80 )
			write_text( "Press %s to delete and %s when finished" % ( 
				config.keys_backspace.name, config.keys_finishedname.name ),
				(255,255,255), 0.06, 0.86 )
			entername_update_screen( config, name, next_letter )
	else:
		if config.keys_finishedname.matches( event ):
			name += next_letter
			waiting = False
		elif config.keys_backspace.matches( event ):
			if next_letter == "":
				name = name[:-1]
			else:
				next_letter = ""
			entername_update_screen( config, name, next_letter )
		elif config.joystick_name_entry == 1 and \
		  config.keys_up.matches( event ):
			if next_letter == "":
				next_letter = 'a'
			else:
				next_letter_ord = ord( next_letter ) + 1
				if next_letter_ord == ord( 'z' ) + 1:
					next_letter_ord = ord( '0' )
				elif next_letter_ord == ord( '9' ) + 1:
					next_letter_ord = ord( 'A' )
				elif next_letter_ord == ord( 'Z' ) + 1:
					next_letter_ord = ord( 'a' )
				next_letter = chr( next_letter_ord )
			entername_update_screen( config, name, next_letter )
		elif config.joystick_name_entry == 1 and \
		  config.keys_down.matches( event ):
			if next_letter == "":
				next_letter = 'Z'
			else:
				next_letter_ord = ord( next_letter ) - 1
				if next_letter_ord == ord( 'A' ) - 1:
					next_letter_ord = ord( '9' )
				elif next_letter_ord == ord( '0' ) - 1:
					next_letter_ord = ord( 'z' )
				elif next_letter_ord == ord( 'a' ) - 1:
					next_letter_ord = ord( 'Z' )
				next_letter = chr( next_letter_ord )
			entername_update_screen( config, name, next_letter )
		elif config.joystick_name_entry == 1 and \
		  config.keys_nextletter.matches( event ):
			name += next_letter
			next_letter = ""
			entername_update_screen( config, name, next_letter )
		elif config.joystick_name_entry == 1 and \
		  config.keys_switchcase.matches( event ):
			if next_letter != "":
				next_letter_ord = ord( next_letter )
				if next_letter_ord >= ord( 'a' ) and \
				  next_letter_ord <= ord( 'z'):
					next_letter_ord -= ord( 'a' ) - ord( 'A' )
				elif next_letter_ord >= ord( 'A' ) and \
				  next_letter_ord <= ord( 'Z'):
					  next_letter_ord += ord( 'a' ) - ord( 'A' )
				next_letter = chr( next_letter_ord )
			entername_update_screen( config, name, next_letter )  
		elif event.type == pygame.KEYDOWN:
			k = event.key
			if 0 <= k <= 255 and len( name ) <= 10:
				if 96 < k < 123 and event.mod & KMOD_SHIFT:
					k -= 32
				ch = chr( k )
				if ch != ",":
					name += ch
					entername_update_screen( config, name, next_letter )
	return ( waiting, name, next_letter, frozen )

# ----------------------

def finishedgame_mainloop( config, score ):
	
	# TODO: dim the screen first
	
	# Stop creating any events until this is over
	pygame.time.set_timer( pygame.USEREVENT, 0 )
	pygame.event.clear( pygame.USEREVENT )	# Throw away extra events
	
	if hiscore_is_on_table( config, score ):
		write_text( "High Score!", (255,255,255), 0.125, 0.3 )
		write_text( "Score: %d" % score, (255,255,255), 0.083, 0.49 )
		
		pygame.display.update()
		
		waiting = True
		frozen = True
		name = ""
		next_letter = ""
		pygame.time.set_timer( pygame.USEREVENT, freeze_tick_time )
		while waiting:
			( waiting, name, next_letter, frozen ) = entername_input(
				pygame.event.wait(), config, waiting, name, next_letter,
				frozen )
		
		if name == "":
			name = "anon"
		
		hiscore_add_to_table( config, name, score )
		config.hiscores.save()
		
	else:
		write_text( "Game Over", (255,255,255), 0.125, 0.3 )
		
		write_text( "Score: %d" % score, (255,255,255), 0.083, 0.59 )
		write_text( "High Score: %d" % hiscore_get_top( config ),
			(255,255,255), 0.083, 0.7 )
		write_text( "Press %s" % config.keys_startgame.name, (255,255,255),
			0.05, 0.8 )
		pygame.display.update()
		
		waiting = True
		while waiting:
			waiting = finishedgame_input( pygame.event.wait(), waiting )
	
	return INTRO_MODE_HISCS
	
# ----------------------

def load_and_scale_image( filename ):
	sur = pygame.image.load( os.path.join( images_dir, filename ) )
	
	if sur.get_size() != config.screen_size:
		sur = pygame.transform.scale( sur, config.screen_size )
	
	sur.convert()
	return sur

def read_mopesnake_version():
	f = file( os.path.join( config.install_dir, "version" ) )
	
	ln = f.readline()
	
	f.close()
	
	return ln.strip()
	
# ----------------------
# Execution starts here
# ----------------------

# Fixed constants

INTRO_MODE_TITLE = 0
INTRO_MODE_INSTR = 1
INTRO_MODE_HISCS = 2
INTRO_MODE_MUSIC = 3
INTRO_MODE_ENDED = 4

INGAME_ALIVE = 0
INGAME_DEAD = 1                   
INGAME_QUIT = 2

DIR_UP    = 0
DIR_RIGHT = 1
DIR_DOWN  = 2
DIR_LEFT  = 3

LEVEL_EASY      = 0
LEVEL_MEDIUM    = 1
LEVEL_HARD      = 2

MODE_NORMAL    = 0
MODE_ONEBUTTON = 1

ARROW_LEFT  = 0
ARROW_RIGHT = 1

MENU_START         = 0
MENU_END           = 1
MENU_LEVEL         = 2
MENU_MODE          = 3
MENU_KEYS          = 4
MENU_MUSIC         = 5
MENU_SOUND_EFFECTS = 6
MENU_QUIT          = 7

# Do only the absolute essential stuff before we put up the loading screen

num_args = len( sys.argv )
if num_args > 1:
	if sys.argv[1] == "--help":
		print "Usage:"
		print "mopesnake [install_dir] [config_file] [resolution]"
		print
		print "e.g. ./mopesnake.py . mopesnakerc.txt '(640,480)'"
		print
		sys.exit( 0 )
	
	install_dir = sys.argv[1]
else:
	install_dir = "."

if num_args > 2:
	config_filename = sys.argv[2]
else:
	config_filename = os.path.expanduser( "~/.mopesnake/config" )

images_dir = os.path.join( install_dir, "images" )

pygame.display.init()
pygame.font.init()

pygame.mouse.set_visible( False )

config = Config( config_filename )

config.install_dir = install_dir
config.music_dir = os.path.join( install_dir, "music" )

if num_args > 3:
	config.screen_size = config.parse_value( sys.argv[3] )

window = pygame.display.set_mode( config.screen_size )
pygame.display.set_caption( 'mop(e) snake' )
screen = pygame.display.get_surface()

# Display the loading screen

config.hiscores = Hiscores( config.hiscores_filename )

if config.loading_screen == 1:
	preinit_draw_hiscores( config )

# Tweaking constants

title_tick_time = 4000

ingame_tick_time_easy   = 300
ingame_tick_time_medium = 150
ingame_tick_time_hard   = 75

ingame_tick_time_onebutton_easy   = 500
ingame_tick_time_onebutton_medium = 250
ingame_tick_time_onebutton_hard   = 125

freeze_tick_time = 200

max_dirs_in_queue = 3

score_apple_min = 2
score_apple_max = 6

arena_size = ( 18, 12 )

scale_factor = ( config.screen_size[0] / (arena_size[0]+2),
	config.screen_size[1] / (arena_size[1]+3) )

# General initialisation

pygame.init()
random.seed()
num_joysticks = pygame.joystick.get_count()
for j in range( num_joysticks ):
        pygame.joystick.Joystick( j ).init()

config.init_tick_time()

ingame_font = pygame.font.Font( None, int( config.screen_size[1] * 0.05 ) )

intro_surface_title = load_and_scale_image( "title.png" )
intro_surface_instr = load_and_scale_image( "instructions.png" )
intro_surface_hiscs = load_and_scale_image( "hiscores.png" )
intro_surface_music = load_and_scale_image( "tryad.png" )

ingame_surface_background = pygame.Surface( screen.get_size() ).convert()
ingame_surface_background.fill( config.colour_background )

intro_mode = INTRO_MODE_TITLE
frozen = False

sound_mgr = MopesnakeSoundManager( config.volume / 100.0 )

mopesnake_version = read_mopesnake_version()

while True:
	sound_mgr.music_loud()
	intro_mainloop( config, intro_mode, frozen )
	sound_mgr.music_quiet()
	score = ingame_mainloop( config )
	intro_mode = finishedgame_mainloop( config, score )
	frozen = True



