Archipelago/worlds/raft/__init__.py

223 lines
11 KiB
Python

import typing
import random
from .Locations import location_table, lookup_name_to_id as locations_lookup_name_to_id
from .Items import (createResourcePackName, item_table, progressive_table, progressive_item_list,
lookup_name_to_item, resourcepack_items as resourcePackItems, lookup_name_to_id as items_lookup_name_to_id)
from .Regions import create_regions, getConnectionName
from .Rules import set_rules
from .Options import raft_options
from BaseClasses import Region, RegionType, Entrance, Location, MultiWorld, Item, ItemClassification, Tutorial
from ..AutoWorld import World, WebWorld
class RaftWeb(WebWorld):
tutorials = [Tutorial(
"Multiworld Setup Guide",
"A guide to setting up Raft integration for Archipelago multiworld games.",
"English",
"setup_en.md",
"setup/en",
["SunnyBat", "Awareqwx"]
)]
class RaftWorld(World):
"""
Raft is a flooded world exploration game. You're stranded on a small raft in the middle of the
ocean, and you must survive on trash floating by you on the top of the water and around/on any
islands that you come across.
"""
game: str = "Raft"
web = RaftWeb()
item_name_to_id = items_lookup_name_to_id.copy()
lastItemId = max(filter(lambda val: val is not None, item_name_to_id.values()))
location_name_to_id = locations_lookup_name_to_id
option_definitions = raft_options
data_version = 2
required_client_version = (0, 3, 4)
def generate_basic(self):
minRPSpecified = self.multiworld.minimum_resource_pack_amount[self.player].value
maxRPSpecified = self.multiworld.maximum_resource_pack_amount[self.player].value
minimumResourcePackAmount = min(minRPSpecified, maxRPSpecified)
maximumResourcePackAmount = max(minRPSpecified, maxRPSpecified)
# Generate item pool
pool = []
for item in item_table:
raft_item = self.create_item_replaceAsNecessary(item["name"])
pool.append(raft_item)
extraItemNamePool = []
extras = len(location_table) - len(item_table) - 1 # Victory takes up 1 unaccounted-for slot
if extras > 0:
if (self.multiworld.filler_item_types[self.player].value != 1): # Use resource packs
for packItem in resourcePackItems:
for i in range(minimumResourcePackAmount, maximumResourcePackAmount + 1):
extraItemNamePool.append(createResourcePackName(i, packItem))
if self.multiworld.filler_item_types[self.player].value != 0: # Use duplicate items
dupeItemPool = item_table.copy()
# Remove frequencies if necessary
if self.multiworld.island_frequency_locations[self.player].value != 5: # Not completely random locations
dupeItemPool = (itm for itm in dupeItemPool if "Frequency" not in itm["name"])
# Remove progression or non-progression items if necessary
if (self.multiworld.duplicate_items[self.player].value == 0): # Progression only
dupeItemPool = (itm for itm in dupeItemPool if itm["progression"] == True)
elif (self.multiworld.duplicate_items[self.player].value == 1): # Non-progression only
dupeItemPool = (itm for itm in dupeItemPool if itm["progression"] == False)
dupeItemPool = list(dupeItemPool)
# Finally, add items as necessary
if len(dupeItemPool) > 0:
for item in dupeItemPool:
extraItemNamePool.append(item["name"])
if (len(extraItemNamePool) > 0):
for randomItem in random.choices(extraItemNamePool, k=extras):
raft_item = self.create_item_replaceAsNecessary(randomItem)
pool.append(raft_item)
self.multiworld.itempool += pool
def set_rules(self):
set_rules(self.multiworld, self.player)
def create_regions(self):
create_regions(self.multiworld, self.player)
def get_pre_fill_items(self):
if self.multiworld.island_frequency_locations[self.player] in [0, 1, 2, 3]:
return [loc.item for loc in self.multiworld.get_filled_locations()]
return []
def create_item_replaceAsNecessary(self, name: str) -> Item:
isFrequency = "Frequency" in name
shouldUseProgressive = ((isFrequency and self.multiworld.island_frequency_locations[self.player].value == 4)
or (not isFrequency and self.multiworld.progressive_items[self.player].value))
if shouldUseProgressive and name in progressive_table:
name = progressive_table[name]
return self.create_item(name)
def create_item(self, name: str) -> Item:
item = lookup_name_to_item[name]
return RaftItem(name, ItemClassification.progression if item["progression"] else ItemClassification.filler,
self.item_name_to_id[name], player=self.player)
def create_resourcePack(self, rpName: str) -> Item:
return RaftItem(rpName, ItemClassification.filler, self.item_name_to_id[rpName], player=self.player)
def collect_item(self, state, item, remove=False):
if item.name in progressive_item_list:
prog_table = progressive_item_list[item.name]
if remove:
for item_name in reversed(prog_table):
if state.has(item_name, item.player):
return item_name
else:
for item_name in prog_table:
if not state.has(item_name, item.player):
return item_name
return super(RaftWorld, self).collect_item(state, item, remove)
def pre_fill(self):
if self.multiworld.island_frequency_locations[self.player] == 0:
self.setLocationItem("Radio Tower Frequency to Vasagatan", "Vasagatan Frequency")
self.setLocationItem("Vasagatan Frequency to Balboa", "Balboa Island Frequency")
self.setLocationItem("Relay Station quest", "Caravan Island Frequency")
self.setLocationItem("Caravan Island Frequency to Tangaroa", "Tangaroa Frequency")
self.setLocationItem("Tangaroa Frequency to Varuna Point", "Varuna Point Frequency")
self.setLocationItem("Varuna Point Frequency to Temperance", "Temperance Frequency")
self.setLocationItem("Temperance Frequency to Utopia", "Utopia Frequency")
elif self.multiworld.island_frequency_locations[self.player] == 1:
self.setLocationItemFromRegion("RadioTower", "Vasagatan Frequency")
self.setLocationItemFromRegion("Vasagatan", "Balboa Island Frequency")
self.setLocationItemFromRegion("BalboaIsland", "Caravan Island Frequency")
self.setLocationItemFromRegion("CaravanIsland", "Tangaroa Frequency")
self.setLocationItemFromRegion("Tangaroa", "Varuna Point Frequency")
self.setLocationItemFromRegion("Varuna Point", "Temperance Frequency")
self.setLocationItemFromRegion("Temperance", "Utopia Frequency")
elif self.multiworld.island_frequency_locations[self.player] in [2, 3]:
locationToFrequencyItemMap = {
"Vasagatan": "Vasagatan Frequency",
"BalboaIsland": "Balboa Island Frequency",
"CaravanIsland": "Caravan Island Frequency",
"Tangaroa": "Tangaroa Frequency",
"Varuna Point": "Varuna Point Frequency",
"Temperance": "Temperance Frequency",
"Utopia": "Utopia Frequency"
}
locationToVanillaFrequencyLocationMap = {
"RadioTower": "Radio Tower Frequency to Vasagatan",
"Vasagatan": "Vasagatan Frequency to Balboa",
"BalboaIsland": "Relay Station quest",
"CaravanIsland": "Caravan Island Frequency to Tangaroa",
"Tangaroa": "Tangaroa Frequency to Varuna Point",
"Varuna Point": "Varuna Point Frequency to Temperance",
"Temperance": "Temperance Frequency to Utopia"
}
# Utopia is never chosen until the end, otherwise these are chosen randomly
availableLocationList = ["Vasagatan", "BalboaIsland", "CaravanIsland", "Tangaroa", "Varuna Point", "Temperance", "Utopia"]
previousLocation = "RadioTower"
while (len(availableLocationList) > 0):
if (len(availableLocationList) > 1):
currentLocation = availableLocationList[random.randint(0, len(availableLocationList) - 2)]
else:
currentLocation = availableLocationList[0] # Utopia (only one left in list)
availableLocationList.remove(currentLocation)
if self.multiworld.island_frequency_locations[self.player] == 2:
self.setLocationItem(locationToVanillaFrequencyLocationMap[previousLocation], locationToFrequencyItemMap[currentLocation])
elif self.multiworld.island_frequency_locations[self.player] == 3:
self.setLocationItemFromRegion(previousLocation, locationToFrequencyItemMap[currentLocation])
previousLocation = currentLocation
# Victory item
self.multiworld.get_location("Utopia Complete", self.player).place_locked_item(
RaftItem("Victory", ItemClassification.progression, None, player=self.player))
def setLocationItem(self, location: str, itemName: str):
itemToUse = next(filter(lambda itm: itm.name == itemName, self.multiworld.itempool))
self.multiworld.itempool.remove(itemToUse)
self.multiworld.get_location(location, self.player).place_locked_item(itemToUse)
def setLocationItemFromRegion(self, region: str, itemName: str):
itemToUse = next(filter(lambda itm: itm.name == itemName, self.multiworld.itempool))
self.multiworld.itempool.remove(itemToUse)
location = random.choice(list(loc for loc in location_table if loc["region"] == region))
self.multiworld.get_location(location["name"], self.player).place_locked_item(itemToUse)
def fill_slot_data(self):
return {
"IslandGenerationDistance": self.multiworld.island_generation_distance[self.player].value,
"ExpensiveResearch": bool(self.multiworld.expensive_research[self.player].value),
"DeathLink": bool(self.multiworld.death_link[self.player].value)
}
def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None):
ret = Region(name, RegionType.Generic, name, player)
ret.multiworld = world
if locations:
for location in locations:
loc_id = locations_lookup_name_to_id.get(location, 0)
locationObj = RaftLocation(player, location, loc_id, ret)
ret.locations.append(locationObj)
if exits:
for exit in exits:
ret.exits.append(Entrance(player, getConnectionName(name, exit), ret))
return ret
class RaftLocation(Location):
game = "Raft"
class RaftItem(Item):
game = "Raft"