From 0f6d6a03a2a22bb9c6530cf12f1ea54da27ff01f Mon Sep 17 00:00:00 2001 From: Mark Wolfman Date: Thu, 29 Mar 2018 23:53:52 -0500 Subject: [PATCH] Added some spells to spellsheet, but many still not entered. --- dungeonsheets/character.py | 11 +- dungeonsheets/make_sheets.py | 29 ++- dungeonsheets/spells.py | 334 +++++++++++++++++++++++++++++++++++ examples/rogue.pdf | Bin 195604 -> 195604 bytes examples/wizard.pdf | Bin 426039 -> 431447 bytes examples/wizard.py | 9 + 6 files changed, 380 insertions(+), 3 deletions(-) create mode 100644 dungeonsheets/spells.py diff --git a/dungeonsheets/character.py b/dungeonsheets/character.py index 42c5cf1..028802c 100644 --- a/dungeonsheets/character.py +++ b/dungeonsheets/character.py @@ -5,7 +5,7 @@ import warnings from .stats import Ability, Skill, findattr from .dice import read_dice_str -from . import weapons, race +from . import weapons, race, spells from .weapons import Weapon dice_re = re.compile('(\d+)d(\d+)') @@ -76,6 +76,8 @@ class Character(): _proficiencies_text = tuple() # Magic spellcasting_ability = None + spells = tuple() + spells_prepared = tuple() def __init__(self, **attrs): """Takes a bunch of attrs and passes them to ``set_attrs``""" @@ -103,6 +105,13 @@ class Character(): elif attr == 'race': MyRace = findattr(race, val) self.race = MyRace() + elif attr == 'spells': + # Create a list of actual spell objects + self.spells = tuple(findattr(spells, spell_name)() for spell_name in val) + elif attr == 'spells_prepared': + # Create a list of actual spell objects + self.spells_prepared = tuple(findattr(spells, spell_name) + for spell_name in val) else: if not hasattr(self, attr): warnings.warn(f"Setting unknown character attribute {attr}", diff --git a/dungeonsheets/make_sheets.py b/dungeonsheets/make_sheets.py index a5eeecb..ef4136c 100644 --- a/dungeonsheets/make_sheets.py +++ b/dungeonsheets/make_sheets.py @@ -55,7 +55,7 @@ def load_character_file(filename): def create_spells_pdf(character, basename, flatten=False): class_level = (character.class_name + ' ' + str(character.level)) spell_level = lambda x : (x or '') - fields = ( + fields = [ ('Spellcasting Class 2', class_level), ("SpellcastingAbility 2", character.spellcasting_ability.capitalize()), ('SpellSaveDC 2', character.spell_save_dc), @@ -70,7 +70,32 @@ def create_spells_pdf(character, basename, flatten=False): ('SlotsTotal 25', spell_level(character.spell_slots(7))), ('SlotsTotal 26', spell_level(character.spell_slots(8))), ('SlotsTotal 27', spell_level(character.spell_slots(9))), - ) + ] + # Cantrips + cantrip_fields = (f'Spells 10{i}' for i in (14, 16, 17, 18, 19, 20, 21, 22)) + cantrips = (spl for spl in character.spells if spl.level == 0) + for spell, field_name in zip(cantrips, cantrip_fields): + fields.append((field_name, spell.name)) + # Spells for each level + field_numbers = { + 1: (1015, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, ), + 2: (1046, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, ), + 3: (1048, 1047, 1049, 1050, 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, ), + 4: (1061, 1060, 1062, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, ), + 5: (1074, 1073, 1075, 1076, 1077, 1078, 1079, 1080, 1081, ), + 6: (1083, 1082, 1084, 1085, 1086, 1087, 1088, 1089, 1090, ), + 7: (1092, 1091, 1093, 1094, 1095, 1096, 1097, 1098, 1099, ), + 8: (10101, 10100, 10102, 10103, 10104, 10105, 10106, ), + 9: (10108, 10107, 10109, 101010, 101011, 101012, 101013), + } + for level in field_numbers.keys(): + spells = tuple(spl for spl in character.spells if spl.level == level) + field_names = tuple(f'Spells {i}' for i in field_numbers[level]) + for spell, field in zip(spells, field_names): + fields.append((field, spell.name)) + # # Uncomment to post field names instead: + # for field in field_names: + # fields.append((field, field)) # Make the actual pdf dirname = os.path.dirname(os.path.abspath(__file__)) src_pdf = os.path.join(dirname, 'blank-spell-sheet-default.pdf') diff --git a/dungeonsheets/spells.py b/dungeonsheets/spells.py new file mode 100644 index 0000000..6cf4cf5 --- /dev/null +++ b/dungeonsheets/spells.py @@ -0,0 +1,334 @@ + + +class Spell(): + """A magical spell castable by a player character.""" + level = 0 + casting_time = "1 action" + casting_range = "60 ft" + components = ("V", "S") + duration = "instantaneous" + magic_school = "" + classes = () + + def __str__(self): + return self.name + + def __repr__(self): + return f'<{self.name}>' + + +class AcidSplash(Spell): + """You hurl a bubble of acid. Choose one creature within range, or + choose two crealures within range that are within 5 feet of each + other. A target must succeed on a Dexterity saving throw or take + 1d6 acid damage. + + This spell's damage increases by 1d6 when you reach 5th level + (2d6), 11th level (3d6), and 17th level (4d6). + + """ + name = "Acid Splash" + classes = ('Sorceror', 'Wizard', ) + magic_school = "Conjuration" + + +class BlindnessDeafness(Spell): + """Vou can blind or deafen a foe. Choose one creature that you can see + within range to make a Constitution saving throw. If it fails, the + target is either blinded or deafened (your choice) for the + duration. At the end of each of its turns, the target can make a + Constitution saving throw. On a success, the spell ends. + + At Higher Levels. When you cast this spell using a spell slot of + 3rd level or higher, you can target one additional creature for + each slot level above 2nd. + + """ + name = "Blindness/Deafness" + magic_school = "Necromancy" + level = 2 + casting_range = "30 feet" + components = ("V", ) + duration = "1 minute" + classes = ('Wizard', ) + + +class BurningHands(Spell): + """As you hold your hands with lhumbs touching and fingers spread, a + thin sheet of flames shoots forth from your outstretched + fingertips. Each creature in a 15-foot cone must make a Dexterity + saving throw. A creature takes 3d6 fire damage on a failed save, + or half as much damage on a successful one. + + The fire ignites any flammable objecls in lhe area that aren't + being worn or carried. + + **At Higher Levels.** When you cast lhis spell using a spell slot + of 2nd level or higher, lhe damage increases by 1d6 for each slot + level above 1st. + + """ + name = "Burning Hands" + level = 1 + casting_time = "1 action" + casting_range = "Self (15 foot cone)" + components = ("V", "S") + duration = "Instantaneous" + magic_school = "Evocation" + classes = ('Wizard', ) + + +class DetectMagic(Spell): + """For the duration, you sense the presence of magic within 30 feet of + you. If you sense magic in this way, you can use your action to + see a faint aura around any visible creature or object in the area + that bears magic, and you learn its school of magic, if any. + + The spell can penetrate most barriers, but is blocked by 1 foot of + stone, 1 inch of common metal, a thin sheet of lead, or 3 feet of + wood or dirt. + + """ + name = "Detect Magic" + level = 1 + casting_time = "1 action" + casting_range = "Self (30 feet)" + components = ("V", "S") + duration = "Concentration, Up to 10 minutes" + magic_school = "Divination" + classes = ('Bard', 'Cleric', 'Druid', 'Paladin', 'Ranger', 'Sorceror', 'Wizard', ) + + +class FalseLife(Spell): + """Bolstering yourself with a necromantic facsimile of life, you gain + 1d4+4 temporary hit points for the duration. + + At Higher Levels: When you cast this spell using a spell slot of + 2nd level or higher, you gain 5 additional temporary hit points + for each slot level above 1st. + + """ + name = "False Life" + level = 1 + casting_time = "1 action" + casting_range = "Self (30 feet)" + components = ("V", "S", "M") + materials = "A small amount of alcohol or distilled spirits" + duration = "1 hour" + magic_school = "Necromancy" + classes = ('Sorceror', 'Wizard', ) + + +class MageArmor(Spell): + """You touch a willing creature who isn't wearing armor, and a + protective magical force surrounds it until the spell ends. The + target's base AC becomes 13 + its Dexterity modifier. The spell + ends it if the target dons armor or if you dismiss the spell as an + action. + + """ + name = "Mage Armor" + level = 1 + casting_time = "1 action" + casting_range = "Touch" + components = ("V", "S", "M") + materials = "A piece of cured leather" + duration = "8 hours" + magic_school = "Abjuration" + classes = ('Sorceror', 'Wizard', ) + + +class MageHand(Spell): + """A spectral, floating hand appears at a point you choose within + range. The hand lasts for the duration or until you dismiss it as + an action. The hand vanishes if it is ever more than 30 feet away + from you or if you cast this spell again. + + You can use your action to control the hand. You can use the hand + to manipulate an object, open an unlocked door or container, stow + or retrieve an item from an open container, or pour the contents + out of a vial. You can move the hand up to 30 feet each time you + use it. + + The hand can't attack, activate magical items, or carry more than + 10 pounds. + + """ + name = "Mage Hand" + level = 0 + casting_time = "1 action" + casting_range = "30 feet" + components = ("V", "S", ) + duration = "1 minute" + magic_school = "Conjuration" + classes = ('Bard', 'Sorceror', 'Warlock', 'Wizard', ) + + +class MagicMissile(Spell): + """You create three glowing darts of magical force. Each dart hits a + creature of your choice that you can see within range. A dart + deals 1d4+1 force damage to its target. The darts all strike + simultaneously and you can direct them to hit one creature or + several. + + At Higher Levels: When you cast this spell using a spell slot of + 2nd level or higher, the spell creates one more dart for each slot + above 1st. + + """ + name = "Magic Missile" + level = 1 + casting_time = "1 action" + casting_range = "120 feet" + components = ("V", "S", ) + duration = "Instantaneous" + magic_school = "Evocation" + classes = ('Sorceror', 'Wizard', ) + + +class Prestidigitation(Spell): + """This spell is a minor magical trick that novice spellcasters use + for practice. You create one of the following magical effects + within range. + + - You create an instantaneous, harmless sensory effect, such as a + shower of sparks, a puff of wind, faint musical notes, or an odd + odor. + - You instantaneously light or snuff out a candle, a torch, or a + small campfire. + - You instantaneously clean or soil an object no larger than 1 + cubic foot. + - You chill, warm, or flavor up to 1 cubic foot of nonliving + material for 1 hour. + - You make a color, a small mark, or a symbol appear on an object + or a surface for 1 hour. + - You create a nonmagical trinket or an illusory image that can + fit in your hand and that lasts until the end of your next turn. + If you cast this spell multiple times, you can have up to three of + its non-instantaneous effects active at a time, and you can + dismiss such an effect as an action. + + """ + name = "Prestidigitation" + level = 0 + casting_time = "1 action" + casting_range = "10 feet" + components = ("V", "S", ) + duration = "1 hour" + magic_school = "Transmutation" + classes = ('Bard', 'Sorceror', 'Warlock', 'Wizard', ) + + +class RayOfFrost(Spell): + """A frigid beam of blue-white light streaks toward a creature within + range. Make a ranged spell attack against the target. On a hit, it + takes 1d8 cold damage, and its speed is reduced by 10 feet until + the start of your next turn. + + The spell's damage increases by 1d8 when you reach 5th level + (2d8), 11th level (3d8), and 17th level (4d8). + + """ + name = "Ray of Frost" + level = 0 + casting_time = "1 action" + casting_range = "60 feet" + components = ("V", "S", ) + duration = "Instantaneous" + magic_school = "Evocation" + classes = ('Sorceror', 'Wizard', ) + + +class RayOfSickness(Spell): + """A ray of sickening greenish energy lashes out toward a creature + within range. Make a ranged spell attack against the target. On a + hit, the target takes 2d8 poison damage and must make a + Constitution saving throw. On a failed save, it is also poisoned + until the end of your next turn. + + At Higher Levels. When you cast this spell using a spell slot of + 2nd level or higher, the damage increases by 1d8 for each slot + level above 1st. + + """ + name = "Ray of Sickness" + level = 1 + casting_time = "1 action" + casting_range = "60 feet" + components = ("V", "S", ) + duration = "Instantaneous" + magic_school = "Necromancy" + classes = ('Sorceror', 'Wizard', ) + + +class Shield(Spell): + """An invisible barrier of magical force appears and protects + you. Until the start of your next turn, you have a +5 bonus to AC, + including against the triggering attack, and you take no damage + from magic missile. + + """ + name = "Shield" + level = 1 + casting_time = "1 reaction" + casting_range = "Self" + components = ("V", "S", ) + duration = "1 round" + magic_school = "Abjuration" + classes = ('Sorceror', 'Wizard', ) + + +class ShockingGrasp(Spell): + """Lightning springs from your hand to deliver a shock to a creature + you try to touch. Make a melee spell attack against the + target. You have advantage on the attack roll if the target is + wearing armor made of metal. On a hit, the target takes 1d8 + lightning damage, and it can't take reactions until the start of + its next turn. + + The spell's damage increases by 1d8 when you reach 5th level + (2d8), 11th level (3d8), and 17th level (4d8). + + """ + name = "Shocking Grasp" + level = 0 + casting_time = "1 action" + casting_range = "Touch" + components = ("V", "S", ) + duration = "Instantaneous" + magic_school = "Evocation" + classes = ('Sorceror', 'Wizard', ) + + +class Sleep(Spell): + """This spell sends creatures into a magical slumber. Roll 5d8, the + total is how many hit points of creatures this spell can + affect. Creatures within 20 feet of a point you choose within + range are affected in ascending order of their current hit points + (ignoring unconscious creatures). + + Starting with the creature that has the lowest current hit points, + each creature affected by this spell falls unconscious until the + spell ends, the sleeper takes damage, or someone uses an action to + shake or slap the sleeper awake. Subtract each creature's hit + points from the total before moving on to the creature with the + next lowest hit points. A creature's hit points must be equal to + or less than the remaining total for that creature to be affected. + + Undead and creatures immune to being charmed aren't affected by + this spell. + + At Higher Levels: When you cast this spell using a spell slot of + 2nd level or higher, roll an additional 2d8 for each slot level + above 1st. + + """ + name = "Sleep" + level = 1 + casting_time = "1 action" + casting_range = "90 feet" + components = ("V", "S", "M", ) + materials = "A pinch of fine sand, rose petals, or a cricket" + duration = "1 minutes" + magic_school = "Enchantment" + classes = ('Bard', 'Sorceror', 'Wizard', ) diff --git a/examples/rogue.pdf b/examples/rogue.pdf index 455d051a3b681aeeadfb10f3fb45f2b9bd7af3b2..731456eda708187b6f3af12451795bb1bcb1c0e0 100644 GIT binary patch delta 112 zcmbR8gL}#k?uHh|Elh`QvRfJ%n;IIJOh0*(NfE}`{_!T$8bzlRLo;Ku#8gw$M6=|? z6!Vl+<75M43qy0`R5Rm53(HhHn?ysy6!TQmwB%&7q@-j+qm&dA6N?mMBO_A-BeO&! L)9LqrGnoPaYn&uQ delta 112 zcmbR8gL}#k?uHh|Elh`QvRfD#n^>4wPCt2*NfE}`{_!T$8bv3gq_kwyBr{V(qeRn0 zLqiKgGt0yjv(%&{)1)MWq!d#-8&fk&!!%<90|Rr5G)qfUleCm13y|`(WOE~vq|~J8 J_kS~)0sv)$BxC>p diff --git a/examples/wizard.pdf b/examples/wizard.pdf index d0ae6afddffcf0a8cd2d8f6355d33e77f6d01047..83367cc466cd0cb47c88ee048b7cc8b520aae290 100644 GIT binary patch delta 32666 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

