rouge
This commit is contained in:
parent
252ae8d03c
commit
d5d80345fc
@ -1,4 +1,4 @@
|
|||||||
#!/bin/zsh
|
#!/bin/zsh
|
||||||
xrdb -merge ~/.Xresources.green
|
#xrdb -merge ~/.Xresources.green
|
||||||
urxvt -fn xft:inconsolata-26:antialias=true:hinting=true -letsp 1 -b 26 &
|
urxvt -fn xft:inconsolata-26:antialias=true:hinting=true -letsp 1 -b 26 &
|
||||||
xrdb -merge ~/.Xresources
|
#xrdb -merge ~/.Xresources
|
||||||
|
324
fov.py
Normal file
324
fov.py
Normal file
@ -0,0 +1,324 @@
|
|||||||
|
"""
|
||||||
|
Author: Aaron MacDonald
|
||||||
|
Date: June 14, 2007
|
||||||
|
|
||||||
|
Description: An implementation of the precise permissive field
|
||||||
|
of view algorithm for use in tile-based games.
|
||||||
|
Based on the algorithm presented at
|
||||||
|
http://roguebasin.roguelikedevelopment.org/
|
||||||
|
index.php?title=
|
||||||
|
Precise_Permissive_Field_of_View.
|
||||||
|
|
||||||
|
You are free to use or modify this code as long as this notice is
|
||||||
|
included.
|
||||||
|
This code is released without warranty.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
|
def fieldOfView(startX, startY, mapWidth, mapHeight, radius, \
|
||||||
|
funcVisitTile, funcTileBlocked):
|
||||||
|
"""
|
||||||
|
Determines which coordinates on a 2D grid are visible from a
|
||||||
|
particular coordinate.
|
||||||
|
|
||||||
|
startX, startY: The (x, y) coordinate on the grid that
|
||||||
|
is the centre of view.
|
||||||
|
|
||||||
|
mapWidth, mapHeight: The maximum extents of the grid. The
|
||||||
|
minimum extents are assumed to be both
|
||||||
|
zero.
|
||||||
|
|
||||||
|
radius: How far the field of view may extend
|
||||||
|
in either direction along the x and y
|
||||||
|
axis.
|
||||||
|
|
||||||
|
funcVisitTile: User function that takes two integers
|
||||||
|
representing an (x, y) coordinate. Is
|
||||||
|
used to "visit" visible coordinates.
|
||||||
|
|
||||||
|
funcTileBlocked: User function that takes two integers
|
||||||
|
representing an (x, y) coordinate.
|
||||||
|
Returns True if the coordinate blocks
|
||||||
|
sight to coordinates "behind" it.
|
||||||
|
"""
|
||||||
|
|
||||||
|
visited = set() # Keep track of what tiles have been visited so
|
||||||
|
# that no tile will be visited twice.
|
||||||
|
|
||||||
|
# Will always see the centre.
|
||||||
|
funcVisitTile(startX, startY)
|
||||||
|
visited.add((startX, startY))
|
||||||
|
|
||||||
|
# Ge the dimensions of the actual field of view, making
|
||||||
|
# sure not to go off the map or beyond the radius.
|
||||||
|
|
||||||
|
if startX < radius:
|
||||||
|
minExtentX = startX
|
||||||
|
else:
|
||||||
|
minExtentX = radius
|
||||||
|
|
||||||
|
if mapWidth - startX - 1 < radius:
|
||||||
|
maxExtentX = mapWidth - startX - 1
|
||||||
|
else:
|
||||||
|
maxExtentX = radius
|
||||||
|
|
||||||
|
if startY < radius:
|
||||||
|
minExtentY = startY
|
||||||
|
else:
|
||||||
|
minExtentY = radius
|
||||||
|
|
||||||
|
if mapHeight - startY - 1 < radius:
|
||||||
|
maxExtentY = mapHeight - startY - 1
|
||||||
|
else:
|
||||||
|
maxExtentY = radius
|
||||||
|
|
||||||
|
# Northeast quadrant
|
||||||
|
__checkQuadrant(visited, startX, startY, 1, 1, \
|
||||||
|
maxExtentX, maxExtentY, \
|
||||||
|
funcVisitTile, funcTileBlocked)
|
||||||
|
|
||||||
|
# Southeast quadrant
|
||||||
|
__checkQuadrant(visited, startX, startY, 1, -1, \
|
||||||
|
maxExtentX, minExtentY, \
|
||||||
|
funcVisitTile, funcTileBlocked)
|
||||||
|
|
||||||
|
# Southwest quadrant
|
||||||
|
__checkQuadrant(visited, startX, startY, -1, -1, \
|
||||||
|
minExtentX, minExtentY, \
|
||||||
|
funcVisitTile, funcTileBlocked)
|
||||||
|
|
||||||
|
# Northwest quadrant
|
||||||
|
__checkQuadrant(visited, startX, startY, -1, 1, \
|
||||||
|
minExtentX, maxExtentY, \
|
||||||
|
funcVisitTile, funcTileBlocked)
|
||||||
|
|
||||||
|
#-------------------------------------------------------------
|
||||||
|
|
||||||
|
class __Line(object):
|
||||||
|
def __init__(self, xi, yi, xf, yf):
|
||||||
|
self.xi = xi
|
||||||
|
self.yi = yi
|
||||||
|
self.xf = xf
|
||||||
|
self.yf = yf
|
||||||
|
|
||||||
|
dx = property(fget = lambda self: self.xf - self.xi)
|
||||||
|
dy = property(fget = lambda self: self.yf - self.yi)
|
||||||
|
|
||||||
|
def pBelow(self, x, y):
|
||||||
|
return self.relativeSlope(x, y) > 0
|
||||||
|
|
||||||
|
def pBelowOrCollinear(self, x, y):
|
||||||
|
return self.relativeSlope(x, y) >= 0
|
||||||
|
|
||||||
|
def pAbove(self, x, y):
|
||||||
|
return self.relativeSlope(x, y) < 0
|
||||||
|
|
||||||
|
def pAboveOrCollinear(self, x, y):
|
||||||
|
return self.relativeSlope(x, y) <= 0
|
||||||
|
|
||||||
|
def pCollinear(self, x, y):
|
||||||
|
return self.relativeSlope(x, y) == 0
|
||||||
|
|
||||||
|
def lineCollinear(self, line):
|
||||||
|
return self.pCollinear(line.xi, line.yi) \
|
||||||
|
and self.pCollinear(line.xf, line.yf)
|
||||||
|
|
||||||
|
def relativeSlope(self, x, y):
|
||||||
|
return (self.dy * (self.xf - x)) \
|
||||||
|
- (self.dx * (self.yf - y))
|
||||||
|
|
||||||
|
class __ViewBump:
|
||||||
|
def __init__(self, x, y, parent):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.parent = parent
|
||||||
|
|
||||||
|
class __View:
|
||||||
|
def __init__(self, shallowLine, steepLine):
|
||||||
|
self.shallowLine = shallowLine
|
||||||
|
self.steepLine = steepLine
|
||||||
|
|
||||||
|
self.shallowBump = None
|
||||||
|
self.steepBump = None
|
||||||
|
|
||||||
|
def __checkQuadrant(visited, startX, startY, dx, dy, \
|
||||||
|
extentX, extentY, funcVisitTile, funcTileBlocked):
|
||||||
|
activeViews = []
|
||||||
|
|
||||||
|
shallowLine = __Line(0, 1, extentX, 0)
|
||||||
|
steepLine = __Line(1, 0, 0, extentY)
|
||||||
|
|
||||||
|
activeViews.append( __View(shallowLine, steepLine) )
|
||||||
|
viewIndex = 0
|
||||||
|
|
||||||
|
# Visit the tiles diagonally and going outwards
|
||||||
|
#
|
||||||
|
# .
|
||||||
|
# .
|
||||||
|
# . .
|
||||||
|
# 9 .
|
||||||
|
# 5 8 .
|
||||||
|
# 2 4 7
|
||||||
|
# @ 1 3 6 . . .
|
||||||
|
maxI = extentX + extentY
|
||||||
|
i = 1
|
||||||
|
while i != maxI + 1 and len(activeViews) > 0:
|
||||||
|
if 0 > i - extentX:
|
||||||
|
startJ = 0
|
||||||
|
else:
|
||||||
|
startJ = i - extentX
|
||||||
|
|
||||||
|
if i < extentY:
|
||||||
|
maxJ = i
|
||||||
|
else:
|
||||||
|
maxJ = extentY
|
||||||
|
|
||||||
|
j = startJ
|
||||||
|
while j != maxJ + 1 and viewIndex < len(activeViews):
|
||||||
|
x = i - j
|
||||||
|
y = j
|
||||||
|
__visitCoord(visited, startX, startY, x, y, dx, dy, \
|
||||||
|
viewIndex, activeViews, \
|
||||||
|
funcVisitTile, funcTileBlocked)
|
||||||
|
|
||||||
|
j += 1
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
def __visitCoord(visited, startX, startY, x, y, dx, dy, viewIndex, \
|
||||||
|
activeViews, funcVisitTile, funcTileBlocked):
|
||||||
|
# The top left and bottom right corners of the current coordinate.
|
||||||
|
topLeft = (x, y + 1)
|
||||||
|
bottomRight = (x + 1, y)
|
||||||
|
|
||||||
|
while viewIndex < len(activeViews) \
|
||||||
|
and activeViews[viewIndex].steepLine.pBelowOrCollinear( \
|
||||||
|
bottomRight[0], bottomRight[1]):
|
||||||
|
# The current coordinate is above the current view and is
|
||||||
|
# ignored. The steeper fields may need it though.
|
||||||
|
viewIndex += 1
|
||||||
|
|
||||||
|
if viewIndex == len(activeViews) \
|
||||||
|
or activeViews[viewIndex].shallowLine.pAboveOrCollinear( \
|
||||||
|
topLeft[0], topLeft[1]):
|
||||||
|
# Either the current coordinate is above all of the fields
|
||||||
|
# or it is below all of the fields.
|
||||||
|
return
|
||||||
|
|
||||||
|
# It is now known that the current coordinate is between the steep
|
||||||
|
# and shallow lines of the current view.
|
||||||
|
|
||||||
|
isBlocked = False
|
||||||
|
|
||||||
|
# The real quadrant coordinates
|
||||||
|
realX = x * dx
|
||||||
|
realY = y * dy
|
||||||
|
|
||||||
|
if (startX + realX, startY + realY) not in visited:
|
||||||
|
visited.add((startX + realX, startY + realY))
|
||||||
|
funcVisitTile(startX + realX, startY + realY)
|
||||||
|
"""else:
|
||||||
|
# Debugging
|
||||||
|
print (startX + realX, startY + realY)"""
|
||||||
|
|
||||||
|
isBlocked = funcTileBlocked(startX + realX, startY + realY)
|
||||||
|
|
||||||
|
if not isBlocked:
|
||||||
|
# The current coordinate does not block sight and therefore
|
||||||
|
# has no effect on the view.
|
||||||
|
return
|
||||||
|
|
||||||
|
if activeViews[viewIndex].shallowLine.pAbove( \
|
||||||
|
bottomRight[0], bottomRight[1]) \
|
||||||
|
and activeViews[viewIndex].steepLine.pBelow( \
|
||||||
|
topLeft[0], topLeft[1]):
|
||||||
|
# The current coordinate is intersected by both lines in the
|
||||||
|
# current view. The view is completely blocked.
|
||||||
|
del activeViews[viewIndex]
|
||||||
|
elif activeViews[viewIndex].shallowLine.pAbove( \
|
||||||
|
bottomRight[0], bottomRight[1]):
|
||||||
|
# The current coordinate is intersected by the shallow line of
|
||||||
|
# the current view. The shallow line needs to be raised.
|
||||||
|
__addShallowBump(topLeft[0], topLeft[1], \
|
||||||
|
activeViews, viewIndex)
|
||||||
|
__checkView(activeViews, viewIndex)
|
||||||
|
elif activeViews[viewIndex].steepLine.pBelow( \
|
||||||
|
topLeft[0], topLeft[1]):
|
||||||
|
# The current coordinate is intersected by the steep line of
|
||||||
|
# the current view. The steep line needs to be lowered.
|
||||||
|
__addSteepBump(bottomRight[0], bottomRight[1], activeViews, \
|
||||||
|
viewIndex)
|
||||||
|
__checkView(activeViews, viewIndex)
|
||||||
|
else:
|
||||||
|
# The current coordinate is completely between the two lines
|
||||||
|
# of the current view. Split the current view into two views
|
||||||
|
# above and below the current coordinate.
|
||||||
|
|
||||||
|
shallowViewIndex = viewIndex
|
||||||
|
viewIndex += 1
|
||||||
|
steepViewIndex = viewIndex
|
||||||
|
|
||||||
|
activeViews.insert(shallowViewIndex, \
|
||||||
|
copy.deepcopy(activeViews[shallowViewIndex]))
|
||||||
|
|
||||||
|
__addSteepBump(bottomRight[0], bottomRight[1], \
|
||||||
|
activeViews, shallowViewIndex)
|
||||||
|
if not __checkView(activeViews, shallowViewIndex):
|
||||||
|
viewIndex -= 1
|
||||||
|
steepViewIndex -= 1
|
||||||
|
|
||||||
|
__addShallowBump(topLeft[0], topLeft[1], activeViews, \
|
||||||
|
steepViewIndex)
|
||||||
|
__checkView(activeViews, steepViewIndex)
|
||||||
|
|
||||||
|
def __addShallowBump(x, y, activeViews, viewIndex):
|
||||||
|
activeViews[viewIndex].shallowLine.xf = x
|
||||||
|
activeViews[viewIndex].shallowLine.yf = y
|
||||||
|
|
||||||
|
activeViews[viewIndex].shallowBump = __ViewBump(x, y, \
|
||||||
|
activeViews[viewIndex].shallowBump)
|
||||||
|
|
||||||
|
curBump = activeViews[viewIndex].steepBump
|
||||||
|
while curBump is not None:
|
||||||
|
if activeViews[viewIndex].shallowLine.pAbove( \
|
||||||
|
curBump.x, curBump.y):
|
||||||
|
activeViews[viewIndex].shallowLine.xi = curBump.x
|
||||||
|
activeViews[viewIndex].shallowLine.yi = curBump.y
|
||||||
|
|
||||||
|
curBump = curBump.parent
|
||||||
|
|
||||||
|
def __addSteepBump(x, y, activeViews, viewIndex):
|
||||||
|
activeViews[viewIndex].steepLine.xf = x
|
||||||
|
activeViews[viewIndex].steepLine.yf = y
|
||||||
|
|
||||||
|
activeViews[viewIndex].steepBump = __ViewBump(x, y, \
|
||||||
|
activeViews[viewIndex].steepBump)
|
||||||
|
|
||||||
|
curBump = activeViews[viewIndex].shallowBump
|
||||||
|
while curBump is not None:
|
||||||
|
if activeViews[viewIndex].steepLine.pBelow( \
|
||||||
|
curBump.x, curBump.y):
|
||||||
|
activeViews[viewIndex].steepLine.xi = curBump.x
|
||||||
|
activeViews[viewIndex].steepLine.yi = curBump.y
|
||||||
|
|
||||||
|
curBump = curBump.parent
|
||||||
|
|
||||||
|
def __checkView(activeViews, viewIndex):
|
||||||
|
"""
|
||||||
|
Removes the view in activeViews at index viewIndex if
|
||||||
|
- The two lines are coolinear
|
||||||
|
- The lines pass through either extremity
|
||||||
|
"""
|
||||||
|
|
||||||
|
shallowLine = activeViews[viewIndex].shallowLine
|
||||||
|
steepLine = activeViews[viewIndex].steepLine
|
||||||
|
|
||||||
|
if shallowLine.lineCollinear(steepLine) \
|
||||||
|
and ( shallowLine.pCollinear(0, 1) \
|
||||||
|
or shallowLine.pCollinear(1, 0) ):
|
||||||
|
del activeViews[viewIndex]
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
60
grid.py
Normal file
60
grid.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
class Grid():
|
||||||
|
def __init__(self, x, y, initial):
|
||||||
|
self.x = x
|
||||||
|
self.y = y
|
||||||
|
self.initial = initial
|
||||||
|
self.data = [initial] * x * y
|
||||||
|
|
||||||
|
def get(self, x, y):
|
||||||
|
return self.data[self.x * y + x]
|
||||||
|
|
||||||
|
def set(self, x, y, v):
|
||||||
|
self.data[self.x * y + x] = v
|
||||||
|
|
||||||
|
def in_bounds(self, x, y):
|
||||||
|
return x < self.x and x >= 0 and y < self.y and y >= 0
|
||||||
|
|
||||||
|
def __getitem__(self, coord):
|
||||||
|
(x, y) = coord
|
||||||
|
return self.get(x, y)
|
||||||
|
|
||||||
|
def __setitem__(self, coord, value):
|
||||||
|
(x, y) = coord
|
||||||
|
self.set(x, y, value)
|
||||||
|
|
||||||
|
def neighbors(self, x, y):
|
||||||
|
r = []
|
||||||
|
for direction in [(-1, -1), (0, -1), (1, -1), (1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0)]:
|
||||||
|
xc, yc = direction
|
||||||
|
tx, ty = x + xc, y + yc
|
||||||
|
if self.in_bounds(tx, ty):
|
||||||
|
r.append((tx, ty))
|
||||||
|
return r
|
||||||
|
|
||||||
|
def bresenhams(x1, y1, x2, y2):
|
||||||
|
r = []
|
||||||
|
dx = abs(x2 - x1)
|
||||||
|
dy = abs(y2 - y1)
|
||||||
|
x, y = x1, y1
|
||||||
|
sx = -1 if x1 > x2 else 1
|
||||||
|
sy = -1 if y1 > y2 else 1
|
||||||
|
if dx > dy:
|
||||||
|
err = dx / 2.0
|
||||||
|
while x != x2:
|
||||||
|
r.append((x, y))
|
||||||
|
err -= dy
|
||||||
|
if err < 0:
|
||||||
|
y += sy
|
||||||
|
err += dx
|
||||||
|
x += sx
|
||||||
|
else:
|
||||||
|
err = dy / 2.0
|
||||||
|
while y != y2:
|
||||||
|
r.append((x, y))
|
||||||
|
err -= dx
|
||||||
|
if err < 0:
|
||||||
|
x += sx
|
||||||
|
err += dy
|
||||||
|
y += sy
|
||||||
|
r.append((x, y))
|
||||||
|
return r
|
243
rougelike.py
Executable file
243
rougelike.py
Executable file
@ -0,0 +1,243 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import collections as cl
|
||||||
|
import networkx as nx
|
||||||
|
import curses as c
|
||||||
|
import random
|
||||||
|
from grid import Grid, bresenhams
|
||||||
|
from fov import fieldOfView
|
||||||
|
|
||||||
|
class Tile():
|
||||||
|
def __init__(self, glyph, name, description, solid=False, transparent=True, color=c.COLOR_WHITE):
|
||||||
|
self.appearance = glyph
|
||||||
|
self.name = name
|
||||||
|
self.description = description
|
||||||
|
self.solid = solid
|
||||||
|
self.transparent = transparent
|
||||||
|
self.color = color
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
return (self.glyph, self.color)
|
||||||
|
|
||||||
|
def describe(self):
|
||||||
|
return self.description
|
||||||
|
|
||||||
|
class World(Grid):
|
||||||
|
def __init__(self, window, width, height, initial_tile):
|
||||||
|
super().__init__(width, height, initial_tile)
|
||||||
|
self.run = True
|
||||||
|
self.window = window
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
|
||||||
|
self.bodies = []
|
||||||
|
self.behavior = []
|
||||||
|
|
||||||
|
class Spirit():
|
||||||
|
def __init__(self, name):
|
||||||
|
self.name = name
|
||||||
|
self.body = None
|
||||||
|
self.world = None
|
||||||
|
|
||||||
|
def behave(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def incarnate(self, body):
|
||||||
|
if not self.body is None:
|
||||||
|
self.body.behavior = None
|
||||||
|
if not body.behavior is None:
|
||||||
|
body.behavior.body = None
|
||||||
|
self.body = body
|
||||||
|
body.behavior = self
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class Player(Spirit):
|
||||||
|
def __init__(self, name):
|
||||||
|
super().__init__(name)
|
||||||
|
self.msgbuffer = cl.deque([], 200)
|
||||||
|
self.messaged = False
|
||||||
|
|
||||||
|
def message(self, msg):
|
||||||
|
if len(self.msgbuffer) > 0 and msg == self.msgbuffer[0][1]:
|
||||||
|
self.msgbuffer.appendleft((self.msgbuffer.pop()[0] + 1, msg))
|
||||||
|
else:
|
||||||
|
self.msgbuffer.appendleft((1, msg))
|
||||||
|
self.messaged = True
|
||||||
|
|
||||||
|
def behave(self):
|
||||||
|
|
||||||
|
# calculate visibility
|
||||||
|
visibility = Grid(self.world.width, self.world.height, False)
|
||||||
|
fieldOfView(self.body.x, self.body.y, self.world.width, self.world.height, 100, lambda x, y: visibility.set(x, y, True), lambda x, y: self.world.get(x, y).solid)
|
||||||
|
|
||||||
|
self.world.window.erase()
|
||||||
|
|
||||||
|
# draw interface
|
||||||
|
for x in range(0, self.world.width):
|
||||||
|
for y in range(0, self.world.height):
|
||||||
|
if visibility.get(x, y):
|
||||||
|
self.world.window.addch(y, x, self.world.get(x, y).appearance)
|
||||||
|
for body in self.world.bodies:
|
||||||
|
if visibility.get(body.x, body.y):
|
||||||
|
body.draw()
|
||||||
|
if not len(self.msgbuffer) == 0 and self.messaged:
|
||||||
|
if self.msgbuffer[0][0] == 1:
|
||||||
|
self.world.window.addstr(self.world.height + 1, 0, self.msgbuffer[0][1])
|
||||||
|
else:
|
||||||
|
self.world.window.addstr(self.world.height + 1, 0, self.msgbuffer[0][1] + " (x" + str(self.msgbuffer[0][0]) + ")")
|
||||||
|
self.messaged = False
|
||||||
|
|
||||||
|
self.world.window.refresh()
|
||||||
|
|
||||||
|
# this is the one gameplay input point.
|
||||||
|
key = self.world.window.getkey()
|
||||||
|
match key:
|
||||||
|
case 'w':
|
||||||
|
if not self.body.move((0, -1)):
|
||||||
|
self.message("You cannot go there.")
|
||||||
|
case 's':
|
||||||
|
if not self.body.move((0, +1)):
|
||||||
|
self.message("You cannot go there.")
|
||||||
|
case 'a':
|
||||||
|
if not self.body.move((-1, 0)):
|
||||||
|
self.message("You cannot go there.")
|
||||||
|
case 'd':
|
||||||
|
if not self.body.move((+1, 0)):
|
||||||
|
self.message("You cannot go there.")
|
||||||
|
case 'c':
|
||||||
|
coords = self.world.neighbors(self.body.x, self.body.y)
|
||||||
|
for coord in coords:
|
||||||
|
x, y = coord
|
||||||
|
t = self.world.get(x, y)
|
||||||
|
if t.name == "open door":
|
||||||
|
self.body.close_door(x, y)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.message("You see nothing here to close.")
|
||||||
|
case 'q':
|
||||||
|
self.world.run = False
|
||||||
|
# case _: self.world.message(key)
|
||||||
|
|
||||||
|
class Drunkard(Spirit):
|
||||||
|
|
||||||
|
def behave(self):
|
||||||
|
while True:
|
||||||
|
dx, dy = random.randint(-1,1), random.randint(-1,1)
|
||||||
|
tx, ty = dx + self.body.x, dy + self.body.y
|
||||||
|
if self.world.in_bounds(tx, ty) and not self.world.get(tx, ty).solid:
|
||||||
|
break
|
||||||
|
bodies = [body for body in self.world.bodies if body.x == tx and body.y == ty]
|
||||||
|
if bodies:
|
||||||
|
for tb in bodies:
|
||||||
|
tb.behavior.message("A " + self.body.name + " bumps into you.")
|
||||||
|
else:
|
||||||
|
self.body.move((dx, dy))
|
||||||
|
|
||||||
|
class Body():
|
||||||
|
def __init__(self, name, appearence, description, color):
|
||||||
|
self.name = name
|
||||||
|
self.appearence = appearence
|
||||||
|
self.description = description
|
||||||
|
self.color = color
|
||||||
|
self.behavior = None
|
||||||
|
self.world = None
|
||||||
|
self.x = None
|
||||||
|
self.y = None
|
||||||
|
|
||||||
|
def move(self, direction):
|
||||||
|
x, y = direction
|
||||||
|
tx, ty = self.x + x, self.y + y
|
||||||
|
if not self.world.in_bounds(tx, ty):
|
||||||
|
return False
|
||||||
|
elif self.world.get(tx, ty).name == "closed door":
|
||||||
|
self.open_door(tx, ty)
|
||||||
|
return True
|
||||||
|
elif self.world.get(tx, ty).solid:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
self.x = tx
|
||||||
|
self.y = ty
|
||||||
|
return True
|
||||||
|
|
||||||
|
def open_door(self, x, y):
|
||||||
|
if not self.world.in_bounds(x, y):
|
||||||
|
self.behavior.message("You cannot open anything there.")
|
||||||
|
return False
|
||||||
|
elif self.world.get(x, y).name == "closed door":
|
||||||
|
self.world.set(x, y, door_open)
|
||||||
|
self.behavior.message("You open the door.")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.behavior.message("You cannot open anything there.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def close_door(self, x, y):
|
||||||
|
if not self.world.in_bounds(x, y):
|
||||||
|
self.behavior.message("You cannot close anything there.")
|
||||||
|
return False
|
||||||
|
elif self.world.get(x, y).name == "open door":
|
||||||
|
self.world.set(x, y, door_closed)
|
||||||
|
self.behavior.message("You close the door.")
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
self.behavior.message("You cannot close anything there.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def describe(self):
|
||||||
|
return self.description
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
self.world.window.addch(self.y, self.x, self.appearence)
|
||||||
|
|
||||||
|
p = Player("you")
|
||||||
|
|
||||||
|
pb = Body("yourself", '@', "an unremarkable person", c.COLOR_WHITE)
|
||||||
|
|
||||||
|
p.incarnate(pb)
|
||||||
|
|
||||||
|
floor = Tile('.', "floor", "an unremarkable piece of floor")
|
||||||
|
wall = Tile('#', "wall", "an unremarkable wall", solid=True, transparent=False)
|
||||||
|
|
||||||
|
door_closed = Tile('+', "closed door", "an unremarkable door", solid=True, transparent=False)
|
||||||
|
door_open = Tile(',', "open door", "an unremarkable door", solid=False, transparent=True)
|
||||||
|
|
||||||
|
w = c.initscr()
|
||||||
|
c.curs_set(0)
|
||||||
|
c.raw()
|
||||||
|
|
||||||
|
wld = World(w, 80, 23, floor)
|
||||||
|
|
||||||
|
drunk = Drunkard("drunkard")
|
||||||
|
db = Body("drunkard", 'H', "A smelly drunkard, stumbling about.", c.COLOR_WHITE)
|
||||||
|
drunk.incarnate(db)
|
||||||
|
|
||||||
|
db.world = wld
|
||||||
|
drunk.world = wld
|
||||||
|
|
||||||
|
db.x = 20
|
||||||
|
db.y = 16
|
||||||
|
|
||||||
|
wld.behaviors = [p, drunk]
|
||||||
|
wld.bodies = [pb, db]
|
||||||
|
pb.world = wld
|
||||||
|
p.world = wld
|
||||||
|
pb.x = 3
|
||||||
|
pb.y = 6
|
||||||
|
|
||||||
|
wld.set(12, 12, wall)
|
||||||
|
wld.set(13, 12, wall)
|
||||||
|
wld.set(14, 12, wall)
|
||||||
|
wld.set(15, 12, wall)
|
||||||
|
wld.set(16, 12, wall)
|
||||||
|
wld.set(16, 13, wall)
|
||||||
|
wld.set(16, 14, wall)
|
||||||
|
wld.set(18, 12, wall)
|
||||||
|
wld.set(18, 13, wall)
|
||||||
|
wld.set(18, 14, wall)
|
||||||
|
wld.set(12, 13, door_closed)
|
||||||
|
|
||||||
|
while wld.run:
|
||||||
|
for behavior in wld.behaviors:
|
||||||
|
behavior.behave()
|
||||||
|
c.endwin()
|
Loading…
Reference in New Issue
Block a user