|
- #!/usr/bin/python3
- import collections as cl
- import networkx as nx
- import curses as c
- import random
- from time import sleep
- 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 Behaviour():
- 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(Behaviour):
- def __init__(self, name):
- super().__init__(name)
- self.msgbuffer = cl.deque([], 200)
- self.messaged = False
- self.messaged_last = False
- self.realtime = False
-
- def message(self, msg):
- if len(self.msgbuffer) > 0 and msg == self.msgbuffer[0][1] and self.messaged_last:
- self.msgbuffer.appendleft((self.msgbuffer.popleft()[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 you
- 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 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.messaged_last = True
- else:
- self.messaged_last = False
-
- self.world.window.refresh()
-
- # this is the one gameplay input point.
- if self.realtime:
- sleep(0.2)
- try:
- key = self.world.window.getkey()
- except c.error:
- key = ""
- c.flushinp()
- else:
- 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 'r':
- if self.realtime:
- self.realtime = False
- self.world.window.nodelay(False)
- else:
- self.realtime = True
- self.world.window.nodelay(True)
- # case _: self.world.message(key)
-
- class Drunkard(Behaviour):
-
- 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)
-
- class Conversation(list):
- def __init__(self, title, description):
- self.title = title
- self.description = description
-
- def run(self):
- # rendering code goes here
- pass
-
- class Response():
- def __init__(self, name, text, target=None, prerequisite=None, function=None):
- self.name = name
- self.text = text
- self.target = target
- self.function = function
-
- def respond(self, title, description):
- # rendering code goes here
- if function:
- function()
- if target:
- target.run()
-
- bum_conversation = Conversation("Conversing With a Drunkard", "A foul-smelling drunkard waves to and fro, trying to form words. His tattered clothes are brown with filth.")
- bum_conversation.append(Response("Hello? Is everything all right?", "Hargl... hurgl...", target=bum_conversation))
- bum_conversation.append(Response("I will take my leave, good sir.", "..."))
-
- 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()
- c.echo(False)
-
- 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()
|