├── .gitignore ├── Readme.md ├── dndshell ├── dndshell.go ├── json ├── ability.json ├── class.json ├── levels.json ├── monsters.json ├── quotes.json ├── race.json └── spells.json ├── one.gif ├── shell ├── character │ ├── ability │ │ └── ability.go │ ├── attack │ │ └── attack.go │ ├── character.go │ ├── class │ │ ├── class.go │ │ ├── feats │ │ │ └── feats.go │ │ ├── lang │ │ │ └── lang.go │ │ ├── skills │ │ │ └── skills.go │ │ └── subclass │ │ │ └── subclass.go │ ├── feats │ │ └── feats.go │ ├── inv │ │ └── inv.go │ ├── levels │ │ └── levels.go │ ├── race │ │ └── race.go │ ├── skill │ │ └── skill.go │ └── spells │ │ └── spells.go ├── commands │ └── commands.go ├── dice │ └── dice.go ├── general │ └── general.go ├── monsters │ └── monsters.go ├── quotes │ └── quotes.go ├── shell.go ├── spells │ └── spells.go └── tables │ └── tables.go └── two.gif /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdpunk/dndshell/4e438d7ce7f2951ed8b6b8e1429c9e5049321a75/.gitignore -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # An all purpose DND Shell 2 | 3 | A shell for all things DND. As an avid command line user, and DM, I figued I would change my DMing work flow to more match the automation work flow I use at work and home. Once completed, you won't have to drop into the shell if you don't want you'll be able to feed the commands externally, allowing portions of your DM prep to be scripted. A while ago I made a simple GoLang program to build many many random encounters, based on certain criteria, eventually that will merge with this. 4 | 5 | ## Installation 6 | 7 | If you have go installed, it's easy: 8 | 9 | ``` 10 | go get github.com/bsdpunk/dndshell 11 | ``` 12 | 13 | ## Currently Working 14 | 15 | Tab Completion, and a workable history of how the shell was used in that instance are working. Listing many things like monsters, races, classes and Spells also work. The Return by Id work on these as well, however you must of course use Id and what is returned is the go struct, not an attractive display. A way to attractively display these things will be added. MonsterByName(mbn), now works but the name must be exact. MonsterByGuess(mbg), now works. MonsterByCR(mcb) now works. 16 | 17 | ![Install and start](one.gif) 18 | ![Monster Commands](two.gif) 19 | 20 | 21 | ## Not working 22 | 23 | Well everything is pretty much half baked, the CreateCharacter command is pretty awful, and will be improved, currently the most complete thing you can get with it, is a half complete blob of JSON representing your character. Let's be honest most things don't work right now, and Nothing's pretty. 24 | 25 | ## Import Agenda Items 26 | 27 | Getting jsonQL to filter so you can search by name or stats for everything. IE I need 4 CR 5 guys, and someone with at least 3 Special Attacks. 28 | ``` 29 | 30 | {"PlayerName":"Dusty","CharacterName":"Beastie","CharacterClass":{"class_levels":{"class":"Wizard","url":"http://www.dnd5eapi.co/api/classes/wizard/levels"},"hit_die":6,"_id":"","index":12,"name":"Wizard","proficiencies":[{"name":"Daggers","url":"http://www.dnd5eapi.co/api/proficiencies/22"},{"name":"Quarterstaffs","url":"http://www.dnd5eapi.co/api/proficiencies/28"},{"name":"Darts","url":"http://www.dnd5eapi.co/api/proficiencies/32"},{"name":"Slings","url":"http://www.dnd5eapi.co/api/proficiencies/34"}],"proficiency_choices":[{"choose":2,"from":[{"name":"Skill: Arcana","url":"http://www.dnd5eapi.co/api/proficiencies/107"},{"name":"Skill: History","url":"http://www.dnd5eapi.co/api/proficiencies/110"},{"name":"Skill: Insight","url":"http://www.dnd5eapi.co/api/proficiencies/111"},{"name":"Skill: Investigation","url":"http://www.dnd5eapi.co/api/proficiencies/113"},{"name":"Skill: Medicine","url":"http://www.dnd5eapi.co/api/proficiencies/114"},{"name":"Skill: Religion","url":"http://www.dnd5eapi.co/api/proficiencies/119"}],"type":"proficiencies"}],"saving_throws":[{"name":"INT","url":"http://www.dnd5eapi.co/api/ability-scores/4"},{"name":"WIS","url":"http://www.dnd5eapi.co/api/ability-scores/5"}],"starting_equipment":{"class":"Wizard","url":"http://www.dnd5eapi.co/api/startingequipment/12"},"subclasses":[{"name":"Evocation","url":"http://www.dnd5eapi.co/api/subclasses/12"}],"url":"http://www.dnd5eapi.co/api/classes/12"},"CharacterRace":{"ability_bonus_options":{"choose":0,"from":null,"type":""},"ability_bonuses":[{"bonus":2,"name":"INT","url":"http://www.dnd5eapi.co/api/ability-scores/4"}],"age":" Gnomes mature at the same rate humans do, and most are expected to settle down into an adult life by around age 40. They can live 350 to almost 500 years.","alignment":"Gnomes are most often good. Those who tend toward law are sages, engineers, researchers, scholars, investigators, or inventors. Those who tend toward chaos are minstrels, tricksters, wanderers, or fanciful jewelers. Gnomes are good-hearted, and even the tricksters among them are more playful than vicious.","index":6,"language_desc":"You can speak, read, and write Common and Gnomish. The Gnomish language, which uses the Dwarvish script, is renowned for its technical treatises and its catalogs of knowledge about the natural world.","language_options":{"choose":0,"from":null,"type":""},"languages":[{"name":"Common","url":"http://www.dnd5eapi.co/api/languages/1"},{"name":"Gnomish","url":"http://www.dnd5eapi.co/api/languages/5"}],"name":"Gnome","Races":null,"size":"Small","size_description":"Gnomes are between 3 and 4 feet tall and average about 40 pounds. Your size is Small.","speed":25,"starting_proficiencies":[],"starting_proficiency_options":{"choose":0,"from":null,"type":""},"subraces":[{"name":"Rock Gnome","url":"http://www.dnd5eapi.co/api/subraces/4"}],"trait_options":{"choose":0,"from":null,"type":""},"traits":[{"name":"Darkvision","url":"http://www.dnd5eapi.co/api/traits/1"},{"name":"Gnome Cunning","url":"http://www.dnd5eapi.co/api/traits/19"}],"url":"http://www.dnd5eapi.co/api/races/6"},"AbilityScores":{"AbilityScores":null},"CharacterScores":[10,10,10,10,10,10],"CharacterModifiers":[0,0,0,0,0,0],"Actions":0,"BonusAction":0,"Prof":2,"HitPoints":0,"ArmorClass":0,"Initiative":0,"Level":2} 31 | ``` 32 | 33 | 34 | ## Monsters 35 | Listing all Monsters currently works. Selecting a monster by ID works, but returns a go structure currently. Getting a limited, better formated Statblock works. 36 | 37 | 38 | ## Abilities, Skills and Spells 39 | 40 | Abilities and Spells are currently listable and selectable by an ID 41 | 42 | 43 | ``` 44 | > 45 | AbilityById cl CreateCharacter LevelsById ListLevels ll Quit rl sbid 46 | aid ClassById d lid ListMonster mid quit rl sid 47 | al clear Dice ListAbilities ListRaces ml RaceById sb SpellBook 48 | cid Clear ic ListClasses ListSpells MonsterById rid SBById SpellById 49 | > ListClasses 50 | 0 Barbarian 51 | 1 Bard 52 | 2 Cleric 53 | 3 Druid 54 | 4 Fighter 55 | 5 Monk 56 | 6 Paladin 57 | 7 Ranger 58 | 8 Rogue 59 | 9 Sorcerer 60 | 10 Warlock 61 | 11 Wizard 62 | > ListRaces 63 | 0 Dwarf 64 | 1 Elf 65 | 2 Halfling 66 | 3 Human 67 | 4 Dragonborn 68 | 5 Gnome 69 | 6 Half-Elf 70 | 7 Half-Orc 71 | 8 Tiefling 72 | 73 | ``` 74 | 75 | ## NPCs 76 | You can create NPCs using in or CreateNPC, this is very beta. 77 | -------------------------------------------------------------------------------- /dndshell: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdpunk/dndshell/4e438d7ce7f2951ed8b6b8e1429c9e5049321a75/dndshell -------------------------------------------------------------------------------- /dndshell.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "fmt" 4 | import "bufio" 5 | import "os" 6 | import "log" 7 | 8 | import "github.com/bsdpunk/dndshell/shell" 9 | 10 | //import "./shell" 11 | 12 | func main() { 13 | 14 | scanner := bufio.NewScanner(os.Stdin) 15 | stat, _ := os.Stdin.Stat() 16 | if (stat.Mode() & os.ModeCharDevice) == 0 { 17 | for scanner.Scan() { 18 | fmt.Println("Feature to come later") 19 | 20 | } 21 | if err := scanner.Err(); err != nil { 22 | log.Println(err) 23 | } 24 | } else { 25 | shell.Shell(os.Args) 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /json/ability.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "index": 1, 4 | "name": "STR", 5 | "full_name": "Strength", 6 | "desc": [ 7 | "Strength measures bodily power, athletic training, and the extent to which you can exert raw physical force.", 8 | "A Strength check can model any attempt to lift, push, pull, or break something, to force your body through a space, or to otherwise apply brute force to a situation. The Athletics skill reflects aptitude in certain kinds of Strength checks." 9 | ], 10 | "skills": [ 11 | { 12 | "url": "http://www.dnd5eapi.co/api/skills/4", 13 | "name": "Athletics" 14 | } 15 | ], 16 | "url": "http://www.dnd5eapi.co/api/ability-scores/1" 17 | }, 18 | { 19 | "index": 2, 20 | "name": "DEX", 21 | "full_name": "Dexterity", 22 | "desc": [ 23 | "Dexterity measures agility, reflexes, and balance.", 24 | "A Dexterity check can model any attempt to move nimbly, quickly, or quietly, or to keep from falling on tricky footing. The Acrobatics, Sleight of Hand, and Stealth skills reflect aptitude in certain kinds of Dexterity checks." 25 | ], 26 | "skills": [ 27 | { 28 | "url": "http://www.dnd5eapi.co/api/skills/1", 29 | "name": "Acrobatics" 30 | }, 31 | { 32 | "url": "http://www.dnd5eapi.co/api/skills/16", 33 | "name": "Sleight of Hand" 34 | }, 35 | { 36 | "url": "http://www.dnd5eapi.co/api/skills/17", 37 | "name": "Stealth" 38 | } 39 | ], 40 | "url": "http://www.dnd5eapi.co/api/ability-scores/2" 41 | }, 42 | { 43 | "index": 3, 44 | "name": "CON", 45 | "full_name": "Constitution", 46 | "desc": [ 47 | "Constitution measures health, stamina, and vital force.", 48 | "Constitution checks are uncommon, and no skills apply to Constitution checks, because the endurance this ability represents is largely passive rather than involving a specific effort on the part of a character or monster." 49 | ], 50 | "skills": [], 51 | "url": "http://www.dnd5eapi.co/api/ability-scores/3" 52 | }, 53 | { 54 | "index": 4, 55 | "name": "INT", 56 | "full_name": "Intelligence", 57 | "desc": [ 58 | "Intelligence measures mental acuity, accuracy of recall, and the ability to reason.", 59 | "An Intelligence check comes into play when you need to draw on logic, education, memory, or deductive reasoning. The Arcana, History, Investigation, Nature, and Religion skills reflect aptitude in certain kinds of Intelligence checks." 60 | ], 61 | "skills": [ 62 | { 63 | "url": "http://www.dnd5eapi.co/api/skills/3", 64 | "name": "Arcana" 65 | }, 66 | { 67 | "url": "http://www.dnd5eapi.co/api/skills/6", 68 | "name": "History" 69 | }, 70 | { 71 | "url": "http://www.dnd5eapi.co/api/skills/9", 72 | "name": "Investigation" 73 | }, 74 | { 75 | "url": "http://www.dnd5eapi.co/api/skills/11", 76 | "name": "Nature" 77 | }, 78 | { 79 | "url": "http://www.dnd5eapi.co/api/skills/15", 80 | "name": "Religion" 81 | } 82 | ], 83 | "url": "http://www.dnd5eapi.co/api/ability-scores/4" 84 | }, 85 | { 86 | "index": 5, 87 | "name": "WIS", 88 | "full_name": "Wisdom", 89 | "desc": [ 90 | "Wisdom reflects how attuned you are to the world around you and represents perceptiveness and intuition.", 91 | "A Wisdom check might reflect an effort to read body language, understand someone's feelings, notice things about the environment, or care for an injured person. The Animal Handling, Insight, Medicine, Perception, and Survival skills reflect aptitude in certain kinds of Wisdom checks." 92 | ], 93 | "skills": [ 94 | { 95 | "url": "http://www.dnd5eapi.co/api/skills/2", 96 | "name": "Animal Handling" 97 | }, 98 | { 99 | "url": "http://www.dnd5eapi.co/api/skills/7", 100 | "name": "Insight" 101 | }, 102 | { 103 | "url": "http://www.dnd5eapi.co/api/skills/10", 104 | "name": "Medicine" 105 | }, 106 | { 107 | "url": "http://www.dnd5eapi.co/api/skills/12", 108 | "name": "Perception" 109 | }, 110 | { 111 | "url": "http://www.dnd5eapi.co/api/skills/18", 112 | "name": "Survival" 113 | } 114 | ], 115 | "url": "http://www.dnd5eapi.co/api/ability-scores/5" 116 | }, 117 | { 118 | "index": 6, 119 | "name": "CHA", 120 | "full_name": "Charisma", 121 | "desc": [ 122 | "Charisma measures your ability to interact effectively with others. It includes such factors as confidence and eloquence, and it can represent a charming or commanding personality.", 123 | "A Charisma check might arise when you try to influence or entertain others, when you try to make an impression or tell a convincing lie, or when you are navigating a tricky social situation. The Deception, Intimidation, Performance, and Persuasion skills reflect aptitude in certain kinds of Charisma checks." 124 | ], 125 | "skills": [ 126 | { 127 | "url": "http://www.dnd5eapi.co/api/skills/5", 128 | "name": "Deception" 129 | }, 130 | { 131 | "url": "http://www.dnd5eapi.co/api/skills/8", 132 | "name": "Intimidation" 133 | }, 134 | { 135 | "url": "http://www.dnd5eapi.co/api/skills/13", 136 | "name": "Performance" 137 | }, 138 | { 139 | "url": "http://www.dnd5eapi.co/api/skills/14", 140 | "name": "Persuasion" 141 | } 142 | ], 143 | "url": "http://www.dnd5eapi.co/api/ability-scores/6" 144 | } 145 | ] 146 | -------------------------------------------------------------------------------- /json/class.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "index": 1, 4 | "name": "Barbarian", 5 | "hit_die": 12, 6 | "proficiency_choices": [ 7 | { 8 | "choose": 2, 9 | "type": "proficiencies", 10 | "from": [ 11 | { 12 | "url": "http://www.dnd5eapi.co/api/proficiencies/106", 13 | "name": "Skill: Animal Handling" 14 | }, 15 | { 16 | "url": "http://www.dnd5eapi.co/api/proficiencies/108", 17 | "name": "Skill: Athletics" 18 | }, 19 | { 20 | "url": "http://www.dnd5eapi.co/api/proficiencies/112", 21 | "name": "Skill: Intimidation" 22 | }, 23 | { 24 | "url": "http://www.dnd5eapi.co/api/proficiencies/115", 25 | "name": "Skill: Nature" 26 | }, 27 | { 28 | "url": "http://www.dnd5eapi.co/api/proficiencies/116", 29 | "name": "Skill: Perception" 30 | }, 31 | { 32 | "url": "http://www.dnd5eapi.co/api/proficiencies/122", 33 | "name": "Skill: Survival" 34 | } 35 | ] 36 | } 37 | ], 38 | "proficiencies": [ 39 | { 40 | "name": "Light armor", 41 | "url": "http://www.dnd5eapi.co/api/proficiencies/1" 42 | }, 43 | { 44 | "name": "Medium armor", 45 | "url": "http://www.dnd5eapi.co/api/proficiencies/2" 46 | }, 47 | { 48 | "name": "Shields", 49 | "url": "http://www.dnd5eapi.co/api/proficiencies/18" 50 | }, 51 | { 52 | "name": "Simple weapons", 53 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 54 | }, 55 | { 56 | "name": "Martial weapons", 57 | "url": "http://www.dnd5eapi.co/api/proficiencies/20" 58 | } 59 | ], 60 | "saving_throws": [ 61 | { 62 | "name": "STR", 63 | "url": "http://www.dnd5eapi.co/api/ability-scores/1" 64 | }, 65 | { 66 | "name": "CON", 67 | "url": "http://www.dnd5eapi.co/api/ability-scores/3" 68 | } 69 | ], 70 | "starting_equipment": { 71 | "url": "http://www.dnd5eapi.co/api/startingequipment/1", 72 | "class": "Barbarian" 73 | }, 74 | "class_levels": { 75 | "url": "http://www.dnd5eapi.co/api/classes/barbarian/levels", 76 | "class": "Barbarian" 77 | }, 78 | "subclasses": [ 79 | { 80 | "url": "http://www.dnd5eapi.co/api/subclasses/1", 81 | "name": "Berserker" 82 | } 83 | ], 84 | "spellcasting": { 85 | 86 | }, 87 | "url": "http://www.dnd5eapi.co/api/classes/1" 88 | }, 89 | { 90 | "index": 2, 91 | "name": "Bard", 92 | "hit_die": 8, 93 | "proficiency_choices": [ 94 | { 95 | "choose": 3, 96 | "type": "proficiencies", 97 | "from": [ 98 | { 99 | "url": "http://www.dnd5eapi.co/api/proficiencies/105", 100 | "name": "Skill: Acrobatics" 101 | }, 102 | { 103 | "url": "http://www.dnd5eapi.co/api/proficiencies/106", 104 | "name": "Skill: Animal Handling" 105 | }, 106 | { 107 | "url": "http://www.dnd5eapi.co/api/proficiencies/107", 108 | "name": "Skill: Arcana" 109 | }, 110 | { 111 | "url": "http://www.dnd5eapi.co/api/proficiencies/108", 112 | "name": "Skill: Athletics" 113 | }, 114 | { 115 | "url": "http://www.dnd5eapi.co/api/proficiencies/109", 116 | "name": "Skill: Deception" 117 | }, 118 | { 119 | "url": "http://www.dnd5eapi.co/api/proficiencies/110", 120 | "name": "Skill: History" 121 | }, 122 | { 123 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 124 | "name": "Skill: Insight" 125 | }, 126 | { 127 | "url": "http://www.dnd5eapi.co/api/proficiencies/112", 128 | "name": "Skill: Intimidation" 129 | }, 130 | { 131 | "url": "http://www.dnd5eapi.co/api/proficiencies/113", 132 | "name": "Skill: Investigation" 133 | }, 134 | { 135 | "url": "http://www.dnd5eapi.co/api/proficiencies/114", 136 | "name": "Skill: Medicine" 137 | }, 138 | { 139 | "url": "http://www.dnd5eapi.co/api/proficiencies/115", 140 | "name": "Skill: Nature" 141 | }, 142 | { 143 | "url": "http://www.dnd5eapi.co/api/proficiencies/116", 144 | "name": "Skill: Perception" 145 | }, 146 | { 147 | "url": "http://www.dnd5eapi.co/api/proficiencies/117", 148 | "name": "Skill: Performance" 149 | }, 150 | { 151 | "url": "http://www.dnd5eapi.co/api/proficiencies/118", 152 | "name": "Skill: Persuasion" 153 | }, 154 | { 155 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 156 | "name": "Skill: Religion" 157 | }, 158 | { 159 | "url": "http://www.dnd5eapi.co/api/proficiencies/120", 160 | "name": "Skill: Sleight of Hand" 161 | }, 162 | { 163 | "url": "http://www.dnd5eapi.co/api/proficiencies/121", 164 | "name": "Skill: Stealth" 165 | }, 166 | { 167 | "url": "http://www.dnd5eapi.co/api/proficiencies/122", 168 | "name": "Skill: Survival" 169 | } 170 | ] 171 | }, 172 | { 173 | "choose": 3, 174 | "type": "proficiencies", 175 | "from": [ 176 | { 177 | "url": "http://www.dnd5eapi.co/api/proficiencies/81", 178 | "name": "Bagpipes" 179 | }, 180 | { 181 | "url": "http://www.dnd5eapi.co/api/proficiencies/82", 182 | "name": "Drum" 183 | }, 184 | { 185 | "url": "http://www.dnd5eapi.co/api/proficiencies/83", 186 | "name": "Dulcimer" 187 | }, 188 | { 189 | "url": "http://www.dnd5eapi.co/api/proficiencies/84", 190 | "name": "Flute" 191 | }, 192 | { 193 | "url": "http://www.dnd5eapi.co/api/proficiencies/85", 194 | "name": "Lute" 195 | }, 196 | { 197 | "url": "http://www.dnd5eapi.co/api/proficiencies/86", 198 | "name": "Lyre" 199 | }, 200 | { 201 | "url": "http://www.dnd5eapi.co/api/proficiencies/87", 202 | "name": "Horn" 203 | }, 204 | { 205 | "url": "http://www.dnd5eapi.co/api/proficiencies/88", 206 | "name": "Pan flute" 207 | }, 208 | { 209 | "url": "http://www.dnd5eapi.co/api/proficiencies/89", 210 | "name": "Shawm" 211 | }, 212 | { 213 | "url": "http://www.dnd5eapi.co/api/proficiencies/90", 214 | "name": "Viol" 215 | } 216 | ] 217 | } 218 | ], 219 | "proficiencies": [ 220 | { 221 | "name": "Light armor", 222 | "url": "http://www.dnd5eapi.co/api/proficiencies/1" 223 | }, 224 | { 225 | "name": "Simple weapons", 226 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 227 | }, 228 | { 229 | "name": "Longswords", 230 | "url": "http://www.dnd5eapi.co/api/proficiencies/42" 231 | }, 232 | { 233 | "name": "Rapiers", 234 | "url": "http://www.dnd5eapi.co/api/proficiencies/46" 235 | }, 236 | { 237 | "name": "Shortswords", 238 | "url": "http://www.dnd5eapi.co/api/proficiencies/48" 239 | }, 240 | { 241 | "name": "Crossbows, hand", 242 | "url": "http://www.dnd5eapi.co/api/proficiencies/54" 243 | } 244 | ], 245 | "saving_throws": [ 246 | { 247 | "name": "DEX", 248 | "url": "http://www.dnd5eapi.co/api/ability-scores/2" 249 | }, 250 | { 251 | "name": "CHA", 252 | "url": "http://www.dnd5eapi.co/api/ability-scores/6" 253 | } 254 | ], 255 | "starting_equipment": { 256 | "url": "http://www.dnd5eapi.co/api/startingequipment/2", 257 | "class": "Bard" 258 | }, 259 | "class_levels": { 260 | "url": "http://www.dnd5eapi.co/api/classes/bard/levels", 261 | "class": "Bard" 262 | }, 263 | "subclasses": [ 264 | { 265 | "url": "http://www.dnd5eapi.co/api/subclasses/2", 266 | "name": "Lore" 267 | } 268 | ], 269 | "spellcasting": { 270 | "url": "http://www.dnd5eapi.co/api/spellcasting/1", 271 | "class": "Bard" 272 | }, 273 | "url": "http://www.dnd5eapi.co/api/classes/2" 274 | }, 275 | { 276 | "index": 3, 277 | "name": "Cleric", 278 | "hit_die": 8, 279 | "proficiency_choices": [ 280 | { 281 | "choose": 2, 282 | "type": "proficiencies", 283 | "from": [ 284 | { 285 | "url": "http://www.dnd5eapi.co/api/proficiencies/110", 286 | "name": "Skill: History" 287 | }, 288 | { 289 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 290 | "name": "Skill: Insight" 291 | }, 292 | { 293 | "url": "http://www.dnd5eapi.co/api/proficiencies/114", 294 | "name": "Skill: Medicine" 295 | }, 296 | { 297 | "url": "http://www.dnd5eapi.co/api/proficiencies/118", 298 | "name": "Skill: Persuasion" 299 | }, 300 | { 301 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 302 | "name": "Skill: Religion" 303 | } 304 | ] 305 | } 306 | ], 307 | "proficiencies": [ 308 | { 309 | "name": "Light armor", 310 | "url": "http://www.dnd5eapi.co/api/proficiencies/1" 311 | }, 312 | { 313 | "name": "Medium armor", 314 | "url": "http://www.dnd5eapi.co/api/proficiencies/2" 315 | }, 316 | { 317 | "name": "Shields", 318 | "url": "http://www.dnd5eapi.co/api/proficiencies/18" 319 | }, 320 | { 321 | "name": "Simple weapons", 322 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 323 | } 324 | ], 325 | "saving_throws": [ 326 | { 327 | "name": "WIS", 328 | "url": "http://www.dnd5eapi.co/api/ability-scores/5" 329 | }, 330 | { 331 | "name": "CHA", 332 | "url": "http://www.dnd5eapi.co/api/ability-scores/6" 333 | } 334 | ], 335 | "starting_equipment": { 336 | "url": "http://www.dnd5eapi.co/api/startingequipment/3", 337 | "class": "Cleric" 338 | }, 339 | "class_levels": { 340 | "url": "http://www.dnd5eapi.co/api/classes/cleric/levels", 341 | "class": "Cleric" 342 | }, 343 | "subclasses": [ 344 | { 345 | "url": "http://www.dnd5eapi.co/api/subclasses/3", 346 | "name": "Life" 347 | } 348 | ], 349 | "spellcasting": { 350 | "url": "http://www.dnd5eapi.co/api/spellcasting/2", 351 | "class": "Cleric" 352 | }, 353 | "url": "http://www.dnd5eapi.co/api/classes/3" 354 | }, 355 | { 356 | "index": 4, 357 | "name": "Druid", 358 | "hit_die": 8, 359 | "proficiency_choices": [ 360 | { 361 | "choose": 2, 362 | "type": "proficiencies", 363 | "from": [ 364 | { 365 | "url": "http://www.dnd5eapi.co/api/proficiencies/106", 366 | "name": "Skill: Animal Handling" 367 | }, 368 | { 369 | "url": "http://www.dnd5eapi.co/api/proficiencies/107", 370 | "name": "Skill: Arcana" 371 | }, 372 | { 373 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 374 | "name": "Skill: Insight" 375 | }, 376 | { 377 | "url": "http://www.dnd5eapi.co/api/proficiencies/114", 378 | "name": "Skill: Medicine" 379 | }, 380 | { 381 | "url": "http://www.dnd5eapi.co/api/proficiencies/115", 382 | "name": "Skill: Nature" 383 | }, 384 | { 385 | "url": "http://www.dnd5eapi.co/api/proficiencies/116", 386 | "name": "Skill: Perception" 387 | }, 388 | { 389 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 390 | "name": "Skill: Religion" 391 | }, 392 | { 393 | "url": "http://www.dnd5eapi.co/api/proficiencies/122", 394 | "name": "Skill: Survival" 395 | } 396 | ] 397 | } 398 | ], 399 | "proficiencies": [ 400 | { 401 | "name": "Light armor", 402 | "url": "http://www.dnd5eapi.co/api/proficiencies/1" 403 | }, 404 | { 405 | "name": "Medium armor", 406 | "url": "http://www.dnd5eapi.co/api/proficiencies/2" 407 | }, 408 | { 409 | "name": "Shields", 410 | "url": "http://www.dnd5eapi.co/api/proficiencies/18" 411 | }, 412 | { 413 | "name": "Clubs", 414 | "url": "http://www.dnd5eapi.co/api/proficiencies/21" 415 | }, 416 | { 417 | "name": "Daggers", 418 | "url": "http://www.dnd5eapi.co/api/proficiencies/22" 419 | }, 420 | { 421 | "name": "Javelins", 422 | "url": "http://www.dnd5eapi.co/api/proficiencies/25" 423 | }, 424 | { 425 | "name": "Maces", 426 | "url": "http://www.dnd5eapi.co/api/proficiencies/27" 427 | }, 428 | { 429 | "name": "Quarterstaffs", 430 | "url": "http://www.dnd5eapi.co/api/proficiencies/28" 431 | }, 432 | { 433 | "name": "Sickles", 434 | "url": "http://www.dnd5eapi.co/api/proficiencies/29" 435 | }, 436 | { 437 | "name": "Spears", 438 | "url": "http://www.dnd5eapi.co/api/proficiencies/30" 439 | }, 440 | { 441 | "name": "Darts", 442 | "url": "http://www.dnd5eapi.co/api/proficiencies/32" 443 | }, 444 | { 445 | "name": "Slings", 446 | "url": "http://www.dnd5eapi.co/api/proficiencies/34" 447 | }, 448 | { 449 | "name": "Scimitars", 450 | "url": "http://www.dnd5eapi.co/api/proficiencies/47" 451 | }, 452 | { 453 | "name": "Herbalism Kit", 454 | "url": "http://www.dnd5eapi.co/api/proficiencies/93" 455 | } 456 | ], 457 | "saving_throws": [ 458 | { 459 | "name": "INT", 460 | "url": "http://www.dnd5eapi.co/api/ability-scores/4" 461 | }, 462 | { 463 | "name": "WIS", 464 | "url": "http://www.dnd5eapi.co/api/ability-scores/5" 465 | } 466 | ], 467 | "starting_equipment": { 468 | "url": "http://www.dnd5eapi.co/api/startingequipment/4", 469 | "class": "Druid" 470 | }, 471 | "class_levels": { 472 | "url": "http://www.dnd5eapi.co/api/classes/druid/levels", 473 | "class": "Druid" 474 | }, 475 | "subclasses": [ 476 | { 477 | "url": "http://www.dnd5eapi.co/api/subclasses/4", 478 | "name": "Land" 479 | } 480 | ], 481 | "spellcasting": { 482 | "url": "http://www.dnd5eapi.co/api/spellcasting/3", 483 | "class": "Druid" 484 | }, 485 | "url": "http://www.dnd5eapi.co/api/classes/4" 486 | }, 487 | { 488 | "index": 5, 489 | "name": "Fighter", 490 | "hit_die": 10, 491 | "proficiency_choices": [ 492 | { 493 | "choose": 2, 494 | "type": "proficiencies", 495 | "from": [ 496 | { 497 | "url": "http://www.dnd5eapi.co/api/proficiencies/105", 498 | "name": "Skill: Acrobatics" 499 | }, 500 | { 501 | "url": "http://www.dnd5eapi.co/api/proficiencies/106", 502 | "name": "Skill: Animal Handling" 503 | }, 504 | { 505 | "url": "http://www.dnd5eapi.co/api/proficiencies/108", 506 | "name": "Skill: Athletics" 507 | }, 508 | { 509 | "url": "http://www.dnd5eapi.co/api/proficiencies/110", 510 | "name": "Skill: History" 511 | }, 512 | { 513 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 514 | "name": "Skill: Insight" 515 | }, 516 | { 517 | "url": "http://www.dnd5eapi.co/api/proficiencies/112", 518 | "name": "Skill: Intimidation" 519 | }, 520 | { 521 | "url": "http://www.dnd5eapi.co/api/proficiencies/116", 522 | "name": "Skill: Perception" 523 | }, 524 | { 525 | "url": "http://www.dnd5eapi.co/api/proficiencies/122", 526 | "name": "Skill: Survival" 527 | } 528 | ] 529 | } 530 | ], 531 | "proficiencies": [ 532 | { 533 | "name": "All armor", 534 | "url": "http://www.dnd5eapi.co/api/proficiencies/4" 535 | }, 536 | { 537 | "name": "Shields", 538 | "url": "http://www.dnd5eapi.co/api/proficiencies/18" 539 | }, 540 | { 541 | "name": "Simple weapons", 542 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 543 | }, 544 | { 545 | "name": "Martial weapons", 546 | "url": "http://www.dnd5eapi.co/api/proficiencies/20" 547 | } 548 | ], 549 | "saving_throws": [ 550 | { 551 | "name": "STR", 552 | "url": "http://www.dnd5eapi.co/api/ability-scores/1" 553 | }, 554 | { 555 | "name": "CON", 556 | "url": "http://www.dnd5eapi.co/api/ability-scores/3" 557 | } 558 | ], 559 | "starting_equipment": { 560 | "url": "http://www.dnd5eapi.co/api/startingequipment/5", 561 | "class": "Fighter" 562 | }, 563 | "class_levels": { 564 | "url": "http://www.dnd5eapi.co/api/classes/fighter/levels", 565 | "class": "Fighter" 566 | }, 567 | "subclasses": [ 568 | { 569 | "url": "http://www.dnd5eapi.co/api/subclasses/5", 570 | "name": "Champion" 571 | } 572 | ], 573 | "spellcasting": { 574 | 575 | }, 576 | "url": "http://www.dnd5eapi.co/api/classes/5" 577 | }, 578 | { 579 | "index": 6, 580 | "name": "Monk", 581 | "hit_die": 8, 582 | "proficiency_choices": [ 583 | { 584 | "choose": 1, 585 | "type": "proficiencies", 586 | "from": [ 587 | { 588 | "url": "http://www.dnd5eapi.co/api/proficiencies/58", 589 | "name": "Alchemist's supplies" 590 | }, 591 | { 592 | "url": "http://www.dnd5eapi.co/api/proficiencies/59", 593 | "name": "Brewer's supplies" 594 | }, 595 | { 596 | "url": "http://www.dnd5eapi.co/api/proficiencies/60", 597 | "name": "Calligrapher's supplies" 598 | }, 599 | { 600 | "url": "http://www.dnd5eapi.co/api/proficiencies/61", 601 | "name": "Carpenter's tools" 602 | }, 603 | { 604 | "url": "http://www.dnd5eapi.co/api/proficiencies/62", 605 | "name": "Cartographer's tools" 606 | }, 607 | { 608 | "url": "http://www.dnd5eapi.co/api/proficiencies/63", 609 | "name": "Cobbler's tools" 610 | }, 611 | { 612 | "url": "http://www.dnd5eapi.co/api/proficiencies/64", 613 | "name": "Cook's utensils" 614 | }, 615 | { 616 | "url": "http://www.dnd5eapi.co/api/proficiencies/65", 617 | "name": "Glassblower's tools" 618 | }, 619 | { 620 | "url": "http://www.dnd5eapi.co/api/proficiencies/66", 621 | "name": "Jeweler's tools" 622 | }, 623 | { 624 | "url": "http://www.dnd5eapi.co/api/proficiencies/67", 625 | "name": "Leatherworker's tools" 626 | }, 627 | { 628 | "url": "http://www.dnd5eapi.co/api/proficiencies/68", 629 | "name": "Mason's tools" 630 | }, 631 | { 632 | "url": "http://www.dnd5eapi.co/api/proficiencies/69", 633 | "name": "Painter's supplies" 634 | }, 635 | { 636 | "url": "http://www.dnd5eapi.co/api/proficiencies/70", 637 | "name": "Potter's tools" 638 | }, 639 | { 640 | "url": "http://www.dnd5eapi.co/api/proficiencies/71", 641 | "name": "Smith's tools" 642 | }, 643 | { 644 | "url": "http://www.dnd5eapi.co/api/proficiencies/72", 645 | "name": "Tinker's tools" 646 | }, 647 | { 648 | "url": "http://www.dnd5eapi.co/api/proficiencies/73", 649 | "name": "Weaver's tools" 650 | }, 651 | { 652 | "url": "http://www.dnd5eapi.co/api/proficiencies/74", 653 | "name": "Woodcarver's tools" 654 | }, 655 | { 656 | "url": "http://www.dnd5eapi.co/api/proficiencies/75", 657 | "name": "Disguise kit" 658 | }, 659 | { 660 | "url": "http://www.dnd5eapi.co/api/proficiencies/76", 661 | "name": "Forgery kit" 662 | } 663 | ] 664 | }, 665 | { 666 | "choose": 1, 667 | "type": "proficiencies", 668 | "from": [ 669 | { 670 | "url": "http://www.dnd5eapi.co/api/proficiencies/81", 671 | "name": "Bagpipes" 672 | }, 673 | { 674 | "url": "http://www.dnd5eapi.co/api/proficiencies/82", 675 | "name": "Drum" 676 | }, 677 | { 678 | "url": "http://www.dnd5eapi.co/api/proficiencies/83", 679 | "name": "Dulcimer" 680 | }, 681 | { 682 | "url": "http://www.dnd5eapi.co/api/proficiencies/84", 683 | "name": "Flute" 684 | }, 685 | { 686 | "url": "http://www.dnd5eapi.co/api/proficiencies/85", 687 | "name": "Lute" 688 | }, 689 | { 690 | "url": "http://www.dnd5eapi.co/api/proficiencies/86", 691 | "name": "Lyre" 692 | }, 693 | { 694 | "url": "http://www.dnd5eapi.co/api/proficiencies/87", 695 | "name": "Horn" 696 | }, 697 | { 698 | "url": "http://www.dnd5eapi.co/api/proficiencies/88", 699 | "name": "Pan flute" 700 | }, 701 | { 702 | "url": "http://www.dnd5eapi.co/api/proficiencies/89", 703 | "name": "Shawm" 704 | }, 705 | { 706 | "url": "http://www.dnd5eapi.co/api/proficiencies/90", 707 | "name": "Viol" 708 | } 709 | ] 710 | }, 711 | { 712 | "choose": 2, 713 | "type": "proficiencies", 714 | "from": [ 715 | { 716 | "url": "http://www.dnd5eapi.co/api/proficiencies/105", 717 | "name": "Skill: Acrobatics" 718 | }, 719 | { 720 | "url": "http://www.dnd5eapi.co/api/proficiencies/108", 721 | "name": "Skill: Athletics" 722 | }, 723 | { 724 | "url": "http://www.dnd5eapi.co/api/proficiencies/110", 725 | "name": "Skill: History" 726 | }, 727 | { 728 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 729 | "name": "Skill: Insight" 730 | }, 731 | { 732 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 733 | "name": "Skill: Religion" 734 | }, 735 | { 736 | "url": "http://www.dnd5eapi.co/api/proficiencies/121", 737 | "name": "Skill: Stealth" 738 | } 739 | ] 740 | } 741 | ], 742 | "proficiencies": [ 743 | { 744 | "name": "Simple weapons", 745 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 746 | }, 747 | { 748 | "name": "Shortswords", 749 | "url": "http://www.dnd5eapi.co/api/proficiencies/48" 750 | } 751 | ], 752 | "saving_throws": [ 753 | { 754 | "name": "STR", 755 | "url": "http://www.dnd5eapi.co/api/ability-scores/1" 756 | }, 757 | { 758 | "name": "DEX", 759 | "url": "http://www.dnd5eapi.co/api/ability-scores/2" 760 | } 761 | ], 762 | "starting_equipment": { 763 | "url": "http://www.dnd5eapi.co/api/startingequipment/6", 764 | "class": "Monk" 765 | }, 766 | "class_levels": { 767 | "url": "http://www.dnd5eapi.co/api/classes/monk/levels", 768 | "class": "Monk" 769 | }, 770 | "subclasses": [ 771 | { 772 | "url": "http://www.dnd5eapi.co/api/subclasses/6", 773 | "name": "Open Hand" 774 | } 775 | ], 776 | "spellcasting": { 777 | 778 | }, 779 | "url": "http://www.dnd5eapi.co/api/classes/6" 780 | }, 781 | { 782 | "index": 7, 783 | "name": "Paladin", 784 | "hit_die": 10, 785 | "proficiency_choices": [ 786 | { 787 | "choose": 2, 788 | "type": "proficiencies", 789 | "from": [ 790 | { 791 | "url": "http://www.dnd5eapi.co/api/proficiencies/108", 792 | "name": "Skill: Athletics" 793 | }, 794 | { 795 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 796 | "name": "Skill: Insight" 797 | }, 798 | { 799 | "url": "http://www.dnd5eapi.co/api/proficiencies/112", 800 | "name": "Skill: Intimidation" 801 | }, 802 | { 803 | "url": "http://www.dnd5eapi.co/api/proficiencies/114", 804 | "name": "Skill: Medicine" 805 | }, 806 | { 807 | "url": "http://www.dnd5eapi.co/api/proficiencies/118", 808 | "name": "Skill: Persuasion" 809 | }, 810 | { 811 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 812 | "name": "Skill: Religion" 813 | } 814 | ] 815 | } 816 | ], 817 | "proficiencies": [ 818 | { 819 | "name": "All armor", 820 | "url": "http://www.dnd5eapi.co/api/proficiencies/4" 821 | }, 822 | { 823 | "name": "Shields", 824 | "url": "http://www.dnd5eapi.co/api/proficiencies/18" 825 | }, 826 | { 827 | "name": "Simple weapons", 828 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 829 | }, 830 | { 831 | "name": "Martial weapons", 832 | "url": "http://www.dnd5eapi.co/api/proficiencies/20" 833 | } 834 | ], 835 | "saving_throws": [ 836 | { 837 | "name": "WIS", 838 | "url": "http://www.dnd5eapi.co/api/ability-scores/5" 839 | }, 840 | { 841 | "name": "CHA", 842 | "url": "http://www.dnd5eapi.co/api/ability-scores/6" 843 | } 844 | ], 845 | "starting_equipment": { 846 | "url": "http://www.dnd5eapi.co/api/startingequipment/7", 847 | "class": "Paladin" 848 | }, 849 | "class_levels": { 850 | "url": "http://www.dnd5eapi.co/api/classes/paladin/levels", 851 | "class": "Paladin" 852 | }, 853 | "subclasses": [ 854 | { 855 | "url": "http://www.dnd5eapi.co/api/subclasses/7", 856 | "name": "Devotion" 857 | } 858 | ], 859 | "spellcasting": { 860 | "url": "http://www.dnd5eapi.co/api/spellcasting/4", 861 | "class": "Paladin" 862 | }, 863 | "url": "http://www.dnd5eapi.co/api/classes/7" 864 | }, 865 | { 866 | "index": 8, 867 | "name": "Ranger", 868 | "hit_die": 10, 869 | "proficiency_choices": [ 870 | { 871 | "choose": 3, 872 | "type": "proficiencies", 873 | "from": [ 874 | { 875 | "url": "http://www.dnd5eapi.co/api/proficiencies/106", 876 | "name": "Skill: Animal Handling" 877 | }, 878 | { 879 | "url": "http://www.dnd5eapi.co/api/proficiencies/108", 880 | "name": "Skill: Athletics" 881 | }, 882 | { 883 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 884 | "name": "Skill: Insight" 885 | }, 886 | { 887 | "url": "http://www.dnd5eapi.co/api/proficiencies/113", 888 | "name": "Skill: Investigation" 889 | }, 890 | { 891 | "url": "http://www.dnd5eapi.co/api/proficiencies/115", 892 | "name": "Skill: Nature" 893 | }, 894 | { 895 | "url": "http://www.dnd5eapi.co/api/proficiencies/116", 896 | "name": "Skill: Perception" 897 | }, 898 | { 899 | "url": "http://www.dnd5eapi.co/api/proficiencies/121", 900 | "name": "Skill: Stealth" 901 | }, 902 | { 903 | "url": "http://www.dnd5eapi.co/api/proficiencies/122", 904 | "name": "Skill: Survival" 905 | } 906 | ] 907 | } 908 | ], 909 | "proficiencies": [ 910 | { 911 | "name": "Light armor", 912 | "url": "http://www.dnd5eapi.co/api/proficiencies/1" 913 | }, 914 | { 915 | "name": "Medium armor", 916 | "url": "http://www.dnd5eapi.co/api/proficiencies/2" 917 | }, 918 | { 919 | "name": "Shields", 920 | "url": "http://www.dnd5eapi.co/api/proficiencies/18" 921 | }, 922 | { 923 | "name": "Simple weapons", 924 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 925 | }, 926 | { 927 | "name": "Martial weapons", 928 | "url": "http://www.dnd5eapi.co/api/proficiencies/20" 929 | } 930 | ], 931 | "saving_throws": [ 932 | { 933 | "name": "STR", 934 | "url": "http://www.dnd5eapi.co/api/ability-scores/1" 935 | }, 936 | { 937 | "name": "DEX", 938 | "url": "http://www.dnd5eapi.co/api/ability-scores/2" 939 | } 940 | ], 941 | "starting_equipment": { 942 | "url": "http://www.dnd5eapi.co/api/startingequipment/8", 943 | "class": "Ranger" 944 | }, 945 | "class_levels": { 946 | "url": "http://www.dnd5eapi.co/api/classes/ranger/levels", 947 | "class": "Ranger" 948 | }, 949 | "subclasses": [ 950 | { 951 | "url": "http://www.dnd5eapi.co/api/subclasses/8", 952 | "name": "Hunter" 953 | } 954 | ], 955 | "spellcasting": { 956 | "url": "http://www.dnd5eapi.co/api/spellcasting/5", 957 | "class": "Ranger" 958 | }, 959 | "url": "http://www.dnd5eapi.co/api/classes/8" 960 | }, 961 | { 962 | "index": 9, 963 | "name": "Rogue", 964 | "hit_die": 8, 965 | "proficiency_choices": [ 966 | { 967 | "choose": 4, 968 | "type": "proficiencies", 969 | "from": [ 970 | { 971 | "url": "http://www.dnd5eapi.co/api/proficiencies/105", 972 | "name": "Skill: Acrobatics" 973 | }, 974 | { 975 | "url": "http://www.dnd5eapi.co/api/proficiencies/108", 976 | "name": "Skill: Athletics" 977 | }, 978 | { 979 | "url": "http://www.dnd5eapi.co/api/proficiencies/109", 980 | "name": "Skill: Deception" 981 | }, 982 | { 983 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 984 | "name": "Skill: Insight" 985 | }, 986 | { 987 | "url": "http://www.dnd5eapi.co/api/proficiencies/112", 988 | "name": "Skill: Intimidation" 989 | }, 990 | { 991 | "url": "http://www.dnd5eapi.co/api/proficiencies/113", 992 | "name": "Skill: Investigation" 993 | }, 994 | { 995 | "url": "http://www.dnd5eapi.co/api/proficiencies/116", 996 | "name": "Skill: Perception" 997 | }, 998 | { 999 | "url": "http://www.dnd5eapi.co/api/proficiencies/117", 1000 | "name": "Skill: Performance" 1001 | }, 1002 | { 1003 | "url": "http://www.dnd5eapi.co/api/proficiencies/118", 1004 | "name": "Skill: Persuasion" 1005 | }, 1006 | { 1007 | "url": "http://www.dnd5eapi.co/api/proficiencies/120", 1008 | "name": "Skill: Sleight of Hand" 1009 | }, 1010 | { 1011 | "url": "http://www.dnd5eapi.co/api/proficiencies/121", 1012 | "name": "Skill: Stealth" 1013 | } 1014 | ] 1015 | } 1016 | ], 1017 | "proficiencies": [ 1018 | { 1019 | "name": "Light armor", 1020 | "url": "http://www.dnd5eapi.co/api/proficiencies/1" 1021 | }, 1022 | { 1023 | "name": "Simple weapons", 1024 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 1025 | }, 1026 | { 1027 | "name": "Longswords", 1028 | "url": "http://www.dnd5eapi.co/api/proficiencies/42" 1029 | }, 1030 | { 1031 | "name": "Rapiers", 1032 | "url": "http://www.dnd5eapi.co/api/proficiencies/46" 1033 | }, 1034 | { 1035 | "name": "Shortswords", 1036 | "url": "http://www.dnd5eapi.co/api/proficiencies/48" 1037 | }, 1038 | { 1039 | "name": "Crossbows, hand", 1040 | "url": "http://www.dnd5eapi.co/api/proficiencies/54" 1041 | }, 1042 | { 1043 | "name": "Thieves' Tools", 1044 | "url": "http://www.dnd5eapi.co/api/proficiencies/96" 1045 | } 1046 | ], 1047 | "saving_throws": [ 1048 | { 1049 | "name": "DEX", 1050 | "url": "http://www.dnd5eapi.co/api/ability-scores/2" 1051 | }, 1052 | { 1053 | "name": "INT", 1054 | "url": "http://www.dnd5eapi.co/api/ability-scores/4" 1055 | } 1056 | ], 1057 | "starting_equipment": { 1058 | "url": "http://www.dnd5eapi.co/api/startingequipment/9", 1059 | "class": "Rogue" 1060 | }, 1061 | "class_levels": { 1062 | "url": "http://www.dnd5eapi.co/api/classes/rogue/levels", 1063 | "class": "Rogue" 1064 | }, 1065 | "subclasses": [ 1066 | { 1067 | "url": "http://www.dnd5eapi.co/api/subclasses/9", 1068 | "name": "Thief" 1069 | } 1070 | ], 1071 | "spellcasting": { 1072 | 1073 | }, 1074 | "url": "http://www.dnd5eapi.co/api/classes/9" 1075 | }, 1076 | { 1077 | "index": 10, 1078 | "name": "Sorcerer", 1079 | "hit_die": 6, 1080 | "proficiency_choices": [ 1081 | { 1082 | "choose": 2, 1083 | "type": "proficiencies", 1084 | "from": [ 1085 | { 1086 | "url": "http://www.dnd5eapi.co/api/proficiencies/107", 1087 | "name": "Skill: Arcana" 1088 | }, 1089 | { 1090 | "url": "http://www.dnd5eapi.co/api/proficiencies/109", 1091 | "name": "Skill: Deception" 1092 | }, 1093 | { 1094 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 1095 | "name": "Skill: Insight" 1096 | }, 1097 | { 1098 | "url": "http://www.dnd5eapi.co/api/proficiencies/112", 1099 | "name": "Skill: Intimidation" 1100 | }, 1101 | { 1102 | "url": "http://www.dnd5eapi.co/api/proficiencies/118", 1103 | "name": "Skill: Persuasion" 1104 | }, 1105 | { 1106 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 1107 | "name": "Skill: Religion" 1108 | } 1109 | ] 1110 | } 1111 | ], 1112 | "proficiencies": [ 1113 | { 1114 | "name": "Daggers", 1115 | "url": "http://www.dnd5eapi.co/api/proficiencies/22" 1116 | }, 1117 | { 1118 | "name": "Quarterstaffs", 1119 | "url": "http://www.dnd5eapi.co/api/proficiencies/28" 1120 | }, 1121 | { 1122 | "name": "Darts", 1123 | "url": "http://www.dnd5eapi.co/api/proficiencies/32" 1124 | }, 1125 | { 1126 | "name": "Slings", 1127 | "url": "http://www.dnd5eapi.co/api/proficiencies/34" 1128 | } 1129 | ], 1130 | "saving_throws": [ 1131 | { 1132 | "name": "CON", 1133 | "url": "http://www.dnd5eapi.co/api/ability-scores/3" 1134 | }, 1135 | { 1136 | "name": "CHA", 1137 | "url": "http://www.dnd5eapi.co/api/ability-scores/6" 1138 | } 1139 | ], 1140 | "starting_equipment": { 1141 | "url": "http://www.dnd5eapi.co/api/startingequipment/10", 1142 | "class": "Sorcerer" 1143 | }, 1144 | "class_levels": { 1145 | "url": "http://www.dnd5eapi.co/api/classes/sorcerer/levels", 1146 | "class": "Sorcerer" 1147 | }, 1148 | "subclasses": [ 1149 | { 1150 | "url": "http://www.dnd5eapi.co/api/subclasses/10", 1151 | "name": "Draconic" 1152 | } 1153 | ], 1154 | "spellcasting": { 1155 | "url": "http://www.dnd5eapi.co/api/spellcasting/6", 1156 | "class": "Sorcerer" 1157 | }, 1158 | "url": "http://www.dnd5eapi.co/api/classes/10" 1159 | }, 1160 | { 1161 | "index": 11, 1162 | "name": "Warlock", 1163 | "hit_die": 8, 1164 | "proficiency_choices": [ 1165 | { 1166 | "choose": 2, 1167 | "type": "proficiencies", 1168 | "from": [ 1169 | { 1170 | "url": "http://www.dnd5eapi.co/api/proficiencies/107", 1171 | "name": "Skill: Arcana" 1172 | }, 1173 | { 1174 | "url": "http://www.dnd5eapi.co/api/proficiencies/109", 1175 | "name": "Skill: Deception" 1176 | }, 1177 | { 1178 | "url": "http://www.dnd5eapi.co/api/proficiencies/110", 1179 | "name": "Skill: History" 1180 | }, 1181 | { 1182 | "url": "http://www.dnd5eapi.co/api/proficiencies/112", 1183 | "name": "Skill: Intimidation" 1184 | }, 1185 | { 1186 | "url": "http://www.dnd5eapi.co/api/proficiencies/113", 1187 | "name": "Skill: Investigation" 1188 | }, 1189 | { 1190 | "url": "http://www.dnd5eapi.co/api/proficiencies/115", 1191 | "name": "Skill: Nature" 1192 | }, 1193 | { 1194 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 1195 | "name": "Skill: Religion" 1196 | } 1197 | ] 1198 | } 1199 | ], 1200 | "proficiencies": [ 1201 | { 1202 | "name": "Light armor", 1203 | "url": "http://www.dnd5eapi.co/api/proficiencies/1" 1204 | }, 1205 | { 1206 | "name": "Simple weapons", 1207 | "url": "http://www.dnd5eapi.co/api/proficiencies/19" 1208 | } 1209 | ], 1210 | "saving_throws": [ 1211 | { 1212 | "name": "WIS", 1213 | "url": "http://www.dnd5eapi.co/api/ability-scores/5" 1214 | }, 1215 | { 1216 | "name": "CHA", 1217 | "url": "http://www.dnd5eapi.co/api/ability-scores/6" 1218 | } 1219 | ], 1220 | "starting_equipment": { 1221 | "url": "http://www.dnd5eapi.co/api/startingequipment/11", 1222 | "class": "Warlock" 1223 | }, 1224 | "class_levels": { 1225 | "url": "http://www.dnd5eapi.co/api/classes/warlock/levels", 1226 | "class": "Warlock" 1227 | }, 1228 | "subclasses": [ 1229 | { 1230 | "url": "http://www.dnd5eapi.co/api/subclasses/11", 1231 | "name": "Fiend" 1232 | } 1233 | ], 1234 | "spellcasting": { 1235 | "url": "http://www.dnd5eapi.co/api/spellcasting/7", 1236 | "class": "Warlock" 1237 | }, 1238 | "url": "http://www.dnd5eapi.co/api/classes/11" 1239 | }, 1240 | { 1241 | "index": 12, 1242 | "name": "Wizard", 1243 | "hit_die": 6, 1244 | "proficiency_choices": [ 1245 | { 1246 | "choose": 2, 1247 | "type": "proficiencies", 1248 | "from": [ 1249 | { 1250 | "url": "http://www.dnd5eapi.co/api/proficiencies/107", 1251 | "name": "Skill: Arcana" 1252 | }, 1253 | { 1254 | "url": "http://www.dnd5eapi.co/api/proficiencies/110", 1255 | "name": "Skill: History" 1256 | }, 1257 | { 1258 | "url": "http://www.dnd5eapi.co/api/proficiencies/111", 1259 | "name": "Skill: Insight" 1260 | }, 1261 | { 1262 | "url": "http://www.dnd5eapi.co/api/proficiencies/113", 1263 | "name": "Skill: Investigation" 1264 | }, 1265 | { 1266 | "url": "http://www.dnd5eapi.co/api/proficiencies/114", 1267 | "name": "Skill: Medicine" 1268 | }, 1269 | { 1270 | "url": "http://www.dnd5eapi.co/api/proficiencies/119", 1271 | "name": "Skill: Religion" 1272 | } 1273 | ] 1274 | } 1275 | ], 1276 | "proficiencies": [ 1277 | { 1278 | "name": "Daggers", 1279 | "url": "http://www.dnd5eapi.co/api/proficiencies/22" 1280 | }, 1281 | { 1282 | "name": "Quarterstaffs", 1283 | "url": "http://www.dnd5eapi.co/api/proficiencies/28" 1284 | }, 1285 | { 1286 | "name": "Darts", 1287 | "url": "http://www.dnd5eapi.co/api/proficiencies/32" 1288 | }, 1289 | { 1290 | "name": "Slings", 1291 | "url": "http://www.dnd5eapi.co/api/proficiencies/34" 1292 | } 1293 | ], 1294 | "saving_throws": [ 1295 | { 1296 | "name": "INT", 1297 | "url": "http://www.dnd5eapi.co/api/ability-scores/4" 1298 | }, 1299 | { 1300 | "name": "WIS", 1301 | "url": "http://www.dnd5eapi.co/api/ability-scores/5" 1302 | } 1303 | ], 1304 | "starting_equipment": { 1305 | "url": "http://www.dnd5eapi.co/api/startingequipment/12", 1306 | "class": "Wizard" 1307 | }, 1308 | "class_levels": { 1309 | "url": "http://www.dnd5eapi.co/api/classes/wizard/levels", 1310 | "class": "Wizard" 1311 | }, 1312 | "subclasses": [ 1313 | { 1314 | "url": "http://www.dnd5eapi.co/api/subclasses/12", 1315 | "name": "Evocation" 1316 | } 1317 | ], 1318 | "spellcasting": { 1319 | "url": "http://www.dnd5eapi.co/api/spellcasting/8", 1320 | "class": "Wizard" 1321 | }, 1322 | "url": "http://www.dnd5eapi.co/api/classes/12" 1323 | } 1324 | ] 1325 | -------------------------------------------------------------------------------- /json/quotes.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "index": 1, 4 | "quote": "'Oh come on man,' said Dave. 'That’s seriously not cool. You’re supposed to ride those, not use them as meat shields.'", 5 | "source": "Critical Failures" 6 | 7 | }, 8 | { 9 | "index": 2, 10 | "quote": "Then five or six more residual traps fired off at greater intervals. And then nothing. 'Dude,' said Dave. 'What have you got against horses?' 'It had to be done.' 'And that,'said Tim, 'is how you disarm a room full of traps.'", 11 | "source": "Critical Failures" 12 | 13 | }, 14 | { 15 | "index": 3, 16 | "quote": "Can the fairies sense I'm pissed off?", 17 | "source": "Unknown Player" 18 | 19 | }, 20 | { 21 | "index": 4, 22 | "quote": "I mean, I guess you can throw the Wererat at him.", 23 | "source": "Unknown Frustrated GM" 24 | 25 | }, 26 | 27 | { 28 | "index": 5, 29 | "quote": "When in doubt, if something goes wrong, just... nudity. It usually works.", 30 | "source": "Molly, M9, Critical Role" 31 | 32 | }, 33 | 34 | { 35 | "index": 6, 36 | "quote": "Sleep well with your bad decisions.", 37 | "source": "Caduceus, M9, Critical Role" 38 | 39 | } 40 | ] 41 | -------------------------------------------------------------------------------- /json/race.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "index": 1, 4 | "name": "Dwarf", 5 | "speed": 30, 6 | "ability_bonuses": [ 7 | { 8 | "name": "CON", 9 | "url": "http://www.dnd5eapi.co/api/ability-scores/3", 10 | "bonus": 2 11 | } 12 | ], 13 | "ability_bonus_options": {}, 14 | "alignment": "Most dwarves are lawful, believing firmly in the benefits of a well-ordered society. They tend toward good as well, with a strong sense of fair play and a belief that everyone deserves to share in the benefits of a just order.", 15 | "age": "Dwarves mature at the same rate as humans, but they're considered young until they reach the age of 50. On average, they live about 350 years.", 16 | "size": "Medium", 17 | "size_description": "Dwarves stand between 4 and 5 feet tall and average about 150 pounds. Your size is Medium.", 18 | "starting_proficiencies": [ 19 | { 20 | "url": "http://www.dnd5eapi.co/api/proficiencies/20", 21 | "name": "Battleaxes" 22 | }, 23 | { 24 | "url": "http://www.dnd5eapi.co/api/proficiencies/24", 25 | "name": "Handaxes" 26 | }, 27 | { 28 | "url": "http://www.dnd5eapi.co/api/proficiencies/26", 29 | "name": "Light hammers" 30 | }, 31 | { 32 | "url": "http://www.dnd5eapi.co/api/proficiencies/51", 33 | "name": "Warhammers" 34 | } 35 | ], 36 | "starting_proficiency_options": { 37 | "choose": 1, 38 | "type": "proficiencies", 39 | "from": [ 40 | { 41 | "url": "http://www.dnd5eapi.co/api/proficiencies/71", 42 | "name": "Smith's tools" 43 | }, 44 | { 45 | "url": "http://www.dnd5eapi.co/api/proficiencies/59", 46 | "name": "Brewer's supplies" 47 | }, 48 | { 49 | "url": "http://www.dnd5eapi.co/api/proficiencies/68", 50 | "name": "Mason's tools" 51 | } 52 | ] 53 | }, 54 | "languages": [ 55 | { 56 | "url": "http://www.dnd5eapi.co/api/languages/1", 57 | "name": "Common" 58 | }, 59 | { 60 | "url": "http://www.dnd5eapi.co/api/languages/2", 61 | "name": "Dwarvish" 62 | } 63 | ], 64 | "language_options": { 65 | 66 | }, 67 | "language_desc": "You can speak, read, and write Common and Dwarvish. Dwarvish is full of hard consonants and guttural sounds, and those characteristics spill over into whatever other language a dwarf might speak.", 68 | "traits": [ 69 | { 70 | "name": "Darkvision (Dwarf)", 71 | "url": "http://www.dnd5eapi.co/api/traits/1" 72 | }, 73 | { 74 | "name": "Dwarven Resilience", 75 | "url": "http://www.dnd5eapi.co/api/traits/2" 76 | }, 77 | { 78 | "name": "Stonecunning", 79 | "url": "http://www.dnd5eapi.co/api/traits/3" 80 | } 81 | ], 82 | "subraces": [ 83 | { 84 | "url": "http://www.dnd5eapi.co/api/subraces/1", 85 | "name": "Hill Dwarf" 86 | } 87 | ], 88 | "url": "http://www.dnd5eapi.co/api/races/1" 89 | }, 90 | { 91 | "index": 2, 92 | "name": "Elf", 93 | "speed": 30, 94 | "ability_bonuses": [ 95 | { 96 | "name": "DEX", 97 | "url": "http://www.dnd5eapi.co/api/ability-scores/2", 98 | "bonus": 2 99 | } 100 | ], 101 | "ability_bonus_options": {}, 102 | "age": "Although elves reach physical maturity at about the same age as humans, the elven understanding of adulthood goes beyond physical growth to encompass worldly experience. An elf typically claims adulthood and an adult name around the age of 100 and can live to be 750 years old.", 103 | "alignment": "Elves love freedom, variety, and self-expression, so they lean strongly toward the gentler aspects of chaos. They value and protect others' freedom as well as their own, and they are more often good than not. The drow are an exception; their exile has made them vicious and dangerous. Drow are more often evil than not.", 104 | "size": "Medium", 105 | "size_description": "Elves range from under 5 to over 6 feet tall and have slender builds. Your size is Medium.", 106 | "starting_proficiencies": [ 107 | { 108 | "url": "http://www.dnd5eapi.co/api/proficiencies/116", 109 | "name": "Skill: Perception" 110 | } 111 | ], 112 | "starting_proficiency_options": {}, 113 | "languages": [ 114 | { 115 | "url": "http://www.dnd5eapi.co/api/languages/1", 116 | "name": "Common" 117 | }, 118 | { 119 | "url": "http://www.dnd5eapi.co/api/languages/3", 120 | "name": "Elvish" 121 | } 122 | ], 123 | "language_options": { 124 | 125 | }, 126 | "language_desc": "You can speak, read, and write Common and Elvish. Elvish is fluid, with subtle intonations and intricate grammar. Elven literature is rich and varied, and their songs and poems are famous among other races. Many bards learn their language so they can add Elvish ballads to their repertoires.", 127 | "traits": [ 128 | { 129 | "name": "Darkvision (Elf)", 130 | "url": "http://www.dnd5eapi.co/api/traits/5" 131 | }, 132 | { 133 | "name": "Fey Ancestry", 134 | "url": "http://www.dnd5eapi.co/api/traits/6" 135 | }, 136 | { 137 | "name": "Trance", 138 | "url": "http://www.dnd5eapi.co/api/traits/7" 139 | } 140 | ], 141 | "subraces": [ 142 | { 143 | "url": "http://www.dnd5eapi.co/api/subraces/2", 144 | "name": "High Elf" 145 | } 146 | ], 147 | "url": "http://www.dnd5eapi.co/api/races/2" 148 | }, 149 | { 150 | "index": 3, 151 | "name": "Halfling", 152 | "speed": 25, 153 | "ability_bonuses": [ 154 | { 155 | "name": "DEX", 156 | "url": "http://www.dnd5eapi.co/api/ability-scores/2", 157 | "bonus": 2 158 | } 159 | ], 160 | "ability_bonus_options": {}, 161 | "age": "A halfling reaches adulthood at the age of 20 and generally lives into the middle of his or her second century.", 162 | "alignment": "Most halflings are lawful good. As a rule, they are good-hearted and kind, hate to see others in pain, and have no tolerance for oppression. They are also very orderly and traditional, leaning heavily on the support of their community and the comfort of their old ways.", 163 | "size": "Small", 164 | "size_description": "Halflings average about 3 feet tall and weigh about 40 pounds. Your size is Small.", 165 | "starting_proficiencies": [], 166 | "starting_proficiency_options": {}, 167 | "languages": [ 168 | { 169 | "url": "http://www.dnd5eapi.co/api/languages/1", 170 | "name": "Common" 171 | }, 172 | { 173 | "url": "http://www.dnd5eapi.co/api/languages/7", 174 | "name": "Halfling" 175 | } 176 | ], 177 | "language_options": {}, 178 | "language_desc": "You can speak, read, and write Common and Halfling. The Halfling language isn't secret, but halflings are loath to share it with others. They write very little, so they don't have a rich body of literature. Their oral tradition, however, is very strong. Almost all halflings speak Common to converse with the people in whose lands they dwell or through which they are traveling.", 179 | "traits": [ 180 | { 181 | "name": "Brave", 182 | "url": "http://www.dnd5eapi.co/api/traits/21" 183 | }, 184 | { 185 | "name": "Halfling Nimbleness", 186 | "url": "http://www.dnd5eapi.co/api/traits/22" 187 | }, 188 | { 189 | "name": "Lucky", 190 | "url": "http://www.dnd5eapi.co/api/traits/23" 191 | } 192 | ], 193 | "subraces": [ 194 | { 195 | "url": "http://www.dnd5eapi.co/api/subraces/3", 196 | "name": "Lightfoot Halfling" 197 | } 198 | ], 199 | "url": "http://www.dnd5eapi.co/api/races/3" 200 | }, 201 | { 202 | "index": 4, 203 | "name": "Human", 204 | "speed": 30, 205 | "ability_bonuses": [ 206 | { 207 | "name": "STR", 208 | "url": "http://www.dnd5eapi.co/api/ability-scores/1", 209 | "bonus": 1 210 | }, 211 | { 212 | "name": "DEX", 213 | "url": "http://www.dnd5eapi.co/api/ability-scores/2", 214 | "bonus": 1 215 | }, 216 | { 217 | "name": "CON", 218 | "url": "http://www.dnd5eapi.co/api/ability-scores/3", 219 | "bonus": 1 220 | }, 221 | { 222 | "name": "INT", 223 | "url": "http://www.dnd5eapi.co/api/ability-scores/4", 224 | "bonus": 1 225 | }, 226 | { 227 | "name": "WIS", 228 | "url": "http://www.dnd5eapi.co/api/ability-scores/5", 229 | "bonus": 1 230 | }, 231 | { 232 | "name": "CHA", 233 | "url": "http://www.dnd5eapi.co/api/ability-scores/6", 234 | "bonus": 1 235 | } 236 | ], 237 | "ability_bonus_options": {}, 238 | "age": "Humans reach adulthood in their late teens and live less than a century.", 239 | "alignment": "Humans tend toward no particular alignment. The best and the worst are found among them.", 240 | "size": "Medium", 241 | "size_description": "Humans vary widely in height and build, from barely 5 feet to well over 6 feet tall. Regardless of your position in that range, your size is Medium.", 242 | "starting_proficiencies": [], 243 | "starting_proficiency_options": {}, 244 | "languages": [ 245 | { 246 | "url": "http://www.dnd5eapi.co/api/languages/1", 247 | "name": "Common" 248 | } 249 | ], 250 | "language_options": { 251 | "choose": 1, 252 | "type": "languages", 253 | "from": [ 254 | { 255 | "url": "http://www.dnd5eapi.co/api/languages/2", 256 | "name": "Dwarvish" 257 | }, 258 | { 259 | "url": "http://www.dnd5eapi.co/api/languages/3", 260 | "name": "Elvish" 261 | }, 262 | { 263 | "url": "http://www.dnd5eapi.co/api/languages/4", 264 | "name": "Giant" 265 | }, 266 | { 267 | "url": "http://www.dnd5eapi.co/api/languages/5", 268 | "name": "Gnomish" 269 | }, 270 | { 271 | "url": "http://www.dnd5eapi.co/api/languages/6", 272 | "name": "Goblin" 273 | }, 274 | { 275 | "url": "http://www.dnd5eapi.co/api/languages/7", 276 | "name": "Halfling" 277 | }, 278 | { 279 | "url": "http://www.dnd5eapi.co/api/languages/8", 280 | "name": "Orc" 281 | }, 282 | { 283 | "url": "http://www.dnd5eapi.co/api/languages/9", 284 | "name": "Abyssal" 285 | }, 286 | { 287 | "url": "http://www.dnd5eapi.co/api/languages/10", 288 | "name": "Celestial" 289 | }, 290 | { 291 | "url": "http://www.dnd5eapi.co/api/languages/11", 292 | "name": "Draconic" 293 | }, 294 | { 295 | "url": "http://www.dnd5eapi.co/api/languages/12", 296 | "name": "Deep Speech" 297 | }, 298 | { 299 | "url": "http://www.dnd5eapi.co/api/languages/13", 300 | "name": "Infernal" 301 | }, 302 | { 303 | "url": "http://www.dnd5eapi.co/api/languages/14", 304 | "name": "Primordial" 305 | }, 306 | { 307 | "url": "http://www.dnd5eapi.co/api/languages/15", 308 | "name": "Sylvan" 309 | }, 310 | { 311 | "url": "http://www.dnd5eapi.co/api/languages/16", 312 | "name": "Undercommon" 313 | } 314 | ] 315 | }, 316 | "language_desc": "You can speak, read, and write Common and one extra language of your choice. Humans typically learn the languages of other peoples they deal with, including obscure dialects. They are fond of sprinkling their speech with words borrowed from other tongues: Orc curses, Elvish musical expressions, Dwarvish military phrases, and so on.", 317 | "traits": [], 318 | "subraces": [], 319 | "url": "http://www.dnd5eapi.co/api/races/4" 320 | }, 321 | { 322 | "index": 5, 323 | "name": "Dragonborn", 324 | "speed": 30, 325 | "ability_bonuses": [ 326 | { 327 | "name": "STR", 328 | "url": "http://www.dnd5eapi.co/api/ability-scores/1", 329 | "bonus": 2 330 | }, 331 | { 332 | "name": "CHA", 333 | "url": "http://www.dnd5eapi.co/api/ability-scores/6", 334 | "bonus": 1 335 | } 336 | ], 337 | "ability_bonus_options": {}, 338 | "alignment": " Dragonborn tend to extremes, making a conscious choice for one side or the other in the cosmic war between good and evil. Most dragonborn are good, but those who side with evil can be terrible villains.", 339 | "age": "Young dragonborn grow quickly. They walk hours after hatching, attain the size and development of a 10-year-old human child by the age of 3, and reach adulthood by 15. They live to be around 80.", 340 | "size": "Medium", 341 | "size_description": "Dragonborn are taller and heavier than humans, standing well over 6 feet tall and averaging almost 250 pounds. Your size is Medium.", 342 | "starting_proficiencies": [], 343 | "starting_proficiency_options": {}, 344 | "languages": [ 345 | { 346 | "url": "http://www.dnd5eapi.co/api/languages/1", 347 | "name": "Common" 348 | }, 349 | { 350 | "url": "http://www.dnd5eapi.co/api/languages/11", 351 | "name": "Draconic" 352 | } 353 | ], 354 | "language_options": { 355 | 356 | }, 357 | "language_desc": "You can speak, read, and write Common and Draconic. Draconic is thought to be one of the oldest languages and is often used in the study of magic. The language sounds harsh to most other creatures and includes numerous hard consonants and sibilants.", 358 | "traits": [ 359 | { 360 | "name": "Draconic Ancestry", 361 | "url": "http://www.dnd5eapi.co/api/traits/24" 362 | }, 363 | { 364 | "name": "Breath Weapon", 365 | "url": "http://www.dnd5eapi.co/api/traits/25" 366 | }, 367 | { 368 | "name": "Damage Resistance (Dragonborn)", 369 | "url": "http://www.dnd5eapi.co/api/traits/18" 370 | } 371 | 372 | ], 373 | "trait_options": 374 | { 375 | "choose": 1, 376 | "from": [ 377 | { 378 | "name": "Breath Weapon (Black)", 379 | "url": "http://www.dnd5eapi.co/api/traits/26" 380 | }, 381 | { 382 | "name": "Breath Weapon (Blue)", 383 | "url": "http://www.dnd5eapi.co/api/traits/27" 384 | }, 385 | { 386 | "name": "Breath Weapon (Brass)", 387 | "url": "http://www.dnd5eapi.co/api/traits/28" 388 | }, 389 | { 390 | "name": "Breath Weapon (Bronze)", 391 | "url": "http://www.dnd5eapi.co/api/traits/29" 392 | }, 393 | { 394 | "name": "Breath Weapon (Copper)", 395 | "url": "http://www.dnd5eapi.co/api/traits/30" 396 | }, 397 | { 398 | "name": "Breath Weapon (Gold)", 399 | "url": "http://www.dnd5eapi.co/api/traits/31" 400 | }, 401 | { 402 | "name": "Breath Weapon (Green)", 403 | "url": "http://www.dnd5eapi.co/api/traits/32" 404 | }, 405 | { 406 | "name": "Breath Weapon (Red)", 407 | "url": "http://www.dnd5eapi.co/api/traits/33" 408 | }, 409 | { 410 | "name": "Breath Weapon (Silver)", 411 | "url": "http://www.dnd5eapi.co/api/traits/34" 412 | }, 413 | { 414 | "name": "Breath Weapon (White)", 415 | "url": "http://www.dnd5eapi.co/api/traits/35" 416 | } 417 | ], 418 | "type": "trait" 419 | }, 420 | "subraces": [], 421 | "url": "http://www.dnd5eapi.co/api/races/5" 422 | }, 423 | { 424 | "index": 6, 425 | "name": "Gnome", 426 | "speed": 25, 427 | "ability_bonuses": [ 428 | { 429 | "name": "INT", 430 | "url": "http://www.dnd5eapi.co/api/ability-scores/4", 431 | "bonus": 2 432 | } 433 | ], 434 | "ability_bonus_options": {}, 435 | "alignment": "Gnomes are most often good. Those who tend toward law are sages, engineers, researchers, scholars, investigators, or inventors. Those who tend toward chaos are minstrels, tricksters, wanderers, or fanciful jewelers. Gnomes are good-hearted, and even the tricksters among them are more playful than vicious.", 436 | "age": " Gnomes mature at the same rate humans do, and most are expected to settle down into an adult life by around age 40. They can live 350 to almost 500 years.", 437 | "size": "Small", 438 | "size_description": "Gnomes are between 3 and 4 feet tall and average about 40 pounds. Your size is Small.", 439 | "starting_proficiencies": [], 440 | "starting_proficiency_options": {}, 441 | "languages": [ 442 | { 443 | "url": "http://www.dnd5eapi.co/api/languages/1", 444 | "name": "Common" 445 | }, 446 | { 447 | "url": "http://www.dnd5eapi.co/api/languages/5", 448 | "name": "Gnomish" 449 | } 450 | ], 451 | "language_options": {}, 452 | "language_desc": "You can speak, read, and write Common and Gnomish. The Gnomish language, which uses the Dwarvish script, is renowned for its technical treatises and its catalogs of knowledge about the natural world.", 453 | "traits": [ 454 | { 455 | "name": "Darkvision", 456 | "url": "http://www.dnd5eapi.co/api/traits/1" 457 | }, 458 | { 459 | "name": "Gnome Cunning", 460 | "url": "http://www.dnd5eapi.co/api/traits/19" 461 | } 462 | ], 463 | "trait_options": {}, 464 | "subraces": [ 465 | { 466 | "url": "http://www.dnd5eapi.co/api/subraces/4", 467 | "name": "Rock Gnome" 468 | } 469 | ], 470 | "url": "http://www.dnd5eapi.co/api/races/6" 471 | }, 472 | { 473 | "index": 7, 474 | "name": "Half-Elf", 475 | "speed": 30, 476 | "ability_bonuses": [ 477 | { 478 | "name": "CHA", 479 | "url": "http://www.dnd5eapi.co/api/ability-scores/6", 480 | "bonus": 2 481 | } 482 | ], 483 | "ability_bonus_options": { 484 | "choose": 2, 485 | "type": "ability_bonuses", 486 | "from": [ 487 | { 488 | "name": "STR", 489 | "url": "http://www.dnd5eapi.co/api/ability-scores/1", 490 | "bonus": 1 491 | }, 492 | { 493 | "name": "DEX", 494 | "url": "http://www.dnd5eapi.co/api/ability-scores/2", 495 | "bonus": 1 496 | }, 497 | { 498 | "name": "CON", 499 | "url": "http://www.dnd5eapi.co/api/ability-scores/3", 500 | "bonus": 1 501 | }, 502 | { 503 | "name": "INT", 504 | "url": "http://www.dnd5eapi.co/api/ability-scores/4", 505 | "bonus": 1 506 | }, 507 | { 508 | "name": "WIS", 509 | "url": "http://www.dnd5eapi.co/api/ability-scores/5", 510 | "bonus": 1 511 | } 512 | ] 513 | }, 514 | "alignment": "Half-elves share the chaotic bent of their elven heritage. They value both personal freedom and creative expression, demonstrating neither love of leaders nor desire for followers. They chafe at rules, resent others' demands, and sometimes prove unreliable, or at least unpredictable.", 515 | "age": "Half-elves mature at the same rate humans do and reach adulthood around the age of 20. They live much longer than humans, however, often exceeding 180 years.", 516 | "size": "Medium", 517 | "size_description": "Half-elves are about the same size as humans, ranging from 5 to 6 feet tall. Your size is Medium.", 518 | "starting_proficiencies": [], 519 | "starting_proficiency_options": {}, 520 | "languages": [ 521 | { 522 | "name": "Common", 523 | "url": "http://www.dnd5eapi.co/api/languages/1" 524 | }, 525 | { 526 | "name": "Elvish", 527 | "url": "http://www.dnd5eapi.co/api/languages/3" 528 | } 529 | ], 530 | "language_options": { 531 | "choose": 1, 532 | "type": "languages", 533 | "from": [ 534 | { 535 | "name":"Dwarvish", 536 | "url":"http://www.dnd5eapi.co/api/languages/2" 537 | }, 538 | { 539 | "name":"Giant", 540 | "url":"http://www.dnd5eapi.co/api/languages/4" 541 | }, 542 | { 543 | "name":"Gnomish", 544 | "url":"http://www.dnd5eapi.co/api/languages/5" 545 | }, 546 | { 547 | "name":"Goblin", 548 | "url":"http://www.dnd5eapi.co/api/languages/6" 549 | }, 550 | { 551 | "name":"Halfling", 552 | "url":"http://www.dnd5eapi.co/api/languages/7" 553 | }, 554 | { 555 | "name":"Orc", 556 | "url":"http://www.dnd5eapi.co/api/languages/8" 557 | }, 558 | { 559 | "name":"Abyssal", 560 | "url":"http://www.dnd5eapi.co/api/languages/9" 561 | }, 562 | { 563 | "name":"Celestial", 564 | "url":"http://www.dnd5eapi.co/api/languages/10" 565 | }, 566 | { 567 | "name":"Draconic", 568 | "url":"http://www.dnd5eapi.co/api/languages/11" 569 | }, 570 | { 571 | "name":"Deep Speech", 572 | "url":"http://www.dnd5eapi.co/api/languages/12" 573 | }, 574 | { 575 | "name":"Infernal", 576 | "url":"http://www.dnd5eapi.co/api/languages/13" 577 | }, 578 | { 579 | "name":"Primordial", 580 | "url":"http://www.dnd5eapi.co/api/languages/14" 581 | }, 582 | { 583 | "name":"Sylvan", 584 | "url":"http://www.dnd5eapi.co/api/languages/15" 585 | }, 586 | { 587 | "name":"Undercommon", 588 | "url":"http://www.dnd5eapi.co/api/languages/16" 589 | } 590 | ] 591 | }, 592 | "language_desc": "You can speak, read, and write Common, Elvish, and one extra language of your choice.", 593 | "traits": [ 594 | { 595 | "name": "Darkvision (Half-Elf)", 596 | "url": "http://www.dnd5eapi.co/api/traits/48" 597 | }, 598 | { 599 | "name": "Fey Ancestry", 600 | "url": "http://www.dnd5eapi.co/api/traits/49" 601 | }, 602 | { 603 | "name": "Skill Versatility", 604 | "url": "http://www.dnd5eapi.co/api/traits/50" 605 | } 606 | 607 | ], 608 | "trait_options": {}, 609 | "subraces": [], 610 | "url": "http://www.dnd5eapi.co/api/races/7" 611 | }, 612 | { 613 | "index": 8, 614 | "name": "Half-Orc", 615 | "speed": 30, 616 | "ability_bonuses": [ 617 | { 618 | "name": "STR", 619 | "url": "http://www.dnd5eapi.co/api/ability-scores/1", 620 | "bonus": 2 621 | }, 622 | { 623 | "name": "CON", 624 | "url": "http://www.dnd5eapi.co/api/ability-scores/3", 625 | "bonus": 1 626 | } 627 | ], 628 | "ability_bonus_options": {}, 629 | "alignment": " Half-orcs inherit a tendency toward chaos from their orc parents and are not strongly inclined toward good. Half-orcs raised among orcs and willing to live out their lives among them are usually evil.", 630 | "age": "Half-orcs mature a little faster than humans, reaching adulthood around age 14. They age noticeably faster and rarely live longer than 75 years.", 631 | "size": "Medium", 632 | "size_description": "Half-orcs are somewhat larger and bulkier than humans, and they range from 5 to well over 6 feet tall. Your size is Medium.", 633 | "starting_proficiencies": [ 634 | { 635 | "name": "Skill: Intimidation", 636 | "url": "http://www.dnd5eapi.co/api/proficiencies/112" 637 | } 638 | ], 639 | "starting_proficiency_options": {}, 640 | "languages": [ 641 | { 642 | "url": "http://www.dnd5eapi.co/api/languages/1", 643 | "name": "Common" 644 | }, 645 | { 646 | "url": "http://www.dnd5eapi.co/api/languages/8", 647 | "name": "Orcish" 648 | } 649 | ], 650 | "language_options": {}, 651 | "language_desc": "You can speak, read, and write Common and Orc. Orc is a harsh, grating language with hard consonants. It has no script of its own but is written in the Dwarvish script.", 652 | "traits": [ 653 | { 654 | "name": "Darkvision (Half-Orc)", 655 | "url": "http://www.dnd5eapi.co/api/traits/51" 656 | }, 657 | { 658 | "name": "Savage Attacks", 659 | "url": "http://www.dnd5eapi.co/api/traits/52" 660 | }, 661 | { 662 | "name": "Restless Endurance", 663 | "url": "http://www.dnd5eapi.co/api/traits/53" 664 | } 665 | 666 | ], 667 | "trait_options": {}, 668 | "subraces": [], 669 | "url": "http://www.dnd5eapi.co/api/races/8" 670 | }, 671 | { 672 | "index": 9, 673 | "name": "Tiefling", 674 | "speed": 30, 675 | "ability_bonuses": [ 676 | { 677 | "name": "INT", 678 | "url": "http://www.dnd5eapi.co/api/ability-scores/4", 679 | "bonus": 1 680 | }, 681 | { 682 | "name": "CHA", 683 | "url": "http://www.dnd5eapi.co/api/ability-scores/6", 684 | "bonus": 2 685 | } 686 | ], 687 | "ability_bonus_options": {}, 688 | "alignment": "Tieflings might not have an innate tendency toward evil, but many of them end up there. Evil or not, an independent nature inclines many tieflings toward a chaotic alignment.", 689 | "age": "Tieflings mature at the same rate as humans but live a few years longer.", 690 | "size": "Medium", 691 | "size_description": "Tieflings are about the same size and build as humans. Your size is Medium.", 692 | "starting_proficiencies": [], 693 | "starting_proficiency_options": {}, 694 | "languages": [ 695 | { 696 | "url": "http://www.dnd5eapi.co/api/languages/1", 697 | "name": "Common" 698 | }, 699 | { 700 | "url": "http://www.dnd5eapi.co/api/languages/9", 701 | "name": "Infernal" 702 | } 703 | ], 704 | "language_options": {}, 705 | "language_desc": "You can speak, read, and write Common and Infernal.", 706 | "traits": [ 707 | { 708 | "name": "Darkvision (Tiefling)", 709 | "url": "http://www.dnd5eapi.co/api/traits/54" 710 | }, 711 | { 712 | "name": "Hellish Resistance", 713 | "url": "http://www.dnd5eapi.co/api/traits/55" 714 | }, 715 | { 716 | "name": "Infernal Legacy", 717 | "url": "http://www.dnd5eapi.co/api/traits/56" 718 | } 719 | ], 720 | "trait_options": {}, 721 | "subraces": [], 722 | "url": "http://www.dnd5eapi.co/api/races/9" 723 | } 724 | ] 725 | -------------------------------------------------------------------------------- /one.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdpunk/dndshell/4e438d7ce7f2951ed8b6b8e1429c9e5049321a75/one.gif -------------------------------------------------------------------------------- /shell/character/ability/ability.go: -------------------------------------------------------------------------------- 1 | package ability 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | h "github.com/mitchellh/go-homedir" 7 | "io/ioutil" 8 | "os" 9 | "strconv" 10 | ) 11 | 12 | var Home, _ = h.Dir() 13 | 14 | type AbilityScore struct { 15 | AbilityScores []AbilityScores `json:"Ability-Scores"` 16 | Desc []string `json:"desc"` 17 | FullName string `json:"full_name"` 18 | Index float64 `json:"index"` 19 | Name string `json:"name"` 20 | Skills []Skills `json:"skills"` 21 | URL string `json:"url"` 22 | } 23 | type Skills struct { 24 | Name string `json:"name"` 25 | URL string `json:"url"` 26 | } 27 | 28 | type AbilityScores struct { 29 | AbilityScores []AbilityScore 30 | } 31 | 32 | func (rc *AbilityScores) Load() { 33 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/ability.json") 34 | 35 | if err != nil { 36 | fmt.Println(err) 37 | } 38 | 39 | defer jsonFile.Close() 40 | 41 | byteValue, _ := ioutil.ReadAll(jsonFile) 42 | if err := json.Unmarshal(byteValue, &rc.AbilityScores); err != nil { 43 | fmt.Println(err) 44 | } 45 | //json.Unmarshal(byteValue, &ms) 46 | return 47 | } 48 | 49 | func (rc *AbilityScores) ById(id string) { 50 | 51 | n, _ := strconv.Atoi(id) 52 | fmt.Println(rc.AbilityScores[n]) //.Strength) 53 | return 54 | } 55 | 56 | func (rc *AbilityScores) List() { 57 | for i := range rc.AbilityScores { 58 | fmt.Print((rc.AbilityScores[i].Index - 1)) 59 | fmt.Println(" " + rc.AbilityScores[i].Name) 60 | } 61 | //fmt.Println(cl.AbilityScores) 62 | return 63 | 64 | } 65 | -------------------------------------------------------------------------------- /shell/character/attack/attack.go: -------------------------------------------------------------------------------- 1 | package attack 2 | 3 | import "../../dice" 4 | 5 | //import "fmt" 6 | 7 | //func main() { 8 | // fmt.Println("vim-go") 9 | //} 10 | 11 | type Attack struct { 12 | AttackBonus float64 `json:"attack_bonus"` 13 | DamageBonus int `json:"damage_bonus"` 14 | DamageDice string `json:"damage_dice"` 15 | Desc string `json:"desc"` 16 | Name string `json:"name"` 17 | } 18 | 19 | type Attacks struct { 20 | Attacks []Attack 21 | } 22 | 23 | func (a Attack) AttackRoll(ability int, prof int, other int) int { 24 | return dice.GetAmount("1d20") + ability + prof + other 25 | } 26 | -------------------------------------------------------------------------------- /shell/character/character.go: -------------------------------------------------------------------------------- 1 | package character 2 | 3 | import ( 4 | "bufio" 5 | "encoding/json" 6 | "fmt" 7 | "github.com/bsdpunk/dndshell/shell/character/ability" 8 | class "github.com/bsdpunk/dndshell/shell/character/class" 9 | "github.com/bsdpunk/dndshell/shell/character/levels" 10 | "github.com/bsdpunk/dndshell/shell/character/race" 11 | "github.com/bsdpunk/dndshell/shell/character/spells" 12 | "github.com/bsdpunk/dndshell/shell/commands" 13 | "github.com/bsdpunk/dndshell/shell/monsters" 14 | "github.com/gobs/readline" 15 | "os" 16 | "strconv" 17 | "strings" 18 | ) 19 | 20 | var Cl class.Classes 21 | var Rc race.Races 22 | var Ls levels.Levels 23 | var Sp spells.Spells 24 | var As ability.AbilityScores 25 | var Ms Monsters.Monsters 26 | var ClassSubs = commands.Commands{ 27 | { 28 | Name: "ClassById", 29 | ShortName: "cid", 30 | Usage: "Get Class By Id", 31 | Category: "Character", 32 | }, 33 | } 34 | var RaceSubs = commands.Commands{ 35 | { 36 | Name: "RaceById", 37 | ShortName: "rid", 38 | Usage: "Get Race By Id", 39 | Category: "Character", 40 | }, 41 | } 42 | var SpellSubs = commands.Commands{ 43 | { 44 | Name: "SpellsById", 45 | ShortName: "sid", 46 | Usage: "Get Spell By Id", 47 | Category: "Character", 48 | }, 49 | } 50 | 51 | var AbilitySubs = commands.Commands{ 52 | { 53 | Name: "AbilityById", 54 | ShortName: "aid", 55 | Usage: "Get Ability By Id", 56 | Category: "Character", 57 | }, 58 | } 59 | 60 | var MonsterSubs = commands.Commands{ 61 | 62 | { 63 | Name: "MonsterById", 64 | ShortName: "mid", 65 | Usage: "Get Monster By Id", 66 | Category: "", 67 | }, 68 | { 69 | Name: "MonsterByCR", 70 | ShortName: "mbc", 71 | Usage: "Get Monster By CR", 72 | Category: "", 73 | }, 74 | { 75 | Name: "MonsterByGuess", 76 | ShortName: "mbg", 77 | Usage: "Get Monster By Guess", 78 | Category: "", 79 | }, 80 | { 81 | Name: "MonsterByName", 82 | ShortName: "mbn", 83 | Usage: "Get Monster By Name", 84 | Category: "", 85 | }, 86 | { 87 | Name: "SBById", 88 | ShortName: "sbid", 89 | Usage: "Get Monster By Id", 90 | Category: "", 91 | }, 92 | } 93 | var LevelSubs = commands.Commands{ 94 | 95 | { 96 | Name: "LevelById", 97 | ShortName: "lid", 98 | Usage: "Get Level By Id", 99 | Category: "", 100 | }, 101 | } 102 | 103 | var levToP = map[int]int{ 104 | 1: 2, 105 | 2: 2, 106 | 3: 2, 107 | 4: 2, 108 | 5: 3, 109 | 6: 3, 110 | 7: 3, 111 | 8: 3, 112 | 9: 4, 113 | 10: 4, 114 | 11: 4, 115 | 12: 4, 116 | 13: 5, 117 | 14: 5, 118 | 15: 5, 119 | 16: 5, 120 | 17: 6, 121 | 18: 6, 122 | 19: 6, 123 | 20: 6, 124 | } 125 | 126 | type Character struct { 127 | //Player's Name 128 | PlayerName string 129 | //Character's Name 130 | CharacterName string 131 | //Class 132 | CharacterClass class.Class 133 | //Race 134 | CharacterRace race.Race 135 | // Ability Score Definitions and Relationships 136 | AbilityScores ability.AbilityScores 137 | //Scores 138 | CharacterScores []int 139 | //Modifiers 140 | CharacterModifiers []int 141 | //Actions 142 | Actions int 143 | BonusAction int 144 | //Level Prof Bonus Map 145 | Prof int 146 | //Health 147 | HitPoints int 148 | //Armor 149 | ArmorClass int 150 | //Initiative 151 | Initiative int 152 | //Level 153 | Level int 154 | } 155 | 156 | func Load() { 157 | Cl.Load() 158 | Rc.Load() 159 | Ms.Load() 160 | As.Load() 161 | Ls.Load() 162 | Sp.Load() 163 | } 164 | func (cr *Character) ChooseClass(id *string) { 165 | idt := *id 166 | n, _ := strconv.Atoi(idt) 167 | cr.CharacterClass = Cl.Classes[n] 168 | fmt.Println(Cl.Classes[n]) 169 | return 170 | } 171 | 172 | func (cr *Character) ChooseRace(id *string) { 173 | idt := *id 174 | n, _ := strconv.Atoi(idt) 175 | fmt.Println(id) 176 | fmt.Println(n) 177 | cr.CharacterRace = Rc.Races[n] 178 | fmt.Println(Rc.Races[n]) 179 | return 180 | } 181 | func (cr *Character) GetScores() { 182 | var scores []int 183 | var mods []int 184 | for i := range As.AbilityScores { 185 | fmt.Println("What is your " + As.AbilityScores[i].Name + " (R for Roll):") 186 | reader := bufio.NewReader(os.Stdin) 187 | score, _ := reader.ReadString('\n') 188 | score = strings.Replace(score, "\n", "", -1) 189 | n, _ := strconv.Atoi(score) 190 | if n == 12 || n == 13 { 191 | mods = append(mods, 1) 192 | } else if n == 8 || n == 9 { 193 | mods = append(mods, -1) 194 | } else { 195 | mods = append(mods, 0) 196 | } 197 | scores = append(scores, n) 198 | } 199 | cr.CharacterScores = scores 200 | cr.CharacterModifiers = mods 201 | 202 | return 203 | } 204 | func (cr *Character) GetNPCScores() { 205 | var scores []string 206 | var mods []int 207 | for i := range As.AbilityScores { 208 | fmt.Println("What is your " + As.AbilityScores[i].Name + " (B for Beefy, A for Average, W for Weak):") 209 | reader := bufio.NewReader(os.Stdin) 210 | score, _ := reader.ReadString('\n') 211 | score = strings.Replace(score, "\n", "", -1) 212 | //n, _ := strconv.Atoi(score) 213 | if score == "b" || score == "B" { 214 | mods = append(mods, 3) 215 | } else if score == "a" || score == "A" { 216 | mods = append(mods, 0) 217 | } else { 218 | mods = append(mods, -1) 219 | } 220 | scores = append(scores, score) 221 | } 222 | //cr.CharacterScores = scores 223 | cr.CharacterModifiers = mods 224 | 225 | return 226 | } 227 | 228 | func InteractiveCreateCharacter() { 229 | c := Character{} 230 | reader := bufio.NewReader(os.Stdin) 231 | //fmt.Println(urlStr) 232 | fmt.Print("Name$ ") 233 | Name, _ := reader.ReadString('\n') 234 | Name = strings.Replace(Name, "\n", "", -1) 235 | c.PlayerName = Name 236 | promptN := "Character Name: " 237 | readN := readline.ReadLine(&promptN) 238 | cn := *readN 239 | c.CharacterName = cn 240 | //fmt.Println(c) 241 | Rc.List() 242 | promptR := "Choose Race: " 243 | readR := readline.ReadLine(&promptR) 244 | 245 | c.ChooseRace(readR) 246 | Cl.List() 247 | promptC := "Choose Class: " 248 | readC := readline.ReadLine(&promptC) 249 | c.ChooseClass(readC) 250 | 251 | promptL := "What Level: " 252 | readL := readline.ReadLine(&promptL) 253 | c.Level, _ = strconv.Atoi(*readL) 254 | c.Prof = levToP[c.Level] 255 | c.GetScores() 256 | 257 | e, err := json.Marshal(&c) 258 | if err != nil { 259 | fmt.Println(err) 260 | return 261 | } 262 | fmt.Println(string(e)) 263 | return 264 | 265 | } 266 | 267 | func InteractiveCreateNPC() { 268 | c := Character{} 269 | reader := bufio.NewReader(os.Stdin) 270 | //fmt.Println(urlStr) 271 | fmt.Print("Name: ") 272 | Name, _ := reader.ReadString('\n') 273 | Name = strings.Replace(Name, "\n", "", -1) 274 | c.PlayerName = Name 275 | promptN := "Character Name: " 276 | readN := readline.ReadLine(&promptN) 277 | cn := *readN 278 | c.CharacterName = cn 279 | //fmt.Println(c) 280 | Rc.List() 281 | promptR := "Choose Race: " 282 | readR := readline.ReadLine(&promptR) 283 | 284 | c.ChooseRace(readR) 285 | Cl.List() 286 | promptC := "Choose Class: " 287 | readC := readline.ReadLine(&promptC) 288 | c.ChooseClass(readC) 289 | 290 | promptL := "What Level: " 291 | readL := readline.ReadLine(&promptL) 292 | c.Level, _ = strconv.Atoi(*readL) 293 | c.Prof = levToP[c.Level] 294 | c.GetNPCScores() 295 | 296 | e, err := json.Marshal(&c) 297 | if err != nil { 298 | fmt.Println(err) 299 | return 300 | } 301 | fmt.Println(string(e)) 302 | return 303 | 304 | } 305 | -------------------------------------------------------------------------------- /shell/character/class/class.go: -------------------------------------------------------------------------------- 1 | package class 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | h "github.com/mitchellh/go-homedir" 7 | "io/ioutil" 8 | "os" 9 | "strconv" 10 | ) 11 | 12 | var Home, _ = h.Dir() 13 | 14 | type Class struct { 15 | ClassLevels ClassLevels `json:"class_levels"` 16 | HitDie float64 `json:"hit_die"` 17 | ID string `json:"_id"` 18 | Index float64 `json:"index"` 19 | Name string `json:"name"` 20 | Proficiencies []Proficiencies `json:"proficiencies"` 21 | ProficiencyChoices []ProficiencyChoices `json:"proficiency_choices"` 22 | SavingThrows []SavingThrows `json:"saving_throws"` 23 | StartingEquipment StartingEquipment `json:"starting_equipment"` 24 | Subclasses []Subclasses `json:"subclasses"` 25 | URL string `json:"url"` 26 | } 27 | type ClassLevels struct { 28 | Class string `json:"class"` 29 | URL string `json:"url"` 30 | } 31 | type From struct { 32 | Name string `json:"name"` 33 | URL string `json:"url"` 34 | } 35 | type Proficiencies struct { 36 | Name string `json:"name"` 37 | URL string `json:"url"` 38 | } 39 | type ProficiencyChoices struct { 40 | Choose float64 `json:"choose"` 41 | From []From `json:"from"` 42 | Type string `json:"type"` 43 | } 44 | type SavingThrows struct { 45 | Name string `json:"name"` 46 | URL string `json:"url"` 47 | } 48 | type StartingEquipment struct { 49 | Class string `json:"class"` 50 | URL string `json:"url"` 51 | } 52 | type Subclasses struct { 53 | Name string `json:"name"` 54 | URL string `json:"url"` 55 | } 56 | 57 | type Classes struct { 58 | Classes []Class `json:"classes"` 59 | } 60 | 61 | func (cl *Classes) Load() { 62 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/class.json") 63 | 64 | if err != nil { 65 | fmt.Println(err) 66 | } 67 | 68 | defer jsonFile.Close() 69 | 70 | byteValue, _ := ioutil.ReadAll(jsonFile) 71 | if err := json.Unmarshal(byteValue, &cl.Classes); err != nil { 72 | fmt.Println(err) 73 | } 74 | //json.Unmarshal(byteValue, &ms) 75 | return 76 | } 77 | 78 | func (cl *Classes) ClassById(id string) { 79 | 80 | n, _ := strconv.Atoi(id) 81 | fmt.Println(cl.Classes[n]) //.Strength) 82 | return 83 | } 84 | 85 | func (cl *Classes) List() { 86 | for i := range cl.Classes { 87 | fmt.Print((cl.Classes[i].Index - 1)) 88 | fmt.Println(" " + cl.Classes[i].Name) 89 | } 90 | //fmt.Println(cl.Classes) 91 | return 92 | 93 | } 94 | -------------------------------------------------------------------------------- /shell/character/class/feats/feats.go: -------------------------------------------------------------------------------- 1 | package feats 2 | 3 | import "fmt" 4 | 5 | type Feat struct { 6 | Index int `json:"index"` 7 | Class struct { 8 | URL string `json:"url"` 9 | Name string `json:"name"` 10 | } `json:"class"` 11 | Name string `json:"name"` 12 | Level int `json:"level,omitempty"` 13 | Desc []string `json:"desc"` 14 | URL string `json:"url"` 15 | Subclass struct { 16 | URL string `json:"url"` 17 | Name string `json:"name"` 18 | } `json:"subclass,omitempty"` 19 | } 20 | 21 | type Feats struct { 22 | Feats []Feat 23 | } 24 | 25 | func (rc *Feats) Load() { 26 | jsonFile, err := os.Open("./json/feats.json") 27 | 28 | if err != nil { 29 | fmt.Println(err) 30 | } 31 | 32 | defer jsonFile.Close() 33 | 34 | byteValue, _ := ioutil.ReadAll(jsonFile) 35 | if err := json.Unmarshal(byteValue, &rc.Feats); err != nil { 36 | fmt.Println(err) 37 | } 38 | //json.Unmarshal(byteValue, &ms) 39 | return 40 | } 41 | 42 | func (rc *Feats) ById(id string) { 43 | 44 | n, _ := strconv.Atoi(id) 45 | fmt.Println(rc.Feats[n]) //.Strength) 46 | return 47 | } 48 | 49 | func (rc *Feats) List() { 50 | for i := range rc.Feats { 51 | fmt.Print((rc.Feats[i].Index - 1)) 52 | fmt.Println(" " + rc.Feats[i].Name) 53 | } 54 | //fmt.Println(cl.Feats) 55 | return 56 | 57 | } 58 | -------------------------------------------------------------------------------- /shell/character/class/lang/lang.go: -------------------------------------------------------------------------------- 1 | package lang 2 | 3 | import "fmt" 4 | 5 | type Language struct { 6 | Index int `json:"index"` 7 | Name string `json:"name"` 8 | Type string `json:"type"` 9 | TypicalSpeakers []string `json:"typical_speakers"` 10 | Script string `json:"script"` 11 | URL string `json:"url"` 12 | } 13 | type Languages struct { 14 | Languages []Language 15 | } 16 | -------------------------------------------------------------------------------- /shell/character/class/skills/skills.go: -------------------------------------------------------------------------------- 1 | package skills 2 | 3 | type Skill struct { 4 | Index int `json:"index"` 5 | Name string `json:"name"` 6 | Desc []string `json:"desc"` 7 | AbilityScore struct { 8 | URL string `json:"url"` 9 | Name string `json:"name"` 10 | } `json:"ability_score"` 11 | URL string `json:"url"` 12 | } 13 | 14 | type Skills struct { 15 | Skills []Skill 16 | } 17 | -------------------------------------------------------------------------------- /shell/character/class/subclass/subclass.go: -------------------------------------------------------------------------------- 1 | package Subclass 2 | 3 | type Subclass struct { 4 | Class Class `json:"class"` 5 | Desc []string `json:"desc"` 6 | Features []Features `json:"features"` 7 | Index float64 `json:"index"` 8 | Name string `json:"name"` 9 | Spells []Spells `json:"spells"` 10 | SubclassFlavor string `json:"subclass_flavor"` 11 | Subclasses []Subclasses `json:"Subclasses"` 12 | URL string `json:"url"` 13 | } 14 | type Class struct { 15 | Name string `json:"name"` 16 | URL string `json:"url"` 17 | } 18 | type Features struct { 19 | Name string `json:"name"` 20 | URL string `json:"url"` 21 | } 22 | type Prerequisites struct { 23 | Name string `json:"name"` 24 | Type string `json:"type"` 25 | URL string `json:"url"` 26 | } 27 | type Spells struct { 28 | Prerequisites []Prerequisites `json:"prerequisites"` 29 | Spell Spell `json:"spell"` 30 | } 31 | type Subclasses struct { 32 | Subclasses []Subclass 33 | } 34 | -------------------------------------------------------------------------------- /shell/character/feats/feats.go: -------------------------------------------------------------------------------- 1 | package feats 2 | 3 | import ( 4 | h "github.com/mitchellh/go-homedir" 5 | ) 6 | 7 | var Home, _ = h.Dir() 8 | 9 | type Feats struct { 10 | Class Class `json:"class"` 11 | Desc []string `json:"desc"` 12 | ID string `json:"_id"` 13 | Index float64 `json:"index"` 14 | Level float64 `json:"level"` 15 | Name string `json:"name"` 16 | URL string `json:"url"` 17 | } 18 | type Class struct { 19 | Name string `json:"name"` 20 | URL string `json:"url"` 21 | } 22 | 23 | func (ms *Feats) FeatById(id string) { 24 | n, _ := strconv.Atoi(id) 25 | fmt.Println(ms.Feats[n]) //.Strength) 26 | return 27 | } 28 | 29 | func (ms *Feats) Load() { 30 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/monsters.json") 31 | 32 | if err != nil { 33 | fmt.Println(err) 34 | } 35 | 36 | defer jsonFile.Close() 37 | 38 | byteValue, _ := ioutil.ReadAll(jsonFile) 39 | if err := json.Unmarshal(byteValue, &ms.Feats); err != nil { 40 | fmt.Println(err) 41 | } 42 | //json.Unmarshal(byteValue, &ms) 43 | return 44 | } 45 | -------------------------------------------------------------------------------- /shell/character/inv/inv.go: -------------------------------------------------------------------------------- 1 | package inv 2 | 3 | type Inventory struct { 4 | Amount int 5 | Weight int 6 | Items []Item 7 | } 8 | 9 | type Item struct { 10 | Type string 11 | } 12 | 13 | func main() { 14 | } 15 | -------------------------------------------------------------------------------- /shell/character/levels/levels.go: -------------------------------------------------------------------------------- 1 | package levels 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | h "github.com/mitchellh/go-homedir" 7 | "io/ioutil" 8 | "os" 9 | "strconv" 10 | ) 11 | 12 | var Home, _ = h.Dir() 13 | 14 | type CharLevel struct { 15 | Level int `json:"level"` 16 | AbilityScoreBonuses int `json:"ability_score_bonuses,omitempty"` 17 | Index int `json:"index"` 18 | 19 | ProfBonus int `json:"prof_bonus,omitempty"` 20 | FeatureChoices []interface{} `json:"feature_choices"` 21 | Features []struct { 22 | Name string `json:"name"` 23 | URL string `json:"url"` 24 | } `json:"features"` 25 | ClassSpecific struct { 26 | BardicInspirationDie int `json:"bardic_inspiration_die"` 27 | SongOfRestDie int `json:"song_of_rest_die"` 28 | MagicalSecretsMax5 int `json:"magical_secrets_max_5"` 29 | MagicalSecretsMax7 int `json:"magical_secrets_max_7"` 30 | MagicalSecretsMax9 int `json:"magical_secrets_max_9"` 31 | ChannelDivinityCharges int `json:"channel_divinity_charges"` 32 | DestroyUndeadCr int `json:"destroy_undead_cr"` 33 | ActionSurges int `json:"action_surges"` 34 | IndomitableUses int `json:"indomitable_uses"` 35 | ExtraAttacks int `json:"extra_attacks"` 36 | 37 | ArcaneRecoveryLevels int `json:"arcane_recovery_levels"` 38 | 39 | InvocationsKnown int `json:"invocations_known"` 40 | MysticArcanumLevel6 int `json:"mystic_arcanum_level_6"` 41 | MysticArcanumLevel7 int `json:"mystic_arcanum_level_7"` 42 | MysticArcanumLevel8 int `json:"mystic_arcanum_level_8"` 43 | MysticArcanumLevel9 int `json:"mystic_arcanum_level_9"` 44 | 45 | MartialArts struct { 46 | DiceCount int `json:"dice_count"` 47 | DiceValue int `json:"dice_value"` 48 | } `json:"martial_arts"` 49 | KiPoints int `json:"ki_points"` 50 | UnarmoredMovement int `json:"unarmored_movement"` 51 | 52 | SneakAttack struct { 53 | DiceCount int `json:"dice_count"` 54 | DiceValue int `json:"dice_value"` 55 | } `json:"sneak_attack"` 56 | 57 | SorceryPoints int `json:"sorcery_points"` 58 | MetamagicKnown int `json:"metamagic_known"` 59 | CreatingSpellSlots []interface{} `json:"creating_spell_slots"` 60 | 61 | FavoredEnemies int `json:"favored_enemies"` 62 | FavoredTerrain int `json:"favored_terrain"` 63 | 64 | AuraRange int `json:"aura_range"` 65 | 66 | WildShapeMaxCr int `json:"wild_shape_max_cr"` 67 | WildShapeSwim bool `json:"wild_shape_swim"` 68 | WildShapeFly bool `json:"wild_shape_fly"` 69 | 70 | RageCount int `json:"rage_count"` 71 | RageDamageBonus int `json:"rage_damage_bonus"` 72 | BrutalCriticalDice int `json:"brutal_critical_dice"` 73 | } 74 | ClassSpecificBarbarian struct { 75 | RageCount int `json:"rage_count"` 76 | RageDamageBonus int `json:"rage_damage_bonus"` 77 | BrutalCriticalDice int `json:"brutal_critical_dice"` 78 | } `json:"class_specific,omitempty"` 79 | Class struct { 80 | Name string `json:"name"` 81 | URL string `json:"url"` 82 | } `json:"class"` 83 | URL string `json:"url"` 84 | //Spellcasting struct { 85 | //} `json:"spellcasting,omitempty"` 86 | Spellcasting struct { 87 | CantripsKnown int `json:"cantrips_known"` 88 | SpellsKnown int `json:"spells_known"` 89 | SpellSlotsLevel1 int `json:"spell_slots_level_1"` 90 | SpellSlotsLevel2 int `json:"spell_slots_level_2"` 91 | SpellSlotsLevel3 int `json:"spell_slots_level_3"` 92 | SpellSlotsLevel4 int `json:"spell_slots_level_4"` 93 | SpellSlotsLevel5 int `json:"spell_slots_level_5"` 94 | SpellSlotsLevel6 int `json:"spell_slots_level_6"` 95 | SpellSlotsLevel7 int `json:"spell_slots_level_7"` 96 | SpellSlotsLevel8 int `json:"spell_slots_level_8"` 97 | SpellSlotsLevel9 int `json:"spell_slots_level_9"` 98 | } `json:"spellcasting,omitempty"` 99 | ClassSpecificBard struct { 100 | BardicInspirationDie int `json:"bardic_inspiration_die"` 101 | SongOfRestDie int `json:"song_of_rest_die"` 102 | MagicalSecretsMax5 int `json:"magical_secrets_max_5"` 103 | MagicalSecretsMax7 int `json:"magical_secrets_max_7"` 104 | MagicalSecretsMax9 int `json:"magical_secrets_max_9"` 105 | } `json:"class_specific,omitempty"` 106 | ClassSpecificCleric struct { 107 | ChannelDivinityCharges int `json:"channel_divinity_charges"` 108 | DestroyUndeadCr int `json:"destroy_undead_cr"` 109 | } `json:"class_specific,omitempty"` 110 | ClassSpecificDruid struct { 111 | WildShapeMaxCr int `json:"wild_shape_max_cr"` 112 | WildShapeSwim bool `json:"wild_shape_swim"` 113 | WildShapeFly bool `json:"wild_shape_fly"` 114 | } `json:"class_specific,omitempty"` 115 | ClassSpecificFighter struct { 116 | ActionSurges int `json:"action_surges"` 117 | IndomitableUses int `json:"indomitable_uses"` 118 | ExtraAttacks int `json:"extra_attacks"` 119 | } `json:"class_specific,omitempty"` 120 | ClassSpecificMonk struct { 121 | MartialArts struct { 122 | DiceCount int `json:"dice_count"` 123 | DiceValue int `json:"dice_value"` 124 | } `json:"martial_arts"` 125 | KiPoints int `json:"ki_points"` 126 | UnarmoredMovement int `json:"unarmored_movement"` 127 | } `json:"class_specific,omitempty"` 128 | ClassSpecificPaladin struct { 129 | AuraRange int `json:"aura_range"` 130 | } `json:"class_specific,omitempty"` 131 | ClassSpecificRanger struct { 132 | FavoredEnemies int `json:"favored_enemies"` 133 | FavoredTerrain int `json:"favored_terrain"` 134 | } `json:"class_specific,omitempty"` 135 | ClassSpecificRogue struct { 136 | SneakAttack struct { 137 | DiceCount int `json:"dice_count"` 138 | DiceValue int `json:"dice_value"` 139 | } `json:"sneak_attack"` 140 | } `json:"class_specific,omitempty"` 141 | ClassSpecificSorcerer struct { 142 | SorceryPoints int `json:"sorcery_points"` 143 | MetamagicKnown int `json:"metamagic_known"` 144 | CreatingSpellSlots []interface{} `json:"creating_spell_slots"` 145 | } `json:"class_specific,omitempty"` 146 | ClassSpecificWarlock struct { 147 | InvocationsKnown int `json:"invocations_known"` 148 | MysticArcanumLevel6 int `json:"mystic_arcanum_level_6"` 149 | MysticArcanumLevel7 int `json:"mystic_arcanum_level_7"` 150 | MysticArcanumLevel8 int `json:"mystic_arcanum_level_8"` 151 | MysticArcanumLevel9 int `json:"mystic_arcanum_level_9"` 152 | } `json:"class_specific,omitempty"` 153 | ClassSpecificWizard struct { 154 | ArcaneRecoveryLevels int `json:"arcane_recovery_levels"` 155 | } `json:"class_specific,omitempty"` 156 | Subclass struct { 157 | Name string `json:"name"` 158 | URL string `json:"url"` 159 | } `json:"subclass,omitempty"` 160 | SubclassSpecific struct { 161 | AdditionalMagicalSecretsMaxLvl int `json:"additional_magical_secrets_max_lvl"` 162 | } `json:"subclass_specific,omitempty"` 163 | } 164 | type Levels struct { 165 | Levels []CharLevel 166 | } 167 | 168 | func (rc *Levels) Load() { 169 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/levels.json") 170 | 171 | if err != nil { 172 | fmt.Println(err) 173 | } 174 | 175 | defer jsonFile.Close() 176 | 177 | byteValue, _ := ioutil.ReadAll(jsonFile) 178 | if err := json.Unmarshal(byteValue, &rc.Levels); err != nil { 179 | fmt.Println(err) 180 | } 181 | //json.Unmarshal(byteValue, &ms) 182 | return 183 | } 184 | 185 | func (rc *Levels) ById(id string) { 186 | 187 | n, _ := strconv.Atoi(id) 188 | fmt.Println(rc.Levels[n]) //.Strength) 189 | return 190 | } 191 | 192 | func (rc *Levels) List() { 193 | for i := range rc.Levels { 194 | fmt.Print((rc.Levels[i].Index - 1)) 195 | fmt.Println(" ", rc.Levels[i].Class.Name, rc.Levels[i].Level) 196 | } 197 | //fmt.Println(cl.Levels) 198 | return 199 | 200 | } 201 | -------------------------------------------------------------------------------- /shell/character/race/race.go: -------------------------------------------------------------------------------- 1 | package race 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | h "github.com/mitchellh/go-homedir" 7 | "io/ioutil" 8 | "os" 9 | "strconv" 10 | ) 11 | 12 | var Home, _ = h.Dir() 13 | 14 | type Race struct { 15 | AbilityBonusOptions AbilityBonusOptions `json:"ability_bonus_options"` 16 | AbilityBonuses []AbilityBonuses `json:"ability_bonuses"` 17 | Age string `json:"age"` 18 | Alignment string `json:"alignment"` 19 | Index float64 `json:"index"` 20 | LanguageDesc string `json:"language_desc"` 21 | LanguageOptions LanguageOptions `json:"language_options"` 22 | Languages []Languages `json:"languages"` 23 | Name string `json:"name"` 24 | Races []Races `json:"Races"` 25 | Size string `json:"size"` 26 | SizeDescription string `json:"size_description"` 27 | Speed float64 `json:"speed"` 28 | StartingProficiencies []StartingProficiencies `json:"starting_proficiencies"` 29 | StartingProficiencyOptions StartingProficiencyOptions `json:"starting_proficiency_options"` 30 | Subraces []Subraces `json:"subraces"` 31 | TraitOptions TraitOptions `json:"trait_options"` 32 | Traits []Traits `json:"traits"` 33 | URL string `json:"url"` 34 | } 35 | type AbilityBonusOptions struct { 36 | Choose float64 `json:"choose"` 37 | From []From `json:"from"` 38 | Type string `json:"type"` 39 | } 40 | type AbilityBonuses struct { 41 | Bonus float64 `json:"bonus"` 42 | Name string `json:"name"` 43 | URL string `json:"url"` 44 | } 45 | type From struct { 46 | Bonus float64 `json:"bonus"` 47 | Name string `json:"name"` 48 | URL string `json:"url"` 49 | } 50 | type LanguageOptions struct { 51 | Choose float64 `json:"choose"` 52 | From []From `json:"from"` 53 | Type string `json:"type"` 54 | } 55 | type Languages struct { 56 | Name string `json:"name"` 57 | URL string `json:"url"` 58 | } 59 | type StartingProficiencies struct { 60 | Name string `json:"name"` 61 | URL string `json:"url"` 62 | } 63 | type StartingProficiencyOptions struct { 64 | Choose float64 `json:"choose"` 65 | From []From `json:"from"` 66 | Type string `json:"type"` 67 | } 68 | type Subraces struct { 69 | Name string `json:"name"` 70 | URL string `json:"url"` 71 | } 72 | type TraitOptions struct { 73 | Choose float64 `json:"choose"` 74 | From []From `json:"from"` 75 | Type string `json:"type"` 76 | } 77 | type Traits struct { 78 | Name string `json:"name"` 79 | URL string `json:"url"` 80 | } 81 | type Races struct { 82 | Races []Race 83 | } 84 | 85 | func (rc *Races) Load() { 86 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/race.json") 87 | 88 | if err != nil { 89 | fmt.Println(err) 90 | } 91 | 92 | defer jsonFile.Close() 93 | 94 | byteValue, _ := ioutil.ReadAll(jsonFile) 95 | if err := json.Unmarshal(byteValue, &rc.Races); err != nil { 96 | fmt.Println(err) 97 | } 98 | //json.Unmarshal(byteValue, &ms) 99 | return 100 | } 101 | 102 | func (rc *Races) ById(id string) { 103 | 104 | n, _ := strconv.Atoi(id) 105 | fmt.Println(rc.Races[n]) //.Strength) 106 | return 107 | } 108 | 109 | func (rc *Races) List() { 110 | for i := range rc.Races { 111 | fmt.Print((rc.Races[i].Index - 1)) 112 | fmt.Println(" " + rc.Races[i].Name) 113 | } 114 | //fmt.Println(cl.Races) 115 | return 116 | 117 | } 118 | -------------------------------------------------------------------------------- /shell/character/skill/skill.go: -------------------------------------------------------------------------------- 1 | package skill 2 | 3 | import ( 4 | h "github.com/mitchellh/go-homedir" 5 | ) 6 | 7 | var Home, _ = h.Dir() 8 | 9 | type Skill struct { 10 | AbilityScore AbilityScore `json:"ability_score"` 11 | Desc []string `json:"desc"` 12 | Index float64 `json:"index"` 13 | Name string `json:"name"` 14 | Skills []Skills `json:"Skills"` 15 | URL string `json:"url"` 16 | } 17 | type AbilityScore struct { 18 | Name string `json:"name"` 19 | URL string `json:"url"` 20 | } 21 | 22 | type Skills struct { 23 | Skills []Skill 24 | } 25 | 26 | func (rc *Skills) Load() { 27 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/skills.json") 28 | 29 | if err != nil { 30 | fmt.Println(err) 31 | } 32 | 33 | defer jsonFile.Close() 34 | 35 | byteValue, _ := ioutil.ReadAll(jsonFile) 36 | if err := json.Unmarshal(byteValue, &rc.Skills); err != nil { 37 | fmt.Println(err) 38 | } 39 | //json.Unmarshal(byteValue, &ms) 40 | return 41 | } 42 | 43 | func (rc *Skills) ById(id string) { 44 | 45 | n, _ := strconv.Atoi(id) 46 | fmt.Println(rc.Skills[n]) //.Strength) 47 | return 48 | } 49 | 50 | func (rc *Skills) List() { 51 | for i := range rc.Skills { 52 | fmt.Print((rc.Skills[i].Index - 1)) 53 | fmt.Println(" " + rc.Skills[i].Name) 54 | } 55 | //fmt.Println(cl.Skills) 56 | return 57 | 58 | } 59 | -------------------------------------------------------------------------------- /shell/character/spells/spells.go: -------------------------------------------------------------------------------- 1 | package spells 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/tatsushid/go-prettytable" 7 | "io/ioutil" 8 | //"log" 9 | "os" 10 | //"os/exec" 11 | h "github.com/mitchellh/go-homedir" 12 | "strconv" 13 | "strings" 14 | ) 15 | 16 | var Home, _ = h.Dir() 17 | 18 | type Spell struct { 19 | Index int `json:"index"` 20 | Name string `json:"name"` 21 | Desc []string `json:"desc"` 22 | HigherLevel []string `json:"higher_level,omitempty"` 23 | Page string `json:"page"` 24 | Range string `json:"range"` 25 | Components []string `json:"components"` 26 | Material string `json:"material,omitempty"` 27 | Ritual bool `json:"ritual"` 28 | Duration string `json:"duration"` 29 | Concentration bool `json:"concentration"` 30 | CastingTime string `json:"casting_time"` 31 | Level int `json:"level"` 32 | School struct { 33 | Name string `json:"name"` 34 | URL string `json:"url"` 35 | } `json:"school"` 36 | Classes []struct { 37 | Name string `json:"name"` 38 | URL string `json:"url"` 39 | } `json:"classes"` 40 | Subclasses []struct { 41 | Name string `json:"name"` 42 | URL string `json:"url"` 43 | } `json:"subclasses"` 44 | URL string `json:"url"` 45 | } 46 | 47 | type Spells struct { 48 | Spells []Spell 49 | } 50 | 51 | func (rc *Spells) Load() { 52 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/spells.json") 53 | 54 | if err != nil { 55 | fmt.Println(err) 56 | } 57 | 58 | defer jsonFile.Close() 59 | 60 | byteValue, _ := ioutil.ReadAll(jsonFile) 61 | if err := json.Unmarshal(byteValue, &rc.Spells); err != nil { 62 | fmt.Println(err) 63 | } 64 | //json.Unmarshal(byteValue, &ms) 65 | return 66 | } 67 | 68 | func (rc *Spells) ById(id string) { 69 | 70 | n, _ := strconv.Atoi(id) 71 | fmt.Println(rc.Spells[n]) //.Strength) 72 | return 73 | } 74 | 75 | func (rc *Spells) List() { 76 | for i := range rc.Spells { 77 | fmt.Print((rc.Spells[i].Index - 1)) 78 | fmt.Println(" " + rc.Spells[i].Name) 79 | } 80 | //fmt.Println(cl.Spells) 81 | return 82 | 83 | } 84 | 85 | func (sp *Spells) SpellBook() { 86 | //cmd := exec.Command("stty", "size") 87 | //cmd.Stdin = os.Stdin 88 | //out, err := cmd.Output() 89 | // fmt.Printf("out: %#v\n", string(out)) 90 | // fmt.Printf("err: %#v\n", err) 91 | //if err != nil { 92 | // log.Fatal(err) 93 | //} 94 | i := 0 95 | tbl, err := prettytable.NewTable([]prettytable.Column{ 96 | {Header: "Left", MinWidth: 80, MaxWidth: 150}, 97 | {Header: "Right", MinWidth: 80, MaxWidth: 150}, 98 | }...) 99 | if err != nil { 100 | panic(err) 101 | } 102 | tbl.Separator = " | " 103 | tbl.AddRow(strings.Join(sp.Spells[i].Desc, " "), strings.Join(sp.Spells[i+1].Desc, " ")) 104 | tbl.AddRow(strings.Join(sp.Spells[i+2].Desc, " "), strings.Join(sp.Spells[i+3].Desc, " ")) 105 | tbl.AddRow(strings.Join(sp.Spells[i+5].Desc, " "), strings.Join(sp.Spells[i+6].Desc, " ")) 106 | //tbl.AddRow(sp.Spells[i+6].Desc, sp.Spells[i+7].Desc, sp.Spells[i+8].Desc) 107 | tbl.Print() 108 | //fmt.Println(err) 109 | 110 | } 111 | -------------------------------------------------------------------------------- /shell/commands/commands.go: -------------------------------------------------------------------------------- 1 | package commands 2 | 3 | type Command struct { 4 | // Command Name 5 | Name string 6 | // Shorter maybe more common name 7 | ShortName string 8 | // Brief help entry for command 9 | Usage string 10 | // Launced Function on command 11 | Action func() 12 | // Action With String Argument 13 | StringAction func(s string) 14 | // Category of command 15 | Category string 16 | // List of child commands 17 | SubCommands Commands 18 | } 19 | 20 | type CommandsByName []Command 21 | 22 | func (c CommandsByName) Len() int { 23 | return len(c) 24 | } 25 | 26 | func (c CommandsByName) Swap(i, j int) { 27 | c[i], c[j] = c[j], c[i] 28 | } 29 | 30 | // FullName returns the full name of the command. 31 | // For subcommands this ensures that parent commands are part of the command path 32 | 33 | type Commands []Command 34 | 35 | func (c Command) Names() []string { 36 | names := []string{c.Name} 37 | 38 | if c.ShortName != "" { 39 | names = append(names, c.ShortName) 40 | } 41 | 42 | return names 43 | //return append(names, c.Aliases...) 44 | } 45 | func (cs Commands) HasCommand(name string) bool { 46 | for _, i := range cs { 47 | for _, n := range i.Names() { 48 | if n == name { 49 | return true 50 | } 51 | } 52 | } 53 | return false 54 | } 55 | 56 | func (c Command) HasName(name string) bool { 57 | for _, n := range c.Names() { 58 | if n == name { 59 | return true 60 | } 61 | } 62 | return false 63 | } 64 | func (cs Commands) NameIs(name string) Command { 65 | for _, c := range cs { 66 | if c.ShortName == name || c.Name == name { 67 | return c 68 | } 69 | } 70 | c := Command{} 71 | return c 72 | } 73 | -------------------------------------------------------------------------------- /shell/dice/dice.go: -------------------------------------------------------------------------------- 1 | package dice 2 | 3 | import ( 4 | "fmt" 5 | "github.com/bsdpunk/dndshell/shell/commands" 6 | "math/rand" 7 | "os" 8 | "strconv" 9 | "strings" 10 | "time" 11 | ) 12 | 13 | var DiceSubs = commands.Commands{ 14 | { 15 | Name: "dice", 16 | ShortName: "dice", 17 | Usage: "Roll Dice", 18 | Category: "", 19 | }, 20 | } 21 | 22 | type DiceRoll struct { 23 | Number int 24 | Amount []int 25 | Type int 26 | Total int 27 | } 28 | 29 | func (d DiceRoll) getAmount() (dr DiceRoll) { 30 | d.Amount = make([]int, d.Number) 31 | for i := range d.Amount { 32 | rand.Seed(time.Now().UnixNano()) 33 | random := rand.Intn(d.Type) 34 | d.Amount[i] = random + 1 35 | d.Total = d.Total + d.Amount[i] 36 | fmt.Println(d) 37 | } 38 | return d 39 | } 40 | 41 | func GetDice(arg string) { 42 | s := strings.Split(arg, "d") 43 | amt, _ := strconv.Atoi(s[0]) 44 | typ, _ := strconv.Atoi(s[1]) 45 | d := DiceRoll{Number: amt, Type: typ} 46 | 47 | d.Amount = make([]int, d.Number) 48 | for i := range d.Amount { 49 | rand.Seed(time.Now().UnixNano()) 50 | random := rand.Intn(d.Type) 51 | d.Amount[i] = random + 1 52 | d.Total = d.Total + d.Amount[i] 53 | } 54 | fmt.Println(d.Total) 55 | return 56 | } 57 | 58 | func main() { 59 | 60 | s := strings.Split(os.Args[1], "d") 61 | amt, _ := strconv.Atoi(s[0]) 62 | typ, _ := strconv.Atoi(s[1]) 63 | d := DiceRoll{Number: amt, Type: typ} 64 | d = d.getAmount() 65 | fmt.Println(d.Total) 66 | } 67 | -------------------------------------------------------------------------------- /shell/general/general.go: -------------------------------------------------------------------------------- 1 | package general 2 | 3 | import "os" 4 | import "fmt" 5 | 6 | func End() { 7 | os.Exit(0) 8 | } 9 | 10 | func Clear() { 11 | fmt.Println("\033[2J") 12 | } 13 | -------------------------------------------------------------------------------- /shell/monsters/monsters.go: -------------------------------------------------------------------------------- 1 | package Monsters 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/elgs/jsonql" 7 | h "github.com/mitchellh/go-homedir" 8 | "github.com/tatsushid/go-prettytable" 9 | "io/ioutil" 10 | "os" 11 | "strconv" 12 | ) 13 | 14 | var Home, _ = h.Dir() 15 | 16 | type Monster struct { 17 | Acrobatics float64 `json:"acrobatics"` 18 | Actions []Actions `json:"actions"` 19 | Alignment string `json:"alignment"` 20 | Arcana float64 `json:"arcana"` 21 | ArmorClass float64 `json:"armor_class"` 22 | Athletics float64 `json:"athletics"` 23 | ChallengeRating float64 `json:"challenge_rating"` 24 | Charisma float64 `json:"charisma"` 25 | CharismaSave float64 `json:"charisma_save"` 26 | ConditionImmunities []string `json:"condition_immunities"` 27 | Constitution float64 `json:"constitution"` 28 | ConstitutionSave float64 `json:"constitution_save"` 29 | DamageImmunities []string `json:"damage_immunities"` 30 | DamageResistances []string `json:"damage_resistances"` 31 | DamageVulnerabilities []string `json:"damage_vulnerabilities"` 32 | Deception float64 `json:"deception"` 33 | Dexterity float64 `json:"dexterity"` 34 | DexteritySave float64 `json:"dexterity_save"` 35 | History float64 `json:"history"` 36 | HitDice string `json:"hit_dice"` 37 | HitPoints float64 `json:"hit_points"` 38 | Index float64 `json:"index"` 39 | Insight float64 `json:"insight"` 40 | Intelligence float64 `json:"intelligence"` 41 | IntelligenceSave float64 `json:"intelligence_save"` 42 | Intimidation float64 `json:"intimidation"` 43 | Investigation float64 `json:"investigation"` 44 | Languages string `json:"languages"` 45 | LegendaryActions []LegendaryActions `json:"legendary_actions"` 46 | Medicine float64 `json:"medicine"` 47 | Monsters []Monster `json:"Monsters"` 48 | Name string `json:"name"` 49 | Nature float64 `json:"nature"` 50 | OtherSpeeds []OtherSpeeds `json:"other_speeds"` 51 | Perception float64 `json:"perception"` 52 | Performance float64 `json:"performance"` 53 | Persuasion float64 `json:"persuasion"` 54 | Reactions []Reactions `json:"reactions"` 55 | Religion float64 `json:"religion"` 56 | Senses string `json:"senses"` 57 | Size string `json:"size"` 58 | SpecialAbilities []SpecialAbilities `json:"special_abilities"` 59 | Speed Speed `json:"speed"` 60 | Stealth float64 `json:"stealth"` 61 | Strength float64 `json:"strength"` 62 | StrengthSave float64 `json:"strength_save"` 63 | Subtype string `json:"subtype"` 64 | Survival float64 `json:"survival"` 65 | Type string `json:"type"` 66 | URL string `json:"url"` 67 | Wisdom float64 `json:"wisdom"` 68 | WisdomSave float64 `json:"wisdom_save"` 69 | } 70 | type Actions struct { 71 | AttackBonus float64 `json:"attack_bonus"` 72 | //DamageBonus float64 `json:"damage_bonus"` 73 | DamageDice string `json:"damage_dice"` 74 | Desc string `json:"desc"` 75 | Name string `json:"name"` 76 | } 77 | type LegendaryActions struct { 78 | AttackBonus float64 `json:"attack_bonus"` 79 | DamageDice string `json:"damage_dice"` 80 | Desc string `json:"desc"` 81 | Name string `json:"name"` 82 | } 83 | type OtherSpeeds struct { 84 | Form string `json:"form"` 85 | Speed Speed `json:"speed"` 86 | } 87 | type Reactions struct { 88 | AttackBonus float64 `json:"attack_bonus"` 89 | Desc string `json:"desc"` 90 | Name string `json:"name"` 91 | } 92 | type SpecialAbilities struct { 93 | AttackBonus float64 `json:"attack_bonus"` 94 | DamageDice string `json:"damage_dice"` 95 | Desc string `json:"desc"` 96 | Name string `json:"name"` 97 | } 98 | type Speed struct { 99 | Burrow string `json:"burrow"` 100 | Climb string `json:"climb"` 101 | Fly string `json:"fly"` 102 | Hover bool `json:"hover"` 103 | Swim string `json:"swim"` 104 | Walk string `json:"walk"` 105 | } 106 | type Monsters struct { 107 | Monsters []Monster 108 | jsonString string 109 | } 110 | 111 | func (ms *Monsters) List() { 112 | 113 | for i := range ms.Monsters { 114 | fmt.Print((ms.Monsters[i].Index - 1)) 115 | fmt.Println(" "+ms.Monsters[i].Name, ms.Monsters[i].ChallengeRating) 116 | } 117 | return 118 | 119 | } 120 | 121 | func (ms *Monsters) MonsterById(id string) { 122 | n, _ := strconv.Atoi(id) 123 | b, err := json.Marshal(ms.Monsters[n]) 124 | if err != nil { 125 | fmt.Println(err) 126 | return 127 | } 128 | fmt.Println(string(b)) 129 | //fmt.Println(ms.Monsters[n]) //.Strength) 130 | return 131 | } 132 | 133 | func (ms *Monsters) SBById(id string) { 134 | n, _ := strconv.Atoi(id) 135 | ms.Monsters[n].StatBlock() //.Strength) 136 | return 137 | } 138 | 139 | func (mo *Monster) StatBlock() { 140 | fmt.Println("Name: ", mo.Name) 141 | fmt.Println("ArmorClass: ", mo.ArmorClass) 142 | fmt.Println("HP: ", mo.HitPoints) 143 | tbl, err := prettytable.NewTable([]prettytable.Column{ 144 | {Header: "STR"}, 145 | {Header: "DEX", MinWidth: 6}, 146 | {Header: "CON"}, 147 | {Header: "INT"}, 148 | {Header: "WIS"}, 149 | {Header: "CHR"}, 150 | }...) 151 | if err != nil { 152 | panic(err) 153 | } 154 | tbl.Separator = " | " 155 | tbl.AddRow(mo.Strength, mo.Dexterity, mo.Constitution, mo.Intelligence, mo.Wisdom, mo.Charisma) 156 | tbl.Print() 157 | } 158 | func (ms *Monsters) ByName(name string) { 159 | parser, err := jsonql.NewStringQuery(ms.jsonString) 160 | if err != nil { 161 | fmt.Println(err) 162 | return 163 | } 164 | fmt.Println(parser.Query("name='" + name + "'")) 165 | } 166 | 167 | func (ms *Monsters) ByGuess(name string) { 168 | parser, err := jsonql.NewStringQuery(ms.jsonString) 169 | if err != nil { 170 | fmt.Println(err) 171 | return 172 | } 173 | fmt.Println(parser.Query("name~='" + name + "'")) 174 | } 175 | 176 | func (ms *Monsters) ByCR(chall string) { 177 | parser, err := jsonql.NewStringQuery(ms.jsonString) 178 | //fchall, _ := strconv.ParseFloat(chall, 64) 179 | if err != nil { 180 | fmt.Println(err) 181 | return 182 | } 183 | inter, _ := parser.Query("challenge_rating=" + chall) 184 | b, err := json.Marshal(inter) 185 | if err != nil { 186 | fmt.Println(err) 187 | return 188 | } 189 | fmt.Println(string(b)) 190 | } 191 | 192 | func (ms *Monsters) Load() { 193 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/monsters.json") 194 | 195 | if err != nil { 196 | fmt.Println(err) 197 | } 198 | 199 | defer jsonFile.Close() 200 | byteValue, _ := ioutil.ReadAll(jsonFile) 201 | ms.jsonString = string(byteValue) 202 | if err := json.Unmarshal(byteValue, &ms.Monsters); err != nil { 203 | fmt.Println(err) 204 | } 205 | //json.Unmarshal(byteValue, &ms) 206 | return 207 | } 208 | -------------------------------------------------------------------------------- /shell/quotes/quotes.go: -------------------------------------------------------------------------------- 1 | package quotes 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | h "github.com/mitchellh/go-homedir" 7 | "io/ioutil" 8 | "math/rand" 9 | "os" 10 | "time" 11 | ) 12 | 13 | var Home, _ = h.Dir() 14 | 15 | type Quote struct { 16 | Index int `json:"index"` 17 | Quote string `json:"quote"` 18 | Source string `json:"source"` 19 | } 20 | type Quotes struct { 21 | Quotes []Quote 22 | } 23 | 24 | func (q *Quotes) RandQ() { 25 | 26 | seed := rand.NewSource(time.Now().UnixNano()) 27 | rq := rand.New(seed) 28 | rqIndex := rq.Intn(len(q.Quotes)) 29 | selected := q.Quotes[rqIndex] 30 | fmt.Println(selected.Quote, " - ", selected.Source) 31 | } 32 | 33 | func (q *Quotes) Load() { 34 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/quotes.json") 35 | 36 | if err != nil { 37 | fmt.Println(err) 38 | } 39 | 40 | defer jsonFile.Close() 41 | 42 | byteValue, _ := ioutil.ReadAll(jsonFile) 43 | if err := json.Unmarshal(byteValue, &q.Quotes); err != nil { 44 | fmt.Println(err) 45 | } 46 | 47 | return 48 | } 49 | -------------------------------------------------------------------------------- /shell/shell.go: -------------------------------------------------------------------------------- 1 | package shell 2 | 3 | import ( 4 | "fmt" 5 | "github.com/bsdpunk/dndshell/shell/character" 6 | //"./character" 7 | "github.com/bsdpunk/dndshell/shell/commands" 8 | "github.com/bsdpunk/dndshell/shell/dice" 9 | "github.com/bsdpunk/dndshell/shell/general" 10 | "github.com/bsdpunk/dndshell/shell/quotes" 11 | "github.com/gobs/readline" 12 | "os" 13 | "strings" 14 | ) 15 | 16 | var found string = "no" 17 | var list []string 18 | var cr character.Character 19 | var matches = make([]string, 0, len(list)) 20 | var Qu quotes.Quotes 21 | var coms = commands.Commands{ 22 | { 23 | Name: "Quit", 24 | ShortName: "quit", 25 | Usage: "Exit the shell", 26 | Action: general.End, 27 | Category: "general", 28 | }, 29 | { 30 | Name: "Clear", 31 | ShortName: "clear", 32 | Usage: "Clear the screen", 33 | Action: general.Clear, 34 | Category: "general", 35 | }, 36 | { 37 | Name: "Dice", 38 | ShortName: "d", 39 | Usage: "3d6: rolls 3 6 sided dice ", 40 | SubCommands: dice.DiceSubs, 41 | StringAction: dice.GetDice, 42 | Category: "general", 43 | }, 44 | { 45 | Name: "CreateCharacter", 46 | ShortName: "ic", 47 | Usage: "", 48 | Action: character.InteractiveCreateCharacter, 49 | Category: "general", 50 | }, 51 | { 52 | Name: "CreateNPC", 53 | ShortName: "in", 54 | Usage: "", 55 | Action: character.InteractiveCreateNPC, 56 | Category: "general", 57 | }, 58 | { 59 | Name: "ListAbilities", 60 | ShortName: "al", 61 | Usage: "Show Abilities List", 62 | Action: character.As.List, 63 | Category: "character", 64 | }, 65 | { 66 | Name: "ListLevels", 67 | ShortName: "ll", 68 | Usage: "Show Levels List", 69 | Action: character.Ls.List, 70 | Category: "character", 71 | }, 72 | { 73 | Name: "SpellBook", 74 | ShortName: "sb", 75 | Usage: "Show Spells in a readable format", 76 | Action: character.Sp.SpellBook, 77 | Category: "character", 78 | }, 79 | { 80 | Name: "ListSpells", 81 | ShortName: "rl", 82 | Usage: "Show Spell List", 83 | Action: character.Sp.List, 84 | Category: "character", 85 | }, 86 | { 87 | Name: "ListRaces", 88 | ShortName: "rl", 89 | Usage: "Show Class List", 90 | Action: character.Rc.List, 91 | Category: "character", 92 | }, 93 | { 94 | Name: "ListClasses", 95 | ShortName: "cl", 96 | Usage: "Show Class List", 97 | Action: character.Cl.List, 98 | Category: "character", 99 | }, 100 | { 101 | Name: "ListMonster", 102 | ShortName: "ml", 103 | Usage: "Show Monster List", 104 | Action: character.Ms.List, 105 | Category: "monsters", 106 | }, 107 | { 108 | Name: "LevelsById", 109 | ShortName: "lid", 110 | Usage: "Show a Level by ID", 111 | SubCommands: character.LevelSubs, 112 | StringAction: character.Ls.ById, 113 | Category: "character", 114 | }, 115 | { 116 | Name: "AbilityById", 117 | ShortName: "aid", 118 | Usage: "Show an Ability by ID", 119 | SubCommands: character.AbilitySubs, 120 | StringAction: character.As.ById, 121 | Category: "monsters", 122 | }, 123 | { 124 | Name: "SpellById", 125 | ShortName: "sid", 126 | Usage: "Show a race by ID", 127 | SubCommands: character.SpellSubs, 128 | StringAction: character.Sp.ById, 129 | Category: "monsters", 130 | }, 131 | { 132 | Name: "RaceById", 133 | ShortName: "rid", 134 | Usage: "Show a race by ID", 135 | SubCommands: character.RaceSubs, 136 | StringAction: character.Rc.ById, 137 | Category: "monsters", 138 | }, 139 | { 140 | Name: "ClassById", 141 | ShortName: "cid", 142 | Usage: "Show a class by ID", 143 | SubCommands: character.ClassSubs, 144 | StringAction: character.Cl.ClassById, 145 | Category: "monsters", 146 | }, 147 | 148 | { 149 | Name: "MonsterByGuess", 150 | ShortName: "mbg", 151 | Usage: "Show a monster by Name", 152 | SubCommands: character.MonsterSubs, 153 | StringAction: character.Ms.ByGuess, 154 | Category: "monsters", 155 | }, 156 | { 157 | Name: "MonsterByName", 158 | ShortName: "mbn", 159 | Usage: "Show a monster by Name", 160 | SubCommands: character.MonsterSubs, 161 | StringAction: character.Ms.ByName, 162 | Category: "monsters", 163 | }, 164 | { 165 | Name: "MonsterByCR", 166 | ShortName: "mbc", 167 | Usage: "Show a monster by CR", 168 | SubCommands: character.MonsterSubs, 169 | StringAction: character.Ms.ByCR, 170 | Category: "monsters", 171 | }, 172 | { 173 | Name: "MonsterById", 174 | ShortName: "mid", 175 | Usage: "Show a monster by ID", 176 | SubCommands: character.MonsterSubs, 177 | StringAction: character.Ms.MonsterById, 178 | Category: "monsters", 179 | }, 180 | { 181 | Name: "SBById", 182 | ShortName: "sbid", 183 | Usage: "Show a monster by ID", 184 | SubCommands: character.MonsterSubs, 185 | StringAction: character.Ms.SBById, 186 | Category: "monsters", 187 | }, 188 | } 189 | 190 | func AttemptedCompletion(text string, start, end int) []string { 191 | if start == 0 { 192 | return readline.CompletionMatches(text, CompletionEntry) 193 | } else { 194 | return nil 195 | } 196 | } 197 | 198 | func CompletionEntry(prefix string, index int) string { 199 | if index == 0 { 200 | matches = matches[:0] 201 | 202 | for _, w := range list { 203 | if strings.HasPrefix(w, prefix) { 204 | matches = append(matches, w) 205 | } 206 | } 207 | } 208 | 209 | if index < len(matches) { 210 | return matches[index] 211 | } else { 212 | return "" 213 | } 214 | } 215 | func NoAction() { 216 | fmt.Println("No action supplied with command") 217 | 218 | } 219 | func Shell(args []string) { 220 | character.Load() 221 | Qu.Load() 222 | for _, c := range coms { 223 | list = append(list, c.Name) 224 | list = append(list, c.ShortName) 225 | } 226 | // cs := character.LoadClasses() 227 | //ms := monsters.Load() 228 | if len(args) > 1 { 229 | words := args 230 | if coms.HasCommand(words[1]) { 231 | cmd := coms.NameIs(words[1]) 232 | if len(words) == 2 { 233 | if len(cmd.SubCommands) == 0 { 234 | cmd.Action() 235 | } 236 | 237 | } else { 238 | if cmd.SubCommands.HasCommand(words[2]) { 239 | cmd.Action() 240 | } else if !(cmd.SubCommands.HasCommand(words[2])) { 241 | if cmd.StringAction != nil { 242 | cmd.StringAction(words[2]) 243 | } 244 | } 245 | } 246 | } 247 | os.Exit(0) 248 | } 249 | Qu.RandQ() 250 | prompt := "> " 251 | matches = make([]string, 0, len(list)) 252 | 253 | L: 254 | for { 255 | 256 | found = "no" 257 | readline.SetCompletionEntryFunction(CompletionEntry) 258 | readline.SetAttemptedCompletionFunction(nil) 259 | 260 | //readline.SetHistoryPath("~/.dnd_history") 261 | result := readline.ReadLine(&prompt) 262 | hist := *result 263 | readline.AddHistory(hist) 264 | //result.HistoryEnable() 265 | if result == nil { 266 | break L 267 | } 268 | 269 | input := *result 270 | words := strings.Fields(input) 271 | if len(words) > 0 && coms.HasCommand(words[0]) { 272 | cmd := coms.NameIs(words[0]) 273 | if len(words) == 1 { 274 | if len(cmd.SubCommands) == 0 { 275 | cmd.Action() 276 | } 277 | 278 | } else { 279 | if cmd.SubCommands.HasCommand(words[1]) { 280 | cmd.Action() 281 | } else if !(cmd.SubCommands.HasCommand(words[1])) { 282 | if cmd.StringAction != nil { 283 | cmd.StringAction(words[1]) 284 | } 285 | } 286 | } 287 | } 288 | } 289 | 290 | return 291 | } 292 | -------------------------------------------------------------------------------- /shell/spells/spells.go: -------------------------------------------------------------------------------- 1 | package spells 2 | 3 | type Spells struct { 4 | CastingTime string `json:"casting_time"` 5 | Classes []Classes `json:"classes"` 6 | Components []string `json:"components"` 7 | Concentration string `json:"concentration"` 8 | Desc []string `json:"desc"` 9 | Duration string `json:"duration"` 10 | HigherLevel []string `json:"higher_level"` 11 | ID string `json:"_id"` 12 | Index float64 `json:"index"` 13 | Level float64 `json:"level"` 14 | Material string `json:"material"` 15 | Name string `json:"name"` 16 | Page string `json:"page"` 17 | Range string `json:"range"` 18 | Ritual string `json:"ritual"` 19 | School School `json:"school"` 20 | Subclasses []Subclasses `json:"subclasses"` 21 | URL string `json:"url"` 22 | } 23 | type Classes struct { 24 | Name string `json:"name"` 25 | URL string `json:"url"` 26 | } 27 | type School struct { 28 | Name string `json:"name"` 29 | URL string `json:"url"` 30 | } 31 | type Subclasses struct { 32 | Name string `json:"name"` 33 | URL string `json:"url"` 34 | } 35 | -------------------------------------------------------------------------------- /shell/tables/tables.go: -------------------------------------------------------------------------------- 1 | package Monsters 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/elgs/jsonql" 7 | h "github.com/mitchellh/go-homedir" 8 | "github.com/tatsushid/go-prettytable" 9 | "io/ioutil" 10 | "os" 11 | "strconv" 12 | ) 13 | 14 | var Home, _ = h.Dir() 15 | 16 | type Table struct { 17 | Name string 18 | table map[int]string 19 | } 20 | 21 | type Tables struct { 22 | Tables []Table 23 | jsonString string 24 | } 25 | 26 | func (ms *Tables) List() { 27 | 28 | for i := range ms.Tables { 29 | fmt.Print((ms.Tables[i].Index - 1)) 30 | fmt.Println(" " + ms.Tables[i].Name) 31 | } 32 | return 33 | 34 | } 35 | 36 | func (ms *Tables) TableById(id string) { 37 | n, _ := strconv.Atoi(id) 38 | fmt.Println(ms.Tables[n]) //.Strength) 39 | return 40 | } 41 | 42 | func (ms *Tables) ByName(name string) { 43 | parser, err := jsonql.NewStringQuery(ms.jsonString) 44 | if err != nil { 45 | fmt.Println(err) 46 | return 47 | } 48 | fmt.Println(parser.Query("name='" + name + "'")) 49 | } 50 | 51 | func (ms *Tables) ByGuess(name string) { 52 | parser, err := jsonql.NewStringQuery(ms.jsonString) 53 | if err != nil { 54 | fmt.Println(err) 55 | return 56 | } 57 | fmt.Println(parser.Query("name~='" + name + "'")) 58 | } 59 | 60 | func (ms *Tables) Load() { 61 | jsonFile, err := os.Open(Home + "/go/src/github.com/bsdpunk/dndshell/json/monsters.json") 62 | 63 | if err != nil { 64 | fmt.Println(err) 65 | } 66 | 67 | defer jsonFile.Close() 68 | byteValue, _ := ioutil.ReadAll(jsonFile) 69 | ms.jsonString = string(byteValue) 70 | if err := json.Unmarshal(byteValue, &ms.Tables); err != nil { 71 | fmt.Println(err) 72 | } 73 | //json.Unmarshal(byteValue, &ms) 74 | return 75 | } 76 | -------------------------------------------------------------------------------- /two.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bsdpunk/dndshell/4e438d7ce7f2951ed8b6b8e1429c9e5049321a75/two.gif --------------------------------------------------------------------------------