All pastes #619100 Raw Edit

UnboundLocalError

public python v1 · immutable
·published 2007-07-14 13:42 UTC
rendered paste body
from OpenGL.GL import *from cPickle import dump, loadimport libfovimport pygame#import hotshotimport randomimport sysimport osfrom math import sqrtdef loadImage(image):	textureSurface = pygame.image.load(image)	colorkey = textureSurface.get_at((0,0))	textureSurface.set_colorkey(colorkey, pygame.RLEACCEL)	textureData = pygame.image.tostring(textureSurface, "RGBA")	width = textureSurface.get_width()	height = textureSurface.get_height()	texture = glGenTextures(1)	glBindTexture(GL_TEXTURE_2D, texture)	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,			GL_UNSIGNED_BYTE, textureData)	return texture, width, heightdef line((x0,y0), (x1,y1)):	steep = abs(y1-y0) > abs(x1-x0)	if steep:		x0, y0 = y0, x0		x1, y1 = y1, x1	if x0 > x1:		x0, x1 = x1, x0		y0, y1 = y1, y0	dx = x1 - x0	dy = abs(y1 - y0)	er = -dx/2	ystep = 0	y = y0	if y0 < y1: ystep = 1	else: ystep = -1	for x in xrange(x0,x1):		if steep: yield (y,x)		else: yield (x,y)		er += dy		if er > 0:			y += ystep			if steep: yield (y,x)			else: yield (x,y)			er -= dxclass memoize(object):	"""Decorator that caches a function's return value each time it is called.		 If called later with the same arguments, the cached value is returned, and		 not re-evaluated. Slow for mutable types."""	def __init__(self, func):		self.func = func		self._cache = {}	def __call__(self, *args, **kwds):		key = args		if kwds:			items = kwds.items()			items.sort()			key = key + tuple(items)		if key in self._cache:			return self._cache[key]		self._cache[key] = result = self.func(*args, **kwds)		return resultdef dist2((x0,y0), (x1,y1)):	dx = x1-x0	dy = y1-y0	return dx*dx + dy*dy@memoizedef dist(p0,p1):	return sqrt(dist2(p0,p1))class Font:	def __init__(self, filename, fontspec=(10,12)):		self.font, self.w, self.h = loadImage(filename)		self.glyphw = fontspec[0]		self.glyphh = fontspec[1]		self.xchars = self.w / self.glyphw		self.ychars = self.h / self.glyphh		self.dls = {}		def drawc(self, c, pos=None):		if pos is not None:			x,y = pos			glTranslatef(x*self.glyphw, y*self.glyphh, 0)		if c in self.dls:			glCallList(self.dls[c])		else:			glCallList(self.build_dl(c))	def translate(self, x,y,z=0):		glTranslatef(x*self.glyphw, y*self.glyphh, z)	def build_dl(self, c):		y,x = divmod(c, self.xchars)		y *= float(self.glyphh)		x *= float(self.glyphw)		w = float(self.w)		h = float(self.h)		l = x/w		r = l+self.glyphw/w		t = y/h		b = t+self.glyphh/h		ls = glGenLists(1)		glNewList(ls, GL_COMPILE)		glBegin(GL_QUADS)		glTexCoord2f(l,t); glVertex2f(0,0)		glTexCoord2f(r,t); glVertex2f(self.glyphw,0)		glTexCoord2f(r,b); glVertex2f(self.glyphw,self.glyphh)		glTexCoord2f(l,b); glVertex2f(0,self.glyphh)		glEnd()		glEndList()		self.dls[c] = ls		return ls	def puts(self, str):		glBindTexture(GL_TEXTURE_2D, self.font)		for c in str:			self.drawc(ord(c))			glTranslatef(self.glyphw,0,0)FACE_L=0FACE_R=1FACE_T=2FACE_B=3CORNER_TL=4CORNER_BL=5CORNER_TR=6CORNER_BR=7TREE=0GROUND=1class Cell:	def __init__(self):		self.type = GROUND		self.seen = (0,0,0)		self.visible = False		self.clear_light()	def clear_light(self):		self.lit = [(0,0,0)]*8		self.mid_lit = (0,0,0)		#self.clear_visited()	def clear_visited(self):		self.visited = 0	def add_light(self, light, (d1,d2)):		if d1 is None:			self.mid_lit = tuple(map(max, zip(light, self.mid_lit)))		elif d2 is None:			self.lit[d1] = tuple(map(max, zip(light, self.lit[d1])))		else:			l1 = map((lambda a: a/2), light)			self.lit[d1] = tuple([min(1.0,a+b) for a,b in zip(self.lit[d1], l1)])			self.lit[d2] = tuple([min(1.0,a+b) for a,b in zip(self.lit[d2], l1)])class Map:	def __init__(self, font, width=64, height=40):		self.font = isinstance(font, str) and Font(font) or font		self.__cells = {}		self.width, self.height = width, height	def __getitem__(self, (x,y)):		if (x,y) in self.__cells: return self.__cells[x,y]		else:			self.__cells[x,y] = Cell()			return self.__cells[x,y]	def __contains__(self, (x,y)):		return x >= 0 and x < self.width and y >= 0 and y < self.height	def cells(self):		return self.__cells.iteritems()	def cansee(self, p0, p1):		for x,y in line(p0,p1):			if self[x,y].type is TREE:				return False		return True	def save(self, filename):		out = open(filename, 'wb')		dump(self.__cells, out, 2)		out.close()	def load(self, filename):		inf = open(filename, 'rb')		self.__cells = load(inf)		inf.close()def direction((sx,sy),(dx,dy)):	"""Returns a (dir1,dir2) pair containing the faces of dest(dx,dy) lit from a source at (sx,sy)"""	if sx < dx:		if sy < dy:			return (FACE_L, FACE_T)		if sy > dy:			return (FACE_L, FACE_B)		return (FACE_L, None)	if sx > dx:		if sy < dy:			return (FACE_R, FACE_T)		if sy > dy:			return (FACE_R, FACE_B)		return (FACE_R, None)	if sy < dy:		return (FACE_T, None)	if sy > dy:		return (FACE_B, None)	return (None, None)class circle:	def __init__(self, size):		self.vals = [0] * size		self._ptr = 0	def add(self, val):		self.vals[self._ptr] = val		self._ptr += 1		if self._ptr >= len(self.vals):			self._ptr = 0	def set(self, val):		self.vals[self._ptr] = valdef blend(t0,t1,a):	"""Skew tuple t0 towards tuple t1 with a bias (zero is towards t0) of a"""	fin = []	for v0,v1 in zip(t0,t1):		fin.append(v0+(v1-v0)*a)	return tuple(fin)def main():	random.seed()	pygame.init()	pygame.display.set_mode((640,480), pygame.OPENGL|pygame.DOUBLEBUF)	font = Font("curses_800x600.bmp")	board = Map(font, 64, 39)	fx, fy = -1,-1	px, py = board.width/2, board.height/2	if 0:#os.path.exists('save.pkl'):		board.load('save.pkl')		for _,c in board.cells():			c.clear_light()	else:#		for y in xrange(board.height):#			for x in xrange(board.width):#				c = board[x,y]#				c.type = GROUND#				c.char = ord(random.choice(["'",'.',',','`']))#				c.color = (random.uniform(0,0.3), random.uniform(0.2,1), 0.1)##		mapt = """w*.*...*#**......#...*....#...*....#**.*....#.....***#........#.......@#"""#		tx = 0#		ty = 0#		for tile in mapt:#			c = board[tx,ty]#			if tile == "\n":#				ty += 1#				tx = 0#				continue#			if tile == '.':#				tx += 1#				continue#			if tile == '*':#				c.type = TREE#				c.char = random.choice([ord('*'), 5])#				tx += 1#				continue#			if tile == 'w':#				fx, fy = tx, ty#				tx += 1#				continue#			if tile == '@':#				px, py = tx, ty#				tx += 1#				continue		#fx, fy = 17,17		for y in xrange(board.height):			for x in xrange(board.width):				if random.randint(0,3) <= 1:					board[x,y].char = ord('*')				else:					board[x,y].char = 5				board[x,y].type = TREE		# now walk out a cave		wx, wy = px, py		for _ in xrange(1000):			if fx < 0 and random.random() < 0.005:				fx, fy = wx, wy			c = board[wx,wy]			c.type = GROUND			c.color = (random.uniform(0,0.3), random.uniform(0.1,0.7), 0)			r = random.randint(0,3)			if r == 0:				c.char = ord(',')			elif r == 1:				c.char = ord('.')			elif r == 2:				c.char = ord("'")			elif r == 3:				c.char = ord('`')			d = random.randint(0,3)			if d == 0:				wx += 1			elif d == 1:				wx -= 1			elif d == 2:				wy += 1			elif d == 3:				wy -= 1			if wx >= board.width: wx = board.width-1			elif wx < 0: wx = 0			if wy >= board.height: wy = board.height-1			elif wy < 0: wy = 0	def opacity_test(self, x, y):		if (x,y) not in board: return 1		return (board[x,y].type is TREE or (x,y) == (px,py)) and 1 or 0	def apply_light(self, x, y, dx, dy, src):		if (x,y) in board:			c = board[x,y]			#if c.visited: return			#c.visited = 1			sx,sy,rad, color = src			opaque = opacity_test(self, x, y)			if not c.visible: return 1 # don't need to bother with lighting if it's not visible			#intensity = min(1.0,(rad/3.0)/(1 + dist2((sx,sy), (x,y))))			pct = 2.0 / (float(dist2((sx,sy),(x,y))) / float(rad*rad) + 1) - 1			intensity = max(0,min(1.0, 1.0*pct))			color = [min(1.0,a*intensity) for a in color]			if opaque:				dir = direction((sx, sy), (x, y))				if dir[1] is not None:					if dir == (FACE_L, FACE_T):						opl, opt = opacity_test(self, x-1, y), opacity_test(self, x, y-1)						if opl and opt:							dir = (CORNER_TL, None)						elif opl:							dir = (FACE_T, None)						elif opt:							dir = (FACE_L, None)					elif dir == (FACE_R, FACE_T):						opr, opt = opacity_test(self, x+1, y), opacity_test(self, x, y-1)						if opr and opt:							dir = (CORNER_TR, None)						elif opr:							dir = (FACE_T, None)						elif opt:							dir = (FACE_R, None)					elif dir == (FACE_L, FACE_B):						opl, opb = opacity_test(self, x-1, y), opacity_test(self, x, y+1)						if opl and opb:							dir = (CORNER_BL, None)						elif opl:							dir = (FACE_B, None)						elif opb:							dir = (FACE_L, None)					elif dir == (FACE_R, FACE_B):						opr, opb = opacity_test(self, x+1, y), opacity_test(self, x, y+1)						if opr and opb:							dir = (CORNER_BR, None)						elif opr:							dir = (FACE_B, None)						elif opb:							dir = (FACE_R, None)			else:				dir = (None,None)			c.add_light(color, dir)			return opaque and 1 or 0		return 1					def apply_sight(self, x, y, dx, dy, src):		if (x,y) in board:			c = board[x,y]			sx, sy, rad = src			c.visible = 2.0 / (float(dx*dx+dy*dy) / float(rad*rad) + 1) - 1			#return (c.type == TREE) and 1 or 0		return 1	fov = libfov.Settings()	fov.set_shape(0)	fov.set_opacity_test_function(opacity_test)	fov.set_apply_lighting_function(apply_light)	los = libfov.Settings()	los.set_shape(0)	los.set_opacity_test_function(opacity_test)	los.set_apply_lighting_function(apply_sight)	glMatrixMode(GL_PROJECTION)	glEnable(GL_TEXTURE_2D)	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)	glEnable(GL_BLEND)	glLoadIdentity()	glOrtho(0, 640, 480, 0, -1, 1)	glMatrixMode(GL_MODELVIEW)	glLoadIdentity()	glDisable(GL_DEPTH_TEST)	def randoff(x):		r = random.random()		if r >= 1.0-x: return 1		if r < x: return -1		return 0	TORCH='TORCH'	ELECTRIC='ELECTRIC'	sourcetype = TORCH	torchdown = False	torchx, torchy = 0,0	moves = circle(3)	clock = pygame.time.Clock()	while 1:		clock.tick(10)		glClear(GL_COLOR_BUFFER_BIT)		if torchdown:			lcx, lcy = torchx, torchy		else:			lcx, lcy = px,py		if sourcetype is TORCH:			rad = 8+randoff(0.1)*0.5			if not torchdown:				rad -= sum(moves.vals)			lcolor = (1,0.6,0.2)		elif sourcetype is ELECTRIC:			rad = 15			lcolor = (1,1,1)		los.fov_circle((px,py,40), px, py, 40)		fov.fov_circle((lcx,lcy,rad, lcolor), lcx, lcy, int(rad))		#for y in xrange(board.height):		#	for x in xrange(board.width):		#		board[x,y].clear_visited()		frad = 15+int(round(random.gauss(0,0.5)))		fov.fov_circle((fx,fy,frad, (1,0.7,0.6)), fx, fy, frad)		#board[lcx, lcy].lit = 1		for (x,y),c in board.cells():			if c.visible:				if opacity_test(None, x, y):					d1, d2 = dir = direction((px,py), (x,y))					color = [min(1.0,a+b) for a,b in zip(c.lit[d1], (d2 is None) and (0,0,0) or c.lit[d2])]					if dir == (FACE_L, FACE_T):						opl, opt = opacity_test(None, x-1, y), opacity_test(None, x, y-1)						if opl and opt:							color = c.lit[CORNER_TL]					elif dir == (FACE_R, FACE_T):						opr, opt = opacity_test(None, x+1, y), opacity_test(None, x, y-1)						if opr and opt:							color = c.lit[CORNER_TR]					elif dir == (FACE_L, FACE_B):						opl, opb = opacity_test(None, x-1, y), opacity_test(None, x, y+1)						if opl and opb:							color = c.lit[CORNER_BL]					elif dir == (FACE_R, FACE_B):						opr, opb = opacity_test(None, x+1, y), opacity_test(None, x, y+1)						if opr and opb:							color = c.lit[CORNER_BR]				else:					color = c.mid_lit				color = [a*c.visible for a in color]				c.seen = tuple(map(max, zip(color, c.seen)))			else:				color = (0,0,0)			if c.seen != (0,0,0):				glLoadIdentity()				board.font.translate(x,y)				if (x,y) == (fx,fy) and c.visible:					glColor3f(1*c.visible,0.5*c.visible,0)					board.font.drawc(ord('*'))				elif torchdown and (x,y) == (torchx, torchy) and c.visible:					glColor3f(0.9*c.visible,0.4*c.visible,0)					board.font.drawc(ord('$'))				elif c.type is TREE:					color = [max(seen*0.1, vis)*col for seen,vis,col in zip(c.seen, color, (0.4,1.0,0.2))]					glColor3f(*color)					board.font.drawc(c.char)				elif c.type is GROUND:					color = [max(seen*0.1, vis)*col for seen,vis,col in zip(c.seen, color, c.color)]					glColor3f(*color)					board.font.drawc(c.char)			"""if c.visible:				if opacity_test(None, x, y):					d1, d2 = direction((px, py), (x, y))					color = [min(1.0,a+b) for a,b in zip(c.lit[d1], (d2 is None) and c.mid_lit or c.lit[d2])]				else:					color = c.mid_lit			else:				color = c.seen			if c.seen != (0,0,0):				glLoadIdentity()				glTranslatef(x*board.font.glyphw, y*board.font.glyphh, 0) # XXX: think of a better way of doing this				if (x,y) == (fx,fy) and c.visible:					glColor3f(1,0.5,0)					board.font.drawc(ord('*'))				elif c.type is TREE:					#tcolor = (0.4,0.9,0.1)					# a light produces so many 'waves' of each color R,G,B.					# if the light produces 1.0 red, and the object reflects 90% of the red waves it receives, the final color is 0.9.					# thus, final color = light color * object color					#color = map((lambda x,y: x*y), tcolor, lcolor)					#color = blend((c.seen*0.15*tcolor[0], c.seen*0.15*tcolor[1], c.seen*0.15*tcolor[2]), color, c.lit)					color = [max(a*b,x) for a,b,x in zip(color, (0.4,0.9,0.1), c.seen)]					glColor3f(*color)					board.font.drawc(c.char)				elif c.type is GROUND:					#tcolor = c.color					#color = map((lambda x,y: x*y), list(tcolor), list(lcolor))					#color = blend((c.seen*0.15*c.color[0], c.seen*0.15*c.color[1], c.seen*0.15*c.color[2]), color, c.lit)					#color = blend(color, lcolor, c.lit/4.0)					color = [max(a*b,x) for a,b,x in zip(color, c.color, c.seen)]					glColor3f(*color)					board.font.drawc(c.char)"""		glLoadIdentity()		glTranslatef(px*board.font.glyphw, py*board.font.glyphh, 0)		glColor3f(1,1,1)		board.font.drawc(ord('@'))		pygame.display.flip()		moved = 0		def player_move(dx,dy):			if board[px+dx,py+dy].type is not TREE and (px+dx,py+dy) in board:				moved = 1				px += dx				py += dy		for event in pygame.event.get():			if event.type == pygame.QUIT:				sys.exit(0)			if event.type == pygame.KEYDOWN:				if event.key == pygame.K_DOWN or event.key == pygame.K_t:					player_move(0,1)				elif event.key == pygame.K_UP or event.key == pygame.K_n:					player_move(0,-1)				elif event.key == pygame.K_LEFT or event.key == pygame.K_h:					player_move(-1,0)				elif event.key == pygame.K_RIGHT or event.key == pygame.K_s:					player_move(1,0)				elif event.key == pygame.K_g:					player_move(-1,-1)				elif event.key == pygame.K_c:					player_move(1,-1)				elif event.key == pygame.K_b:					player_move(-1,1)				elif event.key == pygame.K_m:					player_move(1,1)				elif event.key == pygame.K_SPACE:					if torchdown:						torchdown = False					else:						torchx, torchy = px,py						torchdown = True				elif event.key == pygame.K_v:					board.save('save.pkl')				elif event.key == pygame.K_l:					if sourcetype is TORCH:						sourcetype = ELECTRIC					elif sourcetype is ELECTRIC:						sourcetype = TORCH		for y in xrange(board.height):			for x in xrange(board.width):				board[x,y].clear_light()				board[x,y].visible = False		moves.add(moved)if __name__ == "__main__":	#prof = hotshot.Profile("prof.log", 1)	#prof.runcall(main)	#prof.close()	main()