Asciifarm/asciifarm/server/room.py

163 lines
5.3 KiB
Python

import random
from . import ground
from . import gameobjects
from . import grid
from . import event
from . import entity
from . import roomdata
from . import serialize
class Room:
def __init__(self, name, data, preserved=None):
self.name = name
self.width = data["width"]
self.height = data["height"]
self.entrance = tuple(data["spawn"])
self.changedCells = {} # this probably doesn't belong in this class, but for now it will do
# It's probably better to make the view component more elaborate
self.lastStepStamp = 0
self.roomData = roomdata.RoomData(events={
"control": event.Event(),
"move": event.Event(),
"fight": event.Event(),
"update": event.Event(),
"sound": event.Event()
})
def logSound(source, text):
print("{}: {}: {}".format(self.name, source.getName(), text))
self.roomData.getEvent("sound").addListener(logSound)
self.places = data.get("places", {})
for name, pos in self.places.items():
self.places[name] = tuple(pos)
self.field = {}
g = grid.fromDict(data)
for x in range(g.width):
for y in range(g.height):
val = g.get(x, y)
if not isinstance(val, list) :
val = [val]
for obj in val:
ent = gameobjects.buildEntity(obj, self.roomData)
self.addObj((x, y), ent)
if preserved is not None:
self.loadPreserved(preserved)
self.resetChangedCells()
def getName(self):
return self.name
def getEntrance(self):
return self.entrance
def update(self, stepStamp):
""" call several update events for components
These events are separate to ensure that everything happens in the right order
'update' also has the number of steps as argument.
If the room has been unloaded for a while, it will make a large step next.
This is useful for allowing plants to grow for example
"""
if self.lastStepStamp is None:
timePassed = 1
else:
timePassed = stepStamp - self.lastStepStamp
self.roomData.setStamp(stepStamp)
self.roomData.triggerAlarms()
self.roomData.getEvent("control").trigger()
self.roomData.getEvent("move").trigger()
self.roomData.getEvent("fight").trigger()
self.roomData.getEvent("update").trigger(timePassed, stepStamp)
self.lastStepStamp = stepStamp
def getSprites(self, pos):
return self._getGround(pos).getSprites()
def isValidPos(self, pos):
x, y = pos
return x >= 0 and y >= 0 and x < self.width and y < self.height
def _getGround(self, pos):
if pos not in self.field and self.isValidPos(pos):
groundPatch = ground.GroundPatch(self, pos)
self.field[pos] = groundPatch
groundPatch.addListener("changesprite", self.onGroundChange)
return self.field.get(pos)
def get(self, pos):
if isinstance(pos, str):
pos = self.places.get(pos)
if not pos:
return None
return self._getGround(pos)
def getAllObjs(self):
return set().union(*[{(pos, obj) for obj in gr.getObjs()} for (pos, gr) in self.field.items()])
def getRoomData(self):
return self.roomData
def addObj(self, pos, obj):
if isinstance(pos, tuple) and len(pos) == 2:
x, y = pos
x %= self.width
y %= self.height
pos = (x, y)
if obj is not None:
place = self.get(pos)
if place is None:
if pos not in self.places:
raise Exception("Position {} does not exist in room {}. Available places: {}".format(pos, self.name, self.places))
else:
raise Exception("Position {} at {} is not a valid position.".format(pos, self.places[pos]))
obj.place(self.get(pos))
def removeObj(self, pos, obj):
self._getGround(pos).removeObj(obj)
def onGroundChange(self, obj):
self.changedCells[obj.getPos()] = self.getSprites(obj.getPos())
def getChangedCells(self):
return self.changedCells
def resetChangedCells(self):
self.changedCells = {}
def getPreserved(self):
return {
"changes": [
(obj.getGround().getPos(), obj.serialize())
for obj in self.roomData.getPreserved()],
"step": self.lastStepStamp}
def loadPreserved(self, objects):
if isinstance(objects, list):
# just for rooms that have been saved in the old format
# when there are no such rooms anymore, this can be removed
objects = {"changes": objects}
for (pos, objData) in objects["changes"]:
obj = gameobjects.buildEntity(objData, self.roomData, preserve=True)
self.addObj(tuple(pos), obj)
self.lastStepStamp = objects.get("step")
self.roomData.setStamp(self.lastStepStamp)