module DND.Sheet.Parser ( parseSheet , createExample , getStat , getSkill , getSkillMod , getStatMod , getSaveMod , getProficiency , scoreMod ) where --import Control.Monad import Data.Aeson import qualified Data.ByteString.Lazy as B --import qualified Data.ByteString.Lazy.UTF8 as BSU import Data.Maybe (fromJust) import DND.Bob (bob) import DND.Sheet.Content import qualified Data.Map as Map parseSheet :: FilePath -> IO Character parseSheet x = unwrap . decode =<< B.readFile x where unwrap (Just y) = return y unwrap Nothing = error $ "Failed to parse character sheet: " ++ x createExample :: FilePath -> IO () createExample = flip encodeFile bob getStat :: Character -> String -> Stat getStat char s = head . filter (\a -> statName a == s) . stats $ char getSkill :: Character -> String -> Skill getSkill char s = head . filter (\a -> skillName a == s) . skills $ char getProficiency :: Character -> Int getProficiency = fromJust . flip Map.lookup profTable . charLevel . preamble -- https://www.nerdsandscoundrels.com/how-to-calculate-proficiency-bonus-5e/ -- for some fucking reason there appears to be no simple mathematical way to -- get a character's proficiency bonus where profTable = Map.fromList [ (1,2), (2,2), (3,2), (4,2) , (5,3), (6,3), (7,3), (8,3) , (9,4), (10,4), (11,4), (12,4) , (13,5), (14,5), (15,5), (16,5) , (17,6), (18,6), (19,6), (20,6) ] -- https://worldbuildersjunction.com/dungeon-and-dragons-ability-scores-explained-for-beginners/ -- from the Go implementation -- (stat.Score - 10) / 2 scoreMod :: Int -> Int scoreMod x = div (x - 10) 2 getSkillMod :: Character -> String -> Int getSkillMod char skillString = let skill = getSkill char skillString stat = getStat char $ skillStat skill prof = getProficiency char modifier = case skillMod skill of Proficient -> prof Expertise -> prof * 2 Half -> div prof 2 None -> 0 in (modifier +) . scoreMod . statScore $ stat getStatMod :: Character -> String -> Int getStatMod char statString = scoreMod $ statScore (getStat char statString) getSaveMod :: Character -> String -> Int getSaveMod char statString = let stat = getStat char statString modifier = if statProf stat then getProficiency char else 0 in (modifier +) . scoreMod . statScore $ stat