a9mwIG!2pNwKs3FD!YD2=MABD4Ke<4G z@2uDxq0kYa;Ko>iGDm=da7QrhsF%Yh-UoPaIQ@CRV@Jhb5Y4c+JguL>9m;o3MX}?% zA<%Mh+j-A$qpzq2OzUrmS}4bqH0cz)7v+e~L-9?NQ!9&&1zhG36RJlW`RuBbX?VEl zsMQv}38!~qiGfOp6-@bdL@YS2s3t7arqjUB zbyo+GV`!RQIxTxbyNtyA*9+jdg==dw#Nd$W6ZUI}(V7}9^ZZD^O&T|p=#lD>@Hepy ztgmtlLr=5E0n~sIB0&#r{SD&+NP$bEA5O;%)YU?8pAUy{5X7)>L`Py1K!~&xF}zO@ zCs2=xSjR1ipcMKNHtz{d6iHCC8QMlI4fZASjQVzMyn+?PsA%OA6LUu!^Em_({Y6iX zHaL_L)QT>}f;_|!kvJvIZHgV}hqItzI3h(XpzQ4h8`{wnhn^l0^sr`Mh0w#c#gbq) zP?$&SCu7Tp=jtY1G1iy>sss}T;ETm7T96;@UIYmasz!(=_Drwi15nBG0dhW+L^u)> z9|(C zW7g6LE3|=@&js;e-&nwXm>Xe*_R+m_v(2`~{(mF)!QRD8YBDuxY5?GW?3F7<|#(xN{aLM{^^z8-hiY1j<|HMb$fv zU`NRH=f&81U`t5&zVm=b6(XeYhC=usqN7VOob8zdyV1(ttvU;m*-aZ4VTK_2#!9Gl zCKNJCyF$p(PRBI&mV#)I`rAoHUzSdtRwK|qOuJXqQ_8n=aOyv-V0Gd<-pR{gGH`~) z9bIFZw9q({8yy2G5he-wM*AEAE+7*nq`*k6i5MvXa7W{0UHu{i_`=F8z^)fy`oESK zYp_1hT+!wT&5gD>rlDF)6dE32ocd7f%b8=bjQQ(jhEC=s#&9}*865kZi$UeOUvUAG z4Q51MjahHdjTbX>x8SELVp0F|j0JRb73QDO9mUHd=YeM2@dq>`LMpmgmMmf&A=$DX zFq9~7_NdFF4pZ?J*eEN^fW1Fm4H{4XPJfGDy#(Kc93Q*LI1`nlfMn7B2$G}ikLk4N ze=MT&uLP}ufr97C-XWLPfXErE5WTdx8q{Qy8w{VEKm{mhTxAmbTmnb`$!cRZjl2?= z3HvN6rdO^3ow)p9I_b-6jE3~YQlm+}9n)b%I)QC^2x|iy4ZP}XQx*v>gapR9HoyQ^ z{@>}<^}zY2M407imxFFQq}vYl*NGV^T)YWUV-Ni92sR!SAMSG4e1$QO?@!pRiqXV0 z7_m#DFFR~dud|GOz!SAPadUb+Ve*Oe^&De1W6!@k7;p_Z zf?^SKgmbcOIMVq}q@o2>!lG;2wZBGf6goHUzQe2Ve|KE;Yc%N11NQxvN38NPR& zU_P!;wyrfEt`Rr1g|;6|v;APXlM0@lpoCxO1m$ylhVL`s`%L&8)NBi#prTsn1XWIa zhVO$iV4)KT7@q<9PQMU;C&b?g@pnS}oe+N~#NP?=cYuGtb;fBmPH@Lu=%xZjxIsAp z&q9^(8DQWBzNpX*l4*Q~??Z~*bifHW6YdjaqJ?hIF^<7ZTKgQgC`2WQlM6jJ+{z8u>!E*P_XfiaS?Xm;^@H90Ac!jTL;dtq0ZaXm zQa>F&htl*j;d4ldZ-&oiz!~2PpRMpY#MZ9~dWj1CP%r&ZMt&$GKa`Ol%E%98&s)pz&I}(}>`10%sjK=^rYH+;Sp-`LPm$D;41s-z(37wr=zHnC6xpND10Sj^Y z4@URe)D1>eBH`A4Ju=z7HT7$flTW9;W8~7ohm6fn{11C7E9;h z8$DQ_Y)+H58832%_tCm!CmOWfXvWvpV&_%cjhPAVDf?z*vPJC=j~K%{(Jep0@?-xu zc)aLcq;jwSfRXv{8eNgk&Am3+j(R_vbm$-N8uxI|+O_W)8E%g%-H>cXzYIdB>!J4y zG^(M+scyu6-$-#wj~LnazR{enec$N8m)qHqQ|R=TIe@z%d0eoG^MTQyPV0cN+j8-P z)*06&+t=Rrf$?+Oz8;H5u&B5=x9@4?)n&8Fs>{H^K*+fR21I!1Iklj4H~M|N+Qr+G zpBx9~cy8^QWX@O~qkErD7W0rz=e%o}NlZUg&v_WHT(m&v*hvqU-8ngHZ~3TbPToC4nSPj4pM z0W9vFx4x1*rM6qsoX=6z&M>SZ`fhjf?Ai^@a|S0y1m*-(4lx146(^0KGW;aeoS)K6 zyf`8Jl;S60p7_b;rwpA`kkdLpd&M$g0?)yH$96k$GR=E4*_2s;E9y6sZJPosq5rvk zhmRLqMX}xcCc@C;TjrdCJHFa6EpvX>{^!8|=fMBx!2jpK;pS5RA3E?U|L+bw=6^)7 zuFhGN&RkM8tZK;uSYPx=H0qEui0{+S=#X>rael_Mxj0|lA*ZPB;nog0tGF1~wqs7~ z94lpIY`3<5$DAh$@nAYAm>eCF^QGp&7JoK0XLmw#kZC_UET=PV8)^w+cB@>EuvqMJtA z(C4f2_?VU9a8>{Lf@;#G>+IJHv5we6ekFNG*+d9LL1RT$59Y_?Tm= zI^$S1oLEQ`T~6rZWB5^#B6nna%39aqL`PaH3IWoX&#^uJLGF`1b{V9eitK!s)0_BW z&*OYu9#c8!r&ay%?Mw{8!C=3MtVX89M5{q;qL?Q#qZnWlCHJyXup{`fj)ap5Ln7mD zrZaqT7~didV9J=N%1HBkuB61rOex^hG104!c@aG}QCd+p#EFzoDVU{-$rZ)0IAHuv`>J&`H4QVv%-;%j|T`I5){8ku6~rD8JRoWo;Zf9frGTUjJ<6nx7Z z17e|Kq9B;Yc?#y$)R_@0jUNoli%r!ZS+K9NJS})anS+QY6wz7m$?=m@1J`Y-_RBI& z#X4IimMaLVC&#i<3j3{NcmT_?{S<0AadzPko5e9?1br@r#pgj~6!tr=h)poDo~yR_ zfseG-<0_~atI1k%6seUM#&T>W9I#w;-^$3~N4*MXP~24zbWK^0YBH89%Dr(6Q6tP^ zScjm8fJFxEWw<^YUyCZHqJ)SH6%L{-Xce;ki?Yi{JRom~Gb>YvXqH>BVry+MK}On6 zrMVs}&9mw)YfTut+9>SFlptu}(rA1!LP%NrZNQL`wo!6Z_DlO*28`|3+J;sui!&DD z@|tluoonhfB`XKpL})ARVnb^c(%ERs^GsKX#u1GuX4l3U5=ceeqiuV~SgZ=xwnQN~ zMkbD*DnlDdhK!(_;v#b0THzkykhmmWH;6A8j41}fb}S``wc&0R_Ihe+V7qXTG7Q(O z;SzNmu#3YckKs~5(MI%*D`N6&C1A2WabFaNQFmM-?h)5dN`{21CnXZW^^_7m*}lgW zZ+{(KV`AnWI`dvwy`*9P^2VhoSbiNP3`qNRB%TS2dqaUrQw*TSjP$R^A| zMx#&yZBQt|F;x&m?xL(UEhY4FOxVPLkb3tBx4<>gICWOK-jald1SVVYQVwn&6+&Rt z6r`c8aianE=)lt`Y_(10ygT^INeU4Bi7|x>PzHq%=yV(~;5zu*T4YYnX;R}TM*~-k zN}z{pNUjsdIRuZW0K=7;d|Dh>UuB*f#_drfNrfRM4D-Oc(#ocfmLDWEGmg8@4C`T7#HHt50-!AI}#uS(6ro^>n z3@|QxW7Oeg1{c37V1#}FS0hFUp@O1N7>ia$7#KEml(Y%A$x2A=;=V){6UO2ZP9NS7 z!H0ZYFs2w17j>(#Q;}Dy^$|CN_)Jm>j44LYMUhC>PpGz1ra)@Kcgp-vUAPBz4@^;~ z*q|D~z}=viddRe#PBo^ZD2$67M^O$$gYx-C@~k)%H|x8j7$EtRkEUz+LTs$v_4p&^ zQGh_N}Bv5c-1H}7vh%)0C)f;$!I>30M*e1h=LMVsQg;iGO*-91<-=Y{`*Yy;4g?5J^ zj*8ku3@Ra{>qUax&^6)QE8z_OzJg-h0ax*-t|yvC>Vzw7qKo7=BFR9I@Vl}>g&|i; z1xRDKU8QbAe95>7UDW;5vYLmwfr2##l|%T(EFv)T9Q-_7#?Vm>t%vp~`9yffDENA~=Tq1ZrBT*GY5aaN zU?hqPyHKu@4HBAyD19#5FU4fwC-{ngMsE@K1;kD%`im5wiF$$Jh;Xl>_)&}nfkxDR zA>2~#4-l3ql0jWsiBd48L`Sed3d1oLJEX#X;aW@y2=O~{#RmBq{7qw-3mLdTWekd^ zj;TU0)2O@16HPS+^HErkrHV0?I@Grm1d;5>ZqA3-3N#{Ozfj!bhOM}aEmc2!OO4eq z7LV0%a#3eiVgopUc!jEsn5ZUwK3d?$mP0?)oWr-(>L$iiMxyGj(1RpaK1XOboKK6)<|Nuy?|NCw+Qkq-3JwN=3AlvDwW?!&kQ5mG1= zquEh02*;>hpi!?zG2C22P$=%q5>F2P(>uT zjZ#h|;c*k`VD$ zsScX3S#mIiG2|?9zF~}Osj(xBG38c+$3*zZ+LaA{00AwK@?zYxOPYdtN@&4jvW>@> zBb#m>iz)@f2Y)l7C6&KNkU^j+BV)qIt7CD2@qQ*!A7!4U%FAqlGNUpPf7hUr6A;-L zVqc{IW};m}z9+y~S~e&cv*jQGW1E^jm3FSVTU3H9Wf@!GyNHz&#QEp){ zCYpfbjD$T?7>WLAp`}rkKsYF8Ik=)1@krR2$bL0dSW3cNH@iQR^y<%&HN}$hJ z_Ub76D6I?_^W-)NY^WX#{3=N~tmt=+M+pKMSGl9cePK$je_;&OSeX(Fr9pWNSGLML zgg~<8NLwg6iM92<2vuq)o`*4pP!Fsc+)H9ixoAODFMhNTLpp={fJ`yQ2^!Ku^AAHqpo6jMG<7*ot`#>OSEj39iO z!Wl&1vZf=dlKUEf3|zW&M~%T){gRaog+HZN&V=qOrvyBZFJG`$xxB?#qy`<{QDei5 zsx&wzvQf!+o)X@`dZ^m(!#zseLQp0b0n8c{#1&i3MRG+X$aZ9f<49PZ$L>=FY%8Y; zE}aQs|5NXk+3U#X7-I@`P+{fR!AZpLHz7LMbj4J2z*$eoRMFmQvQ<$iF_nuL%)@=P z%vP9+`VF)DAvvKhmLMIlT!oj2tF!j6E;z=RoYR>&rz%!zIRN*C_%k&!R_J82SNdZ*|@wa*7vcdI>Lb`+KN(Kzi713HDU|^`mbhzG-?~#}>N^XL_207

