Files
Archipelago/worlds/sc2wol/__init__.py
T

212 lines
7.9 KiB
Python

import typing
from typing import List, Set, Tuple
from BaseClasses import Item, MultiWorld, Location, Tutorial, ItemClassification
from worlds.AutoWorld import WebWorld, World
from .Items import StarcraftWoLItem, item_table, filler_items, item_name_groups, get_full_item_list, \
basic_unit
from .Locations import get_locations
from .Regions import create_regions
from .Options import sc2wol_options, get_option_value
from .LogicMixin import SC2WoLLogic
from .PoolFilter import filter_missions, filter_items, filter_upgrades
from .MissionTables import starting_mission_locations, MissionInfo
class Starcraft2WoLWebWorld(WebWorld):
setup = Tutorial(
"Multiworld Setup Guide",
"A guide to setting up the Starcraft 2 randomizer connected to an Archipelago Multiworld",
"English",
"setup_en.md",
"setup/en",
["TheCondor"]
)
tutorials = [setup]
class SC2WoLWorld(World):
"""
StarCraft II: Wings of Liberty is a science fiction real-time strategy video game developed and published by Blizzard Entertainment.
Command Raynor's Raiders in collecting pieces of the Keystone in order to stop the zerg threat posed by the Queen of Blades.
"""
game = "Starcraft 2 Wings of Liberty"
web = Starcraft2WoLWebWorld()
data_version = 3
item_name_to_id = {name: data.code for name, data in item_table.items()}
location_name_to_id = {location.name: location.code for location in get_locations(None, None)}
option_definitions = sc2wol_options
item_name_groups = item_name_groups
locked_locations: typing.List[str]
location_cache: typing.List[Location]
mission_req_table = {}
required_client_version = 0, 3, 5
def __init__(self, world: MultiWorld, player: int):
super(SC2WoLWorld, self).__init__(world, player)
self.location_cache = []
self.locked_locations = []
def _create_items(self, name: str):
data = get_full_item_list()[name]
return [self.create_item(name) for _ in range(data.quantity)]
def create_item(self, name: str) -> Item:
data = get_full_item_list()[name]
return StarcraftWoLItem(name, data.classification, data.code, self.player)
def create_regions(self):
self.mission_req_table = create_regions(self.world, self.player, get_locations(self.world, self.player),
self.location_cache)
def generate_basic(self):
excluded_items = get_excluded_items(self, self.world, self.player)
starter_items = assign_starter_items(self.world, self.player, excluded_items, self.locked_locations)
pool = get_item_pool(self.world, self.player, self.mission_req_table, starter_items, excluded_items, self.location_cache)
fill_item_pool_with_dummy_items(self, self.world, self.player, self.locked_locations, self.location_cache, pool)
self.world.itempool += pool
def set_rules(self):
setup_events(self.world, self.player, self.locked_locations, self.location_cache)
self.world.completion_condition[self.player] = lambda state: state.has('All-In: Victory', self.player)
def get_filler_item_name(self) -> str:
return self.world.random.choice(filler_items)
def fill_slot_data(self):
slot_data = {}
for option_name in sc2wol_options:
option = getattr(self.world, option_name)[self.player]
if type(option.value) in {str, int}:
slot_data[option_name] = int(option.value)
slot_req_table = {}
for mission in self.mission_req_table:
slot_req_table[mission] = self.mission_req_table[mission]._asdict()
slot_data["mission_req"] = slot_req_table
return slot_data
def setup_events(world: MultiWorld, player: int, locked_locations: typing.List[str], location_cache: typing.List[Location]):
for location in location_cache:
if location.address is None:
item = Item(location.name, ItemClassification.progression, None, player)
locked_locations.append(location.name)
location.place_locked_item(item)
def get_excluded_items(self: SC2WoLWorld, world: MultiWorld, player: int) -> Set[str]:
excluded_items: Set[str] = set()
if get_option_value(world, player, "upgrade_bonus") == 1:
excluded_items.add("Ultra-Capacitors")
else:
excluded_items.add("Vanadium Plating")
if get_option_value(world, player, "bunker_upgrade") == 1:
excluded_items.add("Shrike Turret")
else:
excluded_items.add("Fortified Bunker")
for item in world.precollected_items[player]:
excluded_items.add(item.name)
excluded_items_option = getattr(world, 'excluded_items', [])
excluded_items.update(excluded_items_option[player].value)
return excluded_items
def assign_starter_items(world: MultiWorld, player: int, excluded_items: Set[str], locked_locations: List[str]) -> List[Item]:
non_local_items = world.non_local_items[player].value
if get_option_value(world, player, "early_unit"):
local_basic_unit = tuple(item for item in basic_unit if item not in non_local_items)
if not local_basic_unit:
raise Exception("At least one basic unit must be local")
# The first world should also be the starting world
first_mission = list(world.worlds[player].mission_req_table)[0]
if first_mission in starting_mission_locations:
first_location = starting_mission_locations[first_mission]
elif first_mission == "In Utter Darkness":
first_location = first_mission + ": Defeat"
else:
first_location = first_mission + ": Victory"
return [assign_starter_item(world, player, excluded_items, locked_locations, first_location, local_basic_unit)]
else:
return []
def assign_starter_item(world: MultiWorld, player: int, excluded_items: Set[str], locked_locations: List[str],
location: str, item_list: Tuple[str, ...]) -> Item:
item_name = world.random.choice(item_list)
excluded_items.add(item_name)
item = create_item_with_correct_settings(world, player, item_name)
world.get_location(location, player).place_locked_item(item)
locked_locations.append(location)
return item
def get_item_pool(world: MultiWorld, player: int, mission_req_table: dict[str, MissionInfo],
starter_items: List[str], excluded_items: Set[str], location_cache: List[Location]) -> List[Item]:
pool: List[Item] = []
# For the future: goal items like Artifact Shards go here
locked_items = []
# YAML items
locked_items_option = getattr(world, 'locked_items', [])
yaml_locked_items = locked_items_option[player].value
for name, data in item_table.items():
if name not in excluded_items:
for _ in range(data.quantity):
item = create_item_with_correct_settings(world, player, name)
if name in yaml_locked_items:
locked_items.append(item)
else:
pool.append(item)
existing_items = starter_items + [item.name for item in world.precollected_items[player]]
# Removing upgrades for excluded items
for item_name in excluded_items:
pool = filter_upgrades(pool, item_name)
filtered_pool = filter_items(world, player, mission_req_table, location_cache, pool, existing_items, locked_items)
return filtered_pool
def fill_item_pool_with_dummy_items(self: SC2WoLWorld, world: MultiWorld, player: int, locked_locations: List[str],
location_cache: List[Location], pool: List[Item]):
for _ in range(len(location_cache) - len(locked_locations) - len(pool)):
item = create_item_with_correct_settings(world, player, self.get_filler_item_name())
pool.append(item)
def create_item_with_correct_settings(world: MultiWorld, player: int, name: str) -> Item:
data = item_table[name]
item = Item(name, data.classification, data.code, player)
return item