Core: implement start_inventory_from_pool (#1170)
* Core: implement start_inventory_from_pool * Factorio/LttP/Subnautica: add start_inventory_from_pool Option
This commit is contained in:
parent
8d559daa35
commit
c7284f90d9
|
@ -113,7 +113,6 @@ class MultiWorld():
|
||||||
self.dark_world_light_cone = False
|
self.dark_world_light_cone = False
|
||||||
self.rupoor_cost = 10
|
self.rupoor_cost = 10
|
||||||
self.aga_randomness = True
|
self.aga_randomness = True
|
||||||
self.lock_aga_door_in_escape = False
|
|
||||||
self.save_and_quit_from_boss = True
|
self.save_and_quit_from_boss = True
|
||||||
self.custom = False
|
self.custom = False
|
||||||
self.customitemarray = []
|
self.customitemarray = []
|
||||||
|
@ -122,6 +121,7 @@ class MultiWorld():
|
||||||
self.early_items = {player: {} for player in self.player_ids}
|
self.early_items = {player: {} for player in self.player_ids}
|
||||||
self.local_early_items = {player: {} for player in self.player_ids}
|
self.local_early_items = {player: {} for player in self.player_ids}
|
||||||
self.indirect_connections = {}
|
self.indirect_connections = {}
|
||||||
|
self.start_inventory_from_pool = {player: Options.StartInventoryPool({}) for player in range(1, players + 1)}
|
||||||
self.fix_trock_doors = self.AttributeProxy(
|
self.fix_trock_doors = self.AttributeProxy(
|
||||||
lambda player: self.shuffle[player] != 'vanilla' or self.mode[player] == 'inverted')
|
lambda player: self.shuffle[player] != 'vanilla' or self.mode[player] == 'inverted')
|
||||||
self.fix_skullwoods_exit = self.AttributeProxy(
|
self.fix_skullwoods_exit = self.AttributeProxy(
|
||||||
|
|
29
Main.py
29
Main.py
|
@ -115,6 +115,9 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
|
||||||
for item_name, count in world.start_inventory[player].value.items():
|
for item_name, count in world.start_inventory[player].value.items():
|
||||||
for _ in range(count):
|
for _ in range(count):
|
||||||
world.push_precollected(world.create_item(item_name, player))
|
world.push_precollected(world.create_item(item_name, player))
|
||||||
|
for item_name, count in world.start_inventory_from_pool[player].value.items():
|
||||||
|
for _ in range(count):
|
||||||
|
world.push_precollected(world.create_item(item_name, player))
|
||||||
|
|
||||||
logger.info('Creating World.')
|
logger.info('Creating World.')
|
||||||
AutoWorld.call_all(world, "create_regions")
|
AutoWorld.call_all(world, "create_regions")
|
||||||
|
@ -149,6 +152,32 @@ def main(args, seed=None, baked_server_options: Optional[Dict[str, object]] = No
|
||||||
|
|
||||||
AutoWorld.call_all(world, "generate_basic")
|
AutoWorld.call_all(world, "generate_basic")
|
||||||
|
|
||||||
|
# remove starting inventory from pool items.
|
||||||
|
# Because some worlds don't actually create items during create_items this has to be as late as possible.
|
||||||
|
if any(world.start_inventory_from_pool[player].value for player in world.player_ids):
|
||||||
|
new_items: List[Item] = []
|
||||||
|
depletion_pool: Dict[int, Dict[str, int]] = {
|
||||||
|
player: world.start_inventory_from_pool[player].value.copy() for player in world.player_ids}
|
||||||
|
for player, items in depletion_pool.items():
|
||||||
|
player_world: AutoWorld.World = world.worlds[player]
|
||||||
|
for count in items.values():
|
||||||
|
new_items.append(player_world.create_filler())
|
||||||
|
target: int = sum(sum(items.values()) for items in depletion_pool.values())
|
||||||
|
for item in world.itempool:
|
||||||
|
if depletion_pool[item.player].get(item.name, 0):
|
||||||
|
target -= 1
|
||||||
|
depletion_pool[item.player][item.name] -= 1
|
||||||
|
# quick abort if we have found all items
|
||||||
|
if not target:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
new_items.append(item)
|
||||||
|
for player, remaining_items in depletion_pool.items():
|
||||||
|
if remaining_items:
|
||||||
|
raise Exception(f"{world.get_player_name(player)}"
|
||||||
|
f" is trying to remove items from their pool that don't exist: {remaining_items}")
|
||||||
|
world.itempool[:] = new_items
|
||||||
|
|
||||||
# temporary home for item links, should be moved out of Main
|
# temporary home for item links, should be moved out of Main
|
||||||
for group_id, group in world.groups.items():
|
for group_id, group in world.groups.items():
|
||||||
def find_common_pool(players: Set[int], shared_pool: Set[str]) -> Tuple[
|
def find_common_pool(players: Set[int], shared_pool: Set[str]) -> Tuple[
|
||||||
|
|
|
@ -897,6 +897,13 @@ class StartInventory(ItemDict):
|
||||||
display_name = "Start Inventory"
|
display_name = "Start Inventory"
|
||||||
|
|
||||||
|
|
||||||
|
class StartInventoryPool(StartInventory):
|
||||||
|
"""Start with these items and don't place them in the world.
|
||||||
|
The game decides what the replacement items will be."""
|
||||||
|
verify_item_name = True
|
||||||
|
display_name = "Start Inventory from Pool"
|
||||||
|
|
||||||
|
|
||||||
class StartHints(ItemSet):
|
class StartHints(ItemSet):
|
||||||
"""Start with these item's locations prefilled into the !hint command."""
|
"""Start with these item's locations prefilled into the !hint command."""
|
||||||
display_name = "Start Hints"
|
display_name = "Start Hints"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from BaseClasses import MultiWorld
|
from BaseClasses import MultiWorld
|
||||||
from Options import Choice, Range, Option, Toggle, DefaultOnToggle, DeathLink, TextChoice, PlandoBosses
|
from Options import Choice, Range, Option, Toggle, DefaultOnToggle, DeathLink, StartInventoryPool, PlandoBosses
|
||||||
|
|
||||||
|
|
||||||
class Logic(Choice):
|
class Logic(Choice):
|
||||||
|
@ -466,5 +466,6 @@ alttp_options: typing.Dict[str, type(Option)] = {
|
||||||
"beemizer_total_chance": BeemizerTotalChance,
|
"beemizer_total_chance": BeemizerTotalChance,
|
||||||
"beemizer_trap_chance": BeemizerTrapChance,
|
"beemizer_trap_chance": BeemizerTrapChance,
|
||||||
"death_link": DeathLink,
|
"death_link": DeathLink,
|
||||||
"allow_collect": AllowCollect
|
"allow_collect": AllowCollect,
|
||||||
|
"start_inventory_from_pool": StartInventoryPool,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1247,8 +1247,8 @@ def patch_rom(world: MultiWorld, rom: LocalRom, player: int, enemized: bool):
|
||||||
# assorted fixes
|
# assorted fixes
|
||||||
rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world[
|
rom.write_byte(0x1800A2, 0x01 if world.fix_fake_world[
|
||||||
player] else 0x00) # Toggle whether to be in real/fake dark world when dying in a DW dungeon before killing aga1
|
player] else 0x00) # Toggle whether to be in real/fake dark world when dying in a DW dungeon before killing aga1
|
||||||
rom.write_byte(0x180169,
|
# Lock or unlock aga tower door during escape sequence.
|
||||||
0x01 if world.lock_aga_door_in_escape else 0x00) # Lock or unlock aga tower door during escape sequence.
|
rom.write_byte(0x180169, 0x00)
|
||||||
if world.mode[player] == 'inverted':
|
if world.mode[player] == 'inverted':
|
||||||
rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted
|
rom.write_byte(0x180169, 0x02) # lock aga/ganon tower door with crystals in inverted
|
||||||
rom.write_byte(0x180171,
|
rom.write_byte(0x180171,
|
||||||
|
|
|
@ -2,7 +2,8 @@ from __future__ import annotations
|
||||||
import typing
|
import typing
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from Options import Choice, OptionDict, OptionSet, ItemDict, Option, DefaultOnToggle, Range, DeathLink, Toggle
|
from Options import Choice, OptionDict, OptionSet, ItemDict, Option, DefaultOnToggle, Range, DeathLink, Toggle, \
|
||||||
|
StartInventoryPool
|
||||||
from schema import Schema, Optional, And, Or
|
from schema import Schema, Optional, And, Or
|
||||||
|
|
||||||
# schema helpers
|
# schema helpers
|
||||||
|
@ -454,6 +455,7 @@ factorio_options: typing.Dict[str, type(Option)] = {
|
||||||
"evolution_trap_increase": EvolutionTrapIncrease,
|
"evolution_trap_increase": EvolutionTrapIncrease,
|
||||||
"death_link": DeathLink,
|
"death_link": DeathLink,
|
||||||
"energy_link": EnergyLink,
|
"energy_link": EnergyLink,
|
||||||
|
"start_inventory_from_pool": StartInventoryPool,
|
||||||
}
|
}
|
||||||
|
|
||||||
# spoilers below. If you spoil it for yourself, please at least don't spoil it for anyone else.
|
# spoilers below. If you spoil it for yourself, please at least don't spoil it for anyone else.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
from Options import Choice, Range, DeathLink, DefaultOnToggle
|
from Options import Choice, Range, DeathLink, DefaultOnToggle, StartInventoryPool
|
||||||
from .Creatures import all_creatures, Definitions
|
from .Creatures import all_creatures, Definitions
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,4 +104,5 @@ options = {
|
||||||
"creature_scans": CreatureScans,
|
"creature_scans": CreatureScans,
|
||||||
"creature_scan_logic": AggressiveScanLogic,
|
"creature_scan_logic": AggressiveScanLogic,
|
||||||
"death_link": SubnauticaDeathLink,
|
"death_link": SubnauticaDeathLink,
|
||||||
|
"start_inventory_from_pool": StartInventoryPool,
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue