def __init__(self, name="", ID=None): Entity.__init__(self, ID) Runnable.__init__(self) self.workers = [] self.available_workers = [] self.production_units = [] self.current_operations = [] self.name = name
def get_factory_data(self, ID_factory): factory = Entity.get_by_ref(ID_factory) values = {} values["Current time"] = factory.time values["number of production unit"] = len(factory.production_units) values["number of workers"] = len(factory.workers) return values
def get_production_unit_data(self, factory_ID, name): factory = Entity.get_by_ref(factory_ID) values = {} production_unit = None for pu in factory.production_units: if pu.name == name: production_unit = pu break if not production_unit: raise EntityNotFound("No production unit found with name %s" % name) values["produce"] = [material.type for material in production_unit.spec.output_materials] values["units_produced"] = production_unit.unit_produced values["value_produced"] = sum([material.price * production_unit.unit_produced for material in production_unit.spec.output_materials]) return values
def get_production_unit_data(self, factory_ID, name): factory = Entity.get_by_ref(factory_ID) values = {} production_unit = None for pu in factory.production_units: if pu.name == name: production_unit = pu break if not production_unit: raise EntityNotFound("No production unit found with name %s" % name) values["produce"] = [ material.type for material in production_unit.spec.output_materials ] values["units_produced"] = production_unit.unit_produced values["value_produced"] = sum([ material.price * production_unit.unit_produced for material in production_unit.spec.output_materials ]) return values
def txtToCommon(path, entityLookup): """Convert a txt file to the common format""" text = Path(path).read_text("utf-8") text = text.splitlines() numLines = len(text) def skipWS(i): for j in range(i, numLines): if text[j]: return j return numLines entMap = {} # Initial section: entity definitions # [Character]=[type].[variant].[subtype] # one per line, continues until it hits a line starting with --- roomBegin = 0 for i in range(numLines): line = text[i] line = re.sub(r"\s", "", line) roomBegin = i if not line: continue if line.startswith("---"): break char, t, v, s = re.findall(r"(.)=(\d+).(\d+).(\d+)", line)[0] if char in ["-", "|"]: print("Can't use - or | for entities!") continue t = int(t) v = int(v) s = int(s) en = entityLookup.lookupOne(t, v, s) if en is None or en.invalid: print( f"Invalid entity for character '{char}': '{en is None and 'UNKNOWN' or en.name}'! ({t}.{v}.{s})" ) continue entMap[char] = (t, v, s) shapeNames = { "1x1": 1, "2x2": 8, "closet": 2, "vertcloset": 3, "1x2": 4, "long": 7, "longvert": 5, "2x1": 6, "l": 10, "mirrorl": 9, "r": 12, "mirrorr": 11, } ret = [] # Main section: room definitions # First line: [id]: [name] # Second line, in no particular order: [Weight,] [Shape (within tolerance),] [Difficulty,] [Type[=1],] [Subtype[=0],] # Next [room height] lines: room layout # horizontal walls are indicated with -, vertical with | # there will be no validation for this, but if lines are the wrong length it prints an error message and skips the line # coordinates to entities are 1:1, entity ids can be at most 1 char # place xs at door positions to turn them off roomBegin += 1 while roomBegin < numLines: # 2 lines i = skipWS(roomBegin) if i == numLines: break rvariant, name = text[i].split(":", 1) name = name.strip() rvariant = int(rvariant) infoParts = re.sub(r"\s", "", text[i + 1]).lower().split(",") shape = 1 difficulty = 5 weight = 1 rtype = 1 rsubtype = 0 for part in infoParts: prop, val = re.findall(r"(.+)=(.+)", part)[0] if prop == "shape": shape = shapeNames.get(val) or int(val) elif prop == "difficulty": difficulty = shapeNames.get(val) or int(val) elif prop == "weight": weight = float(val) elif prop == "type": rtype = int(val) elif prop == "subtype": rsubtype = int(val) r = Room(name, None, difficulty, weight, rtype, rvariant, rsubtype, shape) width, height = r.info.dims spawns = r.gridSpawns i = skipWS(i + 2) for j in range(i, i + height): if j == numLines: print("Could not finish room!") break y = j - i row = text[j] for x, char in enumerate(row): if char in ["-", "|", " "]: continue if char.lower() == "x": changed = False for door in r.info.doors: if door[0] == x and door[1] == y: door[2] = False changed = True if changed: continue ent = entMap.get(char) if ent: spawns[Room.Info.gridIndex(x, y, width)].append( Entity(x, y, ent[0], ent[1], ent[2], 0)) else: print(f"Unknown entity! '{char}'") r.gridSpawns = r.gridSpawns ret.append(r) i = skipWS(i + height) if i == numLines: break if not text[i].strip().startswith("---"): print("Could not find separator after room!") break roomBegin = i + 1 return ret
def xmlToCommon(path, destPath=None): """Converts an Afterbirth xml to the common format""" xml = ET.parse(path) root = xml.getroot() # can be stage, rooms, etc rooms = root.findall("room") ret = [] for roomNode in rooms: roomXmlProps = dict(roomNode.attrib) rtype = int(roomNode.get("type") or "1") del roomXmlProps["type"] rvariant = int(roomNode.get("variant") or "0") del roomXmlProps["variant"] rsubtype = int(roomNode.get("subtype") or "0") del roomXmlProps["subtype"] difficulty = int(roomNode.get("difficulty") or "0") del roomXmlProps["difficulty"] roomName = roomNode.get("name") or "" del roomXmlProps["name"] rweight = float(roomNode.get("weight") or "1") del roomXmlProps["weight"] shape = int(roomNode.get("shape") or "-1") del roomXmlProps["shape"] if shape == -1: shape = None width = int(roomNode.get("width") or "13") + 2 height = int(roomNode.get("height") or "7") + 2 dims = (width, height) for k, s in Room.Shapes.items(): if s["Dims"] == dims: shape = k break shape = shape or 1 del roomXmlProps["width"] del roomXmlProps["height"] lastTestTime = roomXmlProps.get("lastTestTime", None) if lastTestTime: try: lastTestTime = datetime.datetime.fromisoformat(lastTestTime) del roomXmlProps["lastTestTime"] except: print("Invalid test time string found", lastTestTime) traceback.print_exception(*sys.exc_info()) lastTestTime = None doors = list( map( lambda door: [ int(door.get("x")) + 1, int(door.get("y")) + 1, door.get("exists", "0")[0] in "1tTyY", ], roomNode.findall("door"), )) room = Room(roomName, None, difficulty, rweight, rtype, rvariant, rsubtype, shape, doors) room.xmlProps = roomXmlProps room.lastTestTime = lastTestTime ret.append(room) realWidth = room.info.dims[0] gridLen = room.info.gridLen() for spawn in roomNode.findall("spawn"): ex, ey, stackedEnts = ( int(spawn.get("x")) + 1, int(spawn.get("y")) + 1, spawn.findall("entity"), ) grindex = Room.Info.gridIndex(ex, ey, realWidth) if grindex >= gridLen: print( f"Discarding the current entity stack due to invalid position! {room.getPrefix()}: {ex-1},{ey-1}" ) continue ents = room.gridSpawns[grindex] for ent in stackedEnts: entityXmlProps = dict(ent.attrib) etype, evariant, esubtype, eweight = ( int(ent.get("type")), int(ent.get("variant")), int(ent.get("subtype")), float(ent.get("weight")), ) del entityXmlProps["type"] del entityXmlProps["variant"] del entityXmlProps["subtype"] del entityXmlProps["weight"] ents.append( Entity(ex, ey, etype, evariant, esubtype, eweight, entityXmlProps)) room.gridSpawns = room.gridSpawns fileXmlProps = dict(root.attrib) return File(ret, fileXmlProps)
def stbRBToCommon(path): """Converts an Rebirth STB to the common format""" stb = open(path, "rb").read() headerPacker = struct.Struct("<I") roomBegPacker = struct.Struct("<IIBH") roomEndPacker = struct.Struct("<fBBBH") doorPacker = struct.Struct("<hh?") stackPacker = struct.Struct("<hhB") entPacker = struct.Struct("<HHHf") # Room count # No header for rebirth rooms = headerPacker.unpack_from(stb, 0)[0] off = headerPacker.size ret = [] for r in range(rooms): # Room Type, Room Variant, Difficulty, Length of Room Name String # No subtype for rebirth roomData = roomBegPacker.unpack_from(stb, off) rtype, rvariant, difficulty, nameLen = roomData off += roomBegPacker.size # print ("Room Data: {roomData}") # Room Name roomName = struct.unpack_from(f"<{nameLen}s", stb, off)[0].decode() off += nameLen # print (f"Room Name: {roomName}") # Weight, width, height, number of doors, number of entities # No shape for rebirth entityTable = roomEndPacker.unpack_from(stb, off) rweight, width, height, numDoors, numEnts = entityTable off += roomEndPacker.size # print (f"Entity Table: {entityTable}") # We have to figure out the shape manually for rebirth width += 2 height += 2 shape = 1 for s in [1, 4, 6, 8]: # only valid room shapes as of rebirth, defaults to 1x1 w, h = Room.Info(shape=s).dims if w == width and h == height: shape = s break doors = [] for d in range(numDoors): # X, Y, exists doorX, doorY, exists = doorPacker.unpack_from(stb, off) off += doorPacker.size doors.append([doorX + 1, doorY + 1, exists]) room = Room(roomName, None, difficulty, rweight, rtype, rvariant, 0, shape, doors) ret.append(room) realWidth = room.info.dims[0] gridLen = room.info.gridLen() for e in range(numEnts): # x, y, number of entities at this position ex, ey, stackedEnts = stackPacker.unpack_from(stb, off) ex += 1 ey += 1 off += stackPacker.size grindex = Room.Info.gridIndex(ex, ey, realWidth) if grindex >= gridLen: print( f"Discarding the current entity stack due to invalid position! {room.getPrefix()}: {ex-1},{ey-1}" ) off += entPacker.size * stackedEnts continue ents = room.gridSpawns[grindex] for s in range(stackedEnts): # type, variant, subtype, weight etype, evariant, esubtype, eweight = entPacker.unpack_from( stb, off) off += entPacker.size ents.append(Entity(ex, ey, etype, evariant, esubtype, eweight)) room.gridSpawns = room.gridSpawns # used to update spawn count return File(ret)
def stbAntiToCommon(path): """Converts an Antibirth STB to the common format""" stb = open(path, "rb").read() headerPacker = struct.Struct("<4sI") roomBegPacker = struct.Struct("<IIIBH") roomEndPacker = struct.Struct( "<fBBBBH9s") # 9 padding bytes for some other room data doorPacker = struct.Struct("<hh?") stackPacker = struct.Struct("<hhB") entPacker = struct.Struct("<HHHf") # Header, Room count header, rooms = headerPacker.unpack_from(stb, 0) off = headerPacker.size if header.decode() != "STB2": raise ValueError("Antibirth STBs must have the STB2 header") ret = [] for r in range(rooms): # Room Type, Room Variant, Subtype, Difficulty, Length of Room Name String roomData = roomBegPacker.unpack_from(stb, off) rtype, rvariant, rsubtype, difficulty, nameLen = roomData off += roomBegPacker.size # print ("Room Data: {roomData}") # Room Name roomName = struct.unpack_from(f"<{nameLen}s", stb, off)[0].decode() off += nameLen # print (f"Room Name: {roomName}") # Weight, width, height, shape, number of doors, number of entities entityTable = roomEndPacker.unpack_from(stb, off) rweight, width, height, shape, numDoors, numEnts, extraData = entityTable off += roomEndPacker.size # print (f"Entity Table: {entityTable}") width += 2 height += 2 if shape == 0: print(f"Bad room shape! {rvariant}, {roomName}, {width}, {height}") shape = 1 doors = [] for d in range(numDoors): # X, Y, exists doorX, doorY, exists = doorPacker.unpack_from(stb, off) off += doorPacker.size doors.append([doorX + 1, doorY + 1, exists]) room = Room(roomName, None, difficulty, rweight, rtype, rvariant, rsubtype, shape, doors) ret.append(room) if extraData != b"\x00\x00\x00\x00\x00\x00\x00\x00\x00": print(f"Room {room.getPrefix()} uses the extra bytes:", extraData) realWidth = room.info.dims[0] gridLen = room.info.gridLen() for e in range(numEnts): # x, y, number of entities at this position ex, ey, stackedEnts = stackPacker.unpack_from(stb, off) ex += 1 ey += 1 off += stackPacker.size grindex = Room.Info.gridIndex(ex, ey, realWidth) if grindex >= gridLen: print( f"Discarding the current entity stack due to invalid position! {room.getPrefix()}: {ex-1},{ey-1}" ) off += entPacker.size * stackedEnts continue ents = room.gridSpawns[grindex] for s in range(stackedEnts): # type, variant, subtype, weight etype, evariant, esubtype, eweight = entPacker.unpack_from( stb, off) off += entPacker.size ents.append(Entity(ex, ey, etype, evariant, esubtype, eweight)) room.gridSpawns = room.gridSpawns return File(ret)
from core import run_loop, Entity, style def game(state, press): mut_state = state if press == "q": mut_state["running"] = False if press == "w": mut_state["entities"]["player"].y -= 1 if press == "d": mut_state["entities"]["player"].x += 1 if press == "s": mut_state["entities"]["player"].y += 1 if press == "a": mut_state["entities"]["player"].x -= 1 return mut_state run_loop(game, {"running": True, "entities": { "player": Entity(10, 10, "@", style.RED) }})
def get_factory(self, factory_ID): factory = Entity.get_by_ref(int(factory_ID)) if not factory: raise Exception return factory
def txtToCommon(path, entityXML): """Convert a txt file to the common format""" text = Path(path).read_text('utf-8') text = text.splitlines() numLines = len(text) def skipWS(i): for j in range(i, numLines): if text[j]: return j return numLines entMap = {} # Initial section: entity definitions # [Character]=[type].[variant].[subtype] # one per line, continues until it hits a line starting with --- roomBegin = 0 for i in range(numLines): line = text[i] line = re.sub(r'\s', '', line) roomBegin = i if not line: continue if line.startswith('---'): break char, t, v, s = re.findall(r'(.)=(\d+).(\d+).(\d+)', line)[0] if char in ['-', '|']: print("Can't use - or | for entities!") continue t = int(t) v = int(v) s = int(s) en = entityXML.find( f"entity[@ID='{t}'][@Subtype='{s}'][@Variant='{v}']") if en is None or en.get('Invalid') == '1': print( f"Invalid entity for character '{char}': '{en is None and 'UNKNOWN' or en.get('Name')}'! ({t}.{v}.{s})" ) continue entMap[char] = (t, v, s) shapeNames = { '1x1': 1, '2x2': 8, 'closet': 2, 'vertcloset': 3, '1x2': 4, 'long': 7, 'longvert': 5, '2x1': 6, 'l': 10, 'mirrorl': 9, 'r': 12, 'mirrorr': 11 } ret = [] # Main section: room definitions # First line: [id]: [name] # Second line, in no particular order: [Weight,] [Shape (within tolerance),] [Difficulty,] [Type[=1],] [Subtype[=0],] # Next [room height] lines: room layout # horizontal walls are indicated with -, vertical with | # there will be no validation for this, but if lines are the wrong length it prints an error message and skips the line # coordinates to entities are 1:1, entity ids can be at most 1 char # place xs at door positions to turn them off roomBegin += 1 while roomBegin < numLines: # 2 lines i = skipWS(roomBegin) if i == numLines: break rvariant, name = text[i].split(':', 1) name = name.strip() rvariant = int(rvariant) infoParts = re.sub(r'\s', '', text[i + 1]).lower().split(',') shape = 1 difficulty = 5 weight = 1 rtype = 1 rsubtype = 0 for part in infoParts: prop, val = re.findall(r'(.+)=(.+)', part)[0] if prop == 'shape': shape = shapeNames.get(val) or int(val) elif prop == 'difficulty': difficulty = shapeNames.get(val) or int(val) elif prop == 'weight': weight = float(val) elif prop == 'type': rtype = int(val) elif prop == 'subtype': rsubtype = int(val) r = Room(name, None, difficulty, weight, rtype, rvariant, rsubtype, shape) width, height = r.info.dims spawns = r.gridSpawns i = skipWS(i + 2) for j in range(i, i + height): if j == numLines: print('Could not finish room!') break y = j - i row = text[j] for x, char in enumerate(row): if char in ['-', '|', ' ']: continue if char.lower() == 'x': changed = False for door in r.info.doors: if door[0] == x and door[1] == y: door[2] = False changed = True if changed: continue ent = entMap.get(char) if ent: spawns[Room.Info.gridIndex(x, y, width)].append( Entity(x, y, ent[0], ent[1], ent[2], 0)) else: print(f"Unknown entity! '{char}'") r.gridSpawns = r.gridSpawns ret.append(r) i = skipWS(i + height) if i == numLines: break if not text[i].strip().startswith('---'): print('Could not find separator after room!') break roomBegin = i + 1 return ret
def xmlToCommon(path, destPath=None): """Converts an Afterbirth xml to the common format""" xml = ET.parse(path) root = xml.getroot() # can be stage, rooms, etc rooms = root.findall('room') ret = [] for roomNode in rooms: roomXmlProps = dict(roomNode.attrib) rtype = int(roomNode.get('type') or '1') del roomXmlProps['type'] rvariant = int(roomNode.get('variant') or '0') del roomXmlProps['variant'] rsubtype = int(roomNode.get('subtype') or '0') del roomXmlProps['subtype'] difficulty = int(roomNode.get('difficulty') or '0') del roomXmlProps['difficulty'] roomName = roomNode.get('name') or '' del roomXmlProps['name'] rweight = float(roomNode.get('weight') or '1') del roomXmlProps['weight'] shape = int(roomNode.get('shape') or '-1') del roomXmlProps['shape'] if shape == -1: shape = None width = int(roomNode.get('width') or '13') + 2 height = int(roomNode.get('height') or '7') + 2 dims = (width, height) for k, s in Room.Shapes.items(): if s['Dims'] == dims: shape = k break shape = shape or 1 del roomXmlProps['width'] del roomXmlProps['height'] lastTestTime = roomXmlProps.get('lastTestTime', None) if lastTestTime: try: lastTestTime = datetime.datetime.fromisoformat(lastTestTime) del roomXmlProps['lastTestTime'] except: print('Invalid test time string found', lastTestTime) traceback.print_exception(*sys.exc_info()) lastTestTime = None doors = list( map( lambda door: [ int(door.get('x')) + 1, int(door.get('y')) + 1, door.get('exists', "0")[0] in "1tTyY" ], roomNode.findall('door'))) room = Room(roomName, None, difficulty, rweight, rtype, rvariant, rsubtype, shape, doors) room.xmlProps = roomXmlProps room.lastTestTime = lastTestTime ret.append(room) realWidth = room.info.dims[0] gridLen = room.info.gridLen() for spawn in roomNode.findall('spawn'): ex, ey, stackedEnts = int(spawn.get('x')) + 1, int( spawn.get('y')) + 1, spawn.findall('entity') grindex = Room.Info.gridIndex(ex, ey, realWidth) if grindex >= gridLen: print( f'Discarding the current entity stack due to invalid position! {room.getPrefix()}: {ex-1},{ey-1}' ) continue ents = room.gridSpawns[grindex] for ent in stackedEnts: entityXmlProps = dict(ent.attrib) etype, evariant, esubtype, eweight = int(ent.get('type')), int( ent.get('variant')), int(ent.get('subtype')), float( ent.get('weight')) del entityXmlProps['type'] del entityXmlProps['variant'] del entityXmlProps['subtype'] del entityXmlProps['weight'] ents.append( Entity(ex, ey, etype, evariant, esubtype, eweight, entityXmlProps)) room.gridSpawns = room.gridSpawns fileXmlProps = dict(root.attrib) return File(ret, fileXmlProps)