add ability to generate items of specific rarity

This commit is contained in:
evilchili 2023-12-31 11:17:11 -08:00
parent d13878a7ce
commit b1aad7b0f4
3 changed files with 47 additions and 14 deletions

View File

@ -39,8 +39,7 @@ metadata:
uncommon: 0.05 uncommon: 0.05
rare: 0.5 rare: 0.5
very rare: 0.5 very rare: 0.5
#legendary: 0.3 legendary: 0.3
legendary: 0.0
common: common:
- 0 - 0
uncommon: uncommon:

View File

@ -280,15 +280,17 @@ class ItemGenerator:
def __init__(self): def __init__(self):
super().__init__( super().__init__(
bases=WeightedSet( bases=WeightedSet(
(dict(name='{type} stick', type='wooden', ...), 0.3), (dict(name='{type} stick', type='wooden'), 0.3),
(dict(name='{type} stick', type='lead', ...), 1.0), (dict(name='{type} stick', type='lead'), 1.0),
(dict(name='{type} stick', type='silver', ...), 0.5), (dict(name='{type} stick', type='silver'), 0.5),
(dict(name='{type} stick', type='glass', ...), 0.1), (dict(name='{type} stick', type='glass'), 0.1),
), ),
raritytypes.RARITY, rarity.types.RARITY,
properties_by_rarity=types.PROPERTIES_BY_RARITY, properties_by_rarity=types.PROPERTIES_BY_RARITY,
) )
# ...Add callbacks for string templates in PROPERTIES_BY_RARITY...
Generating Random Items Generating Random Items
Given an ItemGenerator class, use the ItemGenerator.random() method to Given an ItemGenerator class, use the ItemGenerator.random() method to
@ -300,7 +302,7 @@ class ItemGenerator:
Example: Example:
>>> stick = SharpStickGenerator().random(count=1, challenge_rating=17) >>> stick = SharpStickGenerator().random(count=1, rarity='legendary')
>>> stick[0].name >>> stick[0].name
Silver Stick Silver Stick
>>> stick[0].rarity >>> stick[0].rarity
@ -369,7 +371,7 @@ class ItemGenerator:
return set(getreqs(item)) return set(getreqs(item))
def random_properties(self) -> dict: def random_properties(self, rarity: str = '') -> dict:
""" """
Create a dictionary of item attributes appropriate for a given rarity. Create a dictionary of item attributes appropriate for a given rarity.
Dictionaries generated by this method are used as arguments to the Dictionaries generated by this method are used as arguments to the
@ -395,13 +397,16 @@ class ItemGenerator:
This will result in: This will result in:
>>> item['extras']['owner'] >>> item['extras']['owner']
Jules Ultandottir Jules Ultardottir
""" """
# select a random base # select a random base
item = self.bases.random() item = self.bases.random()
# select a random rarity # select a random rarity
if rarity:
item["rarity"] = self.rarity.source.as_dict()[rarity]
else:
item["rarity"] = self.rarity.random() item["rarity"] = self.rarity.random()
# select a number of properties appropriate to the rarity # select a number of properties appropriate to the rarity
@ -431,12 +436,12 @@ class ItemGenerator:
try: try:
item[requirement] = getattr(self, f"get_{requirement}")(**item) item[requirement] = getattr(self, f"get_{requirement}")(**item)
except AttributeError: except AttributeError:
logging.error("{item['name']} requires {self.__class__.__name__} to have a get_{requirement}() method.") logging.error(f"{item['name']} requires {self.__class__.__name__} to define get_{requirement}().")
raise raise
return item return item
def random(self, count: int = 1, challenge_rating: int = 0) -> list: def random(self, count: int = 1, challenge_rating: int = 0, rarity: str = '') -> list:
""" """
Generate one or more random Item instances by selecting random values Generate one or more random Item instances by selecting random values
from the available data sources, appropriate to the specified challenge from the available data sources, appropriate to the specified challenge
@ -446,6 +451,9 @@ class ItemGenerator:
an encounter for an adventuring party of four. This will prevent an encounter for an adventuring party of four. This will prevent
lower-level encounters from generating legendary weapons and so on. If lower-level encounters from generating legendary weapons and so on. If
challenge_rating is 0, a rarity is chosen at random. challenge_rating is 0, a rarity is chosen at random.
If a rarity is supplied, ensure we return items of that rarity; in this
case challenge_rating is ignored.
""" """
if challenge_rating in range(1, 5): if challenge_rating in range(1, 5):
frequency = "1-4" frequency = "1-4"
@ -461,7 +469,7 @@ class ItemGenerator:
items = [] items = []
for _ in range(count): for _ in range(count):
items.append(self.item_class.from_dict(self.random_properties())) items.append(self.item_class.from_dict(self.random_properties(rarity=rarity)))
return items return items

View File

@ -61,3 +61,29 @@ def test_Item_overrides():
ten_foot_pole = types.Item.from_dict(attrs) ten_foot_pole = types.Item.from_dict(attrs)
assert ten_foot_pole.name == '7ft. Pole' assert ten_foot_pole.name == '7ft. Pole'
assert ten_foot_pole.description == 'Broken. The end of this 10ft. pole has been snapped off.' assert ten_foot_pole.description == 'Broken. The end of this 10ft. pole has been snapped off.'
def test_ItemGenerator_subclass():
class SharpStickGenerator(types.ItemGenerator):
def __init__(self):
super().__init__(
bases=types.WeightedSet(
(dict(name='{type} stick', type='wooden'), 0.3),
(dict(name='{type} stick', type='lead'), 1.0),
(dict(name='{type} stick', type='silver'), 0.5),
(dict(name='{type} stick', type='glass'), 0.1),
),
rarity=types.RARITY,
properties_by_rarity=types.PROPERTIES_BY_RARITY,
)
stick = SharpStickGenerator().random(count=1, rarity='common')
assert stick[0].name in [
'wooden stick',
'lead stick',
'silver stick',
'glass stick',
]
assert stick[0].rarity.rarity == 'common'
assert stick[0].description == ''