diff --git a/deadsands/site_tools/jobs.py b/deadsands/site_tools/jobs.py new file mode 100644 index 0000000..34717ef --- /dev/null +++ b/deadsands/site_tools/jobs.py @@ -0,0 +1,129 @@ +import random +import collections + +from npc.generator.base import generate_npc + + +Crime = collections.namedtuple('Crime', ['name', 'min_bounty', 'max_bounty']) + + +class BaseJob: + """ + The base class for random odd jobs. + """ + def __init__( + self, + name=None, + details=None, + reward=None, + contact=None, + location=None + ): + self._name = name + self._details = details + self._reward = reward + self._contact = contact + self._location = location + + @property + def name(self): + return self._name + + @property + def details(self): + if not self._details: + self._details = ( + f"Speak to {self.contact} in {self.location}. " + ) + return self._details + + @property + def reward(self): + return self._reward + + @property + def contact(self): + return self._contact + + @property + def location(self): + return self._location + + def __repr__(self): + return f"{self.__class__.__name__}: {self.name}\n{self.details}" + + +class Bounty(BaseJob): + """ + A Bounty job. + """ + + crimes = [ + Crime(name='theft', min_bounty=50, max_bounty=500), + Crime(name='overdue faction fees', min_bounty=50, max_bounty=500), + Crime(name='unpaid bar tab', min_bounty=50, max_bounty=100), + Crime(name="unpaid debt", min_bounty=50, max_bounty=200), + Crime(name='cattle rustling', min_bounty=200, max_bounty=1000), + Crime(name='murder', min_bounty=500, max_bounty=2000), + Crime(name='kidnapping', min_bounty=500, max_bounty=2000) + ] + + def __init__(self, target=None, crime=None, dead=None, alive=None, **kwargs): + super().__init__(**kwargs) + + self._target = target + + self._crime = crime + + dead_or_alive = [] + if dead is None: + dead = random.choice([True, False]) + if alive is None: + alive = True + if dead: + dead_or_alive.append('Dead') + if alive: + dead_or_alive.append('Alive') + 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) + self._reward = f"{reward} Gold Pieces" + + if not self._name: + self._name = ( + f"{self.reward} for the capture of {self.target.full_name.upper()}, " + f"wanted for the crime of {self.crime.name.upper()}. " + f"Wanted {self._dead_or_alive.upper()}" + ) + + @property + def crime(self): + if not self._crime: + self._crime = random.choice(Bounty.crimes) + return self._crime + + @property + def details(self): + if not self._details: + self._details = f"{self.target.description}\nWhereabouts {self.target.whereabouts}." + return self._details + + @property + def target(self): + if not self._target: + self._target = generate_npc() + return self._target + + +classes = BaseJob.__subclasses__() +job_types = [c.__name__ for c in classes] + + +def generate_job(): + return random.choice(classes)() + + +if __name__ == '__main__': + print(Bounty()) diff --git a/deadsands/site_tools/shell/interactive_shell.py b/deadsands/site_tools/shell/interactive_shell.py index b554005..ef7188e 100644 --- a/deadsands/site_tools/shell/interactive_shell.py +++ b/deadsands/site_tools/shell/interactive_shell.py @@ -8,6 +8,7 @@ from rolltable.tables import RollTable from site_tools.shell.base import BasePrompt, command from site_tools import campaign +from site_tools import jobs from npc.generator.base import generate_npc from reckoning.calendar import TelisaranCalendar @@ -43,6 +44,7 @@ class DMShell(BasePrompt): ("", " [F3] Trinkets"), ("", " [F4] NPC"), ("", " [F5] Date"), + ("", " [F6] Job"), ("", " [F8] Save"), ("", " [^Q] Quit "), ] @@ -74,6 +76,10 @@ class DMShell(BasePrompt): def date(event): self.date() + @self.key_bindings.add("f6") + def job(event): + self.job() + @self.key_bindings.add("f8") def save(event): self.save() @@ -358,3 +364,17 @@ class DMShell(BasePrompt): self.console.error(f"Invalid level: {newlevel}. Levels must be between 1 and 20.") self._campaign['level'] = newlevel self.console.print(f"Party is currently at level {self._campaign['level']}.") + + @command(usage=""" + [title]JOB[/title] + + Generate a random job. + + [title]USAGE[/title] + + [link]> job[/link] + + """) + def job(self, parts=[]): + self.console.print(jobs.generate_job()) +