mirror of
https://github.com/ArchipelagoMW/Archipelago.git
synced 2026-03-30 03:53:23 -07:00
Merge branch 'main' into tunc-combat-logic
This commit is contained in:
6
kvui.py
6
kvui.py
@@ -595,8 +595,8 @@ class GameManager(App):
|
||||
"!help for server commands.")
|
||||
|
||||
def connect_button_action(self, button):
|
||||
self.ctx.username = None
|
||||
if self.ctx.server:
|
||||
self.ctx.username = None
|
||||
async_start(self.ctx.disconnect())
|
||||
else:
|
||||
async_start(self.ctx.connect(self.server_connect_bar.text.replace("/connect ", "")))
|
||||
@@ -836,6 +836,10 @@ class KivyJSONtoTextParser(JSONtoTextParser):
|
||||
return self._handle_text(node)
|
||||
|
||||
def _handle_text(self, node: JSONMessagePart):
|
||||
# All other text goes through _handle_color, and we don't want to escape markup twice,
|
||||
# or mess up text that already has intentional markup applied to it
|
||||
if node.get("type", "text") == "text":
|
||||
node["text"] = escape_markup(node["text"])
|
||||
for ref in node.get("refs", []):
|
||||
node["text"] = f"[ref={self.ref_count}|{ref}]{node['text']}[/ref]"
|
||||
self.ref_count += 1
|
||||
|
||||
@@ -762,7 +762,7 @@ location_table: List[LocationDict] = [
|
||||
'game_id': "graf385"},
|
||||
{'name': "Tagged 389 Graffiti Spots",
|
||||
'stage': Stages.Misc,
|
||||
'game_id': "graf379"},
|
||||
'game_id': "graf389"},
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -140,6 +140,15 @@
|
||||
painting: True
|
||||
The Colorful:
|
||||
painting: True
|
||||
Welcome Back Area:
|
||||
room: Welcome Back Area
|
||||
door: Shortcut to Starting Room
|
||||
Second Room:
|
||||
door: Main Door
|
||||
Hidden Room:
|
||||
door: Back Right Door
|
||||
Rhyme Room (Looped Square):
|
||||
door: Rhyme Room Entrance
|
||||
panels:
|
||||
HI:
|
||||
id: Entry Room/Panel_hi_hi
|
||||
@@ -3265,7 +3274,6 @@
|
||||
door: Traveled Entrance
|
||||
Color Hallways:
|
||||
door: Color Hallways Entrance
|
||||
warp: True
|
||||
panels:
|
||||
Achievement:
|
||||
id: Countdown Panels/Panel_traveled_traveled
|
||||
|
||||
Binary file not shown.
@@ -159,7 +159,7 @@ def create_regions(world: "LingoWorld") -> None:
|
||||
RoomAndDoor("Pilgrim Antechamber", "Sun Painting"), EntranceType.PAINTING, False, world)
|
||||
|
||||
if early_color_hallways:
|
||||
connect_entrance(regions, regions["Starting Room"], regions["Outside The Undeterred"], "Early Color Hallways",
|
||||
connect_entrance(regions, regions["Starting Room"], regions["Color Hallways"], "Early Color Hallways",
|
||||
None, EntranceType.PAINTING, False, world)
|
||||
|
||||
if painting_shuffle:
|
||||
|
||||
@@ -29,7 +29,6 @@ class TestPilgrimageWithRoofAndPaintings(LingoTestBase):
|
||||
"Outside The Undeterred - Green Painting"]
|
||||
|
||||
for door in doors:
|
||||
print(door)
|
||||
self.assertFalse(self.can_reach_location("Pilgrim Antechamber - PILGRIM"))
|
||||
self.collect_by_name(door)
|
||||
|
||||
@@ -53,7 +52,6 @@ class TestPilgrimageNoRoofYesPaintings(LingoTestBase):
|
||||
"Starting Room - Street Painting"]
|
||||
|
||||
for door in doors:
|
||||
print(door)
|
||||
self.assertFalse(self.can_reach_location("Pilgrim Antechamber - PILGRIM"))
|
||||
self.collect_by_name(door)
|
||||
|
||||
@@ -81,13 +79,40 @@ class TestPilgrimageNoRoofNoPaintings(LingoTestBase):
|
||||
"Orange Tower Fourth Floor - Hot Crusts Door"]
|
||||
|
||||
for door in doors:
|
||||
print(door)
|
||||
self.assertFalse(self.can_reach_location("Pilgrim Antechamber - PILGRIM"))
|
||||
self.collect_by_name(door)
|
||||
|
||||
self.assertTrue(self.can_reach_location("Pilgrim Antechamber - PILGRIM"))
|
||||
|
||||
|
||||
class TestPilgrimageRequireStartingRoom(LingoTestBase):
|
||||
options = {
|
||||
"enable_pilgrimage": "true",
|
||||
"shuffle_colors": "false",
|
||||
"shuffle_doors": "complex",
|
||||
"pilgrimage_allows_roof_access": "false",
|
||||
"pilgrimage_allows_paintings": "false",
|
||||
"early_color_hallways": "false"
|
||||
}
|
||||
|
||||
def test_access(self):
|
||||
doors = ["Second Room - Exit Door", "Crossroads - Roof Access", "Hub Room - Crossroads Entrance",
|
||||
"Outside The Undeterred - Green Painting", "Outside The Undeterred - Number Hunt",
|
||||
"Starting Room - Street Painting", "Outside The Initiated - Shortcut to Hub Room",
|
||||
"Directional Gallery - Shortcut to The Undeterred", "Orange Tower First Floor - Salt Pepper Door",
|
||||
"Color Hunt - Shortcut to The Steady", "The Bearer - Entrance",
|
||||
"Orange Tower Fifth Floor - Quadruple Intersection", "The Tenacious - Shortcut to Hub Room",
|
||||
"Outside The Agreeable - Tenacious Entrance", "Crossroads - Tower Entrance",
|
||||
"Orange Tower Fourth Floor - Hot Crusts Door", "Challenge Room - Welcome Door",
|
||||
"Number Hunt - Challenge Entrance", "Welcome Back Area - Shortcut to Starting Room"]
|
||||
|
||||
for door in doors:
|
||||
self.assertFalse(self.can_reach_location("Pilgrim Antechamber - PILGRIM"))
|
||||
self.collect_by_name(door)
|
||||
|
||||
self.assertTrue(self.can_reach_location("Pilgrim Antechamber - PILGRIM"))
|
||||
|
||||
|
||||
class TestPilgrimageYesRoofNoPaintings(LingoTestBase):
|
||||
options = {
|
||||
"enable_pilgrimage": "true",
|
||||
@@ -107,7 +132,6 @@ class TestPilgrimageYesRoofNoPaintings(LingoTestBase):
|
||||
"Orange Tower Fifth Floor - Quadruple Intersection"]
|
||||
|
||||
for door in doors:
|
||||
print(door)
|
||||
self.assertFalse(self.can_reach_location("Pilgrim Antechamber - PILGRIM"))
|
||||
self.collect_by_name(door)
|
||||
|
||||
|
||||
@@ -328,7 +328,7 @@ location_table: List[LocationInfo] = [
|
||||
{"name": "Boat Rental",
|
||||
"id": base_id + 55,
|
||||
"inGameId": "DadDeer[0]",
|
||||
"needsShovel": False, "purchase": True,
|
||||
"needsShovel": False, "purchase": 100,
|
||||
"minGoldenFeathers": 0, "minGoldenFeathersEasy": 0, "minGoldenFeathersBucket": 0},
|
||||
{"name": "Boat Challenge Reward",
|
||||
"id": base_id + 56,
|
||||
|
||||
@@ -255,7 +255,7 @@ class StardewValleyWorld(World):
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_greatest_walnut_hunter:
|
||||
self.create_event_location(location_table[GoalName.greatest_walnut_hunter],
|
||||
self.logic.has_walnut(130),
|
||||
self.logic.walnut.has_walnut(130),
|
||||
Event.victory)
|
||||
elif self.options.goal == Goal.option_protector_of_the_valley:
|
||||
self.create_event_location(location_table[GoalName.protector_of_the_valley],
|
||||
|
||||
@@ -3,6 +3,7 @@ from ..game_content import ContentPack, StardewContent
|
||||
from ...data import villagers_data, fish_data
|
||||
from ...data.game_item import ItemTag, Tag
|
||||
from ...data.harvest import ForagingSource, HarvestFruitTreeSource, HarvestCropSource
|
||||
from ...data.requirement import WalnutRequirement
|
||||
from ...data.shop import ShopSource
|
||||
from ...strings.book_names import Book
|
||||
from ...strings.crop_names import Fruit, Vegetable
|
||||
@@ -10,7 +11,7 @@ from ...strings.fish_names import Fish
|
||||
from ...strings.forageable_names import Forageable, Mushroom
|
||||
from ...strings.fruit_tree_names import Sapling
|
||||
from ...strings.metal_names import Fossil, Mineral
|
||||
from ...strings.region_names import Region
|
||||
from ...strings.region_names import Region, LogicRegion
|
||||
from ...strings.season_names import Season
|
||||
from ...strings.seed_names import Seed
|
||||
|
||||
@@ -62,6 +63,9 @@ ginger_island_content_pack = GingerIslandContentPack(
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_POWER),
|
||||
ShopSource(items_price=((10, Mineral.diamond),), shop_region=Region.volcano_dwarf_shop),
|
||||
),
|
||||
Book.queen_of_sauce_cookbook: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=50000, shop_region=LogicRegion.bookseller_2, other_requirements=(WalnutRequirement(100),)),), # Worst book ever
|
||||
|
||||
},
|
||||
fishes=(
|
||||
|
||||
@@ -290,9 +290,6 @@ pelican_town = ContentPack(
|
||||
Book.woodcutters_weekly: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=5000, shop_region=LogicRegion.bookseller_1),),
|
||||
Book.queen_of_sauce_cookbook: (
|
||||
Tag(ItemTag.BOOK, ItemTag.BOOK_SKILL),
|
||||
ShopSource(money_price=50000, shop_region=LogicRegion.bookseller_2),), # Worst book ever
|
||||
},
|
||||
fishes=(
|
||||
fish_data.albacore,
|
||||
|
||||
@@ -2221,7 +2221,7 @@ id,region,name,tags,mod_name
|
||||
3817,Shipping,Shipsanity: Raisins,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",
|
||||
3818,Shipping,Shipsanity: Dried Fruit,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",
|
||||
3819,Shipping,Shipsanity: Dried Mushrooms,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",
|
||||
3820,Shipping,Shipsanity: Stardrop Tea,"SHIPSANITY,SHIPSANITY_FULL_SHIPMENT",
|
||||
3820,Shipping,Shipsanity: Stardrop Tea,"SHIPSANITY",
|
||||
3821,Shipping,Shipsanity: Prize Ticket,"SHIPSANITY",
|
||||
3822,Shipping,Shipsanity: Treasure Totem,"SHIPSANITY,REQUIRES_MASTERIES",
|
||||
3823,Shipping,Shipsanity: Challenge Bait,"SHIPSANITY,REQUIRES_MASTERIES",
|
||||
@@ -2252,7 +2252,7 @@ id,region,name,tags,mod_name
|
||||
3848,Shipping,Shipsanity: Way Of The Wind pt. 1,"SHIPSANITY",
|
||||
3849,Shipping,Shipsanity: Mapping Cave Systems,"SHIPSANITY",
|
||||
3850,Shipping,Shipsanity: Price Catalogue,"SHIPSANITY",
|
||||
3851,Shipping,Shipsanity: Queen Of Sauce Cookbook,"SHIPSANITY",
|
||||
3851,Shipping,Shipsanity: Queen Of Sauce Cookbook,"SHIPSANITY,GINGER_ISLAND",
|
||||
3852,Shipping,Shipsanity: The Diamond Hunter,"SHIPSANITY,GINGER_ISLAND",
|
||||
3853,Shipping,Shipsanity: Book of Mysteries,"SHIPSANITY",
|
||||
3854,Shipping,Shipsanity: Animal Catalogue,"SHIPSANITY",
|
||||
@@ -2292,7 +2292,7 @@ id,region,name,tags,mod_name
|
||||
4032,Farm,Read Book Of Stars,"BOOKSANITY,BOOKSANITY_SKILL",
|
||||
4033,Farm,Read Combat Quarterly,"BOOKSANITY,BOOKSANITY_SKILL",
|
||||
4034,Farm,Read Mining Monthly,"BOOKSANITY,BOOKSANITY_SKILL",
|
||||
4035,Farm,Read Queen Of Sauce Cookbook,"BOOKSANITY,BOOKSANITY_SKILL",
|
||||
4035,Farm,Read Queen Of Sauce Cookbook,"BOOKSANITY,BOOKSANITY_SKILL,GINGER_ISLAND",
|
||||
4036,Farm,Read Stardew Valley Almanac,"BOOKSANITY,BOOKSANITY_SKILL",
|
||||
4037,Farm,Read Woodcutter's Weekly,"BOOKSANITY,BOOKSANITY_SKILL",
|
||||
4051,Museum,Read Tips on Farming,"BOOKSANITY,BOOKSANITY_LOST",
|
||||
|
||||
|
@@ -29,3 +29,8 @@ class SeasonRequirement(Requirement):
|
||||
@dataclass(frozen=True)
|
||||
class YearRequirement(Requirement):
|
||||
year: int
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class WalnutRequirement(Requirement):
|
||||
amount: int
|
||||
|
||||
@@ -27,8 +27,8 @@ class BundleLogicMixin(BaseLogicMixin):
|
||||
self.bundle = BundleLogic(*args, **kwargs)
|
||||
|
||||
|
||||
class BundleLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, TimeLogicMixin, RegionLogicMixin, MoneyLogicMixin, QualityLogicMixin, FishingLogicMixin, SkillLogicMixin,
|
||||
QuestLogicMixin]]):
|
||||
class BundleLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, TimeLogicMixin, RegionLogicMixin, MoneyLogicMixin, QualityLogicMixin, FishingLogicMixin,
|
||||
SkillLogicMixin, QuestLogicMixin]]):
|
||||
# Should be cached
|
||||
def can_complete_bundle(self, bundle: Bundle) -> StardewRule:
|
||||
item_rules = []
|
||||
@@ -45,7 +45,7 @@ QuestLogicMixin]]):
|
||||
qualities.append(bundle_item.quality)
|
||||
quality_rules = self.get_quality_rules(qualities)
|
||||
item_rules = self.logic.has_n(*item_rules, count=bundle.number_required)
|
||||
time_rule = True_() if time_to_grind <= 0 else self.logic.time.has_lived_months(time_to_grind)
|
||||
time_rule = self.logic.time.has_lived_months(time_to_grind)
|
||||
return can_speak_junimo & item_rules & quality_rules & time_rule
|
||||
|
||||
def get_quality_rules(self, qualities: List[str]) -> StardewRule:
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from functools import cached_property
|
||||
from typing import Collection, Callable
|
||||
|
||||
from .ability_logic import AbilityLogicMixin
|
||||
@@ -43,6 +42,7 @@ from .time_logic import TimeLogicMixin
|
||||
from .tool_logic import ToolLogicMixin
|
||||
from .traveling_merchant_logic import TravelingMerchantLogicMixin
|
||||
from .wallet_logic import WalletLogicMixin
|
||||
from .walnut_logic import WalnutLogicMixin
|
||||
from ..content.game_content import StardewContent
|
||||
from ..data.craftable_data import all_crafting_recipes
|
||||
from ..data.museum_data import all_museum_items
|
||||
@@ -50,16 +50,14 @@ from ..data.recipe_data import all_cooking_recipes
|
||||
from ..mods.logic.magic_logic import MagicLogicMixin
|
||||
from ..mods.logic.mod_logic import ModLogicMixin
|
||||
from ..mods.mod_data import ModNames
|
||||
from ..options import SpecialOrderLocations, ExcludeGingerIsland, FestivalLocations, StardewValleyOptions, Walnutsanity
|
||||
from ..options import ExcludeGingerIsland, FestivalLocations, StardewValleyOptions
|
||||
from ..stardew_rule import False_, True_, StardewRule
|
||||
from ..strings.animal_names import Animal
|
||||
from ..strings.animal_product_names import AnimalProduct
|
||||
from ..strings.ap_names.ap_option_names import OptionName
|
||||
from ..strings.ap_names.community_upgrade_names import CommunityUpgrade
|
||||
from ..strings.ap_names.event_names import Event
|
||||
from ..strings.artisan_good_names import ArtisanGood
|
||||
from ..strings.building_names import Building
|
||||
from ..strings.craftable_names import Consumable, Furniture, Ring, Fishing, Lighting, WildSeeds
|
||||
from ..strings.craftable_names import Consumable, Ring, Fishing, Lighting, WildSeeds
|
||||
from ..strings.crop_names import Fruit, Vegetable
|
||||
from ..strings.currency_names import Currency
|
||||
from ..strings.decoration_names import Decoration
|
||||
@@ -96,7 +94,7 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
CombatLogicMixin, MagicLogicMixin, MonsterLogicMixin, ToolLogicMixin, PetLogicMixin, QualityLogicMixin,
|
||||
SkillLogicMixin, FarmingLogicMixin, BundleLogicMixin, FishingLogicMixin, MineLogicMixin, CookingLogicMixin, AbilityLogicMixin,
|
||||
SpecialOrderLogicMixin, QuestLogicMixin, CraftingLogicMixin, ModLogicMixin, HarvestingLogicMixin, SourceLogicMixin,
|
||||
RequirementLogicMixin, BookLogicMixin, GrindLogicMixin):
|
||||
RequirementLogicMixin, BookLogicMixin, GrindLogicMixin, WalnutLogicMixin):
|
||||
player: int
|
||||
options: StardewValleyOptions
|
||||
content: StardewContent
|
||||
@@ -461,32 +459,6 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
def can_smelt(self, item: str) -> StardewRule:
|
||||
return self.has(Machine.furnace) & self.has(item)
|
||||
|
||||
@cached_property
|
||||
def can_start_field_office(self) -> StardewRule:
|
||||
field_office = self.region.can_reach(Region.field_office)
|
||||
professor_snail = self.received("Open Professor Snail Cave")
|
||||
return field_office & professor_snail
|
||||
|
||||
def can_complete_large_animal_collection(self) -> StardewRule:
|
||||
fossils = self.has_all(Fossil.fossilized_leg, Fossil.fossilized_ribs, Fossil.fossilized_skull, Fossil.fossilized_spine, Fossil.fossilized_tail)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_snake_collection(self) -> StardewRule:
|
||||
fossils = self.has_all(Fossil.snake_skull, Fossil.snake_vertebrae)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_frog_collection(self) -> StardewRule:
|
||||
fossils = self.has_all(Fossil.mummified_frog)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_bat_collection(self) -> StardewRule:
|
||||
fossils = self.has_all(Fossil.mummified_bat)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_field_office(self) -> StardewRule:
|
||||
return self.can_complete_large_animal_collection() & self.can_complete_snake_collection() & \
|
||||
self.can_complete_frog_collection() & self.can_complete_bat_collection()
|
||||
|
||||
def can_finish_grandpa_evaluation(self) -> StardewRule:
|
||||
# https://stardewvalleywiki.com/Grandpa
|
||||
rules_worth_a_point = [
|
||||
@@ -566,86 +538,6 @@ class StardewLogic(ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, Travelin
|
||||
return False_()
|
||||
return self.region.can_reach(Region.island_trader)
|
||||
|
||||
def has_walnut(self, number: int) -> StardewRule:
|
||||
if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
return False_()
|
||||
if number <= 0:
|
||||
return True_()
|
||||
|
||||
if self.options.walnutsanity == Walnutsanity.preset_none:
|
||||
return self.can_get_walnuts(number)
|
||||
if self.options.walnutsanity == Walnutsanity.preset_all:
|
||||
return self.has_received_walnuts(number)
|
||||
puzzle_walnuts = 61
|
||||
bush_walnuts = 25
|
||||
dig_walnuts = 18
|
||||
repeatable_walnuts = 33
|
||||
total_walnuts = puzzle_walnuts + bush_walnuts + dig_walnuts + repeatable_walnuts
|
||||
walnuts_to_receive = 0
|
||||
walnuts_to_collect = number
|
||||
if OptionName.walnutsanity_puzzles in self.options.walnutsanity:
|
||||
puzzle_walnut_rate = puzzle_walnuts / total_walnuts
|
||||
puzzle_walnuts_required = round(puzzle_walnut_rate * number)
|
||||
walnuts_to_receive += puzzle_walnuts_required
|
||||
walnuts_to_collect -= puzzle_walnuts_required
|
||||
if OptionName.walnutsanity_bushes in self.options.walnutsanity:
|
||||
bush_walnuts_rate = bush_walnuts / total_walnuts
|
||||
bush_walnuts_required = round(bush_walnuts_rate * number)
|
||||
walnuts_to_receive += bush_walnuts_required
|
||||
walnuts_to_collect -= bush_walnuts_required
|
||||
if OptionName.walnutsanity_dig_spots in self.options.walnutsanity:
|
||||
dig_walnuts_rate = dig_walnuts / total_walnuts
|
||||
dig_walnuts_required = round(dig_walnuts_rate * number)
|
||||
walnuts_to_receive += dig_walnuts_required
|
||||
walnuts_to_collect -= dig_walnuts_required
|
||||
if OptionName.walnutsanity_repeatables in self.options.walnutsanity:
|
||||
repeatable_walnuts_rate = repeatable_walnuts / total_walnuts
|
||||
repeatable_walnuts_required = round(repeatable_walnuts_rate * number)
|
||||
walnuts_to_receive += repeatable_walnuts_required
|
||||
walnuts_to_collect -= repeatable_walnuts_required
|
||||
return self.has_received_walnuts(walnuts_to_receive) & self.can_get_walnuts(walnuts_to_collect)
|
||||
|
||||
def has_received_walnuts(self, number: int) -> StardewRule:
|
||||
return self.received(Event.received_walnuts, number)
|
||||
|
||||
def can_get_walnuts(self, number: int) -> StardewRule:
|
||||
# https://stardewcommunitywiki.com/Golden_Walnut#Walnut_Locations
|
||||
reach_south = self.region.can_reach(Region.island_south)
|
||||
reach_north = self.region.can_reach(Region.island_north)
|
||||
reach_west = self.region.can_reach(Region.island_west)
|
||||
reach_hut = self.region.can_reach(Region.leo_hut)
|
||||
reach_southeast = self.region.can_reach(Region.island_south_east)
|
||||
reach_field_office = self.region.can_reach(Region.field_office)
|
||||
reach_pirate_cove = self.region.can_reach(Region.pirate_cove)
|
||||
reach_outside_areas = self.logic.and_(reach_south, reach_north, reach_west, reach_hut)
|
||||
reach_volcano_regions = [self.region.can_reach(Region.volcano),
|
||||
self.region.can_reach(Region.volcano_secret_beach),
|
||||
self.region.can_reach(Region.volcano_floor_5),
|
||||
self.region.can_reach(Region.volcano_floor_10)]
|
||||
reach_volcano = self.logic.or_(*reach_volcano_regions)
|
||||
reach_all_volcano = self.logic.and_(*reach_volcano_regions)
|
||||
reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano, reach_field_office]
|
||||
reach_caves = self.logic.and_(self.region.can_reach(Region.qi_walnut_room), self.region.can_reach(Region.dig_site),
|
||||
self.region.can_reach(Region.gourmand_frog_cave),
|
||||
self.region.can_reach(Region.colored_crystals_cave),
|
||||
self.region.can_reach(Region.shipwreck), self.combat.has_slingshot)
|
||||
reach_entire_island = self.logic.and_(reach_outside_areas, reach_all_volcano,
|
||||
reach_caves, reach_southeast, reach_field_office, reach_pirate_cove)
|
||||
if number <= 5:
|
||||
return self.logic.or_(reach_south, reach_north, reach_west, reach_volcano)
|
||||
if number <= 10:
|
||||
return self.count(2, *reach_walnut_regions)
|
||||
if number <= 15:
|
||||
return self.count(3, *reach_walnut_regions)
|
||||
if number <= 20:
|
||||
return self.logic.and_(*reach_walnut_regions)
|
||||
if number <= 50:
|
||||
return reach_entire_island
|
||||
gems = (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz)
|
||||
return reach_entire_island & self.has(Fruit.banana) & self.has_all(*gems) & self.ability.can_mine_perfectly() & \
|
||||
self.ability.can_fish_perfectly() & self.has(Furniture.flute_block) & self.has(Seed.melon) & self.has(Seed.wheat) & self.has(Seed.garlic) & \
|
||||
self.can_complete_field_office()
|
||||
|
||||
def has_all_stardrops(self) -> StardewRule:
|
||||
other_rules = []
|
||||
number_of_stardrops_to_receive = 0
|
||||
|
||||
@@ -41,7 +41,7 @@ class MuseumLogic(BaseLogic[Union[ReceivedLogicMixin, HasLogicMixin, TimeLogicMi
|
||||
else:
|
||||
geodes_rule = False_()
|
||||
# monster_rule = self.can_farm_monster(item.monsters)
|
||||
time_needed_to_grind = (20 - item.difficulty) / 2
|
||||
time_needed_to_grind = int((20 - item.difficulty) // 2)
|
||||
time_rule = self.logic.time.has_lived_months(time_needed_to_grind)
|
||||
pan_rule = False_()
|
||||
if item.item_name == Mineral.earth_crystal or item.item_name == Mineral.fire_quartz or item.item_name == Mineral.frozen_tear:
|
||||
|
||||
@@ -9,8 +9,9 @@ from .season_logic import SeasonLogicMixin
|
||||
from .skill_logic import SkillLogicMixin
|
||||
from .time_logic import TimeLogicMixin
|
||||
from .tool_logic import ToolLogicMixin
|
||||
from .walnut_logic import WalnutLogicMixin
|
||||
from ..data.game_item import Requirement
|
||||
from ..data.requirement import ToolRequirement, BookRequirement, SkillRequirement, SeasonRequirement, YearRequirement
|
||||
from ..data.requirement import ToolRequirement, BookRequirement, SkillRequirement, SeasonRequirement, YearRequirement, WalnutRequirement
|
||||
|
||||
|
||||
class RequirementLogicMixin(BaseLogicMixin):
|
||||
@@ -20,7 +21,7 @@ class RequirementLogicMixin(BaseLogicMixin):
|
||||
|
||||
|
||||
class RequirementLogic(BaseLogic[Union[RequirementLogicMixin, HasLogicMixin, ReceivedLogicMixin, ToolLogicMixin, SkillLogicMixin, BookLogicMixin,
|
||||
SeasonLogicMixin, TimeLogicMixin]]):
|
||||
SeasonLogicMixin, TimeLogicMixin, WalnutLogicMixin]]):
|
||||
|
||||
def meet_all_requirements(self, requirements: Iterable[Requirement]):
|
||||
if not requirements:
|
||||
@@ -50,3 +51,7 @@ SeasonLogicMixin, TimeLogicMixin]]):
|
||||
@meet_requirement.register
|
||||
def _(self, requirement: YearRequirement):
|
||||
return self.logic.time.has_year(requirement.year)
|
||||
|
||||
@meet_requirement.register
|
||||
def _(self, requirement: WalnutRequirement):
|
||||
return self.logic.walnut.has_walnut(requirement.amount)
|
||||
|
||||
@@ -26,8 +26,10 @@ class TimeLogic(BaseLogic[Union[TimeLogicMixin, HasLogicMixin]]):
|
||||
|
||||
@cache_self1
|
||||
def has_lived_months(self, number: int) -> StardewRule:
|
||||
assert isinstance(number, int), "Can't have lived a fraction of a month. Use // instead of / when dividing."
|
||||
if number <= 0:
|
||||
return self.logic.true_
|
||||
|
||||
number = min(number, MAX_MONTHS)
|
||||
return HasProgressionPercent(self.player, number * MONTH_COEFFICIENT)
|
||||
|
||||
|
||||
135
worlds/stardew_valley/logic/walnut_logic.py
Normal file
135
worlds/stardew_valley/logic/walnut_logic.py
Normal file
@@ -0,0 +1,135 @@
|
||||
from functools import cached_property
|
||||
from typing import Union
|
||||
|
||||
from .ability_logic import AbilityLogicMixin
|
||||
from .base_logic import BaseLogic, BaseLogicMixin
|
||||
from .combat_logic import CombatLogicMixin
|
||||
from .has_logic import HasLogicMixin
|
||||
from .received_logic import ReceivedLogicMixin
|
||||
from .region_logic import RegionLogicMixin
|
||||
from ..strings.ap_names.event_names import Event
|
||||
from ..options import ExcludeGingerIsland, Walnutsanity
|
||||
from ..stardew_rule import StardewRule, False_, True_
|
||||
from ..strings.ap_names.ap_option_names import OptionName
|
||||
from ..strings.craftable_names import Furniture
|
||||
from ..strings.crop_names import Fruit
|
||||
from ..strings.metal_names import Mineral, Fossil
|
||||
from ..strings.region_names import Region
|
||||
from ..strings.seed_names import Seed
|
||||
|
||||
|
||||
class WalnutLogicMixin(BaseLogicMixin):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.walnut = WalnutLogic(*args, **kwargs)
|
||||
|
||||
|
||||
class WalnutLogic(BaseLogic[Union[WalnutLogicMixin, ReceivedLogicMixin, HasLogicMixin, RegionLogicMixin, CombatLogicMixin,
|
||||
AbilityLogicMixin]]):
|
||||
|
||||
def has_walnut(self, number: int) -> StardewRule:
|
||||
if self.options.exclude_ginger_island == ExcludeGingerIsland.option_true:
|
||||
return False_()
|
||||
if number <= 0:
|
||||
return True_()
|
||||
|
||||
if self.options.walnutsanity == Walnutsanity.preset_none:
|
||||
return self.can_get_walnuts(number)
|
||||
if self.options.walnutsanity == Walnutsanity.preset_all:
|
||||
return self.has_received_walnuts(number)
|
||||
puzzle_walnuts = 61
|
||||
bush_walnuts = 25
|
||||
dig_walnuts = 18
|
||||
repeatable_walnuts = 33
|
||||
total_walnuts = puzzle_walnuts + bush_walnuts + dig_walnuts + repeatable_walnuts
|
||||
walnuts_to_receive = 0
|
||||
walnuts_to_collect = number
|
||||
if OptionName.walnutsanity_puzzles in self.options.walnutsanity:
|
||||
puzzle_walnut_rate = puzzle_walnuts / total_walnuts
|
||||
puzzle_walnuts_required = round(puzzle_walnut_rate * number)
|
||||
walnuts_to_receive += puzzle_walnuts_required
|
||||
walnuts_to_collect -= puzzle_walnuts_required
|
||||
if OptionName.walnutsanity_bushes in self.options.walnutsanity:
|
||||
bush_walnuts_rate = bush_walnuts / total_walnuts
|
||||
bush_walnuts_required = round(bush_walnuts_rate * number)
|
||||
walnuts_to_receive += bush_walnuts_required
|
||||
walnuts_to_collect -= bush_walnuts_required
|
||||
if OptionName.walnutsanity_dig_spots in self.options.walnutsanity:
|
||||
dig_walnuts_rate = dig_walnuts / total_walnuts
|
||||
dig_walnuts_required = round(dig_walnuts_rate * number)
|
||||
walnuts_to_receive += dig_walnuts_required
|
||||
walnuts_to_collect -= dig_walnuts_required
|
||||
if OptionName.walnutsanity_repeatables in self.options.walnutsanity:
|
||||
repeatable_walnuts_rate = repeatable_walnuts / total_walnuts
|
||||
repeatable_walnuts_required = round(repeatable_walnuts_rate * number)
|
||||
walnuts_to_receive += repeatable_walnuts_required
|
||||
walnuts_to_collect -= repeatable_walnuts_required
|
||||
return self.has_received_walnuts(walnuts_to_receive) & self.can_get_walnuts(walnuts_to_collect)
|
||||
|
||||
def has_received_walnuts(self, number: int) -> StardewRule:
|
||||
return self.logic.received(Event.received_walnuts, number)
|
||||
|
||||
def can_get_walnuts(self, number: int) -> StardewRule:
|
||||
# https://stardewcommunitywiki.com/Golden_Walnut#Walnut_Locations
|
||||
reach_south = self.logic.region.can_reach(Region.island_south)
|
||||
reach_north = self.logic.region.can_reach(Region.island_north)
|
||||
reach_west = self.logic.region.can_reach(Region.island_west)
|
||||
reach_hut = self.logic.region.can_reach(Region.leo_hut)
|
||||
reach_southeast = self.logic.region.can_reach(Region.island_south_east)
|
||||
reach_field_office = self.logic.region.can_reach(Region.field_office)
|
||||
reach_pirate_cove = self.logic.region.can_reach(Region.pirate_cove)
|
||||
reach_outside_areas = self.logic.and_(reach_south, reach_north, reach_west, reach_hut)
|
||||
reach_volcano_regions = [self.logic.region.can_reach(Region.volcano),
|
||||
self.logic.region.can_reach(Region.volcano_secret_beach),
|
||||
self.logic.region.can_reach(Region.volcano_floor_5),
|
||||
self.logic.region.can_reach(Region.volcano_floor_10)]
|
||||
reach_volcano = self.logic.or_(*reach_volcano_regions)
|
||||
reach_all_volcano = self.logic.and_(*reach_volcano_regions)
|
||||
reach_walnut_regions = [reach_south, reach_north, reach_west, reach_volcano, reach_field_office]
|
||||
reach_caves = self.logic.and_(self.logic.region.can_reach(Region.qi_walnut_room), self.logic.region.can_reach(Region.dig_site),
|
||||
self.logic.region.can_reach(Region.gourmand_frog_cave),
|
||||
self.logic.region.can_reach(Region.colored_crystals_cave),
|
||||
self.logic.region.can_reach(Region.shipwreck), self.logic.combat.has_slingshot)
|
||||
reach_entire_island = self.logic.and_(reach_outside_areas, reach_all_volcano,
|
||||
reach_caves, reach_southeast, reach_field_office, reach_pirate_cove)
|
||||
if number <= 5:
|
||||
return self.logic.or_(reach_south, reach_north, reach_west, reach_volcano)
|
||||
if number <= 10:
|
||||
return self.logic.count(2, *reach_walnut_regions)
|
||||
if number <= 15:
|
||||
return self.logic.count(3, *reach_walnut_regions)
|
||||
if number <= 20:
|
||||
return self.logic.and_(*reach_walnut_regions)
|
||||
if number <= 50:
|
||||
return reach_entire_island
|
||||
gems = (Mineral.amethyst, Mineral.aquamarine, Mineral.emerald, Mineral.ruby, Mineral.topaz)
|
||||
return reach_entire_island & self.logic.has(Fruit.banana) & self.logic.has_all(*gems) & \
|
||||
self.logic.ability.can_mine_perfectly() & self.logic.ability.can_fish_perfectly() & \
|
||||
self.logic.has(Furniture.flute_block) & self.logic.has(Seed.melon) & self.logic.has(Seed.wheat) & \
|
||||
self.logic.has(Seed.garlic) & self.can_complete_field_office()
|
||||
|
||||
@cached_property
|
||||
def can_start_field_office(self) -> StardewRule:
|
||||
field_office = self.logic.region.can_reach(Region.field_office)
|
||||
professor_snail = self.logic.received("Open Professor Snail Cave")
|
||||
return field_office & professor_snail
|
||||
|
||||
def can_complete_large_animal_collection(self) -> StardewRule:
|
||||
fossils = self.logic.has_all(Fossil.fossilized_leg, Fossil.fossilized_ribs, Fossil.fossilized_skull, Fossil.fossilized_spine, Fossil.fossilized_tail)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_snake_collection(self) -> StardewRule:
|
||||
fossils = self.logic.has_all(Fossil.snake_skull, Fossil.snake_vertebrae)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_frog_collection(self) -> StardewRule:
|
||||
fossils = self.logic.has_all(Fossil.mummified_frog)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_bat_collection(self) -> StardewRule:
|
||||
fossils = self.logic.has_all(Fossil.mummified_bat)
|
||||
return self.can_start_field_office & fossils
|
||||
|
||||
def can_complete_field_office(self) -> StardewRule:
|
||||
return self.can_complete_large_animal_collection() & self.can_complete_snake_collection() & \
|
||||
self.can_complete_frog_collection() & self.can_complete_bat_collection()
|
||||
@@ -375,7 +375,7 @@ def set_ginger_island_rules(logic: StardewLogic, multiworld, player, world_optio
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Open Professor Snail Cave", player),
|
||||
logic.has(Bomb.cherry_bomb))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Island Field Office", player),
|
||||
logic.can_complete_field_office())
|
||||
logic.walnut.can_complete_field_office())
|
||||
set_walnut_rules(logic, multiworld, player, world_options)
|
||||
|
||||
|
||||
@@ -432,10 +432,10 @@ def set_island_entrances_rules(logic: StardewLogic, multiworld, player, world_op
|
||||
|
||||
def set_island_parrot_rules(logic: StardewLogic, multiworld, player):
|
||||
# Logic rules require more walnuts than in reality, to allow the player to spend them "wrong"
|
||||
has_walnut = logic.has_walnut(5)
|
||||
has_5_walnut = logic.has_walnut(15)
|
||||
has_10_walnut = logic.has_walnut(40)
|
||||
has_20_walnut = logic.has_walnut(60)
|
||||
has_walnut = logic.walnut.has_walnut(5)
|
||||
has_5_walnut = logic.walnut.has_walnut(15)
|
||||
has_10_walnut = logic.walnut.has_walnut(40)
|
||||
has_20_walnut = logic.walnut.has_walnut(60)
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Leo's Parrot", player),
|
||||
has_walnut)
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Island West Turtle", player),
|
||||
@@ -471,7 +471,7 @@ def set_walnut_rules(logic: StardewLogic, multiworld, player, world_options: Sta
|
||||
set_walnut_repeatable_rules(logic, multiworld, player, world_options)
|
||||
|
||||
|
||||
def set_walnut_puzzle_rules(logic, multiworld, player, world_options):
|
||||
def set_walnut_puzzle_rules(logic: StardewLogic, multiworld, player, world_options):
|
||||
if OptionName.walnutsanity_puzzles not in world_options.walnutsanity:
|
||||
return
|
||||
|
||||
@@ -482,15 +482,17 @@ def set_walnut_puzzle_rules(logic, multiworld, player, world_options):
|
||||
logic.has(Mineral.emerald) & logic.has(Mineral.ruby) & logic.has(Mineral.topaz) &
|
||||
logic.region.can_reach_all((Region.island_north, Region.island_west, Region.island_east, Region.island_south)))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Gourmand Frog Melon", player), logic.has(Fruit.melon) & logic.region.can_reach(Region.island_west))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Gourmand Frog Wheat", player), logic.has(Vegetable.wheat) & logic.region.can_reach(Region.island_west))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Gourmand Frog Garlic", player), logic.has(Vegetable.garlic) & logic.region.can_reach(Region.island_west))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Gourmand Frog Wheat", player), logic.has(Vegetable.wheat) &
|
||||
logic.region.can_reach(Region.island_west) & logic.region.can_reach_location("Gourmand Frog Melon"))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Gourmand Frog Garlic", player), logic.has(Vegetable.garlic) &
|
||||
logic.region.can_reach(Region.island_west) & logic.region.can_reach_location("Gourmand Frog Wheat"))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Whack A Mole", player), logic.tool.has_tool(Tool.watering_can, ToolMaterial.iridium))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Large Animal Collection", player), logic.can_complete_large_animal_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Snake Collection", player), logic.can_complete_snake_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Frog Collection", player), logic.can_complete_frog_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Bat Collection", player), logic.can_complete_bat_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Purple Flowers Island Survey", player), logic.can_start_field_office)
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Purple Starfish Island Survey", player), logic.can_start_field_office)
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Large Animal Collection", player), logic.walnut.can_complete_large_animal_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Snake Collection", player), logic.walnut.can_complete_snake_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Frog Collection", player), logic.walnut.can_complete_frog_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Complete Mummified Bat Collection", player), logic.walnut.can_complete_bat_collection())
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Purple Flowers Island Survey", player), logic.walnut.can_start_field_office)
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Purple Starfish Island Survey", player), logic.walnut.can_start_field_office)
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Protruding Tree Walnut", player), logic.combat.has_slingshot)
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Starfish Tide Pool", player), logic.tool.has_fishing_rod(1))
|
||||
MultiWorldRules.add_rule(multiworld.get_location("Mermaid Song", player), logic.has(Furniture.flute_block))
|
||||
|
||||
@@ -431,7 +431,7 @@ class Count(BaseStardewRule):
|
||||
return len(self.rules)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Received {self.count} {repr(self.rules)}"
|
||||
return f"Received {self.count} [{', '.join(f'{value}x {repr(rule)}' for rule, value in self.counter.items())}]"
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
|
||||
@@ -34,7 +34,7 @@ class RuleExplanation:
|
||||
if not self.sub_rules:
|
||||
return self.summary(depth)
|
||||
|
||||
return self.summary(depth) + "\n" + "\n".join(RuleExplanation.__str__(i, depth + 1)
|
||||
return self.summary(depth) + "\n" + "\n".join(i.__str__(depth + 1)
|
||||
if i.result is not self.expected else i.summary(depth + 1)
|
||||
for i in sorted(self.explained_sub_rules, key=lambda x: x.result))
|
||||
|
||||
@@ -42,7 +42,7 @@ class RuleExplanation:
|
||||
if not self.sub_rules:
|
||||
return self.summary(depth)
|
||||
|
||||
return self.summary(depth) + "\n" + "\n".join(RuleExplanation.__repr__(i, depth + 1)
|
||||
return self.summary(depth) + "\n" + "\n".join(i.__repr__(depth + 1)
|
||||
for i in sorted(self.explained_sub_rules, key=lambda x: x.result))
|
||||
|
||||
@cached_property
|
||||
@@ -61,6 +61,33 @@ class RuleExplanation:
|
||||
return [_explain(i, self.state, self.expected, self.explored_rules_key) for i in self.sub_rules]
|
||||
|
||||
|
||||
@dataclass
|
||||
class CountSubRuleExplanation(RuleExplanation):
|
||||
count: int = 1
|
||||
|
||||
@staticmethod
|
||||
def from_explanation(expl: RuleExplanation, count: int) -> CountSubRuleExplanation:
|
||||
return CountSubRuleExplanation(expl.rule, expl.state, expl.expected, expl.sub_rules, expl.explored_rules_key, expl.current_rule_explored, count)
|
||||
|
||||
def summary(self, depth=0) -> str:
|
||||
summary = " " * depth + f"{self.count}x {str(self.rule)} -> {self.result}"
|
||||
if self.current_rule_explored:
|
||||
summary += " [Already explained]"
|
||||
return summary
|
||||
|
||||
|
||||
@dataclass
|
||||
class CountExplanation(RuleExplanation):
|
||||
rule: Count
|
||||
|
||||
@cached_property
|
||||
def explained_sub_rules(self) -> List[RuleExplanation]:
|
||||
return [
|
||||
CountSubRuleExplanation.from_explanation(_explain(rule, self.state, self.expected, self.explored_rules_key), count)
|
||||
for rule, count in self.rule.counter.items()
|
||||
]
|
||||
|
||||
|
||||
def explain(rule: CollectionRule, state: CollectionState, expected: bool = True) -> RuleExplanation:
|
||||
if isinstance(rule, StardewRule):
|
||||
return _explain(rule, state, expected, explored_spots=set())
|
||||
@@ -80,7 +107,7 @@ def _(rule: AggregatingStardewRule, state: CollectionState, expected: bool, expl
|
||||
|
||||
@_explain.register
|
||||
def _(rule: Count, state: CollectionState, expected: bool, explored_spots: Set[Tuple[str, str]]) -> RuleExplanation:
|
||||
return RuleExplanation(rule, state, expected, rule.rules, explored_rules_key=explored_spots)
|
||||
return CountExplanation(rule, state, expected, rule.rules, explored_rules_key=explored_spots)
|
||||
|
||||
|
||||
@_explain.register
|
||||
|
||||
@@ -122,4 +122,4 @@ class HasProgressionPercent(CombinableStardewRule):
|
||||
return self, self(state)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Received {self.percent}% progression items."
|
||||
return f"Received {self.percent}% progression items"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Dict, List, Any, Tuple, TypedDict
|
||||
from typing import Dict, List, Any, Tuple, TypedDict, ClassVar, Union
|
||||
from logging import warning
|
||||
from BaseClasses import Region, Location, Item, Tutorial, ItemClassification, MultiWorld
|
||||
from .items import item_name_to_id, item_table, item_name_groups, fool_tiers, filler_items, slot_data_item_names
|
||||
@@ -13,6 +13,14 @@ from .options import (TunicOptions, EntranceRando, tunic_option_groups, tunic_op
|
||||
from worlds.AutoWorld import WebWorld, World
|
||||
from Options import PlandoConnection
|
||||
from decimal import Decimal, ROUND_HALF_UP
|
||||
from settings import Group, Bool
|
||||
|
||||
|
||||
class TunicSettings(Group):
|
||||
class DisableLocalSpoiler(Bool):
|
||||
"""Disallows the TUNIC client from creating a local spoiler log."""
|
||||
|
||||
disable_local_spoiler: Union[DisableLocalSpoiler, bool] = False
|
||||
|
||||
|
||||
class TunicWeb(WebWorld):
|
||||
@@ -60,6 +68,7 @@ class TunicWorld(World):
|
||||
|
||||
options: TunicOptions
|
||||
options_dataclass = TunicOptions
|
||||
settings: ClassVar[TunicSettings]
|
||||
item_name_groups = item_name_groups
|
||||
location_name_groups = location_name_groups
|
||||
|
||||
@@ -392,7 +401,8 @@ class TunicWorld(World):
|
||||
"Hexagon Quest Holy Cross": self.ability_unlocks["Pages 42-43 (Holy Cross)"],
|
||||
"Hexagon Quest Icebolt": self.ability_unlocks["Pages 52-53 (Icebolt)"],
|
||||
"Hexagon Quest Goal": self.options.hexagon_goal.value,
|
||||
"Entrance Rando": self.tunic_portal_pairs
|
||||
"Entrance Rando": self.tunic_portal_pairs,
|
||||
"disable_local_spoiler": int(self.settings.disable_local_spoiler or self.multiworld.is_race),
|
||||
}
|
||||
|
||||
for tunic_item in filter(lambda item: item.location is not None and item.code is not None, self.slot_data_items):
|
||||
|
||||
@@ -208,15 +208,15 @@ location_table: Dict[str, TunicLocationData] = {
|
||||
"Monastery - Monastery Chest": TunicLocationData("Monastery", "Monastery Back"),
|
||||
"Quarry - [Back Entrance] Bushes Holy Cross": TunicLocationData("Quarry Back", "Quarry Back", location_group="Holy Cross"),
|
||||
"Quarry - [Back Entrance] Chest": TunicLocationData("Quarry Back", "Quarry Back"),
|
||||
"Quarry - [Central] Near Shortcut Ladder": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [Central] Near Shortcut Ladder": TunicLocationData("Quarry Back", "Quarry Back"),
|
||||
"Quarry - [East] Near Telescope": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [East] Upper Floor": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [Central] Below Entry Walkway": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [Central] Below Entry Walkway": TunicLocationData("Quarry Back", "Quarry Back"),
|
||||
"Quarry - [East] Obscured Near Winding Staircase": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [East] Obscured Beneath Scaffolding": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [East] Obscured Near Telescope": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [Back Entrance] Obscured Behind Wall": TunicLocationData("Quarry Back", "Quarry Back"),
|
||||
"Quarry - [Central] Obscured Below Entry Walkway": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [Central] Obscured Below Entry Walkway": TunicLocationData("Quarry Back", "Quarry Back"),
|
||||
"Quarry - [Central] Top Floor Overhang": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [East] Near Bridge": TunicLocationData("Quarry", "Quarry"),
|
||||
"Quarry - [Central] Above Ladder": TunicLocationData("Quarry", "Quarry Monastery Entry"),
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
from typing import Dict, Set
|
||||
from typing import Dict, List
|
||||
|
||||
booster_contents: Dict[str, Set[str]] = {
|
||||
"LEGEND OF B.E.W.D.": {
|
||||
booster_contents: Dict[str, List[str]] = {
|
||||
"LEGEND OF B.E.W.D.": [
|
||||
"Exodia",
|
||||
"Dark Magician",
|
||||
"Polymerization",
|
||||
"Skull Servant"
|
||||
},
|
||||
"METAL RAIDERS": {
|
||||
],
|
||||
"METAL RAIDERS": [
|
||||
"Petit Moth",
|
||||
"Cocoon of Evolution",
|
||||
"Time Wizard",
|
||||
@@ -30,8 +30,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Solemn Judgment",
|
||||
"Dream Clown",
|
||||
"Heavy Storm"
|
||||
},
|
||||
"PHARAOH'S SERVANT": {
|
||||
],
|
||||
"PHARAOH'S SERVANT": [
|
||||
"Beast of Talwar",
|
||||
"Jinzo",
|
||||
"Gearfried the Iron Knight",
|
||||
@@ -43,8 +43,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"The Shallow Grave",
|
||||
"Nobleman of Crossout",
|
||||
"Magic Drain"
|
||||
},
|
||||
"PHARAONIC GUARDIAN": {
|
||||
],
|
||||
"PHARAONIC GUARDIAN": [
|
||||
"Don Zaloog",
|
||||
"Reasoning",
|
||||
"Dark Snake Syndrome",
|
||||
@@ -71,8 +71,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Book of Taiyou",
|
||||
"Dust Tornado",
|
||||
"Raigeki Break"
|
||||
},
|
||||
"SPELL RULER": {
|
||||
],
|
||||
"SPELL RULER": [
|
||||
"Ritual",
|
||||
"Messenger of Peace",
|
||||
"Megamorph",
|
||||
@@ -94,8 +94,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Senju of the Thousand Hands",
|
||||
"Sonic Bird",
|
||||
"Mystical Space Typhoon"
|
||||
},
|
||||
"LABYRINTH OF NIGHTMARE": {
|
||||
],
|
||||
"LABYRINTH OF NIGHTMARE": [
|
||||
"Destiny Board",
|
||||
"Spirit Message 'I'",
|
||||
"Spirit Message 'N'",
|
||||
@@ -119,8 +119,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"United We Stand",
|
||||
"Earthbound Spirit",
|
||||
"The Masked Beast"
|
||||
},
|
||||
"LEGACY OF DARKNESS": {
|
||||
],
|
||||
"LEGACY OF DARKNESS": [
|
||||
"Last Turn",
|
||||
"Yata-Garasu",
|
||||
"Opticlops",
|
||||
@@ -143,8 +143,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Maharaghi",
|
||||
"Susa Soldier",
|
||||
"Emergency Provisions",
|
||||
},
|
||||
"MAGICIAN'S FORCE": {
|
||||
],
|
||||
"MAGICIAN'S FORCE": [
|
||||
"Huge Revolution",
|
||||
"Oppressed People",
|
||||
"United Resistance",
|
||||
@@ -185,8 +185,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Royal Magical Library",
|
||||
"Spell Shield Type-8",
|
||||
"Tribute Doll",
|
||||
},
|
||||
"DARK CRISIS": {
|
||||
],
|
||||
"DARK CRISIS": [
|
||||
"Final Countdown",
|
||||
"Ojama Green",
|
||||
"Dark Scorpion Combination",
|
||||
@@ -213,8 +213,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Spell Reproduction",
|
||||
"Contract with the Abyss",
|
||||
"Dark Master - Zorc"
|
||||
},
|
||||
"INVASION OF CHAOS": {
|
||||
],
|
||||
"INVASION OF CHAOS": [
|
||||
"Ojama Delta Hurricane",
|
||||
"Ojama Yellow",
|
||||
"Ojama Black",
|
||||
@@ -241,8 +241,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Cursed Seal of the Forbidden Spell",
|
||||
"Stray Lambs",
|
||||
"Manju of the Ten Thousand Hands"
|
||||
},
|
||||
"ANCIENT SANCTUARY": {
|
||||
],
|
||||
"ANCIENT SANCTUARY": [
|
||||
"Monster Gate",
|
||||
"Wall of Revealing Light",
|
||||
"Mystik Wok",
|
||||
@@ -255,8 +255,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"King of the Swamp",
|
||||
"Enemy Controller",
|
||||
"Enchanting Fitting Room"
|
||||
},
|
||||
"SOUL OF THE DUELIST": {
|
||||
],
|
||||
"SOUL OF THE DUELIST": [
|
||||
"Ninja Grandmaster Sasuke",
|
||||
"Mystic Swordsman LV2",
|
||||
"Mystic Swordsman LV4",
|
||||
@@ -272,8 +272,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Level Up!",
|
||||
"Howling Insect",
|
||||
"Mobius the Frost Monarch"
|
||||
},
|
||||
"RISE OF DESTINY": {
|
||||
],
|
||||
"RISE OF DESTINY": [
|
||||
"Homunculus the Alchemic Being",
|
||||
"Thestalos the Firestorm Monarch",
|
||||
"Roc from the Valley of Haze",
|
||||
@@ -283,8 +283,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Ultimate Insect Lv3",
|
||||
"Divine Wrath",
|
||||
"Serial Spell"
|
||||
},
|
||||
"FLAMING ETERNITY": {
|
||||
],
|
||||
"FLAMING ETERNITY": [
|
||||
"Insect Knight",
|
||||
"Chiron the Mage",
|
||||
"Granmarg the Rock Monarch",
|
||||
@@ -297,8 +297,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Golem Sentry",
|
||||
"Rescue Cat",
|
||||
"Blade Rabbit"
|
||||
},
|
||||
"THE LOST MILLENIUM": {
|
||||
],
|
||||
"THE LOST MILLENIUM": [
|
||||
"Ritual",
|
||||
"Megarock Dragon",
|
||||
"D.D. Survivor",
|
||||
@@ -311,8 +311,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Elemental Hero Thunder Giant",
|
||||
"Aussa the Earth Charmer",
|
||||
"Brain Control"
|
||||
},
|
||||
"CYBERNETIC REVOLUTION": {
|
||||
],
|
||||
"CYBERNETIC REVOLUTION": [
|
||||
"Power Bond",
|
||||
"Cyber Dragon",
|
||||
"Cyber Twin Dragon",
|
||||
@@ -322,8 +322,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Miracle Fusion",
|
||||
"Elemental Hero Bubbleman",
|
||||
"Jerry Beans Man"
|
||||
},
|
||||
"ELEMENTAL ENERGY": {
|
||||
],
|
||||
"ELEMENTAL ENERGY": [
|
||||
"V-Tiger Jet",
|
||||
"W-Wing Catapult",
|
||||
"VW-Tiger Catapult",
|
||||
@@ -344,8 +344,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Elemental Hero Bladedge",
|
||||
"Pot of Avarice",
|
||||
"B.E.S. Tetran"
|
||||
},
|
||||
"SHADOW OF INFINITY": {
|
||||
],
|
||||
"SHADOW OF INFINITY": [
|
||||
"Hamon, Lord of Striking Thunder",
|
||||
"Raviel, Lord of Phantasms",
|
||||
"Uria, Lord of Searing Flames",
|
||||
@@ -357,8 +357,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Gokipon",
|
||||
"Demise, King of Armageddon",
|
||||
"Anteatereatingant"
|
||||
},
|
||||
"GAME GIFT COLLECTION": {
|
||||
],
|
||||
"GAME GIFT COLLECTION": [
|
||||
"Ritual",
|
||||
"Valkyrion the Magna Warrior",
|
||||
"Alpha the Magnet Warrior",
|
||||
@@ -383,8 +383,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Card Destruction",
|
||||
"Dark Magic Ritual",
|
||||
"Calamity of the Wicked"
|
||||
},
|
||||
"Special Gift Collection": {
|
||||
],
|
||||
"Special Gift Collection": [
|
||||
"Gate Guardian",
|
||||
"Scapegoat",
|
||||
"Gil Garth",
|
||||
@@ -398,8 +398,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Curse of Vampire",
|
||||
"Elemental Hero Flame Wingman",
|
||||
"Magician of Black Chaos"
|
||||
},
|
||||
"Fairy Collection": {
|
||||
],
|
||||
"Fairy Collection": [
|
||||
"Silpheed",
|
||||
"Dunames Dark Witch",
|
||||
"Hysteric Fairy",
|
||||
@@ -416,8 +416,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Asura Priest",
|
||||
"Manju of the Ten Thousand Hands",
|
||||
"Senju of the Thousand Hands"
|
||||
},
|
||||
"Dragon Collection": {
|
||||
],
|
||||
"Dragon Collection": [
|
||||
"Victory D.",
|
||||
"Chaos Emperor Dragon - Envoy of the End",
|
||||
"Kaiser Glider",
|
||||
@@ -434,16 +434,16 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Troop Dragon",
|
||||
"Horus the Black Flame Dragon LV4",
|
||||
"Pitch-Dark Dragon"
|
||||
},
|
||||
"Warrior Collection A": {
|
||||
],
|
||||
"Warrior Collection A": [
|
||||
"Gate Guardian",
|
||||
"Gearfried the Iron Knight",
|
||||
"Dimensional Warrior",
|
||||
"Command Knight",
|
||||
"The Last Warrior from Another Planet",
|
||||
"Dream Clown"
|
||||
},
|
||||
"Warrior Collection B": {
|
||||
],
|
||||
"Warrior Collection B": [
|
||||
"Don Zaloog",
|
||||
"Dark Scorpion - Chick the Yellow",
|
||||
"Dark Scorpion - Meanae the Thorn",
|
||||
@@ -467,8 +467,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Blade Knight",
|
||||
"Marauding Captain",
|
||||
"Toon Goblin Attack Force"
|
||||
},
|
||||
"Fiend Collection A": {
|
||||
],
|
||||
"Fiend Collection A": [
|
||||
"Sangan",
|
||||
"Castle of Dark Illusions",
|
||||
"Barox",
|
||||
@@ -480,8 +480,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Spear Cretin",
|
||||
"Versago the Destroyer",
|
||||
"Toon Summoned Skull"
|
||||
},
|
||||
"Fiend Collection B": {
|
||||
],
|
||||
"Fiend Collection B": [
|
||||
"Raviel, Lord of Phantasms",
|
||||
"Yata-Garasu",
|
||||
"Helpoemer",
|
||||
@@ -505,15 +505,15 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Jowls of Dark Demise",
|
||||
"D. D. Trainer",
|
||||
"Earthbound Spirit"
|
||||
},
|
||||
"Machine Collection A": {
|
||||
],
|
||||
"Machine Collection A": [
|
||||
"Cyber-Stein",
|
||||
"Mechanicalchaser",
|
||||
"Jinzo",
|
||||
"UFO Turtle",
|
||||
"Cyber-Tech Alligator"
|
||||
},
|
||||
"Machine Collection B": {
|
||||
],
|
||||
"Machine Collection B": [
|
||||
"X-Head Cannon",
|
||||
"Y-Dragon Head",
|
||||
"Z-Metal Tank",
|
||||
@@ -531,8 +531,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Red Gadget",
|
||||
"Yellow Gadget",
|
||||
"B.E.S. Tetran"
|
||||
},
|
||||
"Spellcaster Collection A": {
|
||||
],
|
||||
"Spellcaster Collection A": [
|
||||
"Exodia",
|
||||
"Dark Sage",
|
||||
"Dark Magician",
|
||||
@@ -544,8 +544,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Injection Fairy Lily",
|
||||
"Cosmo Queen",
|
||||
"Magician of Black Chaos"
|
||||
},
|
||||
"Spellcaster Collection B": {
|
||||
],
|
||||
"Spellcaster Collection B": [
|
||||
"Jowgen the Spiritualist",
|
||||
"Tsukuyomi",
|
||||
"Manticore of Darkness",
|
||||
@@ -574,8 +574,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Royal Magical Library",
|
||||
"Aussa the Earth Charmer",
|
||||
|
||||
},
|
||||
"Zombie Collection": {
|
||||
],
|
||||
"Zombie Collection": [
|
||||
"Skull Servant",
|
||||
"Regenerating Mummy",
|
||||
"Ryu Kokki",
|
||||
@@ -590,8 +590,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Des Lacooda",
|
||||
"Wandering Mummy",
|
||||
"Royal Keeper"
|
||||
},
|
||||
"Special Monsters A": {
|
||||
],
|
||||
"Special Monsters A": [
|
||||
"X-Head Cannon",
|
||||
"Y-Dragon Head",
|
||||
"Z-Metal Tank",
|
||||
@@ -626,8 +626,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Fushi No Tori",
|
||||
"Maharaghi",
|
||||
"Susa Soldier"
|
||||
},
|
||||
"Special Monsters B": {
|
||||
],
|
||||
"Special Monsters B": [
|
||||
"Polymerization",
|
||||
"Mystic Swordsman LV2",
|
||||
"Mystic Swordsman LV4",
|
||||
@@ -656,8 +656,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Level Up!",
|
||||
"Ultimate Insect Lv3",
|
||||
"Ultimate Insect Lv5"
|
||||
},
|
||||
"Reverse Collection": {
|
||||
],
|
||||
"Reverse Collection": [
|
||||
"Magical Merchant",
|
||||
"Castle of Dark Illusions",
|
||||
"Magician of Faith",
|
||||
@@ -675,8 +675,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Spear Cretin",
|
||||
"Nobleman of Crossout",
|
||||
"Aussa the Earth Charmer"
|
||||
},
|
||||
"LP Recovery Collection": {
|
||||
],
|
||||
"LP Recovery Collection": [
|
||||
"Mystik Wok",
|
||||
"Poison of the Old Man",
|
||||
"Hysteric Fairy",
|
||||
@@ -691,8 +691,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Elemental Hero Steam Healer",
|
||||
"Fushi No Tori",
|
||||
"Emergency Provisions"
|
||||
},
|
||||
"Special Summon Collection A": {
|
||||
],
|
||||
"Special Summon Collection A": [
|
||||
"Perfectly Ultimate Great Moth",
|
||||
"Dark Sage",
|
||||
"Polymerization",
|
||||
@@ -726,8 +726,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Morphing Jar #2",
|
||||
"Spear Cretin",
|
||||
"Dark Magic Curtain"
|
||||
},
|
||||
"Special Summon Collection B": {
|
||||
],
|
||||
"Special Summon Collection B": [
|
||||
"Monster Gate",
|
||||
"Chaos Emperor Dragon - Envoy of the End",
|
||||
"Ojama Trio",
|
||||
@@ -756,8 +756,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Tribute Doll",
|
||||
"Enchanting Fitting Room",
|
||||
"Stray Lambs"
|
||||
},
|
||||
"Special Summon Collection C": {
|
||||
],
|
||||
"Special Summon Collection C": [
|
||||
"Hamon, Lord of Striking Thunder",
|
||||
"Raviel, Lord of Phantasms",
|
||||
"Uria, Lord of Searing Flames",
|
||||
@@ -782,13 +782,13 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Ultimate Insect Lv5",
|
||||
"Rescue Cat",
|
||||
"Anteatereatingant"
|
||||
},
|
||||
"Equipment Collection": {
|
||||
],
|
||||
"Equipment Collection": [
|
||||
"Megamorph",
|
||||
"Cestus of Dagla",
|
||||
"United We Stand"
|
||||
},
|
||||
"Continuous Spell/Trap A": {
|
||||
],
|
||||
"Continuous Spell/Trap A": [
|
||||
"Destiny Board",
|
||||
"Spirit Message 'I'",
|
||||
"Spirit Message 'N'",
|
||||
@@ -801,8 +801,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Solemn Wishes",
|
||||
"Embodiment of Apophis",
|
||||
"Toon World"
|
||||
},
|
||||
"Continuous Spell/Trap B": {
|
||||
],
|
||||
"Continuous Spell/Trap B": [
|
||||
"Hamon, Lord of Striking Thunder",
|
||||
"Uria, Lord of Searing Flames",
|
||||
"Wave-Motion Cannon",
|
||||
@@ -815,8 +815,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Skull Zoma",
|
||||
"Pitch-Black Power Stone",
|
||||
"Metal Reflect Slime"
|
||||
},
|
||||
"Quick/Counter Collection": {
|
||||
],
|
||||
"Quick/Counter Collection": [
|
||||
"Mystik Wok",
|
||||
"Poison of the Old Man",
|
||||
"Scapegoat",
|
||||
@@ -841,8 +841,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Book of Moon",
|
||||
"Serial Spell",
|
||||
"Mystical Space Typhoon"
|
||||
},
|
||||
"Direct Damage Collection": {
|
||||
],
|
||||
"Direct Damage Collection": [
|
||||
"Hamon, Lord of Striking Thunder",
|
||||
"Chaos Emperor Dragon - Envoy of the End",
|
||||
"Dark Snake Syndrome",
|
||||
@@ -868,8 +868,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Jowls of Dark Demise",
|
||||
"Stealth Bird",
|
||||
"Elemental Hero Bladedge",
|
||||
},
|
||||
"Direct Attack Collection": {
|
||||
],
|
||||
"Direct Attack Collection": [
|
||||
"Victory D.",
|
||||
"Dark Scorpion Combination",
|
||||
"Spirit Reaper",
|
||||
@@ -880,8 +880,8 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Toon Mermaid",
|
||||
"Toon Summoned Skull",
|
||||
"Toon Dark Magician Girl"
|
||||
},
|
||||
"Monster Destroy Collection": {
|
||||
],
|
||||
"Monster Destroy Collection": [
|
||||
"Hamon, Lord of Striking Thunder",
|
||||
"Inferno",
|
||||
"Ninja Grandmaster Sasuke",
|
||||
@@ -912,12 +912,12 @@ booster_contents: Dict[str, Set[str]] = {
|
||||
"Offerings to the Doomed",
|
||||
"Divine Wrath",
|
||||
"Dream Clown"
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def get_booster_locations(booster: str) -> Dict[str, str]:
|
||||
return {
|
||||
f"{booster} {i}": content
|
||||
for i, content in enumerate(booster_contents[booster])
|
||||
for i, content in enumerate(booster_contents[booster], 1)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from typing import Dict, Set
|
||||
from typing import Dict, List
|
||||
|
||||
structure_contents: Dict[str, Set] = {
|
||||
"dragons_roar": {
|
||||
structure_contents: Dict[str, List[str]] = {
|
||||
"dragons_roar": [
|
||||
"Luster Dragon",
|
||||
"Armed Dragon LV3",
|
||||
"Armed Dragon LV5",
|
||||
@@ -14,9 +14,9 @@ structure_contents: Dict[str, Set] = {
|
||||
"Stamping Destruction",
|
||||
"Heavy Storm",
|
||||
"Dust Tornado",
|
||||
"Mystical Space Typhoon",
|
||||
},
|
||||
"zombie_madness": {
|
||||
"Mystical Space Typhoon"
|
||||
],
|
||||
"zombie_madness": [
|
||||
"Pyramid Turtle",
|
||||
"Regenerating Mummy",
|
||||
"Ryu Kokki",
|
||||
@@ -26,9 +26,9 @@ structure_contents: Dict[str, Set] = {
|
||||
"Reload",
|
||||
"Heavy Storm",
|
||||
"Dust Tornado",
|
||||
"Mystical Space Typhoon",
|
||||
},
|
||||
"blazing_destruction": {
|
||||
"Mystical Space Typhoon"
|
||||
],
|
||||
"blazing_destruction": [
|
||||
"Inferno",
|
||||
"Solar Flare Dragon",
|
||||
"UFO Turtle",
|
||||
@@ -38,9 +38,9 @@ structure_contents: Dict[str, Set] = {
|
||||
"Level Limit - Area B",
|
||||
"Heavy Storm",
|
||||
"Dust Tornado",
|
||||
"Mystical Space Typhoon",
|
||||
},
|
||||
"fury_from_the_deep": {
|
||||
"Mystical Space Typhoon"
|
||||
],
|
||||
"fury_from_the_deep": [
|
||||
"Mother Grizzly",
|
||||
"Water Beaters",
|
||||
"Gravity Bind",
|
||||
@@ -48,9 +48,9 @@ structure_contents: Dict[str, Set] = {
|
||||
"Mobius the Frost Monarch",
|
||||
"Heavy Storm",
|
||||
"Dust Tornado",
|
||||
"Mystical Space Typhoon",
|
||||
},
|
||||
"warriors_triumph": {
|
||||
"Mystical Space Typhoon"
|
||||
],
|
||||
"warriors_triumph": [
|
||||
"Gearfried the Iron Knight",
|
||||
"D.D. Warrior Lady",
|
||||
"Marauding Captain",
|
||||
@@ -60,9 +60,9 @@ structure_contents: Dict[str, Set] = {
|
||||
"Reload",
|
||||
"Heavy Storm",
|
||||
"Dust Tornado",
|
||||
"Mystical Space Typhoon",
|
||||
},
|
||||
"spellcasters_judgement": {
|
||||
"Mystical Space Typhoon"
|
||||
],
|
||||
"spellcasters_judgement": [
|
||||
"Dark Magician",
|
||||
"Apprentice Magician",
|
||||
"Breaker the Magical Warrior",
|
||||
@@ -70,14 +70,18 @@ structure_contents: Dict[str, Set] = {
|
||||
"Skilled Dark Magician",
|
||||
"Tsukuyomi",
|
||||
"Magical Dimension",
|
||||
"Mage PowerSpell-Counter Cards",
|
||||
"Mage Power",
|
||||
"Spell-Counter Cards",
|
||||
"Heavy Storm",
|
||||
"Dust Tornado",
|
||||
"Mystical Space Typhoon",
|
||||
},
|
||||
"none": {},
|
||||
"Mystical Space Typhoon"
|
||||
],
|
||||
"none": [],
|
||||
}
|
||||
|
||||
|
||||
def get_deck_content_locations(deck: str) -> Dict[str, str]:
|
||||
return {f"{deck} {i}": content for i, content in enumerate(structure_contents[deck])}
|
||||
return {
|
||||
f"{deck} {i}": content
|
||||
for i, content in enumerate(structure_contents[deck], 1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user