Skip to content

Commit

Permalink
Add gnome species from Rough nights and hard days
Browse files Browse the repository at this point in the history
  • Loading branch information
davismr committed Jan 1, 2025
1 parent 3d1574b commit 33b3b34
Show file tree
Hide file tree
Showing 8 changed files with 185 additions and 12 deletions.
50 changes: 50 additions & 0 deletions src/wfrp/character/data/careers.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ def list_careers(species=None):
return list(HALFLING_CAREERS.values())
elif species == "Dwarf":
return list(DWARF_CAREERS.values())
elif species == "Gnome":
return list(GNOME_CAREERS.values())
elif species == "High Elf":
return list(HIGH_ELF_CAREERS.values())
elif species == "Wood Elf":
Expand All @@ -26,6 +28,8 @@ def get_career(species, die_roll):
career_list = HALFLING_CAREERS
elif species == "Dwarf":
career_list = DWARF_CAREERS
elif species == "Gnome":
career_list = GNOME_CAREERS
elif species == "High Elf":
career_list = HIGH_ELF_CAREERS
elif species == "Wood Elf":
Expand Down Expand Up @@ -206,6 +210,52 @@ def get_career(species, die_roll):
100: "Soldier",
}

GNOME_CAREERS = {
1: "Apothecary",
2: "Lawyer",
3: "Physician",
5: "Priest",
6: "Scholar",
8: "Wizard",
15: "Agitator",
16: "Artisan",
18: "Beggar",
19: "Investigator",
20: "Merchant",
22: "Rat Catcher",
23: "Townsman",
29: "Watchman",
30: "Advisor",
31: "Artist",
32: "Envoy",
33: "Noble",
34: "Servant",
36: "Spy",
41: "Warden",
43: "Bailiff",
44: "Herbalist",
45: "Hunter",
47: "Miner",
55: "Scout",
59: "Villager",
63: "Bounty Hunter",
64: "Entertainer",
69: "Messenger",
70: "Pedlar",
76: "Boatman",
77: "Riverwoman",
81: "Smuggler",
84: "Bawd",
86: "Charlatan",
91: "Fence",
92: "Outlaw",
93: "Racketeer",
95: "Thief",
98: "Guard",
99: "Soldier",
100: "Warrior Priest",
}

