Skip to content

Instantly share code, notes, and snippets.

@silarsis
Created November 8, 2012 02:28
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save silarsis/4036185 to your computer and use it in GitHub Desktop.
Save silarsis/4036185 to your computer and use it in GitHub Desktop.
Pythonista Scripts
'''
Dungeon generator
Taken from http://roguebasin.roguelikedevelopment.org/index.php?title=Dungeon_builder_written_in_Python
and modified for purpose.
'''
# Class to produce random map layouts
from random import *
from math import *
import heapq
import scene
# constants
FLOOR = 0
DIRT = 1
WALL = 2
OPENDOOR = 3
CLOSEDDOOR = 4
SECRETDOOR = 5
class dMap:
def __init__(self):
self.roomList=[]
self.cList=[]
def makeMap(self,xsize,ysize,fail=40,b1=40,mrooms=20):
"""Generate random layout of rooms, corridors and other features"""
#makeMap can be modified to accept arguments for values of failed, and percentile of features.
#Create first room
self.mapArr = []
for x in range(xsize):
self.mapArr.append([])
for y in range(ysize):
self.mapArr[-1].append(DIRT)
w,l,t=self.makeRoom()
while len(self.roomList)==0:
y=randrange(ysize-1-l)+1
x=randrange(xsize-1-w)+1
p=self.placeRoom(l,w,x,y,xsize,ysize,6,0)
failed=0
while failed<fail: #The lower the value that failed< , the smaller the dungeon
chooseRoom=randrange(len(self.roomList))
ex,ey,ex2,ey2,et=self.makeExit(chooseRoom)
feature=randrange(100)
if feature<b1: #Begin feature choosing (more features to be added here)
w,l,t=self.makeCorridor()
else:
w,l,t=self.makeRoom()
roomDone=self.placeRoom(l,w,ex2,ey2,xsize,ysize,t,et)
if roomDone==0: #If placement failed increase possibility map is full
failed+=1
elif roomDone==2: #Possiblilty of linking rooms
if self.mapArr[ey2][ex2]==FLOOR:
if randrange(100)<7:
self.makePortal(ex,ey)
failed+=1
else: #Otherwise, link up the 2 rooms
self.makePortal(ex,ey)
failed=0
if t<5:
tc=[len(self.roomList)-1,ex2,ey2,t]
self.cList.append(tc)
self.joinCorridor(len(self.roomList)-1,ex2,ey2,t,50)
if len(self.roomList)==mrooms:
failed=fail
self.finalJoins()
def makeRoom(self):
"""Randomly produce room size"""
rtype=5
rwide=randrange(8)+3
rlong=randrange(8)+3
return rwide,rlong,rtype
def makeCorridor(self):
"""Randomly produce corridor length and heading"""
clength=randrange(18)+3
heading=randrange(4)
if heading==0: #North
wd=1
lg=-clength
elif heading==1: #East
wd=clength
lg=1
elif heading==2: #South
wd=1
lg=clength
elif heading==3: #West
wd=-clength
lg=1
return wd,lg,heading
def placeRoom(self,ll,ww,xposs,yposs,xsize,ysize,rty,ext):
"""Place feature if enough space and return canPlace as true or false"""
#Arrange for heading
xpos=xposs
ypos=yposs
if ll<0:
ypos+=ll+1
ll=abs(ll)
if ww<0:
xpos+=ww+1
ww=abs(ww)
#Make offset if type is room
if rty==5:
if ext==0 or ext==2:
offset=randrange(ww)
xpos-=offset
else:
offset=randrange(ll)
ypos-=offset
#Then check if there is space
canPlace=1
if ww+xpos+1>xsize-1 or ll+ypos+1>ysize:
canPlace=0
return canPlace
elif xpos<1 or ypos<1:
canPlace=0
return canPlace
else:
for j in range(ll):
for k in range(ww):
if self.mapArr[(ypos)+j][(xpos)+k]!=DIRT:
canPlace=2
#If there is space, add to list of rooms
if canPlace==1:
temp=[ll,ww,xpos,ypos]
self.roomList.append(temp)
for j in range(ll+2): #Then build walls
for k in range(ww+2):
self.mapArr[(ypos-1)+j][(xpos-1)+k]=WALL
for j in range(ll): #Then build floor
for k in range(ww):
self.mapArr[ypos+j][xpos+k]=FLOOR
return canPlace #Return whether placed is true/false
def makeExit(self,rn):
"""Pick random wall and random point along that wall"""
room=self.roomList[rn]
while True:
rw=randrange(4)
if rw==0: #North wall
rx=randrange(room[1])+room[2]
ry=room[3]-1
rx2=rx
ry2=ry-1
elif rw==1: #East wall
ry=randrange(room[0])+room[3]
rx=room[2]+room[1]
rx2=rx+1
ry2=ry
elif rw==2: #South wall
rx=randrange(room[1])+room[2]
ry=room[3]+room[0]
rx2=rx
ry2=ry+1
elif rw==3: #West wall
ry=randrange(room[0])+room[3]
rx=room[2]-1
rx2=rx-1
ry2=ry
if self.mapArr[ry][rx]==WALL: #If space is a wall, exit
break
return rx,ry,rx2,ry2,rw
def makePortal(self,px,py):
"""Create doors in walls"""
ptype=randrange(100)
if ptype>90: #Secret door
self.mapArr[py][px]=SECRETDOOR
return
elif ptype>75: #Closed door
self.mapArr[py][px]=CLOSEDDOOR
return
elif ptype>40: #Open door
self.mapArr[py][px]=OPENDOOR
return
else: #Hole in the wall
self.mapArr[py][px]=FLOOR
def joinCorridor(self,cno,xp,yp,ed,psb):
"""Check corridor endpoint and make an exit if it links to another room"""
cArea=self.roomList[cno]
if xp!=cArea[2] or yp!=cArea[3]: #Find the corridor endpoint
endx=xp-(cArea[1]-1)
endy=yp-(cArea[0]-1)
else:
endx=xp+(cArea[1]-1)
endy=yp+(cArea[0]-1)
checkExit=[]
if ed==0: #North corridor
if endx>1:
coords=[endx-2,endy,endx-1,endy]
checkExit.append(coords)
if endy>1:
coords=[endx,endy-2,endx,endy-1]
checkExit.append(coords)
if endx<78:
coords=[endx+2,endy,endx+1,endy]
checkExit.append(coords)
elif ed==1: #East corridor
if endy>1:
coords=[endx,endy-2,endx,endy-1]
checkExit.append(coords)
if endx<78:
coords=[endx+2,endy,endx+1,endy]
checkExit.append(coords)
if endy<38:
coords=[endx,endy+2,endx,endy+1]
checkExit.append(coords)
elif ed==2: #South corridor
if endx<78:
coords=[endx+2,endy,endx+1,endy]
checkExit.append(coords)
if endy<38:
coords=[endx,endy+2,endx,endy+1]
checkExit.append(coords)
if endx>1:
coords=[endx-2,endy,endx-1,endy]
checkExit.append(coords)
elif ed==3: #West corridor
if endx>1:
coords=[endx-2,endy,endx-1,endy]
checkExit.append(coords)
if endy>1:
coords=[endx,endy-2,endx,endy-1]
checkExit.append(coords)
if endy<38:
coords=[endx,endy+2,endx,endy+1]
checkExit.append(coords)
for xxx,yyy,xxx1,yyy1 in checkExit: #Loop through possible exits
if self.mapArr[yyy][xxx]==FLOOR: #If joins to a room
if randrange(100)<psb: #Possibility of linking rooms
self.makePortal(xxx1,yyy1)
def finalJoins(self):
"""Final stage, loops through all the corridors to see if any can be joined to other rooms"""
for x in self.cList:
self.joinCorridor(x[0],x[1],x[2],x[3],10)
def runGame():
import mainframe
scene.run(mainframe.Game())
if __name__ == '__main__':
runGame()
# This script downloads and opens a Gist from a URL in the clipboard.
# It's meant to be put in the editor's actions menu.
#
# It works with "raw" and "web" gist URLs, but not with non-Python files.
#
# If a file already exists, a dialog is shown that asks whether the
# new file should be renamed automatically.
import clipboard
import editor
import console
import re
import os
class InvalidGistURLError (Exception): pass
class NoFilesInGistError (Exception): pass
class GistDownloadError (Exception): pass
def download_gist(gist_url):
# Returns a 2-tuple of filename and content
# console.show_activity()
raw_match = re.match('http(s?)://raw.github.com/gist/', gist_url)
if raw_match:
import requests
from urlparse import urlparse
filename = os.path.split(urlparse(gist_url).path)[1]
try:
r = requests.get(gist_url)
content = r.text
yield filename, content
except:
raise GistDownloadError()
else:
gist_id_match = re.match('http(s?)://gist.github.com/([0-9a-f]*)', gist_url)
if gist_id_match:
import requests
gist_id = gist_id_match.group(2)
json_url = 'https://api.github.com/gists/' + gist_id
try:
import json
gist_json = requests.get(json_url).text
gist_info = json.loads(gist_json)
files = gist_info['files']
except:
raise GistDownloadError()
for file_info in files.values():
lang = file_info.get('language', None)
if lang != 'Python':
continue
filename = file_info['filename']
content = file_info['content']
yield filename, content
else:
raise InvalidGistURLError()
def main():
gist_url = clipboard.get()
num = 0
try:
for num, (filename, content) in enumerate(download_gist(gist_url), start=1):
if os.path.isfile(filename):
i = console.alert('File exists', 'A file with the name ' + filename +
' already exists in your library.',
'Auto Rename')
if i == 1:
editor.make_new_file(filename, content)
else:
editor.make_new_file(filename, content)
except InvalidGistURLError:
console.alert('No Gist URL',
'The clipboard doesn\'t seem to contain a valid Gist URL.',
'OK')
except GistDownloadError:
console.alert('Error', 'The Gist could not be downloaded.')
if not num:
console.alert('No Python Files', 'This Gist contains no Python files.')
if __name__ == '__main__':
main()
# Image Effects
# Demonstrates some effects using different modules
# from the Python Imaging Library (PIL).
#
# Tip: You can touch and hold an image in the output
# to copy it to the clipboard or save it to your
# camera roll.
import Image, ImageOps, ImageFilter
from Image import BILINEAR
from math import sqrt, sin, cos, atan2
def sketch(img):
edge_img = img.filter(ImageFilter.CONTOUR)
return ImageOps.grayscale(edge_img)
def color_tiles(img):
size = img.size
small_img = img.resize((size[0]/2, size[1]/2), BILINEAR)
bw_img = small_img.convert('1', dither=False)
gray_img = bw_img.convert('L')
result = Image.new('RGB', size)
tile1 = ImageOps.colorize(gray_img, 'green', 'red')
tile2 = ImageOps.colorize(gray_img, 'purple', 'yellow')
tile3 = ImageOps.colorize(gray_img, 'yellow', 'brown')
tile4 = ImageOps.colorize(gray_img, 'red', 'cyan')
result.paste(tile1, (0, 0))
result.paste(tile2, (size[0]/2, 0))
result.paste(tile3, (0, size[1]/2))
result.paste(tile4, (size[0]/2, size[1]/2))
return result
def twisted(img, strength):
mesh = []
m = 16
w, h = img.size
for x in xrange(w / m):
for y in xrange(h / m):
target_rect = (x * m, y * m, x * m + m, y * m + m)
quad_points = ((x * m, y * m), (x * m, y * m + m),
(x * m + m, y * m + m), (x * m + m, y * m))
quad_list = []
for qx, qy in quad_points:
dx = w/2 - qx
dy = h/2 - qy
d = sqrt(dx**2 + dy**2)
angle = atan2(dx, dy)
angle += max((w/2 - d), 0) * strength
qx = w/2 - sin(angle) * d
qy = h/2 - cos(angle) * d
quad_list.append(qx)
quad_list.append(qy)
mesh.append((target_rect, quad_list))
return img.transform(img.size, Image.MESH, mesh, BILINEAR)
def main():
img = Image.open('Test_Lenna')
img = img.resize((256, 256), Image.BILINEAR)
img.show()
sketch(img).show()
color_tiles(img).show()
twisted(img, 0.02).show()
if __name__ == '__main__':
main()
'Locations and their alternate types'
import scene
class Location(object):
passable = True
travelCost = 10
image = None
stroke = scene.Color(1, 1, 1)
def __init__(self, pos):
self.pos = pos
self.mapped = self.visible = False
self.contents = []
self.things = []
@property
def background(self):
if self.visible:
return scene.Color(0.9, 0.9, 0.9)
elif self.mapped:
return scene.Color(0.6, 0.6, 0.6)
else:
return scene.Color(0, 0, 0)
@property
def stroke_weight(self):
if self.visible or self.mapped:
return 1
return 0
def drawTo(self, tile):
tile.image = None
if tile.board.player and self.mapped:
tile.image = self.image
if self.contents and tile.board.player.canSeeNPC(self.contents[0]):
tile.image = self.contents[0].image
elif self.things and tile.board.player.canSeeThing(self.things[0]):
tile.image = self.things[0].image
tile.background = self.background
tile.stroke = self.stroke
tile.stroke_weight = self.stroke_weight
tile.draw()
def placeThing(self, thing):
self.things.append(thing)
thing.location = self
def removeThing(self, thing):
self.things.remove(thing)
thing.location = None
class FloorLoc(Location):
'floor - basic location'
passable = True
class DirtLoc(Location):
'dirt - unpassable'
passable = False
#image = 'PC_Tree_Tall'
@property
def background(self):
if self.visible:
return scene.Color(0.5, 0.5, 0.5)
elif self.mapped:
return scene.Color(0.3, 0.3, 0.3)
else:
return scene.Color(0, 0, 0)
class WallLoc(DirtLoc):
'wall - special dirt'
passable = False
def runGame():
import mainframe
scene.run(mainframe.Game())
if __name__ == '__main__':
runGame()
#!/bin/env python
'Mainframe rogue like'
import time
import random
import scene
import sound
import functools
import heapq
import dungeon
from mobiles import NPC, Player
from locations import * # XXX fix this
from things import * # and this
TICKTIME = 0.1
NPCCOUNT = 5
class Tile(scene.Layer):
def __init__(self, x, y, border, tileWidth, tileHeight, board):
self.pos = (x, y)
super(Tile, self).__init__(scene.Rect(x*tileWidth+border, y*tileHeight+border, tileWidth, tileHeight))
board.boardLayer.add_layer(self)
self.board = board
class Board(object):
def __init__(self, root_layer):
self.root_layer = root_layer
self.tileWidth = 20
self.tileHeight = 20
self.boardWidth = 40
self.boardHeight = 35
self.mapWidth = 100
self.mapHeight = 100
self.boardOffsetX = self.boardOffsetY = 0
self.player = None
self.map = {}
self.board = {}
self.genMap()
self.genBoard()
self.locsToDraw = set()
def genMap(self):
dungeonMap = dungeon.dMap()
dungeonMap.makeMap(self.mapWidth, self.mapHeight)
for x in range(self.mapWidth):
for y in range(self.mapHeight):
if dungeonMap.mapArr[x][y] == dungeon.DIRT:
self.map[(x, y)] = DirtLoc((x, y))
elif dungeonMap.mapArr[x][y] == dungeon.WALL:
self.map[(x, y)] = WallLoc((x, y))
else:
self.map[(x, y)] = FloorLoc((x, y))
def genBoard(self):
self.border = border = 5
board = scene.Layer(scene.Rect(0, 0, self.tileWidth*self.boardWidth+border*2, self.tileHeight*self.boardHeight+border*2))
board.stroke = scene.Color(1, 1, 1)
board.stroke_weight = 5
board.ignore_touches = True
self.boardLayer = board
self.root_layer.add_layer(board)
for x in range(self.boardWidth):
for y in range(self.boardHeight):
tile = self.board[(x, y)] = Tile(x, y, border, self.tileWidth, self.tileHeight, self)
def redrawBoard(self):
for x in range(self.boardWidth):
for y in range(self.boardHeight):
loc = self.locationForBoardPos(x, y)
if loc:
loc.drawTo(self.board[(x, y)])
self.locsToDraw.clear()
def boardToMap(self, x, y):
'convert loc(x, y) to map(x, y)'
return(x + self.boardOffsetX, y + self.boardOffsetY)
def mapToBoard(self, x, y):
'returns board coords for map location, None if x or y not displayed currently'
return (x - self.boardOffsetX, y - self.boardOffsetY)
def tileForMapPos(self, x, y):
coords = self.mapToBoard(x, y)
return self.board.get(coords, None)
def locationForBoardPos(self, x, y):
coords = self.boardToMap(x, y)
return self.map.get(coords, None)
def tileAtTouchPos(self, pos):
x = int((pos[0] - self.border) / self.tileWidth)
y = int((pos[1] - self.border) / self.tileHeight)
return self.board.get((x, y), None)
def boardPosition(self, actor):
try:
return self.mapToBoard(*actor.location.pos)
except:
return None
def placeActor(self, actor, centreBoard=True):
# place the player or NPC in a random location
validDests = [loc for loc in self.map.values() if loc.passable and not loc.contents]
x, y = random.choice(validDests).pos
self.move(actor, x, y)
if centreBoard:
self.centreBoardOn(x, y)
tile = self.tileForMapPos(x, y)
if not tile:
print x, y, self.boardOffsetX, self.boardOffsetY
return tile.pos
def placeStairs(self):
validDests = [loc for loc in self.map.values() if loc.passable and not loc.contents]
loc = random.choice(validDests)
loc.placeThing(StairsUp())
validDests.remove(loc)
loc = random.choice(validDests)
loc.placeThing(StairsDown())
def visibleLocations(self, actor):
'loc coords are map coords'
pos = actor.location
if pos:
for dx in range(-actor.lightRange, actor.lightRange+1):
for dy in range(-actor.lightRange, actor.lightRange+1):
loc = self.map.get((pos.pos[0]+dx, pos.pos[1]+dy), None)
if loc and actor.canSeeLocation(loc):
yield loc
def centreBoardOn(self, x, y):
'x, y are map coords'
# we offset the centre, because it's easy. However, we need to ensure we
# don't go past the edges...
boardCentreX = int(self.boardWidth / 2)
boardCentreY = int(self.boardHeight / 2)
minOffsetX = 0
maxOffsetX = self.mapWidth - self.boardWidth
minOffsetY = 0
maxOffsetY = self.mapHeight - self.boardHeight
newOffsetX = max(min(x - boardCentreX, maxOffsetX), minOffsetX)
newOffsetY = max(min(y - boardCentreY, maxOffsetY), minOffsetY)
print 'centreBoardOn', newOffsetX, newOffsetY, minOffsetX, maxOffsetX, x, y
redraw = False
if newOffsetX != self.boardOffsetX:
self.boardOffsetX = newOffsetX
redraw = True
if newOffsetY != self.boardOffsetY:
self.boardOffsetY = newOffsetY
redraw = True
if redraw:
self.redrawBoard()
def isOnEdge(self, x, y):
'x, y are board coords'
if x == 0 or y == 0:
return True
if x == self.boardWidth-1 or y == self.boardHeight-1:
return True
return False
def move(self, actor, x, y):
'x, y are map co-ords'
print 'entering move', actor
srcLoc = actor.location
dstLoc = self.map.get((x, y), None)
if srcLoc is None:
srcTile = None
else:
srcTile = self.tileForMapPos(*srcLoc.pos)
if dstLoc is None:
dstTile = None
else:
dstTile = self.tileForMapPos(x, y)
if dstLoc:
if not dstLoc.passable:
return
if dstLoc is srcLoc:
return
if dstLoc.contents:
actor.attack(dstLoc.contents[0])
actor.path = None
return
if actor is not self.player:
if srcLoc:
self.locsToDraw.add(srcLoc)
if dstLoc:
self.locsToDraw.add(dstLoc)
# Now, update the actor location
actor.moveTo(dstLoc)
return
# dstTile check for multi square move into the non board area
if dstTile is None or self.isOnEdge(*dstTile.pos):
# move the board here...
self.centreBoardOn(x, y)
dstTile = self.tileForMapPos(x, y)
oldVisible = set(self.visibleLocations(actor))
# actually move
actor.moveTo(dstLoc)
# work out what to redraw
newVisible = set(self.visibleLocations(actor))
for loc in oldVisible.difference(newVisible):
loc.visible = False
loc.mapped = True
for loc in newVisible.difference(oldVisible):
loc.mapped = loc.visible = True
self.locsToDraw.update(oldVisible, newVisible)
def updateTiles(self):
while True:
try:
loc = self.locsToDraw.pop()
except KeyError:
return
if loc is None:
continue
tile = self.tileForMapPos(*loc.pos)
if not tile:
continue
loc.drawTo(tile)
def adjacentPassable(self, loc):
for x in (-1, 0, 1):
for y in (-1, 0, 1):
if x == y == 0:
continue
newCoord = (loc.pos[0]+x, loc.pos[1]+y)
newLoc = self.map.get(newCoord, None)
if newLoc is None:
continue
if not newLoc.passable:
continue
if not newLoc.mapped:
continue
yield newLoc
def aStar(self, current, end):
if end is None:
return []
if not end.mapped:
return None
openSet = set([current])
openHeap = []
closedSet = set()
cameFrom = {}
g_score = {current: 0}
heapq.heappush(openHeap, (0, current))
def retracePath(c):
path = [c]
while c.parent is not None:
c = c.parent
path.append(c)
path.reverse()
return path
current.parent = None
while openSet:
current = heapq.heappop(openHeap)[1]
if current == end:
return retracePath(current)
openSet.remove(current)
closedSet.add(current)
nextStepCost = None
for tile in self.adjacentPassable(current):
if tile not in closedSet:
tile.H = (abs(end.pos[0]-tile.pos[0])+abs(end.pos[1]-tile.pos[1])) * current.travelCost # Not strictly true, but good enough
if tile not in openSet and (nextStepCost is None or nextStepCost > tile.H):
openSet.add(tile)
heapq.heappush(openHeap, (tile.H,tile))
nextStepCost = tile.H
tile.parent = current
return []
class Game(scene.Scene):
def setup(self):
self.touchPos = None # board pos
self.lastTouch = 0
self.checkForLife = set()
self.overlay = None
# init the root layer
self.root_layer = scene.Layer(self.bounds)
self.logLayer = scene.Layer
# Create the board
self.board = Board(self.root_layer)
# instantiate and place the player
self.player = self.board.player = Player(game=self)
self.board.placeActor(self.player)
# instantiate some enemies
self.npcs = set()
for num in range(NPCCOUNT):
npc = NPC(game=self)
self.npcs.add(npc)
self.board.placeActor(npc, centreBoard=False)
self.board.placeStairs()
self.root_layer.draw()
def moveNPCs(self):
for npc in self.npcs:
npc.tickMove(self.board)
def touch_began(self, touch):
if touch.layer and hasattr(touch.layer, 'pos'):
self.touchPos = touch.layer.pos
self.lastTouch = 0
self.player.path = None
def checkForTouch(self):
current = self.player.location
if current is None:
return
if not self.player.path:
pos = self.touchPos
if not pos:
return
self.player.path = self.board.aStar(current, self.board.locationForBoardPos(*pos))
if not self.player.path:
# No clear path to the destination
return
newMapPos = self.player.path.pop(0)
if newMapPos:
if newMapPos is not self.player.location:
self.board.move(self.player, newMapPos.pos[0], newMapPos.pos[1])
return True
return False
def touch_moved(self, touch):
tile = self.board.tileAtTouchPos(touch.location.as_tuple())
if tile:
self.touchPos = tile.pos
self.path = None # recalculate
else:
self.touchPos = None
def touch_ended(self, touch):
self.touchPos = None
def updateInfoPanel(self):
if self.overlay:
return
x = self.board.boardWidth * self.board.tileWidth + self.board.border * 2
y = self.board.boardHeight * self.board.tileHeight
scene.fill(0.6, 0.6, 0.6)
scene.stroke(1, 1, 1)
scene.stroke_weight(1)
scene.rect(x, 0, self.bounds.w, y+self.board.border*2)
scene.tint(0, 0, 0)
left = x + 5
right = self.bounds.w - 5
lineHeight = font_size = 20
scene.text('Health:', x=left, y=y, alignment=3, font_size=font_size)
scene.text('{}'.format(self.player.health), x=right, y=y, alignment=1, font_size=font_size)
y -= lineHeight
scene.text('Location:', x=left, y=y, alignment=3, font_size=font_size)
if self.player.location:
scene.text('{}'.format(self.player.location.pos), x=right, y=y, alignment=1, font_size=font_size)
else:
scene.text('Dead', x=right, y=y, alignment=1, font_size=font_size)
scene.no_tint()
def processDeaths(self):
while True:
try:
actor = self.checkForLife.pop()
except KeyError:
break
if actor.health <= 0:
# Dead, remove
self.board.move(actor, -1, -1)
if actor is self.player:
self.died()
else:
self.npcs.remove(actor)
def draw(self):
now = time.time()
delay = now - self.lastTouch
if delay >= TICKTIME:
self.lastTouch = now
if self.checkForTouch():
self.moveNPCs()
self.processDeaths()
self.board.updateTiles()
self.updateInfoPanel()
self.root_layer.update(self.dt)
if self.overlay:
self.overlay.draw()
def died(self):
font_size = 100 if self.size.w > 700 else 50
text_layer = scene.TextLayer('You have died!', 'Futura', font_size)
text_layer.frame.center(self.bounds.center())
self.overlay = overlay = scene.Layer(self.bounds)
overlay.background = scene.Color(0, 0, 0, 0)
overlay.add_layer(text_layer)
self.add_layer(overlay)
overlay.animate('background', scene.Color(0.0, 0.2, 0.3, 0.7))
text_layer.animate('scale_x', 1.3, 0.3, autoreverse=True)
text_layer.animate('scale_y', 1.3, 0.3, autoreverse=True)
self.touch_disabled = True
self.root_layer.animate('scale_x', 0.0, delay=2.0,
curve=scene.curve_ease_back_in)
self.root_layer.animate('scale_y', 0.0, delay=2.0,
curve=scene.curve_ease_back_in)
overlay.draw()
if __name__ == '__main__':
scene.run(Game())
'Mobiles - players and npcs'
import scene
class NPC(object):
"""
Base class for all creatures, mobile, non mobile, and the player.
"""
image = 'Rabbit_Face'
def __init__(self, game=None):
scene.load_image(self.image)
self.game = game
self.level = 1
self.health = 10
self.baseDamage = 1
self.speed = 10 # for travel
self.agility = 10 # for combat
self.lightRange = 3
self.location = None
self.subTravel = 0 # for really difficult terrain
self.path = None
self.inventory = set()
self.equipment = {
'righthand': None,
'lefthand': None,
'head': None,
'chest': None,
'arms': None,
'legs': None,
'feet': None,
}
@property
def damage(self):
dmg = (self.equipment['righthand'] or self).baseDamage
return dmg
def tickMove(self, board):
# xxx should have some sort of "can i see you"
target = self.game.player.location
board = self.game.board
if target in board.visibleLocations(self):
# move toward player if we can see them
pos = self.location
dx = cmp(target.pos[0], pos.pos[0])
dy = cmp(target.pos[1], pos.pos[1])
newMapPos = board.map.get((pos.pos[0]+dx, pos.pos[1]+dy ))
board.move(self, newMapPos.pos[0], newMapPos.pos[1])
def moveTo(self, loc):
if self.location:
if loc:
# if not loc, then we may be dying, speed is irrelevant
distanceLeft = max(0, self.location.travelCost - self.subTravel - self.speed)
if distanceLeft != 0:
# havent made it out of this square yet
self.subTravel += self.speed
return
self.location.contents.remove(self)
self.location = loc
if loc:
loc.contents.append(self)
loc.contents.sort(key=lambda npc: npc.speed)
self.subTravel = 0
def attack(self, target):
if self.health <= 0:
return
target.damaged(self.damage, weapon=self.equipment['righthand'])
target.health -= self.damage
target.path = None
self.game.checkForLife.add(target)
def damaged(self, amount, weapon=None):
for item in self.equipment.values():
amount = amount - getattr(item, 'absorb', 0)
if amount <= 0:
return
self.health -= amount
def canSeeLocation(self, location):
# hack version for now
if not self.location:
return False
if abs(location.pos[0] - self.location.pos[0]) <= self.lightRange:
if abs(location.pos[1] - self.location.pos[1]) <= self.lightRange:
return True
return False
def canSeeNPC(self, npc):
# hack version for now
if abs(npc.location.pos[0] - self.location.pos[0]) <= self.lightRange:
if abs(npc.location.pos[1] - self.location.pos[1]) <= self.lightRange:
return True
return False
def canSeeThing(self, thing):
return self.canSeeNPC(thing)
class Nonmobile(NPC):
image = 'Cactus'
def tickMove(self, board):
return
class Player(NPC):
image = 'Bear_Face'
def __init__(self, game=None):
super(Player, self).__init__(game=game)
self.lightRange = 20
self.agility = 20
def runGame():
import mainframe
scene.run(mainframe.Game())
if __name__ == '__main__':
runGame()
'Things - treasure and traps'
import scene
class Thing(object):
image = 'PC_Chest_Closed'
def __init__(self, game=None):
self.game = game
self.location = None
class Weapon(Thing):
image = 'Hocho'
def __init__(self, game=None):
super(Weapon, self).__init__(game=game)
self.baseDamage = 2
class Armour(Thing):
image = 'Kimono'
def __init__(self, game=None):
super(Armour, self).__init__(game=game)
self.absorb = 1
class StairsDown(Thing):
image = 'PC_Ramp_East'
class StairsUp(Thing):
image = 'PC_Ramp_West'
def runGame():
import mainframe
scene.run(mainframe.Game())
if __name__ == '__main__':
runGame()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment