mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Stardew Valley: Exclude maximum one resource packs from pool when in start inventory (#4839)
Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import logging
|
||||
import typing
|
||||
from random import Random
|
||||
from typing import Dict, Any, Iterable, Optional, List, TextIO, cast
|
||||
from typing import Dict, Any, Iterable, Optional, List, TextIO
|
||||
|
||||
from BaseClasses import Region, Entrance, Location, Item, Tutorial, ItemClassification, MultiWorld, CollectionState
|
||||
from Options import PerGameCommonOptions
|
||||
@@ -148,8 +148,8 @@ class StardewValleyWorld(World):
|
||||
self.precollect_building_items()
|
||||
items_to_exclude = [excluded_items
|
||||
for excluded_items in self.multiworld.precollected_items[self.player]
|
||||
if not item_table[excluded_items.name].has_any_group(Group.RESOURCE_PACK,
|
||||
Group.FRIENDSHIP_PACK)]
|
||||
if item_table[excluded_items.name].has_any_group(Group.MAXIMUM_ONE)
|
||||
or not item_table[excluded_items.name].has_any_group(Group.RESOURCE_PACK, Group.FRIENDSHIP_PACK)]
|
||||
|
||||
if self.options.season_randomization == SeasonRandomization.option_disabled:
|
||||
items_to_exclude = [item for item in items_to_exclude
|
||||
|
@@ -748,7 +748,7 @@ id,name,classification,groups,mod_name
|
||||
5208,Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5209,Stone Chest,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5210,Quality Bobber,filler,RESOURCE_PACK,
|
||||
5211,Mini-Obelisk,filler,"EXACTLY_TWO,RESOURCE_PACK",
|
||||
5211,Mini-Obelisk,filler,"AT_LEAST_TWO,RESOURCE_PACK",
|
||||
5212,Monster Musk,filler,RESOURCE_PACK,
|
||||
5213,Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5214,Quality Sprinkler,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
@@ -760,7 +760,7 @@ id,name,classification,groups,mod_name
|
||||
5220,Lightning Rod,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5221,Resource Pack: 5000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5222,Resource Pack: 10000 Money,useful,"BASE_RESOURCE,RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5223,Junimo Chest,filler,"EXACTLY_TWO,RESOURCE_PACK",
|
||||
5223,Junimo Chest,filler,"AT_LEAST_TWO,RESOURCE_PACK",
|
||||
5224,Horse Flute,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5225,Pierre's Missing Stocklist,useful,"MAXIMUM_ONE,RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
5226,Hopper,filler,"RESOURCE_PACK,RESOURCE_PACK_USEFUL",
|
||||
|
|
@@ -69,7 +69,7 @@ class Group(enum.Enum):
|
||||
TRAP = enum.auto()
|
||||
BONUS = enum.auto()
|
||||
MAXIMUM_ONE = enum.auto()
|
||||
EXACTLY_TWO = enum.auto()
|
||||
AT_LEAST_TWO = enum.auto()
|
||||
DEPRECATED = enum.auto()
|
||||
RESOURCE_PACK_USEFUL = enum.auto()
|
||||
SPECIAL_ORDER_BOARD = enum.auto()
|
||||
@@ -181,7 +181,7 @@ def create_items(item_factory: StardewItemFactory, locations_count: int, items_t
|
||||
items += unique_filler_items
|
||||
logger.debug(f"Created {len(unique_filler_items)} unique filler items")
|
||||
|
||||
resource_pack_items = fill_with_resource_packs_and_traps(item_factory, options, random, items, locations_count)
|
||||
resource_pack_items = fill_with_resource_packs_and_traps(item_factory, options, random, items + items_to_exclude, locations_count - len(items))
|
||||
items += resource_pack_items
|
||||
logger.debug(f"Created {len(resource_pack_items)} resource packs")
|
||||
|
||||
@@ -711,7 +711,7 @@ def weapons_count(options: StardewValleyOptions):
|
||||
|
||||
def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options: StardewValleyOptions, random: Random,
|
||||
items_already_added: List[Item],
|
||||
number_locations: int) -> List[Item]:
|
||||
available_item_slots: int) -> List[Item]:
|
||||
include_traps = options.trap_items != TrapItems.option_no_traps
|
||||
items_already_added_names = [item.name for item in items_already_added]
|
||||
useful_resource_packs = [pack for pack in items_by_group[Group.RESOURCE_PACK_USEFUL]
|
||||
@@ -734,10 +734,9 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options
|
||||
priority_filler_items = remove_excluded_items(priority_filler_items, options)
|
||||
|
||||
number_priority_items = len(priority_filler_items)
|
||||
required_resource_pack = number_locations - len(items_already_added)
|
||||
if required_resource_pack < number_priority_items:
|
||||
if available_item_slots < number_priority_items:
|
||||
chosen_priority_items = [item_factory(resource_pack) for resource_pack in
|
||||
random.sample(priority_filler_items, required_resource_pack)]
|
||||
random.sample(priority_filler_items, available_item_slots)]
|
||||
return chosen_priority_items
|
||||
|
||||
items = []
|
||||
@@ -745,24 +744,24 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options
|
||||
ItemClassification.trap if resource_pack.classification == ItemClassification.trap else ItemClassification.useful)
|
||||
for resource_pack in priority_filler_items]
|
||||
items.extend(chosen_priority_items)
|
||||
required_resource_pack -= number_priority_items
|
||||
available_item_slots -= number_priority_items
|
||||
all_filler_packs = [filler_pack for filler_pack in all_filler_packs
|
||||
if Group.MAXIMUM_ONE not in filler_pack.groups or
|
||||
(filler_pack.name not in [priority_item.name for priority_item in
|
||||
priority_filler_items] and filler_pack.name not in items_already_added_names)]
|
||||
|
||||
while required_resource_pack > 0:
|
||||
while available_item_slots > 0:
|
||||
resource_pack = random.choice(all_filler_packs)
|
||||
exactly_2 = Group.EXACTLY_TWO in resource_pack.groups
|
||||
while exactly_2 and required_resource_pack == 1:
|
||||
exactly_2 = Group.AT_LEAST_TWO in resource_pack.groups
|
||||
while exactly_2 and available_item_slots == 1:
|
||||
resource_pack = random.choice(all_filler_packs)
|
||||
exactly_2 = Group.EXACTLY_TWO in resource_pack.groups
|
||||
exactly_2 = Group.AT_LEAST_TWO in resource_pack.groups
|
||||
classification = ItemClassification.useful if resource_pack.classification == ItemClassification.progression else resource_pack.classification
|
||||
items.append(item_factory(resource_pack, classification))
|
||||
required_resource_pack -= 1
|
||||
available_item_slots -= 1
|
||||
if exactly_2:
|
||||
items.append(item_factory(resource_pack, classification))
|
||||
required_resource_pack -= 1
|
||||
available_item_slots -= 1
|
||||
if exactly_2 or Group.MAXIMUM_ONE in resource_pack.groups:
|
||||
all_filler_packs.remove(resource_pack)
|
||||
|
||||
@@ -803,7 +802,7 @@ def generate_filler_choice_pool(options: StardewValleyOptions) -> list[str]:
|
||||
|
||||
|
||||
def remove_limited_amount_packs(packs):
|
||||
return [pack for pack in packs if Group.MAXIMUM_ONE not in pack.groups and Group.EXACTLY_TWO not in pack.groups]
|
||||
return [pack for pack in packs if Group.MAXIMUM_ONE not in pack.groups and Group.AT_LEAST_TWO not in pack.groups]
|
||||
|
||||
|
||||
def get_all_filler_items(include_traps: bool, exclude_ginger_island: bool) -> List[ItemData]:
|
||||
|
@@ -9,3 +9,4 @@ class Wallet:
|
||||
dark_talisman = "Dark Talisman"
|
||||
club_card = "Club Card"
|
||||
mastery_of_the_five_ways = "Mastery Of The Five Ways"
|
||||
key_to_the_town = "Key To The Town"
|
||||
|
@@ -66,7 +66,7 @@ class TestBaseItemGeneration(SVTestBase):
|
||||
|
||||
def test_does_not_create_or_create_two_of_exactly_two_items(self):
|
||||
all_created_items = self.get_all_created_items()
|
||||
for exactly_two_item in items.items_by_group[items.Group.EXACTLY_TWO]:
|
||||
for exactly_two_item in items.items_by_group[items.Group.AT_LEAST_TWO]:
|
||||
with self.subTest(f"{exactly_two_item.name}"):
|
||||
count = all_created_items.count(exactly_two_item.name)
|
||||
self.assertTrue(count == 0 or count == 2)
|
||||
@@ -114,7 +114,7 @@ class TestNoGingerIslandItemGeneration(SVTestBase):
|
||||
|
||||
def test_does_not_create_exactly_two_items(self):
|
||||
all_created_items = self.get_all_created_items()
|
||||
for exactly_two_item in items.items_by_group[items.Group.EXACTLY_TWO]:
|
||||
for exactly_two_item in items.items_by_group[items.Group.AT_LEAST_TWO]:
|
||||
with self.subTest(f"{exactly_two_item.name}"):
|
||||
count = all_created_items.count(exactly_two_item.name)
|
||||
self.assertTrue(count == 0 or count == 2)
|
||||
|
@@ -19,7 +19,7 @@ class TestItemLinksEverythingIncluded(SVTestBase):
|
||||
continue
|
||||
filler_generated.append(filler)
|
||||
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
|
||||
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
|
||||
self.assertNotIn(Group.AT_LEAST_TWO, item_table[filler].groups)
|
||||
if Group.TRAP in item_table[filler].groups:
|
||||
at_least_one_trap = True
|
||||
if Group.GINGER_ISLAND in item_table[filler].groups:
|
||||
@@ -46,7 +46,7 @@ class TestItemLinksNoIsland(SVTestBase):
|
||||
filler_generated.append(filler)
|
||||
self.assertNotIn(Group.GINGER_ISLAND, item_table[filler].groups)
|
||||
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
|
||||
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
|
||||
self.assertNotIn(Group.AT_LEAST_TWO, item_table[filler].groups)
|
||||
if Group.TRAP in item_table[filler].groups:
|
||||
at_least_one_trap = True
|
||||
if len(filler_generated) >= max_number_filler:
|
||||
@@ -70,7 +70,7 @@ class TestItemLinksNoTraps(SVTestBase):
|
||||
filler_generated.append(filler)
|
||||
self.assertNotIn(Group.TRAP, item_table[filler].groups)
|
||||
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
|
||||
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
|
||||
self.assertNotIn(Group.AT_LEAST_TWO, item_table[filler].groups)
|
||||
if Group.GINGER_ISLAND in item_table[filler].groups:
|
||||
at_least_one_island = True
|
||||
if len(filler_generated) >= max_number_filler:
|
||||
@@ -94,7 +94,7 @@ class TestItemLinksNoTrapsAndIsland(SVTestBase):
|
||||
self.assertNotIn(Group.GINGER_ISLAND, item_table[filler].groups)
|
||||
self.assertNotIn(Group.TRAP, item_table[filler].groups)
|
||||
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
|
||||
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
|
||||
self.assertNotIn(Group.AT_LEAST_TWO, item_table[filler].groups)
|
||||
if len(filler_generated) >= max_number_filler:
|
||||
break
|
||||
self.assertGreaterEqual(len(filler_generated), max_number_filler)
|
||||
|
@@ -1,4 +1,4 @@
|
||||
from BaseClasses import MultiWorld, get_seed
|
||||
from BaseClasses import MultiWorld, get_seed, ItemClassification
|
||||
from . import setup_solo_multiworld, SVTestCase, solo_multiworld
|
||||
from .options.presets import allsanity_no_mods_6_x_x, get_minsanity_options
|
||||
from .. import StardewValleyWorld
|
||||
@@ -72,6 +72,22 @@ class TestItems(SVTestCase):
|
||||
self.assertEqual(len(starting_seasons_rolled), 4)
|
||||
|
||||
|
||||
class TestStartInventoryFillersAreProperlyExcluded(SVTestCase):
|
||||
def test_given_maximum_one_resource_pack_in_start_inventory_when_create_items_then_item_is_properly_excluded(self):
|
||||
assert item_table[Wallet.key_to_the_town].classification == ItemClassification.useful \
|
||||
and {Group.MAXIMUM_ONE, Group.RESOURCE_PACK_USEFUL}.issubset(item_table[Wallet.key_to_the_town].groups), \
|
||||
"'Key to the Town' is no longer suitable to test this usecase."
|
||||
|
||||
options = {
|
||||
"start_inventory": {
|
||||
Wallet.key_to_the_town: 1,
|
||||
}
|
||||
}
|
||||
|
||||
with solo_multiworld(options, world_caching=False) as (multiworld, world):
|
||||
self.assertNotIn(world.create_item(Wallet.key_to_the_town), multiworld.get_items())
|
||||
|
||||
|
||||
class TestMetalDetectors(SVTestCase):
|
||||
def test_minsanity_1_metal_detector(self):
|
||||
options = get_minsanity_options()
|
||||
|
Reference in New Issue
Block a user