import pygame

class m2(list):
	def __init__(self,w,h,fill=None):
		for i in range(w):
			self.append([])
			for j in range(h):
				self[i].append(None)
		self.w = w
		self.h = h

class particle():
	def __init__(self,ary,mtx,x,y):
		if mtx[x][y]:
			return None
		self.mtx = mtx
		self.ary = ary
		self.x = x
		self.y = y
		self.mtx[x][y] = self
		self.ary.append(self)
		return self
		
	def xchg(self,x,y):
		if self.mtx[x][y] != None:
			self.mtx[x][y].y = self.y
			self.mtx[x][y].x = self.x
		self.mtx[self.x][self.y] , self.mtx[x][y] = self.mtx[x][y] , self.mtx[self.x][self.y]
		self.y = y
		self.x = x
		
	def remove(self):
		self.mtx[self.x][self.y] = None
		self.ary.remove(self)		
		
	def oktop(self):			return self.y > 0
	def okbottom(self):		return (self.y < (self.mtx.h-1))
	def okleft(self):			return self.x > 0
	def okright(self):		return (self.x < (self.mtx.w-1))

	def up(self):				return self.mtx[self.x][self.y-1]
	def down(self):			return self.mtx[self.x][self.y+1]
	def left(self):	 		return self.mtx[self.x-1][self.y]
	def right(self):			return self.mtx[self.x+1][self.y]

	def upleft(self):		 	return self.mtx[self.x-1][self.y-1]
	def downleft(self):	 	return self.mtx[self.x-1][self.y+1]
	def upright(self):		return self.mtx[self.x+1][self.y-1]
	def downright(self):		return self.mtx[self.x+1][self.y+1]

#==============================================================

sandcolor = (255,0,0)
rockcolor = (127,127,127)
watercolor = (0,0,255)
greencolor = (0,255,0)
firecolor = (255,255,0)
seedcolor = (255,0,255)
steamcolor = (0,0,127)
geothermiccolor = (255,127,0)

	
class rock(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = rockcolor
		
	def update(self):
		pass		

class water(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = watercolor
		
	def update(self):
		if self.okbottom():
			if not self.down():
				self.xchg(self.x,self.y+1)
			elif self.okright() and not self.right():
					self.xchg(self.x+1,self.y)
			elif self.okleft() and not self.left():
					self.xchg(self.x-1,self.y)

class sand(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = sandcolor
		
	def update(self):
		if self.okbottom():
			if self.down() == None:
				self.xchg(self.x,self.y+1)
			elif self.okright() and not self.downright():
				self.xchg(self.x+1,self.y+1)
			elif self.okleft() and not self.downleft():
				self.xchg(self.x-1,self.y+1)
			elif self.down() and self.down().color == watercolor:			
				self.xchg(self.x,self.y+1)
			elif self.okright() and self.downright() and self.downright().color == watercolor:
				self.xchg(self.x+1,self.y+1)
			elif self.okleft() and self.downleft() and self.downleft().color == watercolor:
				self.xchg(self.x-1,self.y+1)

class green(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = greencolor
		
	def update(self):
		if self.okbottom():
			if not self.down() or self.down().color == watercolor:
				self.xchg(self.x,self.y+1)	
		if self.oktop():
			if self.up():
				if self.up().color == sandcolor:
					self.xchg(self.x,self.y-1)
			else:
				if self.okleft() and self.upleft() and self.upleft().color == watercolor:
					self.upleft().remove()
					green(self.ary,self.mtx,self.x-1, self.y-1)
				elif self.okright() and self.upright() and self.upright().color == watercolor:
					self.upright().remove()
					green(self.ary,self.mtx,self.x+1, self.y-1)
			
class steam(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = steamcolor
		self.fuel = 100

	def update(self):
		if self.oktop() and (not self.up() or self.up().color == watercolor):
				self.xchg(self.x,self.y-1)
		elif self.okright() and (not self.right() or self.right().color == watercolor):
				self.xchg(self.x+1,self.y)
		elif self.okleft() and (not self.left() or self.left().color == watercolor):
				self.xchg(self.x-1,self.y)
		if (self.fuel != 0):
			self.fuel -= 1
		else:
			self.remove()
			water(self.ary,self.mtx,self.x,self.y)		
			
class fire(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = firecolor
		self.fuel = 40
			
	def update(self):
		#fire die
		if self.fuel == 0:
			self.remove()
			sand(self.ary,self.mtx,self.x,self.y)
		else:
			self.fuel -= 1
			#interaction with ...
			around = list()
			if self.oktop() and self.up():		around.append(self.up())
			if self.okbottom() and self.down():	around.append(self.down())
			if self.okleft() and self.left():	around.append(self.left())
			if self.okright() and self.right():	around.append(self.right())
			for blah in around:
				if blah.color == watercolor:
					self.fuel = 0
					blah.remove()
					steam(blah.ary,blah.mtx,blah.x,blah.y)
				elif blah.color == greencolor:
					blah.remove()
					fire(self.ary,self.mtx,blah.x,blah.y)
			#fire flow like water
			if self.okbottom():
				if not self.down():
					self.xchg(self.x,self.y+1)
				elif self.okright() and not self.right():
						self.xchg(self.x+1,self.y)
				elif self.okleft() and not self.left():
						self.xchg(self.x-1,self.y)

class geothermic(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = geothermiccolor

	def update(self):
		around = list()
		if self.oktop() and self.up():		around.append(self.up())
		if self.okbottom() and self.down():	around.append(self.down())
		if self.okleft() and self.left():	around.append(self.left())
		if self.okright() and self.right():	around.append(self.right())
		for blah in around:
			if blah.color == greencolor:
				blah.remove()
				fire(blah.ary,blah.mtx,blah.x,blah.y)
			elif blah.color == watercolor:
				blah.remove()
				steam(blah.ary,blah.mtx,blah.x,blah.y)

class seed(particle):
	def __init__(self,ary,mtx,x,y):
		if not particle.__init__(self,ary,mtx,x,y):
			return None
		self.color = seedcolor

	def update(self):
		if self.oktop() and self.up() and self.up().color == sandcolor:
			self.xchg(self.x,self.y-1)
		elif self.okbottom():
			if (not self.down()) or (self.down().color == watercolor):
				self.xchg(self.x,self.y+1)
			elif self.down().color == sandcolor:
				self.down().remove()
				self.remove()
				green(self.ary,self.mtx,self.x,self.y)
				green(self.ary,self.mtx,self.x,self.y+1)

#======================================================

def build_env(name):
	tmp_m = m2(80,50)
	tmp_a = list()
	tmp_l = pygame.image.load(name)
	for i in range(tmp_l.get_width()):
		for j in range(tmp_l.get_height()):
			tmpcolor = tmp_l.get_at((i, j))
			tmpcolor = (tmpcolor[0],tmpcolor[1],tmpcolor[2])
			if tmpcolor == rockcolor:
				rock(tmp_a,tmp_m,i,j)
			elif tmpcolor == sandcolor:
				sand(tmp_a,tmp_m,i,j)
			elif tmpcolor == watercolor:
				water(tmp_a,tmp_m,i,j)
			elif tmpcolor == greencolor:
				green(tmp_a,tmp_m,i,j)
			elif tmpcolor == seedcolor:
				seed(tmp_a,tmp_m,i,j)
			elif tmpcolor == firecolor:
				fire(tmp_a,tmp_m,i,j)
			elif tmpcolor == steamcolor:
				steam(tmp_a,tmp_m,i,j)
			elif tmpcolor == geothermiccolor:
				geothermic(tmp_a,tmp_m,i,j)
	return tmp_a,tmp_m

class blok_plot():
	def __init__(self):
		pass

	def plot(self,i,screen):
		tmprect = (i.x*scale,i.y*scale,scale,scale)
		pygame.draw.rect(screen, i.color,(tmprect))
		
	def draw(self,array,screen):
		screen.fill((0,0,0))
		for i in array:
			self.plot(i,screen)
			i.update()

class png_plot():
	def __init__(self):
		self.bgimage = pygame.image.load("cloud.png").convert()
		self.sandimage = pygame.image.load("sand.png").convert()
		self.waterimage = pygame.image.load("water.png").convert()
		self.greenimage = pygame.image.load("pelouse.png").convert()
		self.rockimage = pygame.image.load("rock.png").convert()
		self.fireimage = pygame.image.load("fire.png").convert()
		self.seedimage = pygame.image.load("seed.png").convert()
		self.seedimage.set_colorkey((0,0,0))
		self.steamimage = pygame.image.load("puff.png").convert()
		self.steamimage.set_colorkey((0,0,0))

	def plot(self,i,screen):
		tmprect = (i.x*scale,i.y*scale,scale,scale)
		if i.color == rockcolor:
			screen.blit(self.rockimage,tmprect,tmprect)
		elif i.color == sandcolor:
			screen.blit(self.sandimage,tmprect,tmprect)
		elif i.color == watercolor:
			screen.blit(self.waterimage,tmprect,tmprect)
		elif i.color == greencolor:
			screen.blit(self.greenimage,tmprect,tmprect)
		elif i.color == firecolor:
			#pygame.draw.rect(screen, (255,255,0),(tmprect))
			screen.blit(self.fireimage,tmprect,tmprect)
		elif i.color == seedcolor:
			screen.blit(self.seedimage,((i.x*scale)-4,(i.y*scale)-4,15,15))
		elif i.color == steamcolor:
			screen.blit(self.steamimage,((i.x*scale)-4,(i.y*scale)-4,15,15))
			#pygame.draw.rect(screen, steamcolor,(tmprect))
		elif i.color == geothermiccolor:
			pygame.draw.rect(screen, geothermiccolor,(tmprect))
		elif i.color == magmacolor:
			pygame.draw.rect(screen, magmacolor,(tmprect))

	def draw(self,array,screen):
		screen.blit(self.bgimage,(0,0))
		for i in array:
			self.plot(i,screen)
			i.update()		

#======================================================

if __name__ == "__main__":
	res = (640,400)
	scale = 8
	pygame.init()
	screen = pygame.display.set_mode(res)
	Clock = pygame.time.Clock()
	end = False
	#===================
	#render = blok_plot()
	render = png_plot()

	#array, matrix = build_env("_level.png")
	array, matrix = build_env("volcano.png")
	array, matrix = build_env("cheminer.png")
	#array, matrix = build_env("floating.png")
	#array, matrix = build_env("lab.png")
	#array, matrix = build_env("magma.png")
	#array, matrix = build_env("experiment0.png")		
	#===================
	while(not end):
		for event in pygame.event.get():
			if event.type == pygame.QUIT: end = True
			elif event.type == pygame.KEYDOWN:	
				if event.key == pygame.K_ESCAPE:	end = True
			elif event.type == pygame.MOUSEBUTTONDOWN:
				(mx,my) = event.pos
				it = matrix[mx/scale][my/scale]
				if event.button == 1:
					if it != None:
						it.remove()
					if it == None:
						fire(array,matrix,mx/scale,my/scale)
		#===================

		render.draw(array,screen)
		
		#===================	
		pygame.display.flip()	
		
