Skip to content

Commit 0f98cf5

Browse files
agilbert1412Zach Parks
and
Zach Parks
authored
Stardew Valley: Generate proper filler for item links (#2069)
Co-authored-by: Zach Parks <[email protected]>
1 parent cfd2e9c commit 0f98cf5

File tree

4 files changed

+150
-14
lines changed

4 files changed

+150
-14
lines changed

worlds/stardew_valley/__init__.py

+31-4
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import logging
22
from typing import Dict, Any, Iterable, Optional, Union, Set, List
33

4-
from BaseClasses import Region, Entrance, Location, Item, Tutorial, CollectionState, ItemClassification, MultiWorld
4+
from BaseClasses import Region, Entrance, Location, Item, Tutorial, CollectionState, ItemClassification, MultiWorld, Group as ItemLinkGroup
55
from Options import PerGameCommonOptions
66
from worlds.AutoWorld import World, WebWorld
77
from . import rules
88
from .bundles import get_all_bundles, Bundle
9-
from .items import item_table, create_items, ItemData, Group, items_by_group
9+
from .items import item_table, create_items, ItemData, Group, items_by_group, get_all_filler_items, remove_limited_amount_packs
1010
from .locations import location_table, create_locations, LocationData
1111
from .logic import StardewLogic, StardewRule, True_, MAX_MONTHS
1212
from .options import StardewValleyOptions, SeasonRandomization, Goal, BundleRandomization, BundlePrice, NumberOfLuckBuffs, NumberOfMovementBuffs, \
13-
BackpackProgression, BuildingProgression, ExcludeGingerIsland
13+
BackpackProgression, BuildingProgression, ExcludeGingerIsland, TrapItems
1414
from .presets import sv_options_presets
1515
from .regions import create_regions
1616
from .rules import set_rules
@@ -74,6 +74,7 @@ class StardewValleyWorld(World):
7474
def __init__(self, world: MultiWorld, player: int):
7575
super().__init__(world, player)
7676
self.all_progression_items = set()
77+
self.filler_item_pool_names = []
7778

7879
def generate_early(self):
7980
self.force_change_options_if_incompatible()
@@ -270,7 +271,33 @@ def generate_basic(self):
270271
pass
271272

272273
def get_filler_item_name(self) -> str:
273-
return "Joja Cola"
274+
if not self.filler_item_pool_names:
275+
self.generate_filler_item_pool_names()
276+
return self.random.choice(self.filler_item_pool_names)
277+
278+
def generate_filler_item_pool_names(self):
279+
include_traps, exclude_island = self.get_filler_item_rules()
280+
available_filler = get_all_filler_items(include_traps, exclude_island)
281+
available_filler = remove_limited_amount_packs(available_filler)
282+
self.filler_item_pool_names = [item.name for item in available_filler]
283+
284+
def get_filler_item_rules(self):
285+
if self.player in self.multiworld.groups:
286+
link_group: ItemLinkGroup = self.multiworld.groups[self.player]
287+
include_traps = True
288+
exclude_island = False
289+
for player in link_group["players"]:
290+
player_options = self.multiworld.worlds[player].options
291+
if self.multiworld.game[player] != self.game:
292+
293+
continue
294+
if player_options.trap_items == TrapItems.option_no_traps:
295+
include_traps = False
296+
if player_options.exclude_ginger_island == ExcludeGingerIsland.option_true:
297+
exclude_island = True
298+
return include_traps, exclude_island
299+
else:
300+
return self.options.trap_items != TrapItems.option_no_traps, self.options.exclude_ginger_island == ExcludeGingerIsland.option_true
274301

275302
def fill_slot_data(self) -> Dict[str, Any]:
276303

worlds/stardew_valley/data/bundle_data.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -303,8 +303,7 @@ def __lt__(self, other):
303303

304304
river_fish_items = [chub, catfish, rainbow_trout, lingcod, walleye, perch, pike, bream,
305305
salmon, sunfish, tiger_trout, shad, smallmouth_bass, dorado]
306-
lake_fish_items = [chub, rainbow_trout, lingcod, walleye, perch, carp, midnight_carp,
307-
largemouth_bass, sturgeon, bullhead, midnight_carp]
306+
lake_fish_items = [chub, rainbow_trout, lingcod, walleye, perch, carp, midnight_carp, largemouth_bass, sturgeon, bullhead]
308307
ocean_fish_items = [tilapia, pufferfish, tuna, super_cucumber, flounder, anchovy, sardine, red_mullet,
309308
herring, eel, octopus, red_snapper, squid, sea_cucumber, albacore, halibut]
310309
night_fish_items = [walleye, bream, super_cucumber, eel, squid, midnight_carp]

worlds/stardew_valley/items.py

+18-8
Original file line numberDiff line numberDiff line change
@@ -468,10 +468,6 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options
468468
items_already_added: List[Item],
469469
number_locations: int) -> List[Item]:
470470
include_traps = options.trap_items != TrapItems.option_no_traps
471-
all_filler_packs = [pack for pack in items_by_group[Group.RESOURCE_PACK]]
472-
all_filler_packs.extend(items_by_group[Group.TRASH])
473-
if include_traps:
474-
all_filler_packs.extend(items_by_group[Group.TRAP])
475471
items_already_added_names = [item.name for item in items_already_added]
476472
useful_resource_packs = [pack for pack in items_by_group[Group.RESOURCE_PACK_USEFUL]
477473
if pack.name not in items_already_added_names]
@@ -484,8 +480,9 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options
484480
if include_traps:
485481
priority_filler_items.extend(trap_items)
486482

