2023-02-27 00:19:15 +00:00
import csv
import enum
import logging
from dataclasses import dataclass , field
from pathlib import Path
from random import Random
2023-07-19 18:26:38 +00:00
from typing import Dict , List , Protocol , Union , Set , Optional
2023-02-27 00:19:15 +00:00
from BaseClasses import Item , ItemClassification
from . import options , data
2023-04-10 23:44:59 +00:00
from . data . villagers_data import all_villagers
2023-07-19 18:26:38 +00:00
from . mods . mod_data import ModNames
2023-04-10 23:44:59 +00:00
from . options import StardewOptions
2023-07-19 18:26:38 +00:00
from . strings . ap_names . buff_names import Buff
2023-02-27 00:19:15 +00:00
ITEM_CODE_OFFSET = 717000
logger = logging . getLogger ( __name__ )
world_folder = Path ( __file__ ) . parent
class Group ( enum . Enum ) :
RESOURCE_PACK = enum . auto ( )
FRIENDSHIP_PACK = enum . auto ( )
COMMUNITY_REWARD = enum . auto ( )
TRASH = enum . auto ( )
MINES_FLOOR_10 = enum . auto ( )
MINES_FLOOR_20 = enum . auto ( )
MINES_FLOOR_50 = enum . auto ( )
MINES_FLOOR_60 = enum . auto ( )
MINES_FLOOR_80 = enum . auto ( )
MINES_FLOOR_90 = enum . auto ( )
MINES_FLOOR_110 = enum . auto ( )
FOOTWEAR = enum . auto ( )
HATS = enum . auto ( )
RING = enum . auto ( )
WEAPON = enum . auto ( )
PROGRESSIVE_TOOLS = enum . auto ( )
SKILL_LEVEL_UP = enum . auto ( )
ARCADE_MACHINE_BUFFS = enum . auto ( )
GALAXY_WEAPONS = enum . auto ( )
BASE_RESOURCE = enum . auto ( )
WARP_TOTEM = enum . auto ( )
GEODE = enum . auto ( )
ORE = enum . auto ( )
FERTILIZER = enum . auto ( )
SEED = enum . auto ( )
2023-07-19 18:26:38 +00:00
CROPSANITY = enum . auto ( )
2023-02-27 00:19:15 +00:00
FISHING_RESOURCE = enum . auto ( )
2023-04-10 23:44:59 +00:00
SEASON = enum . auto ( )
TRAVELING_MERCHANT_DAY = enum . auto ( )
MUSEUM = enum . auto ( )
FRIENDSANITY = enum . auto ( )
2023-07-19 18:26:38 +00:00
FESTIVAL = enum . auto ( )
RARECROW = enum . auto ( )
TRAP = enum . auto ( )
MAXIMUM_ONE = enum . auto ( )
2023-07-24 23:52:15 +00:00
EXACTLY_TWO = enum . auto ( )
2023-07-19 18:26:38 +00:00
DEPRECATED = enum . auto ( )
RESOURCE_PACK_USEFUL = enum . auto ( )
SPECIAL_ORDER_BOARD = enum . auto ( )
SPECIAL_ORDER_QI = enum . auto ( )
BABY = enum . auto ( )
GINGER_ISLAND = enum . auto ( )
WALNUT_PURCHASE = enum . auto ( )
TV_CHANNEL = enum . auto ( )
MAGIC_SPELL = enum . auto ( )
2023-02-27 00:19:15 +00:00
@dataclass ( frozen = True )
class ItemData :
code_without_offset : Optional [ int ]
name : str
classification : ItemClassification
2023-07-19 18:26:38 +00:00
mod_name : Optional [ str ] = None
2023-02-27 00:19:15 +00:00
groups : Set [ Group ] = field ( default_factory = frozenset )
def __post_init__ ( self ) :
if not isinstance ( self . groups , frozenset ) :
super ( ) . __setattr__ ( " groups " , frozenset ( self . groups ) )
@property
def code ( self ) :
return ITEM_CODE_OFFSET + self . code_without_offset if self . code_without_offset is not None else None
def has_any_group ( self , * group : Group ) - > bool :
groups = set ( group )
return bool ( groups . intersection ( self . groups ) )
class StardewItemFactory ( Protocol ) :
def __call__ ( self , name : Union [ str , ItemData ] ) - > Item :
raise NotImplementedError
def load_item_csv ( ) :
try :
from importlib . resources import files
except ImportError :
2023-04-10 23:44:59 +00:00
from importlib_resources import files # noqa
2023-02-27 00:19:15 +00:00
items = [ ]
with files ( data ) . joinpath ( " items.csv " ) . open ( ) as file :
item_reader = csv . DictReader ( file )
for item in item_reader :
id = int ( item [ " id " ] ) if item [ " id " ] else None
classification = ItemClassification [ item [ " classification " ] ]
groups = { Group [ group ] for group in item [ " groups " ] . split ( " , " ) if group }
2023-07-19 18:26:38 +00:00
mod_name = str ( item [ " mod_name " ] ) if item [ " mod_name " ] else None
items . append ( ItemData ( id , item [ " name " ] , classification , mod_name , groups ) )
2023-02-27 00:19:15 +00:00
return items
events = [
ItemData ( None , " Victory " , ItemClassification . progression ) ,
2023-04-10 23:44:59 +00:00
ItemData ( None , " Month End " , ItemClassification . progression ) ,
2023-02-27 00:19:15 +00:00
]
all_items : List [ ItemData ] = load_item_csv ( ) + events
item_table : Dict [ str , ItemData ] = { }
items_by_group : Dict [ Group , List [ ItemData ] ] = { }
def initialize_groups ( ) :
for item in all_items :
for group in item . groups :
item_group = items_by_group . get ( group , list ( ) )
item_group . append ( item )
items_by_group [ group ] = item_group
def initialize_item_table ( ) :
item_table . update ( { item . name : item for item in all_items } )
initialize_item_table ( )
initialize_groups ( )
2023-07-19 18:26:38 +00:00
def create_items ( item_factory : StardewItemFactory , locations_count : int , items_to_exclude : List [ Item ] ,
world_options : StardewOptions ,
2023-04-10 23:44:59 +00:00
random : Random ) - > List [ Item ] :
2023-07-19 18:26:38 +00:00
items = [ ]
unique_items = create_unique_items ( item_factory , world_options , random )
2023-04-10 23:44:59 +00:00
for item in items_to_exclude :
2023-07-19 18:26:38 +00:00
if item in unique_items :
unique_items . remove ( item )
assert len ( unique_items ) < = locations_count , f " There should be at least as many locations [ { locations_count } ] as there are mandatory items [ { len ( unique_items ) } ] "
items + = unique_items
logger . debug ( f " Created { len ( unique_items ) } unique items " )
2023-04-10 23:44:59 +00:00
2023-07-19 18:26:38 +00:00
unique_filler_items = create_unique_filler_items ( item_factory , world_options , random , locations_count - len ( items ) )
items + = unique_filler_items
logger . debug ( f " Created { len ( unique_filler_items ) } unique filler items " )
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
resource_pack_items = fill_with_resource_packs_and_traps ( item_factory , world_options , random , items , locations_count )
2023-02-27 00:19:15 +00:00
items + = resource_pack_items
logger . debug ( f " Created { len ( resource_pack_items ) } resource packs " )
return items
2023-04-10 23:44:59 +00:00
def create_unique_items ( item_factory : StardewItemFactory , world_options : StardewOptions , random : Random ) - > List [ Item ] :
items = [ ]
items . extend ( item_factory ( item ) for item in items_by_group [ Group . COMMUNITY_REWARD ] )
create_backpack_items ( item_factory , world_options , items )
create_mine_rewards ( item_factory , items , random )
2023-07-19 18:26:38 +00:00
create_elevators ( item_factory , world_options , items )
2023-04-10 23:44:59 +00:00
create_tools ( item_factory , world_options , items )
create_skills ( item_factory , world_options , items )
2023-07-19 18:26:38 +00:00
create_wizard_buildings ( item_factory , world_options , items )
2023-04-10 23:44:59 +00:00
create_carpenter_buildings ( item_factory , world_options , items )
items . append ( item_factory ( " Beach Bridge " ) )
2023-07-19 18:26:38 +00:00
items . append ( item_factory ( " Dark Talisman " ) )
create_tv_channels ( item_factory , items )
2023-04-10 23:44:59 +00:00
create_special_quest_rewards ( item_factory , items )
2023-07-19 18:26:38 +00:00
create_stardrops ( item_factory , world_options , items )
2023-04-10 23:44:59 +00:00
create_museum_items ( item_factory , world_options , items )
create_arcade_machine_items ( item_factory , world_options , items )
items . append ( item_factory ( random . choice ( items_by_group [ Group . GALAXY_WEAPONS ] ) ) )
create_player_buffs ( item_factory , world_options , items )
2023-07-19 18:26:38 +00:00
create_traveling_merchant_items ( item_factory , items )
2023-04-10 23:44:59 +00:00
items . append ( item_factory ( " Return Scepter " ) )
2023-07-19 18:26:38 +00:00
create_seasons ( item_factory , world_options , items )
create_seeds ( item_factory , world_options , items )
2023-04-10 23:44:59 +00:00
create_friendsanity_items ( item_factory , world_options , items )
2023-07-19 18:26:38 +00:00
create_festival_rewards ( item_factory , world_options , items )
create_babies ( item_factory , items , random )
create_special_order_board_rewards ( item_factory , world_options , items )
create_special_order_qi_rewards ( item_factory , world_options , items )
create_walnut_purchase_rewards ( item_factory , world_options , items )
create_magic_mod_spells ( item_factory , world_options , items )
2023-04-10 23:44:59 +00:00
return items
def create_backpack_items ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-02-27 00:19:15 +00:00
if ( world_options [ options . BackpackProgression ] == options . BackpackProgression . option_progressive or
world_options [ options . BackpackProgression ] == options . BackpackProgression . option_early_progressive ) :
items . extend ( item_factory ( item ) for item in [ " Progressive Backpack " ] * 2 )
2023-07-19 18:26:38 +00:00
if ModNames . big_backpack in world_options [ options . Mods ] :
items . append ( item_factory ( " Progressive Backpack " ) )
2023-02-27 00:19:15 +00:00
def create_mine_rewards ( item_factory : StardewItemFactory , items : List [ Item ] , random : Random ) :
items . append ( item_factory ( " Rusty Sword " ) )
items . append ( item_factory ( random . choice ( items_by_group [ Group . MINES_FLOOR_10 ] ) ) )
items . append ( item_factory ( random . choice ( items_by_group [ Group . MINES_FLOOR_20 ] ) ) )
items . append ( item_factory ( " Slingshot " ) )
items . append ( item_factory ( random . choice ( items_by_group [ Group . MINES_FLOOR_50 ] ) ) )
items . append ( item_factory ( random . choice ( items_by_group [ Group . MINES_FLOOR_60 ] ) ) )
items . append ( item_factory ( " Master Slingshot " ) )
items . append ( item_factory ( random . choice ( items_by_group [ Group . MINES_FLOOR_80 ] ) ) )
items . append ( item_factory ( random . choice ( items_by_group [ Group . MINES_FLOOR_90 ] ) ) )
items . append ( item_factory ( random . choice ( items_by_group [ Group . MINES_FLOOR_110 ] ) ) )
items . append ( item_factory ( " Skull Key " ) )
2023-07-19 18:26:38 +00:00
def create_elevators ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if world_options [ options . ElevatorProgression ] == options . ElevatorProgression . option_vanilla :
return
items . extend ( [ item_factory ( item ) for item in [ " Progressive Mine Elevator " ] * 24 ] )
if ModNames . deepwoods in world_options [ options . Mods ] :
2023-07-23 04:23:03 +00:00
items . extend ( [ item_factory ( item ) for item in [ " Progressive Woods Obelisk Sigils " ] * 10 ] )
2023-07-19 18:26:38 +00:00
if ModNames . skull_cavern_elevator in world_options [ options . Mods ] :
items . extend ( [ item_factory ( item ) for item in [ " Progressive Skull Cavern Elevator " ] * 8 ] )
2023-02-27 00:19:15 +00:00
2023-04-10 23:44:59 +00:00
def create_tools ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-02-27 00:19:15 +00:00
if world_options [ options . ToolProgression ] == options . ToolProgression . option_progressive :
items . extend ( item_factory ( item ) for item in items_by_group [ Group . PROGRESSIVE_TOOLS ] * 4 )
items . append ( item_factory ( " Golden Scythe " ) )
2023-04-10 23:44:59 +00:00
def create_skills ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-02-27 00:19:15 +00:00
if world_options [ options . SkillProgression ] == options . SkillProgression . option_progressive :
2023-07-19 18:26:38 +00:00
for item in items_by_group [ Group . SKILL_LEVEL_UP ] :
if item . mod_name not in world_options [ options . Mods ] and item . mod_name is not None :
continue
items . extend ( item_factory ( item ) for item in [ item . name ] * 10 )
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
def create_wizard_buildings ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-02-27 00:19:15 +00:00
items . append ( item_factory ( " Earth Obelisk " ) )
items . append ( item_factory ( " Water Obelisk " ) )
items . append ( item_factory ( " Desert Obelisk " ) )
items . append ( item_factory ( " Junimo Hut " ) )
items . append ( item_factory ( " Gold Clock " ) )
2023-07-19 18:26:38 +00:00
if world_options [ options . ExcludeGingerIsland ] == options . ExcludeGingerIsland . option_false :
items . append ( item_factory ( " Island Obelisk " ) )
if ModNames . deepwoods in world_options [ options . Mods ] :
items . append ( item_factory ( " Woods Obelisk " ) )
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
def create_carpenter_buildings ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-02-27 00:19:15 +00:00
if world_options [ options . BuildingProgression ] in { options . BuildingProgression . option_progressive ,
options . BuildingProgression . option_progressive_early_shipping_bin } :
items . append ( item_factory ( " Progressive Coop " ) )
items . append ( item_factory ( " Progressive Coop " ) )
items . append ( item_factory ( " Progressive Coop " ) )
items . append ( item_factory ( " Progressive Barn " ) )
items . append ( item_factory ( " Progressive Barn " ) )
items . append ( item_factory ( " Progressive Barn " ) )
items . append ( item_factory ( " Well " ) )
items . append ( item_factory ( " Silo " ) )
items . append ( item_factory ( " Mill " ) )
items . append ( item_factory ( " Progressive Shed " ) )
items . append ( item_factory ( " Progressive Shed " ) )
items . append ( item_factory ( " Fish Pond " ) )
items . append ( item_factory ( " Stable " ) )
items . append ( item_factory ( " Slime Hutch " ) )
items . append ( item_factory ( " Shipping Bin " ) )
items . append ( item_factory ( " Progressive House " ) )
items . append ( item_factory ( " Progressive House " ) )
items . append ( item_factory ( " Progressive House " ) )
2023-07-19 18:26:38 +00:00
if ModNames . tractor in world_options [ options . Mods ] :
items . append ( item_factory ( " Tractor Garage " ) )
2023-02-27 00:19:15 +00:00
def create_special_quest_rewards ( item_factory : StardewItemFactory , items : List [ Item ] ) :
items . append ( item_factory ( " Adventurer ' s Guild " ) )
items . append ( item_factory ( " Club Card " ) )
items . append ( item_factory ( " Magnifying Glass " ) )
items . append ( item_factory ( " Bear ' s Knowledge " ) )
items . append ( item_factory ( " Iridium Snake Milk " ) )
2023-07-19 18:26:38 +00:00
def create_stardrops ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-02-27 00:19:15 +00:00
items . append ( item_factory ( " Stardrop " ) ) # The Mines level 100
items . append ( item_factory ( " Stardrop " ) ) # Old Master Cannoli
2023-07-19 18:26:38 +00:00
if world_options [ options . Fishsanity ] != options . Fishsanity . option_none :
items . append ( item_factory ( " Stardrop " ) ) #Master Angler Stardrop
if ModNames . deepwoods in world_options [ options . Mods ] :
items . append ( item_factory ( " Stardrop " ) ) # Petting the Unicorn
2023-02-27 00:19:15 +00:00
2023-04-10 23:44:59 +00:00
def create_museum_items ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if world_options [ options . Museumsanity ] == options . Museumsanity . option_none :
return
items . extend ( item_factory ( item ) for item in [ " Magic Rock Candy " ] * 5 )
items . extend ( item_factory ( item ) for item in [ " Ancient Seeds " ] * 5 )
items . extend ( item_factory ( item ) for item in [ " Traveling Merchant Metal Detector " ] * 4 )
items . append ( item_factory ( " Ancient Seeds Recipe " ) )
items . append ( item_factory ( " Stardrop " ) )
items . append ( item_factory ( " Rusty Key " ) )
items . append ( item_factory ( " Dwarvish Translation Guide " ) )
def create_friendsanity_items ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if world_options [ options . Friendsanity ] == options . Friendsanity . option_none :
return
exclude_non_bachelors = world_options [ options . Friendsanity ] == options . Friendsanity . option_bachelors
exclude_locked_villagers = world_options [ options . Friendsanity ] == options . Friendsanity . option_starting_npcs or \
world_options [ options . Friendsanity ] == options . Friendsanity . option_bachelors
2023-07-19 18:26:38 +00:00
include_post_marriage_hearts = world_options [ options . Friendsanity ] == options . Friendsanity . option_all_with_marriage
exclude_ginger_island = world_options [ options . ExcludeGingerIsland ] == options . ExcludeGingerIsland . option_true
heart_size = world_options [ options . FriendsanityHeartSize ]
2023-04-10 23:44:59 +00:00
for villager in all_villagers :
2023-07-19 18:26:38 +00:00
if villager . mod_name not in world_options [ options . Mods ] and villager . mod_name is not None :
continue
2023-04-10 23:44:59 +00:00
if not villager . available and exclude_locked_villagers :
continue
if not villager . bachelor and exclude_non_bachelors :
continue
2023-07-19 18:26:38 +00:00
if villager . name == " Leo " and exclude_ginger_island :
continue
heart_cap = 8 if villager . bachelor else 10
if include_post_marriage_hearts and villager . bachelor :
heart_cap = 14
2023-04-10 23:44:59 +00:00
for heart in range ( 1 , 15 ) :
2023-07-19 18:26:38 +00:00
if heart > heart_cap :
break
if heart % heart_size == 0 or heart == heart_cap :
items . append ( item_factory ( f " { villager . name } <3 " ) )
2023-04-10 23:44:59 +00:00
if not exclude_non_bachelors :
for heart in range ( 1 , 6 ) :
2023-07-19 18:26:38 +00:00
if heart % heart_size == 0 or heart == 5 :
items . append ( item_factory ( f " Pet <3 " ) )
2023-04-10 23:44:59 +00:00
2023-07-19 18:26:38 +00:00
def create_babies ( item_factory : StardewItemFactory , items : List [ Item ] , random : Random ) :
baby_items = [ item for item in items_by_group [ Group . BABY ] ]
for i in range ( 2 ) :
chosen_baby = random . choice ( baby_items )
items . append ( item_factory ( chosen_baby ) )
2023-04-10 23:44:59 +00:00
2023-07-19 18:26:38 +00:00
def create_arcade_machine_items ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-02-27 00:19:15 +00:00
if world_options [ options . ArcadeMachineLocations ] == options . ArcadeMachineLocations . option_full_shuffling :
items . append ( item_factory ( " JotPK: Progressive Boots " ) )
items . append ( item_factory ( " JotPK: Progressive Boots " ) )
items . append ( item_factory ( " JotPK: Progressive Gun " ) )
items . append ( item_factory ( " JotPK: Progressive Gun " ) )
items . append ( item_factory ( " JotPK: Progressive Gun " ) )
items . append ( item_factory ( " JotPK: Progressive Gun " ) )
items . append ( item_factory ( " JotPK: Progressive Ammo " ) )
items . append ( item_factory ( " JotPK: Progressive Ammo " ) )
items . append ( item_factory ( " JotPK: Progressive Ammo " ) )
items . append ( item_factory ( " JotPK: Extra Life " ) )
items . append ( item_factory ( " JotPK: Extra Life " ) )
items . append ( item_factory ( " JotPK: Increased Drop Rate " ) )
items . extend ( item_factory ( item ) for item in [ " Junimo Kart: Extra Life " ] * 8 )
def create_player_buffs ( item_factory : StardewItemFactory , world_options : options . StardewOptions , items : List [ Item ] ) :
2023-07-19 18:26:38 +00:00
number_of_movement_buffs : int = world_options [ options . NumberOfMovementBuffs ]
number_of_luck_buffs : int = world_options [ options . NumberOfLuckBuffs ]
items . extend ( item_factory ( item ) for item in [ Buff . movement ] * number_of_movement_buffs )
items . extend ( item_factory ( item ) for item in [ Buff . luck ] * number_of_luck_buffs )
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
def create_traveling_merchant_items ( item_factory : StardewItemFactory , items : List [ Item ] ) :
items . extend ( [ * ( item_factory ( item ) for item in items_by_group [ Group . TRAVELING_MERCHANT_DAY ] ) ,
* ( item_factory ( item ) for item in [ " Traveling Merchant Stock Size " ] * 6 ) ,
* ( item_factory ( item ) for item in [ " Traveling Merchant Discount " ] * 8 ) ] )
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
def create_seasons ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
2023-04-10 23:44:59 +00:00
if world_options [ options . SeasonRandomization ] == options . SeasonRandomization . option_disabled :
2023-07-19 18:26:38 +00:00
return
2023-02-27 00:19:15 +00:00
2023-04-10 23:44:59 +00:00
if world_options [ options . SeasonRandomization ] == options . SeasonRandomization . option_progressive :
2023-07-19 18:26:38 +00:00
items . extend ( [ item_factory ( item ) for item in [ " Progressive Season " ] * 3 ] )
return
items . extend ( [ item_factory ( item ) for item in items_by_group [ Group . SEASON ] ] )
def create_seeds ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if world_options [ options . Cropsanity ] == options . Cropsanity . option_disabled :
return
include_ginger_island = world_options [ options . ExcludeGingerIsland ] != options . ExcludeGingerIsland . option_true
seed_items = [ item_factory ( item ) for item in items_by_group [ Group . CROPSANITY ] if include_ginger_island or Group . GINGER_ISLAND not in item . groups ]
items . extend ( seed_items )
def create_festival_rewards ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if world_options [ options . FestivalLocations ] == options . FestivalLocations . option_disabled :
return
items . extend ( [ * [ item_factory ( item ) for item in items_by_group [ Group . FESTIVAL ] if item . classification != ItemClassification . filler ] ,
item_factory ( " Stardrop " ) ] )
def create_walnut_purchase_rewards ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if world_options [ options . ExcludeGingerIsland ] == options . ExcludeGingerIsland . option_true :
return
items . extend ( [ item_factory ( " Boat Repair " ) ,
item_factory ( " Open Professor Snail Cave " ) ,
item_factory ( " Ostrich Incubator Recipe " ) ,
2023-07-21 17:56:03 +00:00
item_factory ( " Treehouse " ) ,
2023-07-19 18:26:38 +00:00
* [ item_factory ( item ) for item in items_by_group [ Group . WALNUT_PURCHASE ] ] ] )
def create_special_order_board_rewards ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if world_options [ options . SpecialOrderLocations ] == options . SpecialOrderLocations . option_disabled :
return
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
items . extend ( [ item_factory ( item ) for item in items_by_group [ Group . SPECIAL_ORDER_BOARD ] ] )
2023-02-27 00:19:15 +00:00
2023-04-10 23:44:59 +00:00
2023-07-19 18:26:38 +00:00
def create_special_order_qi_rewards ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if ( world_options [ options . SpecialOrderLocations ] != options . SpecialOrderLocations . option_board_qi or
world_options [ options . ExcludeGingerIsland ] == options . ExcludeGingerIsland . option_true ) :
return
qi_gem_rewards = [ " 100 Qi Gems " , " 10 Qi Gems " , " 40 Qi Gems " , " 25 Qi Gems " , " 25 Qi Gems " ,
" 40 Qi Gems " , " 20 Qi Gems " , " 50 Qi Gems " , " 40 Qi Gems " , " 35 Qi Gems " ]
qi_gem_items = [ item_factory ( reward ) for reward in qi_gem_rewards ]
items . extend ( qi_gem_items )
def create_tv_channels ( item_factory : StardewItemFactory , items : List [ Item ] ) :
items . extend ( [ item_factory ( item ) for item in items_by_group [ Group . TV_CHANNEL ] ] )
def create_filler_festival_rewards ( item_factory : StardewItemFactory , world_options : StardewOptions ) - > List [ Item ] :
if world_options [ options . FestivalLocations ] == options . FestivalLocations . option_disabled :
2023-04-10 23:44:59 +00:00
return [ ]
2023-07-19 18:26:38 +00:00
return [ item_factory ( item ) for item in items_by_group [ Group . FESTIVAL ] if
item . classification == ItemClassification . filler ]
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
def create_magic_mod_spells ( item_factory : StardewItemFactory , world_options : StardewOptions , items : List [ Item ] ) :
if ModNames . magic not in world_options [ options . Mods ] :
return [ ]
items . extend ( [ item_factory ( item ) for item in items_by_group [ Group . MAGIC_SPELL ] ] )
2023-02-27 00:19:15 +00:00
2023-07-19 18:26:38 +00:00
def create_unique_filler_items ( item_factory : StardewItemFactory , world_options : options . StardewOptions , random : Random ,
available_item_slots : int ) - > List [ Item ] :
2023-02-27 00:19:15 +00:00
items = [ ]
2023-07-19 18:26:38 +00:00
items . extend ( create_filler_festival_rewards ( item_factory , world_options ) )
if len ( items ) > available_item_slots :
items = random . sample ( items , available_item_slots )
return items
def fill_with_resource_packs_and_traps ( item_factory : StardewItemFactory , world_options : options . StardewOptions , random : Random ,
items_already_added : List [ Item ] ,
number_locations : int ) - > List [ Item ] :
include_traps = world_options [ options . TrapItems ] != options . TrapItems . option_no_traps
all_filler_packs = [ pack for pack in items_by_group [ Group . RESOURCE_PACK ] ]
all_filler_packs . extend ( items_by_group [ Group . TRASH ] )
if include_traps :
all_filler_packs . extend ( items_by_group [ Group . TRAP ] )
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 ]
if pack . name not in items_already_added_names ]
trap_items = [ pack for pack in items_by_group [ Group . TRAP ]
if pack . name not in items_already_added_names and
( pack . mod_name is None or pack . mod_name in world_options [ options . Mods ] ) ]
priority_filler_items = [ ]
priority_filler_items . extend ( useful_resource_packs )
if include_traps :
priority_filler_items . extend ( trap_items )
all_filler_packs = remove_excluded_packs ( all_filler_packs , world_options )
priority_filler_items = remove_excluded_packs ( priority_filler_items , world_options )
number_priority_items = len ( priority_filler_items )
required_resource_pack = number_locations - len ( items_already_added )
if required_resource_pack < number_priority_items :
chosen_priority_items = [ item_factory ( resource_pack ) for resource_pack in
random . sample ( priority_filler_items , required_resource_pack ) ]
return chosen_priority_items
items = [ ]
chosen_priority_items = [ item_factory ( resource_pack ) for resource_pack in priority_filler_items ]
items . extend ( chosen_priority_items )
required_resource_pack - = 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 ] ]
while required_resource_pack > 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 :
resource_pack = random . choice ( all_filler_packs )
exactly_2 = Group . EXACTLY_TWO in resource_pack . groups
items . append ( item_factory ( resource_pack ) )
required_resource_pack - = 1
if exactly_2 :
items . append ( item_factory ( resource_pack ) )
required_resource_pack - = 1
if exactly_2 or Group . MAXIMUM_ONE in resource_pack . groups :
all_filler_packs . remove ( resource_pack )
2023-02-27 00:19:15 +00:00
return items
2023-07-19 18:26:38 +00:00
def remove_excluded_packs ( packs , world_options ) :
included_packs = [ pack for pack in packs if Group . DEPRECATED not in pack . groups ]
if world_options [ options . ExcludeGingerIsland ] == options . ExcludeGingerIsland . option_true :
included_packs = [ pack for pack in included_packs if Group . GINGER_ISLAND not in pack . groups ]
return included_packs