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 from ..AutoWorld import World 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" 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 options = raft_options data_version = 1 def generate_basic(self): minRPSpecified = self.world.minimum_resource_pack_amount[self.player].value maxRPSpecified = self.world.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.world.use_resource_packs[self.player].value): for packItem in resourcePackItems: for i in range(minimumResourcePackAmount, maximumResourcePackAmount + 1): extraItemNamePool.append(createResourcePackName(i, packItem)) if self.world.duplicate_items[self.player].value != 0: dupeItemPool = item_table.copy() # Remove frequencies if necessary if self.world.island_frequency_locations[self.player].value != 3: # 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.world.duplicate_items[self.player].value == 1): # Progression only dupeItemPool = (itm for itm in dupeItemPool if itm["progression"] == True) elif (self.world.duplicate_items[self.player].value == 2): # 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.world.itempool += pool def set_rules(self): set_rules(self.world, self.player) def create_regions(self): create_regions(self.world, self.player) def fill_slot_data(self): slot_data = {} return slot_data def create_item_replaceAsNecessary(self, name: str) -> Item: isFrequency = "Frequency" in name shouldUseProgressive = ((isFrequency and self.world.island_frequency_locations[self.player].value == 2) or (not isFrequency and self.world.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, item["progression"], self.item_name_to_id[name], player=self.player) def create_resourcePack(self, rpName: str) -> Item: return RaftItem(rpName, False, 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 get_required_client_version(self) -> typing.Tuple[int, int, int]: return max((0, 2, 0), super(RaftWorld, self).get_required_client_version()) def pre_fill(self): if self.world.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") elif self.world.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") # Victory item self.world.get_location("Tangaroa Next Frequency", self.player).place_locked_item( RaftItem("Victory", True, None, player=self.player)) def setLocationItem(self, location: str, itemName: str): itemToUse = next(filter(lambda itm: itm.name == itemName, self.world.itempool)) self.world.itempool.remove(itemToUse) self.world.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.world.itempool)) self.world.itempool.remove(itemToUse) location = random.choice(list(loc for loc in location_table if loc["region"] == region)) self.world.get_location(location["name"], self.player).place_locked_item(itemToUse) def create_region(world: MultiWorld, player: int, name: str, locations=None, exits=None): ret = Region(name, RegionType.Generic, name, player) ret.world = 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"