From 0a7fe05c4f9e1bfa53dfeb6ed11d457dc04bb305 Mon Sep 17 00:00:00 2001 From: Andrew Miner Date: Mon, 20 Oct 2025 18:27:19 -0600 Subject: [PATCH] Add remaining flora & fauna spawns --- .../datapack/biomemodifier/addfeature_test.py | 7 + .../biomemodifier/removefeature_test.py | 7 + .../biomemodifier/removespawn_test.py | 7 + .../format/datapack/generationstep_test.py | 7 + mcpacker/format/datapack/structure_test.py | 7 + mcpacker/format/report/biomereport.py | 80 ++- mcpacker/format/report/biomereport_test.py | 29 +- mcpacker/format/report/plantspawnreport.py | 60 ++ .../format/report/plantspawnreport_test.py | 7 + mcpacker/format/templatecomposer_test.py | 8 + mcpacker/model/core/altitude.py | 10 +- mcpacker/model/core/blockstate.py | 35 ++ mcpacker/model/core/blockstate_test.py | 21 + mcpacker/model/core/ecology/biomefilter.py | 16 +- .../model/core/ecology/biomefilter_test.py | 17 + mcpacker/model/core/fauna/mobspawn.py | 21 +- mcpacker/model/core/fauna/mobspawn_test.py | 2 +- mcpacker/model/core/flora/canopyshape.py | 44 ++ mcpacker/model/core/flora/canopyshape_test.py | 7 + mcpacker/model/core/flora/density.py | 38 ++ mcpacker/model/core/flora/density_test.py | 7 + mcpacker/model/core/flora/immersion.py | 37 ++ mcpacker/model/core/flora/immersion_test.py | 7 + mcpacker/model/core/flora/patch.py | 87 +++ mcpacker/model/core/flora/patch_test.py | 7 + mcpacker/model/core/flora/plant.py | 12 + mcpacker/model/core/flora/plant_test.py | 7 + mcpacker/model/core/flora/plantcatalog.py | 8 + .../model/core/flora/plantcatalog_test.py | 7 + mcpacker/model/core/flora/plantspawn.py | 51 ++ mcpacker/model/core/flora/plantspawn_test.py | 7 + .../model/core/flora/plantspawncatalog.py | 8 + .../core/flora/plantspawncatalog_test.py | 7 + mcpacker/model/core/flora/tree.py | 50 ++ mcpacker/model/core/flora/tree_test.py | 7 + mcpacker/model/core/flora/trunkshape.py | 39 ++ mcpacker/model/core/flora/trunkshape_test.py | 7 + mcpacker/model/core/habitat.py | 44 +- mcpacker/model/core/spawn.py | 12 +- mcpacker/model/core/world.py | 45 +- mcpacker/model/resourcepack/model_test.py | 7 + mcpacker/pack/mysteriousisland/addbiomes.py | 4 +- mcpacker/pack/mysteriousisland/adddeposits.py | 12 +- .../pack/mysteriousisland/addmobspawns.py | 523 +++++++++++++----- mcpacker/pack/mysteriousisland/addplants.py | 484 ++++++++++++++++ .../pack/mysteriousisland/addplants_test.py | 7 + .../pack/mysteriousisland/addplantspawns.py | 446 +++++++++++++++ .../mysteriousisland/addplantspawns_test.py | 7 + mcpacker/pack/mysteriousisland/modpack.py | 4 + mcpacker/pack/mysteriousisland/runner.py | 2 +- mcpacker/ui/runner.py | 2 + mcpacker/write/compositewriter_test.py | 7 + mcpacker/write/datapack/depositwriter_test.py | 7 + .../datapack/disablefeaturewriter_test.py | 7 + .../write/datapack/disablespawnwriter_test.py | 7 + .../largeoredeposits/depositwriter_test.py | 8 + mcpacker/write/packmetawriter_test.py | 7 + .../resourcepack/blockstatewriter_test.py | 7 + mcpacker/write/staticwriter_test.py | 7 + mcpacker/write/zipwriter_test.py | 7 + 60 files changed, 2205 insertions(+), 243 deletions(-) create mode 100644 mcpacker/format/datapack/biomemodifier/addfeature_test.py create mode 100644 mcpacker/format/datapack/biomemodifier/removefeature_test.py create mode 100644 mcpacker/format/datapack/biomemodifier/removespawn_test.py create mode 100644 mcpacker/format/datapack/generationstep_test.py create mode 100644 mcpacker/format/datapack/structure_test.py create mode 100644 mcpacker/format/report/plantspawnreport.py create mode 100644 mcpacker/format/report/plantspawnreport_test.py create mode 100644 mcpacker/format/templatecomposer_test.py create mode 100644 mcpacker/model/core/blockstate.py create mode 100644 mcpacker/model/core/blockstate_test.py create mode 100644 mcpacker/model/core/flora/canopyshape.py create mode 100644 mcpacker/model/core/flora/canopyshape_test.py create mode 100644 mcpacker/model/core/flora/density.py create mode 100644 mcpacker/model/core/flora/density_test.py create mode 100644 mcpacker/model/core/flora/immersion.py create mode 100644 mcpacker/model/core/flora/immersion_test.py create mode 100644 mcpacker/model/core/flora/patch.py create mode 100644 mcpacker/model/core/flora/patch_test.py create mode 100644 mcpacker/model/core/flora/plant.py create mode 100644 mcpacker/model/core/flora/plant_test.py create mode 100644 mcpacker/model/core/flora/plantcatalog.py create mode 100644 mcpacker/model/core/flora/plantcatalog_test.py create mode 100644 mcpacker/model/core/flora/plantspawn.py create mode 100644 mcpacker/model/core/flora/plantspawn_test.py create mode 100644 mcpacker/model/core/flora/plantspawncatalog.py create mode 100644 mcpacker/model/core/flora/plantspawncatalog_test.py create mode 100644 mcpacker/model/core/flora/tree.py create mode 100644 mcpacker/model/core/flora/tree_test.py create mode 100644 mcpacker/model/core/flora/trunkshape.py create mode 100644 mcpacker/model/core/flora/trunkshape_test.py create mode 100644 mcpacker/model/resourcepack/model_test.py create mode 100644 mcpacker/pack/mysteriousisland/addplants.py create mode 100644 mcpacker/pack/mysteriousisland/addplants_test.py create mode 100644 mcpacker/pack/mysteriousisland/addplantspawns.py create mode 100644 mcpacker/pack/mysteriousisland/addplantspawns_test.py create mode 100644 mcpacker/write/compositewriter_test.py create mode 100644 mcpacker/write/datapack/depositwriter_test.py create mode 100644 mcpacker/write/datapack/disablefeaturewriter_test.py create mode 100644 mcpacker/write/datapack/disablespawnwriter_test.py create mode 100644 mcpacker/write/largeoredeposits/depositwriter_test.py create mode 100644 mcpacker/write/packmetawriter_test.py create mode 100644 mcpacker/write/resourcepack/blockstatewriter_test.py create mode 100644 mcpacker/write/staticwriter_test.py create mode 100644 mcpacker/write/zipwriter_test.py diff --git a/mcpacker/format/datapack/biomemodifier/addfeature_test.py b/mcpacker/format/datapack/biomemodifier/addfeature_test.py new file mode 100644 index 0000000..083f239 --- /dev/null +++ b/mcpacker/format/datapack/biomemodifier/addfeature_test.py @@ -0,0 +1,7 @@ +import mcpacker.format.datapack.biomemodifier.addfeature + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/format/datapack/biomemodifier/removefeature_test.py b/mcpacker/format/datapack/biomemodifier/removefeature_test.py new file mode 100644 index 0000000..941df6e --- /dev/null +++ b/mcpacker/format/datapack/biomemodifier/removefeature_test.py @@ -0,0 +1,7 @@ +import mcpacker.format.datapack.biomemodifier.removefeature + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/format/datapack/biomemodifier/removespawn_test.py b/mcpacker/format/datapack/biomemodifier/removespawn_test.py new file mode 100644 index 0000000..51bd9e6 --- /dev/null +++ b/mcpacker/format/datapack/biomemodifier/removespawn_test.py @@ -0,0 +1,7 @@ +import mcpacker.format.datapack.biomemodifier.removespawn + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/format/datapack/generationstep_test.py b/mcpacker/format/datapack/generationstep_test.py new file mode 100644 index 0000000..3ddc1d2 --- /dev/null +++ b/mcpacker/format/datapack/generationstep_test.py @@ -0,0 +1,7 @@ +import mcpacker.format.datapack.generationstep + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/format/datapack/structure_test.py b/mcpacker/format/datapack/structure_test.py new file mode 100644 index 0000000..48eef04 --- /dev/null +++ b/mcpacker/format/datapack/structure_test.py @@ -0,0 +1,7 @@ +import mcpacker.format.datapack.structure + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/format/report/biomereport.py b/mcpacker/format/report/biomereport.py index d428a3d..0228eb4 100644 --- a/mcpacker/format/report/biomereport.py +++ b/mcpacker/format/report/biomereport.py @@ -1,7 +1,11 @@ from mcpacker.model.modpack import ModPack +from mcpacker.model.core.ecology.biome import Biome from mcpacker.format.report.composer import ReportComposer from pathlib import Path +import mcpacker.model.core.altitude as AL +import mcpacker.model.core.fauna.location as LO + # Class ############################################################################################ @@ -10,29 +14,63 @@ class BiomeReport(ReportComposer): def doCompose(self): for biome in self.pack.world.biomes: self.line(f"Biome: {biome.gameId} ({biome.name})") + self.indent() # biome + + self._composeTraitsLine(biome) + self._composeGeologySection(biome) + self._composeFloraSection(biome) + self._composeFaunaSection(biome) + + self.outdent() # biome self.line() - self.indent() - needsDelimiter = False - self.text("Traits: ") - for trait in biome.traits(): - if needsDelimiter: self.text(", ") - needsDelimiter = True - self.text(trait) - self.line() + def _composeGeologySection(self, biome:Biome): + self.line().line("Geology:").indent() + depositCount = 0 + for deposit in self.pack.world.deposits: + if not deposit.acceptsBiome(biome): continue + self.line(f"{deposit.name} ({deposit.scarcity})") + depositCount += 1 - self.line() - self.line("Deposits:") - self.indent() - depositCount = 0 - for deposit in self.pack.world.deposits: - if not deposit.acceptsBiome(biome): continue - self.line(deposit.name) - depositCount += 1 + if depositCount == 0: + self.line("") + self.outdent() # deposits - if depositCount == 0: - self.line("") - self.outdent() + def _composeFaunaSection(self, biome:Biome): + self.line().line("Fauna:").indent() + faunaLineCount = 0 + for spawn in self.pack.world.mobSpawns: + altitude = None + for habitat in spawn.acceptedBy(biome): + if habitat.location == LO.CAVE: continue + altitude = AL.span(altitude or habitat.altitude, habitat.altitude) - self.outdent() - self.line() + if altitude != None: + self.line(f"{spawn.mob.name} @ {altitude}") + faunaLineCount += 1 + + if faunaLineCount == 0: + self.line("") + self.outdent() # fauna + + def _composeFloraSection(self, biome:Biome): + self.line().line("Flora:").indent() + floraLineCount = 0 + for spawn in self.pack.world.plantSpawns: + if not spawn.acceptsBiome(biome): continue + self.line(f"{spawn.plant.name} @ {spawn.altitude}") + floraLineCount += 1 + + if floraLineCount == 0: + self.line("") + + self.outdent() # flora + + def _composeTraitsLine(self, biome:Biome): + needsDelimiter = False + self.line().text("Traits: ") + for trait in biome.traits(): + if needsDelimiter: self.text(", ") + needsDelimiter = True + self.text(trait) + self.line() diff --git a/mcpacker/format/report/biomereport_test.py b/mcpacker/format/report/biomereport_test.py index 191d4fe..0c6a768 100644 --- a/mcpacker/format/report/biomereport_test.py +++ b/mcpacker/format/report/biomereport_test.py @@ -5,13 +5,12 @@ from mcpacker.model.modpack import ModPack from pytest import fixture from typing import Callable -import mcpacker.model.core.ecology.flora as F -import mcpacker.model.core.ecology.geology as G -import mcpacker.model.core.ecology.heat as E +import mcpacker.model.core.ecology.flora as F +import mcpacker.model.core.ecology.geology as G +import mcpacker.model.core.ecology.heat as E import mcpacker.model.core.ecology.humidity as U -import mcpacker.model.core.ecology.soil as S -import mcpacker.model.core.ecology.water as W - +import mcpacker.model.core.ecology.soil as S +import mcpacker.model.core.ecology.water as W import textwrap @@ -47,18 +46,30 @@ def createReport(pack:ModPack): # Tests ############################################################################################ def test_report(report): - assert str(report).strip() == textwrap.dedent(""" + assert str(report).strip() == textwrap.dedent(""" Biome: minecraft:savanna (dallas) Traits: field, sedimentary, subtropical, dry, sandy, inland - Deposits: + Geology: + Flora: + + + Fauna: + + Biome: minecraft:plains (kansascity) Traits: field, sedimentary, temperate, damp, loamy, inland - Deposits: + Geology: + + Flora: + + + Fauna: + """).strip() diff --git a/mcpacker/format/report/plantspawnreport.py b/mcpacker/format/report/plantspawnreport.py new file mode 100644 index 0000000..24c100f --- /dev/null +++ b/mcpacker/format/report/plantspawnreport.py @@ -0,0 +1,60 @@ +from mcpacker.model.core.flora.patch import Patch +from mcpacker.model.core.flora.tree import Tree +from mcpacker.format.report.composer import ReportComposer +from mcpacker.model.core.ecology.biometrait import BiomeTrait +from mcpacker.model.modpack import ModPack +from pathlib import Path + + +# Class ############################################################################################ + +class PlantSpawnReport(ReportComposer): + + def doCompose(self): + for spawn in self.pack.world.plantSpawns: + self.line(f"Plant: {spawn.name}") + self.indent() # plant + + if isinstance(spawn.plant, Patch): + patch:Patch = spawn.plant + + self.line().line("Patch Biology:") + self.indent() # botany + self.text("blocks: ").line(", ".join(str(b) for b in patch.blocks)) + self.text("immersion: ").line(patch.immersion) + self.text("radius: ").line(patch.radius) + self.text("density: ").text(patch.density).line(f" ({patch.attempts()} attempts)") + self.text("substrates: ").line(", ".join(str(s) for s in patch.substrates)) + self.outdent() # botany + + elif isinstance(spawn.plant, Tree): + tree:Tree = spawn.plant + + self.line().line("Tree Biology:") + self.indent() # botany + self.text("foliage: ").line(tree.foliage) + self.text("log: ").line(tree.log) + self.text("trunkShape: ").line(tree.trunkShape) + self.text("trunkHeightMin: ").line(tree.trunkHeightMin) + self.text("trunkHeightMax: ").line(tree.trunkHeightMax) + self.text("canopyShape: ").line(tree.canopyShape) + self.text("canopyHeight: ").line(tree.canopyHeight) + self.text("canopyRadius: ").line(tree.canopyRadius) + self.outdent() # botany + + self.line().line("Habitat:") + self.indent() # habitat + self.text("altitude: ").line(spawn.altitude) + self.text("biomeFilters: ").line(" -OR- ".join(str(f) for f in spawn.biomeFilters)) + self.text("scarcity: ").line(spawn.scarcity) + self.outdent() # habitat + + self.line().line("Biomes:") + self.indent() # biomes + biomes = self.pack.world.biomes.filter(lambda b: spawn.acceptsBiome(b)) + for biome in biomes: + self.line(biome) + self.outdent() # biomes + + self.outdent() # plant + self.line() diff --git a/mcpacker/format/report/plantspawnreport_test.py b/mcpacker/format/report/plantspawnreport_test.py new file mode 100644 index 0000000..808a4f6 --- /dev/null +++ b/mcpacker/format/report/plantspawnreport_test.py @@ -0,0 +1,7 @@ +import mcpacker.format.report.plantspawnreport + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/format/templatecomposer_test.py b/mcpacker/format/templatecomposer_test.py new file mode 100644 index 0000000..ee8f8b5 --- /dev/null +++ b/mcpacker/format/templatecomposer_test.py @@ -0,0 +1,8 @@ +import mcpacker.format.templatecomposer + + +# Tests ############################################################################################ + +def test_syntax(): + pass + diff --git a/mcpacker/model/core/altitude.py b/mcpacker/model/core/altitude.py index 861d42a..34fe8b9 100644 --- a/mcpacker/model/core/altitude.py +++ b/mcpacker/model/core/altitude.py @@ -92,5 +92,13 @@ def span(*altitudes:Altitude): if bottomAltitude == topAltitude: return bottomAltitude - result = Altitude(f"{bottomAltitude.name} to {topAltitude.name}", bottom, top) + bottomName = bottomAltitude.name + if " to " in bottomName: + (bottomName, _) = bottomName.split(" to ") + + topName = topAltitude.name + if " to " in topName: + (_, topName) = topName.split(" to ") + + result = Altitude(f"{bottomName} to {topName}", bottom, top) return result diff --git a/mcpacker/model/core/blockstate.py b/mcpacker/model/core/blockstate.py new file mode 100644 index 0000000..adf4ea2 --- /dev/null +++ b/mcpacker/model/core/blockstate.py @@ -0,0 +1,35 @@ +from mcpacker.json import JsonBlob +from mcpacker.model.core.resourceid import ResourceId +from typing import Any + + +# Class ############################################################################################ + +class BlockState: + + @staticmethod + def parse(value:"BlockState|str") -> "BlockState": + if isinstance(value, BlockState): return value + return BlockState(ResourceId.parse(value)) + + def __init__(self, gameId:ResourceId|str, properties:JsonBlob=None): + self.gameId = ResourceId.parse(gameId) + self.properties = properties + + def __eq__(self, other:Any) -> bool: + if type(self) != type(other): return False + if self.gameId != other.gameId: return False + if self.properties != other.properties: return False + return True + + def __hash__(self) -> int: + return hash((self.gameId, self.properties)) + + def __repr__(self) -> str: + return f"BlockState(gameId={self.gameId!r}, properties={self.properties!r})" + + def __str__(self) -> str: + if not self.properties: + return str(self.gameId) + + return f"{self.gameId}{self.properties}" diff --git a/mcpacker/model/core/blockstate_test.py b/mcpacker/model/core/blockstate_test.py new file mode 100644 index 0000000..25f9775 --- /dev/null +++ b/mcpacker/model/core/blockstate_test.py @@ -0,0 +1,21 @@ +from pytest import fixture +from mcpacker.model.core.blockstate import BlockState +from mcpacker.model.core.resourceid import ResourceId + + +# Fixtures ######################################################################################### + +@fixture(name="block") +def createBlockState(): + yield BlockState("oak_fence", { "waterlogged": "true" }) + + +# Tests ############################################################################################ + +def test_repr(block): + assert repr(block) == ( + "BlockState(" + + "gameId=ResourceId(isTag=False, mod='minecraft', name='oak_fence'), " + + "properties={'waterlogged': 'true'}" + + ")" + ) diff --git a/mcpacker/model/core/ecology/biomefilter.py b/mcpacker/model/core/ecology/biomefilter.py index 212fc63..b7b5e36 100644 --- a/mcpacker/model/core/ecology/biomefilter.py +++ b/mcpacker/model/core/ecology/biomefilter.py @@ -1,4 +1,5 @@ from collections.abc import Sequence +from mcpacker.model.core.resourceid import ResourceId from mcpacker.model.core.ecology.biome import Biome from mcpacker.model.core.ecology.biometrait import BiomeTrait @@ -26,8 +27,8 @@ class BiomeFilter: def __init__( self, - required:Sequence[BiomeTrait|Sequence[BiomeTrait]]|None=None, - prohibited:Sequence[BiomeTrait]|None=None, + required:Sequence[BiomeTrait|ResourceId|Sequence[BiomeTrait]]|None=None, + prohibited:Sequence[BiomeTrait|ResourceId]|None=None, ): self.required = required or [] self.prohibited = prohibited or [] @@ -45,6 +46,8 @@ class BiomeFilter: for trait in self.required: if isinstance(trait, BiomeTrait): required.append(str(trait)) + elif isinstance(trait, ResourceId): + required.append(str(trait)) else: required.append("(" + " or ".join([str(option) for option in trait]) + @@ -59,7 +62,7 @@ class BiomeFilter: else: result = "".join([ "must:[", " and ".join(required), "], ", - "not:[", " and ".join(prohibited), "]", + "not:[", " or ".join(prohibited), "]", ]) return result @@ -71,6 +74,8 @@ class BiomeFilter: if isinstance(condition, BiomeTrait): trait = condition if trait not in biomeTraits: return False + elif isinstance(condition, ResourceId): + if condition != biome.gameId: return False else: traitOptions = condition foundMatch = False @@ -82,6 +87,9 @@ class BiomeFilter: if not foundMatch: return False for prohibitedTrait in self.prohibited: - if prohibitedTrait in biomeTraits: return False + if isinstance(prohibitedTrait, ResourceId): + if prohibitedTrait == biome.gameId: return False + else: + if prohibitedTrait in biomeTraits: return False return True diff --git a/mcpacker/model/core/ecology/biomefilter_test.py b/mcpacker/model/core/ecology/biomefilter_test.py index affa22c..08a44e7 100644 --- a/mcpacker/model/core/ecology/biomefilter_test.py +++ b/mcpacker/model/core/ecology/biomefilter_test.py @@ -1,5 +1,6 @@ from mcpacker.model.core.ecology.biome import Biome from mcpacker.model.core.ecology.biomefilter import BiomeFilter +from mcpacker.model.core.resourceid import ResourceId from pytest import fixture import mcpacker.model.core.ecology.flora as F @@ -27,6 +28,14 @@ def createDesertBiome(): F.BARREN, G.SEDIMENTARY, E.TROPICAL, U.DRY, S.SANDY, W.INLAND ) +@fixture(name="inDesert") +def createDesertFilter(): + yield BiomeFilter([ResourceId.parse("minecraft:desert")]) + +@fixture(name="notInDesert") +def createNotDesertFilter(): + yield BiomeFilter([], [ResourceId.parse("minecraft:desert")]) + @fixture(name="fertile") def createFertileFilter(): yield BiomeFilter([(S.LOAMY, S.PEATY)]) @@ -59,3 +68,11 @@ def test_requireOptions(fertile, desert, forest): def test_vetoed(barrenNotSandy, desert): assert not barrenNotSandy.accepts(desert) + +def test_requiredBiome(inDesert, desert, forest): + assert inDesert.accepts(desert) + assert not inDesert.accepts(forest) + +def test_prohibitedBiome(notInDesert, desert, forest): + assert not notInDesert.accepts(desert) + assert notInDesert.accepts(forest) diff --git a/mcpacker/model/core/fauna/mobspawn.py b/mcpacker/model/core/fauna/mobspawn.py index d849e67..3b43264 100644 --- a/mcpacker/model/core/fauna/mobspawn.py +++ b/mcpacker/model/core/fauna/mobspawn.py @@ -1,7 +1,8 @@ -from collections.abc import Iterable -from mcpacker.model.core.habitat import Habitat +from collections.abc import Iterable +from mcpacker.model.core.ecology.biome import Biome +from mcpacker.model.core.habitat import Habitat from mcpacker.model.core.fauna.mob import Mob -from mcpacker.model.core.spawn import Spawn +from mcpacker.model.core.spawn import Spawn # Class ############################################################################################ @@ -12,9 +13,21 @@ class MobSpawn(Spawn): """ def __init__(self, mob:Mob, habitats:Iterable[Habitat]|Habitat|None=None): - super().__init__(habitats) self.mob = mob + super().__init__(habitats) + + def __str__(self) -> str: + return self.name @property def name(self) -> str: return self.mob.name + + def acceptedBy(self, biome:Biome) -> list[Habitat]: + result = [] + + for habitat in self.habitats: + if habitat.accepts(biome): + result.append(habitat) + + return result diff --git a/mcpacker/model/core/fauna/mobspawn_test.py b/mcpacker/model/core/fauna/mobspawn_test.py index 8a7f922..f5f54d8 100644 --- a/mcpacker/model/core/fauna/mobspawn_test.py +++ b/mcpacker/model/core/fauna/mobspawn_test.py @@ -27,7 +27,7 @@ def createMobSpawn(cow, fields): # Tests ############################################################################################ def test_cowsInFields(spawn): - assert str(spawn) == ( + assert repr(spawn) == ( "Spawn(" + "habitats=[" + "Habitat(" + diff --git a/mcpacker/model/core/flora/canopyshape.py b/mcpacker/model/core/flora/canopyshape.py new file mode 100644 index 0000000..32847f1 --- /dev/null +++ b/mcpacker/model/core/flora/canopyshape.py @@ -0,0 +1,44 @@ +from typing import Any + + +# Class ############################################################################################ + +class CanopyShape: + + def __init__(self, name:str): + self.name = name + + def __eq__(self, other:Any) -> bool: + if type(self) != type(other): return False + if self.name != other.name: return False + return True + + def __hash__(self) -> int: + return hash(self.name) + + def __lt__(self, other:Any) -> bool: + if type(self) != type(other): raise ValueError() + return self.name < other.name + + def __repr__(self) -> str: + return f"CanopyShape(name={repr(self.name)})" + + def __str__(self) -> str: + return self.name + + +# Constants ######################################################################################## + +ACACIA = CanopyShape("acacia") +BLOB = CanopyShape("blob") +BUSH = CanopyShape("bush") +CHERRY = CanopyShape("cherry") +DARK_OAK = CanopyShape("dark_oak") +FANCY = CanopyShape("fancy") +JUNGLE = CanopyShape("jungle") +MEGA_PINE = CanopyShape("mega_pine") +PINE = CanopyShape("pine") +RANDOM_SPREAD = CanopyShape("random_spread") +SPRUCE = CanopyShape("spruce") + +ALL = [ACACIA, BLOB, BUSH, CHERRY, DARK_OAK, FANCY, JUNGLE, MEGA_PINE, PINE, RANDOM_SPREAD, SPRUCE] diff --git a/mcpacker/model/core/flora/canopyshape_test.py b/mcpacker/model/core/flora/canopyshape_test.py new file mode 100644 index 0000000..0e84e94 --- /dev/null +++ b/mcpacker/model/core/flora/canopyshape_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.canopyshape + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/density.py b/mcpacker/model/core/flora/density.py new file mode 100644 index 0000000..6295eb0 --- /dev/null +++ b/mcpacker/model/core/flora/density.py @@ -0,0 +1,38 @@ +from typing import Any + + +# Class ############################################################################################ + +class Density: + + def __init__(self, name:str): + self.name = name + + def __eq__(self, other:Any) -> bool: + if type(self) != type(other): return False + if self.name != other.name: return False + return True + + def __hash__(self) -> int: + return hash(self.name) + + def __lt__(self, other:Any) -> bool: + if type(self) != type(other): raise ValueError() + return self.name < other.name + + def __repr__(self) -> str: + return f"Density(name={repr(self.name)})" + + def __str__(self) -> str: + return self.name + + +# Constants ######################################################################################## + +SPARSE = Density("sparse") +THIN = Density("thin") +THICK = Density("thick") +PACKED = Density("packed") +CARPET = Density("carpet") + +ALL = [SPARSE, THIN, THICK, PACKED, CARPET] diff --git a/mcpacker/model/core/flora/density_test.py b/mcpacker/model/core/flora/density_test.py new file mode 100644 index 0000000..d59e3ab --- /dev/null +++ b/mcpacker/model/core/flora/density_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.density + + +# Class ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/immersion.py b/mcpacker/model/core/flora/immersion.py new file mode 100644 index 0000000..5847d3a --- /dev/null +++ b/mcpacker/model/core/flora/immersion.py @@ -0,0 +1,37 @@ +from typing import Any + + +# Class ############################################################################################ + +class Immersion: + + def __init__(self, name:str): + self.name = name + + def __eq__(self, other:Any) -> bool: + if type(self) != type(other): return False + if self.name != other.name: return False + return True + + def __hash__(self) -> int: + return hash(self.name) + + def __lt__(self, other:Any) -> bool: + if type(self) != type(other): raise ValueError() + return self.name < other.name + + def __repr__(self) -> str: + return f"Immersion(name={repr(self.name)})" + + def __str__(self) -> str: + return self.name + + +# Constants ######################################################################################## + +DRY = Immersion("dry") +ADJACENT = Immersion("adjacent") +SUBMERGED = Immersion("submerged") + +ALL = [DRY, ADJACENT, SUBMERGED] + diff --git a/mcpacker/model/core/flora/immersion_test.py b/mcpacker/model/core/flora/immersion_test.py new file mode 100644 index 0000000..3ef3e9d --- /dev/null +++ b/mcpacker/model/core/flora/immersion_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.immersion + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/patch.py b/mcpacker/model/core/flora/patch.py new file mode 100644 index 0000000..b857587 --- /dev/null +++ b/mcpacker/model/core/flora/patch.py @@ -0,0 +1,87 @@ +from collections.abc import Iterable +from mcpacker.model.core.blockstate import BlockState +from mcpacker.model.core.flora.density import Density +from mcpacker.model.core.flora.immersion import Immersion +from mcpacker.model.core.flora.plant import Plant +from mcpacker.model.core.resourceid import ResourceId +from mcpacker.model.core.scarcity import Scarcity + +import math +import mcpacker.model.core.flora.density as DE +import mcpacker.model.core.flora.immersion as IM + + +# Class ############################################################################################ + +class Patch(Plant): + + def __init__( + self, + name:str, + blocks:Iterable[BlockState|str]|BlockState|str, + density:Density=DE.THICK, + radius:int=4, + substrates:Iterable[ResourceId]|Iterable[str]|ResourceId|str|None=None, + immersion:Immersion=IM.DRY, + ): + super().__init__(name) + + if isinstance(blocks, str) or isinstance(blocks, BlockState): + blocks = [blocks] + if not substrates: + substrates = ["#minecraft:dirt"] + if not isinstance(substrates, Iterable): + substrates = [substrates] + + self.blocks = [BlockState.parse(b) for b in blocks] + self.density = density + self.immersion = immersion + self.radius = radius + self.substrates = [ResourceId.parse(s) for s in substrates] + + def __repr__(self) -> str: + return ( + "Patch(" + f"blocks={self.blocks!r}, " + f"density={self.density!r}, " + f"immersion={self.immersion!r}, " + f"radius={self.radius!r}, " + f"substrates={self.substrates!r}" + ")" + ) + + def attempts(self, successRate:float=0.25) -> int: + """ + Estimate how many placement attempts a generator should make for this patch. + + The value models repeated random placement within a circular area until the expected + fraction of successful placements (`coverage`) for the patch's density is reached. It + accounts for both failed placements (controlled by `successRate`) and duplicate hits on + already–filled blocks. + + The relationship is derived from the expected coverage equation: + + coverage = 1 - (1 - successRate / area) ** attempts + + which rearranges to the continuous approximation: + + attempts = -(area / successRate) * ln(1 - coverage) + + where: + area = π * radius² + successRate = probability that any single attempt succeeds + coverage = target fill fraction for this patch's density + + see ChatGPT conversation for full details: http://bit.ly/4neps2i + """ + coverage = { + DE.CARPET: 0.99, + DE.PACKED: 0.8, + DE.THICK: 0.6, + DE.THIN: 0.4, + DE.SPARSE: 0.2, + }[self.density] + + return math.ceil(max(1/successRate, + -(math.pi * self.radius * self.radius / successRate) * math.log(1 - coverage) + )) diff --git a/mcpacker/model/core/flora/patch_test.py b/mcpacker/model/core/flora/patch_test.py new file mode 100644 index 0000000..4896b10 --- /dev/null +++ b/mcpacker/model/core/flora/patch_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.plant + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/plant.py b/mcpacker/model/core/flora/plant.py new file mode 100644 index 0000000..344dbd5 --- /dev/null +++ b/mcpacker/model/core/flora/plant.py @@ -0,0 +1,12 @@ +# Class ############################################################################################ + +class Plant: + + def __init__(self, name:str): + self.name = name + + def __repr__(self) -> str: + return f"Plant(name={repr(self.name)})" + + def __str__(self) -> str: + return self.name diff --git a/mcpacker/model/core/flora/plant_test.py b/mcpacker/model/core/flora/plant_test.py new file mode 100644 index 0000000..4896b10 --- /dev/null +++ b/mcpacker/model/core/flora/plant_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.plant + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/plantcatalog.py b/mcpacker/model/core/flora/plantcatalog.py new file mode 100644 index 0000000..220323b --- /dev/null +++ b/mcpacker/model/core/flora/plantcatalog.py @@ -0,0 +1,8 @@ +from mcpacker.model.catalog import Catalog +from mcpacker.model.core.flora.plant import Plant + + +# Class ############################################################################################ + +class PlantCatalog(Catalog[Plant]): + pass diff --git a/mcpacker/model/core/flora/plantcatalog_test.py b/mcpacker/model/core/flora/plantcatalog_test.py new file mode 100644 index 0000000..014f8cc --- /dev/null +++ b/mcpacker/model/core/flora/plantcatalog_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.plantcatalog + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/plantspawn.py b/mcpacker/model/core/flora/plantspawn.py new file mode 100644 index 0000000..fe0589b --- /dev/null +++ b/mcpacker/model/core/flora/plantspawn.py @@ -0,0 +1,51 @@ +from collections.abc import Iterable +from mcpacker.model.core.altitude import Altitude +from mcpacker.model.core.ecology.biome import Biome +from mcpacker.model.core.ecology.biomefilter import BiomeFilter +from mcpacker.model.core.flora.plant import Plant +from mcpacker.model.core.scarcity import Scarcity + +import mcpacker.model.core.altitude as AL +import mcpacker.model.core.scarcity as SC + + +# Class ############################################################################################ + +class PlantSpawn: + + def __init__( + self, + plant:Plant, + altitude:Altitude=AL.ANYWHERE, + biomeFilters:Iterable[BiomeFilter]|BiomeFilter|None=None, + scarcity:Scarcity=SC.SPARSE, + ): + if not biomeFilters: + biomeFilters = BiomeFilter() + if not isinstance(biomeFilters, Iterable): + biomeFilters = [biomeFilters] + + self.altitude = altitude + self.biomeFilters = list(biomeFilters) + self.plant = plant + self.scarcity = scarcity + + def __repr__(self) -> str: + return "".join([ + "PlantSpawn(", + "altitude=", repr(self.altitude), ", ", + "biomeFilters=", repr(self.biomeFilters), ", ", + "plant=", repr(self.plant), ", ", + "scarcity=", repr(self.scarcity), + ")" + ]) + + @property + def name(self) -> str: + return self.plant.name + + def acceptsBiome(self, biome:Biome) -> bool: + for biomeFilter in self.biomeFilters: + if biomeFilter.accepts(biome): return True + + return False diff --git a/mcpacker/model/core/flora/plantspawn_test.py b/mcpacker/model/core/flora/plantspawn_test.py new file mode 100644 index 0000000..13686c7 --- /dev/null +++ b/mcpacker/model/core/flora/plantspawn_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.plantspawn + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/plantspawncatalog.py b/mcpacker/model/core/flora/plantspawncatalog.py new file mode 100644 index 0000000..f95088b --- /dev/null +++ b/mcpacker/model/core/flora/plantspawncatalog.py @@ -0,0 +1,8 @@ +from mcpacker.model.catalog import Catalog +from mcpacker.model.core.flora.plantspawn import PlantSpawn + + +# Class ############################################################################################ + +class PlantSpawnCatalog(Catalog[PlantSpawn]): + pass diff --git a/mcpacker/model/core/flora/plantspawncatalog_test.py b/mcpacker/model/core/flora/plantspawncatalog_test.py new file mode 100644 index 0000000..2cc4a54 --- /dev/null +++ b/mcpacker/model/core/flora/plantspawncatalog_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.plantspawncatalog + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/tree.py b/mcpacker/model/core/flora/tree.py new file mode 100644 index 0000000..3096c7b --- /dev/null +++ b/mcpacker/model/core/flora/tree.py @@ -0,0 +1,50 @@ +from mcpacker.model.core.flora.canopyshape import CanopyShape +from mcpacker.model.core.flora.trunkshape import TrunkShape +from mcpacker.model.core.resourceid import ResourceId +from mcpacker.model.core.flora.plant import Plant + +import mcpacker.model.core.flora.canopyshape as CA +import mcpacker.model.core.flora.trunkshape as TR + + +# Class ############################################################################################ + +class Tree(Plant): + + def __init__( + self, + name:str, + foliage:ResourceId|str, + log:ResourceId|str, + trunkShape:TrunkShape=TR.STRAIGHT, + trunkHeightMin:int=3, + trunkHeightMax:int=5, + canopyShape:CanopyShape=CA.BLOB, + canopyHeight:int=3, + canopyRadius:int=2, + ): + super().__init__(name) + + self.foliage = foliage + self.log = log + self.trunkShape = trunkShape + self.trunkHeightMin = trunkHeightMin + self.trunkHeightMax = trunkHeightMax + self.canopyShape = canopyShape + self.canopyHeight = canopyHeight + self.canopyRadius = canopyRadius + + def __repr__(self) -> str: + return "".join([ + "Tree(", + "name=", repr(self.name), ", ", + "foliage=", repr(self.foliage), ", ", + "log=", repr(self.log), ", ", + "trunkShape=", repr(self.trunkShape), ", ", + "trunkHeightMin=", repr(self.trunkHeightMin), ", ", + "trunkHeightMax=", repr(self.trunkHeightMax), ", ", + "canopyShape=", repr(self.canopyShape), ", ", + "canopyHeight=", repr(self.canopyHeight), ", ", + "canopyRadius=", repr(self.canopyRadius), + ")" + ]) diff --git a/mcpacker/model/core/flora/tree_test.py b/mcpacker/model/core/flora/tree_test.py new file mode 100644 index 0000000..9894770 --- /dev/null +++ b/mcpacker/model/core/flora/tree_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.tree + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/flora/trunkshape.py b/mcpacker/model/core/flora/trunkshape.py new file mode 100644 index 0000000..b124822 --- /dev/null +++ b/mcpacker/model/core/flora/trunkshape.py @@ -0,0 +1,39 @@ +from typing import Any + + +# Class ############################################################################################ + +class TrunkShape: + + def __init__(self, name:str): + self.name = name + + def __eq__(self, other:Any) -> bool: + if type(self) != type(other): return False + if self.name != other.name: return False + return True + + def __hash__(self) -> int: + return hash(self.name) + + def __lt__(self, other:Any) -> bool: + if type(self) != type(other): raise ValueError() + return self.name < other.name + + def __repr__(self) -> str: + return f"Density(name={repr(self.name)})" + + def __str__(self) -> str: + return self.name + + +# Constants ######################################################################################## + +STRAIGHT = TrunkShape("straight") +FORKING = TrunkShape("forking") +GIANT = TrunkShape("giant") +MEGA_JUNGLE = TrunkShape("mega_jungle") +DARK_OAK = TrunkShape("dark_oak") +FANCY = TrunkShape("fancy") + +ALL = [STRAIGHT, FORKING, GIANT, MEGA_JUNGLE, DARK_OAK, FANCY] diff --git a/mcpacker/model/core/flora/trunkshape_test.py b/mcpacker/model/core/flora/trunkshape_test.py new file mode 100644 index 0000000..4c3d72b --- /dev/null +++ b/mcpacker/model/core/flora/trunkshape_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.core.flora.trunkshape + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/model/core/habitat.py b/mcpacker/model/core/habitat.py index 60b2489..a5a9a1e 100644 --- a/mcpacker/model/core/habitat.py +++ b/mcpacker/model/core/habitat.py @@ -1,16 +1,17 @@ -from collections.abc import Iterable -from mcpacker.model.core.altitude import Altitude +from collections.abc import Iterable +from mcpacker.model.core.altitude import Altitude +from mcpacker.model.core.ecology.biome import Biome from mcpacker.model.core.ecology.biomefilter import BiomeFilter -from mcpacker.model.core.fauna.group import Group -from mcpacker.model.core.fauna.location import Location -from mcpacker.model.core.scarcity import Scarcity -from mcpacker.model.core.season import Season +from mcpacker.model.core.fauna.group import Group +from mcpacker.model.core.fauna.location import Location +from mcpacker.model.core.scarcity import Scarcity +from mcpacker.model.core.season import Season -import mcpacker.model.core.altitude as A -import mcpacker.model.core.fauna.group as G +import mcpacker.model.core.altitude as A +import mcpacker.model.core.fauna.group as G import mcpacker.model.core.fauna.location as L -import mcpacker.model.core.scarcity as C -import mcpacker.model.core.season as E +import mcpacker.model.core.scarcity as C +import mcpacker.model.core.season as E # Class ############################################################################################ @@ -63,6 +64,19 @@ class Habitat: ")" ]]) + def accepts(self, biome:Biome) -> bool: + return self.biomeFilter.accepts(biome) + + def collect(self) -> "Iterable[Habitat]": + stack:list[Habitat] = [] + current:Habitat|None = self + while current: + stack.append(current) + current = current._source + + while stack: + yield stack.pop() + def derive( self, *, @@ -84,13 +98,3 @@ class Habitat: result._source = self return result - - def collect(self) -> "Iterable[Habitat]": - stack:list[Habitat] = [] - current:Habitat|None = self - while current: - stack.append(current) - current = current._source - - while stack: - yield stack.pop() diff --git a/mcpacker/model/core/spawn.py b/mcpacker/model/core/spawn.py index 56deb5a..0750337 100644 --- a/mcpacker/model/core/spawn.py +++ b/mcpacker/model/core/spawn.py @@ -11,14 +11,10 @@ class Spawn: def __init__(self, habitats:Iterable[Habitat]|Habitat|None=None): if isinstance(habitats, Habitat): - habitats = habitats.collect() - - self.habitats = habitats or [] + habitats = list(habitats.collect()) + self.habitats = list(habitats or []) def __repr__(self) -> str: - return ( - "Spawn(" + - f"habitats=[{', '.join([repr(h) for h in self.habitats])}]" + - ")" - ) + return f"Spawn(habitats={self.habitats!r})" + diff --git a/mcpacker/model/core/world.py b/mcpacker/model/core/world.py index fd61129..7b2f889 100644 --- a/mcpacker/model/core/world.py +++ b/mcpacker/model/core/world.py @@ -1,10 +1,12 @@ -from mcpacker.model.core.ecology.biomecatalog import BiomeCatalog -from mcpacker.model.core.fauna.mobcatalog import MobCatalog -from mcpacker.model.core.fauna.mobspawncatalog import MobSpawnCatalog +from mcpacker.model.core.ecology.biomecatalog import BiomeCatalog +from mcpacker.model.core.fauna.mobcatalog import MobCatalog +from mcpacker.model.core.fauna.mobspawncatalog import MobSpawnCatalog +from mcpacker.model.core.flora.plantcatalog import PlantCatalog +from mcpacker.model.core.flora.plantspawncatalog import PlantSpawnCatalog from mcpacker.model.core.geology.depositcatalog import DepositCatalog from mcpacker.model.core.geology.mineralcatalog import MineralCatalog -from mcpacker.model.core.material.blockcatalog import BlockCatalog -from mcpacker.model.core.material.itemcatalog import ItemCatalog +from mcpacker.model.core.material.blockcatalog import BlockCatalog +from mcpacker.model.core.material.itemcatalog import ItemCatalog # Class ############################################################################################ @@ -19,12 +21,31 @@ class World: items:ItemCatalog|None=None, minerals:MineralCatalog|None=None, mobs:MobCatalog|None=None, - mobSpawns:MobSpawnCatalog|None=None + mobSpawns:MobSpawnCatalog|None=None, + plants:PlantCatalog|None=None, + plantSpawns:PlantSpawnCatalog|None=None, ): - self.biomes = biomes or BiomeCatalog() - self.blocks = blocks or BlockCatalog() - self.deposits = deposits or DepositCatalog() - self.items = items or ItemCatalog() - self.minerals = minerals or MineralCatalog() - self.mobs = mobs or MobCatalog() + self.biomes = biomes or BiomeCatalog() + self.blocks = blocks or BlockCatalog() + self.deposits = deposits or DepositCatalog() + self.items = items or ItemCatalog() + self.minerals = minerals or MineralCatalog() + self.mobs = mobs or MobCatalog() self.mobSpawns = mobSpawns or MobSpawnCatalog() + self.plants = plants or PlantCatalog() + self.plantSpawns = plantSpawns or PlantSpawnCatalog() + + def __repr__(self) -> str: + return "".join([ + "World(", + "biomes=", repr(self.biomes), ", ", + "blocks=", repr(self.blocks), ", ", + "deposits=", repr(self.deposits), ", ", + "items=", repr(self.items), ", ", + "minerals=", repr(self.minerals), ", ", + "mobs=", repr(self.mobs), ", ", + "mobSpawns=", repr(self.mobSpawns), ", ", + "plants=", repr(self.plants), ", ", + "plantSpawns=", repr(self.plantSpawns), + ")" + ]) diff --git a/mcpacker/model/resourcepack/model_test.py b/mcpacker/model/resourcepack/model_test.py new file mode 100644 index 0000000..512694d --- /dev/null +++ b/mcpacker/model/resourcepack/model_test.py @@ -0,0 +1,7 @@ +import mcpacker.model.resourcepack.model + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/pack/mysteriousisland/addbiomes.py b/mcpacker/pack/mysteriousisland/addbiomes.py index ab64965..0ab8b67 100644 --- a/mcpacker/pack/mysteriousisland/addbiomes.py +++ b/mcpacker/pack/mysteriousisland/addbiomes.py @@ -111,7 +111,7 @@ def addBiomes(pack:ModPack): )) biomes.add(Biome("kola", "minecraft:snowy_taiga", - FL.BARREN, GE.METAMORPHIC, HE.FROZEN, HU.DAMP, SO.ACIDIC, WA.INLAND + FL.FOREST, GE.METAMORPHIC, HE.FROZEN, HU.DAMP, SO.ACIDIC, WA.INLAND )) biomes.add(Biome("kyoto", "minecraft:cherry_grove", @@ -123,7 +123,7 @@ def addBiomes(pack:ModPack): )) biomes.add(Biome("memphis", "minecraft:river", - FL.CLEARING, GE.SEDIMENTARY, HE.TEMPERATE, HU.WET, SO.SANDY, WA.RIVER + FL.BARREN, GE.SEDIMENTARY, HE.TEMPERATE, HU.WET, SO.SANDY, WA.RIVER )) biomes.add(Biome("minsk", "minecraft:old_growth_birch_forest", diff --git a/mcpacker/pack/mysteriousisland/adddeposits.py b/mcpacker/pack/mysteriousisland/adddeposits.py index 7bdd028..af930c7 100644 --- a/mcpacker/pack/mysteriousisland/adddeposits.py +++ b/mcpacker/pack/mysteriousisland/adddeposits.py @@ -35,7 +35,7 @@ def addDeposits(pack:ModPack): deposits.add(GeodeDeposit( name = "geode_kimberlite", altitude = AL.span(AL.MANTLE, AL.CRUST), - biomeFilters = BF([GE.IGNEOUS]), + biomeFilters = BF([GE.IGNEOUS, SO.ROCKY, WA.INLAND]), scarcity = SC.SPARSE, )) @@ -126,10 +126,7 @@ def addDeposits(pack:ModPack): deposits.add(MineralDeposit( name = "sedimentary_iron", altitude = AL.span(AL.OVERBURDEN, AL.SOIL), - biomeFilters = BF([ - FL.within(FL.CANOPY, FL.CLEARING), - (HE.TEMPERATE, HE.BOREAL) - ]), + biomeFilters = BF([SO.PEATY]), bulk = BU.LARGE, inclusions = [I(minerals["iron"], 100)], proportion = PR.LODE, @@ -139,7 +136,7 @@ def addDeposits(pack:ModPack): deposits.add(MineralDeposit( name = "serpentine_nickel", altitude = AL.span(AL.UPLANDS, AL.HILLS), - biomeFilters = BF([GE.METAMORPHIC, (HU.DAMP, HU.WET), (SO.ACIDIC, SO.ROCKY)]), + biomeFilters = BF([GE.METAMORPHIC, HU.DAMP, SO.ACIDIC]), bulk = BU.SMALL, inclusions = [I(minerals["nickel"], 70), I(minerals["iron"], 30)], proportion = PR.LENS, @@ -171,7 +168,7 @@ def addDeposits(pack:ModPack): deposits.add(MineralDeposit( name = "fumarole_sulfur", altitude = AL.CRUST, - biomeFilters = BF([GE.IGNEOUS]), + biomeFilters = BF([GE.IGNEOUS, SO.ROCKY, WA.INLAND]), bulk = BU.MEDIUM, inclusions = [I(minerals["sulfur"], 100)], proportion = PR.VENT, @@ -230,7 +227,6 @@ def addDeposits(pack:ModPack): name = "seam_bituminouscoal", altitude = AL.span(AL.CRUST, AL.OVERBURDEN), biomeFilters = [ - BF([FL.FOREST, GE.SEDIMENTARY, HE.TEMPERATE]), BF([HE.BOREAL, GE.METAMORPHIC, (SO.ACIDIC, SO.ROCKY)]), ], bulk = BU.HUGE, diff --git a/mcpacker/pack/mysteriousisland/addmobspawns.py b/mcpacker/pack/mysteriousisland/addmobspawns.py index 7ba2f71..249b4fd 100644 --- a/mcpacker/pack/mysteriousisland/addmobspawns.py +++ b/mcpacker/pack/mysteriousisland/addmobspawns.py @@ -1,22 +1,23 @@ from mcpacker.model.core.ecology.biomefilter import BiomeFilter as BF -from mcpacker.model.core.fauna.mob import Mob -from mcpacker.model.core.fauna.mobcatalog import MobCatalog -from mcpacker.model.core.fauna.mobspawn import MobSpawn -from mcpacker.model.core.habitat import Habitat -from mcpacker.model.modpack import ModPack +from mcpacker.model.core.fauna.mob import Mob +from mcpacker.model.core.fauna.mobcatalog import MobCatalog +from mcpacker.model.core.fauna.mobspawn import MobSpawn +from mcpacker.model.core.habitat import Habitat +from mcpacker.model.core.resourceid import ResourceId +from mcpacker.model.modpack import ModPack -import mcpacker.model.core.altitude as AL -import mcpacker.model.core.ecology.flora as FL -import mcpacker.model.core.ecology.geology as GE -import mcpacker.model.core.ecology.heat as HE +import mcpacker.model.core.altitude as AL +import mcpacker.model.core.ecology.flora as FL +import mcpacker.model.core.ecology.geology as GE +import mcpacker.model.core.ecology.heat as HE import mcpacker.model.core.ecology.humidity as HU -import mcpacker.model.core.ecology.soil as SO -import mcpacker.model.core.ecology.water as WA -import mcpacker.model.core.fauna.active as AC -import mcpacker.model.core.fauna.group as GR -import mcpacker.model.core.fauna.location as LO -import mcpacker.model.core.scarcity as SC -import mcpacker.model.core.season as SE +import mcpacker.model.core.ecology.soil as SO +import mcpacker.model.core.ecology.water as WA +import mcpacker.model.core.fauna.active as AC +import mcpacker.model.core.fauna.group as GR +import mcpacker.model.core.fauna.location as LO +import mcpacker.model.core.scarcity as SC +import mcpacker.model.core.season as SE # Constants ######################################################################################## @@ -26,11 +27,30 @@ def addMobSpawns(pack:ModPack): spawns = pack.world.mobSpawns spawns.add( - MobSpawn(mobs["animalplus:raccoon"]) + MobSpawn(mobs["animalplus:raccoon"], + Habitat( + altitude = AL.span(AL.LOWLANDS, AL.HILLS), + biomeFilter = BF([(FL.CANOPY, FL.FOREST), HE.within(HE.TEMPERATE, HE.BOREAL)]), + seasons = SE.exclude(SE.WINTER), + group = GR.merge(GR.SOLO, GR.PAIR), + scarcity = SC.UNCOMMON, + ).derive( + seasons = SE.WINTER, + scarcity = SC.SPARSE, + ) + ) ) spawns.add( - MobSpawn(mobs["animalplus:red_panda"]) + MobSpawn(mobs["animalplus:red_panda"], + Habitat( + altitude = AL.span(AL.UPLANDS, AL.HILLS), + biomeFilter = BF([ResourceId.parse("bamboo_forest")]), + seasons = SE.ALL, + group = GR.merge(GR.SOLO, GR.PAIR), + scarcity = SC.SPARSE, + ) + ) ) spawns.add( @@ -60,17 +80,21 @@ def addMobSpawns(pack:ModPack): spawns.add( MobSpawn(mobs["minecraft:armadillo"], Habitat( - altitude = AL.LOWLANDS, - biomeFilter = BF([HE.SUBTROPICAL, HU.DRY]), - seasons = SE.SUMMER, - group = GR.merge(GR.SOLO, GR.PAIR), - scarcity = SC.COMMON + altitude = AL.LOWLANDS, + biomeFilter = BF([HE.SUBTROPICAL, HU.DRY, SO.CLAYEY]), + seasons = SE.SUMMER, + group = GR.merge(GR.SOLO, GR.PAIR), + scarcity = SC.COMMON ).derive( - altitude = AL.UPLANDS, scarcity = SC.SPARSE, + altitude = AL.UPLANDS, + scarcity = SC.SPARSE, ).derive( - altitude = AL.LOWLANDS, seasons = SE.exclude(SE.SUMMER), scarcity = SC.UNCOMMON, + altitude = AL.LOWLANDS, + scarcity = SC.UNCOMMON, + seasons = SE.exclude(SE.SUMMER), ).derive( - altitude = AL.UPLANDS, scarcity = SC.UNUSUAL, + altitude = AL.UPLANDS, + scarcity = SC.UNUSUAL, ) ) ) @@ -79,25 +103,21 @@ def addMobSpawns(pack:ModPack): MobSpawn(mobs["minecraft:blaze"], Habitat( altitude = AL.PLUTONIC, - location = LO.CAVE, - group = GR.SOLO, - scarcity = SC.UNCOMMON + location = LO.CAVE, + group = GR.SOLO, + scarcity = SC.UNCOMMON ) ) ) - spawns.add( - MobSpawn(mobs["minecraft:bogged"]) - ) - spawns.add( MobSpawn(mobs["bearminimum:brown_bear"], Habitat( - altitude = 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, - scarcity = SC.SPARSE + seasons = SE.AUTUMN, + group = GR.SOLO, + scarcity = SC.SPARSE ).derive( seasons = [SE.SPRING, SE.SUMMER], scarcity = SC.UNUSUAL ).derive( @@ -124,9 +144,9 @@ def addMobSpawns(pack:ModPack): MobSpawn(mobs["minecraft:cave_spider"], Habitat( altitude = AL.span(AL.OVERBURDEN, AL.HILLS), - location = LO.CAVE, - group = GR.SOLO, - scarcity = SC.UNCOMMON + location = LO.CAVE, + group = GR.SOLO, + scarcity = SC.UNCOMMON ) ) ) @@ -134,21 +154,14 @@ def addMobSpawns(pack:ModPack): spawns.add( MobSpawn(mobs["cold_sweat:chameleon"], Habitat( - 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), - scarcity = SC.COMMON, + altitude = AL.span(AL.DUNES, AL.UPLANDS), + biomeFilter = BF([(FL.CANOPY, FL.FOREST), HE.TROPICAL, HU.WET, WA.INLAND]), + seasons = SE.WET, + group = GR.merge(GR.SOLO, GR.FAMILY), + scarcity = SC.COMMON, ).derive( - seasons = SE.DRY, - scarcity = SC.UNCOMMON, - ).derive( - biomeFilter = BF([HE.TROPICAL, HU.WET, FL.CLEARING]), - seasons = SE.WET, - scarcity = SC.UNCOMMON - ).derive( - seasons = SE.DRY, - scarcity = SC.SPARSE, + seasons = SE.DRY, + scarcity = SC.UNCOMMON, ) ) ) @@ -156,14 +169,14 @@ def addMobSpawns(pack:ModPack): spawns.add( MobSpawn(mobs["minecraft:chicken"], Habitat( - 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, - scarcity = SC.COMMON, + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilter = BF([FL.CLEARING, HE.TROPICAL, HU.WET], [SO.FUNGAL]), + seasons = SE.SUMMER, + group = GR.TROUP, + scarcity = SC.COMMON, ).derive( - seasons = SE.exclude(SE.SUMMER), - scarcity = SC.UNCOMMON + seasons = SE.exclude(SE.SUMMER), + scarcity = SC.UNCOMMON ) ) ) @@ -171,14 +184,11 @@ def addMobSpawns(pack:ModPack): spawns.add( MobSpawn(mobs["minecraft:cod"], Habitat( - altitude = AL.span(AL.SHALLOWS, AL.DEEPS), - biomeFilter = BF([WA.OCEAN, [HE.TEMPERATE, HE.BOREAL]]), - seasons = SE.ALL, - group = GR.HERD, - scarcity = SC.COMMON, - ).derive( - biomeFilter = BF([WA.OCEAN, HE.FROZEN]), - scarcity = SC.SPARSE, + altitude = AL.span(AL.SHALLOWS, AL.DEEPS), + biomeFilter = BF([HE.BOREAL, WA.OCEAN]), + seasons = SE.ALL, + group = GR.HERD, + scarcity = SC.COMMON, ) ) ) @@ -198,12 +208,12 @@ def addMobSpawns(pack:ModPack): ), seasons = [SE.SPRING, SE.SUMMER], group = GR.HERD, - scarcity = SC.COMMON, + scarcity = SC.SPARSE, ).derive( altitude = AL.LOWLANDS, seasons = [SE.AUTUMN, SE.WINTER], group = GR.TROUP, - scarcity = SC.SPARSE, + scarcity = SC.UNUSUAL, ) ) ) @@ -215,10 +225,10 @@ def addMobSpawns(pack:ModPack): biomeFilter = BF([WA.COAST, [HE.TROPICAL, HE.SUBTROPICAL]]), seasons = SE.ALL, group = GR.SOLO, - scarcity = SC.COMMON, + scarcity = SC.UNCOMMON, ).derive( biomeFilter = BF([WA.COAST, [HE.TEMPERATE, HE.BOREAL]]), - scarcity = SC.UNCOMMON, + scarcity = SC.SPARSE, ) ) ) @@ -245,8 +255,9 @@ def addMobSpawns(pack:ModPack): biomeFilter = BF([HE.SUBTROPICAL, HU.DRY, FL.FIELD]), seasons = [SE.SUMMER, SE.AUTUMN], group = GR.FAMILY, - scarcity = SC.UNCOMMON, + scarcity = SC.SPARSE, ).derive( + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), seasons = [SE.WINTER, SE.SPRING], scarcity = SC.SPARSE, ) @@ -267,145 +278,353 @@ def addMobSpawns(pack:ModPack): )) spawns.add( - MobSpawn(mobs["minecraft:frog"]) + MobSpawn(mobs["minecraft:frog"], + Habitat( + altitude = AL.span(AL.SURFACE, AL.DUNES), + biomeFilter = BF([(HE.TROPICAL, HE.TEMPERATE), HU.WET, WA.SWAMP]), + group = GR.HERD, + scarcity = SC.COMMON, + seasons = [SE.SUMMER], + ).derive( + seasons = [SE.SPRING], + scarcity = SC.SPARSE, + ).derive( + seasons = [SE.AUTUMN], + scarcity = SC.UNUSUAL, + ).derive( + seasons = [SE.WINTER], + scarcity = SC.ABSENT, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:glow_squid"]) + MobSpawn(mobs["minecraft:glow_squid"], + Habitat( + altitude = AL.ABYSS, + biomeFilter = BF([WA.OCEAN], [HE.FROZEN]), + group = GR.SOLO, + location = LO.WATER, + scarcity = SC.RARE, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:goat"]) + MobSpawn(mobs["minecraft:goat"], + Habitat( + altitude = AL.span(AL.HILLS, AL.CRAGS), + biomeFilter = BF([(HE.BOREAL, HE.FROZEN), SO.ROCKY]), + group = GR.FAMILY, + scarcity = SC.UNCOMMON, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:horse"]) + MobSpawn(mobs["minecraft:horse"], + Habitat( + altitude = AL.span(AL.DUNES, AL.LOWLANDS), + biomeFilter = BF( + [FL.FIELD, (HE.SUBTROPICAL, HE.TEMPERATE), (SO.LOAMY, SO.PEATY, SO.SANDY)] + ), + group = GR.HERD, + scarcity = SC.UNUSUAL, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:husk"]) + MobSpawn(mobs["minecraft:llama"], + Habitat( + altitude = AL.span(AL.ALPINE, AL.PEAKS), + biomeFilter = BF([(HE.BOREAL, HE.FROZEN), SO.ROCKY]), + group = GR.HERD, + scarcity = SC.UNCOMMON, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:llama"]) + MobSpawn(mobs["minecraft:magma_cube"], + Habitat( + altitude = AL.PLUTONIC, + location = LO.CAVE, + group = GR.SOLO, + scarcity = SC.UNCOMMON + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:magma_cube"]) + MobSpawn(mobs["minecraft:mooshroom"], + Habitat( + altitude = AL.span(AL.DUNES, AL.UPLANDS), + biomeFilter = BF([SO.FUNGAL]), + group = GR.HERD, + scarcity = SC.UNCOMMON, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:mooshroom"]) + MobSpawn(mobs["minecraft:ocelot"], + Habitat( + altitude = AL.span(AL.LOWLANDS, AL.HILLS), + biomeFilter = BF([FL.CANOPY, HE.TROPICAL, HU.WET]), + group = GR.SOLO, + scarcity = SC.RARE, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:mule"]) + MobSpawn(mobs["minecraft:panda"], + Habitat( + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilter = BF([ResourceId.parse("bamboo_forest")]), + group = GR.SOLO, + scarcity = SC.UNUSUAL, + seasons = SE.exclude(SE.SPRING), + ).derive( + group = GR.PAIR, + seasons = SE.SPRING, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:ocelot"]) + MobSpawn(mobs["minecraft:parrot"], + Habitat( + altitude = AL.span(AL.DUNES, AL.HILLS), + biomeFilter = BF([(FL.CANOPY, FL.FOREST), HE.TROPICAL, HU.WET]), + group = GR.PAIR, + scarcity = SC.COMMON, + seasons = SE.ALL, + ).derive( + biomeFilter = BF([FL.CLEARING, HE.TROPICAL, HU.WET], [SO.FUNGAL]), + scarcity = SC.UNCOMMON, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:panda"]) + MobSpawn(mobs["minecraft:pig"], + Habitat( + altitude = AL.span(AL.LOWLANDS, AL.HILLS), + biomeFilter = BF([ + FL.within(FL.CANOPY, FL.CLEARING), + HE.within(HE.SUBTROPICAL, HE.TEMPERATE) + ]), + group = GR.TROUP, + scarcity = SC.COMMON, + seasons = [SE.SUMMER], + ).derive( + scarcity = SC.UNCOMMON, + seasons = SE.exclude(SE.SUMMER), + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:parrot"]) + MobSpawn(mobs["minecraft:polar_bear"], + Habitat( + altitude = AL.DUNES, + biomeFilter = BF([HE.FROZEN, (WA.COAST, WA.OCEAN)]), + group = GR.PAIR, + scarcity = SC.UNUSUAL, + seasons = [SE.SPRING, SE.WINTER] + ).derive( + group = GR.SOLO, + seasons = [SE.SUMMER, SE.AUTUMN], + scarcity = SC.RARE, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:pig"]) + MobSpawn(mobs["minecraft:pufferfish"], + Habitat( + altitude = AL.SHALLOWS, + biomeFilter = BF([(HE.TEMPERATE, HE.TROPICAL), WA.OCEAN]), + group = GR.TROUP, + location = LO.WATER, + scarcity = SC.UNCOMMON, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:polar_bear"]) + MobSpawn(mobs["minecraft:rabbit"], + Habitat( + altitude = AL.span(AL.DUNES, AL.ALPINE), + biomeFilter = BF([ + FL.within(FL.CANOPY, FL.FIELD), + HE.within(HE.SUBTROPICAL, HE.BOREAL), + WA.INLAND, + ]), + group = GR.FAMILY, + scarcity = SC.COMMON, + seasons = [SE.SPRING], + ).derive( + scarcity = SC.SPARSE, + seasons = [SE.SUMMER, SE.AUTUMN], + ).derive( + scarcity = SC.SPARSE, + seasons = [SE.WINTER], + ).derive( + altitude = AL.span(AL.DUNES, AL.LOWLANDS), + biomeFilter = BF([FL.BARREN, HE.TROPICAL, HU.DRY]), + group = GR.PAIR, + scarcity = SC.SPARSE, + seasons = SE.exclude(SE.SUMMER), + ).derive( + scarcity = SC.UNUSUAL, + seasons = [SE.SUMMER], + ).derive( + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilter = BF([FL.within(FL.FOREST, FL.FIELD), HE.FROZEN]), + scarcity = SC.SPARSE, + seasons = SE.exclude(SE.WINTER), + ).derive( + scarcity = SC.UNUSUAL, + seasons = [SE.WINTER], + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:pufferfish"]) + MobSpawn(mobs["minecraft:salmon"], + Habitat( + altitude = AL.span(AL.SURFACE, AL.SHALLOWS), + biomeFilter = BF([WA.RIVER], [HE.FROZEN]), + group = GR.HERD, + scarcity = SC.COMMON, + seasons = [SE.AUTUMN], + ).derive( + scarcity = SC.UNCOMMON, + seasons = [SE.SPRING], + ).derive( + seasons = [SE.SUMMER, SE.WINTER], + scarcity = SC.ABSENT, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:rabbit"]) + MobSpawn(mobs["minecraft:sheep"], + Habitat( + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilter = BF([FL.within(FL.FOREST, FL.FIELD), HE.BOREAL]), + group = GR.HERD, + scarcity = SC.UNCOMMON, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:salmon"]) + MobSpawn(mobs["minecraft:slime"], + Habitat( + altitude = AL.span(AL.SURFACE, AL.DUNES), + biomeFilter = BF([HE.TEMPERATE, WA.SWAMP]), + group = GR.SOLO, + scarcity = SC.UNCOMMON, + seasons = [SE.SPRING], + ).derive( + scarcity = SC.UNUSUAL, + seasons = SE.exclude(SE.SPRING), + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:sheep"]) + MobSpawn(mobs["minecraft:spider"], + Habitat( + altitude = AL.span(AL.LOWLANDS, AL.HILLS), + biomeFilter = BF([FL.CANOPY, HE.TEMPERATE]), + group = GR.SOLO, + scarcity = SC.COMMON, + seasons = [SE.SUMMER], + ).derive( + scarcity = SC.UNCOMMON, + seasons = [SE.SPRING, SE.AUTUMN], + ).derive( + scarcity = SC.SPARSE, + seasons = [SE.WINTER], + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:skeleton"]) + MobSpawn(mobs["minecraft:squid"], + Habitat( + altitude = AL.DEEPS, + biomeFilter = BF([WA.OCEAN], [HE.FROZEN]), + group = GR.SOLO, + location = LO.WATER, + scarcity = SC.SPARSE, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:slime"]) + MobSpawn(mobs["minecraft:tropical_fish"], + Habitat( + altitude = AL.SHALLOWS, + biomeFilter = BF([HE.TROPICAL, WA.OCEAN]), + group = GR.HERD, + location = LO.WATER, + scarcity = SC.COMMON, + seasons = SE.ALL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:spider"]) + MobSpawn(mobs["minecraft:turtle"], + Habitat( + altitude = AL.span(AL.SURFACE, AL.SHALLOWS), + biomeFilter = BF([HE.within(HE.TROPICAL, HE.SUBTROPICAL), WA.OCEAN]), + group = GR.SOLO, + scarcity = SC.SPARSE, + seasons = SE.ALL, + ).derive( + altitude = AL.DUNES, + biomeFilter = BF([HE.within(HE.TROPICAL, HE.SUBTROPICAL), WA.COAST]), + group = GR.SOLO, + scarcity = SC.UNUSUAL, + ) + ) ) spawns.add( - MobSpawn(mobs["minecraft:squid"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:tropical_fish"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:turtle"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:vex"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:villager"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:vindicator"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:wandering_trader"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:warden"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:witch"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:wither_skeleton"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:wither"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:wolf"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:zoglin"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:zombie_villager"]) - ) - - spawns.add( - MobSpawn(mobs["minecraft:zombie"]) + MobSpawn(mobs["minecraft:wolf"], + Habitat( + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilter = BF([FL.CANOPY, HE.TEMPERATE, WA.INLAND]), + group = GR.TROUP, + scarcity = SC.COMMON, + seasons = SE.ALL, + ).derive( + biomeFilter = BF([ + FL.within(FL.FOREST, FL.FIELD), (HE.TEMPERATE, HE.BOREAL), WA.INLAND, + ]), + scarcity = SC.UNCOMMON, + ).derive( + biomeFilter = BF([FL.within(FL.FOREST, FL.FIELD), HE.FROZEN, WA.INLAND]), + scarcity = SC.UNUSUAL, + ).derive( + biomeFilter = BF([(FL.CLEARING, FL.FIELD), HE.SUBTROPICAL, WA.INLAND]), + scarcity = SC.SPARSE, + ) + ) ) diff --git a/mcpacker/pack/mysteriousisland/addplants.py b/mcpacker/pack/mysteriousisland/addplants.py new file mode 100644 index 0000000..b882607 --- /dev/null +++ b/mcpacker/pack/mysteriousisland/addplants.py @@ -0,0 +1,484 @@ +from mcpacker.model.core.blockstate import BlockState +from mcpacker.model.core.flora.patch import Patch +from mcpacker.model.core.flora.tree import Tree +from mcpacker.model.modpack import ModPack + +import mcpacker.model.core.flora.canopyshape as CA +import mcpacker.model.core.flora.density as DE +import mcpacker.model.core.flora.immersion as IM +import mcpacker.model.core.flora.trunkshape as TR + + +# Constants ######################################################################################## + +CD = "corndelight" +FD = "farmersdelight" +IE = "immersiveengineering" +IH = "immersivehealing" +MC = "minecraft" +RD = "rusticdelight" +RW = "realisticwheat" +UD = "fruitsdelight" +SU = "supplementaries" + + +# Functions ######################################################################################## + +def addPlants(pack:ModPack): + plants = pack.world.plants + + # Crop Patches ############################################################# + + plants.add(Patch( + name = "athelas", + blocks = f"{IH}:medica_herb_block", + density = DE.THIN, + radius = 3, + )) + + plants.add(Patch( + name = "beetroot", + blocks = f"{FD}:wild_beetroots", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "bellpepper", + blocks = f"{RD}:wild_bell_peppers", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "blueberry", + blocks = BlockState(f"{UD}:blueberry_bush", {"age": 4}), + density = DE.THICK, + radius = 5, + )) + + plants.add(Patch( + name = "brownmushroom", + blocks = BlockState(f"{FD}:brown_mushroom_colony", {"age": 3}), + density = DE.PACKED, + radius = 3, + )) + + plants.add(Patch( + name = "cabbage", + blocks = f"{FD}:wild_cabbages", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "carrot", + blocks = f"{FD}:wild_carrots", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "coffee", + blocks = f"{RD}:wild_coffee", + density = DE.THIN, + radius = 5, + )) + + plants.add(Patch( + name = "corn", + blocks = f"{CD}:wild_corn", + density = DE.THICK, + radius = 5, + )) + + plants.add(Patch( + name = "cotton", + blocks = f"{CD}:wild_cotton", + density = DE.THICK, + radius = 6, + )) + + plants.add(Patch( + name = "currant", + blocks = BlockState(f"{MC}:sweet_berry_bush", {"age": 3}), + density = DE.THICK, + radius = 5, + )) + + plants.add(Patch( + name = "cranberry", + blocks = f"{UD}:cranberry_bush", + density = DE.CARPET, + immersion = IM.ADJACENT, + radius = 4, + )) + + plants.add(Patch( + name = "flax", + blocks = f"{SU}:wild_flax", + density = DE.THICK, + radius = 5, + )) + + plants.add(Patch( + name = "hamimelon", + blocks = f"{UD}:hamimelon", + density = DE.PACKED, + radius = 5, + )) + + plants.add(Patch( + name = "hemp", + blocks = BlockState(f"{IE}:hemp", {"half": "lower"}), + density = DE.THICK, + radius = 6, + )) + + plants.add(Patch( + name = "lemon", + blocks = BlockState(f"{UD}:lemon_tree", {"age": 4}), + density = DE.SPARSE, + radius = 3, + )) + + plants.add(Patch( + name = "melon", + blocks = f"{MC}:melon", + density = DE.PACKED, + radius = 5, + )) + + plants.add(Patch( + name = "onion", + blocks = f"{FD}:wild_onions", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "pineapple", + blocks = BlockState(f"{UD}:pineapple", {"age": 4}), + density = DE.SPARSE, + radius = 4, + )) + + plants.add(Patch( + name = "potato", + blocks = f"{FD}:wild_potatoes", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "pumpkin", + blocks = f"{MC}:pumpkin", + density = DE.PACKED, + radius = 5, + )) + + plants.add(Patch( + name = "redmushroom", + blocks = BlockState(f"{FD}:red_mushroom_colony", {"age": 3}), + density = DE.PACKED, + radius = 3, + )) + + plants.add(Patch( + name = "rice", + blocks = f"{FD}:wild_rice", + density = DE.THICK, + immersion = IM.SUBMERGED, + radius = 7, + )) + + plants.add(Patch( + name = "sugarcane", + blocks = f"{MC}:sugar_cane", + immersion = IM.ADJACENT, + density = DE.THICK, + radius = 5, + )) + + plants.add(Patch( + name = "sunflower", + blocks = BlockState(f"{MC}:sunflower", {"half": "lower"}), + density = DE.THIN, + radius = 5, + )) + + plants.add(Patch( + name = "tomato", + blocks = f"{FD}:wild_tomatoes", + density = DE.THIN, + radius = 5, + )) + + plants.add(Patch( + name = "wheat", + blocks = f"{RW}:wild_wheat", + density = DE.THIN, + radius = 6, + )) + + + # Flower Patches ########################################################### + + plants.add(Patch( + name = "allium", + blocks = f"{MC}:allium", + density = DE.SPARSE, + radius = 3, + )) + + plants.add(Patch( + name = "azurebluet", + blocks = f"{MC}:azure_bluet", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "blueorchid", + blocks = f"{MC}:blue_orchid", + density = DE.SPARSE, + radius = 3, + )) + + plants.add(Patch( + name = "cornflower", + blocks = f"{MC}:cornflower", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "daisy", + blocks = f"{MC}:oxeye_daisy", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "dandelion", + blocks = f"{MC}:dandelion", + density = DE.CARPET, + radius = 5, + )) + + plants.add(Patch( + name = "lilac", + blocks = f"{MC}:lilac", + density = DE.SPARSE, + radius = 3, + )) + + plants.add(Patch( + name = "lily", + blocks = f"{MC}:lily_of_the_valley", + density = DE.THICK, + radius = 3, + )) + + plants.add(Patch( + name = "peony", + blocks = f"{MC}:peony", + density = DE.SPARSE, + radius = 3, + )) + + plants.add(Patch( + name = "poppy", + blocks = f"{MC}:poppy", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "rose_black", + blocks = f"{MC}:wither_rose", + density = DE.SPARSE, + radius = 2, + )) + + plants.add(Patch( + name = "rose_bush", + blocks = BlockState(f"{MC}:rose_bush", {"half": "lower"}), + density = DE.SPARSE, + radius = 3, + )) + + plants.add(Patch( + name = "tulip_orange", + blocks = f"{MC}:orange_tulip", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "tulip_pink", + blocks = f"{MC}:pink_tulip", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "tulip_red", + blocks = f"{MC}:red_tulip", + density = DE.THIN, + radius = 4, + )) + + plants.add(Patch( + name = "tulip_white", + blocks = f"{MC}:white_tulip", + density = DE.THIN, + radius = 4, + )) + + + # Trees #################################################################### + + plants.add(Tree( + name = "apple", + foliage = f"{UD}:apple_leaves", + log = f"{MC}:oak_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 3, + trunkHeightMax = 5, + canopyShape = CA.BLOB, + canopyHeight = 3, + canopyRadius = 2 + )) + + plants.add(Tree( + name = "bayberry", + foliage = f"{UD}:bayberry_leaves", + log = f"{MC}:oak_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 1, + trunkHeightMax = 1, + canopyShape = CA.BUSH, + canopyHeight = 2, + canopyRadius = 2 + )) + + plants.add(Tree( + name = "durian", + foliage = f"{UD}:durian_leaves", + log = f"{MC}:jungle_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 12, + trunkHeightMax = 25, + canopyShape = CA.FANCY, + canopyHeight = 6, + canopyRadius = 4 + )) + + plants.add(Tree( + name = "fig", + foliage = f"{UD}:fig_leaves", + log = f"{MC}:acacia_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 3, + trunkHeightMax = 5, + canopyShape = CA.BLOB, + canopyHeight = 3, + canopyRadius = 2 + )) + + plants.add(Tree( + name = "hawberry", + foliage = f"{UD}:hawberry_leaves", + log = f"{MC}:oak_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 2, + trunkHeightMax = 7, + canopyShape = CA.BLOB, + canopyHeight = 3, + canopyRadius = 2 + )) + + plants.add(Tree( + name = "lychee", + foliage = f"{UD}:lychee_leaves", + log = f"{MC}:jungle_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 3, + trunkHeightMax = 7, + canopyShape = CA.BLOB, + canopyHeight = 3, + canopyRadius = 2 + )) + + plants.add(Tree( + name = "mango", + foliage = f"{UD}:mango_leaves", + log = f"{MC}:jungle_log", + trunkShape = TR.FORKING, + trunkHeightMin = 10, + trunkHeightMax = 15, + canopyShape = CA.ACACIA, + canopyHeight = 5, + canopyRadius = 4 + )) + + plants.add(Tree( + name = "mangosteen", + foliage = f"{UD}:mangosteen_leaves", + log = f"{MC}:jungle_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 3, + trunkHeightMax = 12, + canopyShape = CA.BLOB, + canopyHeight = 3, + canopyRadius = 3 + )) + + plants.add(Tree( + name = "orange", + foliage = f"{UD}:orange_leaves", + log = f"{MC}:acacia_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 3, + trunkHeightMax = 5, + canopyShape = CA.BLOB, + canopyHeight = 2, + canopyRadius = 1 + )) + + plants.add(Tree( + name = "peach", + foliage = f"{UD}:peach_leaves", + log = f"{MC}:cherry_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 1, + trunkHeightMax = 2, + canopyShape = CA.BLOB, + canopyHeight = 2, + canopyRadius = 1 + )) + + plants.add(Tree( + name = "pear", + foliage = f"{UD}:pear_leaves", + log = f"{MC}:birch_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 6, + trunkHeightMax = 10, + canopyShape = CA.PINE, + canopyHeight = 4, + canopyRadius = 2 + )) + + plants.add(Tree( + name = "persimmon", + foliage = f"{UD}:persimmon_leaves", + log = f"{MC}:dark_oak_log", + trunkShape = TR.STRAIGHT, + trunkHeightMin = 3, + trunkHeightMax = 9, + canopyShape = CA.BLOB, + canopyHeight = 4, + canopyRadius = 2 + )) diff --git a/mcpacker/pack/mysteriousisland/addplants_test.py b/mcpacker/pack/mysteriousisland/addplants_test.py new file mode 100644 index 0000000..2dc8683 --- /dev/null +++ b/mcpacker/pack/mysteriousisland/addplants_test.py @@ -0,0 +1,7 @@ +import mcpacker.pack.mysteriousisland.addplants + + +# Class ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/pack/mysteriousisland/addplantspawns.py b/mcpacker/pack/mysteriousisland/addplantspawns.py new file mode 100644 index 0000000..92d4b81 --- /dev/null +++ b/mcpacker/pack/mysteriousisland/addplantspawns.py @@ -0,0 +1,446 @@ +from mcpacker.model.core.altitude import Altitude +from mcpacker.model.core.ecology.biomefilter import BiomeFilter as BF +from mcpacker.model.core.flora.plantspawn import PlantSpawn +from mcpacker.model.core.resourceid import ResourceId +from mcpacker.model.modpack import ModPack + +import mcpacker.model.core.altitude as AL +import mcpacker.model.core.ecology.flora as FL +import mcpacker.model.core.ecology.geology as GE +import mcpacker.model.core.ecology.heat as HE +import mcpacker.model.core.ecology.humidity as HU +import mcpacker.model.core.ecology.soil as SO +import mcpacker.model.core.ecology.water as WA +import mcpacker.model.core.scarcity as SC + + +# Functions ######################################################################################## + +def addPlantSpawns(pack:ModPack): + plants = pack.world.plants + spawns = pack.world.plantSpawns + + # Crop Patches ############################################################# + + spawns.add(PlantSpawn( + plant = plants["athelas"], + altitude = AL.span(AL.LOWLANDS, AL.HILLS), + biomeFilters = BF([FL.CANOPY, HE.TEMPERATE]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["beetroot"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.FOREST, HE.BOREAL, SO.ACIDIC]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["bellpepper"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.CLEARING, HE.TROPICAL, HU.WET, WA.INLAND]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["blueberry"], + altitude = AL.span(AL.UPLANDS, AL.ALPINE), + biomeFilters = BF([FL.within(FL.FOREST, FL.FIELD), HE.BOREAL]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["brownmushroom"], + altitude = AL.span(AL.SOIL, AL.ALPINE), + biomeFilters = [ + BF( + [(FL.CANOPY, FL.FOREST), (HE.TEMPERATE, HE.BOREAL), (SO.LOAMY, SO.CLAYEY)], + [WA.OCEAN] + ), + BF([HU.WET], [HE.FROZEN, WA.OCEAN, WA.RIVER]), + BF([SO.FUNGAL]), + ], + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["cabbage"], + altitude = AL.HILLS, + biomeFilters = BF([(HE.SUBTROPICAL, HE.TEMPERATE), SO.SANDY, WA.COAST]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["carrot"], + altitude = AL.LOWLANDS, + biomeFilters = BF( + [(FL.FOREST, FL.CLEARING), HE.TEMPERATE, SO.LOAMY], + [ResourceId.parse("flower_forest")], + ), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["coffee"], + altitude = AL.span(AL.HILLS, AL.ALPINE), + biomeFilters = BF([FL.CANOPY, HE.TROPICAL, HU.WET]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["corn"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.FIELD, HE.SUBTROPICAL, (SO.LOAMY, SO.SANDY)]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["cotton"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.FIELD, HE.SUBTROPICAL, HU.DRY, (SO.LOAMY, SO.SANDY)]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["currant"], + altitude = AL.span(AL.UPLANDS, AL.ALPINE), + biomeFilters = BF([FL.within(FL.FOREST, FL.FIELD), (HE.BOREAL, HE.FROZEN)]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["cranberry"], + altitude = AL.DUNES, + biomeFilters = BF([HU.WET, SO.PEATY]), + scarcity = SC.UNCOMMON, + )) + + # NOTE: Due to a bug in Supplementaries, flax can *only* be planted on sand, despite the actual + # plant requiring an entirely different soil. Therefore, we're imaginging *this* so-called + # "flax" as a fiberous, desert-dwelling cousin. + spawns.add(PlantSpawn( + plant = plants["flax"], + altitude = AL.DUNES, + biomeFilters = BF([FL.BARREN, HU.DRY, SO.SANDY]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["hamimelon"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.FIELD, HE.SUBTROPICAL, HU.DRY, (SO.LOAMY, SO.SANDY)]), + scarcity = SC.RARE, + )) + + spawns.add(PlantSpawn( + plant = plants["hemp"], + altitude = AL.span(AL.DUNES, AL.UPLANDS), + biomeFilters = BF( + [FL.FIELD, HE.TEMPERATE, HU.DAMP, SO.LOAMY], + [ResourceId.parse("sunflower_plains")] + ), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["lemon"], + altitude = AL.UPLANDS, + biomeFilters = BF([FL.FIELD, HE.SUBTROPICAL, HU.DRY]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["melon"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.CLEARING, HE.TROPICAL, HU.WET], [SO.FUNGAL]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["onion"], + altitude = AL.span(AL.UPLANDS, AL.HILLS), + biomeFilters = BF([FL.FOREST, HE.TEMPERATE, HU.DAMP, SO.ACIDIC]), + scarcity = SC.SPARSE, + )) + + # NOTE: Due to a bug in Fruits Delight, pineapple can *only* be planted on sand: despite this + # in now way reflecting the plant's actual ecology. As such, we have to imagine these as + # a more cactus-like cousin of actual pineapples. + spawns.add(PlantSpawn( + plant = plants["pineapple"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.BARREN, HE.TROPICAL, HU.DRY, SO.SANDY]), + scarcity = SC.SPARSE, + # TODO: add sand as substrate in addplants.py + )) + + spawns.add(PlantSpawn( + plant = plants["potato"], + altitude = AL.span(AL.UPLANDS, AL.HILLS), + biomeFilters = BF([FL.FOREST, HE.BOREAL, HU.DAMP, SO.ACIDIC]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["pumpkin"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.FIELD, HE.TEMPERATE, SO.LOAMY]), + scarcity = SC.UNUSUAL, + )) + + spawns.add(PlantSpawn( + plant = plants["redmushroom"], + altitude = AL.span(AL.SOIL, AL.ALPINE), + biomeFilters = [ + BF([(FL.CANOPY, FL.FOREST), (HE.TEMPERATE, HE.BOREAL), (SO.LOAMY, SO.CLAYEY)]), + BF([HU.WET], [HE.FROZEN, WA.OCEAN, WA.RIVER]), + BF([SO.FUNGAL]), + ], + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["rice"], + altitude = AL.SURFACE, + biomeFilters = BF([(HE.SUBTROPICAL, HE.TEMPERATE), (WA.RIVER, WA.SWAMP)]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["sugarcane"], + altitude = AL.DUNES, + biomeFilters = BF([(HE.TROPICAL, HE.TEMPERATE), (WA.RIVER, WA.SWAMP)]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["sunflower"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([ResourceId.parse("sunflower_plains")]), + scarcity = SC.CARPET, + )) + + spawns.add(PlantSpawn( + plant = plants["tomato"], + altitude = AL.span(AL.UPLANDS, AL.HILLS), + biomeFilters = BF([FL.CLEARING, HE.TROPICAL, HU.WET], [SO.FUNGAL]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["wheat"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.FIELD, HE.TEMPERATE, HU.DAMP, SO.LOAMY]), + scarcity = SC.COMMON, + )) + + # Flower Patches ########################################################### + + spawns.add(PlantSpawn( + plant = plants["allium"], + altitude = AL.span(AL.UPLANDS, AL.HILLS), + biomeFilters = BF([FL.FOREST, HE.TEMPERATE, HU.DAMP, SO.ACIDIC]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["azurebluet"], + altitude = AL.span(AL.UPLANDS, AL.ALPINE), + biomeFilters = BF([FL.FIELD, (HE.TEMPERATE, HE.BOREAL), HU.DAMP, (SO.LOAMY, SO.PEATY)]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["blueorchid"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.CANOPY, HE.TROPICAL, HU.WET]), + scarcity = SC.RARE, + )) + + spawns.add(PlantSpawn( + plant = plants["cornflower"], + altitude = AL.span(AL.UPLANDS, AL.ALPINE), + biomeFilters = BF([FL.FIELD, HE.TEMPERATE, (SO.LOAMY, SO.PEATY)]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["daisy"], + altitude = AL.span(AL.UPLANDS, AL.ALPINE), + biomeFilters = BF([FL.FIELD, (HE.TEMPERATE, HE.BOREAL)]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["dandelion"], + altitude = AL.span(AL.DUNES, AL.HILLS), + biomeFilters = BF( + [(FL.CLEARING, FL.FIELD)], + [HE.FROZEN, HU.WET, SO.FUNGAL, SO.ROCKY, ResourceId.parse("flower_forest")]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["lilac"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.FOREST, HE.TEMPERATE, HU.DAMP, SO.LOAMY]), + scarcity = SC.UNUSUAL, + )) + + spawns.add(PlantSpawn( + plant = plants["lily"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.FOREST, (HE.TEMPERATE, HE.BOREAL), HU.DAMP, SO.ACIDIC]), + scarcity = SC.RARE, + )) + + spawns.add(PlantSpawn( + plant = plants["peony"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.CLEARING, HE.TEMPERATE, HU.DAMP, SO.ROCKY]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["poppy"], + altitude = AL.span(AL.DUNES, AL.UPLANDS), + biomeFilters = BF( + [FL.FIELD, (HE.SUBTROPICAL, HE.TEMPERATE), (HU.DRY, HU.DAMP)], + [SO.FUNGAL] + ), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["rose_black"], + altitude = AL.HILLS, + biomeFilters = BF([FL.CANOPY, HE.TEMPERATE]), + scarcity = SC.RARE, + )) + + spawns.add(PlantSpawn( + plant = plants["rose_bush"], + altitude = AL.span(AL.UPLANDS, AL.ALPINE), + biomeFilters = BF([FL.FOREST, (HE.TEMPERATE, HE.BOREAL), SO.LOAMY]), + scarcity = SC.UNUSUAL, + )) + + spawns.add(PlantSpawn( + plant = plants["tulip_orange"], + altitude = AL.span(AL.DUNES, AL.LOWLANDS), + biomeFilters = BF([ResourceId.parse("flower_forest")]), + scarcity = SC.UNUSUAL, + )) + + spawns.add(PlantSpawn( + plant = plants["tulip_pink"], + altitude = AL.span(AL.DUNES, AL.LOWLANDS), + biomeFilters = BF([ResourceId.parse("flower_forest")]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["tulip_red"], + altitude = AL.span(AL.DUNES, AL.LOWLANDS), + biomeFilters = BF([ResourceId.parse("flower_forest")]), + scarcity = SC.COMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["tulip_white"], + altitude = AL.span(AL.DUNES, AL.LOWLANDS), + biomeFilters = BF([ResourceId.parse("flower_forest")]), + scarcity = SC.UNCOMMON, + )) + + # Trees #################################################################### + + spawns.add(PlantSpawn( + plant = plants["apple"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF( + [(FL.FOREST, FL.CLEARING), HE.TEMPERATE, SO.LOAMY], + [ResourceId.parse("flower_forest")], + ), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["bayberry"], + altitude = AL.span(AL.DUNES, AL.UPLANDS), + biomeFilters = BF([HE.TEMPERATE, (SO.ROCKY, SO.SANDY), WA.COAST]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["durian"], + altitude = AL.HILLS, + biomeFilters = BF([FL.within(FL.CANOPY, FL.CLEARING), HE.TROPICAL, HU.WET, SO.ACIDIC]), + scarcity = SC.UNUSUAL, + )) + + spawns.add(PlantSpawn( + plant = plants["fig"], + altitude = AL.span(AL.UPLANDS, AL.HILLS), + biomeFilters = BF([HE.SUBTROPICAL, HU.DRY, SO.SANDY], [FL.BARREN]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["hawberry"], + altitude = AL.span(AL.UPLANDS, AL.HILLS), + biomeFilters = BF([(FL.FOREST, FL.CLEARING), HE.TEMPERATE, (SO.ACIDIC, SO.LOAMY)]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["lychee"], + altitude = AL.UPLANDS, + biomeFilters = BF([FL.CLEARING, HE.TROPICAL, HU.WET], [SO.FUNGAL]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["mango"], + altitude = AL.LOWLANDS, + biomeFilters = BF( + [FL.within(FL.CANOPY, FL.CLEARING), HE.TROPICAL, (HU.DAMP, HU.WET), SO.ACIDIC] + ), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["mangosteen"], + altitude = AL.UPLANDS, + biomeFilters = BF([FL.CANOPY, HE.TROPICAL, HU.WET, SO.ACIDIC]), + scarcity = SC.UNUSUAL, + )) + + spawns.add(PlantSpawn( + plant = plants["orange"], + altitude = AL.LOWLANDS, + biomeFilters = BF([FL.FIELD, HE.SUBTROPICAL, HU.DRY]), + scarcity = SC.SPARSE, + )) + + spawns.add(PlantSpawn( + plant = plants["peach"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.CLEARING, HE.TEMPERATE, HU.DAMP, SO.ROCKY]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["pear"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.CLEARING, HE.TEMPERATE, HU.DAMP, (SO.ACIDIC, SO.LOAMY)]), + scarcity = SC.UNCOMMON, + )) + + spawns.add(PlantSpawn( + plant = plants["persimmon"], + altitude = AL.span(AL.LOWLANDS, AL.UPLANDS), + biomeFilters = BF([FL.FOREST, HE.TEMPERATE, SO.LOAMY]), + scarcity = SC.UNCOMMON, + )) diff --git a/mcpacker/pack/mysteriousisland/addplantspawns_test.py b/mcpacker/pack/mysteriousisland/addplantspawns_test.py new file mode 100644 index 0000000..2d24698 --- /dev/null +++ b/mcpacker/pack/mysteriousisland/addplantspawns_test.py @@ -0,0 +1,7 @@ +import mcpacker.pack.mysteriousisland.addplantspawns + + +# Class ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/pack/mysteriousisland/modpack.py b/mcpacker/pack/mysteriousisland/modpack.py index 5185b57..059bb63 100644 --- a/mcpacker/pack/mysteriousisland/modpack.py +++ b/mcpacker/pack/mysteriousisland/modpack.py @@ -9,6 +9,8 @@ from mcpacker.pack.mysteriousisland.addminerals import addMinerals from mcpacker.pack.mysteriousisland.addmobs import addMobs from mcpacker.pack.mysteriousisland.addmobspawns import addMobSpawns from mcpacker.pack.mysteriousisland.addresourcepack import addResourcePack +from mcpacker.pack.mysteriousisland.addplants import addPlants +from mcpacker.pack.mysteriousisland.addplantspawns import addPlantSpawns # Constants ######################################################################################## @@ -22,6 +24,8 @@ def buildModPack(): pack.augment(addBlocks) pack.augment(addMinerals) pack.augment(addDeposits) + pack.augment(addPlants) + pack.augment(addPlantSpawns) pack.augment(addMobs) pack.augment(addMobSpawns) pack.augment(addDisabledFeatures) diff --git a/mcpacker/pack/mysteriousisland/runner.py b/mcpacker/pack/mysteriousisland/runner.py index cc69d68..8a32479 100644 --- a/mcpacker/pack/mysteriousisland/runner.py +++ b/mcpacker/pack/mysteriousisland/runner.py @@ -1,5 +1,5 @@ from mcpacker.pack.mysteriousisland.modpack import buildModPack -from mcpacker.ui.runner import Runner +from mcpacker.ui.runner import Runner import sys diff --git a/mcpacker/ui/runner.py b/mcpacker/ui/runner.py index cbb2a40..39b27ea 100644 --- a/mcpacker/ui/runner.py +++ b/mcpacker/ui/runner.py @@ -2,6 +2,7 @@ from mcpacker.format.report.biomereport import BiomeReport from mcpacker.format.report.depositreport import DepositReport from mcpacker.format.report.mineralreport import MineralReport from mcpacker.format.report.mobspawnreport import MobSpawnReport +from mcpacker.format.report.plantspawnreport import PlantSpawnReport from mcpacker.model.modpack import ModPack from mcpacker.write.compositewriter import CompositeWriter from mcpacker.write.datapack.depositwriter import DepositWriter @@ -61,6 +62,7 @@ class Runner: ReportWriter(p, DepositReport, o, "deposits.txt"), ReportWriter(p, MineralReport, o, "minerals.txt"), ReportWriter(p, MobSpawnReport, o, "mobspawns.txt"), + ReportWriter(p, PlantSpawnReport, o, "plantspawns.txt"), ]).write() def _command_writeModPack(self): diff --git a/mcpacker/write/compositewriter_test.py b/mcpacker/write/compositewriter_test.py new file mode 100644 index 0000000..135de40 --- /dev/null +++ b/mcpacker/write/compositewriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.compositewriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/datapack/depositwriter_test.py b/mcpacker/write/datapack/depositwriter_test.py new file mode 100644 index 0000000..3026103 --- /dev/null +++ b/mcpacker/write/datapack/depositwriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.datapack.depositwriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/datapack/disablefeaturewriter_test.py b/mcpacker/write/datapack/disablefeaturewriter_test.py new file mode 100644 index 0000000..3aaed21 --- /dev/null +++ b/mcpacker/write/datapack/disablefeaturewriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.datapack.disablefeaturewriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/datapack/disablespawnwriter_test.py b/mcpacker/write/datapack/disablespawnwriter_test.py new file mode 100644 index 0000000..f916a7b --- /dev/null +++ b/mcpacker/write/datapack/disablespawnwriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.datapack.disablespawnwriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/largeoredeposits/depositwriter_test.py b/mcpacker/write/largeoredeposits/depositwriter_test.py new file mode 100644 index 0000000..fae70b1 --- /dev/null +++ b/mcpacker/write/largeoredeposits/depositwriter_test.py @@ -0,0 +1,8 @@ +import mcpacker.write.largeoredeposits.depositwriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass + diff --git a/mcpacker/write/packmetawriter_test.py b/mcpacker/write/packmetawriter_test.py new file mode 100644 index 0000000..62b2998 --- /dev/null +++ b/mcpacker/write/packmetawriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.packmetawriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/resourcepack/blockstatewriter_test.py b/mcpacker/write/resourcepack/blockstatewriter_test.py new file mode 100644 index 0000000..75f22e9 --- /dev/null +++ b/mcpacker/write/resourcepack/blockstatewriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.resourcepack.blockstatewriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/staticwriter_test.py b/mcpacker/write/staticwriter_test.py new file mode 100644 index 0000000..426730f --- /dev/null +++ b/mcpacker/write/staticwriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.staticwriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass diff --git a/mcpacker/write/zipwriter_test.py b/mcpacker/write/zipwriter_test.py new file mode 100644 index 0000000..a4b1b39 --- /dev/null +++ b/mcpacker/write/zipwriter_test.py @@ -0,0 +1,7 @@ +import mcpacker.write.zipwriter + + +# Tests ############################################################################################ + +def test_syntax(): + pass