<@V25DPkK}yJ=K}#_S7Jhaw^8#bhASw`og$z-)pwKWS%148i!dwf&SCPSg zAy7e3Rd;wf)x;xDQce=?@Kv^&;+Lv1RYWSNME>YBQ>1Sp+7e;{{dH#m9bby)#F$+0 zLjt2*LtzX}kTS)HYZWelwy16~|4k6AgyTpS6{Cdp%RFHA9RrGp- zT}SC?#$uH1l*PfVA&{+Kj7w(uP(kV{t35U7LH#hiG(0=Hp(|fNnTV6+@)KH1eEB91 z^OS-c=HU;AoR1@}W}IlWQYtJqE^1`D5o0Q60Aq4h3%BF8Qa`X$eqfxUDrO@{l9`4m zNAZ;ylP~S?TMk@eNrFMFp#=0c|BNFtPpBAoV#y~QwE`urK}|sk&d_$EL?FmuRHRY1 zRuD9CX`}!~Xe^ryG_%QtYxE?elOaM0pA{Q9mVD4KrW6`b;0U9V8TBf5jAk}CG^9#0 z5JZIv(ufLWYi}bcwCUglaOOxkl@++|i3&oX&v(-@G@Lm3xT0jEIBxFoQugzLMsOB# z-O0(G6IXJycj-GC@zpmK)5g@a|Zofv08&z zn?|>VycRu{vNwgDRl-syU89y!xzeNpR*SZ1Dv&!EaDtSZT%=l=D8&K6@b*G^qK6#H zqhe^P-Vbyrfir$?rJO4VvXgZN-XRt^i$jhsG$oaH&^aobHMC49j>*A)%SKjj+_5Sa z2V*K%9Te~sIUy@h#$3d_vW(HrqKx6(9<~sXxW zaO%R@Rs5q$NPzzvx2Fy*oLW4~wPv|?Ieu3;YvwGo%$;q|MktA z@v}YOE1QWz-MMZ#uDM|pQ{|>T8?92VJK*fxzT>K@s(EW@5N|!c@`7@HbouWLEUhkE YQoUkH`RrU^hcqv@bLUge7?%5g0rl1i4FCWD delta 31414 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 z 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 GD*qohQ1zPt diff --git a/examples/wizard.py b/examples/wizard.py index 55ce9a3..c1793e0 100644 --- a/examples/wizard.py +++ b/examples/wizard.py @@ -40,6 +40,15 @@ equipment = ( sheets of parchment, small knife, tome of historical lore, holy symbol, prayer book, set of common clothes, pouch.""") +# List of known spells +spells = ('blindness deafness', 'burning hands', 'detect magic', + 'false life', 'mage armor', 'mage hand', 'magic missile', + 'prestidigitation', 'ray of frost', 'ray of sickness', 'shield', + 'shocking grasp', 'sleep') +# Which spells have been prepared (not including cantrips) +spells_prepared = ('blindness deafness', 'false life', 'mage armor', + 'ray of sickness', 'shield', 'sleep') + # Backstory personality_traits = """I use polysyllabic words that convey the impression of erudition. Also, I’ve spent so long in the temple that I have little