-
-
Save freekrai/4225758 to your computer and use it in GitHub Desktop.
Pythonista Scripts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
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 file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'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