Refactor tilesets
This commit is contained in:
parent
4b02cc4c9d
commit
60528926ee
|
@ -4,11 +4,11 @@ from functools import cached_property
|
|||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from textwrap import indent
|
||||
from typing import List, Union
|
||||
from typing import List, Union, get_type_hints
|
||||
|
||||
from PIL import Image
|
||||
|
||||
from tilemapper.grid import Grid, Position
|
||||
from tilemapper.grid import Grid
|
||||
from tilemapper.tileset import Tile, TileSet
|
||||
|
||||
|
||||
|
@ -16,8 +16,12 @@ class UnsupportedTileException(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class BattleMapType:
|
||||
pass
|
||||
|
||||
|
||||
@dataclass
|
||||
class BattleMap:
|
||||
class BattleMap(BattleMapType):
|
||||
"""
|
||||
A 2D battle map built on a Grid of Tiles.
|
||||
|
||||
|
@ -25,7 +29,7 @@ class BattleMap:
|
|||
|
||||
>>> console = TileSetManager().load("colorized")
|
||||
>>> bmap = BattleMap(name="Example Map", source="input.txt", tileset=console)
|
||||
>>> bmap.render()
|
||||
>>> print(bmap.as_string())
|
||||
|
||||
"""
|
||||
|
||||
|
@ -63,31 +67,27 @@ class BattleMap:
|
|||
for char in set(list(data)):
|
||||
if char == "\n":
|
||||
continue
|
||||
if char not in self.tileset.character_map:
|
||||
if char not in self.tileset.config.legend:
|
||||
raise UnsupportedTileException(f"The current tileset does not support the '{char}' character.")
|
||||
return True
|
||||
|
||||
def render(self) -> Image:
|
||||
def as_image(self) -> Image:
|
||||
"""
|
||||
Create a PNG image of the currenet grid.
|
||||
Create an image of the current grid.
|
||||
|
||||
If a grid position does not exist (as for example if one row is shorter than anoather), the
|
||||
missing position will be rendered as empty space (using the tile set's empty space tile).
|
||||
|
||||
Returns the generated Image instance.
|
||||
Returns an Image instance.
|
||||
"""
|
||||
map_image = Image.new("RGB", (self.tileset.tile_size * self.width, self.tileset.tile_size * self.height))
|
||||
empty_space = Position(y=-1, x=-1, value=self.tileset.empty_space)
|
||||
for y in range(0, self.height):
|
||||
for x in range(0, self.width):
|
||||
pos = self.grid.at(y, x)
|
||||
if not pos or pos.value == self.tileset.empty_space:
|
||||
continue
|
||||
map_image.paste(
|
||||
self.tileset.render_tile(pos, [a or pos for a in self.grid.adjacent(pos)]),
|
||||
(self.tileset.tile_size * x, self.tileset.tile_size * y),
|
||||
)
|
||||
return map_image
|
||||
if get_type_hints(self.tileset.render_grid)["return"] != Image:
|
||||
raise NotImplementedError(f"Tile set does not support image rendering.")
|
||||
return self.tileset.render_grid(grid=self.grid, width=self.width, height=self.height)
|
||||
|
||||
def as_string(self) -> str:
|
||||
if get_type_hints(self.tileset.render_grid)["return"] != str:
|
||||
raise NotImplementedError(f"{self.tileset} does not support string rendering.")
|
||||
return self.tileset.render_grid(grid=self.grid, width=self.width, height=self.height)
|
||||
|
||||
@cached_property
|
||||
def grid(self) -> List[List[Tile]]:
|
||||
|
@ -109,20 +109,12 @@ class BattleMap:
|
|||
def legend(self) -> str:
|
||||
output = ""
|
||||
for char in sorted(set(list(self.source_data)), key=str.lower):
|
||||
if char in self.tileset.character_map:
|
||||
output += f"{char} - {self.tileset.character_map[char]}\n"
|
||||
if char in self.tileset.config.legend:
|
||||
output += f"{char} - {self.tileset.config.legend[char]}\n"
|
||||
return output
|
||||
|
||||
def __str__(self) -> str:
|
||||
output = ""
|
||||
for y in range(0, self.height):
|
||||
for x in range(0, self.width):
|
||||
try:
|
||||
output += str(self.grid.at(y, x).value)
|
||||
except AttributeError:
|
||||
continue
|
||||
output += "\n"
|
||||
return output.rstrip("\n")
|
||||
return self.as_string()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"\n{self.title}\n\n{indent(str(self), ' ')}\n\nLegend:\n{indent(self.legend, ' ')}"
|
||||
|
|
|
@ -42,26 +42,17 @@ def list():
|
|||
print("\n".join(manager.available))
|
||||
|
||||
|
||||
@app.command()
|
||||
def inspect(source: Path = typer.Argument(help="The battle map text file to laod.")):
|
||||
"""
|
||||
Print information about the specified battle map text file.
|
||||
"""
|
||||
manager = app_state["tileset_manager"]
|
||||
bmap = battlemap.BattleMap(name=source.name, source=source, tileset=manager.console_map_colorized)
|
||||
bmap.load()
|
||||
console = Console()
|
||||
console.print(repr(bmap), highlight=False)
|
||||
|
||||
|
||||
@app.command()
|
||||
def render(
|
||||
source: Path = typer.Argument(help="The battle map text file to load."),
|
||||
outfile: Path = typer.Argument(help="The file to create."),
|
||||
tileset: str = typer.Option(help="The name of the tile set to use (run mapper list to see what's available)."),
|
||||
outfile: Path = typer.Option(help="The file to create. If not specified, print to STDOUT", default=None),
|
||||
tileset: str = typer.Option(
|
||||
help="The name of the tile set to use (run mapper list to see what's available).", default="colorized"
|
||||
),
|
||||
):
|
||||
"""
|
||||
Create a PNG image of a battle map using a tile set.
|
||||
Create a rendered battle map using a tile set. Will generate a PNG file if the tile set supports it,
|
||||
otherwise text output.
|
||||
"""
|
||||
manager = app_state["tileset_manager"]
|
||||
if tileset not in manager.available:
|
||||
|
@ -74,9 +65,19 @@ def render(
|
|||
logging.error(e)
|
||||
sys.exit(1)
|
||||
|
||||
image = bmap.render()
|
||||
image.save(outfile)
|
||||
print(f"Wrote {outfile.stat().st_size} bytes to {outfile}")
|
||||
try:
|
||||
image = bmap.as_image()
|
||||
if outfile:
|
||||
image.save(outfile)
|
||||
outfile.write_text(bmap.render())
|
||||
print(f"Wrote {outfile.stat().st_size} bytes to {outfile}")
|
||||
else:
|
||||
image.save(sys.stdout, "png")
|
||||
return
|
||||
except NotImplementedError:
|
||||
pass
|
||||
console = Console()
|
||||
console.print(repr(bmap), highlight=False)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import importlib
|
||||
import logging
|
||||
import random
|
||||
import tomllib
|
||||
|
@ -5,36 +6,15 @@ from collections import defaultdict
|
|||
from dataclasses import dataclass, field
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
from types import SimpleNamespace
|
||||
from typing import Dict, List
|
||||
|
||||
from PIL import Image, ImageDraw
|
||||
|
||||
from tilemapper.grid import Position
|
||||
from tilemapper.grid import Grid, Position
|
||||
|
||||
DEFAULT_TILE_SIZE_IN_PIXELS = 128
|
||||
|
||||
COLOR_MAP = {
|
||||
".": "white on grey58",
|
||||
"d": "bold cyan on grey58",
|
||||
"D": "bold green on grey58",
|
||||
"L": "bold dark_red on grey58",
|
||||
"S": "bold black on grey58",
|
||||
"v": "bold steel_blue on grey3",
|
||||
"^": "bold steel_blue on grey3",
|
||||
"0": "white on dark_red",
|
||||
"1": "white on dark_red",
|
||||
"2": "white on dark_red",
|
||||
"3": "white on dark_red",
|
||||
"4": "white on dark_red",
|
||||
"5": "white on dark_red",
|
||||
"6": "white on dark_red",
|
||||
"7": "white on dark_red",
|
||||
"8": "white on dark_red",
|
||||
"9": "white on dark_red",
|
||||
"_": "white on steel_blue",
|
||||
",": "black on dark_green",
|
||||
}
|
||||
|
||||
|
||||
class UnsupportedTileException(Exception):
|
||||
pass
|
||||
|
@ -44,6 +24,13 @@ class MissingImageDataException(Exception):
|
|||
pass
|
||||
|
||||
|
||||
class MisconfiguredTileSetException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
TileSetConfig = SimpleNamespace
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
class Tile:
|
||||
"""
|
||||
|
@ -53,6 +40,7 @@ class Tile:
|
|||
|
||||
name: str
|
||||
char: str
|
||||
config: TileSetConfig
|
||||
|
||||
def render(self):
|
||||
return str(self)
|
||||
|
@ -65,7 +53,7 @@ class Tile:
|
|||
return self.char
|
||||
|
||||
|
||||
@dataclass(kw_only=True)
|
||||
@dataclass
|
||||
class TileSet:
|
||||
"""
|
||||
Base class representing all tiles in a set which can be used to render
|
||||
|
@ -73,35 +61,15 @@ class TileSet:
|
|||
this class.
|
||||
"""
|
||||
|
||||
name: str
|
||||
desc: str = ""
|
||||
config: TileSetConfig
|
||||
tiles: Dict[str, Tile] = field(default_factory=lambda: defaultdict(list))
|
||||
|
||||
# The default character map is suitable for dungeons and other structures.
|
||||
character_map: Dict[str, str] = field(
|
||||
default_factory=lambda: {
|
||||
" ": "empty",
|
||||
".": "ground",
|
||||
",": "grass",
|
||||
"_": "water",
|
||||
"d": "door, open",
|
||||
"D": "door, closed",
|
||||
"L": "door, locked",
|
||||
"S": "door, secret",
|
||||
"v": "stairs, down",
|
||||
"^": "stairs, up",
|
||||
"0": "location 0",
|
||||
"1": "location 1",
|
||||
"2": "location 2",
|
||||
"3": "location 3",
|
||||
"4": "location 4",
|
||||
"5": "location 5",
|
||||
"6": "location 6",
|
||||
"7": "location 7",
|
||||
"8": "location 8",
|
||||
"9": "location 9",
|
||||
}
|
||||
)
|
||||
tile_type = Tile
|
||||
|
||||
def load(self):
|
||||
self.tiles = defaultdict(list)
|
||||
for char, name in self.config.legend.items():
|
||||
self.add(self.tile_type(char=char, name=name, config=self.config))
|
||||
|
||||
def add(self, tile: Tile):
|
||||
"""
|
||||
|
@ -113,11 +81,24 @@ class TileSet:
|
|||
"""
|
||||
Return the Tile instance corrresponding to an input character.
|
||||
"""
|
||||
if char not in self.character_map:
|
||||
if char not in self.config.legend:
|
||||
raise UnsupportedTileException(f"'{char}' is not supported by the current tile set.")
|
||||
name = self.character_map[char]
|
||||
name = self.config.legend[char]
|
||||
return random.choice(self.tiles[name]) if name in self.tiles else self.placeholder
|
||||
|
||||
def render_grid(self, grid: Grid, width: int = 0, height: int = 0) -> str:
|
||||
output = ""
|
||||
for y in range(0, height):
|
||||
for x in range(0, width):
|
||||
try:
|
||||
pos = grid.at(y, x)
|
||||
except AttributeError:
|
||||
continue
|
||||
if pos and pos.value:
|
||||
output += pos.value.render()
|
||||
output += "\n"
|
||||
return output.rstrip("\n")
|
||||
|
||||
@property
|
||||
def empty_space(self) -> Tile:
|
||||
"""
|
||||
|
@ -126,7 +107,7 @@ class TileSet:
|
|||
return self.get(" ")
|
||||
|
||||
def __str__(self):
|
||||
return f"[Tileset] {self.name}: {self.desc}"
|
||||
return f"[Tileset] {self.config.tileset['name']}: {self.config.tileset['desc']}"
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -136,10 +117,12 @@ class ColorizedTile(Tile):
|
|||
using ANSI color codes.
|
||||
"""
|
||||
|
||||
color: str
|
||||
def render(self):
|
||||
color = self.config.color_map[self.char]
|
||||
return f"[{color}]{self.char}[/{color}]"
|
||||
|
||||
def __str__(self):
|
||||
return f"[{self.color}]{self.char}[/{self.color}]"
|
||||
return self.render()
|
||||
|
||||
|
||||
class ColorizedTileSet(TileSet):
|
||||
|
@ -149,6 +132,8 @@ class ColorizedTileSet(TileSet):
|
|||
|
||||
tiles: Dict[str, ColorizedTile] = {}
|
||||
|
||||
tile_type = ColorizedTile
|
||||
|
||||
|
||||
@dataclass
|
||||
class ImageTile(Tile):
|
||||
|
@ -159,7 +144,6 @@ class ImageTile(Tile):
|
|||
is rendered, a random path from ImageTile.paths will be selected.
|
||||
"""
|
||||
|
||||
paths: List[Path] = []
|
||||
paths: List[Path] = field(default_factory=list)
|
||||
buffer: Image = None
|
||||
|
||||
|
@ -242,7 +226,7 @@ class ImageTileSet(TileSet):
|
|||
|
||||
TERRAIN_VARIANT.EXT.
|
||||
|
||||
where TERRAIN is the name of the terrain, matching the TileSet.character_map
|
||||
where TERRAIN is the name of the terrain, matching the TileSet.config.legend
|
||||
values, and VARIANT is an integer. EXT is the filename extension; images
|
||||
can be any format supported by the Pillow library on your system.
|
||||
|
||||
|
@ -292,16 +276,13 @@ class ImageTileSet(TileSet):
|
|||
will be chosen at random when rendered.
|
||||
"""
|
||||
|
||||
image_dir: Path
|
||||
tile_size: int = 128
|
||||
|
||||
_tile_cache = {} # ImageTile data
|
||||
_image_cache = {} # rendered image data
|
||||
|
||||
@cached_property
|
||||
def paths(self) -> Dict[str, List[Path]]:
|
||||
paths = defaultdict(list)
|
||||
for imgfile in sorted(self.image_dir.glob("*.png")):
|
||||
for imgfile in sorted(self.config.path.glob("*.png")):
|
||||
(terrain_name, *parts) = imgfile.stem.rsplit("_")
|
||||
key = terrain_name
|
||||
if parts[0] in ("edge", "corner"):
|
||||
|
@ -317,10 +298,10 @@ class ImageTileSet(TileSet):
|
|||
|
||||
def load(self):
|
||||
"""
|
||||
Walk the character_map and load the images associated with each terrain type.
|
||||
Walk the config.legend and load the images associated with each terrain type.
|
||||
"""
|
||||
self.tiles = defaultdict(list)
|
||||
for char, name in self.character_map.items():
|
||||
for char, name in self.config.legend.items():
|
||||
if name not in self.paths:
|
||||
raise MissingImageDataException(
|
||||
f"The tile set does not contain any images for the '{char}' ({name}) terrain."
|
||||
|
@ -328,11 +309,11 @@ class ImageTileSet(TileSet):
|
|||
for path in self.paths[name]:
|
||||
key = f"{name}-{path.name}"
|
||||
if key not in self._tile_cache:
|
||||
tile = ImageTile(char=char, name=name, buffer=Image.open(path))
|
||||
tile = ImageTile(char=char, name=name, buffer=Image.open(path), config=self.config)
|
||||
self._tile_cache[key] = tile
|
||||
self.add(tile)
|
||||
for name in self.paths:
|
||||
if name not in self.character_map.values():
|
||||
if name not in self.config.legend.values():
|
||||
logging.warn(f"{name} images exist but do not map to terrain types in the legend.")
|
||||
|
||||
def _get_overlays(self, position: Position, adjacent: List[Position] = []) -> tuple:
|
||||
|
@ -359,6 +340,19 @@ class ImageTileSet(TileSet):
|
|||
|
||||
return (nw, n, ne, e, se, s, sw, w)
|
||||
|
||||
def render_grid(self, grid: Grid, width: int, height: int) -> Image:
|
||||
map_image = Image.new("RGBA", (self.config.tileset["size"] * width, self.config.tileset["size"] * height))
|
||||
for y in range(0, height):
|
||||
for x in range(0, width):
|
||||
pos = grid.at(y, x)
|
||||
if not pos or pos.value == self.empty_space:
|
||||
continue
|
||||
map_image.paste(
|
||||
self.render_tile(pos, [a or pos for a in grid.adjacent(pos)]),
|
||||
(self.config.tileset["size"] * x, self.config.tileset["size"] * y),
|
||||
)
|
||||
return map_image
|
||||
|
||||
def render_tile(self, position, adjacent) -> Image:
|
||||
"""
|
||||
Return a rendered image of the tile in the specified position, including any edge and
|
||||
|
@ -367,7 +361,8 @@ class ImageTileSet(TileSet):
|
|||
key = ":".join([str(position), *[str(a) for a in adjacent]])
|
||||
if key not in self._image_cache:
|
||||
self._image_cache[key] = position.value.render(
|
||||
self.tile_size, *[self._image_cache.get(overlay) for overlay in self._get_overlays(position, adjacent)]
|
||||
self.config.tileset["size"],
|
||||
*[self._image_cache.get(overlay) for overlay in self._get_overlays(position, adjacent)],
|
||||
)
|
||||
return self._image_cache[key]
|
||||
|
||||
|
@ -390,53 +385,36 @@ class TileSetManager:
|
|||
|
||||
"""
|
||||
|
||||
def __init__(self, config_dir: Path):
|
||||
DEFAULT_TILE_SET = ImageTileSet
|
||||
|
||||
def __init__(self, config_dir: Path = Path(__file__).parent.parent / "tilesets"):
|
||||
self.config_dir = config_dir
|
||||
self._available = {}
|
||||
self._find_tilesets()
|
||||
|
||||
@property
|
||||
def available(self) -> dict:
|
||||
"""
|
||||
Return a mapping of available tile sets by name.
|
||||
"""
|
||||
return {"console": self.console_map, "colorized": self.console_map_colorized, **self._available}
|
||||
|
||||
def _find_tilesets(self):
|
||||
@cached_property
|
||||
def available(self):
|
||||
"""
|
||||
Parse the tileset.toml file of every tile set in the configuration directory.
|
||||
"""
|
||||
self._available = {}
|
||||
available = {}
|
||||
for config_file in self.config_dir.rglob("tileset.toml"):
|
||||
config = tomllib.loads(config_file.read_bytes().decode())
|
||||
config["config_dir"] = config_file.parent
|
||||
self._available[config["config_dir"].name] = config
|
||||
available[config_file.parent.name] = TileSetConfig(path=config_file.parent, **config)
|
||||
return available
|
||||
|
||||
def load(self, name: str) -> ImageTileSet:
|
||||
def load(self, name: str) -> TileSet:
|
||||
"""
|
||||
Load the specified tile set, which it is assumed should be an ImageTileSet.
|
||||
"""
|
||||
config = self.available[name]
|
||||
tileset = ImageTileSet(
|
||||
image_dir=config["config_dir"],
|
||||
name=config["tileset"]["name"],
|
||||
desc=config["tileset"]["desc"],
|
||||
tile_size=config["tileset"].get("size", DEFAULT_TILE_SIZE_IN_PIXELS),
|
||||
character_map=config["legend"],
|
||||
)
|
||||
tileset_class = self.DEFAULT_TILE_SET
|
||||
custom_class = self.available[name].tileset.get("class")
|
||||
if custom_class:
|
||||
try:
|
||||
module, class_name = custom_class.rsplit(".", 1)
|
||||
tileset_class = getattr(importlib.import_module(module), class_name)
|
||||
except ImportError as e:
|
||||
raise MisconfiguredTileSetException(
|
||||
f"{self.config.path}: Could not import custom class {custom_class}: {e}"
|
||||
)
|
||||
tileset = tileset_class(self.available[name])
|
||||
tileset.load()
|
||||
return tileset
|
||||
|
||||
@cached_property
|
||||
def console_map(self) -> TileSet:
|
||||
ts = TileSet(name="console", desc="Tiles used for input and text rendering.")
|
||||
for key, value in ts.character_map.items():
|
||||
ts.add(Tile(char=key, name=value))
|
||||
return ts
|
||||
|
||||
@cached_property
|
||||
def console_map_colorized(self) -> ColorizedTileSet:
|
||||
ts = ColorizedTileSet(name="colorized", desc="Colorized ASCII.")
|
||||
for key, value in ts.character_map.items():
|
||||
ts.add(ColorizedTile(char=key, name=value, color=COLOR_MAP.get(key, "grey")))
|
||||
return ts
|
||||
|
|
27
src/tilesets/ascii/tileset.toml
Normal file
27
src/tilesets/ascii/tileset.toml
Normal file
|
@ -0,0 +1,27 @@
|
|||
[tileset]
|
||||
name = "ascii"
|
||||
desc = "Render maps as ascii."
|
||||
class = "tilemapper.tileset.TileSet"
|
||||
|
||||
[legend]
|
||||
" " = "empty"
|
||||
"." = "ground"
|
||||
"," = "grass"
|
||||
"_" = "water"
|
||||
"d" = "door, open"
|
||||
"D" = "door, closed"
|
||||
"L" = "door, locked"
|
||||
"S" = "door, secret"
|
||||
"v" = "stairs, down"
|
||||
"^" = "stairs, up"
|
||||
"0" = "location 0"
|
||||
"1" = "location 1"
|
||||
"2" = "location 2"
|
||||
"3" = "location 3"
|
||||
"4" = "location 4"
|
||||
"5" = "location 5"
|
||||
"6" = "location 6"
|
||||
"7" = "location 7"
|
||||
"8" = "location 8"
|
||||
"9" = "location 9"
|
||||
|
48
src/tilesets/colorized/tileset.toml
Normal file
48
src/tilesets/colorized/tileset.toml
Normal file
|
@ -0,0 +1,48 @@
|
|||
[tileset]
|
||||
name = "Colorized"
|
||||
desc = "Colorized ANSI tiles (text-only)"
|
||||
class = "tilemapper.tileset.ColorizedTileSet"
|
||||
|
||||
[legend]
|
||||
" " = "empty"
|
||||
"." = "ground"
|
||||
"," = "grass"
|
||||
"_" = "water"
|
||||
"d" = "door, open"
|
||||
"D" = "door, closed"
|
||||
"L" = "door, locked"
|
||||
"S" = "door, secret"
|
||||
"v" = "stairs, down"
|
||||
"^" = "stairs, up"
|
||||
"0" = "location 0"
|
||||
"1" = "location 1"
|
||||
"2" = "location 2"
|
||||
"3" = "location 3"
|
||||
"4" = "location 4"
|
||||
"5" = "location 5"
|
||||
"6" = "location 6"
|
||||
"7" = "location 7"
|
||||
"8" = "location 8"
|
||||
"9" = "location 9"
|
||||
|
||||
[color_map]
|
||||
" " = "black"
|
||||
"." = "white on grey58"
|
||||
"d" = "bold cyan on grey58"
|
||||
"D" = "bold green on grey58"
|
||||
"L" = "bold dark_red on grey58"
|
||||
"S" = "bold black on grey58"
|
||||
"v" = "bold steel_blue on grey3"
|
||||
"^" = "bold steel_blue on grey3"
|
||||
"0" = "white on dark_red"
|
||||
"1" = "white on dark_red"
|
||||
"2" = "white on dark_red"
|
||||
"3" = "white on dark_red"
|
||||
"4" = "white on dark_red"
|
||||
"5" = "white on dark_red"
|
||||
"6" = "white on dark_red"
|
||||
"7" = "white on dark_red"
|
||||
"8" = "white on dark_red"
|
||||
"9" = "white on dark_red"
|
||||
"_" = "white on steel_blue"
|
||||
"," = "black on dark_green"
|
|
@ -1,5 +1,4 @@
|
|||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
import pytest
|
||||
|
@ -9,7 +8,7 @@ from tilemapper import battlemap, tileset
|
|||
|
||||
@pytest.fixture
|
||||
def manager():
|
||||
return tileset.TileSetManager(Path(__file__).parent / "fixtures")
|
||||
return tileset.TileSetManager()
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
@ -34,11 +33,12 @@ def sample_map():
|
|||
|
||||
|
||||
def test_tileset_loader(manager):
|
||||
assert manager.console_map.name in manager.available
|
||||
assert "colorized" in manager.available
|
||||
assert "ascii" in manager.available
|
||||
|
||||
|
||||
def test_renderer(manager, sample_map):
|
||||
test_map = battlemap.BattleMap("test map", source=StringIO(sample_map), tileset=manager.console_map)
|
||||
test_map = battlemap.BattleMap("test map", source=StringIO(sample_map), tileset=manager.load("ascii"))
|
||||
test_map.load()
|
||||
assert test_map.width == 21
|
||||
assert test_map.height == 12
|
||||
|
|
Loading…
Reference in New Issue
Block a user