HIGH_ELF_CAREERS = {
2: "Apothecary",
6: "Lawyer",
Expand Down
48 changes: 48 additions & 0 deletions src/wfrp/character/data/species.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,54 @@
20: "Gold",
},
},
"Gnome": {
"skills": [
"Channelling (Ulgu)",
"Charm",
"Consume Alcohol",
"Dodge",
"Entertain (Any)",
"Gossip",
"Haggle",
"Language (Ghassally)",
"Language (Magick)",
"Language (Wastelander)",
"Outdoor Survival",
"Stealth (Any)",
],
"talents": [
"Beneath Notice or Suffused with Ulgu",
"Luck or Mimic",
"Night Vision",
"Fisherman or Read/Write",
"Second Sight or Sixth Sense",
"Small",
],
"hair_colour": {
2: "Black",
3: "Dark Brown",
4: "Auburn",
7: "Brown",
11: "Light Brown",
14: "Ginger",
17: "Red Blond",
18: "Golden Blond",
19: "White Blond",
20: "White",
},
"eye_colour": {
2: "Pale Blue",
3: "Blue",
4: "Deep Blue",
7: "Turquoise",
11: "Pale Green",
14: "Hazel",
17: "Pale Brown",
18: "Brown",
19: "Dark Brown",
20: "Violet",
},
},
"High Elf": {
"skills": [
"Cool",
Expand Down
12 changes: 12 additions & 0 deletions src/wfrp/character/data/talents.py
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,18 @@ def get_random_talent(die_roll):
"(this does not count towards your Advances)."
),
},
"Suffused with Ulgu": {
"max": 1,
"description": (
"You are suffused with the Grey Wind of Magic, which those with Second "
"Sight perceive as a shadowy, shifting mist wreathed about your body. You "
"can use your Channelling (Ulgu) Skill in place of the Stealth Skill for "
"all relevant Tests. Further, any successful attempts to cast spells from "
"the Lore of Shadow within 8 yards of you gain +1 SL. This bonus may only "
"be claimed once, no matter how many Characters are Suffused with Ulgu in "
"a spellcaster’s vicinity."
),
},
"Super Numerate": {
"description": (
"You have a gift for calculation and can work out the solution to most "
Expand Down
10 changes: 10 additions & 0 deletions src/wfrp/character/forms/create/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,16 @@ def _get_bonus_attributes(self, species):
attributes["Dexterity"] += 10
attributes["Willpower"] += 20
attributes["Fellowship"] += -10
elif species == "Gnome":
attributes["Ballistic Skill"] += -10
attributes["Strength"] += -10
attributes["Toughness"] += -5
attributes["Initiative"] += 10
attributes["Agility"] += 10
attributes["Dexterity"] += 10
attributes["Intelligence"] += 10
attributes["Willpower"] += 20
attributes["Fellowship"] += -5
elif species in ["High Elf", "Wood Elf"]:
attributes["Weapon Skill"] += 10
attributes["Ballistic Skill"] += 10
Expand Down
3 changes: 3 additions & 0 deletions src/wfrp/character/forms/create/details.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ def initialise_form(self):
elif species == "Dwarf":
age = 15 + roll_5d10() + roll_5d10()
height = 51 + roll_d10()
elif species == "Gnome":
age = 20 + roll_5d10() + roll_5d10()
height = 40 + roll_d10()
elif species in ["High Elf", "Wood Elf"]:
age = 30 + roll_5d10() + roll_5d10()
height = 71 + roll_d10()
Expand Down
45 changes: 33 additions & 12 deletions src/wfrp/character/forms/create/species.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,43 @@
from pyramid.view import view_defaults

from wfrp.character.data.species import SPECIES_LIST
from wfrp.character.switches import is_gnome_active
from wfrp.character.utils import roll_d100
from wfrp.character.views.base_view import BaseView


@view_defaults(route_name="species")
class SpeciesViews(BaseView):
def _roll_new_species(self):
def _roll_new_species(self): # noqa C901
result = roll_d100()
if result <= 90:
species = "Human"
elif result <= 94:
species = "Halfling"
elif result <= 98:
species = "Dwarf"
elif result == 99:
species = "High Elf"
elif result == 100:
species = "Wood Elf"
if is_gnome_active():
if result <= 89:
species = "Human"
elif result <= 93:
species = "Halfling"
elif result <= 97:
species = "Dwarf"
elif result == 98:
species = "Gnome"
elif result == 99:
species = "High Elf"
elif result == 100:
species = "Wood Elf"
else:
raise NotImplementedError(f"result {result} does not return a species")
else:
raise NotImplementedError(f"result {result} does not return a species")
if result <= 90:
species = "Human"
elif result <= 94:
species = "Halfling"
elif result <= 98:
species = "Dwarf"
elif result == 99:
species = "High Elf"
elif result == 100:
species = "Wood Elf"
else:
raise NotImplementedError(f"result {result} does not return a species")
return species

def initialise_form(self):
Expand Down Expand Up @@ -99,6 +116,10 @@ def _set_species_attributes(self, species):
elif species == "Dwarf":
self.character.resilience = 2
self.character.extra_points = 3
elif species == "Gnome":
self.character.fate = 2
self.character.resilience = 0
self.character.extra_points = 2
elif species in ["High Elf", "Wood Elf"]:
self.character.extra_points = 2
self.character.movement = 5
Expand Down
2 changes: 2 additions & 0 deletions src/wfrp/character/switches.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
def is_gnome_active():
return False
27 changes: 27 additions & 0 deletions tests/test_create_species.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,33 @@ def test_roll_new_species(new_character, species, roll):
view._roll_new_species()


@pytest.mark.create
@pytest.mark.parametrize(
"species, roll",
[
("Human", 89),
("Halfling", 90),
("Dwarf", 97),
("Gnome", 98),
("High Elf", 99),
],
)
@patch("wfrp.character.forms.create.species.is_gnome_active")
def test_roll_new_species_gnome(mock_is_gnome_active, new_character, species, roll):
mock_is_gnome_active.return_value = True
request = testing.DummyRequest(path="species")
request.matched_route = DummyRoute(name="species")
request.matchdict = {"uuid": new_character.uuid}
view = SpeciesViews(request)
with patch("wfrp.character.forms.create.species.roll_d100") as mock_roll:
mock_roll.return_value = roll
response = view._roll_new_species()
assert response == species
mock_roll.return_value = 101
with pytest.raises(NotImplementedError):
view._roll_new_species()


@pytest.mark.create
@pytest.mark.parametrize(
"species, movement",
Expand Down

0 comments on commit 33b3b34

Please sign in to comment.