parent
							
								
									3aacaffe6b
								
							
						
					
					
						commit
						48dd1a1aa6
					
				| 
						 | 
				
			
			@ -29,7 +29,6 @@ game: # Pick a game to play
 | 
			
		|||
  Minecraft: 0
 | 
			
		||||
  Subnautica: 0
 | 
			
		||||
  Slay the Spire: 0
 | 
			
		||||
  Terraria: 0
 | 
			
		||||
requires:
 | 
			
		||||
  version: 0.1.6 # Version of Archipelago required for this yaml to work as expected.
 | 
			
		||||
# Shared Options supported by all games:
 | 
			
		||||
| 
						 | 
				
			
			@ -280,18 +279,6 @@ Minecraft:
 | 
			
		|||
  send_defeated_mobs: # Send killed mobs to other Minecraft worlds which have this option enabled.
 | 
			
		||||
    on: 0
 | 
			
		||||
    off: 1
 | 
			
		||||
Terraria:
 | 
			
		||||
  include_hardmode_achievements: # Junk-fills achievements which can only be obtained after defeating the Wall of Flesh.
 | 
			
		||||
    on: 0
 | 
			
		||||
    off: 1
 | 
			
		||||
  # Junk-fills extremely difficult advancements; this is primarily for achievements which require completing large parts of the game 
 | 
			
		||||
  # (such as gelatin world tour or Real Estate Agent) as well as the more advanced fishing quests.
 | 
			
		||||
  include_insane_achievements: 
 | 
			
		||||
    on: 0
 | 
			
		||||
    off: 1
 | 
			
		||||
  include_postgame_achievements: # Some achievements require defeating the Moon Lord first; this will junk-fill them so you won't have to finish to send some items.
 | 
			
		||||
    on: 0
 | 
			
		||||
    off: 1
 | 
			
		||||
A Link to the Past:
 | 
			
		||||
  ### Logic Section ###
 | 
			
		||||
  glitches_required: # Determine the logic required to complete the seed
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,26 +0,0 @@
 | 
			
		|||
from BaseClasses import Item
 | 
			
		||||
import typing
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ItemData(typing.NamedTuple):
 | 
			
		||||
    code: typing.Optional[int]
 | 
			
		||||
    progression: bool
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TerrariaItem(Item):
 | 
			
		||||
    game: str = "Terraria"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
