import pygame
from pygame.locals import *
import math
import time
import os
import obj
import zombie
import spawn
from locals import *
import renderer
class Tile:
tilesets = []
wallsets = []
def __init__(self, tileset, type, leftwall, rightwall):
self.tileset = tileset
self.type = type
self.leftwall = leftwall
self.rightwall = rightwall
def load_tilesets():
f = open(os.path.join("tiles", "tiles.txt"))
num_tilesets = int(f.readline().strip())
for i in range(num_tilesets):
line = f.readline().strip()
Tile.tilesets.append(pygame.image.load(os.path.join("tiles", line + "floor.png")).convert_alpha())
Tile.wallsets.append(pygame.image.load(os.path.join("tiles", line + "wall.png")).convert_alpha())
class Map:
def __init__(self, width, height):
# Make sure the width and height are positive integers.
try:
width = int(width)
except:
width = 1
if width < 1:
width = 1
try:
height = int(height)
except:
height = 1
if height < 1:
height = 1
self.width = int(width)
self.height = int(height)
# grid stores the basic tiles, objects stores all game objects. Spawnpoints stores routes to other levels.
self.grid = []
self.objects = []
self.spawnpoints = []
for i in range(width*height):
self.grid.append(Tile(0,0,0,0))
def get_tile(self, pos):
x = int(math.floor(pos[0]))
y = int(math.floor(pos[1]))
if x < 0 or y < 0 or x >= self.width or y >= self.height:
return Tile(0,0,0,0)
return self.grid[int(math.floor(pos[0])) + int(math.floor(pos[1])) * self.width]
def draw(self, screen, offset, characters):
i = 0
rend = renderer.Renderer()
for y in range(self.height):
pos = [offset[0] - y * TILEWIDTH/2, offset[1] + y * TILEHEIGHT/2]
for x in range(self.width):
if self.grid[i].type > 0:
rect = pygame.Rect((self.grid[i].type - 1) * TILEWIDTH, 0, TILEWIDTH, TILEHEIGHT)
if (Variables.vdict["psychomode"]):
screen.blit(Tile.tilesets[5], pos, rect)
else:
screen.blit(Tile.tilesets[self.grid[i].tileset], pos, rect)
pos[0] += TILEWIDTH/2
pos[1] += TILEHEIGHT/2
i += 1
x,y = 0,0
while y < self.height or x < self.width:
if y < self.height and x < self.width:
rend.add_walls(self.get_tile((x,y)), (x, y))
x += 1
y -= 1
if y < 0 or x > self.width:
y = y + x + 1
x = 0
for object in self.objects:
rend.add_object(object)
rend.draw(screen, offset)
def update(self):
self.check_collisions()
for object in self.objects:
object.update(self)
#Old style wall rendering was here. Got removed in revision 290.
def check_collisions(self):
for o in self.objects:
if o.objtype == TYPE_OBJECT or o.dead or o.is_walkover():
continue
rect = o.get_rect()
rect.bottom += o.current_animation.dir[1]
rect.top += o.current_animation.dir[1]
rect.left += o.current_animation.dir[0]
rect.right += o.current_animation.dir[0]
stopped = False
# Tile 7 is a door. You don't collide with doors.
for x in range(int(math.ceil(rect.left)),int(math.ceil(rect.right))):
tile = self.get_tile((x, int(math.floor(rect.top))))
if not tile.type or (tile.leftwall and tile.leftwall != 7):
# This "try:" is a hack to make characters and zombies stop, but there's nothing like this
# for objects in general yet. Perhaps I'll make a general "you collided"
# function
try:
o.stop()
stopped = True
break
except:
pass
tile = self.get_tile((x, int(math.floor(rect.bottom))))
if not tile.type or (tile.leftwall and tile.leftwall != 7):
try:
o.stop()
stopped = True
break
except:
pass
if stopped:
continue
for y in range(int(math.ceil(rect.top)), int(math.ceil(rect.bottom))):
tile = self.get_tile((int(math.floor(rect.left)), y))
if not tile.type or (tile.rightwall and tile.rightwall != 7):
try:
o.stop()
stopped = True
break
except:
pass
tile = self.get_tile((int(math.floor(rect.right)), y))
if not tile.type or (tile.rightwall and tile.rightwall != 7):
try:
o.stop()
stopped = True
break
except:
pass
if stopped:
continue
for o2 in self.objects:
if o2.is_walkover(): # or o2.objtype == TYPE_CHARACTER or o2.objtype == TYPE_ENEMY:
continue
if o != o2:
rect2 = o2.get_rect()
rect2.bottom += o2.current_animation.dir[1]
rect2.top += o2.current_animation.dir[1]
rect2.left += o2.current_animation.dir[0]
rect2.right += o2.current_animation.dir[0]
if (rect.left >= rect2.left and rect.left <= rect2.right) or (rect.right >= rect2.left and rect.right <= rect2.right):
if rect.bottom >= rect2.top and rect.bottom <= rect2.bottom:
try:
o.stop()
stopped = True
except:
pass
elif rect.top >= rect2.top and rect.top <= rect2.bottom:
try:
o.stop()
stopped = True
except:
pass
#Selects an object pointed by the mouse. First prefers characters, then zombies, then ordinary items.
def select_object(self, offset, pos):
lastfound = None
lastenemy = None
lastchar = None
for o in self.objects:
spos = get_screen_pos(offset, o.pos)
#print spos
#print pos
rect = pygame.Rect(spos[0] - o.current_animation.center[0], spos[1] - o.current_animation.center[1],
o.current_animation.surface.get_width() / o.current_animation.frames, o.current_animation.surface.get_height())
if rect.collidepoint(pos[0], pos[1]):
if o.objtype == TYPE_CHARACTER:
lastchar = o
if o.objtype == TYPE_ENEMY:
lastenemy = o
if o.objtype == TYPE_SPAWNPOINT:
return o
lastfound = o
if lastchar:
return lastchar
if lastenemy:
return lastenemy
if lastfound:
return lastfound
return None
#This function returns a spawn point from a map
def getspawn(self, name):
result = (0,0)
for sp in self.spawnpoints:
if sp.spawn_to == name:
return sp.pos
return (0,0)
# This function takes parameters x and y in the tile coordinates, and returns coordinates on the screen.
# Offset is just a pair of numbers that is added to the result.
def get_screen_pos(offset, pos):
x,y = pos
return [offset[0] + x * TILEWIDTH/2 - y * TILEWIDTH/2 + TILEWIDTH/2, offset[1] + x * TILEHEIGHT/2 + y * TILEHEIGHT/2]
def get_map_pos(offset, pos):
x,y = pos
pos = (float(x - offset[0]), float(y - offset[1]))
#x = offset[0] + retx * TILEWIDTH/2 - rety * TILEWIDTH/2 + TILEWIDTH/2
#y = offset[1] + retx * TILEHEIGHT/2 + rety * TILEHEIGHT/2
#retx = 2*x/TILEWIDTH - 2*offset[0]/TILEWIDTH + rety - 1
#rety = 2*y/TILEHEIGHT - 2*offset[1]/TILEHEIGHT - retx
# retx = pos[0]/TILEWIDTH + pos[1]/TILEHEIGHT
retx = pos[1]/TILEHEIGHT + pos[0]/TILEWIDTH - 0.5
rety = -pos[0]/TILEWIDTH + pos[1]/TILEHEIGHT + 0.5
return (retx, rety)
# This function reads and parses a map file
def load_map(name):
filename = os.path.join("maps", name + ".txt")
f = open(filename)
str = f.readline()
strs = str.split()
#print strs
width = int(strs[0])
height = int(strs[1])
map = Map(width, height)
map.name = name
# Loads the spawnpoints from the file
num_spawnpoints = int(f.readline().strip())
for i in range(num_spawnpoints):
line = f.readline()
parts = line.split(" ")
spname,rx,ry = parts
spx = float(rx)
spy = float(ry)
sp = spawn.Spawnpoint(spname, (spx, spy))
map.spawnpoints.append(sp)
if sp.spawn_to != "default":
map.objects.append(sp)
num_enemies = int(f.readline().strip())
for i in range(num_enemies):
line = f.readline()
parts = line.split(" ")
objectname,rx,ry = parts
objectx = float(rx)
objecty = float(ry)
map.objects.append(zombie.Zombie(objectname, (objectx, objecty)))
# Loads the objects from the file and adds them to the objects array
num_objects = int(f.readline().strip())
for i in range(num_objects):
line = f.readline()
parts = line.split(" ")
objectname,rx,ry = parts
objectx = float(rx)
objecty = float(ry)
map.objects.append(obj.Object(objectname, (objectx, objecty)))
# Loads tiles from the file and adds them to the grid
i = 0
#print map.width, map.height
for tile in f.read().split():
map.grid[i].tileset = ord(tile[0])-65
map.grid[i].leftwall = int(tile[1])
map.grid[i].type = int(tile[2])
map.grid[i].rightwall = int(tile[3])
i += 1
f.close()
return map
# Testing code got removed in revision 290.