diff --git a/deadsands/site_tools/jobs.py b/deadsands/site_tools/jobs.py index 34717ef..21d717d 100644 --- a/deadsands/site_tools/jobs.py +++ b/deadsands/site_tools/jobs.py @@ -1,12 +1,29 @@ import random import collections +from pathlib import Path +from rolltable.tables import RollTable from npc.generator.base import generate_npc Crime = collections.namedtuple('Crime', ['name', 'min_bounty', 'max_bounty']) +def generate_location(frequency='default'): + source = Path("sources/locations.yaml") + rt = RollTable([source.read_text()], hide_rolls=True, frequency=frequency) + return random.choice(rt.rows[1:])[1] + + +def nearest(value, step=50): + if value < step: + return step + remainder = value % step + if remainder > int(step / 2): + return value - remainder + step + return value - remainder + + class BaseJob: """ The base class for random odd jobs. @@ -22,7 +39,7 @@ class BaseJob: self._name = name self._details = details self._reward = reward - self._contact = contact + self._contact = contact or generate_npc() self._location = location @property @@ -87,8 +104,7 @@ class Bounty(BaseJob): self._dead_or_alive = ' or '.join(dead_or_alive) if not self._reward: - # need to round to the nearest 10 < 100, nearest 100 otherwise - reward = round(random.randint(self.crime.min_bounty, self.crime.max_bounty), 5) + reward = nearest(random.randint(self.crime.min_bounty, self.crime.max_bounty)) self._reward = f"{reward} Gold Pieces" if not self._name: @@ -117,6 +133,48 @@ class Bounty(BaseJob): return self._target +class Determinant(BaseJob): + """ + Hiring the services of a Determinant to resolve a dispute. + """ + def __init__(self, **kwargs): + super().__init__(**kwargs) + + +class Escort(BaseJob): + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._contact = generate_npc() + self._location = generate_location('settlements') + self._destination = generate_location('default') + self._reward = f"{nearest(random.randint(5, 20), step=5)} GP/day" + self._name = ( + f"Accompany {self.contact} from {self.location} to " + f"{self._destination}. {self.reward}" + ) + + +class Foraging(BaseJob): + + def __init__(self, **kwargs): + super().__init__(**kwargs) + + source = Path("sources/flora.yaml") + rt = RollTable([source.read_text()], hide_rolls=True) + + # [ rarity, name, descr, val ] + self._ingredient = random.choice(rt.rows) + + self._amount = nearest(random.randint(0, 300), step=25) + value = self._amount * int(self._ingredient[3].split(' ')[0]) + bonus = nearest(random.randint(0, 200)) + self._reward = f"{value} GP + {bonus} GP Bonus" + + self._name = f"{self.reward} for {self._amount} {self._ingredient[1]}" + self._contact = "Andok" + self._location = "Andok's Apothecary, Tano's Edge" + + classes = BaseJob.__subclasses__() job_types = [c.__name__ for c in classes] @@ -126,4 +184,5 @@ def generate_job(): if __name__ == '__main__': - print(Bounty()) + for i in range(10): + print(Escort()) diff --git a/deadsands/sources/flora.yaml b/deadsands/sources/flora.yaml index b7f3c58..197a458 100644 --- a/deadsands/sources/flora.yaml +++ b/deadsands/sources/flora.yaml @@ -142,7 +142,7 @@ Weird: - A jet black conical mushroom. The soil around it turns jet black. Said to grant visions when ingested. - 5 GP - Rolling Cactus: - - A globular cactus that rolls and bounces freely in the wind. 1 gallon of water can be harvested from 10 cacti. + - A globular cactus that rolls and bounces freely in the wind. - 5 GP - Orc's Fart: - A large succulent up to 4ft in height, which continually produces a pungent gas, swelling the bulb. When the bulb is forced open, a toxic cloud 20ft in diameter is expelled. DC 13 CON save or 1d4 poison dmg. diff --git a/deadsands/sources/locations.yaml b/deadsands/sources/locations.yaml new file mode 100644 index 0000000..aa43562 --- /dev/null +++ b/deadsands/sources/locations.yaml @@ -0,0 +1,27 @@ +# locations +metadata: + headers: + - Name + frequencies: + default: + Settlements: 0.5 + Sahwat: 0.5 + settlements: + Settlements: 1.0 + Sahwat: 0.0 + sahwat: + Settlements: 0.0 + Sahwat: 1.0 +Settlements: + - Tano's Edge + - The Heap + - Gazakh Noch + - Poshni Koth +Sahwat: + - Blooming Wastes + - Dust River Canyon + - Gopher Gulch + - Calamity Ridge + - The Haunted Hills + - Bone City + - The Undersands diff --git a/deadsands/test/test_jobs.py b/deadsands/test/test_jobs.py new file mode 100644 index 0000000..d7c6cc4 --- /dev/null +++ b/deadsands/test/test_jobs.py @@ -0,0 +1,21 @@ +import pytest + +from site_tools import jobs + + +@pytest.mark.parametrize('value, step, expected', [ + (0, 50, 50), + (49, 50, 50), + (51, 50, 50), + (99, 50, 100), + (100, 50, 100), + (101, 50, 100), + (124, 50, 100), + (125, 50, 100), + (126, 50, 150), + (150, 50, 150), + (151, 50, 150), + (199, 50, 200) +]) +def test_nearest(value, step, expected): + assert jobs.nearest(value, step=step) == expected