Add mobreport.py

This commit is contained in:
Andrew Miner
2025-10-06 22:44:46 -06:00
parent 4637137152
commit 3d6f9800ec
17 changed files with 179 additions and 44 deletions
+15 -3
View File
@@ -67,8 +67,20 @@ def span(*altitudes):
if not altitudes: return ANYWHERE
result = Altitude("", ANYWHERE.top, ANYWHERE.bottom)
for altitude in altitudes:
result.bottom = min(result.bottom, altitude.bottom)
result.top = max(result.top, altitude.top)
bottom = OVERGROUND[-1].top
bottomAltitude = None
top = UNDERGROUND[-1].bottom
topAltitude = None
for altitude in altitudes:
if altitude.bottom < bottom:
bottom = altitude.bottom
bottomAltitude = altitude
if altitude.top > top:
top = altitude.top
topAltitude = altitude
result = Altitude(f"{bottomAltitude.name}-{topAltitude.name}", bottom, top)
return result
+1 -1
View File
@@ -13,6 +13,6 @@ def mergeRange():
# Tests ############################################################################################
def test_span(merged):
assert merged.name == "lowlands-uplands"
assert merged.bottom == A.LOWLANDS.bottom
assert merged.top == A.UPLANDS.top
+24
View File
@@ -31,6 +31,30 @@ class BiomeFilter:
self.required = required or []
self.prohibited = prohibited or []
def __str__(self) -> str:
required = []
for trait in self.required:
if isinstance(trait, BiomeTrait):
required.append(str(trait))
else:
required.append("(" +
", ".join([str(option) for option in trait]) +
")")
prohibited = []
for trait in self.prohibited:
prohibited.append(str(trait))
result = "".join([
"must:[",
", ".join(required),
"], not:[",
", ".join(prohibited),
"]"
])
return result
def __repr__(self) -> str:
return f"BiomeFilter([{repr(self.required)}], [{repr(self.prohibited)}])"
+16 -6
View File
@@ -5,7 +5,7 @@ class Group:
How many individuals are commonly present when encountering a creature.
"""
def __init__(self, name, smallest, largest):
def __init__(self, name:str, smallest:int, largest:int):
self.name = name
self.smallest = smallest
self.largest = largest
@@ -42,9 +42,19 @@ ALL = [SOLO, PAIR, FAMILY, TROUP, HERD]
def merge(*groups):
if not groups: return SOLO
result = Group(f"", HERD.largest, SOLO.smallest)
for group in groups:
result.smallest = min(result.smallest, group.smallest)
result.largest = max(result.largest, group.largest)
smallest = ALL[-1].largest
smallestGroup = None
return result
largest = ALL[0].smallest
largestGroup = None
for group in groups:
if group.smallest < smallest:
smallest = group.smallest
smallestGroup = group
if group.largest > largest:
largest = group.largest
largestGroup = group
return Group(f"{smallestGroup.name}-{largestGroup.name}", smallest, largest)
+18 -8
View File
@@ -1,16 +1,26 @@
from tungston.core.fauna.mob import Mob
from collections.abc import Iterator
from tungston.core.fauna.mobplacement import MobPlacement
# Class ############################################################################################
class MobCatalog:
def __init__(self, mobs):
self.mobs = mobs
def __init__(self, mobs:tuple[MobPlacement]):
self._mobs = {}
def findByName(self, name):
for mob in self.mobs:
if mob.name == name:
return mob
for mob in mobs:
self.add(mob)
return None
def add(self, placement:MobPlacement) -> "MobCatalog":
if placement.mob.name in self._mobs:
raise Exception("Catalog already has an entry for {mob.name}")
self._mobs[placement.mob.name] = placement
def all(self) -> Iterator[MobPlacement]:
for placement in self._mobs.values():
yield placement
def get(self, name:str) -> MobPlacement:
return self._mobs.get(name, None)
+1 -1
View File
@@ -30,7 +30,7 @@ def test_cowsInFields(placement):
"Placement{" +
"habitats: [" +
"Habitat{" +
"altitude: [anywhere <-64 to 320>], " +
"altitude: anywhere <-64 to 320>, " +
"biomeFilter: BiomeFilter([[Flora<field>, Heat<temperate>]], [[]]), " +
"seasons: [Season<spring>, Season<summer>, Season<autumn>, Season<winter>], " +
"group: solo<1 to 1>, " +
@@ -44,7 +44,7 @@ def test_repr(bifIron):
assert repr(bifIron) == (
"MetalDeposit<bifiron>{" +
"scarcity: Scarcity<common>, " +
"biomeFilter: BiomeFilter([[Flora<forest>]], [[]]), " +
"biomeFilter: must:[Flora: forest], not:[], " +
"inclusions: [" +
"Inclusion{mineral: iron, weight: 60}, " +
"Inclusion{mineral: quartz, weight: 40}" +
+8 -8
View File
@@ -22,7 +22,7 @@ class Habitat:
def __init__(
self,
altitudes:tuple[Altitude]|Altitude=[A.ANYWHERE],
altitude:Altitude=A.ANYWHERE,
biomeFilter:BiomeFilter=None,
seasons:tuple[Season]=E.ALL,
@@ -30,7 +30,7 @@ class Habitat:
location:Location=L.OUTSIDE,
scarcity:Scarcity=C.SPARSE,
):
self.altitudes = (altitudes,) if isinstance(altitudes, Altitude) else altitudes
self.altitude = altitude
self.biomeFilter = biomeFilter or BiomeFilter()
self.seasons = (seasons,) if isinstance(seasons, Season) else seasons
@@ -41,19 +41,19 @@ class Habitat:
self._source = None
def __str__(self) -> str:
return "".join(str(p) for p in [
self.altitude, "|",
return "".join([str(p) for p in [
", ".join(self.altitude), "|",
self.biomeFilter, "|",
self.seasons, "|",
", ".join([str(s) for s in self.seasons]), "|",
self.group, "|",
self.location, "|",
self.scarcity
])
]])
def __repr__(self) -> str:
return "".join([str(p) for p in [
"Habitat{",
"altitude: [", ", ".join([repr(a) for a in self.altitudes]), "], ",
"altitude: ", repr(self.altitude), ", ",
"biomeFilter: ", repr(self.biomeFilter), ", ",
"seasons: [", ", ".join([repr(s) for s in self.seasons]), "], ",
"group: ", repr(self.group), ", ",
@@ -64,7 +64,7 @@ class Habitat:
def derive(self, **kwargs):
kwargs = {
"altitudes": self.altitudes,
"altitude": self.altitude,
"biomeFilter": self.biomeFilter,
"seasons": self.seasons,
"group": self.group,
+1 -1
View File
@@ -35,7 +35,7 @@ def test_derive(derivedHabitats):
def test_repr(fields):
assert repr(fields) == (
"Habitat{" +
"altitude: [anywhere <-64 to 320>], " +
"altitude: anywhere <-64 to 320>, " +
"biomeFilter: BiomeFilter([[Flora<field>, Heat<temperate>]], [[]]), " +
"seasons: [Season<spring>, Season<summer>, Season<autumn>, Season<winter>], " +
"group: solo<1 to 1>, " +
+1 -1
View File
@@ -25,7 +25,7 @@ def test_repr(placement):
"Placement{" +
"habitats: [" +
"Habitat{" +
"altitude: [anywhere <-64 to 320>], " +
"altitude: anywhere <-64 to 320>, " +
"biomeFilter: BiomeFilter([[Flora<field>, Heat<temperate>]], [[]]), " +
"seasons: [Season<spring>, Season<summer>, Season<autumn>, Season<winter>], " +
"group: solo<1 to 1>, " +
+49
View File
@@ -0,0 +1,49 @@
from tungston.core.world import World
from tungston.core.ecology.biometrait import BiomeTrait
from tungston.generator.markdown.report import Report
# Class ############################################################################################
class MobReport(Report):
def __init__(self, world:World):
super().__init__("mobs.md", world)
def build(self):
for placement in self.world.mobs.all():
self.line(f"# Mob: {placement.mob.name} <{placement.mob.gameId}>")
self.line()
self.indent()
for index, habitat in enumerate(placement.habitats, start=1):
self.text("* habitat ").line(index)
self.indent()
self.text("* altitude: ").line(habitat.altitude)
self.line("* biomeFilter:")
self.indent()
for trait in habitat.biomeFilter.required:
if isinstance(trait, BiomeTrait):
self.text("* ").line(trait)
else:
category = type(trait[0]).__name__
self.text("* ").\
text(category).\
text(": any of: ").\
line(", ".join([t.name for t in trait]))
for trait in habitat.biomeFilter.prohibited:
category = type(trait[0]).__name__
self.text("* ").text(category).text(": not: ").line(trait.name)
self.outdent()
self.text("* seasons: ").line(", ".join([s.name for s in habitat.seasons]))
self.text("* group: ").line(habitat.group.name)
self.text("* location: ").line(habitat.location.name)
self.text("* scarcity: ").line(habitat.scarcity.name)
self.outdent()
self.outdent()
self.line()
@@ -0,0 +1,7 @@
import tungston.modpack.mysteriousisland.biomecatalog
# Class ############################################################################################
def test_syntax():
pass
@@ -0,0 +1,7 @@
import tungston.modpack.mysteriousisland.depositcatalog
# Class ############################################################################################
def test_syntax():
pass
@@ -0,0 +1,7 @@
import tungston.modpack.mysteriousisland.mineralcatalog
# Class ############################################################################################
def test_syntax():
pass
+13 -13
View File
@@ -23,22 +23,22 @@ import tungston.core.season as SE
CATALOG = MobCatalog([
MobPlacement(Mob("armadillo", "minecraft:armadillo", AC.NOCTURNAL),
Habitat(
altitudes = AL.LOWLANDS,
altitude = AL.LOWLANDS,
biomeFilter = BF([HE.SUBTROPICAL, HU.DRY]),
seasons = SE.SUMMER,
group = GR.merge(GR.SOLO, GR.PAIR),
scarcity = SC.COMMON
).derive(
altitudes = AL.UPLANDS, scarcity = SC.SPARSE,
altitude = AL.UPLANDS, scarcity = SC.SPARSE,
).derive(
altitudes = AL.LOWLANDS, seasons = SE.excluding(SE.SUMMER), scarcity = SC.UNCOMMON,
altitude = AL.LOWLANDS, seasons = SE.excluding(SE.SUMMER), scarcity = SC.UNCOMMON,
).derive(
altitudes = AL.UPLANDS, scarcity = SC.UNUSUAL,
altitude = AL.UPLANDS, scarcity = SC.UNUSUAL,
)
),
MobPlacement(Mob("black_bear", "bearminimum:black_bear"),
Habitat(
altitudes = AL.span(AL.LOWLANDS, AL.ALPINE),
altitude = AL.span(AL.LOWLANDS, AL.ALPINE),
biomeFilter = BF([HE.TEMPERATE, FL.FOREST]),
seasons = SE.AUTUMN,
group = GR.merge(GR.SOLO, GR.FAMILY),
@@ -59,7 +59,7 @@ CATALOG = MobCatalog([
),
MobPlacement(Mob("blaze", "minecraft:blaze"),
Habitat(
altitudes = AL.PLUTONIC,
altitude = AL.PLUTONIC,
location = LO.CAVE,
group = GR.SOLO,
scarcity = SC.UNCOMMON
@@ -68,7 +68,7 @@ CATALOG = MobCatalog([
MobPlacement(Mob("bogged", "minecraft:bogged")),
MobPlacement(Mob("brown_bear", "bearminimum:brown_bear"),
Habitat(
altitudes = AL.span(AL.LOWLANDS, AL.ALPINE),
altitude = AL.span(AL.LOWLANDS, AL.ALPINE),
biomeFilter = BF([HE.BOREAL, (FL.CANOPY, FL.FOREST)]),
seasons = SE.AUTUMN,
group = GR.SOLO,
@@ -82,19 +82,19 @@ CATALOG = MobCatalog([
MobPlacement(Mob("bulwark", "immersiveengineering:bulwark")),
MobPlacement(Mob("camel", "minecraft:camel", AC.CREPUSCULAR),
Habitat(
altitudes = AL.span(AL.DUNES, AL.LOWLANDS),
altitude = AL.span(AL.DUNES, AL.LOWLANDS),
biomeFilter = BF([HE.TROPICAL, HU.DRY, FL.BARREN, SO.SANDY]),
seasons = SE.WET,
seasons = SE.DRY,
group = GR.FAMILY,
scarcity = SC.UNUSUAL,
).derive(
seasons = SE.DRY, scarcity = SC.RARE
seasons = SE.WET, scarcity = SC.RARE
)
),
MobPlacement(Mob("cat", "minecraft:cat")),
MobPlacement(Mob("cave_spider", "minecraft:cave_spider"),
Habitat(
altitudes = AL.span(AL.OVERBURDEN, AL.HILLS),
altitude = AL.span(AL.OVERBURDEN, AL.HILLS),
location = LO.CAVE,
group = GR.SOLO,
scarcity = SC.UNCOMMON
@@ -102,7 +102,7 @@ CATALOG = MobCatalog([
),
MobPlacement(Mob("chameleon", "cold_sweat:chameleon"),
Habitat(
altitudes = AL.span(AL.DUNES, AL.UPLANDS),
altitude = AL.span(AL.DUNES, AL.UPLANDS),
biomeFilter = BF([HE.TROPICAL, HU.WET, [FL.CANOPY, FL.FOREST]]),
seasons = SE.WET,
group = GR.merge(GR.SOLO, GR.FAMILY),
@@ -119,7 +119,7 @@ CATALOG = MobCatalog([
),
MobPlacement(Mob("chicken", "minecraft:chicken"),
Habitat(
altitudes = AL.span(AL.LOWLANDS, AL.UPLANDS),
altitude = AL.span(AL.LOWLANDS, AL.UPLANDS),
biomeFilter = BF([HE.TROPICAL, HU.WET, FL.within(FL.CANOPY, FL.CLEARING)]),
seasons = SE.SUMMER,
group = GR.TROUP,
@@ -0,0 +1,7 @@
import tungston.modpack.mysteriousisland.mobcatalog
# Class ############################################################################################
def test_syntax():
pass
+3 -1
View File
@@ -7,6 +7,7 @@ from tungston.modpack.mysteriousisland.mobcatalog import CATALOG as mobs
from tungston.generator.markdown.reportwriter import ReportWriter
from tungston.generator.markdown.biomereport import BiomeReport
from tungston.generator.markdown.mineralreport import MineralReport
from tungston.generator.markdown.mobreport import MobReport
import sys
@@ -23,7 +24,8 @@ class Runner(BaseRunner):
def _command_writeReports(self):
writer = ReportWriter([
BiomeReport(self.world),
MineralReport(self.world)
MineralReport(self.world),
MobReport(self.world),
])
writer.write(REPORT_PATH)