487-
all_filler_packs = remove_excluded_packs(all_filler_packs, options)
488-
priority_filler_items = remove_excluded_packs(priority_filler_items, options)
483+
exclude_ginger_island = options.exclude_ginger_island == ExcludeGingerIsland.option_true
484+
all_filler_packs = get_all_filler_items(include_traps, exclude_ginger_island)
485+
priority_filler_items = remove_excluded_packs(priority_filler_items, exclude_ginger_island)
489486

490487
number_priority_items = len(priority_filler_items)
491488
required_resource_pack = number_locations - len(items_already_added)
@@ -519,8 +516,21 @@ def fill_with_resource_packs_and_traps(item_factory: StardewItemFactory, options
519516
return items
520517

521518

522-
def remove_excluded_packs(packs, options: StardewValleyOptions):
519+
def remove_excluded_packs(packs, exclude_ginger_island: bool):
523520
included_packs = [pack for pack in packs if Group.DEPRECATED not in pack.groups]
524-
if options.exclude_ginger_island == ExcludeGingerIsland.option_true:
521+
if exclude_ginger_island:
525522
included_packs = [pack for pack in included_packs if Group.GINGER_ISLAND not in pack.groups]
526523
return included_packs
524+
525+
526+
def remove_limited_amount_packs(packs):
527+
return [pack for pack in packs if Group.MAXIMUM_ONE not in pack.groups and Group.EXACTLY_TWO not in pack.groups]
528+
529+
530+
def get_all_filler_items(include_traps: bool, exclude_ginger_island: bool):
531+
all_filler_packs = [pack for pack in items_by_group[Group.RESOURCE_PACK]]
532+
all_filler_packs.extend(items_by_group[Group.TRASH])
533+
if include_traps:
534+
all_filler_packs.extend(items_by_group[Group.TRAP])
535+
all_filler_packs = remove_excluded_packs(all_filler_packs, exclude_ginger_island)
536+
return all_filler_packs
+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
from . import SVTestBase
2+
from .. import options, item_table, Group
3+
4+
max_iterations = 2000
5+
6+
7+
class TestItemLinksEverythingIncluded(SVTestBase):
8+
options = {options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false,
9+
options.TrapItems.internal_name: options.TrapItems.option_medium}
10+
11+
def test_filler_of_all_types_generated(self):
12+
max_number_filler = 115
13+
filler_generated = []
14+
at_least_one_trap = False
15+
at_least_one_island = False
16+
for i in range(0, max_iterations):
17+
filler = self.multiworld.worlds[1].get_filler_item_name()
18+
if filler in filler_generated:
19+
continue
20+
filler_generated.append(filler)
21+
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
22+
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
23+
if Group.TRAP in item_table[filler].groups:
24+
at_least_one_trap = True
25+
if Group.GINGER_ISLAND in item_table[filler].groups:
26+
at_least_one_island = True
27+
if len(filler_generated) >= max_number_filler:
28+
break
29+
self.assertTrue(at_least_one_trap)
30+
self.assertTrue(at_least_one_island)
31+
self.assertGreaterEqual(len(filler_generated), max_number_filler)
32+
33+
34+
class TestItemLinksNoIsland(SVTestBase):
35+
options = {options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true,
36+
options.TrapItems.internal_name: options.TrapItems.option_medium}
37+
38+
def test_filler_has_no_island_but_has_traps(self):
39+
max_number_filler = 109
40+
filler_generated = []
41+
at_least_one_trap = False
42+
for i in range(0, max_iterations):
43+
filler = self.multiworld.worlds[1].get_filler_item_name()
44+
if filler in filler_generated:
45+
continue
46+
filler_generated.append(filler)
47+
self.assertNotIn(Group.GINGER_ISLAND, item_table[filler].groups)
48+
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
49+
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
50+
if Group.TRAP in item_table[filler].groups:
51+
at_least_one_trap = True
52+
if len(filler_generated) >= max_number_filler:
53+
break
54+
self.assertTrue(at_least_one_trap)
55+
self.assertGreaterEqual(len(filler_generated), max_number_filler)
56+
57+
58+
class TestItemLinksNoTraps(SVTestBase):
59+
options = {options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_false,
60+
options.TrapItems.internal_name: options.TrapItems.option_no_traps}
61+
62+
def test_filler_has_no_traps_but_has_island(self):
63+
max_number_filler = 100
64+
filler_generated = []
65+
at_least_one_island = False
66+
for i in range(0, max_iterations):
67+
filler = self.multiworld.worlds[1].get_filler_item_name()
68+
if filler in filler_generated:
69+
continue
70+
filler_generated.append(filler)
71+
self.assertNotIn(Group.TRAP, item_table[filler].groups)
72+
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
73+
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
74+
if Group.GINGER_ISLAND in item_table[filler].groups:
75+
at_least_one_island = True
76+
if len(filler_generated) >= max_number_filler:
77+
break
78+
self.assertTrue(at_least_one_island)
79+
self.assertGreaterEqual(len(filler_generated), max_number_filler)
80+
81+
82+
class TestItemLinksNoTrapsAndIsland(SVTestBase):
83+
options = {options.ExcludeGingerIsland.internal_name: options.ExcludeGingerIsland.option_true,
84+
options.TrapItems.internal_name: options.TrapItems.option_no_traps}
85+
86+
def test_filler_generated_without_island_or_traps(self):
87+
max_number_filler = 94
88+
filler_generated = []
89+
for i in range(0, max_iterations):
90+
filler = self.multiworld.worlds[1].get_filler_item_name()
91+
if filler in filler_generated:
92+
continue
93+
filler_generated.append(filler)
94+
self.assertNotIn(Group.GINGER_ISLAND, item_table[filler].groups)
95+
self.assertNotIn(Group.TRAP, item_table[filler].groups)
96+
self.assertNotIn(Group.MAXIMUM_ONE, item_table[filler].groups)
97+
self.assertNotIn(Group.EXACTLY_TWO, item_table[filler].groups)
98+
if len(filler_generated) >= max_number_filler:
99+
break
100+
self.assertGreaterEqual(len(filler_generated), max_number_filler)

0 commit comments

Comments
 (0)