mirror of
https://github.com/MarioSpore/Grinch-AP.git
synced 2025-10-21 20:21:32 -06:00
Stardew Valley: 4.x.x - The Ginger Update (#1931)
## What is this fixing or adding? Major content update for Stardew Valley ## How was this tested? One large-scale public Beta on the archipelago server, plus several smaller private asyncs and test runs You can go to https://github.com/agilbert1412/StardewArchipelago/releases to grab the mod (latest 4.x.x version), the supported mods and the apworld, to test this PR ## New Features: - Festival Checks [Easy mode or Hard Mode] - Special Orders [Both Board and Qi] - Willy's Boat - Ginger Island Parrots - TV Channels - Trap Items [Available in various difficulty levels] - Entrance Randomizer: Buildings and Chaos - New Fishsanity options: Exclude Legendaries, Exclude Hard fish, Only easy fish - Resource Pack overhaul [Resource packs are now more enjoyable and varied] - Goal: Greatest Walnut Hunter [Find every single Golden Walnut] - Goal: Perfection [Achieve Perfection] - Option: Profit Margin [Multiplier over all earnings] - Option: Friendsanity Heart Size [Reduce clutter from friendsanity hearts] - Option: Exclude Ginger Island - will exclude many locations and items to generate a playthrough that does not go to the island - Mod Support [Curated list of mods] ## New Contributors: @Witchybun for the mod support --------- Co-authored-by: Witchybun <embenham05@gmail.com> Co-authored-by: Exempt-Medic <60412657+Exempt-Medic@users.noreply.github.com> Co-authored-by: Fabian Dill <Berserker66@users.noreply.github.com>
This commit is contained in:
99
worlds/stardew_valley/test/long/TestRandomWorlds.py
Normal file
99
worlds/stardew_valley/test/long/TestRandomWorlds.py
Normal file
@@ -0,0 +1,99 @@
|
||||
from typing import Dict, List
|
||||
import random
|
||||
|
||||
from BaseClasses import MultiWorld
|
||||
from Options import SpecialRange, Range
|
||||
from .option_names import options_to_include
|
||||
from .. import setup_solo_multiworld, SVTestBase
|
||||
from ..checks.goal_checks import assert_perfection_world_is_valid, assert_goal_world_is_valid
|
||||
from ..checks.option_checks import assert_can_reach_island_if_should, assert_cropsanity_same_number_items_and_locations, \
|
||||
assert_festivals_give_access_to_deluxe_scarecrow
|
||||
from ..checks.world_checks import assert_same_number_items_locations, assert_victory_exists
|
||||
from ... import options
|
||||
|
||||
|
||||
def get_option_choices(option) -> Dict[str, int]:
|
||||
if issubclass(option, SpecialRange):
|
||||
return option.special_range_names
|
||||
if issubclass(option, Range):
|
||||
return {f"{val}": val for val in range(option.range_start, option.range_end + 1)}
|
||||
elif option.options:
|
||||
return option.options
|
||||
return {}
|
||||
|
||||
|
||||
def generate_random_multiworld(world_id: int):
|
||||
world_options = generate_random_world_options(world_id)
|
||||
multiworld = setup_solo_multiworld(world_options, seed=world_id)
|
||||
return multiworld
|
||||
|
||||
|
||||
def generate_random_world_options(world_id: int) -> Dict[str, int]:
|
||||
num_options = len(options_to_include)
|
||||
world_options = dict()
|
||||
rng = random.Random(world_id)
|
||||
for option_index in range(0, num_options):
|
||||
option = options_to_include[option_index]
|
||||
option_choices = get_option_choices(option)
|
||||
if not option_choices:
|
||||
continue
|
||||
chosen_option_value = rng.choice(list(option_choices.values()))
|
||||
world_options[option.internal_name] = chosen_option_value
|
||||
return world_options
|
||||
|
||||
|
||||
def get_number_log_steps(number_worlds: int) -> int:
|
||||
if number_worlds <= 10:
|
||||
return 2
|
||||
if number_worlds <= 100:
|
||||
return 5
|
||||
if number_worlds <= 500:
|
||||
return 10
|
||||
if number_worlds <= 1000:
|
||||
return 20
|
||||
if number_worlds <= 5000:
|
||||
return 25
|
||||
if number_worlds <= 10000:
|
||||
return 50
|
||||
return 100
|
||||
|
||||
|
||||
def generate_many_worlds(number_worlds: int, start_index: int) -> Dict[int, MultiWorld]:
|
||||
num_steps = get_number_log_steps(number_worlds)
|
||||
log_step = number_worlds / num_steps
|
||||
multiworlds = dict()
|
||||
print(f"Generating {number_worlds} Solo Multiworlds [Start Seed: {start_index}] for Stardew Valley...")
|
||||
for world_number in range(0, number_worlds + 1):
|
||||
world_id = world_number + start_index
|
||||
multiworld = generate_random_multiworld(world_id)
|
||||
multiworlds[world_id] = multiworld
|
||||
if world_number > 0 and world_number % log_step == 0:
|
||||
print(f"Generated {world_number}/{number_worlds} worlds [{(world_number * 100) // number_worlds}%]")
|
||||
print(f"Finished generating {number_worlds} Solo Multiworlds for Stardew Valley")
|
||||
return multiworlds
|
||||
|
||||
|
||||
def check_every_multiworld_is_valid(tester: SVTestBase, multiworlds: Dict[int, MultiWorld]):
|
||||
for multiworld_id in multiworlds:
|
||||
multiworld = multiworlds[multiworld_id]
|
||||
with tester.subTest(f"Checking validity of world {multiworld_id}"):
|
||||
check_multiworld_is_valid(tester, multiworld_id, multiworld)
|
||||
|
||||
|
||||
def check_multiworld_is_valid(tester: SVTestBase, multiworld_id: int, multiworld: MultiWorld):
|
||||
assert_victory_exists(tester, multiworld)
|
||||
assert_same_number_items_locations(tester, multiworld)
|
||||
assert_goal_world_is_valid(tester, multiworld)
|
||||
assert_can_reach_island_if_should(tester, multiworld)
|
||||
assert_cropsanity_same_number_items_and_locations(tester, multiworld)
|
||||
assert_festivals_give_access_to_deluxe_scarecrow(tester, multiworld)
|
||||
|
||||
|
||||
class TestGenerateManyWorlds(SVTestBase):
|
||||
def test_generate_many_worlds_then_check_results(self):
|
||||
if self.skip_long_tests:
|
||||
return
|
||||
number_worlds = 1000
|
||||
start_index = random.Random().randint(0, 9999999999)
|
||||
multiworlds = generate_many_worlds(number_worlds, start_index)
|
||||
check_every_multiworld_is_valid(self, multiworlds)
|
||||
Reference in New Issue
Block a user