mirror of
https://github.com/evennia/evennia.git
synced 2026-03-16 21:06:30 +01:00
First layout of evadventure
This commit is contained in:
parent
b413e0f7f2
commit
a07ef8e3c4
11 changed files with 690 additions and 0 deletions
30
evennia/contrib/tutorials/evadventure/README.md
Normal file
30
evennia/contrib/tutorials/evadventure/README.md
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# EvAdventure
|
||||
|
||||
Contrib by Griatch 2022
|
||||
|
||||
A complete example MUD using Evennia. This is the final result of what is
|
||||
implemented if you follow the Getting-Started tutorial. It's recommended
|
||||
that you follow the tutorial step by step and write your own code. But if
|
||||
you prefer you can also pick apart or use this as a starting point for your
|
||||
own game.
|
||||
|
||||
## Features
|
||||
|
||||
- Uses a MUD-version of the [Knave](https://rpggeek.com/rpg/50827/knave) old-school
|
||||
fantasy ruleset by Ben Milton (classless and overall compatible with early
|
||||
edition D&D), released under the Creative Commons Attribution (all uses,
|
||||
including commercial are allowed
|
||||
as long as attribution is given).
|
||||
- Character creation using an editable character sheet
|
||||
- Weapons, effects, healing and resting
|
||||
- Two alternative combat systems (turn-based and twitch based)
|
||||
- Magic (three spells)
|
||||
- NPC/mobs with simple AI.
|
||||
- Simple Quest system.
|
||||
- Small game world.
|
||||
- Coded using best Evennia practices, with unit tests.
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
TODO
|
||||
0
evennia/contrib/tutorials/evadventure/__init__.py
Normal file
0
evennia/contrib/tutorials/evadventure/__init__.py
Normal file
0
evennia/contrib/tutorials/evadventure/characters.py
Normal file
0
evennia/contrib/tutorials/evadventure/characters.py
Normal file
0
evennia/contrib/tutorials/evadventure/combat.py
Normal file
0
evennia/contrib/tutorials/evadventure/combat.py
Normal file
0
evennia/contrib/tutorials/evadventure/commands.py
Normal file
0
evennia/contrib/tutorials/evadventure/commands.py
Normal file
0
evennia/contrib/tutorials/evadventure/objects.py
Normal file
0
evennia/contrib/tutorials/evadventure/objects.py
Normal file
354
evennia/contrib/tutorials/evadventure/random_tables.py
Normal file
354
evennia/contrib/tutorials/evadventure/random_tables.py
Normal file
|
|
@ -0,0 +1,354 @@
|
|||
"""
|
||||
Random tables - adopted from _Knave_.
|
||||
|
||||
"""
|
||||
|
||||
# Character generation tables
|
||||
|
||||
character_generation = {
|
||||
"physique": [
|
||||
"athletic",
|
||||
"brawny",
|
||||
"corpulent",
|
||||
"delicate",
|
||||
"gaunt",
|
||||
"hulking",
|
||||
"lanky",
|
||||
"ripped",
|
||||
"rugged",
|
||||
"scrawny",
|
||||
"short",
|
||||
"sinewy",
|
||||
"slender",
|
||||
"flabby",
|
||||
"statuesque",
|
||||
"stout",
|
||||
"tiny",
|
||||
"towering",
|
||||
"willowy",
|
||||
"wiry",
|
||||
],
|
||||
"face": [
|
||||
"bloated",
|
||||
"blunt",
|
||||
"bony",
|
||||
"chiseled",
|
||||
"delicate",
|
||||
"elongated",
|
||||
"patrician",
|
||||
"pinched",
|
||||
"hawkish",
|
||||
"broken",
|
||||
"impish",
|
||||
"narrow",
|
||||
"ratlike",
|
||||
"round",
|
||||
"sunken",
|
||||
"sharp",
|
||||
"soft",
|
||||
"square",
|
||||
"wide",
|
||||
"wolfish",
|
||||
],
|
||||
"skin": [
|
||||
"battle scar",
|
||||
"birthmark",
|
||||
"burn scar",
|
||||
"dark",
|
||||
"makeup",
|
||||
"oily",
|
||||
"pale",
|
||||
"perfect",
|
||||
"pierced",
|
||||
"pockmarked",
|
||||
"reeking",
|
||||
"tattooed",
|
||||
"rosy",
|
||||
"rough",
|
||||
"sallow",
|
||||
"sunburned",
|
||||
"tanned",
|
||||
"war paint",
|
||||
"weathered",
|
||||
"whip scar",
|
||||
],
|
||||
"hair": [
|
||||
"bald",
|
||||
"braided",
|
||||
"bristly",
|
||||
"cropped",
|
||||
"curly",
|
||||
"disheveled",
|
||||
"dreadlocks",
|
||||
"filthy",
|
||||
"frizzy",
|
||||
"greased",
|
||||
"limp",
|
||||
"long",
|
||||
"luxurious",
|
||||
"mohawk",
|
||||
"oily",
|
||||
"ponytail",
|
||||
"silky",
|
||||
"topknot",
|
||||
"wavy",
|
||||
"wispy",
|
||||
],
|
||||
"clothing": [
|
||||
"antique",
|
||||
"bloody",
|
||||
"ceremonial",
|
||||
"decorated",
|
||||
"eccentric",
|
||||
"elegant",
|
||||
"fashionable",
|
||||
"filthy",
|
||||
"flamboyant",
|
||||
"stained",
|
||||
"foreign",
|
||||
"frayed",
|
||||
"frumpy",
|
||||
"livery",
|
||||
"oversized",
|
||||
"patched",
|
||||
"perfumed",
|
||||
"rancid",
|
||||
"torn",
|
||||
"undersized",
|
||||
],
|
||||
"virtue": [
|
||||
"ambitious",
|
||||
"cautious",
|
||||
"courageous",
|
||||
"courteous",
|
||||
"curious",
|
||||
"disciplined",
|
||||
"focused",
|
||||
"generous",
|
||||
"gregarious",
|
||||
"honest",
|
||||
"honorable",
|
||||
"humble",
|
||||
"idealistic",
|
||||
"just",
|
||||
"loyal",
|
||||
"merciful",
|
||||
"righteous",
|
||||
"serene",
|
||||
"stoic",
|
||||
"tolerant",
|
||||
],
|
||||
"vice": [
|
||||
"aggressive",
|
||||
"arrogant",
|
||||
"bitter",
|
||||
"cowardly",
|
||||
"cruel",
|
||||
"deceitful",
|
||||
"flippant",
|
||||
"gluttonous",
|
||||
"greedy",
|
||||
"irascible",
|
||||
"lazy",
|
||||
"nervous",
|
||||
"prejudiced",
|
||||
"reckless",
|
||||
"rude",
|
||||
"suspicious",
|
||||
"vain",
|
||||
"vengeful",
|
||||
"wasteful",
|
||||
"whiny",
|
||||
],
|
||||
"speech": [
|
||||
"blunt",
|
||||
"booming",
|
||||
"breathy",
|
||||
"cryptic",
|
||||
"drawling",
|
||||
"droning",
|
||||
"flowery",
|
||||
"formal",
|
||||
"gravelly",
|
||||
"hoarse",
|
||||
"mumbling",
|
||||
"precise",
|
||||
"quaint",
|
||||
"rambling",
|
||||
"rapid-fire",
|
||||
"dialect",
|
||||
"slow",
|
||||
"squeaky",
|
||||
"stuttering",
|
||||
"whispery",
|
||||
],
|
||||
"background": [
|
||||
"alchemist",
|
||||
"beggar",
|
||||
"butcher",
|
||||
"burglar",
|
||||
"charlatan",
|
||||
"cleric",
|
||||
"cook",
|
||||
"cultist",
|
||||
"gambler",
|
||||
"herbalist",
|
||||
"magician",
|
||||
"mariner",
|
||||
"mercenary",
|
||||
"merchant",
|
||||
"outlaw",
|
||||
"performer",
|
||||
"pickpocket",
|
||||
"smuggler",
|
||||
"student",
|
||||
"tracker",
|
||||
],
|
||||
"mifortuntes": [
|
||||
"abandoned",
|
||||
"addicted",
|
||||
"blackmailed",
|
||||
"condemned",
|
||||
"cursed",
|
||||
"defrauded",
|
||||
"demoted",
|
||||
"discredited",
|
||||
"disowned",
|
||||
"exiled",
|
||||
"framed",
|
||||
"haunted",
|
||||
"kidnapped",
|
||||
"mutilated",
|
||||
"poor",
|
||||
"pursued",
|
||||
"rejected",
|
||||
"replaced",
|
||||
"robbed",
|
||||
"suspected",
|
||||
],
|
||||
"alignment": [
|
||||
('1-5', "law"),
|
||||
('6-15', "neutrality"),
|
||||
('16-20', "chaos"),
|
||||
],
|
||||
"armor": [
|
||||
('1-3', "no armor"),
|
||||
('4-14', "gambeson"),
|
||||
('15-19', "brigandine"),
|
||||
('20', "chain"),
|
||||
],
|
||||
"helmets and shields": [
|
||||
('1-13', "no helmet"),
|
||||
('14-16', "helmet"),
|
||||
('17-19', "shield"),
|
||||
('20', "helmet and shield"),
|
||||
],
|
||||
"starting weapon": [ # note: these are all d6 dmg weapons
|
||||
('1-7', "dagger",
|
||||
'8-13', "club",
|
||||
'14-20', "staff"),
|
||||
],
|
||||
"dungeoning gear": [
|
||||
"rope, 50ft",
|
||||
"pulleys",
|
||||
"candles, 5",
|
||||
"chain, 10ft",
|
||||
"chalk, 10",
|
||||
"crowbar",
|
||||
"tinderbox",
|
||||
"grap. hook",
|
||||
"hammer",
|
||||
"waterskin",
|
||||
"lantern",
|
||||
"lamp oil",
|
||||
"padlock",
|
||||
"manacles",
|
||||
"mirror",
|
||||
"pole, 10ft",
|
||||
"sack",
|
||||
"tent",
|
||||
"spikes, 5",
|
||||
"torches, 5",
|
||||
],
|
||||
"general gear 1": [
|
||||
"air bladder",
|
||||
"bear trap",
|
||||
"shovel",
|
||||
"bellows",
|
||||
"grease",
|
||||
"saw",
|
||||
"bucket",
|
||||
"caltrops",
|
||||
"chisel",
|
||||
"drill",
|
||||
"fish. rod",
|
||||
"marbles",
|
||||
"glue",
|
||||
"pick",
|
||||
"hourglass",
|
||||
"net",
|
||||
"tongs",
|
||||
"lockpicks",
|
||||
"metal file",
|
||||
"nails",
|
||||
],
|
||||
"general gear 2": [
|
||||
"incense",
|
||||
"sponge",
|
||||
"lens",
|
||||
"perfume",
|
||||
"horn",
|
||||
"bottle",
|
||||
"soap",
|
||||
"spyglass",
|
||||
"tar pot",
|
||||
"twine",
|
||||
"fake jewels",
|
||||
"blank book",
|
||||
"card deck",
|
||||
"dice set",
|
||||
"cook pots",
|
||||
"face paint",
|
||||
"whistle",
|
||||
"instrument",
|
||||
"quill & ink",
|
||||
"small bell",
|
||||
],
|
||||
"name": [
|
||||
"Abbo", "Adelaide", "Ellis", "Eleanor", "Lief", "Luanda", "Ablerus", "Agatha",
|
||||
"Eneto", "Elizabeth", "Luke", "Lyra", "Acot", "Aleida", "Enio", "Elspeth", "Martin",
|
||||
"Mabel", "Alexander", "Alexia", "Eral", "Emeline", "Merrick", "Maerwynn", "Almanzor",
|
||||
"Alianor", "Erasmus", "Emma", "Mortimer", "Malkyn", "Althalos", "Aline", "Eustace",
|
||||
"Emmony", "Ogden", "Margaret", "Ancelot", "Alma", "Everard", "Enna", "Oliver", "Margery",
|
||||
"Asher", "Alys", "Faustus", "Enndolynn", "Orion", "Maria", "Aster", "Amabel", "Favian",
|
||||
"Eve", "Oswald", "Marion", "Balan", "Amice", "Fendrel", "Evita", "Pelagon", "Matilda",
|
||||
"Balthazar", "Anastas", "Finn", "Felice", "Pello", "Millicent", "Barat", "Angmar",
|
||||
"Florian", "Fern", "Peyton", "Mirabelle", "Bartholomew", "Annabel", "Francis", "Floria",
|
||||
"Philip", "Muriel", "Basil", "Arabella", "Frederick", "Fredegonde", "Poeas", "Nabarne",
|
||||
"Benedict", "Ariana", "Gaidon", "Gillian", "Quinn", "Nell", "Berinon", "Ayleth", "Gavin",
|
||||
"Gloriana", "Ralph", "Nesea", "Bertram", "Barberry", "Geoffrey", "Godeleva", "Randolph",
|
||||
"Niree", "Beves", "Barsaba", "Gerard", "Godiva", "Reginald", "Odette", "Bilmer",
|
||||
"Basilia", "Gervase", "Gunnilda", "Reynold", "Odila", "Blanko", "Beatrix", "Gilbert",
|
||||
"Gussalen", "Richard", "Oria", "Bodo", "Benevolence", "Giles", "Gwendolynn", "Robert",
|
||||
"Osanna", "Borin", "Bess", "Godfrey", "Hawise", "Robin", "Ostrythe", "Bryce", "Brangian",
|
||||
"Gregory", "Helena", "Roger", "Ottilia", "Carac", "Brigida", "Gringoire", "Helewise",
|
||||
"Ronald", "Panope", "Caspar", "Brunhild", "Gunthar", "Hester", "Rowan", "Paternain",
|
||||
"Cassius", "Camilla", "Guy", "Hildegard", "Rulf", "Pechel", "Cedric", "Canace", "Gyras",
|
||||
"Idony", "Sabin", "Pepper", "Cephalos", "Cecily", "Hadrian", "Isabella", "Sevrin",
|
||||
"Petronilla", "Chadwick", "Cedany", "Hedelf", "Iseult", "Silas", "Phrowenia", "Charillos",
|
||||
"Christina", "Hewelin", "Isolde", "Simon", "Poppy", "Charles", "Claramunda", "Hilderith",
|
||||
"Jacquelyn", "Solomon", "Quenell", "Chermon", "Clarice", "Humbert", "Jasmine", "Stephen",
|
||||
"Raisa", "Clement", "Clover", "Hyllus", "Jessamine", "Terrowin", "Reyna", "Clifton",
|
||||
"Collette", "Ianto", "Josselyn", "Thomas", "Rixende", "Clovis", "Constance", "Ibykos",
|
||||
"Juliana", "Tristan", "Rosamund", "Cyon", "Damaris", "Inigo", "Karitate", "Tybalt",
|
||||
"Rose", "Dain", "Daphne", "Itylus", "Katelyn", "Ulric", "Ryia", "Dalmas", "Demona",
|
||||
"James", "Katja", "Walter", "Sarah", "Danor", "Dimia", "Jasper", "Katrina", "Wander",
|
||||
"Seraphina", "Destrian", "Dione", "Jiles", "Kaylein", "Warin", "Thea", "Domeka",
|
||||
"Dorothea", "Joffridus", "Kinna", "Waverly", "Trillby", "Donald", "Douce", "Jordan",
|
||||
"Krea", "Willahelm", "Wendel", "Doran", "Duraina", "Joris", "Kypris", "William",
|
||||
"Wilberga", "Dumphey", "Dyota", "Josef", "Landerra", "Wimarc", "Winifred", "Eadmund",
|
||||
"Eberhild", "Laurence", "Larraza", "Wystan", "Wofled", "Eckardus", "Edelot", "Leofrick",
|
||||
"Linet", "Xalvador", "Wymarc", "Edward", "Edyva", "Letholdus", "Loreena", "Zane", "Ysmay",
|
||||
],
|
||||
}
|
||||
|
||||
0
evennia/contrib/tutorials/evadventure/rooms.py
Normal file
0
evennia/contrib/tutorials/evadventure/rooms.py
Normal file
259
evennia/contrib/tutorials/evadventure/rules.py
Normal file
259
evennia/contrib/tutorials/evadventure/rules.py
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
"""
|
||||
MUD ruleset based on the _Knave_ OSR tabletop RPG by Ben Milton (modified for MUD use).
|
||||
|
||||
The rules are divided into three parts:
|
||||
|
||||
- Character generation - these are rules only used when creating a character.
|
||||
- Improvement - these are rules used with experience to improve the character
|
||||
over time.
|
||||
- Actions - all in-game interactions (making use of the character's abilities)
|
||||
are defined as discreet _actions_ in the game. An action is the smallest rule
|
||||
unit to accomplish something with rule support. While in a tabletop game you
|
||||
have a human game master to arbitrate, the computer requires exactness. While
|
||||
free-form roleplay is also possible, only the actions defined here will have a
|
||||
coded support.
|
||||
|
||||
"""
|
||||
from dataclasses import dataclass
|
||||
from .utils import roll
|
||||
from .random_tables import character_generation as chargen_table
|
||||
|
||||
|
||||
# Basic rolls
|
||||
|
||||
def saving_throw(bonus, advantage=False, disadvantage=False):
|
||||
"""
|
||||
To save, roll d20 + relevant Attrribute bonus > 15 (always 15).
|
||||
|
||||
Args:
|
||||
advantage (bool): Roll 2d20 and use the bigger number.
|
||||
disadvantage (bool): Roll 2d20 and use the smaller number.
|
||||
|
||||
Returns:
|
||||
bool: If the save was passed or not.
|
||||
|
||||
Notes:
|
||||
Advantage and disadvantage cancel each other out.
|
||||
|
||||
Example:
|
||||
Trying to overcome the effects of poison, roll d20 + Constitution-bonus above 15.
|
||||
|
||||
"""
|
||||
if not (advantage or disadvantage) or (advantage and disadvantage):
|
||||
# normal roll
|
||||
dice_roll = roll("1d20")
|
||||
elif advantage:
|
||||
dice_roll = max(roll("1d20"), roll("1d20"))
|
||||
else:
|
||||
dice_roll = min(roll("1d20"), roll("1d20"))
|
||||
return (dice_roll + bonus) > 15
|
||||
|
||||
|
||||
def roll_attribute_bonus():
|
||||
"""
|
||||
For the MUD version, we use a flat bonus and let the user redistribute it. This
|
||||
function (unused by default) implements the original Knave random generator for
|
||||
the Attribute bonus, if you prefer producing more 'unbalanced' characters.
|
||||
|
||||
The Attribute bonus is generated by rolling the lowest value of 3d6.
|
||||
|
||||
Returns:
|
||||
int: The randomly generated Attribute bonus.
|
||||
|
||||
"""
|
||||
return min(roll("1d6"), roll("1d6"), roll("1d6"))
|
||||
|
||||
|
||||
def roll_random_table(dieroll, table, table_choices):
|
||||
"""
|
||||
Make a roll on a random table.
|
||||
|
||||
Args:
|
||||
dieroll (str): The dice to roll, like 1d6, 1d20, 3d6 etc).
|
||||
table_choices (iterable): If a list of single elements, the die roll
|
||||
should fully encompass the table, like a 1d20 roll for a table
|
||||
with 20 elements. If each element is a tuple, the first element
|
||||
of the tuple is assumed to be a string 'X-Y' indicating the
|
||||
range of values that should match the roll.
|
||||
|
||||
Returns:
|
||||
Any: The result of the random roll.
|
||||
|
||||
Example:
|
||||
`roll table_choices = [('1-5', "Blue"), ('6-9': "Red"), ('10', "Purple")]`
|
||||
|
||||
Notes:
|
||||
If the roll is outside of the listing, the closest edge value is used.
|
||||
|
||||
"""
|
||||
roll_result = roll(dieroll)
|
||||
|
||||
if isinstance(table_choices[0], (tuple, list)):
|
||||
# tuple with range conditional, like ('1-5', "Blue") or ('10', "Purple")
|
||||
max_range = -1
|
||||
min_range = 10**6
|
||||
for (valrange, choice) in table_choices:
|
||||
|
||||
minval, *maxval = valrange.split('-', 1)
|
||||
minval = abs(int(minval))
|
||||
maxval = abs(int(maxval[0]) if maxval else minval)
|
||||
|
||||
# we store the largest/smallest values so far in case we need to use them
|
||||
max_range = max(max_range, maxval)
|
||||
min_range = min(min_range, minval)
|
||||
|
||||
if minval <= roll_result <= maxval:
|
||||
return choice
|
||||
|
||||
# if we have no result, we are outside of the range, we pick the edge values. It is also
|
||||
# possible the range contains 'gaps', but that'd be an error in the random table itself.
|
||||
if roll_result > max_range:
|
||||
return max_range
|
||||
else:
|
||||
return min_range
|
||||
else:
|
||||
# regular list - one line per value.
|
||||
roll_result = max(1, min(len(table_choices), roll_result))
|
||||
return table_choices[roll_result - 1]
|
||||
|
||||
|
||||
# character generation
|
||||
|
||||
@dataclass
|
||||
class CharAttribute:
|
||||
"""
|
||||
A character Attribute, like strength or wisdom, has a _bonus_, used
|
||||
to improve the result of doing a related action. It also has a _defense_ value
|
||||
which is always 10 points higher than the bonus. For example, to attack
|
||||
someone, you'd have to roll d20 + `strength bonus` to beat the `strength defense`
|
||||
of the enemy.
|
||||
|
||||
"""
|
||||
bonus: str = 0
|
||||
|
||||
@property
|
||||
def defense(self):
|
||||
return bonus + 10
|
||||
|
||||
|
||||
class CharacterGeneration:
|
||||
"""
|
||||
This collects all the rules for generating a new character. An instance of this class can be
|
||||
used to track all the stats during generation and will be used to apply all the data to the
|
||||
character at the end. This class instance can also be saved temporarily to make sure a user
|
||||
is not losing their half-created character.
|
||||
|
||||
Note:
|
||||
Unlike standard Knave, characters will come out more similar here. This is because in
|
||||
a table top game it's fun to roll randomly and have to live with a crappy roll - but
|
||||
online players can (and usually will) just disconnect and reroll until they get values
|
||||
they are happy with.
|
||||
|
||||
So, in standard Knave, the character's attribute bonus is rolled randomly and will give a
|
||||
value 1-6; and there is no guarantee for 'equal' starting characters. Instead we
|
||||
homogenize the results to a flat +2 bonus and let people redistribute the
|
||||
points afterwards. This also allows us to show off some more advanced concepts in the
|
||||
chargen menu, but you can also easily make it random like in base Knave by using the
|
||||
(currently unused, but included) `roll_attribute_bonus` function above to get the bonus
|
||||
instead of the flat +2.
|
||||
|
||||
In the same way, Knave uses a d8 roll to get the initial hit points. Instead we use a
|
||||
flat max of 8 HP to start, in order to give players a little more survivability.
|
||||
|
||||
We *will* roll random start equipment though. Contrary to standard Knave, we'll also
|
||||
randomly assign the starting weapon among a small selection of equal-dmg weapons (since
|
||||
there is no GM to adjudicate a different choice).
|
||||
|
||||
"""
|
||||
def __init__(self):
|
||||
"""
|
||||
Initialize starting values
|
||||
|
||||
"""
|
||||
# name will likely be modified later
|
||||
self.name = roll_random_table('1d282', chargen_table['name'])
|
||||
|
||||
# base attribute bonuses
|
||||
self.strength = CharAttribute(bonus=2)
|
||||
self.dexterity = CharAttribute(bonus=2)
|
||||
self.constitution = CharAttribute(bonus=2)
|
||||
self.intelligence = CharAttribute(bonus=2)
|
||||
self.wisdom = CharAttribute(bonus=2)
|
||||
self.charisma = CharAttribute(bonus=2)
|
||||
|
||||
self.armor = CharAttribute(bonus=1) # un-armored default
|
||||
|
||||
# physical attributes (only for rp purposes)
|
||||
self.physique = roll_random_table('1d20', chargen_table['physique'])
|
||||
self.face = roll_random_table(chargen_table['1d20', 'face'])
|
||||
self.skin = roll_random_table(chargen_table['1d20', 'skin'])
|
||||
self.hair = roll_random_table(chargen_table['1d20', 'hair'])
|
||||
self.clothing = roll_random_table(chargen_table['1d20', 'clothing'])
|
||||
self.virtue = roll_random_table(chargen_table['1d20', 'virtue'])
|
||||
self.vice = roll_random_table(chargen_table['1d20', 'vice'])
|
||||
self.background = roll_random_table(chargen_table['1d20', 'background'])
|
||||
self.misfortune = roll_random_table(chargen_table['1d20', 'misfortune'])
|
||||
self.alignment = roll_random_table(chargen_table['1d20', 'alignment'])
|
||||
|
||||
# same for all
|
||||
self.exploration_speed = 120
|
||||
self.combat_speed = 40
|
||||
self.hp = 0
|
||||
self.xp = 0
|
||||
self.level = 1
|
||||
|
||||
# random equipment
|
||||
self.armor = roll_random_table('1d20', chargen_table['armor'])
|
||||
|
||||
_helmet_and_shield = roll_random_table('1d20', chargen_table["helmets and shields"])
|
||||
self.helmet = "helmet" if "helmet" in _helmet_and_shield else "none"
|
||||
self.shield = "shield" if "shield" in _helmet_and_shield else "none"
|
||||
|
||||
self.weapon = roll_random_table(chargen_table['1d20', "starting_weapon"])
|
||||
|
||||
self.equipment = [
|
||||
"ration",
|
||||
"ration",
|
||||
roll_random_table(chargen_table['1d20', "dungeoning gear"]),
|
||||
roll_random_table(chargen_table['1d20', "dungeoning gear"]),
|
||||
roll_random_table(chargen_table['1d20', "general gear 1"]),
|
||||
roll_random_table(chargen_table['1d20', "general gear 2"]),
|
||||
]
|
||||
|
||||
def adjust_attribute(self, source_attribute, target_attribute, value):
|
||||
"""
|
||||
Redistribute bonus from one attribute to another. The resulting values
|
||||
must not be lower than +1 and not above +6.
|
||||
|
||||
Args:
|
||||
source_attribute (str): The name of the attribute to deduct bonus from, like 'strength'
|
||||
target_attribute (str): The attribute to give the bonus to, like 'dexterity'.
|
||||
value (int): How much to change. This is always 1 for the current chargen.
|
||||
|
||||
Raises:
|
||||
ValueError: On input error, using invalid values etc.
|
||||
|
||||
Notes:
|
||||
We assume the strings are provided by the chargen, so we don't do
|
||||
much input validation here, we do make sure we don't overcharge ourselves though.
|
||||
|
||||
"""
|
||||
# we use getattr() to fetch the CharaAttribute of e.g. the .strength property etc
|
||||
source_current_bonus = getattr(self, source_attribute).bonus
|
||||
target_current_bonus = getattr(self, target_attribute).bonus
|
||||
|
||||
if source_current_val - value < 1:
|
||||
raise ValueError(f"You can't reduce the {source_attribute} bonus below +1.")
|
||||
if target_current_val + value > 6:
|
||||
raise ValueError(f"You can't increase the {target_attribute} bonus above +6.")
|
||||
|
||||
# all is good, apply the change.
|
||||
setattr(self, source_attribute, CharAttribute(bonus=source_current_val - value))
|
||||
setattr(self, target_attribute, CharAttribute(bonus=source_current_val + value))
|
||||
|
||||
def apply(self, character):
|
||||
"""
|
||||
Once the chargen is complete, call this to transfer all the data to the character
|
||||
permanently.
|
||||
|
||||
"""
|
||||
47
evennia/contrib/tutorials/evadventure/utils.py
Normal file
47
evennia/contrib/tutorials/evadventure/utils.py
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
"""
|
||||
Various utilities.
|
||||
|
||||
"""
|
||||
from random import randint
|
||||
|
||||
|
||||
def roll(roll_string, max_number=10):
|
||||
"""
|
||||
NOTE: In evennia/contribs/rpg/dice/ is a more powerful dice roller with
|
||||
more features, such as modifiers, secret rolls etc. This is much simpler and only
|
||||
gets a simple sum of normal rpg-dice.
|
||||
|
||||
Args:
|
||||
roll_string (str): A roll using standard rpg syntax, <number>d<diesize>, like
|
||||
1d6, 2d10 etc. Max die-size is 1000.
|
||||
max_number (int): The max number of dice to roll. Defaults to 10, which is usually
|
||||
more than enough.
|
||||
|
||||
Returns:
|
||||
int: The rolled result - sum of all dice rolled.
|
||||
|
||||
Raises:
|
||||
TypeError: If roll_string is not on the right format or otherwise doesn't validate.
|
||||
|
||||
Notes:
|
||||
Since we may see user input to this function, we make sure to validate the inputs (we
|
||||
wouldn't bother much with that if it was just for developer use).
|
||||
|
||||
"""
|
||||
max_diesize = 1000
|
||||
roll_string = roll_string.lower()
|
||||
if 'd' not in roll_string:
|
||||
raise TypeError(f"Dice roll '{roll_string}' was not recognized. Must be `<number>d<dicesize>`.")
|
||||
number, diesize = roll_string.split('d', 1)
|
||||
try:
|
||||
number = int(number)
|
||||
diesize = int(diesize)
|
||||
except Exception:
|
||||
raise TypeError(f"The number and dice-size of '{roll_string}' must be numerical.")
|
||||
if 0 < number > max_number:
|
||||
raise TypeError(f"Invalid number of dice rolled (must be between 1 and {max_number})")
|
||||
if 0 < diesize > max_diesize:
|
||||
raise TypeError(f"Invalid die-size used (must be between 1 and {max_diesize} sides)")
|
||||
|
||||
# At this point we know we have valid input - roll and all dice together
|
||||
return sum(randint(1, diesize) for _ in range(number))
|
||||
0
evennia/contrib/tutorials/evadventure/world_batchfile.py
Normal file
0
evennia/contrib/tutorials/evadventure/world_batchfile.py
Normal file
Loading…
Add table
Add a link
Reference in a new issue