item_table = {
 | 
			
		||||
    "Copper Shortsword": ItemData(73001, False),
 | 
			
		||||
 | 
			
		||||
    "Victory": ItemData(73000, True)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# If not listed here then has frequency 1
 | 
			
		||||
item_frequencies = {
 | 
			
		||||
    "Copper Shortsword": 87,
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lookup_id_to_name: typing.Dict[int, str] = {data.code: item_name for item_name, data in item_table.items() if data.code}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,166 +0,0 @@
 | 
			
		|||
from BaseClasses import Location
 | 
			
		||||
import typing
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class AchieveData(typing.NamedTuple):
 | 
			
		||||
    id: typing.Optional[int]
 | 
			
		||||
    region: str
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TerrariaAchievement(Location):
 | 
			
		||||
    game: str = "Terraria"
 | 
			
		||||
 | 
			
		||||
    def __init__(self, player: int, name: str, address: typing.Optional[int], parent):
 | 
			
		||||
        super().__init__(player, name, address, parent)
 | 
			
		||||
        self.event = not address
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
achievement_table = {
 | 
			
		||||
    "Timber!!": AchieveData(0, "Overworld"),
 | 
			
		||||
    "No Hobo": AchieveData(1, "Overworld"),
 | 
			
		||||
    "Stop! Hammer Time!": AchieveData(2, "Overworld"),
 | 
			
		||||
    "Ooo! Shiny!": AchieveData(3, "Overworld"),
 | 
			
		||||
    "Heart Breaker": AchieveData(4, "Overworld"),
 | 
			
		||||
    "Heavy Metal": AchieveData(5, "Overworld"),
 | 
			
		||||
    "I Am Loot!": AchieveData(6, "Overworld"),
 | 
			
		||||
    "Star Power": AchieveData(7, "Overworld"),
 | 
			
		||||
    "Hold on Tight!": AchieveData(8, "Overworld"),
 | 
			
		||||
    "Eye on You": AchieveData(9, "Overworld"),
 | 
			
		||||
    "Smashing, Poppet!": AchieveData(10, "Overworld"),
 | 
			
		||||
    "Worm Fodder": AchieveData(11, "Corruption"),
 | 
			
		||||
    "Mastermind": AchieveData(12, "Crimson"),
 | 
			
		||||
    "Where's My Honey?": AchieveData(13, "Jungle"),
 | 
			
		||||
    "Sting Operation": AchieveData(14, "Jungle"),
 | 
			
		||||
    "Boned": AchieveData(15, "Overworld"),
 | 
			
		||||
    "Dungeon Heist": AchieveData(16, "Dungeon"),
 | 
			
		||||
    "It's Getting Hot in Here": AchieveData(17, "Underworld"),
 | 
			
		||||
    "Miner for Fire": AchieveData(18, "Underworld"),
 | 
			
		||||
    "Still Hungry": AchieveData(19, "Underworld"),
 | 
			
		||||
    "It's Hard!": AchieveData(20, "Underworld"),
 | 
			
		||||
    "Begone, Evil!": AchieveData(21, "Hardmode"),
 | 
			
		||||
    "Extra Shiny!": AchieveData(22, "Hardmode"),
 | 
			
		||||
    "Head in the Clouds": AchieveData(23, "Hardmode"),
 | 
			
		||||
    "Like a Boss": AchieveData(24, "Overworld"),
 | 
			
		||||
    "Buckets of Bolts": AchieveData(25, "Hardmode"),
 | 
			
		||||
    "Drax Attax": AchieveData(26, "Hardmode"),
 | 
			
		||||
    "Photosynthesis": AchieveData(27, "Hardmode Jungle"),
 | 
			
		||||
    "Get a Life": AchieveData(28, "Hardmode Jungle"),
 | 
			
		||||
    "The Great Southern Plantkill": AchieveData(29, "Hardmode Jungle"),
 | 
			
		||||
    "Temple Raider": AchieveData(30, "Post-Plantera"),
 | 
			
		||||
    "Lihzahrdian Idol": AchieveData(31, "Post-Plantera"),
 | 
			
		||||
    "Robbing the Grave": AchieveData(32, "Post-Plantera"),
 | 
			
		||||
    "Big Booty": AchieveData(33, "Post-Plantera"),
 | 
			
		||||
    "Fish Out of Water": AchieveData(34, "Overworld"),
 | 
			
		||||
    "Obsessive Devotion": AchieveData(35, "Post-Golem"),
 | 
			
		||||
    "Star Destroyer": AchieveData(36, "Post-Golem"),
 | 
			
		||||
    "Champion of Terraria": AchieveData(37, "Post-Golem"),
 | 
			
		||||
    "Bloodbath": AchieveData(38, "Overworld"),
 | 
			
		||||
    "Slippery Shinobi": AchieveData(39, "Overworld"),
 | 
			
		||||
    "Goblin Punter": AchieveData(40, "Overworld"),
 | 
			
		||||
    "Walk the Plank": AchieveData(41, "Hardmode"),
 | 
			
		||||
    "Kill the Sun": AchieveData(42, "Hardmode"),
 | 
			
		||||
    "Do You Want to Slay a Snowman?": AchieveData(43, "Hardmode"),
 | 
			
		||||
    "Tin-Foil Hatter": AchieveData(44, "Post-Golem"),
 | 
			
		||||
    "Baleful Harvest": AchieveData(45, "Post-Plantera"),
 | 
			
		||||
    "Ice Scream": AchieveData(46, "Post-Plantera"),
 | 
			
		||||
    "Sticky Situation": AchieveData(47, "Overworld"),
 | 
			
		||||
    "Real Estate Agent": AchieveData(48, "Postgame"),
 | 
			
		||||
    "Not the Bees!": AchieveData(49, "Jungle"),
 | 
			
		||||
    "Jeepers Creepers": AchieveData(50, "Overworld"),
 | 
			
		||||
    "Funkytown": AchieveData(51, "Overworld"),
 | 
			
		||||
    "Into Orbit": AchieveData(52, "Overworld"),
 | 
			
		||||
    "Rock Bottom": AchieveData(53, "Underworld"),
 | 
			
		||||
    "Mecha Mayhem": AchieveData(54, "Hardmode"),
 | 
			
		||||
    "Gelatin World Tour": AchieveData(55, "Postgame"),
 | 
			
		||||
    "Fashion Statement": AchieveData(56, "Overworld"),
 | 
			
		||||
    "Vehicular Manslaughter": AchieveData(57, "Overworld"),
 | 
			
		||||
    "Bulldozer": AchieveData(58, "Overworld"),
 | 
			
		||||
    "There are Some Who Call Him...": AchieveData(59, "Overworld"),
 | 
			
		||||
    "Deceiver of Fools": AchieveData(60, "Overworld"),
 | 
			
		||||
    "Sword of the Hero": AchieveData(61, "Hardmode"),
 | 
			
		||||
    "Lucky Break": AchieveData(62, "Overworld"),
 | 
			
		||||
    "Throwing Lines": AchieveData(63, "Overworld"),
 | 
			
		||||
    "Dye Hard": AchieveData(64, "Overworld"),
 | 
			
		||||
    "Sick Throw": AchieveData(65, "Postgame"),
 | 
			
		||||
    "The Frequent Flyer": AchieveData(66, "Overworld"),
 | 
			
		||||
    "The Cavalry": AchieveData(67, "Overworld"),
 | 
			
		||||
    "Completely Awesome": AchieveData(68, "Overworld"),
 | 
			
		||||
    "Til Death...": AchieveData(69, "Overworld"),
 | 
			
		||||
    "Archaeologist": AchieveData(70, "Jungle"),
 | 
			
		||||
    "Pretty in Pink": AchieveData(71, "Overworld"),
 | 
			
		||||
    "Rainbows and Unicorns": AchieveData(72, "Hardmode"),
 | 
			
		||||
    "You and What Army?": AchieveData(73, "Hardmode"),
 | 
			
		||||
    "Prismancer": AchieveData(74, "Hardmode"),
 | 
			
		||||
    "It Can Talk?!": AchieveData(75, "Hardmode"),
 | 
			
		||||
    "Watch Your Step!": AchieveData(76, "Overworld"),
 | 
			
		||||
    "Marathon Medalist": AchieveData(77, "Overworld"),
 | 
			
		||||
    "Glorious Golden Pole": AchieveData(78, "Overworld"),
 | 
			
		||||
    "Servant-in-Training": AchieveData(79, "Overworld"),
 | 
			
		||||
    "Good Little Slave": AchieveData(80, "Overworld"),
 | 
			
		||||
    "Trout Monkey": AchieveData(81, "Overworld"),
 | 
			
		||||
    "Fast and Fishious": AchieveData(82, "Overworld"),
 | 
			
		||||
    "Supreme Helper Minion!": AchieveData(83, "Overworld"),
 | 
			
		||||
    "Topped Off": AchieveData(84, "Hardmode"),
 | 
			
		||||
    "Slayer of Worlds": AchieveData(85, "Postgame"),
 | 
			
		||||
    "You Can Do It!": AchieveData(86, "Overworld"),
 | 
			
		||||
    "Matching Attire": AchieveData(87, "Overworld"),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exclusion_table = {
 | 
			
		||||
    "hardmode": {
 | 
			
		||||
        "It's Hard!",
 | 
			
		||||
        "Extra Shiny!",
 | 
			
		||||
        "Head in the Clouds",
 | 
			
		||||
        "Buckets of Bolts",
 | 
			
		||||
        "Drax Attax",
 | 
			
		||||
        "Photosynthesis",
 | 
			
		||||
        "Get a Life",
 | 
			
		||||
        "The Great Southern Plantkill",
 | 
			
		||||
        "Temple Raider",
 | 
			
		||||
        "Lihzahrdian Idol",
 | 
			
		||||
        "Robbing the Grave",
 | 
			
		||||
        "Big Booty",
 | 
			
		||||
        "Fish Out of Water",
 | 
			
		||||
        "Obsessive Devotion",
 | 
			
		||||
        "Star Destroyer",
 | 
			
		||||
        "Champion of Terraria",
 | 
			
		||||
        "Walk the Plank",
 | 
			
		||||
        "Kill the Sun",
 | 
			
		||||
        "Do You Want to Slay a Snowman?",
 | 
			
		||||
        "Tin-Foil Hatter",
 | 
			
		||||
        "Baleful Harvest",
 | 
			
		||||
        "Ice Scream",
 | 
			
		||||
        "Real Estate Agent",
 | 
			
		||||
        "Mecha Mayhem",
 | 
			
		||||
        "Gelatin World Tour",
 | 
			
		||||
        "Sword of the Hero",
 | 
			
		||||
        "Sick Throw",
 | 
			
		||||
        "Rainbows and Unicorns",
 | 
			
		||||
        "You and What Army?",
 | 
			
		||||
        "Prismancer",
 | 
			
		||||
        "It Can Talk?!",
 | 
			
		||||
        "Topped Off",
 | 
			
		||||
        "Slayer of Worlds",
 | 
			
		||||
    },
 | 
			
		||||
    "insane": {
 | 
			
		||||
        "Gelatin World Tour",
 | 
			
		||||
        "Fast and Fishious",
 | 
			
		||||
        "Supreme Helper Minion!",
 | 
			
		||||
        "Real Estate Agent",
 | 
			
		||||
        "Mecha Mayhem",
 | 
			
		||||
        "Bulldozer",
 | 
			
		||||
        "Marathon Medalist",
 | 
			
		||||
        "Slayer of Worlds",
 | 
			
		||||
    },
 | 
			
		||||
    "postgame": {
 | 
			
		||||
        "Slayer of Worlds",
 | 
			
		||||
        "Sick Throw",
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
events_table = {
 | 
			
		||||
    "Still Hungry": "Victory"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
lookup_id_to_name: typing.Dict[int, str] = {loc_data.id: loc_name for loc_name, loc_data in achievement_table.items() if
 | 
			
		||||
                                            loc_data.id}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,8 +0,0 @@
 | 
			
		|||
import typing
 | 
			
		||||
from Options import Choice, Option, Toggle, Range
 | 
			
		||||
 | 
			
		||||
terraria_options: typing.Dict[str, type(Option)] = {
 | 
			
		||||
    "include_hardmode_achievements": Toggle,
 | 
			
		||||
    "include_insane_achievements": Toggle,
 | 
			
		||||
    "include_postgame_achievements": Toggle,
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,85 +0,0 @@
 | 
			
		|||
 | 
			
		||||
def link_terraria_structures(world, player):
 | 
			
		||||
 | 
			
		||||
    # Link mandatory connections first
 | 
			
		||||
    for (exit, region) in mandatory_connections:
 | 
			
		||||
        world.get_entrance(exit, player).connect(world.get_region(region, player))
 | 
			
		||||
 | 
			
		||||
    # Get all unpaired exits and all regions without entrances (except the Menu)
 | 
			
		||||
    # This function is destructive on these lists. 
 | 
			
		||||
    exits = [exit.name for r in world.regions if r.player == player for exit in r.exits if exit.connected_region == None]
 | 
			
		||||
    structs = [r.name for r in world.regions if r.player == player and r.entrances == [] and r.name != 'Menu']
 | 
			
		||||
    exits_spoiler = exits[:] # copy the original order for the spoiler log
 | 
			
		||||
    #try: 
 | 
			
		||||
    #    assert len(exits) == len(structs)
 | 
			
		||||
    #except AssertionError as e: # this should never happen
 | 
			
		||||
    #    raise Exception(f"Could not obtain equal numbers of Minecraft exits and structures for player {player} ({world.player_names[player]})")
 | 
			
		||||
 | 
			
		||||
    pairs = {}
 | 
			
		||||
 | 
			
		||||
    def set_pair(exit, struct): 
 | 
			
		||||
        if (exit in exits) and (struct in structs) and (exit not in illegal_connections.get(struct, [])):
 | 
			
		||||
            pairs[exit] = struct
 | 
			
		||||
            exits.remove(exit)
 | 
			
		||||
            structs.remove(struct)
 | 
			
		||||
        else: 
 | 
			
		||||
            raise Exception(f"Invalid connection: {exit} => {struct} for player {player} ({world.player_names[player]})")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    for (exit, struct) in default_connections: 
 | 
			
		||||
        if exit in exits: 
 | 
			
		||||
            set_pair(exit, struct)
 | 
			
		||||
 | 
			
		||||
    # Make sure we actually paired everything; might fail if plando
 | 
			
		||||
    try:
 | 
			
		||||
        assert len(exits) == len(structs) == 0
 | 
			
		||||
    except AssertionError: 
 | 
			
		||||
        raise Exception(f"Failed to connect all Minecraft structures for player {player} ({world.player_names[player]})")
 | 
			
		||||
 | 
			
		||||
    for exit in exits_spoiler:
 | 
			
		||||
        world.get_entrance(exit, player).connect(world.get_region(pairs[exit], player))
 | 
			
		||||
        if world.shuffle_structures[player] or world.plando_connections[player]:
 | 
			
		||||
            world.spoiler.set_entrance(exit, pairs[exit], 'entrance', player)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# (Region name, list of exits)
 | 
			
		||||
terraria_regions = [
 | 
			
		||||
    ('Menu', ['New World']),
 | 
			
		||||
    ('Overworld', ['Descend to Underworld', 'Go to Jungle', 'Go to Dungeon', 'Go to Corruption', 'Go to Crimson']),
 | 
			
		||||
    ('Underworld', ['Kill WoF']),
 | 
			
		||||
    ('Jungle', []),
 | 
			
		||||
    ('Corruption', []),
 | 
			
		||||
    ('Crimson', []),
 | 
			
		||||
    ('Dungeon', []),
 | 
			
		||||
    ('Hardmode Jungle', []),
 | 
			
		||||
    ('Hardmode', ['Kill Plantera', 'Go to Hardmode Jungle']),
 | 
			
		||||
    ('Post-Plantera', ['Kill Golem']),
 | 
			
		||||
    ('Post-Golem', ['Kill Moon Lord']),
 | 
			
		||||
    ('Postgame', [])
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
# (Entrance, region pointed to)
 | 
			
		||||
mandatory_connections = [
 | 
			
		||||
    ('New World', 'Overworld'),
 | 
			
		||||
    ('Descend to Underworld', 'Underworld'),
 | 
			
		||||
    ('Go to Jungle', 'Jungle'),
 | 
			
		||||
    ('Go to Corruption', 'Corruption'),
 | 
			
		||||
    ('Go to Crimson', 'Crimson'),
 | 
			
		||||
    ('Go to Hardmode Jungle', 'Hardmode Jungle'),
 | 
			
		||||
    ('Go to Dungeon', 'Dungeon'),
 | 
			
		||||
    ('Kill WoF', 'Hardmode'),
 | 
			
		||||
    ('Kill Plantera', 'Post-Plantera'),
 | 
			
		||||
    ('Kill Golem', 'Post-Golem'),
 | 
			
		||||
    ('Kill Moon Lord', 'Postgame'),
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
default_connections = {
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# Structure: illegal locations
 | 
			
		||||
illegal_connections = {
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,43 +0,0 @@
 | 
			
		|||
from ..generic.Rules import set_rule
 | 
			
		||||
from .Locations import exclusion_table, events_table
 | 
			
		||||
from BaseClasses import MultiWorld
 | 
			
		||||
from ..AutoWorld import LogicMixin
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TerrariaLogic(LogicMixin):
 | 
			
		||||
    # Defs here
 | 
			
		||||
    
 | 
			
		||||
    def temp(self, player: int):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
def set_rules(world: MultiWorld, player: int):
 | 
			
		||||
    def reachable_locations(state):
 | 
			
		||||
        postgame_advancements = exclusion_table['postgame'].copy()
 | 
			
		||||
        for event in events_table.keys():
 | 
			
		||||
            postgame_advancements.add(event)
 | 
			
		||||
        return [location for location in world.get_locations() if
 | 
			
		||||
                location.player == player and
 | 
			
		||||
                location.name not in postgame_advancements and
 | 
			
		||||
                location.can_reach(state)]
 | 
			
		||||
 | 
			
		||||
    # 88 total achievements. Goal is to defeat Wall of Flesh. 
 | 
			
		||||
    goal = 20#int(world.achievement_goal[player].value)
 | 
			
		||||
    can_complete = lambda state: len(reachable_locations(state)) >= goal and state.can_reach('Hardmode', 'Region', player)
 | 
			
		||||
 | 
			
		||||
    if world.logic[player] != 'nologic':
 | 
			
		||||
        world.completion_condition[player] = lambda state: state.has('Victory', player)
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_entrance("Kill WoF", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Kill Plantera", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Kill Golem", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Kill Moon Lord", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Descend to Underworld", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Go to Corruption", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Go to Crimson", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Go to Dungeon", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Go to Jungle", player), lambda state: True)
 | 
			
		||||
    set_rule(world.get_entrance("Go to Hardmode Jungle", player), lambda state: True)
 | 
			
		||||
 | 
			
		||||
    set_rule(world.get_location("Still Hungry", player), lambda state: can_complete(state))
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -1,99 +0,0 @@
 | 
			
		|||
import os
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from .Items import TerrariaItem, item_table, item_frequencies
 | 
			
		||||
from .Locations import TerrariaAchievement, achievement_table, exclusion_table, events_table
 | 
			
		||||
from .Regions import terraria_regions, link_terraria_structures, default_connections
 | 
			
		||||
from .Rules import set_rules
 | 
			
		||||
from worlds.generic.Rules import exclusion_rules
 | 
			
		||||
 | 
			
		||||
from BaseClasses import Region, Entrance, Item
 | 
			
		||||
from .Options import terraria_options
 | 
			
		||||
from ..AutoWorld import World
 | 
			
		||||
 | 
			
		||||
client_version = 5
 | 
			
		||||
 | 
			
		||||
class TerrariaWorld(World):
 | 
			
		||||
    game: str = "Terraria"
 | 
			
		||||
    options = terraria_options
 | 
			
		||||
    topology_present = True
 | 
			
		||||
 | 
			
		||||
    item_name_to_id = {name: data.code for name, data in item_table.items()}
 | 
			
		||||
    location_name_to_id = {name: data.id for name, data in achievement_table.items()}
 | 
			
		||||
 | 
			
		||||
    data_version = 2
 | 
			
		||||
 | 
			
		||||
    def _get_terraria_data(self):
 | 
			
		||||
        exits = [connection[0] for connection in default_connections]
 | 
			
		||||
        return {
 | 
			
		||||
            'world_seed': self.world.slot_seeds[self.player].getrandbits(32),
 | 
			
		||||
            # consistent and doesn't interfere with other generation
 | 
			
		||||
            'seed_name': self.world.seed_name,
 | 
			
		||||
            'player_name': self.world.get_player_name(self.player),
 | 
			
		||||
            'player_id': self.player,
 | 
			
		||||
            'client_version': client_version,
 | 
			
		||||
            'race': self.world.is_race
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    def generate_basic(self):
 | 
			
		||||
 | 
			
		||||
        # Generate item pool
 | 
			
		||||
        itempool = []
 | 
			
		||||
        pool_counts = item_frequencies.copy()
 | 
			
		||||
        for item_name in item_table:
 | 
			
		||||
            for count in range(pool_counts.get(item_name, 1)):
 | 
			
		||||
                itempool.append(self.create_item(item_name))
 | 
			
		||||
 | 
			
		||||
        # Choose locations to automatically exclude based on settings
 | 
			
		||||
        exclusion_pool = set()
 | 
			
		||||
        exclusion_types = ['hardmode', 'insane', 'postgame']
 | 
			
		||||
        for key in exclusion_types:
 | 
			
		||||
            if not getattr(self.world, f"include_{key}_achievements")[self.player]:
 | 
			
		||||
                exclusion_pool.update(exclusion_table[key])
 | 
			
		||||
        exclusion_rules(self.world, self.player, exclusion_pool)
 | 
			
		||||
 | 
			
		||||
        # Prefill the Wall of Flesh with the completion condition
 | 
			
		||||
        completion = self.create_item("Victory")
 | 
			
		||||
        self.world.get_location("Still Hungry", self.player).place_locked_item(completion)
 | 
			
		||||
        itempool.remove(completion)
 | 
			
		||||
        self.world.itempool += itempool
 | 
			
		||||
 | 
			
		||||
    def set_rules(self):
 | 
			
		||||
        set_rules(self.world, self.player)
 | 
			
		||||
 | 
			
		||||
    def create_regions(self):
 | 
			
		||||
        def TerrariaRegion(region_name: str, exits=[]):
 | 
			
		||||
            ret = Region(region_name, None, region_name, self.player, self.world)
 | 
			
		||||
            ret.locations = [TerrariaAchievement(self.player, loc_name, loc_data.id, ret)
 | 
			
		||||
                for loc_name, loc_data in achievement_table.items() 
 | 
			
		||||
                if loc_data.region == region_name]
 | 
			
		||||
            for exit in exits: 
 | 
			
		||||
                ret.exits.append(Entrance(self.player, exit, ret))
 | 
			
		||||
            return ret
 | 
			
		||||
 | 
			
		||||
        self.world.regions += [TerrariaRegion(*r) for r in terraria_regions]
 | 
			
		||||
        link_terraria_structures(self.world, self.player)
 | 
			
		||||
 | 
			
		||||
    def generate_output(self, output_directory: str):
 | 
			
		||||
        import json
 | 
			
		||||
        from base64 import b64encode
 | 
			
		||||
 | 
			
		||||
        data = self._get_terraria_data()
 | 
			
		||||
        filename = f"AP_{self.world.seed_name}_P{self.player}_{self.world.get_player_name(self.player)}.apterra"
 | 
			
		||||
        with open(os.path.join(output_directory, filename), 'wb') as f:
 | 
			
		||||
            f.write(b64encode(bytes(json.dumps(data), 'utf-8')))
 | 
			
		||||
 | 
			
		||||
    def fill_slot_data(self): 
 | 
			
		||||
        slot_data = self._get_terraria_data()
 | 
			
		||||
        for option_name in terraria_options:
 | 
			
		||||
            option = getattr(self.world, option_name)[self.player]
 | 
			
		||||
            slot_data[option_name] = int(option.value)
 | 
			
		||||
        return slot_data
 | 
			
		||||
 | 
			
		||||
    def create_item(self, name: str) -> Item:
 | 
			
		||||
        item_data = item_table[name]
 | 
			
		||||
        item = TerrariaItem(name, item_data.progression, item_data.code, self.player)
 | 
			
		||||
        nonexcluded_items = []
 | 
			
		||||
        if name in nonexcluded_items:  # prevent books from going on excluded locations
 | 
			
		||||
            item.never_exclude = True
 | 
			
		||||
        return item
 | 
			
		||||
		Loading…
	
		Reference in New Issue