Added CLI options for controlling text output
This commit is contained in:
parent
2cddc902ab
commit
ae3d40e91e
|
@ -1,13 +1,12 @@
|
|||
# import logging
|
||||
import tomllib
|
||||
from dataclasses import dataclass
|
||||
from functools import cached_property
|
||||
from io import StringIO
|
||||
from pathlib import Path
|
||||
from textwrap import indent
|
||||
from typing import List, Union, get_type_hints
|
||||
from types import SimpleNamespace
|
||||
|
||||
import tomllib
|
||||
from typing import List, Union, get_type_hints
|
||||
|
||||
from PIL import Image
|
||||
|
||||
|
@ -40,6 +39,13 @@ class BattleMap(BattleMapType):
|
|||
map_string: str = ""
|
||||
metadata: SimpleNamespace = None
|
||||
tileset: TileSet = None
|
||||
|
||||
render_header: bool = True
|
||||
render_border: bool = True
|
||||
render_coordinates: bool = True
|
||||
render_legend: bool = True
|
||||
render_notes: bool = True
|
||||
|
||||
width: int = 0
|
||||
height: int = 0
|
||||
|
||||
|
@ -62,7 +68,7 @@ class BattleMap(BattleMapType):
|
|||
line = line.lstrip(" ")
|
||||
if in_map:
|
||||
if line and line[0] == "#":
|
||||
map_data += line[1:] + "\n"
|
||||
map_data += line[1:].lstrip() + "\n"
|
||||
continue
|
||||
in_map = False
|
||||
metadata += line + "\n"
|
||||
|
@ -82,6 +88,8 @@ class BattleMap(BattleMapType):
|
|||
del self.legend
|
||||
if hasattr(self, "coordinates"):
|
||||
del self.coordinates
|
||||
if hasattr(self, "notes"):
|
||||
del self.notes
|
||||
return self.grid
|
||||
|
||||
def validate_map_string(self, data: str) -> bool:
|
||||
|
@ -127,31 +135,46 @@ class BattleMap(BattleMapType):
|
|||
|
||||
@cached_property
|
||||
def header(self) -> str:
|
||||
lines = [f"BattleMap: {self.metadata.map['name']} ({self.width}x{self.height})"]
|
||||
lines.append(('-' * len(lines[0])))
|
||||
lines = ["", f"BattleMap: {self.metadata.map['name']} ({self.width}x{self.height})"]
|
||||
lines.append(("-" * len(lines[0])))
|
||||
for key, value in self.metadata.map.items():
|
||||
if key in ("name", "description"):
|
||||
continue
|
||||
lines.append(f"{key.title()}: {value}")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
@cached_property
|
||||
def footer(self) -> str:
|
||||
lines = []
|
||||
if 'description' in self.metadata.map:
|
||||
if "description" in self.metadata.map:
|
||||
lines.append(f"{self.metadata.map['description']}")
|
||||
lines.append("")
|
||||
lines.append("Legend:")
|
||||
lines.append(self.legend)
|
||||
return "\n".join(lines)
|
||||
|
||||
@cached_property
|
||||
def notes(self) -> str:
|
||||
lines = []
|
||||
for number in dir(self.metadata):
|
||||
if not number.isdigit():
|
||||
continue
|
||||
location = getattr(self.metadata, number)
|
||||
lines.append(f"[{number}]{location.get('name', '')}")
|
||||
if hasattr(location, "notes"):
|
||||
for note in location.notes:
|
||||
lines.append(f" {note}")
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
@cached_property
|
||||
def legend(self) -> str:
|
||||
output = ""
|
||||
locations = False
|
||||
for char in sorted(set(list(self.map_string)), key=str.lower):
|
||||
if char in self.tileset.config.legend:
|
||||
if char in "0123456789":
|
||||
if char.isdigit():
|
||||
locations = True
|
||||
continue
|
||||
output += f"{char} - {self.tileset.config.legend[char]}\n"
|
||||
|
@ -182,24 +205,42 @@ class BattleMap(BattleMapType):
|
|||
return self.as_string()
|
||||
|
||||
def __repr__(self) -> str:
|
||||
lines = ""
|
||||
left_coords = self.left_coordinates
|
||||
i = 0
|
||||
for line in str(self).splitlines():
|
||||
lines += f"{left_coords[i].rjust(2, ' ')} │ {line}".ljust(self.width, " ") + " │\n"
|
||||
i = i + 1
|
||||
top_break = "┌" + ("─" * (self.width + 2)) + "┐"
|
||||
bot_break = "└" + ("─" * (self.width + 2)) + "┘"
|
||||
return "\n".join(
|
||||
[
|
||||
"",
|
||||
self.header,
|
||||
"",
|
||||
indent(self.top_coordinates, " " * 5),
|
||||
indent(top_break, " " * 3),
|
||||
lines.rstrip(),
|
||||
indent(bot_break, " " * 3),
|
||||
"",
|
||||
indent(self.footer, " ")
|
||||
]
|
||||
)
|
||||
lines = [""]
|
||||
|
||||
map_lines = ""
|
||||
if self.render_coordinates:
|
||||
left_coords = self.left_coordinates
|
||||
i = 0
|
||||
border = "│" if self.render_border else " "
|
||||
for line in str(self).splitlines():
|
||||
map_lines += f"{left_coords[i].rjust(2, ' ')}{border}{line}".ljust(self.width, " ") + f"{border}\n"
|
||||
i = i + 1
|
||||
elif self.render_border:
|
||||
for line in str(self).splitlines():
|
||||
map_lines += f"│{line}".ljust(self.width, " ") + "│\n"
|
||||
else:
|
||||
map_lines = str(self)
|
||||
|
||||
top_break = bot_break = ""
|
||||
if self.render_border:
|
||||
top_break = "┌" + ("─" * self.width) + "┐"
|
||||
bot_break = "└" + ("─" * self.width) + "┘"
|
||||
|
||||
lines = [self.header] if self.render_header else []
|
||||
if self.render_coordinates:
|
||||
lines.append(indent(self.top_coordinates, " " * 3))
|
||||
if top_break:
|
||||
lines.append(indent(top_break, " " * 2) if self.render_coordinates else top_break)
|
||||
lines.append(map_lines.rstrip())
|
||||
if bot_break:
|
||||
lines.append(indent(bot_break, " " * 2) if self.render_coordinates else bot_break)
|
||||
lines.append("")
|
||||
|
||||
if self.render_legend:
|
||||
lines.append(indent(self.footer, " "))
|
||||
lines.append("")
|
||||
|
||||
if self.render_notes:
|
||||
lines.append(self.notes)
|
||||
|
||||
return indent("\n".join(lines), " ")
|
||||
|
|
|
@ -54,31 +54,60 @@ def convert(source: typer.FileText = typer.Argument(help="The donjon.sh .json fi
|
|||
@app.command()
|
||||
def render(
|
||||
source: typer.FileText = typer.Argument(
|
||||
help="The battle map text file to load.", default=INSTALL_DIR / "examples" / "five_room_dungeon.txt"
|
||||
help="The battle map text file to load.", default=INSTALL_DIR / "examples" / "five_room_dungeon.toml"
|
||||
),
|
||||
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"
|
||||
),
|
||||
header: bool = typer.Option(help="If True, include the map header.", default=True),
|
||||
border: bool = typer.Option(help="If True, draw the map border.", default=True),
|
||||
coordinates: bool = typer.Option(help="If True, draw the coordinate outside the border.", default=True),
|
||||
legend: bool = typer.Option(help="If True, include the legend.", default=True),
|
||||
notes: bool = typer.Option(help="If True, include the notes.", default=True),
|
||||
map_only: bool = typer.Option(
|
||||
help="Equivalent to --no-header --no-border --no-coordinates --no-legend --no-notes", default=False
|
||||
),
|
||||
):
|
||||
"""
|
||||
Create a rendered battle map using a tile set. Will generate a PNG file if the tile set supports it,
|
||||
otherwise text output.
|
||||
"""
|
||||
render_map(source, outfile, tileset)
|
||||
render_map(
|
||||
source=source,
|
||||
outfile=outfile,
|
||||
tileset=tileset,
|
||||
header=header and not map_only,
|
||||
border=border and not map_only,
|
||||
coordinates=coordinates and not map_only,
|
||||
legend=legend and not map_only,
|
||||
notes=notes and not map_only,
|
||||
)
|
||||
|
||||
|
||||
def render_map(
|
||||
source: typer.FileText = INSTALL_DIR / "examples" / "five_room_dungeon.txt",
|
||||
outfile: Union[Path, None] = None,
|
||||
tileset: str = "colorized",
|
||||
header: bool = True,
|
||||
border: bool = True,
|
||||
coordinates: bool = True,
|
||||
legend: bool = True,
|
||||
notes: bool = True,
|
||||
):
|
||||
manager = app_state["tileset_manager"]
|
||||
if tileset not in manager.available:
|
||||
raise RuntimeError(f"Could not locate the tile set {tileset} in {manager.config_dir}.")
|
||||
|
||||
render_options = {
|
||||
"render_header": header,
|
||||
"render_border": border,
|
||||
"render_coordinates": coordinates,
|
||||
"render_notes": notes,
|
||||
"render_legend": legend,
|
||||
}
|
||||
try:
|
||||
bmap = battlemap.BattleMap(source=source, tileset=manager.load(tileset))
|
||||
bmap = battlemap.BattleMap(source=source, tileset=manager.load(tileset), **render_options)
|
||||
bmap.load()
|
||||
except battlemap.UnsupportedTileException as e:
|
||||
logging.error(e)
|
||||
|
|
|
@ -35,6 +35,10 @@ def sample_map():
|
|||
|
||||
[1]
|
||||
name = "room 1"
|
||||
description = "A large empty room."
|
||||
notes = [
|
||||
"Locked door DC 15"
|
||||
]
|
||||
[2]
|
||||
name = "room 2"
|
||||
[3]
|
||||
|
@ -62,13 +66,13 @@ def test_renderer(manager, sample_map):
|
|||
srclines = sample_map.splitlines()[1:]
|
||||
strlines = str(test_map).splitlines()
|
||||
for i in range(len(strlines)):
|
||||
assert strlines[i] == srclines[i].lstrip(' #').ljust(21, " ")
|
||||
assert strlines[i] == srclines[i].lstrip(" #").ljust(21, " ")
|
||||
|
||||
|
||||
def test_grid_coordiates(manager):
|
||||
coord_length = len(X_COORDS)
|
||||
map_size = 2 * coord_length + 1
|
||||
bigmap = StringIO((' # ' + ("." * map_size) + "\n") * map_size)
|
||||
bigmap = StringIO((" # " + ("." * map_size) + "\n") * map_size)
|
||||
test_map = battlemap.BattleMap(source=bigmap, tileset=manager.load("ascii"))
|
||||
test_map.load()
|
||||
assert test_map.grid.data[-1][-1].coordinates == (f"{map_size - 1}", X_COORDS[0] * 3)
|
||||
|
|
Loading…
Reference in New Issue
Block a user