mirror of
https://gitlab.com/EternalWanderer/sheet-parser.git
synced 2025-03-12 13:38:58 +01:00
Start of abstraction
This commit is contained in:
parent
01252f30c3
commit
2389825b02
355
Parser/Parser.go
Normal file
355
Parser/Parser.go
Normal file
|
@ -0,0 +1,355 @@
|
|||
package Parser
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"gitlab.com/EternalWanderer/dice-roller/Dice"
|
||||
)
|
||||
|
||||
const exampleFile string = "/etc/sheet-parser/example.json"
|
||||
|
||||
var (
|
||||
path, pathFlag, skillString, saveString, statString string
|
||||
modifier, diceThrows, surfaces int
|
||||
X, Y int
|
||||
char Character
|
||||
skillMap = make(map[string]int)
|
||||
statMap = make(map[string]int)
|
||||
advantage, disadvantage, stat_list, skill_list, verbose, trivia bool
|
||||
)
|
||||
|
||||
func parseFlags() {
|
||||
flag.StringVar(&pathFlag, "file", pathFlag, "Used to point to character sheet")
|
||||
flag.StringVar(&pathFlag, "f", pathFlag, "Used to point to character sheet")
|
||||
flag.StringVar(&skillString, "skill", "", "Skill to parse")
|
||||
flag.StringVar(&statString, "stat", "", "Stat check")
|
||||
flag.StringVar(&saveString, "save", "", "Saving throw to... throw")
|
||||
|
||||
flag.BoolVar(&advantage, "advantage", advantage, "Roll with advantage")
|
||||
flag.BoolVar(&disadvantage, "disadvantage", disadvantage, "Roll with disadvantage")
|
||||
|
||||
flag.BoolVar(&stat_list, "stat-list", false, "Print list of stats, can also be used with -save flag")
|
||||
flag.BoolVar(&skill_list, "skill-list", false, "Print list of skills to be used in combination with the -skill flag")
|
||||
flag.BoolVar(&verbose, "verbose", false, "Print stat numbers, to be used in combination with -stat-list or -skill-list")
|
||||
flag.BoolVar(&verbose, "v", false, "Print stat numbers, to be used in combination with -stat-list or -skill-list")
|
||||
|
||||
flag.BoolVar(&trivia, "t", false, "Print character name, level and proficiency")
|
||||
flag.BoolVar(&trivia, "trivia", false, "Print character name, level and proficiency")
|
||||
|
||||
flag.Parse()
|
||||
}
|
||||
|
||||
func handleError(err error) {
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func readJson() {
|
||||
envPath, isSet := os.LookupEnv("CHARSHEET")
|
||||
switch {
|
||||
case len(pathFlag) > 0:
|
||||
path = pathFlag
|
||||
case isSet:
|
||||
path = envPath
|
||||
default:
|
||||
path = exampleFile
|
||||
}
|
||||
|
||||
fmt.Println("Opening file:", path)
|
||||
var file, err = os.Open(path)
|
||||
handleError(err)
|
||||
defer file.Close()
|
||||
|
||||
byteValue, _ := ioutil.ReadAll(file)
|
||||
|
||||
err = json.Unmarshal(byteValue, &char)
|
||||
handleError(err)
|
||||
|
||||
}
|
||||
|
||||
func initMaps() {
|
||||
for i := 0; i < len(char.Skills); i++ {
|
||||
skillMap[char.Skills[i].SkillName] = i
|
||||
}
|
||||
|
||||
for i := 0; i < len(char.Stats); i++ {
|
||||
statMap[char.Stats[i].StatName] = i
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
parseFlags()
|
||||
readJson()
|
||||
initMaps()
|
||||
|
||||
switch {
|
||||
|
||||
case trivia:
|
||||
fmt.Printf("Name: %s\tLevel: %d\tProficiency: %d\n", char.Misc.Name, char.Misc.Level, GetProficiency())
|
||||
fmt.Printf("Race: %s\tClass: %s\tBackground: %s\n", char.Misc.Race, char.Misc.Class, char.Misc.Background)
|
||||
|
||||
// passive perception
|
||||
var passivePerception int
|
||||
switch {
|
||||
case GetSkill("perception").Proficient && GetSkill("perception").Expertise:
|
||||
passivePerception = 10 + GetModifier(GetStat("wisdom")) + GetProficiency()*2
|
||||
case GetSkill("perception").Proficient:
|
||||
passivePerception = 10 + GetModifier(GetStat("wisdom")) + GetProficiency()
|
||||
default:
|
||||
passivePerception = 10 + GetModifier(GetStat("wisdom"))
|
||||
}
|
||||
fmt.Printf("Passive perception: %d\n", passivePerception)
|
||||
|
||||
case stat_list && skill_list:
|
||||
printStatList(verbose)
|
||||
printSkillList(verbose)
|
||||
case stat_list:
|
||||
printStatList(verbose)
|
||||
case skill_list:
|
||||
printSkillList(verbose)
|
||||
|
||||
case advantage && disadvantage:
|
||||
fmt.Println("You can't roll with both advantage and disadvantage")
|
||||
os.Exit(1)
|
||||
case len(saveString) > 0:
|
||||
result, plainResult, err := savingThrow(GetStat(saveString))
|
||||
badCheck(saveString, err)
|
||||
if advantage {
|
||||
color.Yellow("Rolling %s saving throw with advantage...", saveString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
color.Green("%d\n", result)
|
||||
} else if disadvantage {
|
||||
color.Yellow("Rolling %s saving throw with disadvantage...", saveString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
color.Red("%d\n", result)
|
||||
} else {
|
||||
color.Yellow("Rolling %s saving throw...", saveString)
|
||||
fmt.Printf("Without modifier: %d\tModifier: %d\n", plainResult, result-plainResult)
|
||||
color.Green("%d\n", result)
|
||||
}
|
||||
|
||||
case len(skillString) > 0 && char.Misc.IsKurthog && strings.Contains(skillString, "performance"):
|
||||
result, plainResult, err := skillCheck(GetSkill(skillString))
|
||||
badCheck(skillString, err)
|
||||
if advantage {
|
||||
color.Yellow("Rolling %s check with advantage...", skillString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
fmt.Printf("Kurthogifier: %d\n", -1)
|
||||
color.Green("%d\n", result*-1)
|
||||
} else if disadvantage {
|
||||
color.Yellow("Rolling %s check with disadvantage...", skillString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
fmt.Printf("Kurthogifier: %d\n", -1)
|
||||
color.Red("%d\n", result*-1)
|
||||
} else {
|
||||
color.Yellow("Rolling %s check...", skillString)
|
||||
fmt.Printf("Without modifier: %d\tModifier: %d\n", plainResult, result-plainResult)
|
||||
fmt.Printf("Kurthogifier: %d\n", -1)
|
||||
color.Green("%d\n", result*-1)
|
||||
}
|
||||
|
||||
case len(skillString) > 0:
|
||||
result, plainResult, err := skillCheck(GetSkill(skillString))
|
||||
badCheck(skillString, err)
|
||||
if advantage {
|
||||
color.Yellow("Rolling %s check with advantage...", skillString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
color.Green("%d\n", result)
|
||||
} else if disadvantage {
|
||||
color.Yellow("Rolling %s check with disadvantage...", skillString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
color.Red("%d\n", result)
|
||||
} else {
|
||||
color.Yellow("Rolling %s check...", skillString)
|
||||
fmt.Printf("Without modifier: %d\tModifier: %d\n", plainResult, result-plainResult)
|
||||
color.Green("%d\n", result)
|
||||
}
|
||||
|
||||
case len(statString) > 0:
|
||||
result, plainResult, err := statCheck(GetStat(statString))
|
||||
badCheck(statString, err)
|
||||
if advantage {
|
||||
color.Yellow("Rolling %s check with advantage...", statString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
color.Green("%d\n", result)
|
||||
} else if disadvantage {
|
||||
color.Yellow("Rolling %s check with disadvantage...", statString)
|
||||
fmt.Printf("x: %d\ty: %d\n", X, Y)
|
||||
fmt.Printf("Modifier: %d\n", result-plainResult)
|
||||
color.Red("%d\n", result)
|
||||
} else {
|
||||
color.Yellow("Rolling %s check...", statString)
|
||||
fmt.Printf("Without modifier: %d\tModifier: %d\n", plainResult, result-plainResult)
|
||||
color.Green("%d\n", result)
|
||||
}
|
||||
|
||||
default:
|
||||
flag.Usage()
|
||||
}
|
||||
}
|
||||
|
||||
func GetProficiency() int {
|
||||
// https://worldbuildersjunction.com/what-is-proficiency-bonus-in-dd-5e-how-it-works-calculated/
|
||||
return (char.Misc.Level-1)/4 + 2
|
||||
}
|
||||
|
||||
func GetSkill(skillName string) Skill {
|
||||
return char.Skills[skillMap[skillName]]
|
||||
}
|
||||
|
||||
func GetStat(statName string) Stat {
|
||||
return char.Stats[statMap[statName]]
|
||||
}
|
||||
|
||||
func GetModifier(stat Stat) int {
|
||||
// https://worldbuildersjunction.com/dungeon-and-dragons-ability-scores-explained-for-beginners/
|
||||
return (stat.Score - 10) / 2
|
||||
}
|
||||
|
||||
func rollDice() int {
|
||||
var die int
|
||||
switch {
|
||||
case advantage:
|
||||
die, X, Y = Dice.Advantage()
|
||||
case disadvantage:
|
||||
die, X, Y = Dice.Disadvantage()
|
||||
default:
|
||||
die = Dice.SimpleCast()
|
||||
}
|
||||
switch die {
|
||||
case 20:
|
||||
color.Magenta("Natural 20!\n")
|
||||
case 1:
|
||||
color.Magenta("Natural 1!\n")
|
||||
}
|
||||
return die
|
||||
}
|
||||
func badCheck(errorMessage string, err error) {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
fmt.Println(err)
|
||||
fmt.Println(errorMessage)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func statErrorCheck() error {
|
||||
for i := 0; i < len(char.Stats); i++ {
|
||||
if statString == char.Stats[i].StatName || saveString == char.Stats[i].StatName {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("Unknown stat:")
|
||||
}
|
||||
|
||||
func skillErrorCheck() error {
|
||||
for i := 0; i < len(char.Skills); i++ {
|
||||
if skillString == char.Skills[i].SkillName {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return errors.New("Unknown skill:")
|
||||
}
|
||||
|
||||
func statCheck(stat Stat) (int, int, error) {
|
||||
die := rollDice()
|
||||
return die + GetModifier(stat), die, statErrorCheck()
|
||||
|
||||
}
|
||||
|
||||
func savingThrow(stat Stat) (int, int, error) {
|
||||
die := rollDice()
|
||||
plainDie := die
|
||||
|
||||
if stat.Proficient {
|
||||
die += GetProficiency()
|
||||
}
|
||||
return die + GetModifier(stat), plainDie, statErrorCheck()
|
||||
}
|
||||
|
||||
func skillCheck(skill Skill) (int, int, error) {
|
||||
die := rollDice()
|
||||
if char.Misc.ReliableTalent && skill.Proficient && die < 10 {
|
||||
die = 10
|
||||
}
|
||||
plainDie := die
|
||||
|
||||
die += GetModifier(GetStat(skill.BaseStat))
|
||||
|
||||
switch {
|
||||
case skill.Expertise:
|
||||
die += GetProficiency() * 2
|
||||
case skill.Proficient:
|
||||
die += GetProficiency()
|
||||
case !skill.Proficient && char.Misc.JackOfAllTrades:
|
||||
die += (GetProficiency() / 2)
|
||||
}
|
||||
return die, plainDie, skillErrorCheck()
|
||||
}
|
||||
|
||||
func printStatList(verbose bool) {
|
||||
color.Magenta("Listing stats...")
|
||||
if verbose {
|
||||
var proficiency string
|
||||
for i := 0; i < len(char.Stats); i++ {
|
||||
name := char.Stats[i].StatName
|
||||
isProficient := char.Stats[i].Proficient
|
||||
if isProficient {
|
||||
proficiency = "Proficient"
|
||||
} else {
|
||||
proficiency = "Not proficient"
|
||||
}
|
||||
score := char.Stats[i].Score
|
||||
fmt.Printf("Stat: %13s\t%s\tStat score: %2d\tStat modifier: %2d\n", name, proficiency, score, GetModifier(char.Stats[i]))
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(char.Stats); i++ {
|
||||
fmt.Println(char.Stats[i].StatName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func printSkillList(verbose bool) {
|
||||
color.Magenta("Listing skills...")
|
||||
var proficiency string
|
||||
var expertise string
|
||||
if verbose {
|
||||
for i := 0; i < len(char.Skills); i++ {
|
||||
name := char.Skills[i].SkillName
|
||||
localModifier := GetModifier(GetStat(char.Skills[i].BaseStat))
|
||||
if char.Skills[i].Proficient {
|
||||
proficiency = "Proficient"
|
||||
localModifier += GetProficiency()
|
||||
} else {
|
||||
proficiency = "Not proficient"
|
||||
}
|
||||
if char.Skills[i].Expertise {
|
||||
expertise = "Has expertise"
|
||||
localModifier += GetProficiency()
|
||||
} else {
|
||||
expertise = "Doesn't have expertise"
|
||||
}
|
||||
fmt.Printf("Skill:%16s\tSkill modifier:%3d\t%s\t%s\n", name, localModifier, proficiency, expertise)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(char.Skills); i++ {
|
||||
fmt.Println(char.Skills[i].SkillName)
|
||||
}
|
||||
}
|
||||
}
|
29
Parser/sheetContent.go
Normal file
29
Parser/sheetContent.go
Normal file
|
@ -0,0 +1,29 @@
|
|||
package Parser
|
||||
|
||||
type Character struct {
|
||||
Misc Misc `json:"misc"`
|
||||
Stats []Stat `json:"stats"`
|
||||
Skills []Skill `json:"skills"`
|
||||
}
|
||||
|
||||
type Misc struct {
|
||||
Level int `json:"level"`
|
||||
Name string `json:"name"`
|
||||
Race string `json:"race"`
|
||||
Class string `json:"class"`
|
||||
Background string `json:"background"`
|
||||
ReliableTalent bool `json:"reliableTalent"`
|
||||
JackOfAllTrades bool `json:"jackOfAllTrades"`
|
||||
IsKurthog bool `json:"isKurthog"`
|
||||
}
|
||||
type Skill struct {
|
||||
SkillName string `json:"skillName"`
|
||||
Proficient bool `json:"proficient"`
|
||||
Expertise bool `json:"expertise"`
|
||||
BaseStat string `json:"baseStat"`
|
||||
}
|
||||
type Stat struct {
|
||||
StatName string `json:"statName"`
|
||||
Score int `json:"score"`
|
||||
Proficient bool `json:"proficient"`
|
||||
}
|
Loading…
Reference in a new issue