Revert "Add Terraria Support"

This reverts commit 3aacaffe6b.
This commit is contained in:
SolventMercury 2021-09-08 07:02:12 -07:00
parent 3aacaffe6b
commit 48dd1a1aa6
7 changed files with 0 additions and 440 deletions

View File

@ -29,7 +29,6 @@ game: # Pick a game to play
Minecraft: 0 Minecraft: 0
Subnautica: 0 Subnautica: 0
Slay the Spire: 0 Slay the Spire: 0
Terraria: 0
requires: requires:
version: 0.1.6 # Version of Archipelago required for this yaml to work as expected. version: 0.1.6 # Version of Archipelago required for this yaml to work as expected.
# Shared Options supported by all games: # 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. send_defeated_mobs: # Send killed mobs to other Minecraft worlds which have this option enabled.
on: 0 on: 0
off: 1 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: A Link to the Past:
### Logic Section ### ### Logic Section ###
glitches_required: # Determine the logic required to complete the seed glitches_required: # Determine the logic required to complete the seed

View File

@ -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}

View File

@ -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}

View File

@ -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,
}

View File

@ -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 = {
}

View File

@ -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))

View File

@ -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