diff --git a/D&D_5e_Reshaped/D&D_5e.css b/D&D_5e_Reshaped/D&D_5e.css index db252f038c..8e39bb008b 100644 --- a/D&D_5e_Reshaped/D&D_5e.css +++ b/D&D_5e_Reshaped/D&D_5e.css @@ -1 +1 @@ -*,.sheet-rolltemplate-5e-shaped *{box-sizing:border-box;line-height:100%}::-webkit-scrollbar{height:.5em;width:.5em}::-webkit-scrollbar-thumb{background:#708090;border-radius:10px}body{scrollbar-face-color:#708090}.sheet-wrapper,input,select,textarea{font-size:12px}button[type=roll]{background-image:none;border:0;box-shadow:none;-webkit-box-shadow:none;text-align:left;text-shadow:initial}button[type=roll].btn{font-size:inherit;margin:0}button[type=roll].btn:not(.sheet-visible-button){background-color:transparent;padding:0}button[type=roll].btn:not(.sheet-visible-button):hover,button[type=roll].btn:not(.sheet-visible-button):hover input{color:#3f88e6!important}button[type=roll].btn.sheet-visible-button{background-color:#3f88e6;border-radius:3px;box-shadow:0 2px 5px 0 rgba(0,0,0,.26);color:rgba(255,255,255,.87);padding:3px}button[type=roll].btn.sheet-visible-button:hover{color:rgba(255,255,255,.87)}button[type=roll].btn.sheet-visible-button:active{box-shadow:0 4px 8px 0 rgba(0,0,0,.4)}button[type=roll]:hover{background-position:initial}button[type=roll]::before{content:''!important}button[type=roll]:active{box-shadow:none;-webkit-box-shadow:none}button.repcontrol_add,button.repcontrol_edit{font-size:10px;padding:1px 3px}button.repcontrol_del{font-size:13px;padding:0 3px 2px;position:relative;z-index:99999}button.repcontrol_add,button.repcontrol_del,button.repcontrol_edit{border-radius:3px;width:auto!important}.btn.repcontrol_move{padding:2px 6px;background:0 0;border:none;font-size:16px;font-weight:700;position:relative;z-index:99999}.sheet-wrapper-button{width:100%}p{margin:0}ol,ul{margin:0 0 0 15px}button,input[type=number],input[type=text],select,textarea{border-left:0;border-right:0;border-top:0;border-radius:0;box-shadow:none;margin-bottom:0!important;padding:1px}button.sheet-no-border,input[type=number].sheet-no-border,input[type=text].sheet-no-border,select.sheet-no-border,textarea.sheet-no-border{border-bottom:0}button:focus,input[type=number]:focus,input[type=text]:focus,select:focus,textarea:focus{outline:0}.sheet-border-bottom{border-bottom:1px solid #ccc}input[type=number],input[type=text],select,textarea{width:100%!important}select{-moz-appearance:none;-webkit-appearance:none;appearance:none;height:17px}input[type=number]{text-align:center}.sheet-pseudo-input{display:block;padding:2px;min-height:17px}input[disabled],input[readonly],input[type=number].sheet-no-spin{-moz-appearance:textfield}input[disabled]{background-color:transparent;cursor:inherit}input[disabled]::-webkit-inner-spin-button,input[disabled]::-webkit-outer-spin-button,input[readonly]::-webkit-inner-spin-button,input[readonly]::-webkit-outer-spin-button,input[type=number].sheet-no-spin::-webkit-inner-spin-button,input[type=number].sheet-no-spin::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.sheet-float-right{float:right}.sheet-mar-t-sm{margin-top:2px}.sheet-pad-t-sm{padding-top:2px}.sheet-rolltemplate-5e-shaped .sheet-mar-t-sm{margin-top:2px!important}.sheet-mar-t-smd{margin-top:4px}.sheet-pad-t-smd{padding-top:4px}.sheet-mar-t-md{margin-top:5px}.sheet-pad-t-md{padding-top:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-t-md{margin-top:5px!important}.sheet-mar-t-lg{margin-top:10px}.sheet-pad-t-lg{padding-top:10px}.sheet-mar-t-xl{margin-top:15px}.sheet-pad-t-xl{padding-top:15px}.sheet-mar-t-xxl{margin-top:20px}.sheet-pad-t-xxl{padding-top:20px}.sheet-mar-r-sm{margin-right:2px}.sheet-pad-r-sm{padding-right:2px}.sheet-mar-r-smd{margin-right:4px}.sheet-pad-r-smd{padding-right:4px}.sheet-mar-r-md{margin-right:5px}.sheet-pad-r-md{padding-right:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-r-md{margin-right:5px!important}.sheet-mar-r-lg{margin-right:10px}.sheet-pad-r-lg{padding-right:10px}.sheet-mar-r-xl{margin-right:15px}.sheet-pad-r-xl{padding-right:15px}.sheet-mar-r-xxl{margin-right:20px}.sheet-pad-r-xxl{padding-right:20px}.sheet-mar-b-sm{margin-bottom:2px}.sheet-pad-b-sm{padding-bottom:2px}.sheet-pad-b-smd{padding-bottom:4px}.sheet-mar-b-md{margin-bottom:5px}.sheet-pad-b-md{padding-bottom:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-b-md{margin-bottom:5px!important}.sheet-mar-b-lg{margin-bottom:10px}.sheet-pad-b-lg{padding-bottom:10px}.sheet-mar-b-xl{margin-bottom:15px}.sheet-pad-b-xl{padding-bottom:15px}.sheet-mar-b-xxl{margin-bottom:20px}.sheet-pad-b-xxl{padding-bottom:20px}.sheet-mar-l-sm{margin-left:2px}.sheet-pad-l-sm{padding-left:2px}.sheet-mar-l-smd{margin-left:4px}.sheet-pad-l-smd{padding-left:4px}.sheet-mar-l-md{margin-left:5px}.sheet-pad-l-md{padding-left:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-l-md{margin-left:5px!important}.sheet-mar-l-lg{margin-left:10px}.sheet-pad-l-lg{padding-left:10px}.sheet-mar-l-xl{margin-left:15px}.sheet-pad-l-xl{padding-left:15px}.sheet-mar-l-xxl{margin-left:20px}.sheet-pad-l-xxl{padding-left:20px}.sheet-hidden{display:none!important}.sheet-mar-b-smd{margin-bottom:4px}.sheet-wrapper{min-width:834px}.charsheet{background:url(http://i.imgur.com/RggDtsN.png) #ededed;margin-top:-10px;padding:2px 3px!important}.sheet-slide-input-pc:checked~.sheet-pc,.sheet-slide-input-pc:checked~div .sheet-pc,.sheet-slide-input-pc:not(:checked)~.sheet-npc,.sheet-slide-input-pc:not(:checked)~div .sheet-npc{display:none}.sheet-small-note{font-size:10px;text-align:center}.sheet-wrap-box{background-color:#fff;border:1px solid #000;border-radius:3px;padding:2px}.sheet-tooltip-position-wrapper{position:absolute;top:1px;right:1px;z-index:99}.sheet-tooltip{position:relative}.sheet-tooltip-toggle-text{background-color:#000;border-radius:50%;color:#fff;font-size:77%;font-weight:700;height:10px;width:10px;padding:1px 2px}[class*=sheet-tooltip-content]{background-color:#000;border-bottom-right-radius:4px;border-bottom-left-radius:4px;color:#fff;margin-top:-15px;opacity:.9;padding:4px;position:absolute;width:260px;text-align:left;visibility:hidden;z-index:99}[class*=sheet-tooltip-content]::after{border-bottom:8px solid transparent;border-top:8px solid transparent;content:'';margin-top:-8px;position:absolute;top:9px}.sheet-character-name .sheet-wrap-box-label,.sheet-shield .sheet-wrap-box-title{margin-top:1px}.sheet-tooltip-small{width:80px}.sheet-tooltip-content-left{border-top-left-radius:4px;margin-right:12px;right:100%}.sheet-tooltip-content-right{border-top-right-radius:4px;left:100%;margin-left:12px}.sheet-tooltip-content-left::after{border-left:8px solid #000;right:-8px}.sheet-tooltip-content-right::after{border-right:8px solid #000;left:-8px}.sheet-tooltip:focus [class*=sheet-tooltip-content],.sheet-tooltip:hover [class*=sheet-tooltip-content]{visibility:visible;z-index:999}.sheet-dnd-image-wrapper{margin-bottom:1px}.sheet-dnd-image-wrapper img{display:block;max-height:27px}.sheet-character-name input[type=text]{border:1px solid #000;border-bottom-left-radius:5px!important;border-right-width:0;border-top-left-radius:5px!important;font-size:22px;font-weight:700;padding:0 2px}.sheet-ability-wrapper{height:68px;margin-bottom:12px;position:relative}.sheet-ability-wrapper .sheet-ability-score-wrapper{background-color:#fff;border:1px solid #000;border-radius:50%;bottom:-8px;left:0;margin-right:auto;margin-left:auto;padding:2px;position:absolute;right:0;width:40px!important}.sheet-ability-wrapper .sheet-ability-score-wrapper input{font-size:11px;background:0 0;border-radius:50%}.sheet-ability-name{font-size:9px;font-weight:700;text-transform:uppercase}.sheet-ability-modifier{font-size:24px;font-weight:700;padding-bottom:5px!important;padding-top:6px!important}.sheet-spell-slots-points input[type=number]{background-color:transparent;font-size:12px;padding:0}.sheet-attacks input[readonly],.sheet-gray-bg,.sheet-resource input[readonly],.sheet-spell input[readonly]{background:#dedede}.sheet-flex-grow{flex-grow:1}.sheet-no-shrink{flex-shrink:0}.sheet-inline{display:inline}.sheet-inline-block{display:inline-block}.sheet-block{display:block}.sheet-pre-line{white-space:pre-line}.sheet-relative,.sheet-rolltemplate-5e-shaped .sheet-relative{position:relative}.sheet-absolute{position:absolute;top:0}.sheet-section-core .sheet-ability-saving-throw-name,.sheet-section-core .sheet-skill-name{font-size:11px}.sheet-section-core .sheet-heading{font-weight:700;font-style:italic;margin-left:8px}.sheet-skill-ability{color:#a0a0a0;font-size:10px}.sheet-skills select{padding:0}.sheet-skills-ability-selector{background:0 0;border-bottom:0;color:#909090;height:11px;position:relative;width:25px!important;z-index:2}.sheet-skill-select-wrapper select{font-size:14px;height:16px}select.sheet-skills-ability-selector{font-size:9px}.sheet-parenthesis-wrapper,.sheet-skills-ability-selector-wrapper{display:inline-block;position:relative}.sheet-parenthesis-wrapper::after,.sheet-parenthesis-wrapper::before,.sheet-skills-ability-selector-wrapper::after,.sheet-skills-ability-selector-wrapper::before{color:#909090;position:absolute;top:0}.sheet-parenthesis-wrapper::before,.sheet-skills-ability-selector-wrapper::before{content:'('}.sheet-parenthesis-wrapper::after,.sheet-skills-ability-selector-wrapper::after{content:')';right:1px}.sheet-parenthesis-wrapper input,.sheet-skills-ability-selector-wrapper input{padding-left:3px;padding-right:3px}.sheet-shield{height:55px;margin-left:auto;margin-right:auto;width:52px;padding-top:7px;padding-right:2px;position:relative;z-index:10}.sheet-shield::before{color:#fff;content:'b';font-family:'Pictos Three';font-size:72px;left:-1px;line-height:51px;position:absolute;text-shadow:-1px 0 #000,0 1px #000,1px 0 #000,0 -1px #000;top:3px;z-index:-1}.sheet-shield .sheet-big-text{padding:1px}.sheet-bold,.sheet-rolltemplate-5e-shaped .sheet-bold{font-weight:700}.sheet-italic,.sheet-rolltemplate-5e-shaped .sheet-italic{font-style:italic}.sheet-capitalize{text-transform:capitalize!important}.sheet-uppercase{text-transform:uppercase!important}.sheet-big-text{font-size:16px}.sheet-initiative .sheet-big-text,.sheet-speed .sheet-big-text{padding:.4em}.sheet-heart-divider{font-size:15px}.sheet-wrap-box-label,.sheet-wrap-box-title{text-transform:uppercase}.sheet-wrap-box-title{font-weight:700;font-size:9px;margin:5px 0 0}.sheet-wrap-box-label{font-size:80%}.sheet-light-label{color:#a0a0a0}.sheet-heart,.sheet-temp-heart{height:68px;width:80px;margin-left:auto;margin-right:auto;margin-top:4px;position:relative;z-index:4}.sheet-heart::after,.sheet-temp-heart::after{position:absolute;z-index:-1;top:21px;left:0;content:'k';font-family:Pictos;font-size:90px;color:#fff;text-shadow:-1px 0 #000,0 1px #000,1px 0 #000,0 -1px #000}.sheet-heart>.sheet-shaped-row,.sheet-temp-heart>.sheet-shaped-row{padding-top:8px}.sheet-heart input[type=number],.sheet-temp-heart input[type=number]{border-radius:7px;padding:1px;background-color:transparent}.sheet-temp-heart{margin-top:10px;height:54px;width:63px}.sheet-temp-heart::after{top:16px;font-size:70px}.sheet-temp-heart>.sheet-shaped-row{padding-top:10px}.sheet-temp-heart .sheet-wrap-box-title{margin-top:2px}[class^=sheet-checkbox-label]{cursor:pointer;white-space:nowrap;margin-bottom:0;padding-right:0;font-weight:400}.sheet-white-space-no-wrap{white-space:nowrap}.sheet-checkbox-label-sm{font-size:9px}.sheet-checkbox-label-sm input[type=checkbox]{-webkit-transform:scale(.6);transform:scale(.6);height:10px;margin-top:-1px}.sheet-checkbox-label-md{font-size:85%}.sheet-checkbox-label-md input[type=checkbox]{-webkit-transform:scale(.7);transform:scale(.7);margin-top:-1px}.sheet-checkbox-label{display:inline-block;font-size:100%}.sheet-checkbox-label [type=checkbox]{display:none}.sheet-checkbox-label [type=checkbox]+span{display:inline-block;padding:1px;text-align:center;font-weight:700}.sheet-exhaustion,.sheet-inspiration,.sheet-proficiency-bonus{margin-left:3px}.sheet-exhaustion .sheet-wrap-box-title,.sheet-inspiration .sheet-wrap-box-title,.sheet-proficiency-bonus .sheet-wrap-box-title{margin-bottom:3px}.sheet-big-font{font-size:15px}.sheet-exhaustion-wrapper,.sheet-inspiration .sheet-checkbox-label span,.sheet-proficiency-bonus-wrapper{border:1px solid #000;height:27px;left:-5px;top:-3px;position:absolute;width:27px!important}.sheet-exhaustion-wrapper,.sheet-proficiency-bonus-wrapper{background-color:#fff;border-radius:50%;padding:3px}.sheet-proficiency-bonus .sheet-wrap-box-title{margin-left:22px}.sheet-exhaustion .sheet-wrap-box-title,.sheet-inspiration .sheet-wrap-box-title{margin-left:24px}.sheet-coin{margin-left:-8px}.sheet-coin-value-wrap{position:relative;left:-2px}.sheet-inspiration .sheet-checkbox-label span{border-radius:3px}.sheet-inspiration .sheet-checkbox-label [type=checkbox]+span{background-color:#fff}.sheet-inspiration .sheet-checkbox-label [type=checkbox]:checked+span{background-image:url(http://i.imgur.com/m5WFImZ.png)}.sheet-inspiration .sheet-small-input{font-size:10px;padding:0}.sheet-death-saving-throw .sheet-checkbox-label{height:14px;width:14px;margin:0 2px;position:relative;z-index:5}.sheet-death-saving-throw .sheet-checkbox-label [type=checkbox]+span{background-color:#fff;border:1px solid #000;border-radius:50%;height:14px;width:14px}.sheet-death-saving-throw [type=radio]{margin:1px;opacity:0;position:relative;z-index:9999}.sheet-death-saving-throw [type=radio],.sheet-death-saving-throw [type=radio]+span{height:14px;width:14px}.sheet-death-saving-throw [type=radio]+span{border:1px solid #000;border-radius:50%;display:inline-block;margin-left:-14px;position:relative;vertical-align:middle;z-index:5}.sheet-death-saving-throw [type=radio]:first-of-type,.sheet-death-saving-throw [type=radio]:first-of-type+span{left:-12px;position:absolute;top:1px}.sheet-death-saving-throw [type=radio]:first-of-type+span{background-color:#fff;border:none;color:#980000;font-size:15px;margin-left:0}.sheet-death-saving-throw [type=radio]:first-of-type:checked+span{opacity:0}.sheet-death-saving-throw [type=radio]:checked~input[type=radio]+span{background-color:#fff}.sheet-death-succeed [type=radio]+span{background-color:#879a6a}.sheet-death-fail [type=radio]+span{background-color:#8c6075}.sheet-death-saving-throw-hr{top:2px;width:100%}.sheet-rolltemplate-5e-shaped{margin-left:-34px;margin-right:-4px}.sheet-rolltemplate-5e-shaped .sheet-no-border{border-bottom:0!important}.sheet-rolltemplate-5e-shaped a[href^="~"]{background-color:transparent;border:none;color:#ce0f69;display:inline;padding:0}.withoutavatars .sheet-rolltemplate-5e-shaped{margin-left:-4px}.sheet-rolltemplate-5e-shaped .sheet-rt-card{background-color:#fff;border:1px solid #000;border-radius:3px;box-sizing:border-box;font-size:12px;margin-right:10px;padding:4px 0 2px}.sheet-rolltemplate-5e-shaped .inlinerollresult{background:0 0;border:2px solid transparent}.sheet-rolltemplate-5e-shaped .sheet-rt-header{background-color:#5c5c5c;background-image:linear-gradient(rgba(255,255,255,.3),rgba(255,255,255,0));box-shadow:0 2px 0 rgba(0,0,0,.3);color:#fff;margin:0 -10px 2px;padding:3px;text-align:center}.sheet-rolltemplate-5e-shaped .sheet-rt-header .inlinerollresult{border:none;padding:0;font-weight:400;font-size:100%}.sheet-rolltemplate-5e-shaped .sheet-rt-header::after,.sheet-rolltemplate-5e-shaped .sheet-rt-header::before{content:'';position:absolute;border-style:solid;border-color:transparent;bottom:-10px}.sheet-rolltemplate-5e-shaped .sheet-rt-header::before{border-width:0 10px 10px 0;border-right-color:#222;left:0}.sheet-rolltemplate-5e-shaped .sheet-rt-header::after{border-width:0 0 10px 10px;border-left-color:#222;right:0}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-action,.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-attack{background-color:#2c5d28}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-action::before,.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-attack::before{border-right-color:#375035}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-action::after,.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-attack::after{border-left-color:#375035}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-spell{background-color:#45285d}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-spell::before{border-right-color:#443550}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-spell::after{border-left-color:#443550}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-ability{background-color:#28595d}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-ability::before{border-right-color:#354e50}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-ability::after{border-left-color:#354e50}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-saving-throw{background-color:#5d2828}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-saving-throw::before{border-right-color:#503535}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-saving-throw::after{border-left-color:#503535}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-death-saving-throw{background-color:#240f0f}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-death-saving-throw::before{border-right-color:#1f1414}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-death-saving-throw::after{border-left-color:#1f1414}.sheet-rolltemplate-5e-shaped .inlinerollresult{border-radius:3px;font-size:105%;line-height:130%;padding:0 3px}.sheet-rolltemplate-5e-shaped .sheet-rt-title{font-size:1.7em}.sheet-rolltemplate-5e-shaped .sheet-rt-subheader{line-height:1.2em}.sheet-rolltemplate-5e-shaped .sheet-rt-content>div{padding:2px 3px}.sheet-rolltemplate-5e-shaped .sheet-rt-content>div:not(:last-of-type){border-top:0;border-left:0;border-right:0;border-bottom:1px;border-image:linear-gradient(to right,transparent,rgba(0,0,0,.75),transparent) 1}.sheet-rolltemplate-5e-shaped .sheet-shaped-row{padding:2px}.sheet-rolltemplate-5e-shaped .sheet-rt-emote{border:1px dashed green;border-radius:3px;font-family:Arial;font-size:11px;font-style:italic;margin:0 3px 2px;padding:0 4px;text-align:center}.sheet-rolltemplate-5e-shaped .sheet-output{font-size:1.7em;text-align:center}.sheet-rolltemplate-5e-shaped .sheet-output-small-label{color:#676767;font-style:italic;text-align:center}.sheet-rolltemplate-5e-shaped .sheet-less-important{color:#A2A2A2}div[class='repcontainer editmode']~div[class^=repcontrol] button[class='btn repcontrol_add']{display:inline-block!important;visibility:hidden}[class^=sheet-section-],input[value=de]:not(:checked)~div .sheet-de,input[value=de]:not(:checked)~label .sheet-de,input[value=de]:not(:checked)~span .sheet-de,input[value=en]:not(:checked)~div .sheet-en,input[value=en]:not(:checked)~label .sheet-en,input[value=en]:not(:checked)~span .sheet-en,input[value=es]:not(:checked)~div .sheet-es,input[value=es]:not(:checked)~label .sheet-es,input[value=es]:not(:checked)~span .sheet-es,input[value=fr]:not(:checked)~div .sheet-fr,input[value=fr]:not(:checked)~label .sheet-fr,input[value=fr]:not(:checked)~span .sheet-fr,input[value=ru]:not(:checked)~div .sheet-ru,input[value=ru]:not(:checked)~label .sheet-ru,input[value=ru]:not(:checked)~span .sheet-ru{display:none}input[class^=sheet-toggle-],span[class^=sheet-toggle-]{vertical-align:top}.sheet-vert-middle{vertical-align:middle}input[class^=sheet-toggle-]{cursor:pointer;opacity:0;position:relative;z-index:9999}span[class^=sheet-toggle-]{background-color:#a19a91;border-radius:3px;color:#fff;cursor:pointer;display:inline-block;font-size:10px;padding:1px;position:relative;text-align:center}input.sheet-toggle-page-core,span.sheet-toggle-page-core{width:36px}span.sheet-toggle-page-core{margin-left:-36px}input.sheet-toggle-page-spells,span.sheet-toggle-page-spells{width:43px}input.sheet-toggle-page-character,input.sheet-toggle-page-equipment,span.sheet-toggle-page-character,span.sheet-toggle-page-equipment{width:69px}span.sheet-toggle-page-spells{margin-left:-43px}span.sheet-toggle-page-character,span.sheet-toggle-page-equipment{margin-left:-69px}input.sheet-toggle-page-settings,span.sheet-toggle-page-settings{width:19px}span.sheet-toggle-page-settings{margin-left:-19px}input.sheet-toggle-page-all,span.sheet-toggle-page-all{width:24px}span.sheet-toggle-page-all{margin-left:-24px}input.sheet-toggle-icon-attack-settings,span.sheet-toggle-icon-attack-settings{width:17px}span.sheet-toggle-icon-attack-settings{margin-left:-17px}input.sheet-toggle-edit-mode,span.sheet-toggle-edit-mode{width:23px}input.sheet-toggle-hd-d2,input.sheet-toggle-hd-d4,input.sheet-toggle-hd-d6,input.sheet-toggle-hd-d8,span.sheet-toggle-hd-d2,span.sheet-toggle-hd-d4,span.sheet-toggle-hd-d6,span.sheet-toggle-hd-d8{width:16px}span.sheet-toggle-edit-mode{margin-left:-23px}span.sheet-toggle-hd-d2,span.sheet-toggle-hd-d4,span.sheet-toggle-hd-d6,span.sheet-toggle-hd-d8{margin-left:-16px}input.sheet-toggle-hd-d10,input.sheet-toggle-hd-d12,input.sheet-toggle-hd-d20,span.sheet-toggle-hd-d10,span.sheet-toggle-hd-d12,span.sheet-toggle-hd-d20{width:22px}span.sheet-toggle-hd-d10,span.sheet-toggle-hd-d12,span.sheet-toggle-hd-d20{margin-left:-22px}input.sheet-toggle-emote,span.sheet-toggle-emote{width:36px}span.sheet-toggle-emote{margin-left:-36px}input.sheet-toggle-attack,span.sheet-toggle-attack{width:35px}span.sheet-toggle-attack{margin-left:-35px}input.sheet-toggle-reach,span.sheet-toggle-reach{width:36px}span.sheet-toggle-reach{margin-left:-36px}input.sheet-toggle-range,span.sheet-toggle-range{width:37px}span.sheet-toggle-range{margin-left:-37px}input.sheet-toggle-target,span.sheet-toggle-target{width:36px}span.sheet-toggle-target{margin-left:-36px}input.sheet-toggle-ammo,span.sheet-toggle-ammo{width:35px}span.sheet-toggle-ammo{margin-left:-35px}input.sheet-toggle-ammo-auto,span.sheet-toggle-ammo-auto{width:28px}input.sheet-toggle-damage,input.sheet-toggle-sv-damage,span.sheet-toggle-damage,span.sheet-toggle-sv-damage{width:27px}span.sheet-toggle-ammo-auto{margin-left:-28px}span.sheet-toggle-damage,span.sheet-toggle-sv-damage{margin-left:-27px}input.sheet-toggle-alt-damage,span.sheet-toggle-alt-damage{width:18px}input.sheet-toggle-second-damage,input.sheet-toggle-sv-second-damage,span.sheet-toggle-second-damage,span.sheet-toggle-sv-second-damage{width:56px}span.sheet-toggle-alt-damage{margin-left:-18px}span.sheet-toggle-second-damage,span.sheet-toggle-sv-second-damage{margin-left:-56px}input.sheet-toggle-crit,span.sheet-toggle-crit{width:21px}input.sheet-toggle-bonus,input.sheet-toggle-crit-bonus,span.sheet-toggle-bonus,span.sheet-toggle-crit-bonus{width:36px}span.sheet-toggle-crit{margin-left:-21px}span.sheet-toggle-bonus,span.sheet-toggle-crit-bonus{margin-left:-36px}input.sheet-toggle-bonuses,input.sheet-toggle-spells-filter-prepared,input.sheet-toggle-spells-prepared,span.sheet-toggle-bonuses,span.sheet-toggle-spells-filter-prepared,span.sheet-toggle-spells-prepared{width:47px}span.sheet-toggle-bonuses,span.sheet-toggle-spells-filter-prepared,span.sheet-toggle-spells-prepared{margin-left:-47px}input.sheet-toggle-spells-filter-ritual,input.sheet-toggle-spells-ritual,span.sheet-toggle-spells-filter-ritual,span.sheet-toggle-spells-ritual{width:30px}span.sheet-toggle-spells-filter-ritual,span.sheet-toggle-spells-ritual{margin-left:-30px}input.sheet-toggle-spells-concentration,input.sheet-toggle-spells-filter-concentration,span.sheet-toggle-spells-concentration,span.sheet-toggle-spells-filter-concentration{width:69px}span.sheet-toggle-spells-concentration,span.sheet-toggle-spells-filter-concentration{margin-left:-69px}input.sheet-toggle-spells-filter-somatic,input.sheet-toggle-spells-filter-verbal,span.sheet-toggle-spells-filter-somatic,span.sheet-toggle-spells-filter-verbal{width:13px}span.sheet-toggle-spells-filter-somatic,span.sheet-toggle-spells-filter-verbal{margin-left:-13px}input.sheet-toggle-spells-filter-material,span.sheet-toggle-spells-filter-material{width:14px}input.sheet-toggle-spell-vsm-s,input.sheet-toggle-spell-vsm-v,span.sheet-toggle-spell-vsm-s,span.sheet-toggle-spell-vsm-v{width:13px}span.sheet-toggle-spells-filter-material{margin-left:-14px}span.sheet-toggle-spell-vsm-s,span.sheet-toggle-spell-vsm-v{margin-left:-13px}input.sheet-toggle-spell-vsm-m,span.sheet-toggle-spell-vsm-m{width:14px}span.sheet-toggle-spell-vsm-m{margin-left:-14px}input.sheet-toggle-spell-filters,span.sheet-toggle-spell-filters{width:33px}span.sheet-toggle-spell-filters{margin-left:-33px}input.sheet-toggle-spells-filter-level-cantrips,span.sheet-toggle-spells-filter-level-cantrips{width:43px}span.sheet-toggle-spells-filter-level-cantrips{margin-left:-43px}input.sheet-toggle-spells-filter-level-all,span.sheet-toggle-spells-filter-level-all{width:17px}input.sheet-toggle-spells-filter-level-1,input.sheet-toggle-spells-filter-level-2,input.sheet-toggle-spells-filter-level-3,input.sheet-toggle-spells-filter-level-4,input.sheet-toggle-spells-filter-level-5,input.sheet-toggle-spells-filter-level-6,input.sheet-toggle-spells-filter-level-7,input.sheet-toggle-spells-filter-level-8,input.sheet-toggle-spells-filter-level-9,span.sheet-toggle-spells-filter-level-1,span.sheet-toggle-spells-filter-level-2,span.sheet-toggle-spells-filter-level-3,span.sheet-toggle-spells-filter-level-4,span.sheet-toggle-spells-filter-level-5,span.sheet-toggle-spells-filter-level-6,span.sheet-toggle-spells-filter-level-7,span.sheet-toggle-spells-filter-level-8,span.sheet-toggle-spells-filter-level-9{width:11px}span.sheet-toggle-spells-filter-level-all{margin-left:-17px}span.sheet-toggle-spells-filter-level-1,span.sheet-toggle-spells-filter-level-2,span.sheet-toggle-spells-filter-level-3,span.sheet-toggle-spells-filter-level-4,span.sheet-toggle-spells-filter-level-5,span.sheet-toggle-spells-filter-level-6,span.sheet-toggle-spells-filter-level-7,span.sheet-toggle-spells-filter-level-8,span.sheet-toggle-spells-filter-level-9{margin-left:-11px}input.sheet-toggle-spells-filter-casting-time-all,span.sheet-toggle-spells-filter-casting-time-all{width:17px}span.sheet-toggle-spells-filter-casting-time-all{margin-left:-17px}input.sheet-toggle-spells-filter-casting-time-reaction,span.sheet-toggle-spells-filter-casting-time-reaction{width:43px}span.sheet-toggle-spells-filter-casting-time-reaction{margin-left:-43px}input.sheet-toggle-spells-filter-casting-time-bonus,span.sheet-toggle-spells-filter-casting-time-bonus{width:35px}span.sheet-toggle-spells-filter-casting-time-bonus{margin-left:-35px}input.sheet-toggle-spells-filter-casting-time-action,span.sheet-toggle-spells-filter-casting-time-action{width:34px}span.sheet-toggle-spells-filter-casting-time-action{margin-left:-34px}input.sheet-toggle-description,span.sheet-toggle-description{width:57px}span.sheet-toggle-description{margin-left:-57px}input.sheet-toggle-saving-throw,span.sheet-toggle-saving-throw{width:30px}span.sheet-toggle-saving-throw{margin-left:-30px}input.sheet-toggle-heal,span.sheet-toggle-heal{width:27px}span.sheet-toggle-heal{margin-left:-27px}input.sheet-toggle-effects,span.sheet-toggle-effects{width:38px}span.sheet-toggle-effects{margin-left:-38px}input.sheet-toggle-spell-source,span.sheet-toggle-spell-source{width:39px}span.sheet-toggle-spell-source{margin-left:-39px}input.sheet-toggle-spell-from,span.sheet-toggle-spell-from{width:29px}span.sheet-toggle-spell-from{margin-left:-29px}input.sheet-toggle-recharge,span.sheet-toggle-recharge{width:51px}span.sheet-toggle-recharge{margin-left:-51px}input.sheet-toggle-spell-slots,span.sheet-toggle-spell-slots{width:53px}span.sheet-toggle-spell-slots{margin-left:-53px}input.sheet-toggle-spell-points,span.sheet-toggle-spell-points{width:60px}span.sheet-toggle-spell-points{margin-left:-60px}input.sheet-toggle-spell-sorcery-points,span.sheet-toggle-spell-sorcery-points{width:45px}span.sheet-toggle-spell-sorcery-points{margin-left:-45px}input.sheet-toggle-spell-warlock-slots,span.sheet-toggle-spell-warlock-slots{width:42px}span.sheet-toggle-spell-warlock-slots{margin-left:-42px}input.sheet-toggle-generate-skills,span.sheet-toggle-generate-skills{width:74px}span.sheet-toggle-generate-skills{margin-left:-74px}span.sheet-toggle-spells-filter-casting-time-reaction,span.sheet-toggle-spells-filter-level-cantrips{border-bottom-right-radius:0;border-top-right-radius:0}span.sheet-toggle-spells-filter-casting-time-action,span.sheet-toggle-spells-filter-casting-time-bonus,span.sheet-toggle-spells-filter-level-1,span.sheet-toggle-spells-filter-level-2,span.sheet-toggle-spells-filter-level-3,span.sheet-toggle-spells-filter-level-4,span.sheet-toggle-spells-filter-level-5,span.sheet-toggle-spells-filter-level-6,span.sheet-toggle-spells-filter-level-7,span.sheet-toggle-spells-filter-level-8,span.sheet-toggle-spells-filter-level-9{border-radius:0}span.sheet-toggle-spells-filter-casting-time-all,span.sheet-toggle-spells-filter-level-all{border-bottom-left-radius:0;border-top-left-radius:0}input.sheet-toggle-jack-of-all-trades,span.sheet-toggle-jack-of-all-trades{width:82px}span.sheet-toggle-jack-of-all-trades{margin-left:-82px}input.sheet-toggle-remarkable-athlete,span.sheet-toggle-remarkable-athlete{width:97px}span.sheet-toggle-remarkable-athlete{margin-left:-97px}input.sheet-toggle-query,span.sheet-toggle-query{width:34px}span.sheet-toggle-query{margin-left:-34px}input.sheet-toggle-halfling-luck,span.sheet-toggle-halfling-luck{width:65px}span.sheet-toggle-halfling-luck{margin-left:-65px}input.sheet-toggle-language,span.sheet-toggle-language{height:11px;width:16px}input.sheet-toggle-language:checked+span.sheet-toggle-language{opacity:1}span.sheet-toggle-language{background-repeat:no-repeat;margin-left:2px;margin-right:-16px;opacity:.4}span.sheet-toggle-language.sheet-en{background:url(http://i.imgur.com/TniJIqt.png)}span.sheet-toggle-language.sheet-de{background:url(http://i.imgur.com/xUhfiqu.png)}span.sheet-toggle-language.sheet-fr{background:url(http://i.imgur.com/94SeipS.png)}span.sheet-toggle-language.sheet-ru{background:url(http://i.imgur.com/9XCOBJX.png)}span.sheet-toggle-language.sheet-es{background:url(http://i.imgur.com/UcndHqG.png)}input.sheet-slide-input-pc:checked~.sheet-toggle-edit-mode,input.sheet-slide-input-pc:checked~div.sheet-section-core,input.sheet-slide-input-pc:not(:checked)~div.sheet-section-npc{display:none!important}input.sheet-slide-input-pc:checked~input.sheet-toggle-page-all:checked~div[class^=sheet-section-]:not(.sheet-pc),input.sheet-slide-input-pc:checked~input.sheet-toggle-page-core:checked~div.sheet-section-npc,input.sheet-slide-input-pc:not(:checked)~input.sheet-toggle-page-all:checked~div[class^=sheet-section-]:not(.sheet-npc),input.sheet-slide-input-pc:not(:checked)~input.sheet-toggle-page-core:checked~div.sheet-section-core,input.sheet-toggle-page-character:checked~div.sheet-section-character,input.sheet-toggle-page-equipment:checked~div.sheet-section-equipment,input.sheet-toggle-page-settings:checked~div.sheet-section-settings,input.sheet-toggle-page-spells:checked~div.sheet-section-spells{display:block}input.sheet-toggle-page-all:checked~div[class^=sheet-section-]:not(:last-of-type){border-bottom:10px solid #000;margin-bottom:5px;padding-bottom:5px}input[class^=sheet-toggle-page-],span[class^=sheet-toggle-page-]{height:16px;margin-bottom:2px;margin-top:2px}span[class^=sheet-toggle-page-]{font-size:12px;font-weight:700;padding:2px}input[class^=sheet-toggle-page-]:checked+span[class^=sheet-toggle-page-]{background-color:#416696!important}.sheet-spell .sheet-wrap-box{background-color:#f5f5f5;box-shadow:0 0 5px #676767;padding:3px}input[readonly]{background-color:inherit;cursor:inherit}input[class^=sheet-slide-input-]{cursor:pointer;display:inline-block;margin:0;opacity:0;position:relative;vertical-align:top;z-index:99}label[class^=sheet-slide-toggle-]{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;border:1px solid #d9d9d9;border-bottom-color:#e6e6e6;border-radius:2px;box-shadow:inset 0 .1em .03em rgba(0,0,0,.2),inset 0 .1em .3em rgba(0,0,0,.3),0 0 2em rgba(255,255,255,.6);box-sizing:border-box;display:inline-block;font-size:10px;font-weight:400;margin-bottom:0;padding:0;perspective:300px;position:relative;text-align:left;vertical-align:top}label[class^=sheet-slide-toggle-] .sheet-slide-cover{background-color:#f5f5f5;box-shadow:.1em 0 .2em rgba(0,0,0,.3);color:#fff;display:inline-block;margin-right:-1px;margin-top:-1px;position:absolute;right:0;text-align:center;top:0;transition:all .2s ease-in-out;transition-duration:.13333s;transition-timing-function:cubic-bezier(.52,-.41,.55,1.46)}label[class^=sheet-slide-toggle-] span[class^=sheet-slide-toggle-]{display:inline-block;text-align:center;transition:all .2s ease-in-out}input.sheet-slide-input-pc,label.sheet-slide-toggle-pc{height:12px;width:80px}label.sheet-slide-toggle-pc{margin-left:-80px;line-height:12px}label.sheet-slide-toggle-pc .sheet-slide-cover{width:40px;height:12px;box-shadow:0 .12em .01em #394535,0 .12em .3em rgba(57,69,53,.6),0 .12em 2em rgba(0,0,0,.3),-.12em .15em .2em rgba(0,0,0,.2)}input[type=checkbox].sheet-slide-input-pc+label.sheet-slide-toggle-pc .sheet-slide-cover{background-color:#51624b;text-shadow:0 .05em 0 #455440}input[type=checkbox].sheet-slide-input-pc+label.sheet-slide-toggle-pc span[class^=sheet-slide-toggle-]{width:50%;color:#51624b}.sheet-creature-name,.sheet-spell-name,input[type=checkbox].sheet-slide-input-pc:checked+label.sheet-slide-toggle-pc span[class^=sheet-slide-toggle-]{color:#591209}input[type=checkbox].sheet-slide-input-pc:checked+label.sheet-slide-toggle-pc .sheet-slide-cover{background-color:#591209;margin-right:40px;border-bottom:.03em solid #871b0e;text-shadow:0 .05em 0 #2b0904;box-shadow:0 .12em .01em #2b0904,0 .12em .3em rgba(43,9,4,.6),0 .12em 2em rgba(0,0,0,.3),.12em .15em .2em rgba(0,0,0,.2)}input.sheet-toggle-hidden-info:checked~div.sheet-toggle-hidden-info{display:block}input.sheet-attack-toggle:not(:checked)~div.sheet-attack-toggle,input.sheet-toggle-alt-damage:not(:checked)~div div.sheet-toggle-alt-damage,input.sheet-toggle-ammo:not(:checked)~.sheet-toggle-ammo-auto,input.sheet-toggle-ammo:not(:checked)~div div.sheet-toggle-ammo,input.sheet-toggle-custom-class:not(:checked)~.sheet-custom-class,input.sheet-toggle-edit-mode:checked~div .sheet-presentation,input.sheet-toggle-edit-mode:not(:checked)~div .sheet-edit,input.sheet-toggle-hd-d10:not(:checked)~div.sheet-toggle-hd-d10,input.sheet-toggle-hd-d12:not(:checked)~div.sheet-toggle-hd-d12,input.sheet-toggle-hd-d20:not(:checked)~div.sheet-toggle-hd-d20,input.sheet-toggle-hd-d2:not(:checked)~div.sheet-toggle-hd-d2,input.sheet-toggle-hd-d4:not(:checked)~div.sheet-toggle-hd-d4,input.sheet-toggle-hd-d6:not(:checked)~div.sheet-toggle-hd-d6,input.sheet-toggle-hd-d8:not(:checked)~div.sheet-toggle-hd-d8,input.sheet-toggle-icon-settings:not(:checked)~div.sheet-details,input.sheet-toggle-range:not(:checked)~.sheet-toggle-ammo,input.sheet-toggle-range:not(:checked)~.sheet-toggle-ammo-auto,input.sheet-toggle-range:not(:checked)~div div.sheet-toggle-range,input.sheet-toggle-reach:not(:checked)~div div.sheet-toggle-reach,input.sheet-toggle-sorcerer-levels:not(:checked)~div .sheet-spell-sorcery-points,input.sheet-toggle-spell-filters:not(:checked)~[class^=sheet-toggle-spells-filter],input.sheet-toggle-spell-filters:not(:checked)~span.sheet-spells-filter,input.sheet-toggle-spell-level-1:not(:checked)~div .sheet-spell-level-1,input.sheet-toggle-spell-level-2:not(:checked)~div .sheet-spell-level-2,input.sheet-toggle-spell-level-3:not(:checked)~div .sheet-spell-level-3,input.sheet-toggle-spell-level-4:not(:checked)~div .sheet-spell-level-4,input.sheet-toggle-spell-level-5:not(:checked)~div .sheet-spell-level-5,input.sheet-toggle-spell-level-6:not(:checked)~div .sheet-spell-level-6,input.sheet-toggle-spell-level-7:not(:checked)~div .sheet-spell-level-7,input.sheet-toggle-spell-level-8:not(:checked)~div .sheet-spell-level-8,input.sheet-toggle-spell-level-9:not(:checked)~div .sheet-spell-level-9,input.sheet-toggle-spell-points:not(:checked)~.sheet-spell-points,input.sheet-toggle-spell-slots:not(:checked)~.sheet-spell-slots,input.sheet-toggle-spell-slots:not(:checked)~div div.sheet-spell-slots-points,input.sheet-toggle-spells-filter-casting-time-action:checked~.repcontainer input.sheet-toggle-casting-time-action:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-casting-time-bonus:checked~.repcontainer input.sheet-toggle-casting-time-bonus:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-casting-time-reaction:checked~.repcontainer input.sheet-toggle-casting-time-reaction:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-concentration:not(:checked)~.repcontainer input.sheet-toggle-spells-concentration:checked~.sheet-spell,input.sheet-toggle-spells-filter-level-1:checked~.repcontainer input.sheet-toggle-spell-level-1:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-2:checked~.repcontainer input.sheet-toggle-spell-level-2:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-3:checked~.repcontainer input.sheet-toggle-spell-level-3:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-4:checked~.repcontainer input.sheet-toggle-spell-level-4:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-5:checked~.repcontainer input.sheet-toggle-spell-level-5:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-6:checked~.repcontainer input.sheet-toggle-spell-level-6:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-7:checked~.repcontainer input.sheet-toggle-spell-level-7:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-8:checked~.repcontainer input.sheet-toggle-spell-level-8:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-9:checked~.repcontainer input.sheet-toggle-spell-level-9:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-cantrips:checked~.repcontainer input.sheet-toggle-spell-level-cantrip:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-material:not(:checked)~.repcontainer input.sheet-toggle-spell-vsm-m:checked~.sheet-spell,input.sheet-toggle-spells-filter-prepared:checked~.repcontainer input.sheet-toggle-spells-prepared:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-ritual:checked~.repcontainer input.sheet-toggle-spells-ritual:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-somatic:not(:checked)~.repcontainer input.sheet-toggle-spell-vsm-s:checked~.sheet-spell,input.sheet-toggle-spells-filter-verbal:not(:checked)~.repcontainer input.sheet-toggle-spell-vsm-v:checked~.sheet-spell,input.sheet-toggle-target:not(:checked)~div div.sheet-toggle-target,input.sheet-toggle-warlock-levels:not(:checked)~div .sheet-spell-warlock-slots{display:none}.sheet-spells-filter{display:inline-block;font-size:11px}input[class^=sheet-toggle-spells-filter],span[class^=sheet-toggle-spells-filter]{height:12px}.sheet-spell input,.sheet-spell select,.sheet-spell textarea{background-color:transparent}.sheet-action-name,.sheet-creature-name,.sheet-spell-name{border:0;font-family:'Times New Roman';font-size:17px;font-weight:700;padding:0!important}input[class^=sheet-toggle]:checked+span[class^=sheet-toggle]{background-color:#51624b}input[class^=sheet-toggle-icon]:checked+span[class^=sheet-toggle-icon],input[class^=sheet-toggle-edit-mode]:checked+span[class^=sheet-toggle-edit-mode]{background-color:transparent;color:rgba(255,255,1,.95);text-shadow:-1px 0 #000,0 1px #000,1px 0 #000,0 -1px #000}input[class^=sheet-toggle-spells]:checked+span[class^=sheet-toggle-spells]{background-color:#591209}span[class^=sheet-toggle-spells-filter]{font-size:10px}.sheet-rolltemplate-5e-shaped .sheet-zebra,.sheet-spell-points .sheet-shaped-row:nth-child(even),.sheet-spell-slots .sheet-shaped-row:nth-child(even),.sheet-zebra,.sheet-zebra-rows .sheet-shaped-row:nth-child(even){background-color:#E6F5F9}.sheet-spell-slots input{background:0 0}.sheet-toggle-icon-settings{position:absolute!important;right:0;top:0}span.sheet-toggle-icon-settings{background-color:transparent;color:#8c8c8c;font-size:14px;height:16px;margin-top:0}span.sheet-toggle-edit-mode{background-color:transparent;color:#8c8c8c;font-size:18px;margin-top:0}input.sheet-toggle-edit-mode,span.sheet-toggle-edit-mode{height:20px}input.sheet-toggle-edit-mode:checked~div input:not([readonly]),input.sheet-toggle-edit-mode:checked~div select:not([readonly]),input.sheet-toggle-edit-mode:checked~div textarea:not([readonly]){background-color:rgba(255,255,1,.41)}input.sheet-toggle-edit-mode:not(:checked)~div.sheet-section-core .repcontrol,input.sheet-toggle-edit-mode:not(:checked)~div.sheet-section-core .sheet-item-to-toggle,input.sheet-toggle-edit-mode:not(:checked)~div.sheet-shaped-row .repcontrol,input.sheet-toggle-edit-mode:not(:checked)~div.sheet-shaped-row .sheet-item-to-toggle{display:none}.sheet-item-toggle[value="1"]+.sheet-item-to-toggle{display:block!important}.sheet-no-background{background-color:transparent!important}.sheet-rolltemplate-5e-shaped .sheet-small-label,.sheet-small-label{font-size:11px}.sheet-small-label select{-moz-appearance:none;-webkit-appearance:none;appearance:none}[class*=sheet-pictos]{font-size:14px}.sheet-pictos{font-family:Pictos}.sheet-border-right,.sheet-rolltemplate-5e-shaped .sheet-border-right{border-right:1px solid #000}.sheet-border-left,.sheet-rolltemplate-5e-shaped .sheet-border-left{border-left:1px solid #000}hr{margin:5px 0;background-image:linear-gradient(to right,transparent,rgba(0,0,0,.75),transparent);border:0;height:1px}span.sheet-spacer{display:block;margin-top:5px}.sheet-spacer-sm{margin-top:2px}.sheet-left{text-align:left!important}.sheet-center,.sheet-rolltemplate-5e-shaped .sheet-center{text-align:center}.sheet-right{text-align:right}textarea{height:150px;resize:both}.sheet-background-textarea,.sheet-features-and-traits{font-size:.95em}.sheet-equipment-wrapper,.sheet-traits-wrapper{max-height:20em;overflow-y:auto}.sheet-personality-traits{border-bottom-left-radius:0;border-bottom-right-radius:0}.sheet-bonds,.sheet-ideals{border-radius:0}.sheet-flaws{border-top-left-radius:0;border-top-right-radius:0}.sheet-one-line-textarea,.sheet-xs-textarea{height:1.417em}.sheet-two-line-textarea{height:2.15em}.sheet-three-line-textarea{height:3.2em}.sheet-four-line-textarea{height:4.2em}.sheet-five-line-textarea{height:5.2em}.sheet-six-line-textarea{height:6.2em}.sheet-eight-line-textarea{height:8.3em}.sheet-important-text,.sheet-rolltemplate-5e-shaped .sheet-important-text{color:red}.sheet-rolltemplate-5e-shaped .sheet-shaped-row,.sheet-section-npc .sheet-skills .repcontainer,.sheet-section-spells .repcontainer,.sheet-shaped-row{display:flex;flex-direction:row;flex-wrap:wrap}.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-center,.sheet-section-npc .sheet-skills .repcontainer.sheet-center,.sheet-section-spells .repcontainer.sheet-center,.sheet-shaped-row.sheet-center{justify-content:center}.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-vert-center,.sheet-section-npc .sheet-skills .repcontainer.sheet-vert-center,.sheet-section-spells .repcontainer.sheet-vert-center,.sheet-shaped-row.sheet-vert-center{align-items:center}.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-flex-end,.sheet-section-npc .sheet-skills .repcontainer.sheet-flex-end,.sheet-section-spells .repcontainer.sheet-flex-end,.sheet-shaped-row.sheet-flex-end{align-items:flex-end}.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-no-wrap,.sheet-section-npc .sheet-skills .repcontainer.sheet-no-wrap,.sheet-section-spells .repcontainer.sheet-no-wrap,.sheet-shaped-row.sheet-no-wrap{flex-wrap:nowrap}.sheet-section-spells .repitem{width:50%}.sheet-section-spells .repitem:nth-child(even){padding-left:3px}.sheet-section-spells .repitem:nth-child(odd){padding-right:3px}.sheet-section-spells .sheet-wrap-box textarea{font-size:11px}.sheet-col-1-3{width:33.33333%}.sheet-col-2-3{width:66.66667%}.sheet-col-1-6{width:16.66667%}.sheet-col-1-8{width:12.5%}.sheet-col-1-12{width:8.33333%}.sheet-col-1-3-em{width:1.3em}.sheet-col-2-em{width:2em}.sheet-col-01,.sheet-rolltemplate-5e-shaped .sheet-col-01{width:1%}.sheet-col-02,.sheet-rolltemplate-5e-shaped .sheet-col-02{width:2%}.sheet-col-03,.sheet-rolltemplate-5e-shaped .sheet-col-03{width:3%}.sheet-col-04,.sheet-rolltemplate-5e-shaped .sheet-col-04{width:4%}.sheet-col-05,.sheet-rolltemplate-5e-shaped .sheet-col-05{width:5%}.sheet-col-06,.sheet-rolltemplate-5e-shaped .sheet-col-06{width:6%}.sheet-col-07,.sheet-rolltemplate-5e-shaped .sheet-col-07{width:7%}.sheet-col-08,.sheet-rolltemplate-5e-shaped .sheet-col-08{width:8%}.sheet-col-09,.sheet-rolltemplate-5e-shaped .sheet-col-09{width:9%}.sheet-col-10,.sheet-rolltemplate-5e-shaped .sheet-col-10{width:10%}.sheet-col-11,.sheet-rolltemplate-5e-shaped .sheet-col-11{width:11%}.sheet-col-12,.sheet-rolltemplate-5e-shaped .sheet-col-12{width:12%}.sheet-col-13,.sheet-rolltemplate-5e-shaped .sheet-col-13{width:13%}.sheet-col-14,.sheet-rolltemplate-5e-shaped .sheet-col-14{width:14%}.sheet-col-15,.sheet-rolltemplate-5e-shaped .sheet-col-15{width:15%}.sheet-col-16,.sheet-rolltemplate-5e-shaped .sheet-col-16{width:16%}.sheet-col-17,.sheet-rolltemplate-5e-shaped .sheet-col-17{width:17%}.sheet-col-18,.sheet-rolltemplate-5e-shaped .sheet-col-18{width:18%}.sheet-col-19,.sheet-rolltemplate-5e-shaped .sheet-col-19{width:19%}.sheet-col-20,.sheet-rolltemplate-5e-shaped .sheet-col-20{width:20%}.sheet-col-21,.sheet-rolltemplate-5e-shaped .sheet-col-21{width:21%}.sheet-col-22,.sheet-rolltemplate-5e-shaped .sheet-col-22{width:22%}.sheet-col-23,.sheet-rolltemplate-5e-shaped .sheet-col-23{width:23%}.sheet-col-24,.sheet-rolltemplate-5e-shaped .sheet-col-24{width:24%}.sheet-col-25,.sheet-rolltemplate-5e-shaped .sheet-col-25{width:25%}.sheet-col-26,.sheet-rolltemplate-5e-shaped .sheet-col-26{width:26%}.sheet-col-27,.sheet-rolltemplate-5e-shaped .sheet-col-27{width:27%}.sheet-col-28,.sheet-rolltemplate-5e-shaped .sheet-col-28{width:28%}.sheet-col-29,.sheet-rolltemplate-5e-shaped .sheet-col-29{width:29%}.sheet-col-30,.sheet-rolltemplate-5e-shaped .sheet-col-30{width:30%}.sheet-col-31,.sheet-rolltemplate-5e-shaped .sheet-col-31{width:31%}.sheet-col-32,.sheet-rolltemplate-5e-shaped .sheet-col-32{width:32%}.sheet-col-33,.sheet-rolltemplate-5e-shaped .sheet-col-33{width:33%}.sheet-col-34,.sheet-rolltemplate-5e-shaped .sheet-col-34{width:34%}.sheet-col-35,.sheet-rolltemplate-5e-shaped .sheet-col-35{width:35%}.sheet-col-36,.sheet-rolltemplate-5e-shaped .sheet-col-36{width:36%}.sheet-col-37,.sheet-rolltemplate-5e-shaped .sheet-col-37{width:37%}.sheet-col-38,.sheet-rolltemplate-5e-shaped .sheet-col-38{width:38%}.sheet-col-39,.sheet-rolltemplate-5e-shaped .sheet-col-39{width:39%}.sheet-col-40,.sheet-rolltemplate-5e-shaped .sheet-col-40{width:40%}.sheet-col-41,.sheet-rolltemplate-5e-shaped .sheet-col-41{width:41%}.sheet-col-42,.sheet-rolltemplate-5e-shaped .sheet-col-42{width:42%}.sheet-col-43,.sheet-rolltemplate-5e-shaped .sheet-col-43{width:43%}.sheet-col-44,.sheet-rolltemplate-5e-shaped .sheet-col-44{width:44%}.sheet-col-45,.sheet-rolltemplate-5e-shaped .sheet-col-45{width:45%}.sheet-col-46,.sheet-rolltemplate-5e-shaped .sheet-col-46{width:46%}.sheet-col-47,.sheet-rolltemplate-5e-shaped .sheet-col-47{width:47%}.sheet-col-48,.sheet-rolltemplate-5e-shaped .sheet-col-48{width:48%}.sheet-col-49,.sheet-rolltemplate-5e-shaped .sheet-col-49{width:49%}.sheet-col-50,.sheet-rolltemplate-5e-shaped .sheet-col-50{width:50%}.sheet-col-51,.sheet-rolltemplate-5e-shaped .sheet-col-51{width:51%}.sheet-col-52,.sheet-rolltemplate-5e-shaped .sheet-col-52{width:52%}.sheet-col-53,.sheet-rolltemplate-5e-shaped .sheet-col-53{width:53%}.sheet-col-54,.sheet-rolltemplate-5e-shaped .sheet-col-54{width:54%}.sheet-col-55,.sheet-rolltemplate-5e-shaped .sheet-col-55{width:55%}.sheet-col-56,.sheet-rolltemplate-5e-shaped .sheet-col-56{width:56%}.sheet-col-57,.sheet-rolltemplate-5e-shaped .sheet-col-57{width:57%}.sheet-col-58,.sheet-rolltemplate-5e-shaped .sheet-col-58{width:58%}.sheet-col-59,.sheet-rolltemplate-5e-shaped .sheet-col-59{width:59%}.sheet-col-60,.sheet-rolltemplate-5e-shaped .sheet-col-60{width:60%}.sheet-col-61,.sheet-rolltemplate-5e-shaped .sheet-col-61{width:61%}.sheet-col-62,.sheet-rolltemplate-5e-shaped .sheet-col-62{width:62%}.sheet-col-63,.sheet-rolltemplate-5e-shaped .sheet-col-63{width:63%}.sheet-col-64,.sheet-rolltemplate-5e-shaped .sheet-col-64{width:64%}.sheet-col-65,.sheet-rolltemplate-5e-shaped .sheet-col-65{width:65%}.sheet-col-66,.sheet-rolltemplate-5e-shaped .sheet-col-66{width:66%}.sheet-col-67,.sheet-rolltemplate-5e-shaped .sheet-col-67{width:67%}.sheet-col-68,.sheet-rolltemplate-5e-shaped .sheet-col-68{width:68%}.sheet-col-69,.sheet-rolltemplate-5e-shaped .sheet-col-69{width:69%}.sheet-col-70,.sheet-rolltemplate-5e-shaped .sheet-col-70{width:70%}.sheet-col-71,.sheet-rolltemplate-5e-shaped .sheet-col-71{width:71%}.sheet-col-72,.sheet-rolltemplate-5e-shaped .sheet-col-72{width:72%}.sheet-col-73,.sheet-rolltemplate-5e-shaped .sheet-col-73{width:73%}.sheet-col-74,.sheet-rolltemplate-5e-shaped .sheet-col-74{width:74%}.sheet-col-75,.sheet-rolltemplate-5e-shaped .sheet-col-75{width:75%}.sheet-col-76,.sheet-rolltemplate-5e-shaped .sheet-col-76{width:76%}.sheet-col-77,.sheet-rolltemplate-5e-shaped .sheet-col-77{width:77%}.sheet-col-78,.sheet-rolltemplate-5e-shaped .sheet-col-78{width:78%}.sheet-col-79,.sheet-rolltemplate-5e-shaped .sheet-col-79{width:79%}.sheet-col-80,.sheet-rolltemplate-5e-shaped .sheet-col-80{width:80%}.sheet-col-81,.sheet-rolltemplate-5e-shaped .sheet-col-81{width:81%}.sheet-col-82,.sheet-rolltemplate-5e-shaped .sheet-col-82{width:82%}.sheet-col-83,.sheet-rolltemplate-5e-shaped .sheet-col-83{width:83%}.sheet-col-84,.sheet-rolltemplate-5e-shaped .sheet-col-84{width:84%}.sheet-col-85,.sheet-rolltemplate-5e-shaped .sheet-col-85{width:85%}.sheet-col-86,.sheet-rolltemplate-5e-shaped .sheet-col-86{width:86%}.sheet-col-87,.sheet-rolltemplate-5e-shaped .sheet-col-87{width:87%}.sheet-col-88,.sheet-rolltemplate-5e-shaped .sheet-col-88{width:88%}.sheet-col-89,.sheet-rolltemplate-5e-shaped .sheet-col-89{width:89%}.sheet-col-90,.sheet-rolltemplate-5e-shaped .sheet-col-90{width:90%}.sheet-col-91,.sheet-rolltemplate-5e-shaped .sheet-col-91{width:91%}.sheet-col-92,.sheet-rolltemplate-5e-shaped .sheet-col-92{width:92%}.sheet-col-93,.sheet-rolltemplate-5e-shaped .sheet-col-93{width:93%}.sheet-col-94,.sheet-rolltemplate-5e-shaped .sheet-col-94{width:94%}.sheet-col-95,.sheet-rolltemplate-5e-shaped .sheet-col-95{width:95%}.sheet-col-96,.sheet-rolltemplate-5e-shaped .sheet-col-96{width:96%}.sheet-col-97,.sheet-rolltemplate-5e-shaped .sheet-col-97{width:97%}.sheet-col-98,.sheet-rolltemplate-5e-shaped .sheet-col-98{width:98%}.sheet-col-99,.sheet-rolltemplate-5e-shaped .sheet-col-99{width:99%}.sheet-col-100,.sheet-rolltemplate-5e-shaped .sheet-col-100{width:100%}.sheet-offset-20{margin-left:20%}.sheet-gm-info-block,.sheet-gm-info-inline-block,.sheet-rolltemplate-5e-shaped .sheet-gm-info-block,.sheet-rolltemplate-5e-shaped .sheet-gm-info-inline-block{background-color:#f2f5d3!important;display:none}.sheet-section-npc input,.sheet-section-npc select,.sheet-section-npc textarea{background:0 0;color:inherit;padding-bottom:0;padding-top:0}.sheet-section-npc select{height:1.1em}.sheet-section-npc .btn[type=roll]{font-size:13px!important}.sheet-section-npc .sheet-bar{height:5px;background:#E69A28;background:repeating-linear-gradient(15deg,#E69A28,#CA8929 5px,#CA8929 5px,#E69A28 10px);border:1px solid #000;position:relative;z-index:1}.sheet-section-npc .sheet-npc-content-wrap{background:url(http://i.imgur.com/hggz0ed.jpg);font-family:'Noto Sans','Myriad Pro',Calibri,Helvetica,Arial,sans-serif;font-size:14px;padding:.6em .3em;border:1px solid #DDD;box-shadow:0 0 1.5em #867453;position:relative;z-index:0;margin-left:2px;margin-right:2px}.sheet-section-npc .sheet-parenthesis-wrapper::after,.sheet-section-npc .sheet-parenthesis-wrapper::before{font-size:13px;top:1px;color:#3A0E06}.sheet-section-npc .sheet-creature-name{font-family:Lora,'Calisto MT','Bookman Old Style',Bookman,'Goudy Old Style',Garamond,'Hoefler Text','Bitstream Charter',Georgia,serif;color:#3A0E06;font-weight:700;margin-top:-6px;margin-bottom:-2px;font-size:25px;letter-spacing:2px;font-variant:small-caps}.sheet-section-npc h3{border-bottom:1px solid #3A0E06;color:#3A0E06;font-size:20px;font-variant:small-caps;font-weight:400;margin:0;line-height:110%}.sheet-section-npc .sheet-heading{font-weight:700}.sheet-section-npc .sheet-top-stats,.sheet-section-npc .sheet-top-stats button,.sheet-section-npc .sheet-top-stats input,.sheet-section-npc .sheet-top-stats textarea{color:#3A0E06}.sheet-section-npc .sheet-divider{border-top:3px solid transparent;border-bottom:3px solid transparent;border-left:400px solid #922610;margin:5px 0}.sheet-section-npc .sheet-skills .repitem:last-child .sheet-comma{display:none} \ No newline at end of file +input.sheet-toggle-pseudo-button,select{height:17px}*,.sheet-rolltemplate-5e-shaped *{box-sizing:border-box;line-height:100%}::-webkit-scrollbar{height:.5em;width:.5em}::-webkit-scrollbar-thumb{background:#708090;border-radius:10px}body{scrollbar-face-color:#708090}.sheet-wrapper,input,select,textarea{font-size:12px}button[type=roll]{background-image:none;border:0;box-shadow:none;-webkit-box-shadow:none;text-align:left;text-shadow:initial}button[type=roll].btn{font-size:inherit;margin:0}button[type=roll].btn:not(.sheet-visible-button){background-color:transparent;padding:0}button[type=roll].btn:not(.sheet-visible-button):hover,button[type=roll].btn:not(.sheet-visible-button):hover input{color:#3f88e6!important}button[type=roll].btn.sheet-visible-button{background-color:#3f88e6;border-radius:3px;box-shadow:0 2px 5px 0 rgba(0,0,0,.26);color:rgba(255,255,255,.87);font-size:11px;padding:3px}button[type=roll].btn.sheet-visible-button:hover{color:rgba(255,255,255,.87)}button[type=roll].btn.sheet-visible-button:active{box-shadow:0 4px 8px 0 rgba(0,0,0,.4)}button[type=roll]:hover{background-position:initial}button[type=roll]::before{content:''!important}button[type=roll]:active{box-shadow:none;-webkit-box-shadow:none}button.repcontrol_add,button.repcontrol_edit{font-size:10px;padding:1px 3px}button.repcontrol_del{font-size:13px;padding:0 3px 2px;position:relative;z-index:999}button.repcontrol_add,button.repcontrol_del,button.repcontrol_edit{border-radius:3px;width:auto!important}.btn.repcontrol_move{padding:2px 6px;background:0 0;border:none;font-size:16px;font-weight:700;position:relative;z-index:999}span.sheet-toggle-pseudo-button{background-color:#3f88e6!important;box-shadow:0 2px 5px 0 rgba(0,0,0,.26);font-size:11px!important;height:17px;padding:3px!important}.sheet-wrapper-button{width:100%}p{margin:0}ol,ul{margin:0 0 0 15px}button,input[type=number],input[type=text],select,textarea{border-left:0;border-right:0;border-top:0;border-radius:0;box-shadow:none;margin-bottom:0!important;padding:1px}button.sheet-no-border,input[type=number].sheet-no-border,input[type=text].sheet-no-border,select.sheet-no-border,textarea.sheet-no-border{border-bottom:0}button:focus,input[type=number]:focus,input[type=text]:focus,select:focus,textarea:focus{outline:0}.sheet-border-bottom{border-bottom:1px solid #ccc}input[type=number],input[type=text],select,textarea{width:100%!important}select{-moz-appearance:none;-webkit-appearance:none;appearance:none}input[type=number]{text-align:center}.sheet-pseudo-input{display:block;padding:2px;min-height:17px}input[disabled],input[readonly],input[type=number].sheet-no-spin{-moz-appearance:textfield}input[disabled]{background-color:transparent;cursor:inherit}input[disabled]::-webkit-inner-spin-button,input[disabled]::-webkit-outer-spin-button,input[readonly]::-webkit-inner-spin-button,input[readonly]::-webkit-outer-spin-button,input[type=number].sheet-no-spin::-webkit-inner-spin-button,input[type=number].sheet-no-spin::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.sheet-float-right{float:right}.sheet-mar-t-sm{margin-top:2px}.sheet-pad-t-sm{padding-top:2px}.sheet-rolltemplate-5e-shaped .sheet-mar-t-sm{margin-top:2px!important}.sheet-mar-t-smd{margin-top:4px}.sheet-pad-t-smd{padding-top:4px}.sheet-mar-t-md{margin-top:5px}.sheet-pad-t-md{padding-top:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-t-md{margin-top:5px!important}.sheet-mar-t-lg{margin-top:10px}.sheet-pad-t-lg{padding-top:10px}.sheet-mar-t-xl{margin-top:15px}.sheet-pad-t-xl{padding-top:15px}.sheet-mar-t-xxl{margin-top:20px}.sheet-pad-t-xxl{padding-top:20px}.sheet-mar-r-sm{margin-right:2px}.sheet-pad-r-sm{padding-right:2px}.sheet-mar-r-smd{margin-right:4px}.sheet-pad-r-smd{padding-right:4px}.sheet-mar-r-md{margin-right:5px}.sheet-pad-r-md{padding-right:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-r-md{margin-right:5px!important}.sheet-mar-r-lg{margin-right:10px}.sheet-pad-r-lg{padding-right:10px}.sheet-mar-r-xl{margin-right:15px}.sheet-pad-r-xl{padding-right:15px}.sheet-mar-r-xxl{margin-right:20px}.sheet-pad-r-xxl{padding-right:20px}.sheet-mar-b-sm{margin-bottom:2px}.sheet-pad-b-sm{padding-bottom:2px}.sheet-pad-b-smd{padding-bottom:4px}.sheet-mar-b-md{margin-bottom:5px}.sheet-pad-b-md{padding-bottom:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-b-md{margin-bottom:5px!important}.sheet-mar-b-lg{margin-bottom:10px}.sheet-pad-b-lg{padding-bottom:10px}.sheet-mar-b-xl{margin-bottom:15px}.sheet-pad-b-xl{padding-bottom:15px}.sheet-mar-b-xxl{margin-bottom:20px}.sheet-pad-b-xxl{padding-bottom:20px}.sheet-mar-l-sm{margin-left:2px}.sheet-pad-l-sm{padding-left:2px}.sheet-mar-l-smd{margin-left:4px}.sheet-pad-l-smd{padding-left:4px}.sheet-mar-l-md{margin-left:5px}.sheet-pad-l-md{padding-left:5px}.sheet-rolltemplate-5e-shaped .sheet-mar-l-md{margin-left:5px!important}.sheet-mar-l-lg{margin-left:10px}.sheet-pad-l-lg{padding-left:10px}.sheet-mar-l-xl{margin-left:15px}.sheet-pad-l-xl{padding-left:15px}.sheet-mar-l-xxl{margin-left:20px}.sheet-pad-l-xxl{padding-left:20px}.sheet-pad-t-twelve{padding-top:12px}.sheet-pad-t-eight{padding-top:8px}.sheet-pad-t-hundred{padding-top:100px}.sheet-hidden{display:none!important}.sheet-import-data-present:not(:checked)~.sheet-overlay,.sheet-slide-input-pc:checked~.sheet-pc,.sheet-slide-input-pc:checked~div .sheet-pc,.sheet-slide-input-pc:not(:checked)~.sheet-npc,.sheet-slide-input-pc:not(:checked)~div .sheet-npc{display:none}.sheet-mar-b-smd{margin-bottom:4px}.sheet-wrapper{min-width:834px}.sheet-overlay{width:100%;height:100%;background-color:rgba(0,0,0,.75);z-index:9999}.charsheet{background:url(http://i.imgur.com/RggDtsN.png) #ededed;margin-top:-10px;padding:2px 3px!important}.sheet-small-note{font-size:10px;text-align:center}.sheet-wrap-box{background-color:#fff;border:1px solid #000;border-radius:3px;padding:2px}.sheet-tooltip-position-wrapper{position:absolute;top:1px;right:1px;z-index:99}.sheet-tooltip{position:relative}.sheet-tooltip-toggle-text{background-color:#000;border-radius:50%;color:rgba(255,255,255,.87);font-size:77%;font-weight:700;height:10px;width:10px;padding:1px 2px}[class*=sheet-tooltip-content]{background-color:#000;border-bottom-right-radius:4px;border-bottom-left-radius:4px;color:rgba(255,255,255,.87);margin-top:-15px;opacity:.9;padding:4px;position:absolute;width:260px;text-align:left;visibility:hidden;z-index:99}[class*=sheet-tooltip-content]::after{border-bottom:8px solid transparent;border-top:8px solid transparent;content:'';margin-top:-8px;position:absolute;top:9px}.sheet-character-name .sheet-wrap-box-label,.sheet-shield .sheet-wrap-box-title{margin-top:1px}.sheet-tooltip-small{width:80px}.sheet-tooltip-content-left{border-top-left-radius:4px;margin-right:12px;right:100%}.sheet-tooltip-content-right{border-top-right-radius:4px;left:100%;margin-left:12px}.sheet-tooltip-content-left::after{border-left:8px solid #000;right:-8px}.sheet-tooltip-content-right::after{border-right:8px solid #000;left:-8px}.sheet-tooltip:focus [class*=sheet-tooltip-content],.sheet-tooltip:hover [class*=sheet-tooltip-content]{visibility:visible;z-index:450}.sheet-dnd-image-wrapper{margin-bottom:1px}.sheet-dnd-image-wrapper img{display:block;max-height:27px}.sheet-character-name input[type=text]{border:1px solid #000;border-bottom-left-radius:5px!important;border-right-width:0;border-top-left-radius:5px!important;font-size:20px;font-weight:700;padding:0 2px}.sheet-ability-wrapper{height:69px;margin-bottom:12px;position:relative}.sheet-ability-wrapper .sheet-ability-score-wrapper{background-color:#fff;border:1px solid #000;border-radius:50%;bottom:-8px;left:0;margin-right:auto;margin-left:auto;padding:2px;position:absolute;right:0;width:40px!important}input.sheet-toggle-edit-mode:checked~div .sheet-ability-wrapper .sheet-ability-score-wrapper{width:60px!important}.sheet-ability-wrapper .sheet-ability-score-wrapper input{font-size:11px;background:0 0;border-radius:50%}.sheet-ability-name{font-size:9px;font-weight:700;text-transform:uppercase}.sheet-ability-modifier{font-size:24px;font-weight:700;padding-bottom:8px!important;padding-top:8px!important}input.sheet-toggle-edit-mode:checked~div .sheet-ability-modifier{padding-bottom:0!important;padding-top:0!important}.sheet-spell-slots-points input[type=number]{background-color:transparent;font-size:12px;padding:0}.sheet-class-features,.sheet-section-core .sheet-ability-saving-throw-name,.sheet-section-core .sheet-skill-name{font-size:11px}.sheet-attacks input[readonly],.sheet-class-feature input[readonly],.sheet-gray-bg,.sheet-spell input[readonly]{background:#dedede}.sheet-flex-grow{flex-grow:1}.sheet-no-shrink{flex-shrink:0}.sheet-inline{display:inline}.sheet-inline-block{display:inline-block}.sheet-block{display:block}.sheet-pre-line{white-space:pre-line}.sheet-relative,.sheet-rolltemplate-5e-shaped .sheet-relative{position:relative}.sheet-absolute{position:absolute;top:0}.sheet-section-core .sheet-heading{font-weight:700;font-style:italic;margin-left:8px}.sheet-input-like{padding:1px}.sheet-skill-ability{color:#a0a0a0;font-size:10px}.sheet-skills select{padding:0}.sheet-skills-ability-selector{background:0 0;border-bottom:0;color:#909090;font-size:9px;height:11px!important}.sheet-skill-select-wrapper select{font-size:14px;height:16px}.sheet-parenthesis-wrapper,.sheet-skills-ability-selector-wrapper{color:#909090;font-size:9px}.sheet-parenthesis-wrapper input,.sheet-skills-ability-selector-wrapper input{padding-left:3px;padding-right:3px}.sheet-shield{height:55px;margin-left:auto;margin-right:auto;width:52px;padding-top:7px;padding-right:2px;position:relative;z-index:5}.sheet-shield::before{color:#fff;content:'b';font-family:'Pictos Three';font-size:72px;left:-1px;line-height:51px;position:absolute;text-shadow:-1px 0 #000,0 1px #000,1px 0 #000,0 -1px #000;top:3px;z-index:-1}.sheet-shield .sheet-big-text{padding:1px}.sheet-bold,.sheet-rolltemplate-5e-shaped .sheet-bold{font-weight:700}.sheet-italic,.sheet-rolltemplate-5e-shaped .sheet-italic{font-style:italic}.sheet-capitalize{text-transform:capitalize!important}.sheet-uppercase{text-transform:uppercase!important}.sheet-big-text{font-size:16px}.sheet-initiative .sheet-big-text,.sheet-speed .sheet-big-text{padding:.4em}.sheet-heart-divider{font-size:15px}.sheet-wrap-box-label,.sheet-wrap-box-title{text-transform:uppercase}.sheet-wrap-box-title{font-weight:700;font-size:9px;margin:5px 0 0}.sheet-wrap-box-label{font-size:80%}.sheet-light-label{color:#a0a0a0}.sheet-heart,.sheet-temp-heart{height:68px;width:80px;margin-left:auto;margin-right:auto;margin-top:4px;position:relative;z-index:5}.sheet-heart::after,.sheet-temp-heart::after{position:absolute;z-index:-1;top:21px;left:0;content:'k';font-family:Pictos;font-size:90px;color:#fff;text-shadow:-1px 0 #000,0 1px #000,1px 0 #000,0 -1px #000}.sheet-heart>.sheet-shaped-row,.sheet-temp-heart>.sheet-shaped-row{padding-top:8px}.sheet-heart input[type=number],.sheet-temp-heart input[type=number]{border-radius:7px;padding:1px;background-color:transparent}.sheet-temp-heart{margin-top:10px;height:54px;width:63px}.sheet-temp-heart::after{top:16px;font-size:70px}.sheet-temp-heart>.sheet-shaped-row{padding-top:10px}.sheet-temp-heart .sheet-wrap-box-title{margin-top:2px}[class^=sheet-checkbox-label]{cursor:pointer;white-space:nowrap;margin-bottom:0;padding-right:0;font-weight:400}.sheet-white-space-no-wrap{white-space:nowrap}.sheet-small-checkbox{-webkit-transform:scale(.8);transform:scale(.8)}.sheet-checkbox-label-sm{font-size:9px}.sheet-checkbox-label-sm input[type=checkbox]{-webkit-transform:scale(.6);transform:scale(.6);height:10px;margin-top:-1px}.sheet-checkbox-label-md{font-size:85%}.sheet-checkbox-label-md input[type=checkbox]{-webkit-transform:scale(.7);transform:scale(.7);margin-top:-1px}.sheet-checkbox-label{display:inline-block;font-size:100%}.sheet-checkbox-label [type=checkbox]{display:none}.sheet-checkbox-label [type=checkbox]+span{display:inline-block;padding:1px;text-align:center;font-weight:700}.sheet-exhaustion,.sheet-inspiration,.sheet-proficiency-bonus{margin-left:3px}.sheet-exhaustion .sheet-wrap-box-title,.sheet-inspiration .sheet-wrap-box-title,.sheet-proficiency-bonus .sheet-wrap-box-title{margin-bottom:3px}.sheet-big-font{font-size:15px}.sheet-exhaustion-wrapper,.sheet-inspiration .sheet-checkbox-label span,.sheet-proficiency-bonus-wrapper{border:1px solid #000;height:27px;left:-5px;top:-3px;position:absolute;width:27px!important}.sheet-exhaustion-wrapper,.sheet-proficiency-bonus-wrapper{background-color:#fff;border-radius:50%;padding:3px}.sheet-proficiency-bonus .sheet-wrap-box-title{margin-left:22px}.sheet-exhaustion .sheet-wrap-box-title,.sheet-inspiration .sheet-wrap-box-title{margin-left:24px}.sheet-coin{margin-left:-8px}.sheet-coin-value-wrap{position:relative;left:-2px}.sheet-inspiration .sheet-checkbox-label span{border-radius:3px}.sheet-inspiration .sheet-checkbox-label [type=checkbox]+span{background-color:#fff}.sheet-inspiration .sheet-checkbox-label [type=checkbox]:checked+span{background-image:url(http://i.imgur.com/m5WFImZ.png)}.sheet-inspiration .sheet-small-input{font-size:10px;padding:0}.sheet-death-saving-throw .sheet-checkbox-label{height:14px;width:14px;margin:0 2px;position:relative;z-index:5}.sheet-death-saving-throw .sheet-checkbox-label [type=checkbox]+span{background-color:#fff;border:1px solid #000;border-radius:50%;height:14px;width:14px}.sheet-death-saving-throw [type=radio]{margin:1px;opacity:0;position:relative;z-index:99}.sheet-death-saving-throw [type=radio],.sheet-death-saving-throw [type=radio]+span{height:14px;width:14px}.sheet-death-saving-throw [type=radio]+span{border:1px solid #000;border-radius:50%;display:inline-block;margin-left:-14px;position:relative;vertical-align:middle;z-index:5}.sheet-death-saving-throw [type=radio]:first-of-type,.sheet-death-saving-throw [type=radio]:first-of-type+span{left:-12px;position:absolute;top:1px}.sheet-death-saving-throw [type=radio]:first-of-type+span{background-color:#fff;border:none;color:#980000;font-size:15px;margin-left:0}.sheet-death-saving-throw [type=radio]:first-of-type:checked+span{opacity:0}.sheet-death-saving-throw [type=radio]:checked~input[type=radio]+span{background-color:#fff}.sheet-death-succeed [type=radio]+span{background-color:#879a6a}.sheet-death-fail [type=radio]+span{background-color:#8c6075}.sheet-death-saving-throw-hr{top:2px;width:100%}.sheet-rolltemplate-5e-shaped{margin-left:-34px;margin-right:-4px}.sheet-rolltemplate-5e-shaped .sheet-no-border{border-bottom:0!important}.sheet-rolltemplate-5e-shaped a[href^="~"]{background-color:transparent;border:none;color:#ce0f69;display:inline;padding:0}.withoutavatars .sheet-rolltemplate-5e-shaped{margin-left:-4px}.sheet-rolltemplate-5e-shaped .sheet-rt-card{background-color:#fff;border:1px solid #000;border-radius:3px;box-sizing:border-box;font-size:12px;margin-right:10px;padding:4px 0 2px}.sheet-rolltemplate-5e-shaped .inlinerollresult{background:0 0;border:2px solid transparent}.sheet-rolltemplate-5e-shaped .sheet-rt-header{background-color:#5c5c5c;background-image:linear-gradient(rgba(255,255,255,.3),rgba(255,255,255,0));box-shadow:0 2px 0 rgba(0,0,0,.3);color:#fff;margin:0 -10px 2px;padding:3px;text-align:center}.sheet-rolltemplate-5e-shaped .sheet-rt-header .inlinerollresult{border:none;padding:0;font-weight:400;font-size:100%}.sheet-rolltemplate-5e-shaped .sheet-rt-header::after,.sheet-rolltemplate-5e-shaped .sheet-rt-header::before{content:'';position:absolute;border-style:solid;border-color:transparent;bottom:-10px}.sheet-rolltemplate-5e-shaped .sheet-rt-header::before{border-width:0 10px 10px 0;border-right-color:#222;left:0}.sheet-rolltemplate-5e-shaped .sheet-rt-header::after{border-width:0 0 10px 10px;border-left-color:#222;right:0}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-action,.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-attack{background-color:#2c5d28}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-action::before,.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-attack::before{border-right-color:#375035}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-action::after,.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-attack::after{border-left-color:#375035}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-spell{background-color:#45285d}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-spell::before{border-right-color:#443550}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-spell::after{border-left-color:#443550}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-ability{background-color:#28595d}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-ability::before{border-right-color:#354e50}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-ability::after{border-left-color:#354e50}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-saving-throw{background-color:#5d2828}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-saving-throw::before{border-right-color:#503535}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-saving-throw::after{border-left-color:#503535}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-death-saving-throw{background-color:#240f0f}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-death-saving-throw::before{border-right-color:#1f1414}.sheet-rolltemplate-5e-shaped .sheet-rt-header.sheet-death-saving-throw::after{border-left-color:#1f1414}.sheet-rolltemplate-5e-shaped .inlinerollresult{border-radius:3px;font-size:105%;line-height:130%;padding:0 3px}.sheet-rolltemplate-5e-shaped .sheet-rt-title{font-size:1.7em}.sheet-rolltemplate-5e-shaped .sheet-rt-subheader{line-height:1.2em}.sheet-rolltemplate-5e-shaped .sheet-rt-content>div{padding:2px 3px}.sheet-rolltemplate-5e-shaped .sheet-rt-content>div:not(:last-of-type){border-top:0;border-left:0;border-right:0;border-bottom:1px;border-image:linear-gradient(to right,transparent,rgba(0,0,0,.75),transparent) 1}.sheet-rolltemplate-5e-shaped .sheet-shaped-row{padding:2px}.sheet-rolltemplate-5e-shaped .sheet-rt-emote{border:1px dashed green;border-radius:3px;font-family:Arial;font-size:11px;font-style:italic;margin:0 3px 2px;padding:0 4px;text-align:center}.sheet-rolltemplate-5e-shaped .sheet-output{font-size:1.7em;text-align:center}.sheet-rolltemplate-5e-shaped .sheet-output-small-label{color:#676767;font-style:italic;text-align:center}div[class='repcontainer editmode']~div[class^=repcontrol] button[class='btn repcontrol_add']{display:inline-block!important;visibility:hidden}[class^=sheet-section-],input[value=de]:not(:checked)~div .sheet-de,input[value=de]:not(:checked)~label .sheet-de,input[value=de]:not(:checked)~span .sheet-de,input[value=en]:not(:checked)~div .sheet-en,input[value=en]:not(:checked)~label .sheet-en,input[value=en]:not(:checked)~span .sheet-en,input[value=es]:not(:checked)~div .sheet-es,input[value=es]:not(:checked)~label .sheet-es,input[value=es]:not(:checked)~span .sheet-es,input[value=fr]:not(:checked)~div .sheet-fr,input[value=fr]:not(:checked)~label .sheet-fr,input[value=fr]:not(:checked)~span .sheet-fr,input[value=ru]:not(:checked)~div .sheet-ru,input[value=ru]:not(:checked)~label .sheet-ru,input[value=ru]:not(:checked)~span .sheet-ru{display:none}input[class^=sheet-toggle-],span[class^=sheet-toggle-]{vertical-align:top}.sheet-vert-middle{vertical-align:middle}input[class^=sheet-toggle-]{cursor:pointer;opacity:0;position:relative;z-index:999}input[class^=sheet-toggle-]:active+span[class^=sheet-toggle-].sheet-button{box-shadow:0 4px 8px 0 rgba(0,0,0,.4)}span[class^=sheet-toggle-]{background-color:#a19a91;border-radius:3px;color:rgba(255,255,255,.87);cursor:pointer;display:inline-block;font-size:10px;padding:1px;position:relative;text-align:center}input.sheet-toggle-page-core,span.sheet-toggle-page-core{width:36px}span.sheet-toggle-page-core{margin-left:-36px}input.sheet-toggle-page-spells,span.sheet-toggle-page-spells{width:43px}input.sheet-toggle-page-character,input.sheet-toggle-page-equipment,span.sheet-toggle-page-character,span.sheet-toggle-page-equipment{width:69px}span.sheet-toggle-page-spells{margin-left:-43px}span.sheet-toggle-page-character,span.sheet-toggle-page-equipment{margin-left:-69px}input.sheet-toggle-page-settings,span.sheet-toggle-page-settings{width:19px}span.sheet-toggle-page-settings{margin-left:-19px}input.sheet-toggle-page-all,span.sheet-toggle-page-all{width:24px}span.sheet-toggle-page-all{margin-left:-24px}input.sheet-toggle-icon-attack-settings,span.sheet-toggle-icon-attack-settings{width:17px}span.sheet-toggle-icon-attack-settings{margin-left:-17px}input.sheet-toggle-edit-mode,span.sheet-toggle-edit-mode{width:23px}span.sheet-toggle-edit-mode{margin-left:-23px}input.sheet-toggle-pseudo-button,span.sheet-toggle-pseudo-button{width:104px}input.sheet-toggle-spells-filter-prepared,input.sheet-toggle-spells-prepared,span.sheet-toggle-spells-filter-prepared,span.sheet-toggle-spells-prepared{width:47px}span.sheet-toggle-pseudo-button{margin-left:-104px}span.sheet-toggle-spells-filter-prepared,span.sheet-toggle-spells-prepared{margin-left:-47px}input.sheet-toggle-spells-filter-ritual,input.sheet-toggle-spells-ritual,span.sheet-toggle-spells-filter-ritual,span.sheet-toggle-spells-ritual{width:30px}span.sheet-toggle-spells-filter-ritual,span.sheet-toggle-spells-ritual{margin-left:-30px}input.sheet-toggle-spells-concentration,input.sheet-toggle-spells-filter-concentration,span.sheet-toggle-spells-concentration,span.sheet-toggle-spells-filter-concentration{width:69px}span.sheet-toggle-spells-concentration,span.sheet-toggle-spells-filter-concentration{margin-left:-69px}input.sheet-toggle-spells-filter-somatic,input.sheet-toggle-spells-filter-verbal,span.sheet-toggle-spells-filter-somatic,span.sheet-toggle-spells-filter-verbal{width:13px}span.sheet-toggle-spells-filter-somatic,span.sheet-toggle-spells-filter-verbal{margin-left:-13px}input.sheet-toggle-spells-filter-material,span.sheet-toggle-spells-filter-material{width:14px}input.sheet-toggle-spell-vsm-s,input.sheet-toggle-spell-vsm-v,span.sheet-toggle-spell-vsm-s,span.sheet-toggle-spell-vsm-v{width:13px}span.sheet-toggle-spells-filter-material{margin-left:-14px}span.sheet-toggle-spell-vsm-s,span.sheet-toggle-spell-vsm-v{margin-left:-13px}input.sheet-toggle-spell-vsm-m,span.sheet-toggle-spell-vsm-m{width:14px}span.sheet-toggle-spell-vsm-m{margin-left:-14px}input.sheet-toggle-spell-filters,span.sheet-toggle-spell-filters{width:33px}span.sheet-toggle-spell-filters{margin-left:-33px}input.sheet-toggle-spells-filter-level-cantrips,span.sheet-toggle-spells-filter-level-cantrips{width:43px}span.sheet-toggle-spells-filter-level-cantrips{margin-left:-43px}input.sheet-toggle-spells-filter-level-all,span.sheet-toggle-spells-filter-level-all{width:17px}input.sheet-toggle-spells-filter-level-1,input.sheet-toggle-spells-filter-level-2,input.sheet-toggle-spells-filter-level-3,input.sheet-toggle-spells-filter-level-4,input.sheet-toggle-spells-filter-level-5,input.sheet-toggle-spells-filter-level-6,input.sheet-toggle-spells-filter-level-7,input.sheet-toggle-spells-filter-level-8,input.sheet-toggle-spells-filter-level-9,span.sheet-toggle-spells-filter-level-1,span.sheet-toggle-spells-filter-level-2,span.sheet-toggle-spells-filter-level-3,span.sheet-toggle-spells-filter-level-4,span.sheet-toggle-spells-filter-level-5,span.sheet-toggle-spells-filter-level-6,span.sheet-toggle-spells-filter-level-7,span.sheet-toggle-spells-filter-level-8,span.sheet-toggle-spells-filter-level-9{width:11px}span.sheet-toggle-spells-filter-level-all{margin-left:-17px}span.sheet-toggle-spells-filter-level-1,span.sheet-toggle-spells-filter-level-2,span.sheet-toggle-spells-filter-level-3,span.sheet-toggle-spells-filter-level-4,span.sheet-toggle-spells-filter-level-5,span.sheet-toggle-spells-filter-level-6,span.sheet-toggle-spells-filter-level-7,span.sheet-toggle-spells-filter-level-8,span.sheet-toggle-spells-filter-level-9{margin-left:-11px}input.sheet-toggle-spells-filter-casting-time-all,span.sheet-toggle-spells-filter-casting-time-all{width:17px}span.sheet-toggle-spells-filter-casting-time-all{margin-left:-17px}input.sheet-toggle-spells-filter-casting-time-reaction,span.sheet-toggle-spells-filter-casting-time-reaction{width:43px}span.sheet-toggle-spells-filter-casting-time-reaction{margin-left:-43px}input.sheet-toggle-spells-filter-casting-time-bonus,span.sheet-toggle-spells-filter-casting-time-bonus{width:35px}span.sheet-toggle-spells-filter-casting-time-bonus{margin-left:-35px}input.sheet-toggle-spells-filter-casting-time-action,span.sheet-toggle-spells-filter-casting-time-action{width:34px}span.sheet-toggle-spells-filter-casting-time-action{margin-left:-34px}input.sheet-toggle-description,span.sheet-toggle-description{width:57px}span.sheet-toggle-description{margin-left:-57px}input.sheet-toggle-saving-throw,span.sheet-toggle-saving-throw{width:30px}span.sheet-toggle-saving-throw{margin-left:-30px}input.sheet-toggle-heal,span.sheet-toggle-heal{width:27px}span.sheet-toggle-heal{margin-left:-27px}input.sheet-toggle-effects,span.sheet-toggle-effects{width:38px}span.sheet-toggle-effects{margin-left:-38px}input.sheet-toggle-spell-source,span.sheet-toggle-spell-source{width:39px}span.sheet-toggle-spell-source{margin-left:-39px}input.sheet-toggle-spell-from,span.sheet-toggle-spell-from{width:29px}span.sheet-toggle-spell-from{margin-left:-29px}input.sheet-toggle-recharge,span.sheet-toggle-recharge{width:51px}span.sheet-toggle-recharge{margin-left:-51px}input.sheet-toggle-spell-slots,span.sheet-toggle-spell-slots{width:53px}span.sheet-toggle-spell-slots{margin-left:-53px}input.sheet-toggle-spell-points,span.sheet-toggle-spell-points{width:60px}span.sheet-toggle-spell-points{margin-left:-60px}span.sheet-toggle-spells-filter-casting-time-reaction,span.sheet-toggle-spells-filter-level-cantrips{border-bottom-right-radius:0;border-top-right-radius:0}span.sheet-toggle-spells-filter-casting-time-action,span.sheet-toggle-spells-filter-casting-time-bonus,span.sheet-toggle-spells-filter-level-1,span.sheet-toggle-spells-filter-level-2,span.sheet-toggle-spells-filter-level-3,span.sheet-toggle-spells-filter-level-4,span.sheet-toggle-spells-filter-level-5,span.sheet-toggle-spells-filter-level-6,span.sheet-toggle-spells-filter-level-7,span.sheet-toggle-spells-filter-level-8,span.sheet-toggle-spells-filter-level-9{border-radius:0}span.sheet-toggle-spells-filter-casting-time-all,span.sheet-toggle-spells-filter-level-all{border-bottom-left-radius:0;border-top-left-radius:0}input.sheet-toggle-jack-of-all-trades,span.sheet-toggle-jack-of-all-trades{width:82px}span.sheet-toggle-jack-of-all-trades{margin-left:-82px}input.sheet-toggle-remarkable-athlete,span.sheet-toggle-remarkable-athlete{width:97px}span.sheet-toggle-remarkable-athlete{margin-left:-97px}input.sheet-toggle-query,span.sheet-toggle-query{width:34px}span.sheet-toggle-query{margin-left:-34px}input.sheet-toggle-halfling-luck,span.sheet-toggle-halfling-luck{width:65px}span.sheet-toggle-halfling-luck{margin-left:-65px}input.sheet-toggle-language,span.sheet-toggle-language{height:11px;width:16px}input.sheet-toggle-language:checked+span.sheet-toggle-language{opacity:1}span.sheet-toggle-language{background-repeat:no-repeat;margin-left:2px;margin-right:-16px;opacity:.4}span.sheet-toggle-language.sheet-en{background:url(http://i.imgur.com/TniJIqt.png)}span.sheet-toggle-language.sheet-de{background:url(http://i.imgur.com/xUhfiqu.png)}span.sheet-toggle-language.sheet-fr{background:url(http://i.imgur.com/94SeipS.png)}span.sheet-toggle-language.sheet-ru{background:url(http://i.imgur.com/9XCOBJX.png)}span.sheet-toggle-language.sheet-es{background:url(http://i.imgur.com/UcndHqG.png)}input.sheet-slide-input-pc:checked~.sheet-toggle-edit-mode,input.sheet-slide-input-pc:checked~div.sheet-section-core,input.sheet-slide-input-pc:not(:checked)~div.sheet-section-npc{display:none!important}input.sheet-slide-input-pc:checked~input.sheet-toggle-page-all:checked~div[class^=sheet-section-]:not(.sheet-pc),input.sheet-slide-input-pc:checked~input.sheet-toggle-page-core:checked~div.sheet-section-npc,input.sheet-slide-input-pc:not(:checked)~input.sheet-toggle-page-all:checked~div[class^=sheet-section-]:not(.sheet-npc),input.sheet-slide-input-pc:not(:checked)~input.sheet-toggle-page-core:checked~div.sheet-section-core,input.sheet-toggle-page-character:checked~div.sheet-section-character,input.sheet-toggle-page-equipment:checked~div.sheet-section-equipment,input.sheet-toggle-page-settings:checked~div.sheet-section-settings,input.sheet-toggle-page-spells:checked~div.sheet-section-spells{display:block}input.sheet-toggle-page-all:checked~div[class^=sheet-section-]:not(:last-of-type){border-bottom:10px solid #000;margin-bottom:5px;padding-bottom:5px}input[class^=sheet-toggle-page-],span[class^=sheet-toggle-page-]{height:16px}span[class^=sheet-toggle-page-]{font-size:12px;font-weight:700;padding:2px}input[class^=sheet-toggle-page-]:checked+span[class^=sheet-toggle-page-]{background-color:#416696!important}.sheet-spell .sheet-wrap-box{background-color:#f5f5f5;box-shadow:0 0 5px #676767;padding:3px}input[readonly]{background-color:inherit;cursor:inherit}input[class^=sheet-slide-input-]{cursor:pointer;display:inline-block;margin:0;opacity:0;position:relative;vertical-align:top;z-index:5}label[class^=sheet-slide-toggle-]{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#fff;border:1px solid #d9d9d9;border-bottom-color:#e6e6e6;border-radius:2px;box-shadow:inset 0 .1em .03em rgba(0,0,0,.2),inset 0 .1em .3em rgba(0,0,0,.3),0 0 2em rgba(255,255,255,.6);box-sizing:border-box;display:inline-block;font-size:10px;font-weight:400;margin-bottom:0;padding:0;perspective:300px;position:relative;text-align:left;vertical-align:top}label[class^=sheet-slide-toggle-] .sheet-slide-cover{background-color:#f5f5f5;box-shadow:.1em 0 .2em rgba(0,0,0,.3);color:#fff;display:inline-block;margin-right:-1px;margin-top:-1px;position:absolute;right:0;text-align:center;top:0;transition:all .2s ease-in-out;transition-duration:.13333s;transition-timing-function:cubic-bezier(.52,-.41,.55,1.46)}label[class^=sheet-slide-toggle-] span[class^=sheet-slide-toggle-]{display:inline-block;text-align:center;transition:all .2s ease-in-out}input.sheet-slide-input-pc,label.sheet-slide-toggle-pc{height:12px;width:80px}label.sheet-slide-toggle-pc{margin-left:-80px;line-height:12px}label.sheet-slide-toggle-pc .sheet-slide-cover{width:40px;height:12px;box-shadow:0 .12em .01em #394535,0 .12em .3em rgba(57,69,53,.6),0 .12em 2em rgba(0,0,0,.3),-.12em .15em .2em rgba(0,0,0,.2)}input[type=checkbox].sheet-slide-input-pc+label.sheet-slide-toggle-pc .sheet-slide-cover{background-color:#51624b;text-shadow:0 .05em 0 #455440}input[type=checkbox].sheet-slide-input-pc+label.sheet-slide-toggle-pc span[class^=sheet-slide-toggle-]{width:50%;color:#51624b}.sheet-creature-name,.sheet-spell-name,input[type=checkbox].sheet-slide-input-pc:checked+label.sheet-slide-toggle-pc span[class^=sheet-slide-toggle-]{color:#591209}input[type=checkbox].sheet-slide-input-pc:checked+label.sheet-slide-toggle-pc .sheet-slide-cover{background-color:#591209;margin-right:40px;border-bottom:.03em solid #871b0e;text-shadow:0 .05em 0 #2b0904;box-shadow:0 .12em .01em #2b0904,0 .12em .3em rgba(43,9,4,.6),0 .12em 2em rgba(0,0,0,.3),.12em .15em .2em rgba(0,0,0,.2)}input.sheet-toggle-hidden-info:checked~div.sheet-toggle-hidden-info{display:block}input.sheet-attack-toggle:not(:checked)~div.sheet-attack-toggle,input.sheet-has-barbarian-levels:not([value="1"])~div .sheet-has-barbarian-levels,input.sheet-has-bard-levels:not([value="1"])~div .sheet-has-bard-levels,input.sheet-has-cleric-levels:not([value="1"])~div .sheet-has-cleric-levels,input.sheet-has-druid-levels:not([value="1"])~div .sheet-has-druid-levels,input.sheet-has-fighter-levels:not([value="1"])~div .sheet-has-fighter-levels,input.sheet-has-monk-levels:not([value="1"])~div .sheet-has-monk-levels,input.sheet-has-paladin-levels:not([value="1"])~div .sheet-has-paladin-levels,input.sheet-has-ranger-levels:not([value="1"])~div .sheet-has-ranger-levels,input.sheet-has-rogue-levels:not([value="1"])~div .sheet-has-rogue-levels,input.sheet-has-sorcerer-levels:not([value="1"])~div .sheet-has-sorcerer-levels,input.sheet-has-warlock-levels:not([value="1"])~div .sheet-has-warlock-levels,input.sheet-has-wizard-levels:not([value="1"])~div .sheet-has-wizard-levels,input.sheet-show-uses:not(:checked)~.sheet-show-uses,input.sheet-toggle-alt-damage:not(:checked)~div div.sheet-toggle-alt-damage,input.sheet-toggle-custom-class:not(:checked)~.sheet-custom-class,input.sheet-toggle-edit-mode:checked~div .sheet-presentation,input.sheet-toggle-edit-mode:not(:checked)~div .sheet-edit,input.sheet-toggle-hd-d10:not(:checked)~div.sheet-toggle-hd-d10,input.sheet-toggle-hd-d12:not(:checked)~div.sheet-toggle-hd-d12,input.sheet-toggle-hd-d20:not(:checked)~div.sheet-toggle-hd-d20,input.sheet-toggle-hd-d2:not(:checked)~div.sheet-toggle-hd-d2,input.sheet-toggle-hd-d4:not(:checked)~div.sheet-toggle-hd-d4,input.sheet-toggle-hd-d6:not(:checked)~div.sheet-toggle-hd-d6,input.sheet-toggle-hd-d8:not(:checked)~div.sheet-toggle-hd-d8,input.sheet-toggle-icon-settings:not(:checked)~div .sheet-details,input.sheet-toggle-icon-settings:not(:checked)~div.sheet-details,input.sheet-toggle-range:not(:checked)~div div.sheet-toggle-range,input.sheet-toggle-reach:not(:checked)~div div.sheet-toggle-reach,input.sheet-toggle-spell-filters:not(:checked)~[class^=sheet-toggle-spells-filter],input.sheet-toggle-spell-filters:not(:checked)~span.sheet-spells-filter,input.sheet-toggle-spell-level-1:not(:checked)~div .sheet-spell-level-1,input.sheet-toggle-spell-level-2:not(:checked)~div .sheet-spell-level-2,input.sheet-toggle-spell-level-3:not(:checked)~div .sheet-spell-level-3,input.sheet-toggle-spell-level-4:not(:checked)~div .sheet-spell-level-4,input.sheet-toggle-spell-level-5:not(:checked)~div .sheet-spell-level-5,input.sheet-toggle-spell-level-6:not(:checked)~div .sheet-spell-level-6,input.sheet-toggle-spell-level-7:not(:checked)~div .sheet-spell-level-7,input.sheet-toggle-spell-level-8:not(:checked)~div .sheet-spell-level-8,input.sheet-toggle-spell-level-9:not(:checked)~div .sheet-spell-level-9,input.sheet-toggle-spell-points:not(:checked)~.sheet-spell-points,input.sheet-toggle-spell-slots:not(:checked)~.sheet-spell-slots,input.sheet-toggle-spell-slots:not(:checked)~div div.sheet-spell-slots-points,input.sheet-toggle-spells-filter-casting-time-action:checked~.repcontainer input.sheet-toggle-casting-time-action:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-casting-time-bonus:checked~.repcontainer input.sheet-toggle-casting-time-bonus:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-casting-time-reaction:checked~.repcontainer input.sheet-toggle-casting-time-reaction:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-concentration:not(:checked)~.repcontainer input.sheet-toggle-spells-concentration:checked~.sheet-spell,input.sheet-toggle-spells-filter-level-1:checked~.repcontainer input.sheet-toggle-spell-level-1:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-2:checked~.repcontainer input.sheet-toggle-spell-level-2:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-3:checked~.repcontainer input.sheet-toggle-spell-level-3:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-4:checked~.repcontainer input.sheet-toggle-spell-level-4:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-5:checked~.repcontainer input.sheet-toggle-spell-level-5:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-6:checked~.repcontainer input.sheet-toggle-spell-level-6:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-7:checked~.repcontainer input.sheet-toggle-spell-level-7:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-8:checked~.repcontainer input.sheet-toggle-spell-level-8:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-9:checked~.repcontainer input.sheet-toggle-spell-level-9:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-level-cantrips:checked~.repcontainer input.sheet-toggle-spell-level-cantrip:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-material:not(:checked)~.repcontainer input.sheet-toggle-spell-vsm-m:checked~.sheet-spell,input.sheet-toggle-spells-filter-prepared:checked~.repcontainer input.sheet-toggle-spells-prepared:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-ritual:checked~.repcontainer input.sheet-toggle-spells-ritual:not(:checked)~.sheet-spell,input.sheet-toggle-spells-filter-somatic:not(:checked)~.repcontainer input.sheet-toggle-spell-vsm-s:checked~.sheet-spell,input.sheet-toggle-spells-filter-verbal:not(:checked)~.repcontainer input.sheet-toggle-spell-vsm-v:checked~.sheet-spell,input.sheet-toggle-target:not(:checked)~div div.sheet-toggle-target{display:none}.sheet-spells-filter{display:inline-block;font-size:11px}input[class^=sheet-toggle-spells-filter],span[class^=sheet-toggle-spells-filter]{height:12px}.sheet-spell input,.sheet-spell select,.sheet-spell textarea{background-color:transparent}.sheet-action-name,.sheet-creature-name,.sheet-spell-name{border:0;font-family:'Times New Roman';font-size:17px;font-weight:700;padding:0!important}input[class^=sheet-toggle]:checked+span[class^=sheet-toggle]{background-color:#51624b}input[class^=sheet-toggle-icon]:checked+span[class^=sheet-toggle-icon],input[class^=sheet-toggle-edit-mode]:checked+span[class^=sheet-toggle-edit-mode]{background-color:transparent;color:rgba(255,255,1,.95);text-shadow:-1px 0 #000,0 1px #000,1px 0 #000,0 -1px #000}input[class^=sheet-toggle-spells]:checked+span[class^=sheet-toggle-spells]{background-color:#591209}span[class^=sheet-toggle-spells-filter]{font-size:10px}.sheet-rolltemplate-5e-shaped .sheet-zebra,.sheet-spell-points .sheet-shaped-row:nth-child(even),.sheet-spell-slots .sheet-shaped-row:nth-child(even),.sheet-zebra,.sheet-zebra-rows .sheet-shaped-row:nth-child(even){background-color:#E6F5F9}.sheet-spell-slots input{background:0 0}.sheet-toggle-icon-settings{height:16px;position:absolute!important;right:0;top:0;width:15px}input.sheet-toggle-icon-settings{height:16px}span.sheet-toggle-edit-mode,span.sheet-toggle-icon-settings{background-color:transparent;color:#8c8c8c;margin-top:0;text-shadow:-1px 0 #000,0 1px #000,1px 0 #000,0 -1px #000}span.sheet-toggle-icon-settings{font-size:14px;height:16px}span.sheet-toggle-edit-mode{font-size:22px}input.sheet-toggle-edit-mode,span.sheet-toggle-edit-mode{height:24px}input.sheet-toggle-edit-mode.sheet-negative-mar-t-eight,span.sheet-toggle-edit-mode.sheet-negative-mar-t-eight{margin-top:-8px}input.sheet-toggle-edit-mode:checked~div input:not([readonly]),input.sheet-toggle-edit-mode:checked~div select:not([readonly]),input.sheet-toggle-edit-mode:checked~div textarea:not([readonly]){background-color:rgba(255,255,1,.41)}input.sheet-toggle-edit-mode:not(:checked)~div.sheet-section-core .repcontrol,input.sheet-toggle-edit-mode:not(:checked)~div.sheet-section-core .sheet-item-to-toggle,input.sheet-toggle-edit-mode:not(:checked)~div.sheet-shaped-row .repcontrol,input.sheet-toggle-edit-mode:not(:checked)~div.sheet-shaped-row .sheet-item-to-toggle{display:none}.sheet-item-toggle[value="1"]+.sheet-item-to-toggle{display:block!important}.sheet-no-background{background-color:transparent!important}.sheet-rolltemplate-5e-shaped .sheet-small-label,.sheet-small-label{font-size:11px}.sheet-small-label select{-moz-appearance:none;-webkit-appearance:none;appearance:none}[class*=sheet-pictos]{font-size:14px}.sheet-pictos{font-family:Pictos}.sheet-border-right,.sheet-rolltemplate-5e-shaped .sheet-border-right{border-right:1px solid #000}.sheet-border-left,.sheet-rolltemplate-5e-shaped .sheet-border-left{border-left:1px solid #000}hr{margin:5px 0;background-image:linear-gradient(to right,transparent,rgba(0,0,0,.75),transparent);border:0;height:1px}span.sheet-spacer{display:block;margin-top:5px}.sheet-spacer-smd{margin-top:4px}.sheet-left{text-align:left!important}.sheet-center,.sheet-rolltemplate-5e-shaped .sheet-center{text-align:center}.sheet-right{text-align:right}textarea{height:150px;resize:both}.sheet-personality-traits{border-bottom-left-radius:0;border-bottom-right-radius:0}.sheet-bonds,.sheet-ideals{border-radius:0}.sheet-flaws{border-top-left-radius:0;border-top-right-radius:0}.sheet-one-line-textarea,.sheet-xs-textarea{height:1.417em}.sheet-two-line-textarea{height:2.15em}.sheet-three-line-textarea{height:3.2em}.sheet-four-line-textarea{height:4.2em}.sheet-five-line-textarea{height:5.2em}.sheet-six-line-textarea{height:6.2em}.sheet-eight-line-textarea{height:8.3em}.sheet-important-text,.sheet-rolltemplate-5e-shaped .sheet-important-text{color:red}.sheet-ammo .repcontainer,.sheet-rolltemplate-5e-shaped .sheet-shaped-row,.sheet-section-npc .sheet-skills .repcontainer,.sheet-section-spells .repcontainer,.sheet-shaped-row{display:flex;flex-direction:row;flex-wrap:wrap}.sheet-ammo .repcontainer.sheet-center,.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-center,.sheet-section-npc .sheet-skills .repcontainer.sheet-center,.sheet-section-spells .repcontainer.sheet-center,.sheet-shaped-row.sheet-center{justify-content:center}.sheet-ammo .repcontainer.sheet-vert-center,.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-vert-center,.sheet-section-npc .sheet-skills .repcontainer.sheet-vert-center,.sheet-section-spells .repcontainer.sheet-vert-center,.sheet-shaped-row.sheet-vert-center{align-items:center}.sheet-ammo .repcontainer.sheet-flex-end,.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-flex-end,.sheet-section-npc .sheet-skills .repcontainer.sheet-flex-end,.sheet-section-spells .repcontainer.sheet-flex-end,.sheet-shaped-row.sheet-flex-end{align-items:flex-end}.sheet-ammo .repcontainer.sheet-no-wrap,.sheet-rolltemplate-5e-shaped .sheet-shaped-row.sheet-no-wrap,.sheet-section-npc .sheet-skills .repcontainer.sheet-no-wrap,.sheet-section-spells .repcontainer.sheet-no-wrap,.sheet-shaped-row.sheet-no-wrap{flex-wrap:nowrap}.sheet-section-spells .repitem{width:50%}.sheet-section-spells .repitem:nth-child(even){padding-left:3px}.sheet-section-spells .repitem:nth-child(odd){padding-right:3px}.sheet-ammo .repitem{padding-left:2px;padding-right:2px}.sheet-section-core .sheet-ammo .repitem{width:25%}.sheet-section-equipment .sheet-ammo .repitem{width:20%}.sheet-section-spells .sheet-wrap-box textarea{font-size:11px}.sheet-col-1-3{width:33.33333%}.sheet-col-2-3{width:66.66667%}.sheet-col-1-6{width:16.66667%}.sheet-col-1-8{width:12.5%}.sheet-col-1-12{width:8.33333%}.sheet-col-1-3-em{width:1.3em}.sheet-col-2-em{width:2em}.sheet-col-01,.sheet-rolltemplate-5e-shaped .sheet-col-01{width:1%}.sheet-col-02,.sheet-rolltemplate-5e-shaped .sheet-col-02{width:2%}.sheet-col-03,.sheet-rolltemplate-5e-shaped .sheet-col-03{width:3%}.sheet-col-04,.sheet-rolltemplate-5e-shaped .sheet-col-04{width:4%}.sheet-col-05,.sheet-rolltemplate-5e-shaped .sheet-col-05{width:5%}.sheet-col-06,.sheet-rolltemplate-5e-shaped .sheet-col-06{width:6%}.sheet-col-07,.sheet-rolltemplate-5e-shaped .sheet-col-07{width:7%}.sheet-col-08,.sheet-rolltemplate-5e-shaped .sheet-col-08{width:8%}.sheet-col-09,.sheet-rolltemplate-5e-shaped .sheet-col-09{width:9%}.sheet-col-10,.sheet-rolltemplate-5e-shaped .sheet-col-10{width:10%}.sheet-col-11,.sheet-rolltemplate-5e-shaped .sheet-col-11{width:11%}.sheet-col-12,.sheet-rolltemplate-5e-shaped .sheet-col-12{width:12%}.sheet-col-13,.sheet-rolltemplate-5e-shaped .sheet-col-13{width:13%}.sheet-col-14,.sheet-rolltemplate-5e-shaped .sheet-col-14{width:14%}.sheet-col-15,.sheet-rolltemplate-5e-shaped .sheet-col-15{width:15%}.sheet-col-16,.sheet-rolltemplate-5e-shaped .sheet-col-16{width:16%}.sheet-col-17,.sheet-rolltemplate-5e-shaped .sheet-col-17{width:17%}.sheet-col-18,.sheet-rolltemplate-5e-shaped .sheet-col-18{width:18%}.sheet-col-19,.sheet-rolltemplate-5e-shaped .sheet-col-19{width:19%}.sheet-col-20,.sheet-rolltemplate-5e-shaped .sheet-col-20{width:20%}.sheet-col-21,.sheet-rolltemplate-5e-shaped .sheet-col-21{width:21%}.sheet-col-22,.sheet-rolltemplate-5e-shaped .sheet-col-22{width:22%}.sheet-col-23,.sheet-rolltemplate-5e-shaped .sheet-col-23{width:23%}.sheet-col-24,.sheet-rolltemplate-5e-shaped .sheet-col-24{width:24%}.sheet-col-25,.sheet-rolltemplate-5e-shaped .sheet-col-25{width:25%}.sheet-col-26,.sheet-rolltemplate-5e-shaped .sheet-col-26{width:26%}.sheet-col-27,.sheet-rolltemplate-5e-shaped .sheet-col-27{width:27%}.sheet-col-28,.sheet-rolltemplate-5e-shaped .sheet-col-28{width:28%}.sheet-col-29,.sheet-rolltemplate-5e-shaped .sheet-col-29{width:29%}.sheet-col-30,.sheet-rolltemplate-5e-shaped .sheet-col-30{width:30%}.sheet-col-31,.sheet-rolltemplate-5e-shaped .sheet-col-31{width:31%}.sheet-col-32,.sheet-rolltemplate-5e-shaped .sheet-col-32{width:32%}.sheet-col-33,.sheet-rolltemplate-5e-shaped .sheet-col-33{width:33%}.sheet-col-34,.sheet-rolltemplate-5e-shaped .sheet-col-34{width:34%}.sheet-col-35,.sheet-rolltemplate-5e-shaped .sheet-col-35{width:35%}.sheet-col-36,.sheet-rolltemplate-5e-shaped .sheet-col-36{width:36%}.sheet-col-37,.sheet-rolltemplate-5e-shaped .sheet-col-37{width:37%}.sheet-col-38,.sheet-rolltemplate-5e-shaped .sheet-col-38{width:38%}.sheet-col-39,.sheet-rolltemplate-5e-shaped .sheet-col-39{width:39%}.sheet-col-40,.sheet-rolltemplate-5e-shaped .sheet-col-40{width:40%}.sheet-col-41,.sheet-rolltemplate-5e-shaped .sheet-col-41{width:41%}.sheet-col-42,.sheet-rolltemplate-5e-shaped .sheet-col-42{width:42%}.sheet-col-43,.sheet-rolltemplate-5e-shaped .sheet-col-43{width:43%}.sheet-col-44,.sheet-rolltemplate-5e-shaped .sheet-col-44{width:44%}.sheet-col-45,.sheet-rolltemplate-5e-shaped .sheet-col-45{width:45%}.sheet-col-46,.sheet-rolltemplate-5e-shaped .sheet-col-46{width:46%}.sheet-col-47,.sheet-rolltemplate-5e-shaped .sheet-col-47{width:47%}.sheet-col-48,.sheet-rolltemplate-5e-shaped .sheet-col-48{width:48%}.sheet-col-49,.sheet-rolltemplate-5e-shaped .sheet-col-49{width:49%}.sheet-col-50,.sheet-rolltemplate-5e-shaped .sheet-col-50{width:50%}.sheet-col-51,.sheet-rolltemplate-5e-shaped .sheet-col-51{width:51%}.sheet-col-52,.sheet-rolltemplate-5e-shaped .sheet-col-52{width:52%}.sheet-col-53,.sheet-rolltemplate-5e-shaped .sheet-col-53{width:53%}.sheet-col-54,.sheet-rolltemplate-5e-shaped .sheet-col-54{width:54%}.sheet-col-55,.sheet-rolltemplate-5e-shaped .sheet-col-55{width:55%}.sheet-col-56,.sheet-rolltemplate-5e-shaped .sheet-col-56{width:56%}.sheet-col-57,.sheet-rolltemplate-5e-shaped .sheet-col-57{width:57%}.sheet-col-58,.sheet-rolltemplate-5e-shaped .sheet-col-58{width:58%}.sheet-col-59,.sheet-rolltemplate-5e-shaped .sheet-col-59{width:59%}.sheet-col-60,.sheet-rolltemplate-5e-shaped .sheet-col-60{width:60%}.sheet-col-61,.sheet-rolltemplate-5e-shaped .sheet-col-61{width:61%}.sheet-col-62,.sheet-rolltemplate-5e-shaped .sheet-col-62{width:62%}.sheet-col-63,.sheet-rolltemplate-5e-shaped .sheet-col-63{width:63%}.sheet-col-64,.sheet-rolltemplate-5e-shaped .sheet-col-64{width:64%}.sheet-col-65,.sheet-rolltemplate-5e-shaped .sheet-col-65{width:65%}.sheet-col-66,.sheet-rolltemplate-5e-shaped .sheet-col-66{width:66%}.sheet-col-67,.sheet-rolltemplate-5e-shaped .sheet-col-67{width:67%}.sheet-col-68,.sheet-rolltemplate-5e-shaped .sheet-col-68{width:68%}.sheet-col-69,.sheet-rolltemplate-5e-shaped .sheet-col-69{width:69%}.sheet-col-70,.sheet-rolltemplate-5e-shaped .sheet-col-70{width:70%}.sheet-col-71,.sheet-rolltemplate-5e-shaped .sheet-col-71{width:71%}.sheet-col-72,.sheet-rolltemplate-5e-shaped .sheet-col-72{width:72%}.sheet-col-73,.sheet-rolltemplate-5e-shaped .sheet-col-73{width:73%}.sheet-col-74,.sheet-rolltemplate-5e-shaped .sheet-col-74{width:74%}.sheet-col-75,.sheet-rolltemplate-5e-shaped .sheet-col-75{width:75%}.sheet-col-76,.sheet-rolltemplate-5e-shaped .sheet-col-76{width:76%}.sheet-col-77,.sheet-rolltemplate-5e-shaped .sheet-col-77{width:77%}.sheet-col-78,.sheet-rolltemplate-5e-shaped .sheet-col-78{width:78%}.sheet-col-79,.sheet-rolltemplate-5e-shaped .sheet-col-79{width:79%}.sheet-col-80,.sheet-rolltemplate-5e-shaped .sheet-col-80{width:80%}.sheet-col-81,.sheet-rolltemplate-5e-shaped .sheet-col-81{width:81%}.sheet-col-82,.sheet-rolltemplate-5e-shaped .sheet-col-82{width:82%}.sheet-col-83,.sheet-rolltemplate-5e-shaped .sheet-col-83{width:83%}.sheet-col-84,.sheet-rolltemplate-5e-shaped .sheet-col-84{width:84%}.sheet-col-85,.sheet-rolltemplate-5e-shaped .sheet-col-85{width:85%}.sheet-col-86,.sheet-rolltemplate-5e-shaped .sheet-col-86{width:86%}.sheet-col-87,.sheet-rolltemplate-5e-shaped .sheet-col-87{width:87%}.sheet-col-88,.sheet-rolltemplate-5e-shaped .sheet-col-88{width:88%}.sheet-col-89,.sheet-rolltemplate-5e-shaped .sheet-col-89{width:89%}.sheet-col-90,.sheet-rolltemplate-5e-shaped .sheet-col-90{width:90%}.sheet-col-91,.sheet-rolltemplate-5e-shaped .sheet-col-91{width:91%}.sheet-col-92,.sheet-rolltemplate-5e-shaped .sheet-col-92{width:92%}.sheet-col-93,.sheet-rolltemplate-5e-shaped .sheet-col-93{width:93%}.sheet-col-94,.sheet-rolltemplate-5e-shaped .sheet-col-94{width:94%}.sheet-col-95,.sheet-rolltemplate-5e-shaped .sheet-col-95{width:95%}.sheet-col-96,.sheet-rolltemplate-5e-shaped .sheet-col-96{width:96%}.sheet-col-97,.sheet-rolltemplate-5e-shaped .sheet-col-97{width:97%}.sheet-col-98,.sheet-rolltemplate-5e-shaped .sheet-col-98{width:98%}.sheet-col-99,.sheet-rolltemplate-5e-shaped .sheet-col-99{width:99%}.sheet-col-100,.sheet-rolltemplate-5e-shaped .sheet-col-100{width:100%}.sheet-offset-20{margin-left:20%}.sheet-gm-info-block,.sheet-gm-info-flex,.sheet-gm-info-inline-block,.sheet-rolltemplate-5e-shaped .sheet-gm-info-block,.sheet-rolltemplate-5e-shaped .sheet-gm-info-flex,.sheet-rolltemplate-5e-shaped .sheet-gm-info-inline-block{background-color:#f2f5d3!important;display:none}.sheet-section-npc input,.sheet-section-npc select,.sheet-section-npc textarea{background:0 0;color:inherit;padding-bottom:0;padding-top:0}.sheet-section-npc select{height:1.1em}.sheet-section-npc .btn[type=roll]{font-size:13px!important}.sheet-section-npc .sheet-bar{height:5px;background:#E69A28;background:repeating-linear-gradient(15deg,#E69A28,#CA8929 5px,#CA8929 5px,#E69A28 10px);border:1px solid #000;position:relative;z-index:1}.sheet-section-npc .sheet-npc-content-wrap{background:url(http://i.imgur.com/hggz0ed.jpg);font-family:'Noto Sans','Myriad Pro',Calibri,Helvetica,Arial,sans-serif;font-size:14px;padding:.6em .3em;border:1px solid #DDD;box-shadow:0 0 1.5em #867453;position:relative;z-index:0;margin-left:2px;margin-right:2px}.sheet-section-npc .sheet-parenthesis-wrapper::after,.sheet-section-npc .sheet-parenthesis-wrapper::before{font-size:13px;top:1px;color:#3A0E06}.sheet-section-npc .sheet-creature-name{font-family:Lora,'Calisto MT','Bookman Old Style',Bookman,'Goudy Old Style',Garamond,'Hoefler Text','Bitstream Charter',Georgia,serif;color:#3A0E06;font-weight:700;margin-top:-6px;margin-bottom:-2px;font-size:25px;letter-spacing:2px;font-variant:small-caps}.sheet-section-npc h3{border-bottom:1px solid #3A0E06;color:#3A0E06;font-size:20px;font-variant:small-caps;font-weight:400;margin:0;line-height:110%}.sheet-section-npc .sheet-heading{font-weight:700}.sheet-section-npc .sheet-top-stats,.sheet-section-npc .sheet-top-stats button,.sheet-section-npc .sheet-top-stats input,.sheet-section-npc .sheet-top-stats textarea{color:#3A0E06}.sheet-section-npc .sheet-divider{border-top:3px solid transparent;border-bottom:3px solid transparent;border-left:400px solid #922610;margin:5px 0}.sheet-section-npc .sheet-skills .repitem:last-child .sheet-comma{display:none} \ No newline at end of file diff --git a/D&D_5e_Reshaped/D&D_5e.html b/D&D_5e_Reshaped/D&D_5e.html index bafc6b8b80..d1f4b66d2d 100644 --- a/D&D_5e_Reshaped/D&D_5e.html +++ b/D&D_5e_Reshaped/D&D_5e.html @@ -1,4 +1,5 @@ -
Shaped v
Dungeons & Dragons (5th edition)
Character nameCharakter NameNom du personnageИмя Персонажа
/
CoreKernBaseCore SpellsZauberSortsМагия EquipmentAusrüstungÉquipementEquipment CharacterCharakterPersonnageCharacter y AllAllesToutAll p
Saving ThrowsRettungswürfeJets de sauvegardeSaving Throws
Generate skillsFertigkeiten erzeugenGénérerGenerate skills
SkillsFertigkeitenCompétencesНавыки
Other Proficiencies & LanguagesAndere BefähigungenMaîtrises & LanguesOther Proficiencies & Languages
/
/
/
/
/
/
/
/
Hit diceHit diceDés de vieКость Хитов
SuccessesErfolgeRéussitesSuccesses

FailuresFehlschlägeÉchecsFailures

/
y
HealHeilungSoinsHeal.
+
QueryQueryVarieQuery
ExtrasExtrasExtrasExtras.
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
ResourcesRessourcenResourcesResources
Spell slotsZauberslotsEmplacem.Spell slots Spell pointsZauberpunktePointsSpell points
1st1.1er1st
/
2nd2.2ème2nd
/
3rd3.3ème3rd
/
4th4.4ème4th
/
5th5.5ème5th
/
6th6.6ème6th
/
7th7.7ème7th
/
8th8.8ème8th
/
9th9.9ème9th
/
Spell slotsZauberslotsEmplacement de sortSpell slots
1st1.1er1st
2
2nd2.2ème2nd
3
3rd3.3ème3rd
5
4th4.4ème4th
6
5th5.5ème5th
7
6th6.6ème6th
9
7th7.7ème7th
10
8th8.8ème8th
11
9th9.9ème9th
13
/
Spell pointsZauberpunktePoints de sortSpell points
?
Recharges on a long rest (4 recharge on a short rest if lvl 20)Recharges on a long rest (4 recharge on a short rest if lvl 20)Recharge après un repos long (4 recharges après un repos court au niv 20).Recharges on a long rest (4 recharge on a short rest if lvl 20)
/
Sorcery PointsHexpunktePoints de SorcelerieSorcery Points
?
Recharges on a long or short rest and are all of the same levelRecharges on a long or short rest and are all of the same levelRecharge après un repos court ou long et ont tous le même niveauRecharges on a long or short rest and are all of the same level
/
Warlock spell slotsHexer ZauberslotsEmplacement de sort (Sorcier)Warlock spell slots
AttackAngriffAttaqueAttack
ATKATTATQATK
DamageSchadenDégâtsDamage
y
NameNameNomНаименование
TypeTypTypeТип
ReachReichweiteAllongeReach
RangeReichweitePortéeRange
AmmoMunitionMunAmmo
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
AttacksAngriffeAttaquesНападки
ArmorRüstungArmureДоспехи
ACRKCAКБ

EquipmentAusrüstungÉquipementEquipment
QtyMengeQtéКлво
EquipmentAusrüstungÉquipementEquipment
TypeTypTypeТип
RechargeAufladungRechargeRecharge
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
HealHeilungSoinsHeal.
+
+
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
Below will be removed shortly. Please port it over to the new version above.
Features & TraitsTalente & FertigkeitenTraits Raciaux & CapacitésFeatures & Traits
Resistances & ImmunitiesResistenzen & ImmunitätenRésistances & ImmunitésResistances & Immunities
?
LevelStufeNiveauУровеньEffectEffektEffetsEffect
1Disadvantage on ability checksNachteil auf FähigkeitschecksDésavantage aux jets de caractéristiquesDisadvantage on ability checks
2Speed halvedGeschwindigkeit halbiertVitesse diminuée de moitiéSpeed halved
3Disadvantage on attack rolls and saving throwsNachteil auf Angriffswürfe & RettungswürfeDésavantage aux jets d'attaque et de sauvegardeDisadvantage on attack rolls and saving throws
4Hit point maximum halvedTrefferpunkte-Maximum halbiertPoints de vie maximums diminués de moitiéHit point maximum halved
5Speed reduced to 0Geschwindigkeit reduziert auf 0Vitesse réduite à 0Speed reduced to 0
6DeathTodMortDeath
p
,
()
()
()
()
()
()
Saving ThrowsRettungswürfeJets de sauvegardeSaving Throws
,
,
,
,
,
SkillsFertigkeitenCompétencesНавыки
,
Generate skillsFertigkeiten erzeugenGénérerGenerate skills
TypeTypTypeТип
RechargeAufladungRechargeRecharge
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
HealHeilungSoinsHeal.
+
+
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

ActionsAktionenActionsActions

TypeTypTypeТип
ReachReichweiteAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

ReactionsReaktionenRéactionsReactions

TypeTypTypeТип
ReachReichweiteAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

Legendary actionsLegendary actionsActions légendairesLegendary actions

TheTheUn(e)The can takecan takepeut prendrecan take
 legendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. Thelegendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. Theactions légendaires, en choix parmi les options suivantes. Une seule action légendaire peut être utilisée à la fois et uniquement à la fin du tour d'une autre créature. Un(e)legendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. The regains spent legendary actions at the start of its turn.regains spent legendary actions at the start of its turn.récupère les actions légendaires dépensées au début de son tour de jeu.regains spent legendary actions at the start of its turn.
TypeTypTypeТип
ReachReichweiteAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

Lair ActionsLair ActionsActions de repaireLair Actions

TypeTypTypeТип
ReachReichweiteAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
Filters PreparedVorbereitetPréparéPrepared RitualRitualRituelRitual CantripsZaubertricksCantripsCantrips123456789AllAllesToutAll ReactionReaktionRéactionReactionBonusBonusBonusБонусActionAktionActionActionAllAllesToutAll Spells can haveZauber kann habenSorts peuvent avoirSpells can have: ConcentrationKonzentrationConcentrationConcentration V S M
SpellZauberSortSpell
LevelStufeNiveauУровень
Casting TimeZauberzeitTemps d'incantationCasting Time
ConcKonz.ConcConc
SpellZauberSortSpell
LevelStufeNiveauУровень
Casting TimeZauberzeitTemps d'incantationCasting Time
ConcKonz.ConcConc
y
RitualRitualRituelRitual
PreparedVorbereitetPréparéPrepared
Casting TimeZauberzeitTemps d'incantationCasting Time:
RangeReichweitePortéeRange:
ComponentsKomponentenComposantesComponents:
DurationDauerDuréeDuration:
ConcentrationKonzentrationConcentrationConcentration
TargetZielCibleTarget:
ContentInhaltContenuContent.
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
HealHeilungSoinsHeal.
+
+
Higher levelHigher levelNiveau SupHigher level.
DiceWürfelDésDice
DieWürfelDie
2nd2.2ème2nd DiceWürfelDésDice
2nd2.2ème2nd DieWürfelDie
Flat healEinfache HeilungBonus soinFlat heal
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
SpellsZauberSortsМагия
Spell slotsZauberslotsEmplacem.Spell slots Spell pointsZauberpunktePointsSpell points
1st1.1er1st
/
2nd2.2ème2nd
/
3rd3.3ème3rd
/
4th4.4ème4th
/
5th5.5ème5th
/
6th6.6ème6th
/
7th7.7ème7th
/
8th8.8ème8th
/
9th9.9ème9th
/
Spell slotsZauberslotsEmplacement de sortSpell slots
1st1.1er1st
2
2nd2.2ème2nd
3
3rd3.3ème3rd
5
4th4.4ème4th
6
5th5.5ème5th
7
6th6.6ème6th
9
7th7.7ème7th
10
8th8.8ème8th
11
9th9.9ème9th
13
/
Spell pointsZauberpunktePoints de sortSpell points
?
Recharges on a long rest (4 recharge on a short rest if lvl 20)Recharges on a long rest (4 recharge on a short rest if lvl 20)Recharge après un repos long (4 recharges après un repos court au niv 20).Recharges on a long rest (4 recharge on a short rest if lvl 20)
/
Sorcery PointsHexpunktePoints de SorcelerieSorcery Points
?
Recharges on a long or short rest and are all of the same levelRecharges on a long or short rest and are all of the same levelRecharge après un repos court ou long et ont tous le même niveauRecharges on a long or short rest and are all of the same level
/
Warlock spell slotsHexer ZauberslotsEmplacement de sort (Sorcier)Warlock spell slots
SpellcastingZaubernLancement de sortSpellcasting
ATKATTATQATK
DMGDMGDMGDMG
Saving DCRettungs-SGDD de sauvSaving DC
HealHeilungSoinsHeal
Bonuses & PenaltiesBoni & MaliBonus & MalusBonuses & Penalties
?
This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.Ceci ajoutera automatiquement la caractéristique pour déterminer le DD de sauvegarde lors de l'importation d'un sort ou d'une attaque. Si "Ajoutez la carac de lancement de sort" est également activé sur l'objet importé, la caractéristique de dégâts ou de soins changera en conséquence.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.
Default abilityStandardfähigkeitCarac par défautDefault ability
ArmorRüstungArmureДоспехи
TypeTypTypeТип
ACRKCAКБ
BonusBonusBonusБонус
TotalGesamtTotalВсего
StrengthStärkeForceСила
StealthTarnungDiscrétionStealth
WeightGewichtPoidsВес
+
=
Armored ACGepanzerte-RKCA (armure)КБ (в доспехах)
Unarmored abilityUngepanzerte FähigkeitBonus de carac (CA sans armure)Unarmored ability
Unarmored ACUngepanzerte-RKCA (sans armure)КБ (без доспехов)
ArmorRüstungArmureДоспехи
AttacksAngriffeAttaquesНападки
ArmorRüstungArmureДоспехи
EquipmentAusrüstungÉquipementEquipment
CoinageMünzenMonnaieчеканка монет
MiscSonstigesAutreMisc
TotalGesamtTotalВсего
WeightGewichtPoidsВес
Carrying capacityTrage-KapazitätCapacité de chargeГрузоподъемность
Push/Drag/LiftZiehen/Schieben/HebenPousse/Tire/LèveМожно поднять\перенести
EncumberedBeladenEncombréПерегрузка
H. EncumberedSchw. BeladenL. EncombréСил.Перегрузка
WeightGewichtPoidsВес
EquipmentAusrüstungÉquipementEquipment
ContentInhaltContenuContent
QtyMengeQtéКлво
WeightGewichtPoidsВес
TotalGesamtTotalВсего
×
=

AttackAngriffAttaqueAttack
WeightGewichtPoidsВес
AmmoMunitionMunAmmo
Ammo weightMunitionsgewichtPoids des munAmmo weight
TotalGesamtTotalВсего
+
×
=
EquipmentAusrüstungÉquipementEquipment
ClassKlasseClasseClass
LevelStufeNiveauУровень
Hit diceHit diceDés de vieКость Хитов
SpellcastingZaubernLancement de sortSpellcasting
Custom nameBenutzerdef. NameNom persoCustom name
Class levelsKlassenstufenNiveaux de classeClass levels
?
This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.Ceci ajoutera automatiquement la caractéristique pour déterminer le DD de sauvegarde lors de l'importation d'un sort ou d'une attaque. Si "Ajoutez la carac de lancement de sort" est également activé sur l'objet importé, la caractéristique de dégâts ou de soins changera en conséquence.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.
Default abilityStandardfähigkeitCarac par défautDefault ability
LevelStufeNiveauУровень
CalcCalcCalcCalc
BonusBonusBonusБонус
MaxMaxMaxMax
1st1.1er1st
+
=
2nd2.2ème2nd
+
=
3rd3.3ème3rd
+
=
4th4.4ème4th
+
=
5th5.5ème5th
+
=
6th6.6ème6th
+
=
7th7.7ème7th
+
=
8th8.8ème8th
+
=
9th9.9ème9th
+
=
Spell slotsZauberslotsEmplacem.Spell slots
GenderGeschlechtSexeПол
SizeGrößeCatégorie de tailleРазмер
AgeAlterAgeВозраст
HeightHöheTailleРост
WeightGewichtPoidsВес
EyesAugenYeuxГлаза
SkinHautPeauКожа
HairHaarCheveuxВолосы
AppearanceAussehenApparenceВнешний Вид
BlindsightBlindsichtVision aveugleСлеповидение
DarkvisionDunkelsichtVision dans le noirТемновидение
TremorsenseBebensinnPerception des vibrationsЧувство вибрации
TruesightWahrsichtVision véritableИстинное зрение
VisionSichtVisionVision
BurrowGrabenCreusementПолзание
ClimbKletternEscaladeClimb
FlyFliegenVolFly
SwimSchwimmenNageSwim
MovementBewegungMouvementMovement
Jack of all tradesJack of all tradesTouche-à-toutМастер на все руки Remarkable AthleteRemarkable AthleteAthlète remarquableRemarkable Athlete Halfling LuckHalblings GlückChance (Half)Halfling Luck
everyeveryeveryevery
RogueSchurkeRoublardПлут levelslevelslevelslevels
FeaturesTalenteCapacités spécialesFeatures
Miscellaneous notesSonstige NotizenAutres notesMiscellaneous notes
Sheet outputSheet outputLes jets de cette fiche doivent êtreSheet output
Death saving throws outputTodesrettungswürfeChuchoter jets contre la mortDeath saving throws output
Initiative outputInitiative outputChuchoter l'initiativeInitiative output
Character Name on all roll templatesCharakter Name auf allen WürfenNom du perso sur tous les jetsCharacter Name on all roll templates
Roll optionsRoll optionsOptions de jetRoll options:
InitiativeInitiativeInitiativeInitiative:
Break Initiative TiesBreak Initiative TiesAjoute Mod Dex à l'initBreak Initiative Ties
Initiative RollInitiative RollJet d'initiativeInitiative Roll
Show Target's AC on AttacksShow Target's AC on AttacksMontrer la CA de la cible sur les jets d'attaqueShow Target's AC on Attacks
Show Target's Name on Attacks and SavesShow Target's Name on Attacks and SavesMontrer le nom de la cible sur les jets d'attaque et de sauvegardeShow Target's Name on Attacks and Saves
OutputAusgabeOptions d'affichageРезультат
AbilityFähigkeitCaractéristiqueAbility
Ability score bonusFähigkeitsbonusBonus Mod de carac.Ability score bonus
Check bonusCheck bonusBonus Jet de CaracCheck bonus
Saving throw bonusRettungswurfbonusBonus jet de sauvSaving throw bonus
StrengthStärkeForceСила
DexterityGeschickDextéritéЛовкость
ConstitutionKonstitutionConstitutionТелосложение
IntelligenceIntelligenzIntelligenceИнтеллект
WisdomWeisheitSagesseМудрость
CharismaCharismaCharismeХаризма
AllAllesToutAll

Medium armor max dexMedium armor max dexBonus dex max (armure intermédaire)Medium armor max dex
Initiative bonusInitiative bonusBonus initiativeInitiative bonus
BonusesBoniBonusBonuses
?
Auto add a bonus/penalty to rolls made using the sheet macros.
Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter "d4cs0cf0" in both attack roll fields, and the saving throw one
Auto add a bonus/penalty to rolls made using the sheet macros.
Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter "d4cs0cf0" in both attack roll fields, and the saving throw one
Ajoute automatiquement un bonus/malus aux jets effectués à l'aide des macros de la fiche de Personnage.
Utilisation: Vous trouvez un objet magique qui vous donne +1 à vos dommages, entrez 1 dans la case Dmg des Armes. Si vous êtes sous les effet du sort Bénediction, entrez "d4cs0cf0" dans les cases de jets d'attaque et de jets de sauvegarde.
Auto add a bonus/penalty to rolls made using the sheet macros.
Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter "d4cs0cf0" in both attack roll fields, and the saving throw one
AttacksAngriffeAttaquesНападки
MeleeNahkampfMêléeMelee
RangedReichweiteTirRanged
AttackAngriffAttaqueAttack
DamageSchadenDégâtsDamage
AttackAngriffAttaqueAttack
DamageSchadenDégâtsDamage
AttackAngriffAttaqueAttack
DamageSchadenDégâtsDamage
SpellcastingZaubernLancement de sortSpellcasting
ATKATTATQATK
DMGDMGDMGDMG
Saving DCRettungs-SGDD de sauvSaving DC
HealHeilungSoinsHeal
Bonuses & PenaltiesBoni & MaliBonus & MalusBonuses & Penalties
LevelStufeNiveauУровень
CalcCalcCalcCalc
BonusBonusBonusБонус
MaxMaxMaxMax
1st1.1er1st
+
=
2nd2.2ème2nd
+
=
3rd3.3ème3rd
+
=
4th4.4ème4th
+
=
5th5.5ème5th
+
=
6th6.6ème6th
+
=
7th7.7ème7th
+
=
8th8.8ème8th
+
=
9th9.9ème9th
+
=
Spell slotsZauberslotsEmplacem.Spell slots
Copper per Gold (default 100)Kupfer pro Gold (standard 100)Cuivre par Or (100 par défaut)Copper per Gold (default 100):
Silver per Gold (default 10)Silber pro Gold (standard 10)Argent par Or (10 par défaut)Silver per Gold (default 10):
Electrum per Gold (default 2)Elektrum pro Gold (standard 2)Electrum par Or (2 par défaut)Electrum per Gold (default 2):
Gold per Platinum (default 10)Gold pro Platinum (standard 10)Or par Platine (10 par défaut)Gold per Platinum (default 10):
Custom gold valuesBenutzerdef. Gold-WerteValeur de l'or personnaliséeCustom gold values
y
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
Ability ChecksFähigkeits-CheckJet de CaracAbility Checks
Saving ThrowsRettungswürfeJets de sauvegardeSaving Throws
MiscSonstigesAutreMisc
SkillsFertigkeitenCompétencesНавыки
StrengthStärkeForceСила
DexterityGeschickDextéritéЛовкость
ConstitutionKonstitutionConstitutionТелосложение
IntelligenceIntelligenzIntelligenceИнтеллект
WisdomWeisheitSagesseМудрость
CharismaCharismaCharismeХаризма
InitiativeInitiativeInitiativeInitiative
StrengthStärkeForceСила
DexterityGeschickDextéritéЛовкость
ConstitutionKonstitutionConstitutionТелосложение
IntelligenceIntelligenzIntelligenceИнтеллект
WisdomWeisheitSagesseМудрость
CharismaCharismaCharismeХаризма
Death savesTodesrettungSauv contre la mortDeath saves
Hit diceHit diceDés de vieКость Хитов
AttackAngriffAttaqueAttack
SpellZauberSortSpell
SkillFertigkeitCompétenceSkill
AttachersAttachersAttachesAttachers
Please see the wiki. You'll need to use a browser extension to change the css to show certain partsPlease see the wiki. You'll need to use a browser extension to change the css to show certain partsMerci de vous référer au wiki. Vous aurez besoin d'une extension de navigateur pour changer le css afin de montrer certaines parties.Please see the wiki. You'll need to use a browser extension to change the css to show certain parts
Hide Saving throw DCHide Saving throw DCCacher DD de sauvHide Saving throw DC
Hide Spell contentHide Spell contentHide Spell contentHide Spell content
Hide Action freetextHide Action freetextHide Action freetextHide Action freetext
Hide Saving throw failureHide Saving throw failureCacher échec sauvHide Saving throw failure
Hide Saving throw successHide Saving throw successCacher succès sauvHide Saving throw success
Hide RechargeHide RechargeCacher RechargeHide Recharge
Hide NPC infoHide NPC infoCacher Infos PNJHide NPC info
MacrosMakrosMacrosMacros

+
Shaped v
Dungeons & Dragons (5th edition)
Character nameCharaktenameNom du personnageИмя Персонажа
/
CoreKernBaseCore SpellsZauberSortsМагия EquipmentAusrüstungÉquipementEquipment CharacterCharakterPersonnageCharacter y AllAllesToutAll p
CheckCheckJetCheck
+
+
CheckCheckJetCheck
+
+
CheckCheckJetCheck
+
+
CheckCheckJetCheck
+
+
CheckCheckJetCheck
+
+
CheckCheckJetCheck
+
+
Saving throwsRettungswürfeJets de sauvegardeSaving throws
( )
Generate skillsFertigkeiten erzeugenGénérerGenerate skills
SkillsFertigkeitenCompétencesНавыки
Other Proficiencies & LanguagesAndere BefähigungenMaîtrises & LanguesOther Proficiencies & Languages
+
/
/
/
/
/
/
/
/
Hit diceTrefferwürfelDés de vieКость Хитов
SuccessesErfolgeRéussitesSuccesses

FailuresFehlschlägeÉchecsFailures

Spell slotsZauberslotsEmplacem.Spell slots Spell pointsZauberpunktePointsSpell points
1st1.1er1st
/
2nd2.2ème2nd
/
3rd3.3ème3rd
/
4th4.4ème4th
/
5th5.5ème5th
/
6th6.6ème6th
/
7th7.7ème7th
/
8th8.8ème8th
/
9th9.9ème9th
/
Spell slotsZauberslotsEmplacement de sortSpell slots
1st1.1er1st
2
2nd2.2ème2nd
3
3rd3.3ème3rd
5
4th4.4ème4th
6
5th5.5ème5th
7
6th6.6ème6th
9
7th7.7ème7th
10
8th8.8ème8th
11
9th9.9ème9th
13
/
Spell pointsZauberpunktePoints de sortSpell points
/
y
DamageSchadenDégâtsDamage.
+
+
DamageSchadenDégâtsDamage.
+
+
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
HealHeilungSoinsHeal.
+
+
+
QueryQueryVarieQuery
ExtrasExtrasExtrasExtras.
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
Class featuresClass featuresClass featuresСпособности Класса
AttackAngriffAttaqueAttack
ATKATTATQATK
DamageSchadenDégâtsDamage
y
NameNameNomНаименование
TypeTypTypeТип
ReachBereichAllongeReach
RangeReichweitePortéeRange
/
UsesUsesUsesUses
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
AmmoMunitionMunAmmo.
AmmoMunitionMunAmmo
QtyMengeQtéКлво
WeightGewichtPoidsВес
AttacksAngriffeAttaquesНападки
ArmorRüstungArmureДоспехи
UsesUsesUsesUses
ACRKCAКБ
/

EquipmentAusrüstungÉquipementEquipment
UsesUsesUsesUses
QtyMengeQtéКлво
/
EquipmentAusrüstungÉquipementEquipment
Resistances & ImmunitiesResistenzen & ImmunitätenRésistances & ImmunitésResistances & Immunities
?
LevelStufeNiveauУровеньEffectEffektEffetsEffect
1Disadvantage on ability checksNachteil auf FähigkeitschecksDésavantage aux jets de caractéristiquesDisadvantage on ability checks
2Speed halvedGeschwindigkeit halbiertVitesse diminuée de moitiéSpeed halved
3Disadvantage on attack rolls and saving throwsNachteil auf Angriffswürfe & RettungswürfeDésavantage aux jets d'attaque et de sauvegardeDisadvantage on attack rolls and saving throws
4Hit point maximum halvedTrefferpunkte-Maximum halbiertPoints de vie maximums diminués de moitiéHit point maximum halved
5Speed reduced to 0Geschwindigkeit reduziert auf 0Vitesse réduite à 0Speed reduced to 0
6DeathTodMortDeath
TypeTypTypeТип
RechargeAufladungRechargeRecharge
y
Display textDisplay textDisplay textDisplay text
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
HealHeilungSoinsHeal.
+
+
+
QueryQueryVarieQuery
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
Below will be removed shortly. Please port it over to the new version above.
Features & TraitsTalente & FertigkeitenTraits Raciaux & CapacitésFeatures & Traits
p
,
( )
+
+
()
CheckCheckJetCheck
+
+
()
CheckCheckJetCheck
+
+
()
CheckCheckJetCheck
+
+
()
CheckCheckJetCheck
+
+
()
CheckCheckJetCheck
+
+
()
CheckCheckJetCheck
+
Saving throwsRettungswürfeJets de sauvegardeSaving throws
,
,
,
,
,
SkillsFertigkeitenCompétencesНавыки
( )
,
Generate skillsFertigkeiten erzeugenGénérerGenerate skills
TypeTypTypeТип
RechargeAufladungRechargeRecharge
y
Display textDisplay textDisplay textDisplay text
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
HealHeilungSoinsHeal.
+
+
+
QueryQueryVarieQuery
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

ActionsAktionenActionsActions

TypeTypTypeТип
ReachBereichAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
y
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

ReactionsReaktionenRéactionsReactions

TypeTypTypeТип
ReachBereichAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
y
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

Legendary actionsLegendäre AktionenActions légendairesLegendary actions

TheTheUn(e)The can takecan takepeut prendrecan take
 legendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. Thelegendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. Theactions légendaires, en choix parmi les options suivantes. Une seule action légendaire peut être utilisée à la fois et uniquement à la fin du tour d'une autre créature. Un(e)legendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. The regains spent legendary actions at the start of its turn.regains spent legendary actions at the start of its turn.récupère les actions légendaires dépensées au début de son tour de jeu.regains spent legendary actions at the start of its turn.
TypeTypTypeТип
ReachBereichAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
y
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform

Lair ActionsLair ActionsActions de repaireLair Actions

TypeTypTypeТип
ReachBereichAllongeReach
RangeReichweitePortéeRange
RechargeAufladungRechargeRecharge
y
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
Filters PreparedVorbereitetPréparéPrepared RitualRitualRituelRitual CantripsZaubertricksCantripsCantrips123456789AllAllesToutAll ReactionReaktionRéactionReactionBonusBonusBonusБонусActionAktionActionActionAllAllesToutAll Spells can haveZauber kann habenSorts peuvent avoirSpells can have: ConcentrationKonzentrationConcentrationConcentration V S M
SpellZauberSortSpell
LevelStufeNiveauУровень
Casting TimeZauberzeitTemps d'incantationCasting Time
ConcKonz.ConcConc
SpellZauberSortSpell
LevelStufeNiveauУровень
Casting TimeZauberzeitTemps d'incantationCasting Time
ConcKonz.ConcConc
y
RitualRitualRituelRitual
PreparedVorbereitetPréparéPrepared
Casting TimeZauberzeitTemps d'incantationCasting Time:
RangeReichweitePortéeRange:
ComponentsKomponentenComposantesComponents:
( )
DurationDauerDuréeDuration:
ConcentrationKonzentrationConcentrationConcentration
TargetZielCibleTarget:
ContentInhaltContenuContent.
AttackAngriffAttaqueAttack.
ProfBefähigtMaîtProf
+
Crit rangeKrit-AbCoup CritCrit range
Saving throwRettungswurfJet de sauvSaving throw.
+
=
DCSGDDDC
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
DamageSchadenDégâtsDamage.
+
+
CritKritCritCrit
HealHeilungSoinsHeal.
+
+
+
QueryQueryVarieQuery
Higher levelHöhere StufeNiveau SupHigher level.
DiceWürfelDésDice
DieWürfelDie
2nd2.2ème2nd DiceWürfelDésDice
2nd2.2ème2nd DieWürfelDie
Flat healEinfache HeilungBonus soinFlat heal
ExtrasExtrasExtrasExtras.
EmoteEmoteEmoteEmote
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
SpellsZauberSortsМагия
Spell slotsZauberslotsEmplacem.Spell slots Spell pointsZauberpunktePointsSpell points
1st1.1er1st
/
2nd2.2ème2nd
/
3rd3.3ème3rd
/
4th4.4ème4th
/
5th5.5ème5th
/
6th6.6ème6th
/
7th7.7ème7th
/
8th8.8ème8th
/
9th9.9ème9th
/
Spell slotsZauberslotsEmplacement de sortSpell slots
1st1.1er1st
2
2nd2.2ème2nd
3
3rd3.3ème3rd
5
4th4.4ème4th
6
5th5.5ème5th
7
6th6.6ème6th
9
7th7.7ème7th
10
8th8.8ème8th
11
9th9.9ème9th
13
/
Spell pointsZauberpunktePoints de sortSpell points
SpellcastingZaubernLancement de sortSpellcasting
ATKATTATQATK
DMGDMGDMGDMG
Saving DCRettungs-SGDD de sauvSaving DC
HealHeilungSoinsHeal
Bonuses & PenaltiesBoni & MaliBonus & MalusBonuses & Penalties
?
This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.Ceci ajoutera automatiquement la caractéristique pour déterminer le DD de sauvegarde lors de l'importation d'un sort ou d'une attaque. Si "Ajoutez la carac de lancement de sort" est également activé sur l'objet importé, la caractéristique de dégâts ou de soins changera en conséquence.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.
Default abilityStandardfähigkeitCarac par défautDefault ability
ArmorRüstungArmureДоспехи
TypeTypTypeТип
ACRKCAКБ
BonusBonusBonusБонус
TotalGesamtTotalВсего
StrengthStärkeForceСила
StealthTarnungDiscrétionStealth
UsesUsesUsesUses
WeightGewichtPoidsВес
+
=
/
Armored ACGepanzerte-RKCA (armure)КБ (в доспехах)
Unarmored abilityUngepanzerte FähigkeitBonus de carac (CA sans armure)Unarmored ability
Unarmored ACUngepanzerte-RKCA (sans armure)КБ (без доспехов)
ArmorRüstungArmureДоспехи
AttacksAngriffeAttaquesНападки
AmmoMunitionMunAmmo
ArmorRüstungArmureДоспехи
EquipmentAusrüstungÉquipementEquipment
CoinageMünzenMonnaieчеканка монет
TotalGesamtTotalВсего
WeightGewichtPoidsВес
Carrying capacityTrage-KapazitätCapacité de chargeГрузоподъемность
Push/Drag/LiftZiehen/Schieben/HebenPousse/Tire/LèveМожно поднять\перенести
EncumberedBeladenEncombréПерегрузка
H. EncumberedSchw. BeladenL. EncombréСил.Перегрузка
Carrying capacityTrage-KapazitätCapacité de chargeГрузоподъемность
EquipmentAusrüstungÉquipementEquipment
ContentInhaltContenuContent
UsesUsesUsesUses
QtyMengeQtéКлво
WeightGewichtPoidsВес
TotalGesamtTotalВсего
/
×
=

AttackAngriffAttaqueAttack
UsesUsesUsesUses
WeightGewichtPoidsВес
/
AmmoMunitionMunAmmo
QtyMengeQtéКлво
WeightGewichtPoidsВес
EquipmentAusrüstungÉquipementEquipment
ClassKlasseClasseClass
LevelStufeNiveauУровень
Hit diceTrefferwürfelDés de vieКость Хитов
SpellcastingZaubernLancement de sortSpellcasting
Custom nameBenutzerdef. NameNom persoCustom name
Class levelsKlassenstufenNiveaux de classeClass levels
?
This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.Ceci ajoutera automatiquement la caractéristique pour déterminer le DD de sauvegarde lors de l'importation d'un sort ou d'une attaque. Si "Ajoutez la carac de lancement de sort" est également activé sur l'objet importé, la caractéristique de dégâts ou de soins changera en conséquence.This will set the ability for saving throw DCs when importing a Spell or Attack. If "Add Casting Modifier" is also set on the importing item it will apply to the damage ability or heal ability as well.
Default abilityStandardfähigkeitCarac par défautDefault ability
LevelStufeNiveauУровень
CalcCalcCalcCalc
BonusBonusBonusБонус
MaxMaxMaxMax
1st1.1er1st
+
=
2nd2.2ème2nd
+
=
3rd3.3ème3rd
+
=
4th4.4ème4th
+
=
5th5.5ème5th
+
=
6th6.6ème6th
+
=
7th7.7ème7th
+
=
8th8.8ème8th
+
=
9th9.9ème9th
+
=
Spell slotsZauberslotsEmplacem.Spell slots
GenderGeschlechtSexeПол
SizeGrößeCatégorie de tailleРазмер
AgeAlterAgeВозраст
HeightHöheTailleРост
WeightGewichtPoidsВес
EyesAugenYeuxГлаза
SkinHautfarbePeauКожа
HairHaarCheveuxВолосы
AppearanceAussehenApparenceВнешний Вид
BlindsightBlindsichtVision aveugleСлеповидение
DarkvisionDunkelsichtVision dans le noirТемновидение
TremorsenseErschütterungssinnPerception des vibrationsЧувство вибрации
TruesightWahrsichtVision véritableИстинное зрение
VisionSichtVisionVision
BurrowGrabenCreusementПолзание
ClimbKletternEscaladeClimb
FlyFliegenVolFly
SwimSchwimmenNageSwim
MovementBewegungMouvementMovement
Jack of all tradesJack of all tradesTouche-à-toutМастер на все руки Remarkable AthleteHerausragender AthletAthlète remarquableRemarkable Athlete Halfling LuckHalblings GlückChance (Half)Halfling Luck
SorcererHexenmeisterEnsorceleurЧародей
Careful SpellCareful SpellCareful SpellCareful Spell
Distant SpellDistant SpellDistant SpellDistant Spell
Empowered SpellEmpowered SpellEmpowered SpellEmpowered Spell
Extended SpellExtended SpellExtended SpellExtended Spell
Heightened SpellHeightened SpellHeightened SpellHeightened Spell
Quickened SpellQuickened SpellQuickened SpellQuickened Spell
Subtle SpellSubtle SpellSubtle SpellSubtle Spell
Twinned SpellTwinned SpellTwinned SpellTwinned Spell
FeaturesTalenteCapacités spécialesFeatures
Miscellaneous notesSonstige NotizenAutres notesMiscellaneous notes
Sheet outputBogen AusgabeLes jets de cette fiche doivent êtreSheet output
Death saving throws outputTodesrettungswürfeChuchoter jets contre la mortDeath saving throws output
Initiative outputInitiative AusgabeChuchoter l'initiativeInitiative output
Character Name on all roll templatesCharaktername bei allen WürfenNom du perso sur tous les jetsCharacter Name on all roll templates
Roll optionsRoll optionsOptions de jetRoll options:
InitiativeInitiativeInitiativeInitiative:
Break Initiative TiesBreak Initiative TiesAjoute Mod Dex à l'initBreak Initiative Ties
Initiative RollInitiative WurfJet d'initiativeInitiative Roll
Show Target's AC on AttacksZeige Ziel-RK bei AngriffenMontrer la CA de la cible sur les jets d'attaqueShow Target's AC on Attacks
Show Target's Name on Attacks and SavesZeige Ziel-Name bei AngriffenMontrer le nom de la cible sur les jets d'attaque et de sauvegardeShow Target's Name on Attacks and Saves
OutputAusgabeOptions d'affichageРезультат
?
Auto add a bonus/penalty to rolls made using the sheet macros.
Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter "d4cs0cf0" in both attack roll fields, and the saving throw one
Auto add a bonus/penalty to rolls made using the sheet macros.
Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter "d4cs0cf0" in both attack roll fields, and the saving throw one
Ajoute automatiquement un bonus/malus aux jets effectués à l'aide des macros de la fiche de Personnage.
Utilisation: Vous trouvez un objet magique qui vous donne +1 à vos dommages, entrez 1 dans la case Dmg des Armes. Si vous êtes sous les effet du sort Bénediction, entrez "d4cs0cf0" dans les cases de jets d'attaque et de jets de sauvegarde.
Auto add a bonus/penalty to rolls made using the sheet macros.
Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter "d4cs0cf0" in both attack roll fields, and the saving throw one
AttacksAngriffeAttaquesНападки
MeleeNahkampfMêléeMelee
RangedFernkampfTirRanged
AttackAngriffAttaqueAttack
DamageSchadenDégâtsDamage
AttackAngriffAttaqueAttack
DamageSchadenDégâtsDamage
AttackAngriffAttaqueAttack
DamageSchadenDégâtsDamage

SpellcastingZaubernLancement de sortSpellcasting
ATKATTATQATK
DMGDMGDMGDMG
Saving DCRettungs-SGDD de sauvSaving DC
HealHeilungSoinsHeal

Ability scoresAbility scoresAbility scoresAbility scores
Saving throwsRettungswürfeJets de sauvegardeSaving throws
Ability checksFähigkeits-CheckJet de CaracAbility checks
Bonuses & PenaltiesBoni & MaliBonus & MalusBonuses & Penalties
Automatically use ammoAutomatically use ammoAutomatically use ammoAutomatically use ammo
Medium armor max dexMittlere Rüstung Max Gesch.Bonus dex max (armure intermédaire)Medium armor max dex
MiscellaneousMiscellaneousMiscellaneousMiscellaneous
LevelStufeNiveauУровень
CalcCalcCalcCalc
BonusBonusBonusБонус
MaxMaxMaxMax
1st1.1er1st
+
=
2nd2.2ème2nd
+
=
3rd3.3ème3rd
+
=
4th4.4ème4th
+
=
5th5.5ème5th
+
=
6th6.6ème6th
+
=
7th7.7ème7th
+
=
8th8.8ème8th
+
=
9th9.9ème9th
+
=
Spell slotsZauberslotsEmplacem.Spell slots
Copper per Gold (100)Kupfer pro Gold (100)Cuivre par Or (100)Copper per Gold (100):
Silver per Gold (10)Silber pro Gold (10)Argent par Or (10)Silver per Gold (10):
Electrum per Gold (2)Elektrum pro Gold (2)Electrum par Or (2)Electrum per Gold (2):
Gold per Platinum (10)Gold pro Platinum (10)Or par Platine (10)Gold per Platinum (10):
Custom gold valuesBenutzerdef. Gold-WerteValeur de l'or personnaliséeCustom gold values
y
FreetextFreitextTexte supplémentaireFreetext
FreeformFreiformEntrée supplémentaireFreeform
Ability checksFähigkeits-CheckJet de CaracAbility checks
Saving throwsRettungswürfeJets de sauvegardeSaving throws
MiscSonstigesAutreMisc
SkillsFertigkeitenCompétencesНавыки
StrengthStärkeForceСила
DexterityGeschickDextéritéЛовкость
ConstitutionKonstitutionConstitutionТелосложение
IntelligenceIntelligenzIntelligenceИнтеллект
WisdomWeisheitSagesseМудрость
CharismaCharismaCharismeХаризма
InitiativeInitiativeInitiativeInitiative
StrengthStärkeForceСила
DexterityGeschickDextéritéЛовкость
ConstitutionKonstitutionConstitutionТелосложение
IntelligenceIntelligenzIntelligenceИнтеллект
WisdomWeisheitSagesseМудрость
CharismaCharismaCharismeХаризма
Death savesTodesrettungSauv contre la mortDeath saves
Hit diceTrefferwürfelDés de vieКость Хитов
AttackAngriffAttaqueAttack
SpellZauberSortSpell
SkillFertigkeitCompétenceSkill
AttachersAttachersAttachesAttachers
Please see the wiki. You'll need to use a browser extension to change the css to show certain partsPlease see the wiki. You'll need to use a browser extension to change the css to show certain partsMerci de vous référer au wiki. Vous aurez besoin d'une extension de navigateur pour changer le css afin de montrer certaines parties.Please see the wiki. You'll need to use a browser extension to change the css to show certain parts
Hide AttackHide AttackHide AttackHide Attack
Hide DamageHide DamageHide DamageHide Damage
Hide Saving throw DCVerstecke Rettungswurf SGCacher DD de sauvHide Saving throw DC
Hide Spell contentVerstecke ZauberinfoHide Spell contentHide Spell content
Hide Action freetextVerstecke Action FreitexteHide Action freetextHide Action freetext
Hide Saving throw failureVerstecke Rettungswurf FehlschlagCacher échec sauvHide Saving throw failure
Hide Saving throw successVerstecke Rettungswurf ErfolgCacher succès sauvHide Saving throw success
Hide RechargeVerstecke WiederaufladungCacher RechargeHide Recharge
Hide NPC infoVerstecke NPC InfoCacher Infos PNJHide NPC info
MacrosMakrosMacrosMacros

CancelCancelCancelCancel
ImportImportImportImport
+
@@ -13,18 +14,24 @@
{{#reach}}{{reach}} reach{{/reach}} {{#range}}{{#reach}} • {{/reach}}{{range}} range{{/range}} - {{#ammo}}{{#range}} • {{/range}}{{ammo}} ammo{{/ammo}} + {{#ammo}}{{#range}} • {{/range}}{{ammo}} {{#ammo_name}}{{ammo_name}}{{/ammo_name}}{{^ammo_name}}ammo{{/ammo_name}}{{/ammo}}
- {{#target}} -
{{target}}
- {{/target}} {{/action}} + {{#uses}} +
{{uses}} / {{uses_max}}
+ {{/uses}} {{#subheader}}
{{subheader}}
{{/subheader}} {{#targetName}}
vs {{targetName}}
{{/targetName}} + {{#advantage}} +
advantaged
+ {{/advantage}} + {{#disadvantage}} +
disadvantaged
+ {{/disadvantage}}
{{#emote}}

{{character_name}} {{emote}}

@@ -33,14 +40,12 @@ {{#spell}} {{#casting_time}}
- Casting Time: - {{casting_time}} + Casting Time: {{casting_time}}
{{/casting_time}} {{#range}}
- Range: - {{range}} + Range: {{range}}
{{/range}} {{#components}} @@ -59,8 +64,7 @@ {{/duration}} {{#target}}
- Target: - {{target}} + Target: {{target}}
{{/target}} {{/spell}} @@ -70,29 +74,17 @@ {{#text_top}}
{{text_top}}
{{/text_top}} - {{#roll_toggle}} -
-
- {{#rollLess() roll1 roll2}}{{#advantage}}
{{/advantage}}{{/rollLess() roll1 roll2}} - {{#rollGreater() roll1 roll2}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll1 roll2}} - {{roll1}} - {{#rollLess() roll1 roll2}}{{#advantage}}
{{/advantage}}{{/rollLess() roll1 roll2}} - {{#rollGreater() roll1 roll2}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll1 roll2}} -
- {{^only_roll_1}} -
- {{#rollLess() roll2 roll1}}{{#advantage}}
{{/advantage}}{{/rollLess() roll2 roll1}} - {{#rollGreater() roll2 roll1}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll2 roll1}} - {{roll2}} - {{#rollLess() roll2 roll1}}{{#advantage}}
{{/advantage}}{{/rollLess() roll2 roll1}} - {{#rollGreater() roll2 roll1}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll2 roll1}} -
- {{/only_roll_1}} + {{#roll1}} +
+
{{roll1}}
+ {{#roll2}} +
{{roll2}}
+ {{/roll2}} {{#vs_ac}}
vs AC{{#targetAC}} {{targetAC}}{{/targetAC}}
{{/vs_ac}}
- {{/roll_toggle}} + {{/roll1}} {{#saving_throw_dc}}
{{#saving_throw_condition}} @@ -100,8 +92,8 @@ {{/saving_throw_condition}} {{#saving_throw_dc}}
- DC {{saving_throw_dc}} - [{{saving_throw_vs_ability}}](~target|{{saving_throw_vs_ability}}_saving_throw) + DC {{saving_throw_dc}} + [{{saving_throw_vs_ability}}](~target|{{saving_throw_vs_ability}}_saving_throw)
saving throw
{{/saving_throw_dc}} @@ -120,43 +112,25 @@
{{/saving_throw_dc}} {{#damage}} -
+
{{damage}} - {{#roll_toggle}} - {{#rollWasCrit() roll1}} - {{#only_roll_1}}+ {{crit_damage}}{{/only_roll_1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - + {{crit_damage}} - {{/rollWasCrit() roll2}} - {{#^rollWasCrit() roll2}} - {{#^rollLess() roll1 roll2}} - {{#advantage}}+ {{crit_damage}}{{/advantage}} - {{/^rollLess() roll1 roll2}} - {{/^rollWasCrit() roll2}} - {{/only_roll_1}} - {{/rollWasCrit() roll1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - {{#^rollWasCrit() roll1}} - {{#^rollLess() roll2 roll1}} - {{#advantage}}+ {{crit_damage}}{{/advantage}} - {{/^rollLess() roll2 roll1}} - {{/^rollWasCrit() roll1}} - {{/rollWasCrit() roll2}} - {{/only_roll_1}} - {{/roll_toggle}} + {{#rollWasCrit() roll1}} + + {{crit_damage}} + {{/rollWasCrit() roll1}} + {{#^rollWasCrit() roll1}} + {{#rollWasCrit() roll2}} + + {{crit_damage}} + {{/rollWasCrit() roll2}} + {{/^rollWasCrit() roll1}}
{{damage_type}}{{^damage_type}}damage{{/damage_type}}
{{/damage}} {{#second_damage}} {{#damage}} -
- + -
+
+
{{/damage}} {{^damage}}
@@ -164,30 +138,14 @@
{{second_damage}} - {{#roll_toggle}} - {{#rollWasCrit() roll1}} - {{#only_roll_1}}+ {{second_crit_damage}}{{/only_roll_1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - + {{second_crit_damage}} - {{/rollWasCrit() roll2}} - {{#^rollWasCrit() roll2}} - {{#^rollLess() roll1 roll2}} - {{#advantage}}+ {{second_crit_damage}}{{/advantage}} - {{/^rollLess() roll1 roll2}} - {{/^rollWasCrit() roll2}} - {{/only_roll_1}} - {{/rollWasCrit() roll1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - {{#^rollWasCrit() roll1}} - {{#^rollLess() roll2 roll1}} - {{#advantage}}+ {{second_crit_damage}}{{/advantage}} - {{/^rollLess() roll2 roll1}} - {{/^rollWasCrit() roll1}} - {{/rollWasCrit() roll2}} - {{/only_roll_1}} - {{/roll_toggle}} + {{#rollWasCrit() roll1}} + + {{second_crit_damage}} + {{/rollWasCrit() roll1}} + {{#^rollWasCrit() roll1}} + {{#rollWasCrit() roll2}} + + {{second_crit_damage}} + {{/rollWasCrit() roll2}} + {{/^rollWasCrit() roll1}}
{{second_damage_type}}{{^second_damage_type}}damage{{/second_damage_type}}
@@ -199,9 +157,7 @@
{{/damage}} {{#heal}} -
- Heal for {{heal}} HP -
+
Heal for {{heal}} HP
{{/heal}} {{#death_saving_throw_successes}}
@@ -213,22 +169,23 @@ Failures {{death_saving_throw_failures}} / 3
{{/death_saving_throw_failures}} + {{#text_center}} +
{{text_center}}
+ {{/text_center}} {{#text}} -
{{text}}
+
{{text}}
{{/text}} {{#text_big}} -
{{text_big}}
+
{{text_big}}
{{/text_big}} - - {{#allprops() freetext text text_big text_top character_name saving_throw title ignore show_character_name subheader roll_toggle roll1 roll2 only_roll_1 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} -
+ {{#allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} +
{{key}}. {{value}}
- {{/allprops() freetext text text_big text_top character_name saving_throw title ignore show_character_name subheader roll_toggle roll1 roll2 only_roll_1 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} - + {{/allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} {{#freetext}} -
{{freetext}}
+
{{freetext}}
{{/freetext}} {{#recharge}}
diff --git a/D&D_5e_Reshaped/ReadMe.md b/D&D_5e_Reshaped/ReadMe.md index ba9fce7bfe..2434f0c7a2 100644 --- a/D&D_5e_Reshaped/ReadMe.md +++ b/D&D_5e_Reshaped/ReadMe.md @@ -1,613 +1,10 @@ # D&D 5e Character Sheet -This is a character sheet for use on Roll20.net with the latest (5th) edition of Dungeons & Dragons. The sheet is designed to be usable by all Roll20 users regardless of subscription level. It is not fully compatible with the default 5e sheet. - -### TODO - -Short Term: -* Spell Crit damage should use higher level -* Spell Crit damage should not roll 3D dice for secondary and other stuff that is toggled off. -* Revamp Traits. Keep fluff traits on the first page and for action like traits write "see Actions". Also include fluff traits on "Actions". -* Refactor Actions to use damage die and bonus like weapons do - -Long term: -* Explore icons for damage types/resistances/etc https://app.roll20.net/forum/post/2110339/icons-for-damage-types-5e -* Add saves and other stuff to class actions. -* Make spells automatically reduce the amount left -* Add "Conditions" that make sheet-wide changes when a condition is toggled. -* Use the new roll templates greater than to enhance ac targeting. https://app.roll20.net/forum/post/1977290/update-5-slash-20-improved-player-directory-and-new-roll-template-features -* Vitality Points -* Look into proficiency dice -* Add support for crit fails/successes to weapons/spells/actions - - -### Changelog - -**November 19th 2015** - -* Bind to without chat avatars - -**November 16th 2015** - -* Add Halfling to NPC Actions - -**November 15th 2015** - -* Russian Indentation fixes - -**October 30th 2015** - -* Added Russian - -**October 24th 2015** - -* Added a setting for changing the passive skill base (instead of 10) -* Removed skill macro as it's in the check macro -* Fixed Lucian's spell thing after I changed spell higher level stuff to a select input -* Move Jack of All Trades to the class page - -**October 16th 2015** - -* Spell higher levels are now a select. No data should be lost unless you used something other than d2,d4,d6,d8,d10,d12,d20 - -**October 2nd 2015** - -* More French Translations - -**October 1st 2015** - -* Setup some variables for Lucian - -**September 28th 2015** - -* Prevent "freetextname" from showing on roll templates - -**September 20th 2015** - -* Removed spellcastingtime from rolltemplate stuff - -**September 19th 2015** - -* Updated Save Macro -* Updated Check Macro (Depreciate Skill macro) - -**September 17th 2015** - -* French translations - -**September 13th 2015** - -* Removed old spell syntax - -**September 5th 2015** - -* Reduce number of attributes for spells. - -**August 30th 2015** - -* Fixed roll template header colors. - -**August 29th 2015** - -* Adjusted inline roll spacing for roll templates. - -**August 26th 2015** - -* Fixed class action page tabs - -**August 22nd 2015** - -* Added global bonus for spell healing - -**August 19th 2015** - -* Added casting time toggle. You can now toggle spells based on their casting time. Spells default to "1 action", but can be changed to "1 reaction", "1 bonus action", "1 minute" or "longer" which allows for any input. The roll template will always show the new value. The old value will be shown for a time (with a red error to tell you to fix it), but it will be removed soon. - -**August 18th 2015** - -* Altered query macros to remove "selected" -* Fixed multiattack macro to not display all the data -* Add Range to melee weapons for thrown weapons - -**August 17th 2015** - -* Moved speed up to the header. -* Styled jack of all trades to be a button -* Fixed ammo in roll template for new weapons - -**August 16th 2015** - -* CSS Cleanup - -**August 15th 2015** - -* Massive refactoring to all the toggle/tab buttons. They are all setup the same way now and have consistent padding. I have verified all the pages and I believe everything is still working -* Massive refactoring of the HTML structure for sheet-row stuff. Lots of changes. I've checked the whole UI and it all looks good, but I may have missed some things -* Removed separate damage for the second crit. Both crits (normal and adv/dis) now show the same damage if both show. - -**August 14th 2015** - -* output higher level query level to the roll template - -**August 13th 2015** - -* hide GM info settings and styling - -**August 12th 2015** - -* Renamed spell macro options to force it to update for some users which it wasn't updating for. -* Added alt damage to weapons - -**August 11th 2015** - -* fixed global spell bonus damage - higher level stuff broke it. - -**August 10th 2015** - -* Spell filters -* Removed HD note - -**26th July - August 5th 2015** - -* Revamp of spells: - * Toggles are all redone and can be changed in the future - * Added Emote - * Added higher level for damage and heal - * Split damage to attack damage and save damage - * Aoe split from target - * Save condition - * Save failure - * Revamped roll template to match these new changes. For the most part spells now use action stuff -* Added Query macros for Saves, Checks, and Skills - -**25th July 2015** - -* Changed Custom Skills to the slider. -* Removed Macro from weapons and actions. - -**24th July 2015** - -* Changed spell slots/points toggle to the same slider used on PC/NPC. Still unsure about the colors - -**23rd July 2015** - -* Initiative bonus can now text instead of just a number -* Removed warning about settings changes -* Made a new toggle for PC/NPC. The animation is super smooth outside of roll20, but in roll20 it is super laggy. I'll try to massage it more later. - -**22nd July 2015** - -* Weapon & Action Macro no longer outputs a blank line. (It cannot be toggled off - though it never could be) - -**14th July 2015** - -* Spell points are now a different field. Was a bug. - -**13th July 2015** - -* Bonus crit damage is now added via the bonus crit toggle instead of the bonuses toggle. - -**12th July 2015** - -* Added back a blank variable because repeating sections are bad. - -**11th July 2015** - -Most of the changes are to allow for a spell importer that is in the works on my API script. Components is for the API and for cosmetic purposes. -* Spells now have V,S,M toggles. The old syntax will still work as well (it appears in the materials field, but it is still named the same for compatability) -* Added Spell Source so you can show where it's from (Example: "phb 241", "ee pc 20"). Also has a toggle. It appears in the header of the roll template. -* Moved "Gained from" under a toggle - -**3rd July 2015** - -* Updated target name to show the token's name, not the character name -* Small UI adjustments (Quick Resources, header padding, quick spell stuff) - -**2nd July 2015** - -* Fixed the HTML of spells so they no longer break any pages after it -* (Dev) cleaned the tabs to use more consistent css -* (Dev) small cleanup based on html vaidation (value on textareas removed, step on input type text removed) -* Added a toggle to show HD rows -* Slightly decreased the height of the speed wrap box (5px) -* Added a notation so spell slots are current/max. Also changed color of the tab. -* Added attacks and saves vs target's name with a setting and API support. Removed from TODO - -**1st July 2015** - -* Weapons and Actions will automatically have crit turned on by default. -* Fixed several bugs - quick melee has "button" printed. Melee attacks had an error where no bonuses were being added. -* Refactored spells' buttons to match the styling of weapons and actions. - -**30th June 2015** - -* Change of how the line break for macro works for weapons and actions. Tried to set it up -* Added custom gold values. See https://app.roll20.net/forum/post/2016392/#post-2126410 Removed from my TODO. -* Added Multiattack to the roll template. See See https://app.roll20.net/forum/post/2016392/#post-2128439 Removed from my TODO. -* Second damage bonus for weapons was not being calculated. Fixed that. -* Weapon bonuses do not apply unless bonuses is checked. Applied to to hit bonus, dmg bonus, secondary dmg bonus, bonus crit dmg. Removed from my TODO. - -**29th June 2015** - -* Added a setting to always hide initiative -* Refactored the settings page completely. See https://app.roll20.net/forum/post/2016392/#post-2128397 Removed from my TODO. - -**26th June 2015** - -* Macro was added to Actions by Lucian. - -**25th June 2015** - -* Fixed delete buttons so they show on spellbook and quick class resources. -* Added Class Actions to the Core page for PC sheets - -**24th June 2015** - -* Added Class Resources to the Core page for PC sheets -* Added "Loot" to the Core page for NPC sheets - -**23rd June 2015** - -* Added output all to the roll template - -**22nd June 2015** - -* Added a bonus field for AC that works on PC pages. - -**21st June 2015** - -* Death saves & failures now fill from left to right (with a "X" to reset) - -**19th-20th June 2015** - -* (Dev) Lots more cleanup -* Monk DC added to spells -* Added targetAC to Spells & Cantrips -* Added a toggle for "Quick Weapons" on the weapons page -* Halfling Luck (works on everything but spell attacks) -* Improved heart on tablets (still not great, but doesn't cut off at least) - -**18th June 2015** - -* (Dev) Refactored the grid system and cleaned up a lot of CSS - using scss now -* (Dev) HTML is compiled to be smaller now -* Removed the old NPC sheet -* Moved bonuses for Abilities/Saves/Checks/Skills to the Settings tab. - -**9th June 2015** - -* Resize quick fields to allow more room for hit and +dmg -* Shrink saves and checks to match skills' height -* Reorder pages to put Weapons, Actions, and Spellbook much earlier - -**8th June 2015** - -* Hide fields that shouldn't be displayed from weapons output now that class actions are added to the new weapons -* Remove name from the emote -* Shrunk some elements on the core page - mainly skills - -**7th June 2015** - -* Passive Perception in the header now corectly adds the bonus -* Class Actions added to new weapons - -**29th May 2015** - -* Class actions work on new weapons -* Character name is on its own line on the roll template now - -**24th May 2015** - -* Weapons can now run chat commands on each roll. Courtesy of Jeff S.(jjsheets on github). - -**23rd May 2015** - -* Spell points work on the core page as well now - -**22nd May 2015** - -* Ammo is now toggleable to show in the output. -* Added an optional button to ranged weapons that will auto increment ammo if you also have my script installed. https://app.roll20.net/forum/post/1734923/new-d-and-d-5e-shaped-character-sheet - -**21st May 2015** - -* Roll template's width is shrunk a bit to work with hidden chat avatars. Still larger than normal, but only by 6 pixels. -* (dev) used gulp to compile many pages to reduce duplicate code while making changes (doesn't change length for the final ouput) - -**17-20th May 2015** - -* Quick Actions example done - need to think about this before duplicating it -* Thrown weapons removed -* Some NPC elements now show on the PC sheet (Blindsight, other speeds) -* Expanded weapons out to 7 each -* Resized all of the core page to allow for quick weapons -* Weapons tab now has quick weapons as well - -**16th May 2015** - -* Added spell components to the spell header -* Made inputs smaller by default all over the sheet -* Added toggle for Old weapons -* Action name inputs are now big like spells and weapons - -**14th May 2015** - -* Fixed initiative -* Removed name from the other roll templates as well as cleaned more up -* Added an option setting to show the character name on all rolls. It is off by default. - -**13th May 2015** - -* Cleaned up CSS and expanded the roll template 20 px to the left -* Moved Ritual and Concentration icon to the top right of the roll template header -* Put Range, Reach, target, and spell details in the roll template header. - -**12th May 2015** - -* Spell Effects on a new line instead of a column -* Fix bug around printing out hd max values for players -* Shrunk the "Higher Level" textarea for spells and increased the description textarea. -* Allowed for the "Effects" textarea to be resized -* Revamped the spell roll template -* Added icons for Ritual and Concentration on the spell roll template - -**9th May 2015** - -* Added more German translations from Rouby. Core, Background, and Spells -* Split all the pages into their own html file which is all combined via GULP - this change only matters for contributors. It helps manage the pages to split the 20,000 lines to different files. - -**8th May 2015** - -* Added skill passive bonus -* Cleaned up skills on core sheet -* Shrunk Prof bonus and Exhaustion level inputs. - -**4th May 2015** - -* Added Spell Points - -**2nd May 2015** - -* Weapons revamp v2. - -**1st May 2015** - -* Attacks: First revision of new weapons has been completed. -* Show Bonuses / Penalties on the weapon and spell page as well. - - -**30th April 2015** - -* Prevented weapons from erroring if the crit damage field did not have a value. -* Made targetAC work on Actions and Spells -* Spells can be removed again -* Spells no longer have a (dis)advantage toggle. All attacks roll the second die. -* Cleaned up how Actions send data to the roll templates -* Cleaned up spellbook to show "-" when a class doesn't have cantrips, spells known, or spells prepared -* Cleaned up roll templates - -**29th April 2015** - -* Actions: Effects now print out - -**28th April 2015** - -* Actions now have "Details" tab split out to "Reach", "Range", and "Target". Old creature who still had "Details" will still work even if the fields do not show. -* Added Multilingual support for other users to translate the sheet. -* Adjusted tooltips so that they can work on plain text. Put them in for Strength and Athletics. I expect many more to be added soon. -* Added tooltips for basic ability and skill checks. - -**24th April 2015** - -* Added spell slots to the Core page -* Cleaned up a few pages by adding tooltips for the text that was there. -* Changed colors on a lot of buttons and tabs - -**21st-23rd April 2015** - -* Bars now clear before importing. They currently do not work with formula attributes (passive_perception). -* Removed multiattack from each action -* Added a button on the sheet for multiattack. Text and script are there and the token action just references that button. The import script will auto populate this. -* BREAKING CHANGE: All actions have been renamed to follow the repeating syntax. I was really hoping to make repeating work, but it needs to be supported by roll20. This will make it easier to transition to repeating syntax if/when they do support it. - -**20th April 2015** - -* NPC Actions fixed details tabs so they show at the right times. -* Restyled spellbook page a bit to match the Shaped style. -* Filtered spells based on "Prepared", "Ritual", or "Concentration" - -**19th April 2015** - -* Added Save Damage and Save Damage Type -* Reorganized the tabs for npc Attacks to have Alt Dmg, Secondary Dmg, and Crit to be "under" Dmg for instance - -**13th April 2015** - -* Fixed typo: "legendary_action_notess" to "legendary_action_notes" -* Increased size on damage field for NPC Actions -* Added an additional attack type to NPC Actions: "Line". I will add more in the future - -**12th April 2015** - -* Background attribute updated so that the textarea matches the default sheet and the background in the header is a new attribute. -* Set the inventory to default to multiply - -**10th April 2015** - -* All sheets use "AC" again. It is calculated correctly for everyone. "Target" under settings now uses this and will work to target NPC and PC sheets. - -**9th April 2015** - -* Jack of All Trades now applies to Basic ability checks (Strength, Dex, Con, Int, Wis, Cha) - -**8th April 2015** - -* Added a setting to allow initiative to work on mobile. -* Cut the heart's top off on mobile as there is no other fix currently. - -**7th April 2015** - -* Previously hidden items are now shown by default: ability check bonuses, skill bonuses, initiative bonus. -* Added Save Bonus -* Renamed "Attacks" to "Actions" for NPC Attacks (now NPC Actions) -* Added "Alt Dmg" to all NPC Actions to allow for cases like swarms or creatures holding versatile weapons. - -**6th April 2015** - -* Wrote import script (Still a work in Progress) -* Fixed NPC attacks to work even if the values are blank (See https://app.roll20.net/forum/post/1806911/empty-input-type-number-breaks-calculation) - -**5th April 2015** - -* Added Custom Classes -* Fixed custom classes to add their level to the hit dice pool for the appropriately selected hit dice -* Added Real Lair Actions (3) -* Added Real Legendary Actions (3) -* Added more NPC Attacks (total 11) -* Cleaned up HD -* Added Custom Skills toggle -* Added Tooltips - -**4th April 2015** - -* Quick attacks' range bug fixed -* NPC Attacks Duplicated out to 2 until I add action types -* "Hidden Info" not possible as you can't send 2 rolls with 1 roll. see https://app.roll20.net/forum/post/1793729/show-certain-parts-of-a-roll-template-to-gm -* Added Passive Perception to the header info -* Split out senses to multiple fields in the header info -* Added Background to the header info for PCs -* Redid alignment the 2nd row of header info items with the addition of the new items. -* Set Proficiency for monsters (See MM 8) -* Removed save bonus to NPCs as they should simply use Proficiency. They should use Expertise if needed for skills -* Renamed some titles of sections such as - * "Appearance" - * "Background and Race Info" - * "Class Levels and Resources" - * "Class Features and Feats" - * "Miscellaneous Notes" -* Added "Recharge" to the NPC attacks -* Added Lair Actions, Legendary Actions, and Reactions (need to turn Lair Actions into actual attacks) - -**3rd April 2015** - -* Added a testable version of NPC Attacks - -**2nd April 2015** - -* Fix initiative/ac row breaking line -* Prevent jumping on new death saves and other small adjustments -* Added save bonus to NPCs -* Moved AC note down for NPC sheets -* Fixed which pages are shown on "Show All" -* New Parenthesis for skills -* Style resistances better -* Style other textareas to match -* Used -> Current to have consistency across the board. 4/5 slots instead of 4/5 slots used. It is more consistent with HP and makes sense. - -**1st April 2015** - -* AC is now for PCs and npc_ac is for NPCs. AC still calculates the highest between armored and unarmored AC. See https://app.roll20.net/forum/post/1759669/target-and-ac-on-5e-character-sheet#post-1784957 -* Cleaned up the sheet so it works better on firefox and iPad. The heart still needs to be fixed on iPad. see https://app.roll20.net/forum/post/1788374/targeting-tablet-devices-with-css -* Added "Skin" to determine skin color. -* Reduced the size of the shield -* Redid the buttons for Inspiration and Death saves -* Added Exhaustion -* Added number spinners to hp, hd, exhaustion - -**31st March 2015** - -* NPC sheet now hides all the PC tabs except spellbook and the new "NPC Attacks". The old NPC sheet can be shown via a toggle. -* Started work on "NPC Attacks" - -**30th March 2015** - -* Fixed text scrunching on the spellbook - -**29th March 2015** - -* Merged Actoba's work - -**29th March 2015** - -* Merged Actoba's work - -**27th March 2015** - -* Attacks can now use target to display the target's AC. It's under the settings. - -**24th March 2015** - -* Quick Attacks are added for melee and ranged weapons -* Merged Actoba's subheaderright2 issue: https://github.com/Actoba/roll20-character-sheets/commit/36d300e4432ac61f83625675fc765d9e01f7feb6 - -**23rd March 2015** - -* Resized shield and heart to make them smaller. See https://app.roll20.net/forum/post/1734923/new-d-and-d-5e-shaped-character-sheet#post-1748932 -* Resized all of core to make it even more compact. -* Core now have 5 columns - 2/5, 1/5, 1/5, and 1/5. - - -**22nd March 2015** - -* Merged changes from Actoba. See https://app.roll20.net/forum/post/1744887/dnd-5e-sheet-uoh-user-feedback-mini-update. -* Added back class actions as per above. -* Fixed alignment on ranged attacks' ranges. -* AC takes the highest of either the normal AC_Calc or NPC_AC -* Added Medicine back. -* Added a setting to determine who the sheet rolls to - public or DM. Applies to both PCs and NPCs. - - -**21st March 2015** - -* Ranged Weapons now have Ranges -* NPC sheet is being depreciated. All of the items are put into the main sheet besides the attacks as of 22nd March version. For instance some items in the top header info switch, the AC field is editable, and the different forms of movement are shown for NPCs. I plan to disable Background, Class, Weapons, Armor, and Inventory for the NPC sheet. I'll make a NPC version of the Weapons tab for "standard attacks" which is a mix of standardized attacks and open ended attacks. -* Inventory expanded to 3 pages of 15 for a total of 45 (old was 40) -* Gray background added -* Updated the header info area to contain important info. Works for PCs and NPCs -* Resistances and Immunities are now viewable by PCs - -**Initial release - 19th March 2015** -First release of the redesigned sheet. - -**Notable changes:** - -* Core page has been revamped based on the design of the official paper sheet (http://1.bp.blogspot.com/-SIz9DByDeZw/U6M51aKP-OI/AAAAAAAAAzM/OZ72wWzJMTA/s1600/sheet1.jpg). The core sheet is meant to present the information in a more concise, readable way so that users can find information quickly. I'm not fully satisfied with everything (The initiative box is funky, skills are too tall, etc), but it leaves plenty of room to expand if anyone has suggestions for things to put in the holes. -* Header part of the sheet now includes information such as Character Name, Race, Class, Background, Level, Alignment, Vision, XP -* Heart contains HP info. -* Shield Contains AC info. -* Skills - * Skills have moved to the core sheet. The skill page has been removed. - * Skill proficiency automatically adds "Jack of All Trades" if you are unproficient and it is checked. There are 3 states now (Unproficient, Proficient, and Expertise) which are displayed with a more visible token (—, +, or ++). The full description can be seen when clicking the select box. - * Skill modifiers can be seen on hover. -* Initiative's modifier is hidden - it can be seen on hover. (Not satisfied with the positioning of this. -* Armor Class (AC) now calculates based on the greater of Unarmored AC and Armored AC. -* Removed old class features as it will be removed in the main version soon anyways. -* Realigned classes on the class page -* Optional Settings tab has been added with the following options: - * Death saves can be whispered to the DM - * Initiative can have a tiebreaker. This adds a modifier based on your initiative bonus. For instance rolling a 14 on a d20 with a initiative bonus of 3 would be 17.03. - -### Future Changes - -* Custom settings: I'm willing to add custom options/variants as long as they are technically feasible and can be hidden away without effecting users who do not want it. - -### Requests and issues - -Please include the "Shaped" term when posting about this sheet. I will do my best to respond to posts here. You can also open issues on github or contact me by PM, Twitter (@mlenser), gchat, or skype. If you have ideas/suggestions or want to work together I'm quite open. - -### ​Differences between this version and the current version - -PCs remain mostly the same. Things that have changed: - -* Armor -* Vision -* Spell Prepared, Ritual, Concentration -* Class specific -* * Expertise -* * Jack of All Trades (retoggle it in 1 place) -* * NPCs lose most everything, but the old NPC sheet is still included and you can use conversion/import scripts. +This is the redesigned Shaped character sheet for use on Roll20.net with the latest (5th) edition of Dungeons & Dragons. The sheet is designed to be usable by all Roll20 users regardless of subscription level. +![alt text](http://i.imgur.com/li1ETpJ.jpg "PC sheet") +![alt text](http://i.imgur.com/T2hbvnA.jpg "NPC sheet") --- -Mark Lenser ([@mlenser](https://app.roll20.net/users/277007/mark) on roll20) \ No newline at end of file +Mark Lenser ([Kryx](https://app.roll20.net/users/277007/kryx) on roll20) \ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/D&D_5e.html b/D&D_5e_Reshaped/precompiled/D&D_5e.html index b4359c022e..f6c1f59225 100644 --- a/D&D_5e_Reshaped/precompiled/D&D_5e.html +++ b/D&D_5e_Reshaped/precompiled/D&D_5e.html @@ -1,12 +1,12 @@ -
+
//= include components/header/firstLine.html //= include components/header/header.html //= include components/header/nav.html -
- //= include components/header/toggleVariables.html +
+ //= include components/core/core.html //= include components/npc/npc.html //= include components/spells/spells.html @@ -14,8 +14,10 @@ //= include components/character/character.html //= include components/settings/settings.html
- + + //= include components/importOverlay.html
- \ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/D&D_5e.scss b/D&D_5e_Reshaped/precompiled/D&D_5e.scss index bb23d8e280..383b5f831d 100644 --- a/D&D_5e_Reshaped/precompiled/D&D_5e.scss +++ b/D&D_5e_Reshaped/precompiled/D&D_5e.scss @@ -9,6 +9,7 @@ $pinkish-red: #8c6075; $deep-green: #51624b; $light-green: #879a6a; $deep-blue: #416696; +$bright-blue: #3f88e6; $light-gray: #cecece; $gray: #a19a91; $grayer-gray: #8c8c8c; @@ -18,6 +19,8 @@ $light-yellow: #f2f5d3; $teal: #E6F5F9; $scrollbar-size: .5em; +$classes: 'barbarian', 'bard', 'cleric', 'druid', 'fighter', 'monk', 'paladin', 'ranger', 'rogue', 'sorcerer', 'warlock', 'wizard'; + @mixin no-highlight { -webkit-touch-callout: none; -webkit-user-select: none; @@ -26,6 +29,10 @@ $scrollbar-size: .5em; user-select: none; } +@mixin text-shadow { + text-shadow: -1px 0 $black, 0 1px $black, 1px 0 $black, 0 -1px $black; +} + @mixin tab-toggle($tab, $width, $padding) { @if $padding == 'padding' { $width: $width + 4; @@ -172,18 +179,19 @@ button { padding: 0; &:hover { - color: #3f88e6 !important; + color: $bright-blue !important; input { - color: #3f88e6 !important; + color: $bright-blue !important; } } } &.sheet-visible-button { - background-color: #3f88e6; + background-color: $bright-blue; border-radius: $border-radius; box-shadow: 0 2px 5px 0 rgba(0,0,0,.26); color: rgba(255,255,255, .87); + font-size: 11px; padding: 3px; &:hover { color: rgba(255,255,255, .87); @@ -194,7 +202,6 @@ button { } } - &:hover { background-position: initial; } @@ -217,7 +224,7 @@ button { font-size: 13px; padding: 0 3px 2px; position: relative; - z-index: 99999; + z-index: 999; } &.repcontrol_add, &.repcontrol_edit, @@ -234,10 +241,20 @@ button { font-size: 16px; font-weight: bold; position: relative; - z-index: 99999; + z-index: 999; } } +input.sheet-toggle-pseudo-button { + height: 17px; +} +span.sheet-toggle-pseudo-button { + background-color: $bright-blue !important; + box-shadow: 0 2px 5px 0 rgba(0,0,0,.26); + font-size: 11px !important; + height: 17px; + padding: 3px !important; +} .sheet-wrapper-button { width: 100%; @@ -359,6 +376,15 @@ $pad-mar: ( } } } +.sheet-pad-t-twelve { + padding-top: 12px; +} +.sheet-pad-t-eight { + padding-top: 8px; +} +.sheet-pad-t-hundred { + padding-top: 100px; +} .sheet-hidden { display: none !important; @@ -372,6 +398,19 @@ $pad-mar: ( min-width: 834px; } +.sheet-import-data-present { + &:not(:checked) ~ .sheet-overlay { + display: none; + } +} + +.sheet-overlay { + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0.75); + z-index: 9999; +} + .charsheet { background: rgb(237, 237, 237) url('http://i.imgur.com/RggDtsN.png'); margin-top: -10px; @@ -411,7 +450,7 @@ $pad-mar: ( .sheet-tooltip-toggle-text, { background-color: black; border-radius: 50%; - color: white; + color: rgba(255,255,255, .87); font-size: 77%; font-weight: bold; height: 10px; @@ -422,7 +461,7 @@ $pad-mar: ( background-color: $black; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; - color: $white; + color: rgba(255,255,255, .87); margin-top: -15px; opacity: .9; padding: 4px; @@ -464,7 +503,7 @@ $pad-mar: ( .sheet-tooltip:hover [class*='sheet-tooltip-content'], .sheet-tooltip:focus [class*='sheet-tooltip-content'] { visibility: visible; - z-index: 999; + z-index: 450; } .sheet-dnd-image-wrapper { @@ -481,7 +520,7 @@ $pad-mar: ( border-bottom-left-radius: 5px !important; border-right-width: 0; border-top-left-radius: 5px !important; - font-size: 22px; + font-size: 20px; font-weight: bold; padding: 0 2px; } @@ -491,7 +530,7 @@ $pad-mar: ( } .sheet-ability-wrapper { - height: 68px; + height: 69px; margin-bottom: 12px; position: relative; @@ -507,6 +546,11 @@ $pad-mar: ( position: absolute; right: 0; width: 40px !important; + + input.sheet-toggle-edit-mode:checked ~ div & { + width: 60px !important; + } + input { font-size: 11px; background: transparent; @@ -524,8 +568,13 @@ $pad-mar: ( .sheet-ability-modifier { font-size: 24px; font-weight: bold; - padding-bottom: 5px !important; - padding-top: 6px !important; + padding-bottom: 8px !important; + padding-top: 8px !important; + + input.sheet-toggle-edit-mode:checked ~ div & { + padding-bottom: 0 !important; + padding-top: 0 !important; + } } .sheet-spell-slots-points { @@ -536,7 +585,11 @@ $pad-mar: ( } } -.sheet-resource, +.sheet-class-features { + font-size: 11px; +} + +.sheet-class-feature, .sheet-attacks, .sheet-spell { input[readonly] { @@ -588,10 +641,14 @@ $pad-mar: ( } } +.sheet-input-like { + padding: 1px; +} .sheet-skill-ability { color: $light-gray; font-size: 10px; } + .sheet-skills { select { padding: 0; @@ -601,10 +658,8 @@ $pad-mar: ( background: transparent; border-bottom: 0; color: #909090; - height: 11px; - position: relative; - width: 25px !important; - z-index: 2; + font-size: 9px; + height: 11px !important; } .sheet-skill-select-wrapper { select { @@ -613,28 +668,10 @@ $pad-mar: ( } } -select.sheet-skills-ability-selector { - font-size: 9px; -} - .sheet-skills-ability-selector-wrapper, .sheet-parenthesis-wrapper { - display: inline-block; - position: relative; - - &::before, - &::after { - color: #909090; - position: absolute; - top: 0; - } - &::before { - content: '('; - } - &::after { - content: ')'; - right: 1px; - } + color: #909090; + font-size: 9px; input { padding-left: 3px; padding-right: 3px; @@ -649,7 +686,7 @@ select.sheet-skills-ability-selector { padding-top: 7px; padding-right: 2px; position: relative; - z-index: 10; + z-index: 5; &::before { color: white; @@ -659,7 +696,7 @@ select.sheet-skills-ability-selector { left: -1px; line-height: 51px; position: absolute; - text-shadow: -1px 0 $black, 0 1px $black, 1px 0 $black, 0 -1px $black; + @include text-shadow(); top: 3px; z-index: -1; } @@ -689,7 +726,6 @@ select.sheet-skills-ability-selector { text-transform: uppercase !important } - .sheet-big-text { font-size: 16px; } @@ -731,7 +767,7 @@ select.sheet-skills-ability-selector { margin-right: auto; margin-top: 4px; position: relative; - z-index: 4; + z-index: 5; &::after { position: absolute; @@ -742,7 +778,7 @@ select.sheet-skills-ability-selector { font-family: 'Pictos'; font-size: 90px; color: white; - text-shadow: -1px 0 black, 0 1px black, 1px 0 black, 0 -1px black; + @include text-shadow(); } > .sheet-shaped-row { @@ -785,6 +821,11 @@ select.sheet-skills-ability-selector { white-space: nowrap; } +.sheet-small-checkbox { + -webkit-transform: scale(.8); + transform: scale(.8); +} + .sheet-checkbox-label-sm { font-size: 9px; @@ -920,7 +961,7 @@ select.sheet-skills-ability-selector { margin: 1px; opacity: 0; position: relative; - z-index: 9999; + z-index: 99; &, & + span { @@ -1162,10 +1203,6 @@ select.sheet-skills-ability-selector { font-style: italic; text-align: center; } - - .sheet-less-important { - color: #A2A2A2; - } } div[class='repcontainer editmode'] ~ div[class^='repcontrol'] button[class='btn repcontrol_add'] { @@ -1186,13 +1223,18 @@ input[class^='sheet-toggle-'] { cursor: pointer; opacity: 0; position: relative; - z-index: 9999; + z-index: 999; + + &:active + span[class^='sheet-toggle-'].sheet-button { + box-shadow: 0 4px 8px 0 rgba(0,0,0,.4); + } } + span[class^='sheet-toggle-'] { background-color: $gray; border-radius: $border-radius; - color: white; + color: rgba(255,255,255, .87); cursor: pointer; display: inline-block; font-size: 10px; @@ -1211,32 +1253,8 @@ span[class^='sheet-toggle-'] { @include tab-toggle('icon-attack-settings', 13px, 'padding'); @include tab-toggle('edit-mode', 19px, 'padding'); -$tab-hd-single-digit-width: 14px; -$tab-hd-double-digit-width: 20px; -@include tab-toggle('hd-d2', $tab-hd-single-digit-width, 'halfPadding'); -@include tab-toggle('hd-d4', $tab-hd-single-digit-width, 'halfPadding'); -@include tab-toggle('hd-d6', $tab-hd-single-digit-width, 'halfPadding'); -@include tab-toggle('hd-d8', $tab-hd-single-digit-width, 'halfPadding'); -@include tab-toggle('hd-d10', $tab-hd-double-digit-width, 'halfPadding'); -@include tab-toggle('hd-d12', $tab-hd-double-digit-width, 'halfPadding'); -@include tab-toggle('hd-d20', $tab-hd-double-digit-width, 'halfPadding'); +@include tab-toggle('pseudo-button', 100px, 'padding'); -@include tab-toggle('emote', 32px, 'padding'); -@include tab-toggle('attack', 31px, 'padding'); -@include tab-toggle('reach', 32px, 'padding'); -@include tab-toggle('range', 33px, 'padding'); -@include tab-toggle('target', 32px, 'padding'); -@include tab-toggle('ammo', 31px, 'padding'); -@include tab-toggle('ammo-auto', 24px, 'padding'); -@include tab-toggle('damage', 23px, 'padding'); -@include tab-toggle('sv-damage', 23px, 'padding'); -@include tab-toggle('alt-damage', 14px, 'padding'); -@include tab-toggle('second-damage', 52px, 'padding'); -@include tab-toggle('sv-second-damage', 52px, 'padding'); -@include tab-toggle('crit', 17px, 'padding'); -@include tab-toggle('crit-bonus', 32px, 'padding'); -@include tab-toggle('bonus', 32px, 'padding'); -@include tab-toggle('bonuses', 43px, 'padding'); @include tab-toggle('spells-filter-prepared', 43px, 'padding'); @include tab-toggle('spells-prepared', 43px, 'padding'); @include tab-toggle('spells-filter-ritual', 26px, 'padding'); @@ -1274,10 +1292,6 @@ $tab-hd-double-digit-width: 20px; @include tab-toggle('recharge', 47px, 'padding'); @include tab-toggle('spell-slots', 49px, 'padding'); @include tab-toggle('spell-points', 56px, 'padding'); -@include tab-toggle('spell-sorcery-points', 41px, 'padding'); -@include tab-toggle('spell-warlock-slots', 38px, 'padding'); - -@include tab-toggle('generate-skills', 70px, 'padding'); span.sheet-toggle-spells-filter-level-cantrips, span.sheet-toggle-spells-filter-casting-time-reaction { @@ -1393,8 +1407,6 @@ input.sheet-toggle-page-all:checked ~ div[class^='sheet-section-'] { input[class^='sheet-toggle-page-'], span[class^='sheet-toggle-page-'] { height: 16px; - margin-bottom: 2px; - margin-top: 2px; } span[class^='sheet-toggle-page-'] { @@ -1427,7 +1439,7 @@ input[class^='sheet-slide-input-'] { opacity: 0; position: relative; vertical-align: top; - z-index: 99; + z-index: 5; } label[class^='sheet-slide-toggle-'] { @@ -1480,15 +1492,12 @@ input.sheet-toggle-hidden-info:checked ~ div.sheet-toggle-hidden-info { } input.sheet-toggle-icon-settings:not(:checked) ~ div.sheet-details, +input.sheet-toggle-icon-settings:not(:checked) ~ div .sheet-details, input.sheet-toggle-edit-mode:not(:checked) ~ div .sheet-edit, input.sheet-toggle-edit-mode:checked ~ div .sheet-presentation, input.sheet-toggle-reach:not(:checked) ~ div div.sheet-toggle-reach, input.sheet-toggle-range:not(:checked) ~ div div.sheet-toggle-range, -input.sheet-toggle-range:not(:checked) ~ .sheet-toggle-ammo, -input.sheet-toggle-range:not(:checked) ~ .sheet-toggle-ammo-auto, -input.sheet-toggle-ammo:not(:checked) ~ div div.sheet-toggle-ammo, -input.sheet-toggle-ammo:not(:checked) ~ .sheet-toggle-ammo-auto, input.sheet-toggle-target:not(:checked) ~ div div.sheet-toggle-target, input.sheet-toggle-alt-damage:not(:checked) ~ div div.sheet-toggle-alt-damage, @@ -1524,8 +1533,6 @@ input.sheet-toggle-hd-d20:not(:checked) ~ div.sheet-toggle-hd-d20, input.sheet-toggle-spell-slots:not(:checked) ~ .sheet-spell-slots, input.sheet-toggle-spell-points:not(:checked) ~ .sheet-spell-points, input.sheet-toggle-spell-slots:not(:checked) ~ div div.sheet-spell-slots-points, -input.sheet-toggle-sorcerer-levels:not(:checked) ~ div .sheet-spell-sorcery-points, -input.sheet-toggle-warlock-levels:not(:checked) ~ div .sheet-spell-warlock-slots, input.sheet-toggle-spell-filters:not(:checked) ~ [class^=sheet-toggle-spells-filter], input.sheet-toggle-spell-filters:not(:checked) ~ span.sheet-spells-filter, @@ -1541,9 +1548,16 @@ input.sheet-toggle-spell-level-9:not(:checked) ~ div .sheet-spell-level-9, input.sheet-toggle-custom-class:not(:checked) ~ .sheet-custom-class, -input.sheet-attack-toggle:not(:checked) ~ div.sheet-attack-toggle { +input.sheet-attack-toggle:not(:checked) ~ div.sheet-attack-toggle, + +input.sheet-show-uses:not(:checked) ~ .sheet-show-uses { display: none; } +@each $class in $classes { + input.sheet-has-#{$class}-levels:not([value="1"]) ~ div .sheet-has-#{$class}-levels { + display: none; + } +} .sheet-spells-filter { display: inline-block; @@ -1585,7 +1599,7 @@ input[class^='sheet-toggle-icon']:checked + span[class^='sheet-toggle-icon'], input[class^='sheet-toggle-edit-mode']:checked + span[class^='sheet-toggle-edit-mode'] { background-color: transparent; color: rgba(255,255,1,.95); - text-shadow: -1px 0 $black, 0 1px $black, 1px 0 $black, 0 -1px $black; + @include text-shadow(); } input[class^='sheet-toggle-spells']:checked + span[class^='sheet-toggle-spells'] { @@ -1616,28 +1630,39 @@ span[class^='sheet-toggle-spells-filter'] { } .sheet-toggle-icon-settings { + height: 16px; position: absolute !important; right: 0; top: 0; + width: 15px; +} +input.sheet-toggle-icon-settings { + height: 16px; +} + +span.sheet-toggle-icon-settings, +span.sheet-toggle-edit-mode { + background-color: transparent; + color: $grayer-gray; + margin-top: 0; + @include text-shadow(); } span.sheet-toggle-icon-settings { - background-color: transparent; - color: $grayer-gray; font-size: 14px; height: 16px; - margin-top: 0; } span.sheet-toggle-edit-mode { - background-color: transparent; - color: $grayer-gray; - font-size: 18px; - margin-top: 0; + font-size: 22px; } input.sheet-toggle-edit-mode, span.sheet-toggle-edit-mode { - height: 20px; + height: 24px; + &.sheet-negative-mar-t-eight { + margin-top: -8px; + } } + input.sheet-toggle-edit-mode:checked ~ div { input, select, @@ -1708,8 +1733,8 @@ span.sheet-spacer { margin-top: 5px; } -.sheet-spacer-sm { - margin-top: 2px; +.sheet-spacer-smd { + margin-top: 4px; } .sheet-left { @@ -1728,16 +1753,6 @@ textarea { resize: both; } -.sheet-background-textarea, -.sheet-features-and-traits { - font-size: .95em; -} -.sheet-equipment-wrapper, -.sheet-traits-wrapper { - max-height: 20em; - overflow-y: auto; -} - .sheet-personality-traits { border-bottom-left-radius: 0; border-bottom-right-radius: 0; @@ -1782,7 +1797,8 @@ textarea { .sheet-shaped-row, .sheet-rolltemplate-5e-shaped .sheet-shaped-row, .sheet-section-spells .repcontainer, -.sheet-section-npc .sheet-skills .repcontainer { +.sheet-section-npc .sheet-skills .repcontainer, +.sheet-ammo .repcontainer { display: flex; flex-direction: row; flex-wrap: wrap; @@ -1811,11 +1827,21 @@ textarea { } } +.sheet-ammo .repitem { + .sheet-section-core & { + width: 25%; + } + .sheet-section-equipment & { + width: 20%; + } + padding-left: 2px; + padding-right: 2px; +} + .sheet-section-spells .sheet-wrap-box textarea { font-size: 11px; } - .sheet-col-1-3 { width: 33.33333%; } @@ -1858,9 +1884,11 @@ textarea { margin-left: 20%; } +.sheet-gm-info-flex, +.sheet-rolltemplate-5e-shaped .sheet-gm-info-flex, .sheet-gm-info-block, -.sheet-gm-info-inline-block, .sheet-rolltemplate-5e-shaped .sheet-gm-info-block, +.sheet-gm-info-inline-block, .sheet-rolltemplate-5e-shaped .sheet-gm-info-inline-block { background-color: $light-yellow !important; display: none; diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/ammo.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/ammo.html new file mode 100644 index 0000000000..438dc9a60a --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/ammo.html @@ -0,0 +1,11 @@ +
+ + + +
{{'AMMO' | translate}}.
+
+
+ +
+
+
diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/attack.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/attack.html index b74fbe7c22..4e8bb73627 100644 --- a/D&D_5e_Reshaped/precompiled/components/actionComponents/attack.html +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/attack.html @@ -1,7 +1,7 @@
- +
{{'ATTACK' | translate}}.
diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/attackSpell.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/attackSpell.html index f0df14965b..a1b6191b1f 100644 --- a/D&D_5e_Reshaped/precompiled/components/actionComponents/attackSpell.html +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/attackSpell.html @@ -1,7 +1,7 @@
- +
{{'ATTACK' | translate}}.
diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/damageClassFeatures.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/damageClassFeatures.html new file mode 100644 index 0000000000..b85830a07b --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/damageClassFeatures.html @@ -0,0 +1,69 @@ + + +
+ + + +
{{'DAMAGE' | translate}}.
+
+ +
+
+
+
+ + + + + + + + + + + + +
+
+
+
+ +
+
+ +
+
diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/damageSecondaryClassFeatures.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/damageSecondaryClassFeatures.html new file mode 100644 index 0000000000..ef06336431 --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/damageSecondaryClassFeatures.html @@ -0,0 +1,69 @@ + + +
+ + + +
{{'DAMAGE' | translate}}.
+
+ +
+
+
+
+ + + + + + + + + + + + +
+
+
+
+ +
+
+ +
+
diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/extras.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/extras.html index e5b2e28ede..ca9cae2952 100644 --- a/D&D_5e_Reshaped/precompiled/components/actionComponents/extras.html +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/extras.html @@ -1,21 +1,20 @@
- - + +
{{'EXTRAS' | translate}}.
-
- +
+
{{'EMOTE' | translate}}
-
-
- +
+
{{'FREETEXT' | translate}}
-
- +
+
{{'FREEFORM' | translate}}
diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/extrasClassFeatures.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/extrasClassFeatures.html new file mode 100644 index 0000000000..49a6ce6e03 --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/extrasClassFeatures.html @@ -0,0 +1,16 @@ +
+ + + +
{{'EXTRAS' | translate}}.
+
+ + +
{{'FREETEXT' | translate}}
+
+
+ + +
{{'FREEFORM' | translate}}
+
+
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/heal.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/heal.html index a5f59bc72f..5f0f334732 100644 --- a/D&D_5e_Reshaped/precompiled/components/actionComponents/heal.html +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/heal.html @@ -1,15 +1,15 @@ -
+
{{'HEAL' | translate}}.
-
+
-
+
-
+
+
+
-
+
+
+
+
+
+
+ + {{'QUERY' | translate}} +
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/healClassFeatures.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/healClassFeatures.html new file mode 100644 index 0000000000..2f7f3ce019 --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/healClassFeatures.html @@ -0,0 +1,67 @@ + + +
+ + + +
{{'HEAL' | translate}}.
+
+ +
+
+
+
+ + + + + + + + + + + + +
+
+
+
+ +
+
+
+
+ + {{'QUERY' | translate}} +
+
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/healResource.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/healResource.html deleted file mode 100644 index a78368b005..0000000000 --- a/D&D_5e_Reshaped/precompiled/components/actionComponents/healResource.html +++ /dev/null @@ -1,64 +0,0 @@ -
- - - -
{{'HEAL' | translate}}.
-
-
-
- -
-
+
-
- - - - - - - - - - - - -
-
- - {{'QUERY' | translate}} -
-
-
-
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/savingThrow.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/savingThrow.html index e87998b049..de66e61be5 100644 --- a/D&D_5e_Reshaped/precompiled/components/actionComponents/savingThrow.html +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/savingThrow.html @@ -1,10 +1,10 @@
- +
{{'SAVING_THROW' | translate}}.
- +
@@ -108,9 +108,9 @@
- +
- +
diff --git a/D&D_5e_Reshaped/precompiled/components/actionComponents/savingThrowClassFeatures.html b/D&D_5e_Reshaped/precompiled/components/actionComponents/savingThrowClassFeatures.html new file mode 100644 index 0000000000..9bf414cd6d --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/actionComponents/savingThrowClassFeatures.html @@ -0,0 +1,116 @@ +
+ + + +
{{'SAVING_THROW' | translate}}.
+
+ +
+
+
+ + + + + + + + + + + + +
+
+
+
+ +
+
=
+
+ {{'DC' | translate}} +
+
+ +
+
+ + + + + + + + + + + + +
+
+
+ +
+
+ +
+
diff --git a/D&D_5e_Reshaped/precompiled/components/character/character.html b/D&D_5e_Reshaped/precompiled/components/character/character.html index a54c42a75a..536f77d98d 100644 --- a/D&D_5e_Reshaped/precompiled/components/character/character.html +++ b/D&D_5e_Reshaped/precompiled/components/character/character.html @@ -26,58 +26,51 @@
- - {{'JACK_OF_ALL_TRADES' | translate}} - - - {{'REMARKABLE_ATHLETE' | translate}} - - - {{'HALFLING_LUCK' | translate}} -
-
-
-
- -
- {{'EVERY' | translate}} -
- -
- {{'CLASSES.ROGUE' | translate}} {{'LEVELS' | translate}} -
+
+ + {{'JACK_OF_ALL_TRADES' | translate}} - + + {{'REMARKABLE_ATHLETE' | translate}} + + + {{'HALFLING_LUCK' | translate}}
-
-
-
- -
-
- - +
+
+
{{'CLASSES.SORCERER' | translate}}
+
+ + {{'CLASS_FEATURES.METAMAGIC_CAREFUL_SPELL' | translate}} +
+
+ + {{'CLASS_FEATURES.METAMAGIC_DISTANT_SPELL' | translate}} +
+
+ + {{'CLASS_FEATURES.METAMAGIC_EMPOWERED_SPELL' | translate}} +
+
+ + {{'CLASS_FEATURES.METAMAGIC_EXTENDED_SPELL' | translate}} +
+
+ + {{'CLASS_FEATURES.METAMAGIC_HEIGHTENED_SPELL' | translate}} +
+
+ + {{'CLASS_FEATURES.METAMAGIC_QUICKENED_SPELL' | translate}} +
+
+ + {{'CLASS_FEATURES.METAMAGIC_SUBTLE_SPELL' | translate}} +
+
+ + {{'CLASS_FEATURES.METAMAGIC_TWINNED_SPELL' | translate}}
diff --git a/D&D_5e_Reshaped/precompiled/components/classFeatures/classFeatures.html b/D&D_5e_Reshaped/precompiled/components/classFeatures/classFeatures.html new file mode 100644 index 0000000000..afc021a33f --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/classFeatures/classFeatures.html @@ -0,0 +1,73 @@ +
+
+
+
+
+ +
+
+ +
+
/
+
+ +
+
+ y + +
+
+
+ +
+
+ + + + + + + + + + + + +
+
+ + //= include ../actionComponents/damageClassFeatures.html + //= include ../actionComponents/damageSecondaryClassFeatures.html + //= include ../actionComponents/savingThrowClassFeatures.html + //= include ../actionComponents/healClassFeatures.html + //= include ../actionComponents/extrasClassFeatures.html +
+
+
+
{{'CLASS_FEATURES_TITLE' | translate}}
+
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/core/abilities.html b/D&D_5e_Reshaped/precompiled/components/core/abilities.html index 631ae1d458..4d458ec3f3 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/abilities.html +++ b/D&D_5e_Reshaped/precompiled/components/core/abilities.html @@ -1,23 +1,33 @@
- + - -
+ +
+ {{'CHECK' | translate}} + +
+
+ +
+ +
+
+
+
- + - -
+
+ {{'CHECK' | translate}} + +
+
+ +
+ +
+
+
+
- + - -
+
+ {{'CHECK' | translate}} + +
+
+ +
+ +
+
+
+
- + - -
+
+ {{'CHECK' | translate}} + +
+
+ +
+ +
+
+
+
- + - -
+
+ {{'CHECK' | translate}} + +
+
+ +
+ +
+
+
+
- + - -
+
+ {{'CHECK' | translate}} + +
+
+ +
+ +
+
+
+
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/core/armorInit.html b/D&D_5e_Reshaped/precompiled/components/core/armorInit.html index 615f022a68..b4175422a0 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/armorInit.html +++ b/D&D_5e_Reshaped/precompiled/components/core/armorInit.html @@ -1,26 +1,33 @@
-
-
- + +
-
+
- +
+ +
diff --git a/D&D_5e_Reshaped/precompiled/components/core/attacks.html b/D&D_5e_Reshaped/precompiled/components/core/attacks.html index 29129e4d50..34f8e8f9d5 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/attacks.html +++ b/D&D_5e_Reshaped/precompiled/components/core/attacks.html @@ -2,7 +2,7 @@
{{'ATTACK' | translate}}
{{'ATK' | translate}}
-
{{'DAMAGE' | translate}}
+
{{'DAMAGE' | translate}}
@@ -10,7 +10,7 @@ - y - -
+ y +
-
{{'NAME' | translate}}
@@ -61,24 +59,27 @@ -
{{'TYPE' | translate}}
-
{{'REACH' | translate}}
-
-
{{'RANGE' | translate}}
-
- - -
{{'AMMO' | translate}}
+
+
+
+ +
+
/
+
+ +
+
+
{{'USES' | translate}}
@@ -87,9 +88,12 @@ //= include ../actionComponents/damage.html //= include ../actionComponents/damageSecondary.html //= include ../actionComponents/extras.html + //= include ../actionComponents/ammo.html
+ //= include ../equipment/ammo.html +
{{'ATTACKS' | translate}}
diff --git a/D&D_5e_Reshaped/precompiled/components/core/core.html b/D&D_5e_Reshaped/precompiled/components/core/core.html index 529452a471..c74546113c 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/core.html +++ b/D&D_5e_Reshaped/precompiled/components/core/core.html @@ -31,14 +31,8 @@
- //= include ../resources/resource.html - //= include ../spells/spell_slots_points.html -
- //= include ../spells/sorceryPoints.html -
-
- //= include ../spells/warlockSlots.html -
+ //= include ../spells/spellSlots.html + //= include ../classFeatures/classFeatures.html
@@ -50,12 +44,12 @@
//= include background.html - //= include traits.html
//= include resistancesVulnerabilities.html
{{'RESISTANCES_AND_IMMUNITIES' | translate}}
//= include exhaustion.html + //= include traits.html
diff --git a/D&D_5e_Reshaped/precompiled/components/core/deathSaves.html b/D&D_5e_Reshaped/precompiled/components/core/deathSaves.html index ea9945007c..15438952b0 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/deathSaves.html +++ b/D&D_5e_Reshaped/precompiled/components/core/deathSaves.html @@ -20,7 +20,7 @@
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/core/equipment.html b/D&D_5e_Reshaped/precompiled/components/core/equipment.html index 416bf28499..1d9be0cc40 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/equipment.html +++ b/D&D_5e_Reshaped/precompiled/components/core/equipment.html @@ -6,20 +6,21 @@
-
-
{{'ARMOR' | translate}}
-
{{'AC' | translate}}
+
+
{{'ARMOR' | translate}}
+
{{'USES' | translate}}
+
{{'AC' | translate}}
-
+
-
- - + @@ -28,7 +29,19 @@
-
+
+
+ +
+ +
+
/
+
+ +
+
+
+
@@ -37,26 +50,39 @@
-
-
{{'EQUIPMENT' | translate}}
-
{{'QTY' | translate}}
+
+
{{'EQUIPMENT' | translate}}
+
{{'USES' | translate}}
+
{{'QTY' | translate}}
-
+
-
- - +
-
- +
+
+ +
+ +
+
/
+
+ +
+
+
+
+
diff --git a/D&D_5e_Reshaped/precompiled/components/core/exhaustion.html b/D&D_5e_Reshaped/precompiled/components/core/exhaustion.html index 59aa46ac85..397fa9870e 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/exhaustion.html +++ b/D&D_5e_Reshaped/precompiled/components/core/exhaustion.html @@ -1,4 +1,4 @@ -
+
diff --git a/D&D_5e_Reshaped/precompiled/components/core/hitDice.html b/D&D_5e_Reshaped/precompiled/components/core/hitDice.html index d61a6b613d..31c3f53743 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/hitDice.html +++ b/D&D_5e_Reshaped/precompiled/components/core/hitDice.html @@ -15,8 +15,9 @@
+
-
@@ -29,8 +30,9 @@
+
-
@@ -43,8 +45,9 @@
+
-
@@ -57,8 +60,9 @@
+
-
@@ -71,8 +75,9 @@
+
-
@@ -85,8 +90,9 @@
+
-
@@ -99,8 +105,9 @@
+
-
diff --git a/D&D_5e_Reshaped/precompiled/components/core/hitPoints.html b/D&D_5e_Reshaped/precompiled/components/core/hitPoints.html index 277e7fe9c4..e692de1b61 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/hitPoints.html +++ b/D&D_5e_Reshaped/precompiled/components/core/hitPoints.html @@ -1,16 +1,16 @@
-
-
+
+
-
/
-
+
/
+
-
-
+
-
+
-
-
+
-
-
+
-
-
+
-
-
-
+
+
-
diff --git a/D&D_5e_Reshaped/precompiled/components/core/skills.html b/D&D_5e_Reshaped/precompiled/components/core/skills.html index b1e39f5fad..86eb6f8b1f 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/skills.html +++ b/D&D_5e_Reshaped/precompiled/components/core/skills.html @@ -31,12 +31,14 @@
-
+
-
@@ -44,53 +46,58 @@
- - - - - - - - - - - - +
+ ( + + + + + + + + + + + + + ) +
- {{'GENERATE_SKILLS' | translate}} +
+ {{'GENERATE_SKILLS' | translate}}
{{'SKILLS_TITLE' | translate}}
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/core/traits.html b/D&D_5e_Reshaped/precompiled/components/core/traits.html index 4d0a933955..9c15ebae26 100644 --- a/D&D_5e_Reshaped/precompiled/components/core/traits.html +++ b/D&D_5e_Reshaped/precompiled/components/core/traits.html @@ -1,9 +1,9 @@ -
-
- //= include ../npc/traits.html +
+
+ //= include ../traits/traits.html
Below will be removed shortly. Please port it over to the new version above.
- +
{{'FEATURES_AND_TRAITS' | translate}}
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/equipment/ammo.html b/D&D_5e_Reshaped/precompiled/components/equipment/ammo.html new file mode 100644 index 0000000000..f09e9b5b91 --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/equipment/ammo.html @@ -0,0 +1,21 @@ +
+
{{'AMMO' | translate}}
+
+
+
+ +
{{'QTY' | translate}}
+
+
+ +
{{'WEIGHT' | translate}}
+
+
+
+ + +
+
+
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/equipment/armor.html b/D&D_5e_Reshaped/precompiled/components/equipment/armor.html index 7e3e6af848..3aa3736b12 100644 --- a/D&D_5e_Reshaped/precompiled/components/equipment/armor.html +++ b/D&D_5e_Reshaped/precompiled/components/equipment/armor.html @@ -1,25 +1,26 @@
-
-
{{'ARMOR' | translate}}
+
+
{{'ARMOR' | translate}}
{{'TYPE' | translate}}
{{'AC' | translate}}
-
{{'BONUS' | translate}}
+
{{'BONUS' | translate}}
{{'TOTAL' | translate}}
{{'ABILITIES.strength.NAME' | translate}}
-
{{'SKILLS.stealth' | translate}}
-
{{'WEIGHT' | translate}}
+
{{'SKILLS.stealth' | translate}}
+
{{'USES' | translate}}
+
{{'WEIGHT' | translate}}
-
+
-
+
@@ -76,7 +77,7 @@
+
-
+
=
@@ -113,10 +114,21 @@
-
+
-
+
+
+
+ +
+
/
+
+ +
+
+
+
@@ -182,9 +194,9 @@
{{'AC_UNARMORED' | translate}}
-
+ +//= include ammo.html \ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/equipment/equipment.html b/D&D_5e_Reshaped/precompiled/components/equipment/equipment.html index 9e6503f3e3..2139947bfb 100644 --- a/D&D_5e_Reshaped/precompiled/components/equipment/equipment.html +++ b/D&D_5e_Reshaped/precompiled/components/equipment/equipment.html @@ -1,19 +1,19 @@
-
+
//= include armor.html
-
+
//= include weight.html
-
+
//= include coins.html
-
+
//= include equipmentItems.html
//= include attacks.html diff --git a/D&D_5e_Reshaped/precompiled/components/equipment/equipmentItems.html b/D&D_5e_Reshaped/precompiled/components/equipment/equipmentItems.html index 16dc9f8f67..bcbca13a68 100644 --- a/D&D_5e_Reshaped/precompiled/components/equipment/equipmentItems.html +++ b/D&D_5e_Reshaped/precompiled/components/equipment/equipmentItems.html @@ -1,33 +1,45 @@
-
-
{{'EQUIPMENT' | translate}}
+
+
{{'EQUIPMENT' | translate}}
{{'CONTENT' | translate}}
-
{{'QTY' | translate}}
+
{{'USES' | translate}}
+
{{'QTY' | translate}}
-
{{'WEIGHT' | translate}}
+
{{'WEIGHT' | translate}}
-
{{'TOTAL' | translate}}
+
{{'TOTAL' | translate}}
-
+
-
+
- +
-
+
+
+
+ +
+
/
+
+ +
+
+
+
×
-
+
=
-
+
diff --git a/D&D_5e_Reshaped/precompiled/components/equipment/weight.html b/D&D_5e_Reshaped/precompiled/components/equipment/weight.html index 640ba06c3e..3e85dfada0 100644 --- a/D&D_5e_Reshaped/precompiled/components/equipment/weight.html +++ b/D&D_5e_Reshaped/precompiled/components/equipment/weight.html @@ -9,6 +9,14 @@
+
+
+ {{'AMMO' | translate}} +
+
+ +
+
{{'ARMOR' | translate}} @@ -33,14 +41,6 @@
-
-
- {{'MISC' | translate}} -
-
- -
-
{{'TOTAL' | translate}} @@ -86,7 +86,7 @@
-
{{'WEIGHT' | translate}}
+
{{'CARRYING_CAPACITY' | translate}}
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/header/header.html b/D&D_5e_Reshaped/precompiled/components/header/header.html index 87910ae746..60397b0e62 100644 --- a/D&D_5e_Reshaped/precompiled/components/header/header.html +++ b/D&D_5e_Reshaped/precompiled/components/header/header.html @@ -14,7 +14,7 @@
- + diff --git a/D&D_5e_Reshaped/precompiled/components/header/nav.html b/D&D_5e_Reshaped/precompiled/components/header/nav.html index 58341b8ee7..dd0f62a63b 100644 --- a/D&D_5e_Reshaped/precompiled/components/header/nav.html +++ b/D&D_5e_Reshaped/precompiled/components/header/nav.html @@ -1,8 +1,8 @@ -
-{{'CORE' | translate}} -{{'SPELLS' | translate}} -{{'EQUIPMENT' | translate}} -{{'CHARACTER' | translate}} -y -{{'ALL' | translate}} -p +
+{{'CORE' | translate}} +{{'SPELLS' | translate}} +{{'EQUIPMENT' | translate}} +{{'CHARACTER' | translate}} +y +{{'ALL' | translate}} +p diff --git a/D&D_5e_Reshaped/precompiled/components/header/toggleVariables.html b/D&D_5e_Reshaped/precompiled/components/header/toggleVariables.html index 17481cff7c..aa596e99f5 100644 --- a/D&D_5e_Reshaped/precompiled/components/header/toggleVariables.html +++ b/D&D_5e_Reshaped/precompiled/components/header/toggleVariables.html @@ -1,5 +1,15 @@ - - + + + + + + + + + + + + diff --git a/D&D_5e_Reshaped/precompiled/components/importOverlay.html b/D&D_5e_Reshaped/precompiled/components/importOverlay.html new file mode 100644 index 0000000000..c63eefed87 --- /dev/null +++ b/D&D_5e_Reshaped/precompiled/components/importOverlay.html @@ -0,0 +1,11 @@ + +
+
+
+ {{'CANCEL' | translate}} +
+
+ {{'IMPORT' | translate}} +
+
+
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/macros/macros.html b/D&D_5e_Reshaped/precompiled/components/macros/macros.html index 38889a9763..ea81498aef 100644 --- a/D&D_5e_Reshaped/precompiled/components/macros/macros.html +++ b/D&D_5e_Reshaped/precompiled/components/macros/macros.html @@ -2,8 +2,8 @@
-
@@ -16,7 +16,7 @@
-
diff --git a/D&D_5e_Reshaped/precompiled/components/npc/abilities.html b/D&D_5e_Reshaped/precompiled/components/npc/abilities.html index 603be9ac29..b7bb1e71d4 100644 --- a/D&D_5e_Reshaped/precompiled/components/npc/abilities.html +++ b/D&D_5e_Reshaped/precompiled/components/npc/abilities.html @@ -1,7 +1,7 @@
-
- -
-
+
+
-
+
+
+
+ +
+
()
+ +
+ {{'CHECK' | translate}} + +
+
+
+ +
+
-
- -
-
+
+
-
+
+
+
+ +
+
()
+ +
+ {{'CHECK' | translate}} + +
+
+
+ +
+
-
- -
-
+
+
-
+
+
+
+ +
+
()
+ +
+ {{'CHECK' | translate}} + +
+
+
+ +
+
-
- -
-
+
+
-
+
+
+
+ +
+
()
+ +
+ {{'CHECK' | translate}} + +
+
+
+ +
+
-
- -
-
+
+
-
+
+
+
+ +
+
()
+ +
+ {{'CHECK' | translate}} + +
+
+
+ +
+
-
- -
-
+
+
-
+
+
+
+ +
+
()
+ +
+ {{'CHECK' | translate}} + +
+
+
+ +
+
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/npc/acHpSpeed.html b/D&D_5e_Reshaped/precompiled/components/npc/acHpSpeed.html index 13a39a0862..a1a62ecb7c 100644 --- a/D&D_5e_Reshaped/precompiled/components/npc/acHpSpeed.html +++ b/D&D_5e_Reshaped/precompiled/components/npc/acHpSpeed.html @@ -1,35 +1,41 @@
-
- +
-
-
- +
+
+ ( + + )
-
- +
+
+
+ +
- - diff --git a/D&D_5e_Reshaped/precompiled/components/npc/actionContents.html b/D&D_5e_Reshaped/precompiled/components/npc/actionContents.html index e538437654..e7809e4990 100644 --- a/D&D_5e_Reshaped/precompiled/components/npc/actionContents.html +++ b/D&D_5e_Reshaped/precompiled/components/npc/actionContents.html @@ -1,17 +1,17 @@ -
+
-
-
-
- -
-
+ +
+
+ +
+
-
{{'TYPE' | translate}}
-
-
- +
{{'TYPE' | translate}}
+
+
+ -
{{'REACH' | translate}}
-
- -
- - -
{{'RANGE' | translate}}
-
- -
- - -
{{'RECHARGE' | translate}}
-
+
{{'REACH' | translate}}
+
+ + +
{{'RANGE' | translate}}
+
+ +
+ + +
{{'RECHARGE' | translate}}
+
+
+ y +
//= include ../actionComponents/attack.html //= include ../actionComponents/savingThrow.html //= include ../actionComponents/damage.html diff --git a/D&D_5e_Reshaped/precompiled/components/npc/details.html b/D&D_5e_Reshaped/precompiled/components/npc/details.html index 92221c8cbe..bd52d3667f 100644 --- a/D&D_5e_Reshaped/precompiled/components/npc/details.html +++ b/D&D_5e_Reshaped/precompiled/components/npc/details.html @@ -22,7 +22,7 @@
-
- //= include traits.html + //= include ../traits/traits.html //= include actions.html //= include reactions.html //= include legendaryActions.html diff --git a/D&D_5e_Reshaped/precompiled/components/npc/savingThrows.html b/D&D_5e_Reshaped/precompiled/components/npc/savingThrows.html index a1014ebad1..3be3a9dc28 100644 --- a/D&D_5e_Reshaped/precompiled/components/npc/savingThrows.html +++ b/D&D_5e_Reshaped/precompiled/components/npc/savingThrows.html @@ -9,7 +9,7 @@
- @@ -20,7 +20,7 @@
- @@ -31,7 +31,7 @@
- @@ -42,7 +42,7 @@
- @@ -53,7 +53,7 @@
- @@ -64,7 +64,7 @@
- diff --git a/D&D_5e_Reshaped/precompiled/components/npc/skills.html b/D&D_5e_Reshaped/precompiled/components/npc/skills.html index 883517905c..706b3d87d7 100644 --- a/D&D_5e_Reshaped/precompiled/components/npc/skills.html +++ b/D&D_5e_Reshaped/precompiled/components/npc/skills.html @@ -37,62 +37,68 @@
-
- - - - - - - - - - - - +
+ ( + + + + + + + + + + + + + ) +
,
- {{'GENERATE_SKILLS' | translate}} + {{'GENERATE_SKILLS' | translate}}
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/resources/resource.html b/D&D_5e_Reshaped/precompiled/components/resources/resource.html deleted file mode 100644 index d8ebcc62bf..0000000000 --- a/D&D_5e_Reshaped/precompiled/components/resources/resource.html +++ /dev/null @@ -1,89 +0,0 @@ -
-
-
-
-
- -
-
- -
-
/
-
- -
-
- y - -
-
-
- -
-
- - - - - - - - - - - - -
-
- - //= include ../actionComponents/healResource.html - -
- - - -
-
{{'EXTRAS' | translate}}.
-
-
- - -
{{'FREETEXT' | translate}}
-
-
- - -
{{'FREEFORM' | translate}}
-
-
-
-
-
-
-
{{'RESOURCES' | translate}}
-
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/rollTemplate.html b/D&D_5e_Reshaped/precompiled/components/rollTemplate.html index 6cfbcc42c4..6caaae5a59 100644 --- a/D&D_5e_Reshaped/precompiled/components/rollTemplate.html +++ b/D&D_5e_Reshaped/precompiled/components/rollTemplate.html @@ -12,18 +12,24 @@
{{#reach}}{{reach}} reach{{/reach}} {{#range}}{{#reach}} • {{/reach}}{{range}} range{{/range}} - {{#ammo}}{{#range}} • {{/range}}{{ammo}} ammo{{/ammo}} + {{#ammo}}{{#range}} • {{/range}}{{ammo}} {{#ammo_name}}{{ammo_name}}{{/ammo_name}}{{^ammo_name}}ammo{{/ammo_name}}{{/ammo}}
- {{#target}} -
{{target}}
- {{/target}} {{/action}} + {{#uses}} +
{{uses}} / {{uses_max}}
+ {{/uses}} {{#subheader}}
{{subheader}}
{{/subheader}} {{#targetName}}
vs {{targetName}}
{{/targetName}} + {{#advantage}} +
advantaged
+ {{/advantage}} + {{#disadvantage}} +
disadvantaged
+ {{/disadvantage}}
{{#emote}}

{{character_name}} {{emote}}

@@ -32,14 +38,12 @@ {{#spell}} {{#casting_time}}
- Casting Time: - {{casting_time}} + Casting Time: {{casting_time}}
{{/casting_time}} {{#range}}
- Range: - {{range}} + Range: {{range}}
{{/range}} {{#components}} @@ -58,8 +62,7 @@ {{/duration}} {{#target}}
- Target: - {{target}} + Target: {{target}}
{{/target}} {{/spell}} @@ -69,29 +72,17 @@ {{#text_top}}
{{text_top}}
{{/text_top}} - {{#roll_toggle}} -
-
- {{#rollLess() roll1 roll2}}{{#advantage}}
{{/advantage}}{{/rollLess() roll1 roll2}} - {{#rollGreater() roll1 roll2}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll1 roll2}} - {{roll1}} - {{#rollLess() roll1 roll2}}{{#advantage}}
{{/advantage}}{{/rollLess() roll1 roll2}} - {{#rollGreater() roll1 roll2}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll1 roll2}} -
- {{^only_roll_1}} -
- {{#rollLess() roll2 roll1}}{{#advantage}}
{{/advantage}}{{/rollLess() roll2 roll1}} - {{#rollGreater() roll2 roll1}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll2 roll1}} - {{roll2}} - {{#rollLess() roll2 roll1}}{{#advantage}}
{{/advantage}}{{/rollLess() roll2 roll1}} - {{#rollGreater() roll2 roll1}}{{#disadvantage}}
{{/disadvantage}}{{/rollGreater() roll2 roll1}} -
- {{/only_roll_1}} + {{#roll1}} +
+
{{roll1}}
+ {{#roll2}} +
{{roll2}}
+ {{/roll2}} {{#vs_ac}}
vs AC{{#targetAC}} {{targetAC}}{{/targetAC}}
{{/vs_ac}}
- {{/roll_toggle}} + {{/roll1}} {{#saving_throw_dc}}
{{#saving_throw_condition}} @@ -99,8 +90,8 @@ {{/saving_throw_condition}} {{#saving_throw_dc}}
- DC {{saving_throw_dc}} - [{{saving_throw_vs_ability}}](~target|{{saving_throw_vs_ability}}_saving_throw) + DC {{saving_throw_dc}} + [{{saving_throw_vs_ability}}](~target|{{saving_throw_vs_ability}}_saving_throw)
saving throw
{{/saving_throw_dc}} @@ -119,43 +110,25 @@
{{/saving_throw_dc}} {{#damage}} -
+
{{damage}} - {{#roll_toggle}} - {{#rollWasCrit() roll1}} - {{#only_roll_1}}+ {{crit_damage}}{{/only_roll_1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - + {{crit_damage}} - {{/rollWasCrit() roll2}} - {{#^rollWasCrit() roll2}} - {{#^rollLess() roll1 roll2}} - {{#advantage}}+ {{crit_damage}}{{/advantage}} - {{/^rollLess() roll1 roll2}} - {{/^rollWasCrit() roll2}} - {{/only_roll_1}} - {{/rollWasCrit() roll1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - {{#^rollWasCrit() roll1}} - {{#^rollLess() roll2 roll1}} - {{#advantage}}+ {{crit_damage}}{{/advantage}} - {{/^rollLess() roll2 roll1}} - {{/^rollWasCrit() roll1}} - {{/rollWasCrit() roll2}} - {{/only_roll_1}} - {{/roll_toggle}} + {{#rollWasCrit() roll1}} + + {{crit_damage}} + {{/rollWasCrit() roll1}} + {{#^rollWasCrit() roll1}} + {{#rollWasCrit() roll2}} + + {{crit_damage}} + {{/rollWasCrit() roll2}} + {{/^rollWasCrit() roll1}}
{{damage_type}}{{^damage_type}}damage{{/damage_type}}
{{/damage}} {{#second_damage}} {{#damage}} -
- + -
+
+
{{/damage}} {{^damage}}
@@ -163,30 +136,14 @@
{{second_damage}} - {{#roll_toggle}} - {{#rollWasCrit() roll1}} - {{#only_roll_1}}+ {{second_crit_damage}}{{/only_roll_1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - + {{second_crit_damage}} - {{/rollWasCrit() roll2}} - {{#^rollWasCrit() roll2}} - {{#^rollLess() roll1 roll2}} - {{#advantage}}+ {{second_crit_damage}}{{/advantage}} - {{/^rollLess() roll1 roll2}} - {{/^rollWasCrit() roll2}} - {{/only_roll_1}} - {{/rollWasCrit() roll1}} - {{^only_roll_1}} - {{#rollWasCrit() roll2}} - {{#^rollWasCrit() roll1}} - {{#^rollLess() roll2 roll1}} - {{#advantage}}+ {{second_crit_damage}}{{/advantage}} - {{/^rollLess() roll2 roll1}} - {{/^rollWasCrit() roll1}} - {{/rollWasCrit() roll2}} - {{/only_roll_1}} - {{/roll_toggle}} + {{#rollWasCrit() roll1}} + + {{second_crit_damage}} + {{/rollWasCrit() roll1}} + {{#^rollWasCrit() roll1}} + {{#rollWasCrit() roll2}} + + {{second_crit_damage}} + {{/rollWasCrit() roll2}} + {{/^rollWasCrit() roll1}}
{{second_damage_type}}{{^second_damage_type}}damage{{/second_damage_type}}
@@ -198,9 +155,7 @@
{{/damage}} {{#heal}} -
- Heal for {{heal}} HP -
+
Heal for {{heal}} HP
{{/heal}} {{#death_saving_throw_successes}}
@@ -212,22 +167,23 @@ Failures {{death_saving_throw_failures}} / 3
{{/death_saving_throw_failures}} + {{#text_center}} +
{{text_center}}
+ {{/text_center}} {{#text}} -
{{text}}
+
{{text}}
{{/text}} {{#text_big}} -
{{text_big}}
+
{{text_big}}
{{/text_big}} - - {{#allprops() freetext text text_big text_top character_name saving_throw title ignore show_character_name subheader roll_toggle roll1 roll2 only_roll_1 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} -
+ {{#allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} +
{{key}}. {{value}}
- {{/allprops() freetext text text_big text_top character_name saving_throw title ignore show_character_name subheader roll_toggle roll1 roll2 only_roll_1 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} - + {{/allprops() freetext text text_center text_big text_top character_name saving_throw title ignore show_character_name subheader uses uses_max roll1 roll2 advantage disadvantage vs_ac ability emote death_saving_throw death_saving_throw_successes death_saving_throw_failures targetAC targetName action type damage damage_type crit_damage second_damage second_damage_type second_crit_damage ranged damage target reach range ammo ammo_name spell saving_throw_condition saving_throw_dc saving_throw_vs_ability saving_throw_success saving_throw_failure friendly_level school ritual content cast_as_level heal casting_time concentration duration components materials hide_saving_throw_dc hide_spell_content hide_freetext hide_attack hide_damage hide_saving_throw_failure hide_saving_throw_success recharge hide_recharge}} {{#freetext}} -
{{freetext}}
+
{{freetext}}
{{/freetext}} {{#recharge}}
diff --git a/D&D_5e_Reshaped/precompiled/components/settings/bonuses.html b/D&D_5e_Reshaped/precompiled/components/settings/bonuses.html index 3f466734dc..d7b62360cc 100644 --- a/D&D_5e_Reshaped/precompiled/components/settings/bonuses.html +++ b/D&D_5e_Reshaped/precompiled/components/settings/bonuses.html @@ -43,6 +43,29 @@
- //= include ../spells/spellcasting_bonuses.html +
+ + //= include ../spells/spellcastingBonuses.html + +
+ +
+
+ + +
{{'ABILITY_SCORES' | translate}}
+
+
+ + +
{{'SAVING_THROWS' | translate}}
+
+
+ + +
{{'ABILITY_CHECKS' | translate}}
+
+
+
{{'BONUSES_AND_PENALTIES' | translate}}
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/settings/settings.html b/D&D_5e_Reshaped/precompiled/components/settings/settings.html index 37d1326ace..36dd51f32c 100644 --- a/D&D_5e_Reshaped/precompiled/components/settings/settings.html +++ b/D&D_5e_Reshaped/precompiled/components/settings/settings.html @@ -131,40 +131,42 @@
{{'ROLL_OPTIONS' | translate}}:
- - - - + + + + + +
@@ -174,38 +176,33 @@
- - +
@@ -315,110 +312,31 @@
{{'OUTPUT' | translate}}
-
-
-
-
-
{{'ABILITY' | translate}}
-
{{'ABILITY_SCORE_BONUS' | translate}}
-
{{'CHECK_BONUS' | translate}}
-
{{'SAVING_THROW_BONUS' | translate}}
-
-
-
{{'ABILITIES.strength.NAME' | translate}}
-
- -
-
- -
-
-
-
{{'ABILITIES.dexterity.NAME' | translate}}
-
- -
-
- -
-
-
-
{{'ABILITIES.constitution.NAME' | translate}}
-
- -
-
- -
-
-
-
{{'ABILITIES.intelligence.NAME' | translate}}
-
- -
-
- -
-
-
-
{{'ABILITIES.wisdom.NAME' | translate}}
-
- -
-
- -
-
-
-
{{'ABILITIES.charisma.NAME' | translate}}
-
- -
-
- -
-
-
-
{{'ALL' | translate}}
-
- -
-
- -
-
- -
-
- -
- -
- - -
{{'MEDIUM_ARMOR_MAX_DEX' | translate}}
-
-
-
-
-
{{'INITIATIVE_BONUS' | translate}}
-
- -
-
-
-
-
{{'BONUSES' | translate}}
-
-
//= include bonuses.html
+
+
+
+
{{'AMMO_AUTO_USE' | translate}}
+
+ + +
+
+
+ + +
{{'MEDIUM_ARMOR_MAX_DEX' | translate}}
+
+
{{'MISCELLANEOUS' | translate}}
+
+
//= include ../character/spellSlotAdjustments.html
-
+
{{'COIN_CONVERSION_GP_PER_CP' | translate}}:
@@ -455,8 +373,18 @@
{{'HIDE_NPC_INFO_NOTE' | translate}}
- + +
+ {{'HIDE_NPC_INFO_ATTACK' | translate}} + + +
+
+ {{'HIDE_NPC_INFO_DAMAGE' | translate}} + + +
{{'HIDE_NPC_INFO_SAVING_THROW_DC' | translate}} diff --git a/D&D_5e_Reshaped/precompiled/components/sheetWorkers.js b/D&D_5e_Reshaped/precompiled/components/sheetWorkers.js index bc1e55a2fb..82144306a0 100644 --- a/D&D_5e_Reshaped/precompiled/components/sheetWorkers.js +++ b/D&D_5e_Reshaped/precompiled/components/sheetWorkers.js @@ -1,918 +1,1947 @@ -var currentVersion = '2.1.13'; -var skills = { - abilities: { - 'acrobatics': 'dexterity', - 'animalHandling': 'wisdom', - 'arcana': 'intelligence', - 'athletics': 'strength', - 'deception': 'charisma', - 'history': 'intelligence', - 'insight': 'wisdom', - 'intimidation': 'charisma', - 'investigation': 'intelligence', - 'medicine': 'wisdom', - 'nature': 'intelligence', - 'perception': 'wisdom', - 'performance': 'charisma', - 'persuasion': 'charisma', - 'religion': 'intelligence', - 'sleightOfHand': 'dexterity', - 'stealth': 'dexterity', - 'survival': 'wisdom' - }, - names: { - en: { - 'acrobatics': 'Acrobatics', - 'animalHandling': 'Animal Handling', - 'arcana': 'Arcana', - 'athletics': 'Athletics', - 'deception': 'Deception', - 'history': 'History', - 'insight': 'Insight', - 'intimidation': 'Intimidation', - 'investigation': 'Investigation', - 'medicine': 'Medicine', - 'nature': 'Nature', - 'perception': 'Perception', - 'performance': 'Performance', - 'persuasion': 'Persuasion', - 'religion': 'Religion', - 'sleightOfHand': 'Sleight of Hand', - 'stealth': 'Stealth', - 'survival': 'Survival' - }, - de: { - 'acrobatics': 'Akrobatik', - 'animalHandling': 'Umgang mit Tieren', - 'arcana': 'Arkanes', - 'athletics': 'Athletik', - 'deception': 'Täuschung', - 'history': 'Geschichte', - 'insight': 'Einsicht', - 'intimidation': 'Einschüchterung', - 'investigation': 'Investigation', - 'medicine': 'Medizin', - 'nature': 'Natur', - 'perception': 'Entdecken', - 'performance': 'Auftreten', - 'persuasion': 'Überreden', - 'religion': 'Religion', - 'sleightOfHand': 'Taschendiebstahl', - 'stealth': 'Tarnung', - 'survival': 'Überleben' - }, - fr: { - 'acrobatics': 'Acrobaties', - 'animalHandling': 'Dressage', - 'arcana': 'Arcanes', - 'athletics': 'Athlétisme', - 'deception': 'Tromperie', - 'history': 'Histoire', - 'insight': 'Intuition', - 'intimidation': 'Intimidation', - 'investigation': 'Investigation', - 'medicine': 'Médecine', - 'nature': 'Nature', - 'perception': 'Perception', - 'performance': 'Représentation', - 'persuasion': 'Persuasion', - 'religion': 'Religion', - 'sleightOfHand': 'Escamotage', - 'stealth': 'Discrétion', - 'survival': 'Survie' - } - } +'use strict'; + +const currentVersion = '2.2.16'; +let TRANSLATIONS; +const SKILLS = { + acrobatics: 'dexterity', + animalHandling: 'wisdom', + arcana: 'intelligence', + athletics: 'strength', + deception: 'charisma', + history: 'intelligence', + insight: 'wisdom', + intimidation: 'charisma', + investigation: 'intelligence', + medicine: 'wisdom', + nature: 'intelligence', + perception: 'wisdom', + performance: 'charisma', + persuasion: 'charisma', + religion: 'intelligence', + sleightOfHand: 'dexterity', + stealth: 'dexterity', + survival: 'wisdom', }; +const CLASSES = ['barbarian', 'bard', 'cleric', 'druid', 'fighter', 'monk', 'paladin', 'ranger', 'rogue', 'sorcerer', 'warlock', 'wizard']; +const ABILITIES = ['strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma']; -String.prototype.capitalize = function () { - return this.replace(/\w\S*/g, function (txt) { - return txt.charAt(0).toUpperCase() + txt.substr(1); - }); +const translate = (language, key) => { + let translatedValue; + if (key.indexOf('.') !== -1) { + translatedValue = key.split('.').reduce((a, b) => a[b], TRANSLATIONS[language]); + } + + if (TRANSLATIONS[language] && TRANSLATIONS[language][key]) { + translatedValue = TRANSLATIONS[language][key]; + } + + if (!translatedValue && language !== 'en') { + translate('en', key); + } + return translatedValue; }; -String.prototype.firstThree = function () { - return this.substring(0, 3); +const capitalize = (string) => { + return string.replace(/\w\S*/g, (txt) => { + return txt.charAt(0).toUpperCase() + txt.substr(1); + }); }; -Number.prototype.round = function(places) { - return +(Math.round(this + 'e+' + places) + 'e-' + places); +const firstThree = (string) => { + return string.substring(0, 3); }; -Object.prototype.getKeyByValue = function( value ) { - for (var prop in this) { - if (this.hasOwnProperty( prop )) { - if (this[ prop ] === value) { - return prop; - } - } - } +const round = (value, places) => { + return +(`${Math.round(`${value}e+${places}`)}e-${places}`); }; -function getIntValue(value, defaultValue) { - if (!defaultValue) { - defaultValue = 0; - } - return parseInt(value, 10) || defaultValue; -} -function getFloatValue(value, defaultValue) { - if (!defaultValue) { - defaultValue = 0; - } - return parseFloat(value) || defaultValue; -} -function getAbilityName(varName) { - if (!varName) { - return 'strength'; - } - return getAbilityModName(varName).replace('_mod', ''); -} -function getAbilityModName(varName) { - if (!varName) { - return 'strength_mod'; - } else if (typeof varName === 'string') { - varName = varName.replace(/\W/g, ''); - } - return varName; -} -function getAbilityValue(v, varName, defaultAbility) { - if (typeof varName === 'undefined') { - if (defaultAbility) { - return getIntValue(v[defaultAbility]); - } - } else if (exists(varName)) { - varName = getAbilityModName(varName); - return getIntValue(v[varName], 0); - } - return 0; -} -function getAbilityShortName(varName, capital) { - if (!varName) { - return 'Str'; - } - varName = getAbilityModName(varName); - if (capital) { - varName = varName.capitalize(); - } - return varName.firstThree(); -} -function exists(value) { - if (!value || value === '' || value === '0' || value === 0) { - return false; - } - return true; -} -function getRowId(leadingString, eventInfo) { - var re = new RegExp(leadingString + '_([a-zA-Z0-9\-]*)_.*'); - return eventInfo.sourceAttribute.replace(re, '$1'); -} -function getRepeatingField(leadingString, eventInfo) { - var re = new RegExp(leadingString + '_[a-zA-Z0-9\-]*_(.*)'); +const getKeyByValue = (obj, value) => { + for (const prop in obj) { + if (obj.hasOwnProperty(prop)) { + if (obj[prop] === value) { + return prop; + } + } + } + return null; +}; +const calculatePercentDifference = (oldValue, newValue) => { + return Math.abs(((oldValue - newValue) / oldValue) * 100); +}; +const isUndefined = (value) => { + if (typeof value === 'undefined' || value === '') { + return true; + } + return false; +}; +const getIntValue = (value, defaultValue) => { + if (!defaultValue) { + defaultValue = 0; + } + return parseInt(value, 10) || defaultValue; +}; +const getFloatValue = (value, defaultValue) => { + if (!defaultValue) { + defaultValue = 0; + } + return parseFloat(value) || defaultValue; +}; +const exists = (value) => { + if (!value || value === '' || value === '0' || value === 0) { + return false; + } + return true; +}; +const getAbilityModName = (varName) => { + if (!varName) { + return 'strength_mod'; + } else if (typeof varName === 'string') { + varName = varName.replace(/\W/g, ''); + } + return varName; +}; +const getAbilityName = (varName) => { + if (!varName) { + return 'strength'; + } + return getAbilityModName(varName).replace('_mod', ''); +}; +const getAbilityValue = (v, varName, defaultAbility) => { + if (typeof varName === 'undefined') { + if (defaultAbility) { + return getIntValue(v[defaultAbility]); + } + } else if (exists(varName)) { + varName = getAbilityModName(varName); + return getIntValue(v[varName], 0); + } + return 0; +}; +const getAbilityShortName = (varName, capital) => { + if (!varName) { + return 'Str'; + } + varName = getAbilityModName(varName); + if (capital) { + varName = capitalize(varName); + } + return firstThree(varName); +}; +const getRepeatingInfo = (leadingString, eventInfo) => { + const re = new RegExp(`${leadingString}_(-[a-zA-Z0-9\-]*)_(.*)`); + const match = eventInfo.sourceAttribute.match(re); - return eventInfo.sourceAttribute.replace(re, '$1'); -} -function isEmpty(obj) { - for (var prop in obj) { - if (obj.hasOwnProperty(prop)) { - return false; - } - } - return true; -} -function setFinalAttrs(v, finalSetAttrs) { - if (!isEmpty(finalSetAttrs)) { - for (var key in finalSetAttrs) { - if (finalSetAttrs.hasOwnProperty(key)) { - if (v[key] === finalSetAttrs[key]) { - delete finalSetAttrs[key]; - } - } - } - console.log('finalSetAttrs', finalSetAttrs); - setAttrs(finalSetAttrs); - } -} -function fromVOrFinalSetAttrs(v, finalSetAttrs, value) { - if (exists(finalSetAttrs[value])) { - return finalSetAttrs[value]; - } - return v[value]; -} -function parseAttackComponent(v, repeatingString, finalSetAttrs, options) { - var parsed = v[repeatingString + 'parsed']; + let result; + if (match && match[1] && match[2]) { + result = { + rowId: match[1], + field: match[2], + }; + } + return result; +}; +const isEmpty = (obj) => { + for (const prop in obj) { + if (obj.hasOwnProperty(prop)) { + return false; + } + } + return true; +}; +const setFinalAttrs = (v, finalSetAttrs) => { + if (!isEmpty(finalSetAttrs)) { + for (const key in finalSetAttrs) { + if (finalSetAttrs.hasOwnProperty(key)) { + if (v[key] === finalSetAttrs[key]) { + delete finalSetAttrs[key]; + } + } + } + if (!isEmpty(finalSetAttrs)) { + console.log('finalSetAttrs', finalSetAttrs); + } + if (!isEmpty(finalSetAttrs)) { + setAttrs(finalSetAttrs); + } + } +}; +const fromVOrFinalSetAttrs = (v, finalSetAttrs, value) => { + if (exists(finalSetAttrs[value])) { + return finalSetAttrs[value]; + } + return v[value]; +}; +const parseAttackComponent = (v, repeatingString, finalSetAttrs, options) => { + let parsed = v[`${repeatingString}parsed`]; - if (isUndefined(parsed)) { - parsed = finalSetAttrs[repeatingString + 'parsed']; - } + if (isUndefined(parsed)) { + parsed = finalSetAttrs[`${repeatingString}parsed`]; + } - if (isUndefined(parsed) || parsed.indexOf(options.parseName) === -1) { - var aTriggerFieldExists = false; + if (isUndefined(parsed) || parsed.indexOf(options.parseName) === -1) { + let aTriggerFieldExists = false; - for (var i = 0; i < options.triggerFields.length; i++) { - if (exists(v[repeatingString + options.triggerFields[i]])) { - aTriggerFieldExists = true; - } - } + for (let i = 0; i < options.triggerFields.length; i++) { + if (exists(v[repeatingString + options.triggerFields[i]])) { + aTriggerFieldExists = true; + } + } + if (aTriggerFieldExists && isUndefined(v[repeatingString + options.toggleField])) { + finalSetAttrs[repeatingString + options.toggleField] = options.toggleFieldSetTo; - if (aTriggerFieldExists && !exists(v[repeatingString + options.toggleField])) { - finalSetAttrs[repeatingString + options.toggleField] = options.toggleFieldSetTo; + if (isUndefined(finalSetAttrs[`${repeatingString}parsed`])) { + finalSetAttrs[`${repeatingString}parsed`] = ''; + } + finalSetAttrs[`${repeatingString}parsed`] += ` ${options.parseName}`; + } + if (options.attackAbility && isUndefined(v[`${repeatingString}attack_ability`])) { + finalSetAttrs[`${repeatingString}attack_ability`] = v.default_ability; + } - if (isUndefined(finalSetAttrs[repeatingString + 'parsed'])) { - finalSetAttrs[repeatingString + 'parsed'] = ''; - } - finalSetAttrs[repeatingString + 'parsed'] += ' ' + options.parseName; - } - if (options.attackAbility && !exists(v[repeatingString + 'attack_ability']) && v[repeatingString + 'attack_ability'] !== '0') { - finalSetAttrs[repeatingString + 'attack_ability'] = v.default_ability; - } + if (options.addCastingModifier) { + if (exists(v[`${repeatingString}damage`]) && isUndefined(v[`${repeatingString}damage_ability`])) { + finalSetAttrs[`${repeatingString}damage_ability`] = v.default_ability; + } + if (exists(v[`${repeatingString}heal`]) && isUndefined(v[`${repeatingString}heal_ability`])) { + finalSetAttrs[`${repeatingString}heal_ability`] = v.default_ability; + } + } + } +}; +const hasUpperCase = (string) => { + return (/[A-Z]/.test(string)); +}; +const ordinalSpellLevel = (level) => { + let spellLevel = ''; + if (level === 0) { + spellLevel = 'Cantrip'; + } else { + switch (level % 10) { + case 1: + spellLevel = `${level}st-level`; + break; + case 2: + spellLevel = `${level}nd-level`; + break; + case 3: + spellLevel = `${level}rd-level`; + break; + default: + spellLevel = `${level}th-level`; + break; + } + } + return spellLevel; +}; +const versionCompare = (v1, v2, options) => { + const lexicographical = options && options.lexicographical; + const zeroExtend = options && options.zeroExtend; + let v1parts = v1.split('.'); + let v2parts = v2.split('.'); - if (options.addCastingModifier) { - if (exists(v[repeatingString + 'damage']) && !exists(v[repeatingString + 'damage_ability']) && v[repeatingString + 'damage_ability'] !== '0') { - finalSetAttrs[repeatingString + 'damage_ability'] = v.default_ability; - } - if (exists(v[repeatingString + 'heal']) && !exists(v[repeatingString + 'heal_ability']) && v[repeatingString + 'heal_ability'] !== '0') { - finalSetAttrs[repeatingString + 'heal_ability'] = v.default_ability; - } - } - } -} -function hasUpperCase(string) { - return (/[A-Z]/.test(string)); -} -function isUndefined(value) { - if (typeof value === 'undefined' || value === ''){ - return true; - } - return false; -} -function emptyIfUndefined(value) { - if (!value) { - return ''; - } - return value; -} -function ordinalSpellLevel(level) { - if (level === 0) { - return 'Cantrip'; - } else { - switch (level % 10) { - case 1: - return level + 'st-level'; - case 2: - return level + 'nd-level'; - case 3: - return level + 'rd-level'; - default: - return level + 'th-level'; - } - } -} -function versionCompare(v1, v2, options) { - var lexicographical = options && options.lexicographical, - zeroExtend = options && options.zeroExtend, - v1parts = v1.split('.'), - v2parts = v2.split('.'); + const isValidPart = (x) => { + return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x); + }; - function isValidPart(x) { - return (lexicographical ? /^\d+[A-Za-z]*$/ : /^\d+$/).test(x); - } + if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) { + return NaN; + } - if (!v1parts.every(isValidPart) || !v2parts.every(isValidPart)) { - return NaN; - } + if (zeroExtend) { + while (v1parts.length < v2parts.length) { + v1parts.push('0'); + } + while (v2parts.length < v1parts.length) { + v2parts.push('0'); + } + } - if (zeroExtend) { - while (v1parts.length < v2parts.length) v1parts.push('0'); - while (v2parts.length < v1parts.length) v2parts.push('0'); - } + if (!lexicographical) { + v1parts = v1parts.map(Number); + v2parts = v2parts.map(Number); + } - if (!lexicographical) { - v1parts = v1parts.map(Number); - v2parts = v2parts.map(Number); - } + for (let i = 0; i < v1parts.length; ++i) { + if (v2parts.length === i) { + return 1; + } - for (var i = 0; i < v1parts.length; ++i) { - if (v2parts.length == i) { - return 1; - } + if (v1parts[i] === v2parts[i]) { + continue; + } else if (v1parts[i] > v2parts[i]) { + return 1; + } else { + return -1; + } + } - if (v1parts[i] == v2parts[i]) { - continue; - } - else if (v1parts[i] > v2parts[i]) { - return 1; - } - else { - return -1; - } - } + if (v1parts.length !== v2parts.length) { + return -1; + } - if (v1parts.length != v2parts.length) { - return -1; - } - - return 0; -} -function getAbilityMod (score) { + return 0; +}; +const getAbilityMod = (score) => { return Math.floor((getIntValue(score) - 10) / 2); -} -function addOrSubtract (string, number) { - var value = number; - if (string && value) { - if (value >= 0) { - value = ADD + value; - } else { - value = SUBTRACT + Math.abs(value); - } - } - return value; -} -function numberWithCommas(x) { - if (x) { - var parts = x.toString().split('.'); - parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); - return parts.join('.'); - } -} -function lowercaseWords (string) { - if (!string) { - return; - } - return string.toLowerCase(); -} -function findClosest (array, goal) { - return array.reduce(function (prev, curr) { - return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev); - }); -} -function getCorrectAbilityBasedOnBonus (finalSetAttrs, repeatingString, fieldName, bonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod) { - var closest; - if (bonus) { - if (spellAttack) { - closest = findClosest(spellMods, bonus); - bonus -= closest; - if (closest === spellMods[0]) { - finalSetAttrs[repeatingString + fieldName] = '@{intelligence_mod}'; - } else if (closest === spellMods[1]) { - finalSetAttrs[repeatingString + fieldName] = '@{wisdom_mod}'; - } else if (closest === spellMods[2]) { - finalSetAttrs[repeatingString + fieldName] = '@{charisma_mod}'; - } - } else { - if (rangedAttack) { - finalSetAttrs[repeatingString + 'attack_ability'] = '@{dexterity_mod}'; - bonus -= dexMod; - } else { - closest = findClosest(meleeMods, bonus); - bonus -= closest; - if (closest === meleeMods[0]) { - finalSetAttrs[repeatingString + fieldName] = '@{strength_mod}'; - } else if (closest === meleeMods[1]) { - finalSetAttrs[repeatingString + fieldName] = '@{dexterity_mod}'; - } - } - } - } else { - finalSetAttrs[repeatingString + fieldName] = 0; - } - return bonus; -} -function getAnyCorrectAbilityBasedOnBonus (finalSetAttrs, repeatingString, fieldName, bonus, abilityMods) { - var closest = findClosest(abilityMods, bonus); - if (bonus) { - bonus -= closest; +}; +const addOrSubtract = (string, number) => { + let value = number; + if (string && value) { + if (value >= 0) { + value = ` + ${value}`; + } else { + value = ` - ${Math.abs(value)}`; + } + } + return value; +}; +const numberWithCommas = (x) => { + const parts = x.toString().split('.'); + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ','); + return parts.join('.'); +}; +const lowercaseWords = (string) => { + return string.toLowerCase(); +}; +const findClosest = (array, goal) => { + return array.reduce((prev, curr) => { + return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev); + }); +}; +const getCorrectAbilityBasedOnBonus = (finalSetAttrs, repeatingString, fieldName, bonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod) => { + let closest; + if (bonus) { + if (spellAttack) { + closest = findClosest(spellMods, bonus); + bonus -= closest; + if (closest === spellMods[0]) { + finalSetAttrs[repeatingString + fieldName] = '@{intelligence_mod}'; + } else if (closest === spellMods[1]) { + finalSetAttrs[repeatingString + fieldName] = '@{wisdom_mod}'; + } else if (closest === spellMods[2]) { + finalSetAttrs[repeatingString + fieldName] = '@{charisma_mod}'; + } + } else { + if (rangedAttack) { + finalSetAttrs[`${repeatingString}attack_ability`] = '@{dexterity_mod}'; + bonus -= dexMod; + } else { + closest = findClosest(meleeMods, bonus); + bonus -= closest; + if (closest === meleeMods[0]) { + finalSetAttrs[repeatingString + fieldName] = '@{strength_mod}'; + } else if (closest === meleeMods[1]) { + finalSetAttrs[repeatingString + fieldName] = '@{dexterity_mod}'; + } + } + } + } else { + finalSetAttrs[repeatingString + fieldName] = 0; + } + return bonus; +}; +const getAnyCorrectAbilityBasedOnBonus = (finalSetAttrs, repeatingString, fieldName, bonus, abilityMods) => { + const closest = findClosest(abilityMods, bonus); + if (bonus) { + bonus -= closest; - if (closest === abilityMods[0]) { - finalSetAttrs[repeatingString + fieldName] = '@{strength_mod}'; - } else if (closest === abilityMods[1]) { - finalSetAttrs[repeatingString + fieldName] = '@{dexterity_mod}'; - } else if (closest === abilityMods[2]) { - finalSetAttrs[repeatingString + fieldName] = '@{constitution_mod}'; - } else if (closest === abilityMods[3]) { - finalSetAttrs[repeatingString + fieldName] = '@{intelligence_mod}'; - } else if (closest === abilityMods[4]) { - finalSetAttrs[repeatingString + fieldName] = '@{wisdom_mod}'; - } else if (closest === abilityMods[5]) { - finalSetAttrs[repeatingString + fieldName] = '@{charisma_mod}'; - } - } else { - finalSetAttrs[repeatingString + fieldName] = 0; - } - return bonus; -} + if (closest === abilityMods[0]) { + finalSetAttrs[repeatingString + fieldName] = '@{strength_mod}'; + } else if (closest === abilityMods[1]) { + finalSetAttrs[repeatingString + fieldName] = '@{dexterity_mod}'; + } else if (closest === abilityMods[2]) { + finalSetAttrs[repeatingString + fieldName] = '@{constitution_mod}'; + } else if (closest === abilityMods[3]) { + finalSetAttrs[repeatingString + fieldName] = '@{intelligence_mod}'; + } else if (closest === abilityMods[4]) { + finalSetAttrs[repeatingString + fieldName] = '@{wisdom_mod}'; + } else if (closest === abilityMods[5]) { + finalSetAttrs[repeatingString + fieldName] = '@{charisma_mod}'; + } + } else { + finalSetAttrs[repeatingString + fieldName] = 0; + } + return bonus; +}; -function lowercaseDamageTypes (string) { - if (!string) { - return; - } - return string - .replace('Acid', 'acid') - .replace('Cold', 'cold') - .replace('Fire', 'fire') - .replace('Force', 'force') - .replace('Lightning', 'lightning') - .replace('Necrotic', 'necrotic') - .replace('Poison', 'poison') - .replace('Psychic', 'psychic') - .replace('Radiant', 'radiant') - .replace('Thunder', 'thunder') - .replace('Bludgeoning', 'bludgeoning') - .replace('Piercing', 'piercing') - .replace('Slashing', 'slashing') - .replace('And', 'and') - .replace('From', 'from') - .replace('Nonmagical', 'nonmagical') - .replace('Weapons', 'weapons') - .replace('That', 'that') - .replace('Aren\'t', 'aren\'t') - .replace('Silvered', 'silvered') - .replace('Adamantine', 'adamantine'); -} +const lowercaseDamageTypes = (string) => { + if (!string) { + string = ''; + } + return string + .replace('Acid', 'acid') + .replace('Cold', 'cold') + .replace('Fire', 'fire') + .replace('Force', 'force') + .replace('Lightning', 'lightning') + .replace('Necrotic', 'necrotic') + .replace('Poison', 'poison') + .replace('Psychic', 'psychic') + .replace('Radiant', 'radiant') + .replace('Thunder', 'thunder') + .replace('Bludgeoning', 'bludgeoning') + .replace('Piercing', 'piercing') + .replace('Slashing', 'slashing') + .replace('And', 'and') + .replace('From', 'from') + .replace('Nonmagical', 'nonmagical') + .replace('Weapons', 'weapons') + .replace('That', 'that') + .replace('Aren\'t', 'aren\'t') + .replace('Silvered', 'silvered') + .replace('Adamantine', 'adamantine'); +}; -var ABILITIES = ['strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma']; -var ADD = ' + '; -var SUBTRACT = ' - '; -var SPACE = ' '; - -on('change:cp change:sp change:ep change:gp change:pp', function () { - getAttrs(['cp', 'copper_per_gold', 'sp', 'silver_per_gold', 'ep', 'electrum_per_gold', 'gp', 'pp', 'platinum_per_gold'], function (v) { - var copperPieces = getFloatValue(v.cp); - var silverPieces = getFloatValue(v.sp); - var electrumPieces = getFloatValue(v.ep); - var goldPieces = getFloatValue(v.gp); - var platinumPieces = getFloatValue(v.pp); - var copperPerGold = getFloatValue(v.copper_per_gold, 100); - var silverPerGold = getFloatValue(v.silver_per_gold, 10); - var electrumPerGold = getFloatValue(v.electrum_per_gold, 2); - var platinumPerGold = getFloatValue(v.platinum_per_gold, 10); - var totalGold = (copperPieces / copperPerGold) + (silverPieces / silverPerGold) + (electrumPieces / electrumPerGold) + goldPieces + (platinumPieces * platinumPerGold); - var coinWeight = (copperPieces + silverPieces + electrumPieces + goldPieces + platinumPieces) / 50; - setAttrs({ - total_gp: totalGold.toFixed(2), - weight_coinage: coinWeight - }); - }); +on('change:cp change:sp change:ep change:gp change:pp', () => { + getAttrs(['cp', 'copper_per_gold', 'sp', 'silver_per_gold', 'ep', 'electrum_per_gold', 'gp', 'pp', 'platinum_per_gold'], (v) => { + const copperPieces = getFloatValue(v.cp); + const silverPieces = getFloatValue(v.sp); + const electrumPieces = getFloatValue(v.ep); + const goldPieces = getFloatValue(v.gp); + const platinumPieces = getFloatValue(v.pp); + const copperPerGold = getFloatValue(v.copper_per_gold, 100); + const silverPerGold = getFloatValue(v.silver_per_gold, 10); + const electrumPerGold = getFloatValue(v.electrum_per_gold, 2); + const platinumPerGold = getFloatValue(v.platinum_per_gold, 10); + const totalGold = (copperPieces / copperPerGold) + (silverPieces / silverPerGold) + (electrumPieces / electrumPerGold) + goldPieces + (platinumPieces * platinumPerGold); + const coinWeight = (copperPieces + silverPieces + electrumPieces + goldPieces + platinumPieces) / 50; + setAttrs({ + total_gp: totalGold.toFixed(2), + weight_coinage: coinWeight, + }); + }); }); -function updateAbilityModifiers () { - updateAbilityModifier('strength'); - updateAbilityModifier('dexterity'); - updateAbilityModifier('constitution'); - updateAbilityModifier('intelligence'); - updateAbilityModifier('wisdom'); - updateAbilityModifier('charisma'); -} -function updateAbilityModifier (ability) { - var collectionArray = [ability, ability + '_bonus', ability + '_mod', ability + '_check_mod', 'global_ability_bonus', 'strength_mod', 'dexterity_mod', 'jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete']; - var finalSetAttrs = {}; +const updateAbilityModifier = (ability) => { + const collectionArray = [ability, `${ability}_bonus`, `${ability}_mod`, `${ability}_mod_with_sign`, `${ability}_check_mod`, `${ability}_check_mod_formula`, `${ability}_check_bonus`, 'global_ability_bonus', 'strength_mod', 'dexterity_mod', 'jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'global_check_bonus']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - var abilityScore = getIntValue(v[ability]); - var abilityBonus = getIntValue(v[ability + '_bonus']); - var globalAbilityBonus = getIntValue(v.global_ability_bonus); - var abilityMod = getAbilityMod((abilityScore + abilityBonus + globalAbilityBonus)); + if (ability === 'strength' || ability === 'dexterity') { + collectionArray.push('finesse_mod'); + } + if (ability === 'strength') { + collectionArray.push('carrying_capacity'); + collectionArray.push('max_push_drag_lift'); + collectionArray.push('encumbered'); + collectionArray.push('heavily_encumbered'); + } - var abilityCheckFormula = abilityMod + '[' + ability.firstThree() + ' mod with bonus]'; - if ((ability === 'strength' || ability === 'dexterity' || ability === 'constitution') && v.remarkable_athlete_toggle === '@{remarkable_athlete}') { - var remarkableAthlete = getIntValue(v.remarkable_athlete); - abilityCheckFormula += ADD + remarkableAthlete + '[remarkable athlete]'; - } else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') { - var jackOfAllTrades = getIntValue(v.jack_of_all_trades); - abilityCheckFormula += ADD + jackOfAllTrades + '[jack of all trades]'; - } - abilityCheckFormula += ADD + '(@{global_check_bonus})[global check bonus]'; + getAttrs(collectionArray, (v) => { + const abilityScore = getIntValue(v[ability]); + const abilityBonus = getIntValue(v[`${ability}_bonus`]); + const abilityCheckBonus = getIntValue(v[`${ability}_check_bonus`]); + const globalAbilityBonus = getIntValue(v.global_ability_bonus); + const abilityMod = getAbilityMod((abilityScore + abilityBonus + globalAbilityBonus)); - var abilityModWithSign = abilityMod; - if (abilityMod >= 0) { - abilityModWithSign = '+' + abilityMod; - } + let abilityCheck = abilityMod; + let abilityCheckFormula = `${abilityMod}[${firstThree(ability)} mod with bonus]`; + if ((ability === 'strength' || ability === 'dexterity' || ability === 'constitution') && v.remarkable_athlete_toggle === '@{remarkable_athlete}') { + const remarkableAthlete = getIntValue(v.remarkable_athlete); + abilityCheck += remarkableAthlete; + abilityCheckFormula += ` + ${remarkableAthlete}[remarkable athlete]`; + } else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') { + const jackOfAllTrades = getIntValue(v.jack_of_all_trades); + abilityCheck += jackOfAllTrades; + abilityCheckFormula += ` + ${jackOfAllTrades}[jack of all trades]`; + } + if (abilityCheckBonus) { + abilityCheck += abilityCheckBonus; + abilityCheckFormula += ` + ${abilityCheckBonus}[${ability} check bonus]`; + } + if (!isNaN(v.global_check_bonus)) { + abilityCheck += getIntValue(v.global_check_bonus); + } + abilityCheckFormula += ' + (@{global_check_bonus})[global check bonus]'; - finalSetAttrs[ability + '_mod'] = abilityMod; - finalSetAttrs[ability + '_mod_with_sign'] = abilityModWithSign; - finalSetAttrs[ability + '_check_mod'] = abilityCheckFormula; + let abilityModWithSign = abilityMod; + if (abilityMod >= 0) { + abilityModWithSign = `+${abilityMod}`; + } - if (ability === 'strength') { - finalSetAttrs.finesse_mod = Math.max(abilityMod, getIntValue(v.dexterity_mod)); - finalSetAttrs.carrying_capacity = abilityScore * 15; - finalSetAttrs.max_push_drag_lift = abilityScore * 30; - finalSetAttrs.encumbered = abilityScore * 5; - finalSetAttrs.heavily_encumbered = abilityScore * 10; - } else if (ability === 'dexterity') { - finalSetAttrs.finesse_mod = Math.max(abilityMod, getIntValue(v.strength_mod)); - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:strength change:strength_bonus change:strength_check_mod change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_ability_bonus', function () { - updateAbilityModifier('strength'); + finalSetAttrs[`${ability}_mod`] = abilityMod; + finalSetAttrs[`${ability}_mod_with_sign`] = abilityModWithSign; + finalSetAttrs[`${ability}_check_mod`] = abilityCheck; + finalSetAttrs[`${ability}_check_mod_formula`] = abilityCheckFormula; + + if (ability === 'strength') { + finalSetAttrs.finesse_mod = Math.max(abilityMod, getIntValue(v.dexterity_mod)); + finalSetAttrs.carrying_capacity = abilityScore * 15; + finalSetAttrs.max_push_drag_lift = abilityScore * 30; + finalSetAttrs.encumbered = abilityScore * 5; + finalSetAttrs.heavily_encumbered = abilityScore * 10; + } else if (ability === 'dexterity') { + finalSetAttrs.finesse_mod = Math.max(abilityMod, getIntValue(v.strength_mod)); + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +const updateAbilityModifiers = () => { + updateAbilityModifier('strength'); + updateAbilityModifier('dexterity'); + updateAbilityModifier('constitution'); + updateAbilityModifier('intelligence'); + updateAbilityModifier('wisdom'); + updateAbilityModifier('charisma'); +}; +on('change:strength change:strength_bonus change:strength_check_mod change:strength_check_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_ability_bonus', () => { + updateAbilityModifier('strength'); }); -on('change:dexterity change:dexterity_bonus change:dexterity_check_mod change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_ability_bonus', function () { - updateAbilityModifier('dexterity'); +on('change:dexterity change:dexterity_bonus change:dexterity_check_mod change:dexterity_check_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_ability_bonus', () => { + updateAbilityModifier('dexterity'); }); -on('change:constitution change:constitution_bonus change:constitution_check_mod change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_ability_bonus', function () { - updateAbilityModifier('constitution'); +on('change:constitution change:constitution_bonus change:constitution_check_mod change:constitution_check_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_ability_bonus', () => { + updateAbilityModifier('constitution'); }); -on('change:intelligence change:intelligence_bonus change:intelligence_check_mod change:jack_of_all_trades_toggle change:jack_of_all_trades change:global_ability_bonus', function () { - updateAbilityModifier('intelligence'); +on('change:intelligence change:intelligence_bonus change:intelligence_check_mod change:intelligence_check_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:global_ability_bonus', () => { + updateAbilityModifier('intelligence'); }); -on('change:wisdom change:wisdom_bonus change:wisdom_check_mod change:jack_of_all_trades_toggle change:jack_of_all_trades change:global_ability_bonus', function () { - updateAbilityModifier('wisdom'); +on('change:wisdom change:wisdom_bonus change:wisdom_check_mod change:wisdom_check_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:global_ability_bonus', () => { + updateAbilityModifier('wisdom'); }); -on('change:charisma change:charisma_bonus change:charisma_check_mod change:jack_of_all_trades_toggle change:jack_of_all_trades change:global_ability_bonus', function () { - updateAbilityModifier('charisma'); -}); -on('change:dexterity_mod', function () { - updateArmor(); +on('change:charisma change:charisma_bonus change:charisma_check_mod change:charisma_check_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:global_ability_bonus', () => { + updateAbilityModifier('charisma'); }); -function updateLevels () { - var repeatingItem = 'repeating_class'; - var collectionArray = ['barbarian_level', 'bard_level', 'cleric_level', 'druid_level', 'fighter_level', 'monk_level', 'paladin_level', 'ranger_level', 'rogue_level', 'sorcerer_level', 'warlock_level', 'wizard_level']; - var finalSetAttrs = {}; +const setClassFeatureOrTrait = (repeatingItem, obj) => { + const collectionArray = []; + const finalSetAttrs = {}; + let itemId; - var defaultClassDetails = { - barbarian: { - hd: 'd12' - }, - bard: { - hd: 'd8', - spellcasting: 'full' - }, - cleric: { - hd: 'd8', - spellcasting: 'full' - }, - druid: { - hd: 'd8', - spellcasting: 'full' - }, - fighter: { - hd: 'd10' - }, - monk: { - hd: 'd8' - }, - paladin: { - hd: 'd10', - spellcasting: 'half' - }, - ranger: { - hd: 'd10', - spellcasting: 'half' - }, - rogue: { - hd: 'd8' - }, - sorcerer: { - hd: 'd6', - spellcasting: 'full' - }, - warlock: { - hd: 'd8', - spellcasting: 'warlock' - }, - wizard: { - hd: 'd6', - spellcasting: 'full' - } - }; + if (!obj.name) { + obj.name = obj.storageName; + } - var hd = { - d20: 0, - d12: 0, - d10: 0, - d8: 0, - d6: 0, - d4: 0, - d2: 0, - d0: 0 - }; + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}storage_name`); + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}uses`); + collectionArray.push(`${repeatingString}freetext`); + collectionArray.push(`${repeatingString}saving_throw_toggle`); + collectionArray.push(`${repeatingString}damage_toggle`); + collectionArray.push(`${repeatingString}heal_toggle`); + collectionArray.push(`${repeatingString}extras_toggle`); + if (repeatingItem === 'repeating_trait') { + collectionArray.push(`${repeatingString}display_text`); + } + for (const prop in obj) { + if (obj.hasOwnProperty(prop)) { + collectionArray.push(`${repeatingString}${prop}`); + } + } + } - var spellcasting = { - full: 0, - half: 0, - third: 0, - warlock: 0 - }; - var totalLevel = 0; - var levelArray = []; - var sorcererLevels = 0; - var classesWithSpellcasting = 0; - var xpTable = [0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000, 85000, 100000, 120000, 140000, 165000, 195000, 225000, 265000, 305000, 355000, 385000, 405000, 435000, 465000, 495000, 525000, 555000, 585000, 605000, 635000, 665000]; + getAttrs(collectionArray, (v) => { + let repeatingString; + for (let j = 0; j < ids.length; j++) { + repeatingString = `${repeatingItem}_${ids[j]}_`; - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'level'); - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'custom_name'); - collectionArray.push(repeatingString + 'hd'); - collectionArray.push(repeatingString + 'spellcasting'); - } + if (v[`${repeatingString}storage_name`] === obj.storageName) { + itemId = ids[j]; + } + } + if (!itemId) { + itemId = generateRowID(); + } - getAttrs(collectionArray, function (v) { - finalSetAttrs.barbarian_level = 0; - finalSetAttrs.bard_level = 0; - finalSetAttrs.cleric_level = 0; - finalSetAttrs.druid_level = 0; - finalSetAttrs.fighter_level = 0; - finalSetAttrs.monk_level = 0; - finalSetAttrs.paladin_level = 0; - finalSetAttrs.ranger_level = 0; - finalSetAttrs.rogue_level = 0; - finalSetAttrs.sorcerer_level = 0; - finalSetAttrs.warlock_level = 0; - finalSetAttrs.wizard_level = 0; + repeatingString = `${repeatingItem}_${itemId}_`; + if (!obj.clear && isUndefined(v[`${repeatingString}storage_name`])) { + finalSetAttrs[`${repeatingString}storage_name`] = obj.storageName; + } + if (!obj.clear && v[`${repeatingString}name`] !== obj.name) { + finalSetAttrs[`${repeatingString}name`] = obj.name; + } + delete obj.storageName; - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; + if (obj.clear) { + delete obj.clear; + for (const prop in obj) { + if (obj.hasOwnProperty(prop) && !isUndefined(v[`${repeatingString}${prop}`])) { + finalSetAttrs[`${repeatingString}${prop}`] = obj[prop]; + } + } + } else { + for (const prop in obj) { + if (obj.hasOwnProperty(prop) && v[`${repeatingString}${prop}`] !== obj[prop]) { + finalSetAttrs[`${repeatingString}${prop}`] = obj[prop]; + } + } + if (obj.saving_throw_ability || obj.saving_throw_bonus || obj.saving_throw_vs_ability) { + finalSetAttrs[`${repeatingString}saving_throw_toggle`] = '@{saving_throw_toggle_var}'; + } + if (obj.damage || obj.damage_ability || obj.damage_bonus) { + finalSetAttrs[`${repeatingString}damage_toggle`] = '@{damage_toggle_var}'; + } + if (obj.heal || obj.heal_ability || obj.heal_bonus || obj.heal_query_toggle) { + finalSetAttrs[`${repeatingString}heal_toggle`] = '@{heal_toggle_var}'; + } + if (obj.freetext && isUndefined(v[`${repeatingString}extras_toggle`])) { + finalSetAttrs[`${repeatingString}extras_toggle`] = '@{extras_var}'; + } + if (obj.uses_max && !obj.uses && isUndefined(v[`${repeatingString}uses`])) { + finalSetAttrs[`${repeatingString}uses`] = obj.uses_max; + } + if (obj.freetext && repeatingItem === 'repeating_trait' && (isUndefined(v[`${repeatingString}display_text`]) || + calculatePercentDifference(v[`${repeatingString}display_text`].length, obj.freetext.length) < 10)) { + finalSetAttrs[`${repeatingString}display_text`] = obj.freetext; + } + } - var className = v[repeatingString + 'name']; - if (isUndefined(className)) { - className = 'barbarian'; - } - if (className === 'custom') { - finalSetAttrs[repeatingString + 'custom_class_toggle'] = 'on'; - var customName = v[repeatingString + 'custom_name']; - if (exists(customName)) { - className = customName; - } else { - className = 'custom'; - } - } else { - finalSetAttrs[repeatingString + 'custom_class_toggle'] = 0; - } + setFinalAttrs(v, finalSetAttrs); + return itemId; + }); + }); +}; +const setClassFeature = (obj) => { + return setClassFeatureOrTrait('repeating_classfeature', obj); +}; +const setTrait = (obj) => { + return setClassFeatureOrTrait('repeating_trait', obj); +}; - var classLevel = getIntValue(v[repeatingString + 'level']); - totalLevel += classLevel; - levelArray.push(className.capitalize() + ' ' + classLevel); +const updateLevels = (changedField) => { + const repeatingItem = 'repeating_class'; + const collectionArray = ['is_npc', 'lang', 'caster_level', 'caster_type', 'class_and_level', 'level', 'xp_next_level']; + const finalSetAttrs = {}; - if (v[className + '_level']) { - finalSetAttrs[className + '_level'] += classLevel; - } else { - finalSetAttrs[className + '_level'] = classLevel; + for (let i = 0; i < CLASSES.length; i++) { + collectionArray.push(`${CLASSES[i]}_level`); + collectionArray.push(`has_${CLASSES[i]}_levels`); + } + + const defaultClassDetails = { + barbarian: { + hd: 'd12', + }, + bard: { + hd: 'd8', + spellcasting: 'full', + }, + cleric: { + hd: 'd8', + spellcasting: 'full', + }, + druid: { + hd: 'd8', + spellcasting: 'full', + }, + fighter: { + hd: 'd10', + }, + monk: { + hd: 'd8', + }, + paladin: { + hd: 'd10', + spellcasting: 'half', + }, + ranger: { + hd: 'd10', + spellcasting: 'half', + }, + rogue: { + hd: 'd8', + }, + sorcerer: { + hd: 'd6', + spellcasting: 'full', + }, + warlock: { + hd: 'd8', + spellcasting: 'warlock', + }, + wizard: { + hd: 'd6', + spellcasting: 'full', + }, + }; + const hd = { + d20: 0, + d12: 0, + d10: 0, + d8: 0, + d6: 0, + d4: 0, + d2: 0, + d0: 0, + }; + const spellcasting = { + full: 0, + half: 0, + third: 0, + warlock: 0, + }; + let totalLevel = 0; + const classLevels = {}; + let classesWithSpellcasting = 0; + const xpTable = [0, 300, 900, 2700, 6500, 14000, 23000, 34000, 48000, 64000, 85000, 100000, 120000, 140000, 165000, 195000, 225000, 265000, 305000, 355000, 385000, 405000, 435000, 465000, 495000, 525000, 555000, 585000, 605000, 635000, 665000]; + + for (const key in hd) { + if (hd.hasOwnProperty(key)) { + collectionArray.push(`hd_${key}_max`); + collectionArray.push(`hd_${key}_query`); + collectionArray.push(`hd_${key}_toggle`); + } + } + + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}level`); + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}custom_name`); + collectionArray.push(`${repeatingString}hd`); + collectionArray.push(`${repeatingString}spellcasting`); + collectionArray.push(`${repeatingString}custom_class_toggle`); + } + + getAttrs(collectionArray, (v) => { + for (let i = 0; i < CLASSES.length; i++) { + finalSetAttrs[`${CLASSES[i]}_level`] = 0; + } + + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + + let className = v[`${repeatingString}name`]; + const classLevel = getIntValue(v[`${repeatingString}level`]); + + if (isUndefined(v[`${repeatingString}name`]) && isUndefined(v[`${repeatingString}level`])) { + continue; } - var classHd = v[repeatingString + 'hd']; - if (isUndefined(classHd)) { - if (defaultClassDetails.hasOwnProperty(className)) { - classHd = defaultClassDetails[className].hd; - finalSetAttrs[repeatingString + 'hd'] = classHd; - } else { - classHd = 'd12'; - } - } - hd[classHd] += classLevel; + if (isUndefined(className)) { + className = 'barbarian'; + } + if (className === 'custom') { + finalSetAttrs[`${repeatingString}custom_class_toggle`] = 'on'; + const customName = v[`${repeatingString}custom_name`]; + if (exists(customName)) { + className = customName; + } else { + className = 'custom'; + } + } else if (v[`${repeatingString}custom_class_toggle`]) { + finalSetAttrs[`${repeatingString}custom_class_toggle`] = 0; + } - var classSpellcasting = v[repeatingString + 'spellcasting']; - if (isUndefined(classSpellcasting)) { - if (defaultClassDetails.hasOwnProperty(className)) { - classSpellcasting = defaultClassDetails[className].spellcasting; - finalSetAttrs[repeatingString + 'spellcasting'] = classSpellcasting; - } - } - if (exists(classSpellcasting)) { - classesWithSpellcasting += 1; - spellcasting[classSpellcasting] += classLevel; - } + if (classLevel) { + totalLevel += classLevel; + if (classLevels[capitalize(className)]) { + classLevels[capitalize(className)] += classLevel; + } else { + classLevels[capitalize(className)] = classLevel; + } + } else if (isUndefined(finalSetAttrs[`${className}_level`])) { + finalSetAttrs[`${className}_level`] = classLevel; + } - if (className === 'sorcerer' || className === 'sorcerer') { - sorcererLevels += classLevel; - } - } + let classHd = v[`${repeatingString}hd`]; + if (isUndefined(classHd) || changedField === 'name') { + if (defaultClassDetails.hasOwnProperty(className)) { + classHd = defaultClassDetails[className].hd; + } else { + classHd = 'd12'; + } + finalSetAttrs[`${repeatingString}hd`] = classHd; + } + if (classHd && classLevel) { + hd[classHd] += classLevel; + } - for (var key in hd) { - if (hd.hasOwnProperty(key)) { - if (hd[key] !== 0) { - finalSetAttrs['hd_' + key + '_max'] = hd[key]; - finalSetAttrs['hd_' + key + '_toggle'] = 1; - } else { - finalSetAttrs['hd_' + key + '_max'] = 0; - finalSetAttrs['hd_' + key + '_toggle'] = 0; - } - } - } + let classSpellcasting = v[`${repeatingString}spellcasting`]; + if (isUndefined(classSpellcasting) || changedField === 'name') { + if (defaultClassDetails.hasOwnProperty(className)) { + classSpellcasting = defaultClassDetails[className].spellcasting; + finalSetAttrs[`${repeatingString}spellcasting`] = classSpellcasting; + } + } else { + classesWithSpellcasting += 1; + spellcasting[classSpellcasting] += classLevel; + } + } - var casterLevel = 0; - casterLevel += spellcasting.full; - casterLevel += Math.floor(spellcasting.half / 2); - casterLevel += Math.floor(spellcasting.third / 3); - finalSetAttrs.caster_level = casterLevel; + finalSetAttrs.class_and_level = ''; + for (const className in classLevels) { + if (classLevels.hasOwnProperty(className)) { + finalSetAttrs[`${className}_level`] = classLevels[className]; + if (finalSetAttrs.class_and_level !== '') { + finalSetAttrs.class_and_level += ', '; + } + finalSetAttrs.class_and_level += `${className} ${classLevels[className]}`; + } + } - if (classesWithSpellcasting > 1 || spellcasting.full) { - finalSetAttrs.caster_type = 'full'; - } else if (spellcasting.half) { - finalSetAttrs.caster_type = 'half'; - } else if (spellcasting.third) { - finalSetAttrs.caster_type = 'third'; - } else { - finalSetAttrs.caster_type = 'full'; - } + finalSetAttrs.level = totalLevel; - finalSetAttrs.level = totalLevel; - finalSetAttrs.class_and_level = levelArray.join(' '); + let xpForNextLevel = 0; + if (!totalLevel) { + totalLevel = 0; + } + if (totalLevel > 30) { + xpForNextLevel = xpTable[30]; + } else { + xpForNextLevel = xpTable[totalLevel]; + } + finalSetAttrs.xp_next_level = xpForNextLevel; - var xpForNextLevel = 0; - if (!totalLevel) { - totalLevel = 0; - } - if (totalLevel > 30) { - xpForNextLevel = xpTable[30]; - } else { - xpForNextLevel = xpTable[totalLevel]; - } - finalSetAttrs.xp_next_level = xpForNextLevel; + for (let y = 0; y < CLASSES.length; y++) { + if (finalSetAttrs[`${CLASSES[y]}_level`] > 0) { + finalSetAttrs[`has_${CLASSES[y]}_levels`] = 1; + } else if (!isUndefined(v[`has_${CLASSES[y]}_levels`])) { + finalSetAttrs[`has_${CLASSES[y]}_levels`] = 0; + } + } - if (sorcererLevels > 0) { - finalSetAttrs.has_sorcerer_levels = 'on'; - if (sorcererLevels === 1) { - finalSetAttrs.sorcery_points_max = 0; - } else { - finalSetAttrs.sorcery_points_max = sorcererLevels; - } - } else { - finalSetAttrs.has_sorcerer_levels = 0; - } - if (spellcasting.warlock > 0) { - finalSetAttrs.has_warlock_levels = 'on'; + for (const key in hd) { + if (hd.hasOwnProperty(key)) { + if (hd[key] && hd[key] !== 0) { + finalSetAttrs[`hd_${key}_max`] = hd[key]; + finalSetAttrs[`hd_${key}_query`] = '?{HD'; + for (let x = 1; x <= hd[key]; x++) { + finalSetAttrs[`hd_${key}_query`] += `|${x}`; + } + finalSetAttrs[`hd_${key}_query`] += '}'; + finalSetAttrs[`hd_${key}_toggle`] = 1; + } else { + if (!isUndefined(v[`hd_${key}_max`])) { + finalSetAttrs[`hd_${key}_max`] = 0; + } + if (!isUndefined(v[`hd_${key}_query`])) { + finalSetAttrs[`hd_${key}_query`] = ''; + } + if (!isUndefined(v[`hd_${key}_toggle`])) { + finalSetAttrs[`hd_${key}_toggle`] = 0; + } + } + } + } - if (spellcasting.warlock === 1) { - finalSetAttrs.warlock_spell_slots_max = 1; - } else if (spellcasting.warlock >= 2 && spellcasting.warlock < 11) { - finalSetAttrs.warlock_spell_slots_max = 2; - } else if (spellcasting.warlock >= 11 && spellcasting.warlock < 17) { - finalSetAttrs.warlock_spell_slots_max = 3; - } else { - finalSetAttrs.warlock_spell_slots_max = 4; - } - } else { - finalSetAttrs.has_warlock_levels = 0; - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} + let casterLevel = 0; + if (!v.is_npc || v.is_npc === '0' || v.is_npc === 0) { + casterLevel += spellcasting.full; + casterLevel += Math.floor(spellcasting.half / 2); + casterLevel += Math.floor(spellcasting.third / 3); + finalSetAttrs.caster_level = casterLevel; + } -on('change:repeating_class remove:repeating_class', function () { - updateLevels(); - updateSpellSlots(); + if (classesWithSpellcasting > 1 || spellcasting.full) { + finalSetAttrs.caster_type = 'full'; + } else if (spellcasting.half) { + finalSetAttrs.caster_type = 'half'; + } else if (spellcasting.third) { + finalSetAttrs.caster_type = 'third'; + } else { + finalSetAttrs.caster_type = 'full'; + } + + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; + +const updateSpellSlots = () => { + const collectionArray = ['level', 'caster_level', 'caster_type']; + const finalSetAttrs = {}; + + const spellSlots = { + 1: 0, + 2: 0, + 3: 0, + 4: 0, + 5: 0, + 6: 0, + 7: 0, + 8: 0, + 9: 0, + }; + + for (let i = 1; i <= 9; i++) { + const repeatingString = `spell_slots_l${i}_`; + collectionArray.push(`${repeatingString}calc`); + collectionArray.push(`${repeatingString}bonus`); + collectionArray.push(`${repeatingString}max`); + collectionArray.push(`${repeatingString}toggle`); + } + getAttrs(collectionArray, (v) => { + let casterLevel = getIntValue(v.level); + let casterType = v.caster_type; + if (isUndefined(casterType)) { + casterType = 'full'; + } + + if (casterType === 'full') { + casterLevel = getIntValue(v.caster_level); + + if (casterLevel >= 3) { + spellSlots[1] = 4; + } else if (casterLevel === 2) { + spellSlots[1] = 3; + } else if (casterLevel === 1) { + spellSlots[1] = 2; + } + if (casterLevel >= 4) { + spellSlots[2] = 3; + } else if (casterLevel === 3) { + spellSlots[2] = 2; + } + if (casterLevel >= 6) { + spellSlots[3] = 3; + } else if (casterLevel === 5) { + spellSlots[3] = 2; + } + if (casterLevel >= 9) { + spellSlots[4] = 3; + } else if (casterLevel === 8) { + spellSlots[4] = 2; + } else if (casterLevel === 7) { + spellSlots[4] = 1; + } + if (casterLevel >= 18) { + spellSlots[5] = 3; + } else if (casterLevel >= 10) { + spellSlots[5] = 2; + } else if (casterLevel === 9) { + spellSlots[5] = 1; + } + if (casterLevel >= 19) { + spellSlots[6] = 2; + } else if (casterLevel >= 11) { + spellSlots[6] = 1; + } + if (casterLevel >= 20) { + spellSlots[7] = 2; + } else if (casterLevel >= 13) { + spellSlots[7] = 1; + } + if (casterLevel >= 15) { + spellSlots[8] = 1; + } + if (casterLevel >= 17) { + spellSlots[9] = 1; + } + } + + if (casterType === 'half') { + if (casterLevel >= 5) { + spellSlots[1] = 4; + } else if (casterLevel >= 3) { + spellSlots[1] = 3; + } else if (casterLevel === 2) { + spellSlots[1] = 2; + } + if (casterLevel >= 7) { + spellSlots[2] = 3; + } else if (casterLevel >= 5) { + spellSlots[2] = 2; + } + if (casterLevel >= 11) { + spellSlots[3] = 3; + } else if (casterLevel >= 9) { + spellSlots[3] = 2; + } + if (casterLevel >= 17) { + spellSlots[4] = 3; + } else if (casterLevel >= 15) { + spellSlots[4] = 2; + } else if (casterLevel >= 13) { + spellSlots[4] = 1; + } + if (casterLevel >= 19) { + spellSlots[5] = 2; + } else if (casterLevel >= 17) { + spellSlots[5] = 1; + } + } + + if (casterType === 'third') { + if (casterLevel >= 7) { + spellSlots[1] = 4; + } else if (casterLevel >= 4) { + spellSlots[1] = 3; + } else if (casterLevel === 3) { + spellSlots[1] = 2; + } + if (casterLevel >= 10) { + spellSlots[2] = 3; + } else if (casterLevel >= 7) { + spellSlots[2] = 2; + } + if (casterLevel >= 16) { + spellSlots[3] = 3; + } else if (casterLevel >= 13) { + spellSlots[3] = 2; + } + if (casterLevel >= 19) { + spellSlots[4] = 1; + } + } + + for (let i = 1; i <= 9; i++) { + const slotCalc = spellSlots[i]; + finalSetAttrs[`spell_slots_l${i}_calc`] = slotCalc; + + const slotBonus = getIntValue(v[`spell_slots_l${i}_bonus`]); + const spellSlotMax = slotCalc + slotBonus; + if (v[`spell_slots_l${i}_max`] !== spellSlotMax) { + finalSetAttrs[`spell_slots_l${i}_max`] = spellSlotMax; + } + + let spellSlotToggle; + if (spellSlotMax > 0) { + spellSlotToggle = 'on'; + } else { + spellSlotToggle = 0; + } + if (v[`spell_slots_l${i}_toggle`] !== spellSlotToggle) { + finalSetAttrs[`spell_slots_l${i}_toggle`] = spellSlotToggle; + } + } + setFinalAttrs(v, finalSetAttrs); + }); +}; + +const setClassFeatures = () => { + const finalSetAttrs = {}; + const collectionArray = ['ac_unarmored_ability', 'lang', 'jack_of_all_trades_toggle', 'careful_spell_toggle', 'distant_spell_toggle', 'empowered_spell_toggle', 'extended_spell_toggle', 'heightened_spell_toggle', 'quickened_spell_toggle', 'subtle_spell_toggle', 'twinned_spell_toggle']; + + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`${ABILITIES[i]}_mod`); + } + for (let j = 0; j < CLASSES.length; j++) { + collectionArray.push(`${CLASSES[j]}_level`); + } + + getAttrs(collectionArray, (v) => { + const language = v.lang || 'en'; + + if (v.fighter_level >= 5) { + let extraAttackTimes; + if (v.fighter_level >= 20) { + extraAttackTimes = translate(language, 'CLASS_FEATURES.EXTRA_ATTACK_FOUR'); + } else if (v.fighter_level >= 11) { + extraAttackTimes = translate(language, 'CLASS_FEATURES.EXTRA_ATTACK_THREE'); + } else { + extraAttackTimes = translate(language, 'CLASS_FEATURES.EXTRA_ATTACK_TWICE'); + } + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.EXTRA_ATTACK_TEXT').replace('NUMBER_OF_TIMES', extraAttackTimes), + name: translate(language, 'CLASS_FEATURES.EXTRA_ATTACK'), + storageName: 'Extra Attack', + }); + } else if (v.barbarian_level >= 5 || v.monk_level >= 5 || v.paladin_level >= 5 || v.ranger_level >= 5) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.EXTRA_ATTACK_TEXT').replace('NUMBER_OF_TIMES', translate(language, 'CLASS_FEATURES.EXTRA_ATTACK_TWICE')), + name: translate(language, 'CLASS_FEATURES.EXTRA_ATTACK'), + storageName: 'Extra Attack', + }); + } + + if (v.barbarian_level) { + let rageUses; + if (v.barbarian_level >= 20) { + rageUses = 999999; + } else if (v.barbarian_level >= 17) { + rageUses = 6; + } else if (v.barbarian_level >= 12) { + rageUses = 5; + } else if (v.barbarian_level >= 6) { + rageUses = 4; + } else if (v.barbarian_level >= 3) { + rageUses = 3; + } else { + rageUses = 2; + } + + let rageDamage; + if (v.barbarian_level >= 16) { + rageDamage = 4; + } else if (v.barbarian_level >= 9) { + rageDamage = 3; + } else { + rageDamage = 2; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.RAGE_TEXT').replace('RAGE_DAMAGE', rageDamage), + name: translate(language, 'CLASS_FEATURES.RAGE'), + recharge: 'Long Rest', + storageName: 'Rage', + uses_max: rageUses, + }); + + if (isUndefined(v.ac_unarmored_ability)) { + finalSetAttrs.ac_unarmored_ability = '@{constitution_mod}'; + } + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.UNARMORED_DEFENSE_TEXT'), + name: translate(language, 'CLASS_FEATURES.UNARMORED_DEFENSE'), + storageName: 'Unarmored Defense', + }); + + if (v.barbarian_level >= 2) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.RECKLESS_ATTACK'), + name: translate(language, 'CLASS_FEATURES.RECKLESS_ATTACK'), + storageName: 'Reckless Attack', + }); + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.DANGER_SENSE_TEXT'), + name: translate(language, 'CLASS_FEATURES.DANGER_SENSE'), + storageName: 'Danger Sense', + }); + } + if (v.barbarian_level >= 5) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.FAST_MOVEMENT_TEXT'), + name: translate(language, 'CLASS_FEATURES.FAST_MOVEMENT'), + storageName: 'Fast Movement', + }); + } + if (v.barbarian_level >= 7) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.FERAL_INSTINCT_TEXT'), + name: translate(language, 'CLASS_FEATURES.FERAL_INSTINCT'), + storageName: 'Feral Instinct', + }); + } + if (v.barbarian_level >= 9) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.BRUTAL_CRITICAL_TEXT'), + name: translate(language, 'CLASS_FEATURES.BRUTAL_CRITICAL'), + storageName: 'Brutal Critical', + }); + } + if (v.barbarian_level >= 11) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.RELENTLESS_RAGE_TEXT'), + name: translate(language, 'CLASS_FEATURES.RELENTLESS_RAGE'), + storageName: 'Relentless Rage', + }); + } + if (v.barbarian_level >= 15) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.PERSISTENT_RAGE_TEXT'), + name: translate(language, 'CLASS_FEATURES.PERSISTENT_RAGE'), + storageName: 'Persistent Rage', + }); + } + if (v.barbarian_level >= 18) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.INDOMITABLE_MIGHT_TEXT'), + name: translate(language, 'CLASS_FEATURES.INDOMITABLE_MIGHT'), + storageName: 'Indomitable Might', + }); + } + } + + if (v.bard_level) { + let die; + if (v.bard_level >= 15) { + die = 'd12'; + } else if (v.bard_level >= 10) { + die = 'd10'; + } else if (v.bard_level >= 5) { + die = 'd8'; + } else { + die = 'd6'; + } + let recharge = 'Long Rest'; + if (v.bard_level >= 5) { + recharge = 'Short Rest'; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.BARDIC_INSPIRATION_TEXT').replace('d6', die), + name: translate(language, 'CLASS_FEATURES.BARDIC_INSPIRATION'), + recharge, + storageName: 'Bardic Inspiration', + uses_max: Math.max(getIntValue(v.charisma_mod), 1), + }); + + if (v.bard_level >= 2) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.JACK_OF_ALL_TRADES_TEXT'), + name: translate(language, 'CLASS_FEATURES.JACK_OF_ALL_TRADES'), + storageName: 'Jack of All Trades', + }); + finalSetAttrs.jack_of_all_trades_toggle = '@{jack_of_all_trades}'; + + let heal; + if (v.bard_level >= 17) { + heal = 'd12'; + } else if (v.bard_level >= 13) { + heal = 'd10'; + } else if (v.bard_level >= 9) { + heal = 'd8'; + } else { + heal = 'd6'; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.SONG_OF_REST_TEXT'), + heal, + name: translate(language, 'CLASS_FEATURES.SONG_OF_REST'), + storageName: 'Song of Rest', + }); + } + if (v.bard_level >= 3) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.EXPERTISE_BARD_TEXT'), + name: translate(language, 'CLASS_FEATURES.EXPERTISE'), + storageName: 'Expertise Bard', + }); + } + if (v.bard_level >= 6) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.COUNTERCHARM_TEXT'), + name: translate(language, 'CLASS_FEATURES.COUNTERCHARM'), + storageName: 'Countercharm', + }); + } + if (v.bard_level >= 10) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.MAGICAL_SECRETS_TEXT'), + name: translate(language, 'CLASS_FEATURES.MAGICAL_SECRETS'), + storageName: 'Magical Secrets', + }); + } + if (v.bard_level >= 20) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.SUPERIOR_INSPIRATION_TEXT'), + name: translate(language, 'CLASS_FEATURES.SUPERIOR_INSPIRATION'), + storageName: 'Superior Inspiration', + }); + } + } + + if (v.cleric_level) { + if (v.cleric_level >= 2) { + let channelDivinityUses; + if (v.cleric_level >= 18) { + channelDivinityUses = 3; + } else if (v.cleric_level >= 6) { + channelDivinityUses = 2; + } else { + channelDivinityUses = 1; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.CHANNEL_DIVINITY_CLERIC_TEXT'), + name: translate(language, 'CLASS_FEATURES.CHANNEL_DIVINITY'), + recharge: 'Short Rest', + storageName: 'Channel Divinity Cleric', + uses_max: channelDivinityUses, + }); + + let turnUndeadText = translate(language, 'CLASS_FEATURES.CHANNEL_DIVINITY_TURN_UNDEAD_TEXT'); + if (v.cleric_level >= 5) { + let turnUndeadDestroyCR; + if (v.cleric_level >= 17) { + turnUndeadDestroyCR = '4'; + } else if (v.cleric_level >= 14) { + turnUndeadDestroyCR = '3'; + } else if (v.cleric_level >= 11) { + turnUndeadDestroyCR = '2'; + } else if (v.cleric_level >= 8) { + turnUndeadDestroyCR = '1'; + } else { + turnUndeadDestroyCR = '1/2'; + } + turnUndeadText += `\n${translate(language, 'CLASS_FEATURES.CHANNEL_DIVINITY_TURN_UNDEAD_TEXT_PART_2').replace('CHALLENGE_RATING', turnUndeadDestroyCR)}`; + } + setClassFeature({ + freetext: turnUndeadText, + name: translate(language, 'CLASS_FEATURES.CHANNEL_DIVINITY_TURN_UNDEAD'), + saving_throw_ability: '@{wisdom_mod}', + saving_throw_vs_ability: 'Wisdom', + storageName: 'Turn Undead', + }); + if (v.cleric_level >= 10) { + setClassFeature({ + freeform: '{{text_top=[[d100]] > [[@{cleric_level}]]}}', + freetext: translate(language, 'CLASS_FEATURES.DIVINE_INTERVENTION_TEXT'), + name: translate(language, 'CLASS_FEATURES.DIVINE_INTERVENTION'), + storageName: 'Divine Intervention', + uses_max: 1, + }); + } + } + } + + if (v.druid_level) { + if (v.druid_level >= 2) { + let wildShapeUses; + let wildShapeCR; + let wildShapeLimitations; + + if (v.druid_level >= 4) { + wildShapeCR = '1/2'; + wildShapeLimitations = translate(language, 'CLASS_FEATURES.WILD_SHAPE_NO_FLYING'); + } else if (v.druid_level >= 8) { + wildShapeCR = 1; + wildShapeLimitations = ''; + } else { + wildShapeCR = '1/4'; + wildShapeLimitations = translate(language, 'CLASS_FEATURES.WILD_SHAPE_NO_FLYING_OR_SWIMMING'); + } + if (v.druid_level >= 20) { + wildShapeUses = 999999; + } else { + wildShapeUses = 2; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.WILD_SHAPE_TEXT').replace('CHALLENGE_RATING', wildShapeCR).replace('LIMITATIONS', ` ${wildShapeLimitations}`), + name: translate(language, 'CLASS_FEATURES.WILD_SHAPE'), + recharge: 'Short Rest', + storageName: 'Wild Shape', + uses_max: wildShapeUses, + }); + } + if (v.druid_level >= 18) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.TIMELESS_BODY_DRUID_TEXT'), + name: translate(language, 'CLASS_FEATURES.TIMELESS_BODY'), + storageName: 'Timeless Body', + }); + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.BEAST_SPELLS_TEXT'), + name: translate(language, 'CLASS_FEATURES.BEAST_SPELLS'), + storageName: 'Beast Spells', + }); + } + if (v.druid_level >= 20) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.ARCHDRUID_TEXT'), + name: translate(language, 'CLASS_FEATURES.ARCHDRUID'), + storageName: 'Archdruid', + }); + } + } + + if (v.fighter_level) { + setTrait({ + freetext: `${translate(language, 'CLASS_FEATURES.FIGHTING_STYLE_TEXT')} ${translate(language, 'CLASS_FEATURES.FIGHTING_STYLE_FIGHTER_OPTIONS')}`, + name: translate(language, 'CLASS_FEATURES.FIGHTING_STYLE'), + storageName: 'Fighting Style', + }); + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.SECOND_WIND_TEXT'), + name: translate(language, 'CLASS_FEATURES.SECOND_WIND'), + heal: 'd10 + @{fighter_level}', + recharge: 'Short Rest', + storageName: 'Second Wind', + uses_max: 1, + }); + + if (v.fighter_level >= 2) { + let actionSurgeUses; + if (v.fighter_level >= 17) { + actionSurgeUses = 2; + } else { + actionSurgeUses = 1; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.ACTION_SURGE_TEXT'), + name: translate(language, 'CLASS_FEATURES.ACTION_SURGE'), + recharge: 'Short Rest', + storageName: 'Action Surge', + uses_max: actionSurgeUses, + }); + } + if (v.fighter_level >= 9) { + let indomitableUses; + if (v.fighter_level >= 17) { + indomitableUses = 3; + } else if (v.fighter_level >= 13) { + indomitableUses = 2; + } else { + indomitableUses = 1; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.INDOMITABLE_TEXT'), + name: translate(language, 'CLASS_FEATURES.INDOMITABLE'), + recharge: 'Long Rest', + storageName: 'Indomitable', + uses_max: indomitableUses, + }); + } + } + + if (v.monk_level) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.MARTIAL_ARTS_TEXT'), + name: translate(language, 'CLASS_FEATURES.MARTIAL_ARTS'), + storageName: 'Martial Arts', + }); + if (v.monk_level >= 2) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.KI_TEXT'), + name: translate(language, 'CLASS_FEATURES.KI'), + recharge: 'Short Rest', + storageName: 'Ki', + uses_max: v.monk_level, + }); + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.FLURRY_OF_BLOWS_TEXT'), + name: translate(language, 'CLASS_FEATURES.FLURRY_OF_BLOWS'), + storageName: 'Flurry of Blows', + }); + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.PATIENT_DEFENSE_TEXT'), + name: translate(language, 'CLASS_FEATURES.PATIENT_DEFENSE'), + storageName: 'Patient Defense', + }); + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.STEP_OF_THE_WIND_TEXT'), + name: translate(language, 'CLASS_FEATURES.STEP_OF_THE_WIND'), + storageName: 'Step of the Wind', + }); + + let unarmoredMovementFeet; + if (v.monk_level >= 18) { + unarmoredMovementFeet = 30; + } else if (v.monk_level >= 14) { + unarmoredMovementFeet = 25; + } else if (v.monk_level >= 10) { + unarmoredMovementFeet = 20; + } else if (v.monk_level >= 6) { + unarmoredMovementFeet = 15; + } else { + unarmoredMovementFeet = 10; + } + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.UNARMORED_MOVEMENT_TEXT').replace('UNARMORED_MOVEMENT_FEET', unarmoredMovementFeet), + name: translate(language, 'CLASS_FEATURES.UNARMORED_MOVEMENT'), + storageName: 'Unarmored Movement', + }); + } + if (v.monk_level >= 3) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.DEFLECT_MISSILES_TEXT'), + name: translate(language, 'CLASS_FEATURES.DEFLECT_MISSILES'), + storageName: 'Deflect Missiles', + }); + } + if (v.monk_level >= 4) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.SLOW_FALL_TEXT'), + name: translate(language, 'CLASS_FEATURES.SLOW_FALL'), + storageName: 'Slow Fall', + }); + } + if (v.monk_level >= 5) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.STUNNING_STRIKE_TEXT'), + name: translate(language, 'CLASS_FEATURES.STUNNING_STRIKE'), + saving_throw_ability: '@{wisdom_mod}', + saving_throw_failure: 'or be stunned until the end of your next turn', + saving_throw_vs_ability: 'Constitution', + storageName: 'Stunning Strike', + }); + } + if (v.monk_level >= 6) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.KI_EMPOWERED_STRIKES_TEXT'), + name: translate(language, 'CLASS_FEATURES.KI_EMPOWERED_STRIKES'), + storageName: 'Ki-Empowered Strikes', + }); + } + if (v.monk_level >= 7) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.EVASION_TEXT'), + name: translate(language, 'CLASS_FEATURES.EVASION'), + storageName: 'Evasion', + }); + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.STILLNESS_OF_MIND_TEXT'), + name: translate(language, 'CLASS_FEATURES.STILLNESS_OF_MIND'), + storageName: 'Stillness of Mind', + }); + } + if (v.monk_level >= 10) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.PURITY_OF_BODY_TEXT'), + name: translate(language, 'CLASS_FEATURES.PURITY_OF_BODY'), + storageName: 'Purity of Body', + }); + } + if (v.monk_level >= 13) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.TONGUE_OF_THE_SUN_AND_MOON_TEXT'), + name: translate(language, 'CLASS_FEATURES.TONGUE_OF_THE_SUN_AND_MOON'), + storageName: 'Tongue of the Sun and Moon', + }); + } + if (v.monk_level >= 14) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.DIAMOND_SOUL_TEXT'), + name: translate(language, 'CLASS_FEATURES.DIAMOND_SOUL'), + storageName: 'Diamond Soul', + }); + } + if (v.monk_level >= 15) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.TIMELESS_BODY_MONK_TEXT'), + name: translate(language, 'CLASS_FEATURES.TIMELESS_BODY'), + storageName: 'Timeless Body', + }); + } + if (v.monk_level >= 15) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.EMPTY_BODY_TEXT'), + name: translate(language, 'CLASS_FEATURES.EMPTY_BODY'), + storageName: 'Empty Body', + }); + } + if (v.monk_level >= 20) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.PERFECT_SELF_TEXT'), + name: translate(language, 'CLASS_FEATURES.PERFECT_SELF'), + storageName: 'Perfect Self', + }); + } + } + + if (v.paladin_level) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.DIVINE_SENSE_TEXT'), + name: translate(language, 'CLASS_FEATURES.DIVINE_SENSE'), + recharge: 'Long Rest', + storageName: 'Divine Sense', + uses_max: 1 + v.charisma_mod, + }); + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.LAY_ON_HANDS_TEXT'), + heal_query_toggle: '@{heal_query}', + name: translate(language, 'CLASS_FEATURES.LAY_ON_HANDS'), + recharge: 'Long Rest', + storageName: 'Lay on Hands', + uses_max: 5 * v.paladin_level, + }); + + if (v.paladin_level >= 2) { + setTrait({ + freetext: `${translate(language, 'CLASS_FEATURES.FIGHTING_STYLE_TEXT')} ${translate(language, 'CLASS_FEATURES.FIGHTING_STYLE_PALADIN_OPTIONS')}`, + name: translate(language, 'CLASS_FEATURES.FIGHTING_STYLE'), + storageName: 'Fighting Style', + }); + setClassFeature({ + damage: '(?{Spell Level|1|2|3|4+, 4} + 1)d8', + damage_type: 'radiant', + freetext: translate(language, 'CLASS_FEATURES.DIVINE_SMITE_TEXT'), + name: translate(language, 'CLASS_FEATURES.DIVINE_SMITE'), + second_damage: 'd8', + second_damage_type: 'vs undead or fiend', + storageName: 'Divine Smite', + }); + } + if (v.paladin_level >= 3) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.DIVINE_HEALTH_TEXT'), + name: translate(language, 'CLASS_FEATURES.DIVINE_HEALTH'), + storageName: 'Divine Health', + }); + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.CHANNEL_DIVINITY_PALADIN_TEXT'), + name: translate(language, 'CLASS_FEATURES.CHANNEL_DIVINITY'), + recharge: 'Short Rest', + storageName: 'Channel Divinity Paladin', + uses_max: 1, + }); + } + if (v.paladin_level >= 6) { + let auraRange; + if (v.paladin_level >= 18) { + auraRange = 30; + } else { + auraRange = 10; + } + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.AURA_OF_PROTECTION_TEXT').replace('AURA_RANGE', auraRange), + name: translate(language, 'CLASS_FEATURES.AURA_OF_PROTECTION'), + storageName: 'Aura of Protection', + }); + + if (v.paladin_level >= 10) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.AURA_OF_COURAGE_TEXT').replace('AURA_RANGE', auraRange), + name: translate(language, 'CLASS_FEATURES.AURA_OF_COURAGE'), + storageName: 'Aura of Courage', + }); + } + } + if (v.paladin_level >= 11) { + setTrait({ + damage: 'd8', + damage_type: 'radiant', + freetext: translate(language, 'CLASS_FEATURES.IMPROVED_DIVINE_SMITE_TEXT'), + name: translate(language, 'CLASS_FEATURES.IMPROVED_DIVINE_SMITE'), + storageName: 'Improved Divine Smite', + }); + } + if (v.paladin_level >= 14) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.CLEANSING_TOUCH_TEXT'), + name: translate(language, 'CLASS_FEATURES.CLEANSING_TOUCH'), + recharge: 'Long Rest', + storageName: 'Cleaning Touch', + uses_max: Math.max(getIntValue(v.charisma_mod), 1), + }); + } + } + + if (v.ranger_level) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.FAVORED_ENEMY_TEXT'), + name: translate(language, 'CLASS_FEATURES.FAVORED_ENEMY'), + storageName: 'Favored Enemy', + }); + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.NATURAL_EXPLORER_TEXT'), + name: translate(language, 'CLASS_FEATURES.NATURAL_EXPLORER'), + storageName: 'Natural Explorer', + }); + if (v.ranger_level >= 2) { + setTrait({ + freetext: `${translate(language, 'CLASS_FEATURES.FIGHTING_STYLE_TEXT')} ${translate(language, 'CLASS_FEATURES.FIGHTING_STYLE_RANGER_OPTIONS')}`, + name: translate(language, 'CLASS_FEATURES.FIGHTING_STYLE'), + storageName: 'Fighting Style', + }); + } + if (v.ranger_level >= 3) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.PRIMEVAL_AWARENESS_TEXT'), + name: translate(language, 'CLASS_FEATURES.PRIMEVAL_AWARENESS'), + storageName: 'Primeval Awareness', + }); + } + if (v.ranger_level >= 8) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.LANDS_STRIDE_TEXT'), + name: translate(language, 'CLASS_FEATURES.LANDS_STRIDE'), + storageName: 'Land\'s Stride', + }); + } + if (v.ranger_level >= 10) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.HIDE_IN_PLAIN_SIGHT_TEXT'), + name: translate(language, 'CLASS_FEATURES.HIDE_IN_PLAIN_SIGHT'), + storageName: 'Hide in Plain Sight', + }); + } + if (v.ranger_level >= 14) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.VANISH_TEXT'), + name: translate(language, 'CLASS_FEATURES.VANISH'), + storageName: 'Vanish', + }); + } + if (v.ranger_level >= 18) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.FERAL_SENSES_TEXT'), + name: translate(language, 'CLASS_FEATURES.FERAL_SENSES'), + storageName: 'Feral Senses', + }); + } + if (v.ranger_level >= 20) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.FOE_SLAYER_TEXT'), + name: translate(language, 'CLASS_FEATURES.FOE_SLAYER'), + storageName: 'Foe Slayer', + }); + } + } + + if (v.rogue_level) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.EXPERTISE_ROGUE_TEXT'), + name: translate(language, 'CLASS_FEATURES.EXPERTISE'), + storageName: 'Expertise Rogue', + }); + setClassFeature({ + damage: `${Math.ceil(getIntValue(v.rogue_level) / 2)}d6`, + freetext: translate(language, 'CLASS_FEATURES.SNEAK_ATTACK_TEXT'), + name: translate(language, 'CLASS_FEATURES.SNEAK_ATTACK'), + storageName: 'Sneak Attack', + }); + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.THIEVES_CANT_TEXT'), + name: translate(language, 'CLASS_FEATURES.THIEVES_CANT'), + storageName: 'Thieves\' Cant', + }); + if (v.rogue_level >= 2) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.CUNNING_ACTION_TEXT'), + name: translate(language, 'CLASS_FEATURES.CUNNING_ACTION'), + storageName: 'Cunning Action', + }); + } + if (v.rogue_level >= 5) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.UNCANNY_DODGE_TEXT'), + name: translate(language, 'CLASS_FEATURES.UNCANNY_DODGE'), + storageName: 'Uncanny Dodge', + }); + } + if (v.rogue_level >= 7) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.EVASION_TEXT'), + name: translate(language, 'CLASS_FEATURES.EVASION'), + storageName: 'Evasion', + }); + } + if (v.rogue_level >= 11) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.RELIABLE_TALENT_TEXT'), + name: translate(language, 'CLASS_FEATURES.RELIABLE_TALENT'), + storageName: 'Reliable Talent', + }); + } + if (v.rogue_level >= 14) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.BLINDSENSE_TEXT'), + name: translate(language, 'CLASS_FEATURES.BLINDSENSE'), + storageName: 'Blindsense', + }); + } + if (v.rogue_level >= 15) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.SLIPPERY_MIND_TEXT'), + name: translate(language, 'CLASS_FEATURES.SLIPPERY_MIND'), + storageName: 'Slippery Mind', + }); + } + if (v.rogue_level >= 18) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.ELUSIVE_TEXT'), + name: translate(language, 'CLASS_FEATURES.ELUSIVE'), + storageName: 'Elusive', + }); + } + if (v.rogue_level >= 20) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.STROKE_OF_LUCK_TEXT'), + name: translate(language, 'CLASS_FEATURES.STROKE_OF_LUCK'), + recharge: 'Short Rest', + storageName: 'Stroke of Luck', + uses_max: 1, + }); + } + } + + if (v.sorcerer_level) { + if (v.sorcerer_level >= 2) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.SORCERY_POINTS_TEXT'), + name: translate(language, 'CLASS_FEATURES.SORCERY_POINTS'), + recharge: 'Long Rest', + storageName: 'Sorcery Points', + uses_max: v.sorcerer_level, + }); + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.FLEXIBLE_CASTING_TEXT'), + name: translate(language, 'CLASS_FEATURES.FLEXIBLE_CASTING'), + storageName: 'Flexible Casting', + }); + if (v.sorcerer_level >= 3) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC'), + storageName: 'Metamagic', + }); + if (v.careful_spell_toggle === '@{careful_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_CAREFUL_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_CAREFUL_SPELL'), + storageName: 'Careful Spell', + }); + } + if (v.distant_spell_toggle === '@{distant_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_DISTANT_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_DISTANT_SPELL'), + storageName: 'Distant Spell', + }); + } + if (v.empowered_spell_toggle === '@{empowered_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_EMPOWERED_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_EMPOWERED_SPELL'), + storageName: 'Empowered Spell', + }); + } + if (v.extended_spell_toggle === '@{extended_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_EXTENDED_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_EXTENDED_SPELL'), + storageName: 'Extended Spell', + }); + } + if (v.heightened_spell_toggle === '@{heightened_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_HEIGHTENED_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_HEIGHTENED_SPELL'), + storageName: 'Heightened Spell', + }); + } + if (v.quickened_spell_toggle === '@{quickened_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_QUICKENED_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_QUICKENED_SPELL'), + storageName: 'Quickened Spell', + }); + } + if (v.subtle_spell_toggle === '@{subtle_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_SUBTLE_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_SUBTLE_SPELL'), + storageName: 'Subtle Spell', + }); + } + if (v.twinned_spell_toggle === '@{twinned_spell_toggle_var}') { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.METAMAGIC_TWINNED_SPELL_TEXT'), + name: translate(language, 'CLASS_FEATURES.METAMAGIC_TWINNED_SPELL'), + storageName: 'Twinned Spell', + }); + } + } + if (v.sorcerer_level >= 20) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.SORCEROUS_RESTORATION_TEXT'), + name: translate(language, 'CLASS_FEATURES.SORCEROUS_RESTORATION'), + storageName: 'Sorcerous Restoration', + }); + } + } + } + + if (v.warlock_level) { + let warlockSpellSlots; + if (v.warlock_level >= 17) { + warlockSpellSlots = 4; + } else if (v.warlock_level >= 11) { + warlockSpellSlots = 3; + } else if (v.warlock_level >= 2) { + warlockSpellSlots = 2; + } else { + warlockSpellSlots = 1; + } + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.WARLOCK_SPELL_SLOTS_TEXT'), + name: translate(language, 'CLASS_FEATURES.WARLOCK_SPELL_SLOTS'), + recharge: 'Short Rest', + storageName: 'Warlock Spell Slots', + uses_max: warlockSpellSlots, + }); + + if (v.warlock_level >= 2) { + let eldritchInvocations; + if (v.warlock_level >= 17) { + eldritchInvocations = 8; + } else if (v.warlock_level >= 15) { + eldritchInvocations = 7; + } else if (v.warlock_level >= 12) { + eldritchInvocations = 6; + } else if (v.warlock_level >= 9) { + eldritchInvocations = 5; + } else if (v.warlock_level >= 7) { + eldritchInvocations = 4; + } else if (v.warlock_level >= 5) { + eldritchInvocations = 3; + } else { + eldritchInvocations = 2; + } + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.ELDRITCH_INVOCATIONS_TEXT').replace('NUMBER_OF_INVOCATIONS_KNOWN', eldritchInvocations), + name: translate(language, 'CLASS_FEATURES.ELDRITCH_INVOCATIONS'), + storageName: 'Eldritch Invocations', + }); + } + if (v.warlock_level >= 11) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.MYSTIC_ARCANUM_TEXT'), + name: translate(language, 'CLASS_FEATURES.MYSTIC_ARCANUM'), + storageName: 'Mystic Arcanum', + }); + } + if (v.warlock_level >= 20) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.ELDRITCH_MASTER_TEXT'), + name: translate(language, 'CLASS_FEATURES.ELDRITCH_MASTER'), + recharge: 'Long Rest', + storageName: 'Eldritch Master', + }); + } + } + + if (v.wizard_level) { + setClassFeature({ + freetext: translate(language, 'CLASS_FEATURES.ARCANE_RECOVERY_TEXT'), + name: translate(language, 'CLASS_FEATURES.ARCANE_RECOVERY'), + recharge: 'Long Rest', + storageName: 'Arcane Recovery', + uses_max: 1, + }); + if (v.wizard_level >= 18) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.SPELL_MASTERY_TEXT'), + name: translate(language, 'CLASS_FEATURES.SPELL_MASTERY'), + storageName: 'Spell Mastery', + }); + } + if (v.wizard_level >= 20) { + setTrait({ + freetext: translate(language, 'CLASS_FEATURES.SIGNATURE_SPELLS_TEXT'), + name: translate(language, 'CLASS_FEATURES.SIGNATURE_SPELLS'), + storageName: 'Signature Spells', + }); + } + } + + setFinalAttrs(v, finalSetAttrs); + }); +}; + +on('change:repeating_class', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_class', eventInfo); + if (repeatingInfo) { + console.log('change:repeating_class', repeatingInfo.field); + updateLevels(repeatingInfo.field); + if (repeatingInfo.field === 'spellcasting') { + updateSpellSlots(); + } + } +}); +on('remove:repeating_class', () => { + console.log('remove:repeating_class'); + updateLevels(); + updateSpellSlots(); + setClassFeatures(); }); -function updateSpellSlots () { - var collectionArray = ['level', 'caster_level', 'caster_type']; - var finalSetAttrs = {}; +const watchForClassLevelChanges = () => { + const classFeatureWatch = []; + for (let z = 0; z < CLASSES.length; z++) { + classFeatureWatch.push(`change:${CLASSES[z]}_level`); + } + for (let i = 0; i < ABILITIES.length; i++) { + classFeatureWatch.push(`change:${ABILITIES[i]}_mod`); + } + classFeatureWatch.push('change:careful_spell_toggle'); + classFeatureWatch.push('change:distant_spell_toggle'); + classFeatureWatch.push('change:empowered_spell_toggle'); + classFeatureWatch.push('change:extended_spell_toggle'); + classFeatureWatch.push('change:heightened_spell_toggle'); + classFeatureWatch.push('change:quickened_spell_toggle'); + classFeatureWatch.push('change:subtle_spell_toggle'); + classFeatureWatch.push('change:twinned_spell_toggle'); - var spellSlots = { - 1: 0, - 2: 0, - 3: 0, - 4: 0, - 5: 0, - 6: 0, - 7: 0, - 8: 0, - 9: 0 - }; - - for (var i = 1; i <= 9; i++) { - var repeatingString = 'spell_slots_l' + i + '_'; - collectionArray.push(repeatingString + 'calc'); - collectionArray.push(repeatingString + 'bonus'); - collectionArray.push(repeatingString + 'max'); - } - getAttrs(collectionArray, function (v) { - var casterLevel = getIntValue(v.level); - var casterType = v.caster_type; - if (isUndefined(casterType)) { - casterType = 'full'; - } - - if (casterType === 'full') { - casterLevel = getIntValue(v.caster_level); - - if (casterLevel >= 3) { - spellSlots['1'] = 4; - } else if (casterLevel === 2) { - spellSlots['1'] = 3; - } else if (casterLevel === 1) { - spellSlots['1'] = 2; - } - if (casterLevel >= 4) { - spellSlots['2'] = 3; - } else if (casterLevel === 3) { - spellSlots['2'] = 2; - } - if (casterLevel >= 6) { - spellSlots['3'] = 3; - } else if (casterLevel === 5) { - spellSlots['3'] = 2; - } - if (casterLevel >= 9) { - spellSlots['4'] = 3; - } else if (casterLevel === 8) { - spellSlots['4'] = 2; - } else if (casterLevel === 7) { - spellSlots['4'] = 1; - } - if (casterLevel >= 18) { - spellSlots['5'] = 3; - } else if (casterLevel >= 10) { - spellSlots['5'] = 2; - } else if (casterLevel === 9) { - spellSlots['5'] = 1; - } - if (casterLevel >= 19) { - spellSlots['6'] = 2; - } else if (casterLevel >= 11) { - spellSlots['6'] = 1; - } - if (casterLevel >= 20) { - spellSlots['7'] = 2; - } else if (casterLevel >= 13) { - spellSlots['7'] = 1; - } - if (casterLevel >= 15) { - spellSlots['8'] = 1; - } - if (casterLevel >= 17) { - spellSlots['9'] = 1; - } - } - - if (casterType === 'half') { - if (casterLevel >= 5) { - spellSlots['1'] = 4; - } else if (casterLevel >= 3) { - spellSlots['1'] = 3; - } else if (casterLevel === 2) { - spellSlots['1'] = 2; - } - if (casterLevel >= 7) { - spellSlots['2'] = 3; - } else if (casterLevel >= 5) { - spellSlots['2'] = 2; - } - if (casterLevel >= 11) { - spellSlots['3'] = 3; - } else if (casterLevel >= 9) { - spellSlots['3'] = 2; - } - if (casterLevel >= 17) { - spellSlots['4'] = 3; - } else if (casterLevel >= 15) { - spellSlots['4'] = 2; - } else if (casterLevel >= 13) { - spellSlots['4'] = 1; - } - if (casterLevel >= 19) { - spellSlots['5'] = 2; - } else if (casterLevel >= 17) { - spellSlots['5'] = 1; - } - } - - if (casterType === 'third') { - if (casterLevel >= 7) { - spellSlots['1'] = 4; - } else if (casterLevel >= 4) { - spellSlots['1'] = 3; - } else if (casterLevel === 3) { - spellSlots['1'] = 2; - } - if (casterLevel >= 10) { - spellSlots['2'] = 3; - } else if (casterLevel >= 7) { - spellSlots['2'] = 2; - } - if (casterLevel >= 16) { - spellSlots['3'] = 3; - } else if (casterLevel >= 13) { - spellSlots['3'] = 2; - } - if (casterLevel >= 19) { - spellSlots['4'] = 1; - } - } - - for (var i = 1; i <= 9; i++) { - var slotCalc = spellSlots[i]; - finalSetAttrs['spell_slots_l' + i + '_calc'] = slotCalc; - - var slotBonus = getIntValue(v['spell_slots_l' + i + '_bonus']); - var spellSlotMax = slotCalc + slotBonus; - finalSetAttrs['spell_slots_l' + i + '_max'] = spellSlotMax; - - if (spellSlotMax > 0) { - finalSetAttrs['spell_slots_l' + i + '_toggle'] = 'on'; - } else { - finalSetAttrs['spell_slots_l' + i + '_toggle'] = 0; - } - } - setFinalAttrs(v, finalSetAttrs); - }); -} - -on('change:caster_level change:spell_slots_l1_bonus change:spell_slots_l2_bonus change:spell_slots_l3_bonus change:spell_slots_l4_bonus change:spell_slots_l5_bonus change:spell_slots_l6_bonus change:spell_slots_l7_bonus change:spell_slots_l8_bonus change:spell_slots_l9_bonus', function () { - updateSpellSlots(); + on(classFeatureWatch.join(' '), () => { + setClassFeatures(); + }); +}; +watchForClassLevelChanges(); +on('change:caster_level change:spell_slots_l1_bonus change:spell_slots_l2_bonus change:spell_slots_l3_bonus change:spell_slots_l4_bonus change:spell_slots_l5_bonus change:spell_slots_l6_bonus change:spell_slots_l7_bonus change:spell_slots_l8_bonus change:spell_slots_l9_bonus', () => { + updateSpellSlots(); }); -function getPB (level, challenge) { - var pb = 2; +const getPB = (level, challenge) => { + let pb = 2; level = getIntValue(level); if (challenge < 1) { @@ -920,2407 +1949,2540 @@ function getPB (level, challenge) { } else { getIntValue(challenge); } - var levelOrChallenge = Math.max(level, challenge); + const levelOrChallenge = Math.max(level, challenge); if (exists(levelOrChallenge)) { pb += Math.floor(Math.abs((levelOrChallenge - 1) / 4)); } return pb; -} -function updatePb () { - var collectionArray = ['level', 'challenge']; - var finalSetAttrs = {}; +}; +const updatePb = () => { + const collectionArray = ['level', 'challenge', 'pb', 'exp', 'h_PB']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - var pb = getPB(v.level, v.challenge); + getAttrs(collectionArray, (v) => { + const pb = getPB(v.level, v.challenge); - finalSetAttrs.pb = pb; - finalSetAttrs.exp = pb * 2; - finalSetAttrs.h_PB = pb / 2; - setFinalAttrs(v, finalSetAttrs); - }); -} + finalSetAttrs.pb = pb; + finalSetAttrs.exp = pb * 2; + finalSetAttrs.h_PB = pb / 2; + setFinalAttrs(v, finalSetAttrs); + }); +}; -on('change:level', function () { - updatePb(); +on('change:level', () => { + updatePb(); }); -function sumRepeating (options, sumItems) { - var repeatingItem = 'repeating_' + options.collection; - var collectionArray = []; - var finalSetAttrs = {}; +const sumRepeating = (options, sumItems) => { + const repeatingItem = `repeating_${options.collection}`; + let collectionArray = []; + const finalSetAttrs = {}; - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + options.toggle); - if (options.qty) { - collectionArray.push(repeatingString + options.qty); - } + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(repeatingString + options.toggle); + if (options.qty) { + collectionArray.push(repeatingString + options.qty); + } - for (var x = 0; x < sumItems.length; x++) { - finalSetAttrs[sumItems[x].totalField] = 0; - if (sumItems[x].totalFieldSecondary) { - finalSetAttrs[sumItems[x].totalFieldSecondary] = 0; - } - collectionArray.push(repeatingString + sumItems[x].fieldToAdd); - if (sumItems[x].bonus) { - collectionArray.push(repeatingString + sumItems[x].bonus); - } - if (sumItems[x].armorType) { - collectionArray.push(repeatingString + sumItems[x].armorType); - } - if (sumItems[x].addOnAfterQty) { - collectionArray.push(repeatingString + sumItems[x].addOnAfterQty); - } - } - } - if (options.getExtraFields) { - collectionArray = collectionArray.concat(options.getExtraFields); - } + for (let x = 0; x < sumItems.length; x++) { + finalSetAttrs[sumItems[x].totalField] = 0; + if (sumItems[x].totalFieldSecondary) { + finalSetAttrs[sumItems[x].totalFieldSecondary] = 0; + } + collectionArray.push(repeatingString + sumItems[x].fieldToAdd); + if (sumItems[x].bonus) { + collectionArray.push(repeatingString + sumItems[x].bonus); + } + if (sumItems[x].armorType) { + collectionArray.push(repeatingString + sumItems[x].armorType); + } + if (sumItems[x].addOnAfterQty) { + collectionArray.push(repeatingString + sumItems[x].addOnAfterQty); + } + } + } + if (options.getExtraFields) { + collectionArray = collectionArray.concat(options.getExtraFields); + } - getAttrs(collectionArray, function (v) { - var dexMod = 0; - if (options.collection === 'armor') { - dexMod = getIntValue(v.dexterity_mod); - } + getAttrs(collectionArray, (v) => { + let dexMod = 0; + if (options.collection === 'armor') { + dexMod = getIntValue(v.dexterity_mod); + } - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; - var qty = getIntValue(v[repeatingString + options.qty], 1); + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + const qty = getIntValue(v[repeatingString + options.qty], 1); - for (var x = 0; x < sumItems.length; x++) { - var sumItem = sumItems[x]; - var fieldToAdd = getFloatValue(v[repeatingString + sumItem.fieldToAdd]); - if (sumItem.bonus) { - fieldToAdd += getFloatValue(v[repeatingString + sumItem.bonus]); - } - if (sumItem.armorType) { - if (!v[repeatingString + sumItem.armorType] || v[repeatingString + sumItem.armorType] === 'Light Armor') { - fieldToAdd += Math.min(5, dexMod); - } else if (v[repeatingString + sumItem.armorType] === 'Medium Armor') { - var mediumArmorDexMod = getIntValue(v.medium_armor_max_dex, 2); - fieldToAdd += Math.min(mediumArmorDexMod, dexMod); - } else if (v[repeatingString + sumItem.armorType] === 'Armor + Dex') { - fieldToAdd += dexMod; - } - } + for (let x = 0; x < sumItems.length; x++) { + const sumItem = sumItems[x]; + let fieldToAdd = getFloatValue(v[repeatingString + sumItem.fieldToAdd]); + if (sumItem.bonus) { + fieldToAdd += getFloatValue(v[repeatingString + sumItem.bonus]); + } + if (sumItem.armorType) { + if (!v[repeatingString + sumItem.armorType] || v[repeatingString + sumItem.armorType] === 'Light Armor') { + fieldToAdd += Math.min(5, dexMod); + } else if (v[repeatingString + sumItem.armorType] === 'Medium Armor') { + const mediumArmorDexMod = getIntValue(v.medium_armor_max_dex, 2); + fieldToAdd += Math.min(mediumArmorDexMod, dexMod); + } else if (v[repeatingString + sumItem.armorType] === 'Armor + Dex') { + fieldToAdd += dexMod; + } + } - var itemTotal = (qty * fieldToAdd).round(2); - console.log('itemTotal', itemTotal); + let itemTotal = round((qty * fieldToAdd), 2); - if (sumItem.addOnAfterQty) { - itemTotal += getFloatValue(v[repeatingString + sumItem.addOnAfterQty]); - } + if (sumItem.addOnAfterQty) { + itemTotal += getFloatValue(v[repeatingString + sumItem.addOnAfterQty]); + } - itemTotal = itemTotal.round(2); + itemTotal = round(itemTotal, 2); - if (sumItem.itemTotal) { - finalSetAttrs[repeatingString + sumItem.itemTotal] = itemTotal; - } + if (sumItem.itemTotal) { + finalSetAttrs[repeatingString + sumItem.itemTotal] = itemTotal; + } - var toggle = v[repeatingString + options.toggle]; - if (toggle !== 0 && toggle !== '0') { - var addToPrimary = true; - var addToSecondary = false; + const toggle = v[repeatingString + options.toggle]; + if (toggle !== 0 && toggle !== '0') { + let addToPrimary = true; + let addToSecondary = false; - if (sumItem.armorType) { - if (v[repeatingString + sumItem.armorType] === 'Shield' || v[repeatingString + sumItem.armorType] === 'AC') { - addToSecondary = true; - } else if (v[repeatingString + sumItem.armorType] === 'Unarmored') { - addToPrimary = false; - addToSecondary = true; - } - } + if (sumItem.armorType) { + if (v[repeatingString + sumItem.armorType] === 'Shield' || v[repeatingString + sumItem.armorType] === 'AC') { + addToSecondary = true; + } else if (v[repeatingString + sumItem.armorType] === 'Unarmored') { + addToPrimary = false; + addToSecondary = true; + } + } - if (addToPrimary) { - finalSetAttrs[sumItem.totalField] += itemTotal; - } - if (addToSecondary) { - finalSetAttrs[sumItem.totalFieldSecondary] += itemTotal; - } - } - } - } - for (var y = 0; y < sumItems.length; y++) { - var item = sumItems[y]; - if (item.totalField && !exists(finalSetAttrs[item.totalField])) { - finalSetAttrs[item.totalField] = 0; - } - if (item.totalFieldSecondary && !exists(finalSetAttrs[item.totalFieldSecondary])) { - finalSetAttrs[item.totalFieldSecondary] = 0; - } - } + if (addToPrimary) { + finalSetAttrs[sumItem.totalField] += itemTotal; + } + if (addToSecondary) { + finalSetAttrs[sumItem.totalFieldSecondary] += itemTotal; + } + } + } + } + for (let y = 0; y < sumItems.length; y++) { + const item = sumItems[y]; + if (item.totalField && !exists(finalSetAttrs[item.totalField])) { + finalSetAttrs[item.totalField] = 0; + } + if (item.totalFieldSecondary && !exists(finalSetAttrs[item.totalFieldSecondary])) { + finalSetAttrs[item.totalFieldSecondary] = 0; + } + } - if (options.collection === 'armor' && !getIntValue(v.is_npc)) { - finalSetAttrs.ac_unarmored_calc += 10 + dexMod + getAbilityValue(v, v.ac_unarmored_ability); + if (options.collection === 'armor' && !getIntValue(v.is_npc)) { + finalSetAttrs.ac_unarmored_calc += 10 + dexMod + getAbilityValue(v, v.ac_unarmored_ability); - finalSetAttrs.ac = Math.max(finalSetAttrs.ac_armored_calc, finalSetAttrs.ac_unarmored_calc); - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} + finalSetAttrs.AC = Math.max(finalSetAttrs.ac_armored_calc, finalSetAttrs.ac_unarmored_calc); + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; -function updateArmor (rowId) { - var repeatingItem = 'repeating_armor'; - var collectionArray = []; - var finalSetAttrs = {}; +const updateArmor = (rowId) => { + const repeatingItem = 'repeating_armor'; + const collectionArray = []; + const finalSetAttrs = {}; - getSectionIDs(repeatingItem, function (ids) { - if (rowId) { - ids = []; - ids.push(rowId); - } - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'modifiers'); - } + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}parsed`); + collectionArray.push(`${repeatingString}modifiers`); + } - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; - if (isUndefined(v[repeatingString + 'parsed']) || v[repeatingString + 'parsed'].indexOf('acBonus') === -1) { - var armorModifiers = v[repeatingString + 'modifiers']; - if (exists(armorModifiers)) { - var acBonus = armorModifiers.replace(/^\D+/g, ''); + if (isUndefined(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('acBonus') === -1) { + const armorModifiers = v[`${repeatingString}modifiers`]; + if (exists(armorModifiers)) { + const acBonus = armorModifiers.replace(/^\D+/g, ''); - finalSetAttrs[repeatingString + 'ac_bonus'] = acBonus; - } - if (isUndefined(finalSetAttrs[repeatingString + 'parsed'])) { - finalSetAttrs[repeatingString + 'parsed'] = ''; - } - finalSetAttrs[repeatingString + 'parsed'] += ' acBonus'; - } - } - setFinalAttrs(v, finalSetAttrs); - }); - }); + finalSetAttrs[`${repeatingString}ac_bonus`] = acBonus; + } + if (isUndefined(finalSetAttrs[`${repeatingString}parsed`])) { + finalSetAttrs[`${repeatingString}parsed`] = ''; + } + finalSetAttrs[`${repeatingString}parsed`] += ' acBonus'; + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); - var options = { - collection: 'armor', - getExtraFields: ['medium_armor_max_dex', 'dexterity_mod', 'ac_unarmored_ability', 'is_npc'], - toggle: 'worn' - }; - for (var i = 0; i < ABILITIES.length; i++) { - options.getExtraFields.push(ABILITIES[i] + '_mod'); - } - var sumItems = [ - { - fieldToAdd: 'weight', - totalField: 'weight_armor' - }, - { - fieldToAdd: 'ac_base', - bonus: 'ac_bonus', - armorType: 'type', - itemTotal: 'ac_total', - totalField: 'ac_armored_calc', - totalFieldSecondary: 'ac_unarmored_calc' - } - ]; - sumRepeating(options, sumItems); -} -on('change:repeating_armor', function (eventInfo) { - var changedField = getRepeatingField('repeating_armor', eventInfo); - if (changedField !== 'ac_total') { - var rowId = getRowId('repeating_armor', eventInfo); - updateArmor(rowId); - } + const options = { + collection: 'armor', + getExtraFields: ['medium_armor_max_dex', 'dexterity_mod', 'ac_unarmored_ability', 'is_npc'], + toggle: 'worn', + }; + for (let i = 0; i < ABILITIES.length; i++) { + options.getExtraFields.push(`${ABILITIES[i]}_mod`); + } + const sumItems = [ + { + fieldToAdd: 'weight', + totalField: 'weight_armor', + }, + { + fieldToAdd: 'ac_base', + bonus: 'ac_bonus', + armorType: 'type', + itemTotal: 'ac_total', + totalField: 'ac_armored_calc', + totalFieldSecondary: 'ac_unarmored_calc', + }, + ]; + sumRepeating(options, sumItems); +}; +on('change:repeating_armor', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_armor', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'ac_total') { + updateArmor(repeatingInfo.rowId); + } }); -on('change:medium_armor_max_dex change:ac_unarmored_ability remove:repeating_armor', function () { - updateArmor(); +on('change:dexterity_mod change:medium_armor_max_dex change:ac_unarmored_ability remove:repeating_armor', () => { + updateArmor(); }); -function updateEquipment (rowId) { - var repeatingItem = 'repeating_equipment'; - var collectionArray = []; - var finalSetAttrs = {}; +const updateEquipment = (rowId) => { + const repeatingItem = 'repeating_equipment'; + const collectionArray = []; + const finalSetAttrs = {}; - getSectionIDs(repeatingItem, function (ids) { - if (rowId) { - ids = []; - ids.push(rowId); - } - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'content'); - } + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}content`); + } - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; - if (isUndefined(v[repeatingString + 'parsed']) || v[repeatingString + 'parsed'].indexOf('content') === -1) { - var content = v[repeatingString + 'content']; - if (exists(content)) { - content = content.replace(/\s(\d+d\d+\s(?:\+|\-)\s\d+)\s/g, ' [[$1]] ') - .replace(/\s(\d+d\d+)\s/g, ' [[$1]] ') - .replace(/\s(\d+)\s/g, ' [[$1]] '); + if (isUndefined(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('content') === -1) { + let content = v[`${repeatingString}content`]; + if (exists(content)) { + content = content.replace(/\s(\d+d\d+\s(?:\+|\-)\s\d+)\s/g, ' [[$1]] ') + .replace(/\s(\d+d\d+)\s/g, ' [[$1]] ') + .replace(/\s(\d+)\s/g, ' [[$1]] '); - finalSetAttrs[repeatingString + 'content'] = content; - } - if (isUndefined(finalSetAttrs[repeatingString + 'parsed'])) { - finalSetAttrs[repeatingString + 'parsed'] = ''; - } - finalSetAttrs[repeatingString + 'parsed'] += ' content'; - } - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} + finalSetAttrs[`${repeatingString}content`] = content; -on('change:repeating_equipment', function (eventInfo) { - var rowId = getRowId('repeating_equipment', eventInfo); - updateEquipment(rowId); + if (isUndefined(finalSetAttrs[`${repeatingString}parsed`])) { + finalSetAttrs[`${repeatingString}parsed`] = ''; + } + finalSetAttrs[`${repeatingString}parsed`] += ' content'; + } + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; + +on('change:repeating_equipment', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_equipment', eventInfo); + updateEquipment(repeatingInfo.rowId); }); -function weighEquipment () { - var options = { - collection: 'equipment', - toggle: 'carried', - qty: 'qty' - }; - var sumItems = [ - { - fieldToAdd: 'weight', - itemTotal: 'weight_total', - totalField: 'weight_equipment' - } - ]; - sumRepeating(options, sumItems); -} -on('change:repeating_equipment:carried change:repeating_equipment:qty change:repeating_equipment:weight remove:repeating_equipment', function () { - weighEquipment(); +const weighEquipment = () => { + const options = { + collection: 'equipment', + toggle: 'carried', + qty: 'qty', + }; + const sumItems = [ + { + fieldToAdd: 'weight', + itemTotal: 'weight_total', + totalField: 'weight_equipment', + }, + ]; + sumRepeating(options, sumItems); +}; +on('change:repeating_equipment:carried change:repeating_equipment:qty change:repeating_equipment:weight remove:repeating_equipment', () => { + weighEquipment(); }); -on('change:pb', function () { - updateSkill(); - updateAttack(); - updateSpell(); - updateJackOfAllTrades(); - updateRemarkableAthlete(); - updateAction('trait'); - updateAction('action'); - updateAction('reaction'); - updateAction('legendaryaction'); - updateAction('lairaction'); +const weighAmmo = () => { + const options = { + collection: 'ammo', + qty: 'qty', + }; + const sumItems = [ + { + fieldToAdd: 'weight', + totalField: 'weight_ammo', + }, + ]; + sumRepeating(options, sumItems); +}; +on('change:repeating_ammo:weight change:repeating_ammo:qty', () => { + weighAmmo(); }); -function updateJackOfAllTrades () { - var collectionArray = ['pb']; - var finalSetAttrs = {}; +const updateJackOfAllTrades = () => { + const collectionArray = ['pb', 'jack_of_all_trades']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - finalSetAttrs.jack_of_all_trades = Math.floor(getIntValue(v.pb) / 2); - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:jack_of_all_trades_toggle', function () { - updateJackOfAllTrades(); + getAttrs(collectionArray, (v) => { + finalSetAttrs.jack_of_all_trades = Math.floor(getIntValue(v.pb) / 2); + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:jack_of_all_trades_toggle', () => { + updateJackOfAllTrades(); }); -function updateRemarkableAthlete () { - var collectionArray = ['pb']; - var finalSetAttrs = {}; +const updateRemarkableAthlete = () => { + const collectionArray = ['pb', 'remarkable_athlete']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - finalSetAttrs.remarkable_athlete = Math.ceil(getIntValue(v.pb) / 2); - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:remarkable_athlete_toggle', function () { - updateRemarkableAthlete(); + getAttrs(collectionArray, (v) => { + finalSetAttrs.remarkable_athlete = Math.ceil(getIntValue(v.pb) / 2); + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:remarkable_athlete_toggle', () => { + updateRemarkableAthlete(); }); -function updateInitiative () { - var collectionArray = ['dexterity_mod', 'dexterity_check_bonus', 'initiative_bonus', 'jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'global_check_bonus']; - var finalSetAttrs = {}; +const updateInitiative = () => { + const collectionArray = ['initiative', 'initiative_formula', 'dexterity_mod', 'dexterity_check_bonus', 'initiative_bonus', 'jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'global_check_bonus']; + const finalSetAttrs = {}; - finalSetAttrs.initiative = 0; - finalSetAttrs.initiative_formula = ''; - getAttrs(collectionArray, function (v) { + finalSetAttrs.initiative = 0; + getAttrs(collectionArray, (v) => { + const dexMod = getIntValue(v.dexterity_mod); + if (exists(dexMod)) { + finalSetAttrs.initiative += dexMod; + } + finalSetAttrs.initiative_formula = `${dexMod}[dex]`; - var dexMod = getIntValue(v.dexterity_mod); - if (exists(dexMod)) { - finalSetAttrs.initiative += dexMod; - } - finalSetAttrs.initiative_formula += dexMod + '[dex]'; + const dexCheckBonus = getIntValue(v.dexterity_check_bonus); + if (exists(dexCheckBonus)) { + finalSetAttrs.initiative += dexCheckBonus; + finalSetAttrs.initiative_formula += ` + ${dexCheckBonus}[dex check bonus]`; + } - var dexCheckBonus = getIntValue(v.dexterity_check_bonus); - if (exists(dexCheckBonus)) { - finalSetAttrs.initiative += dexCheckBonus; - finalSetAttrs.initiative_formula += dexCheckBonus + '[dex check bonus]'; - } + const initiativeBonus = v.initiative_bonus; + if (exists(initiativeBonus)) { + if (!isNaN(initiativeBonus)) { + finalSetAttrs.initiative += getIntValue(initiativeBonus); + } + finalSetAttrs.initiative_formula += ' + @{initiative_bonus}[initiative bonus]'; + } - var initiativeBonus = getIntValue(v.initiative_bonus); - if (exists(initiativeBonus)) { - finalSetAttrs.initiative += initiativeBonus; - finalSetAttrs.initiative_formula += ADD + initiativeBonus + '[initiative bonus]'; - } + if (v.remarkable_athlete_toggle === '@{remarkable_athlete}') { + const remarkableAthlete = getIntValue(v.remarkable_athlete); + if (exists(remarkableAthlete)) { + finalSetAttrs.initiative += remarkableAthlete; + finalSetAttrs.initiative_formula += ` + ${remarkableAthlete}[remarkable athlete]`; + } + } else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') { + const jackOfAllTrades = getIntValue(v.jack_of_all_trades); + if (exists(jackOfAllTrades)) { + finalSetAttrs.initiative += jackOfAllTrades; + finalSetAttrs.initiative_formula += ` + ${jackOfAllTrades}[jack of all trades]`; + } + } - if (v.remarkable_athlete_toggle === '@{remarkable_athlete}') { - var remarkableAthlete = getIntValue(v.remarkable_athlete); - if (exists(remarkableAthlete)) { - finalSetAttrs.initiative += remarkableAthlete; - finalSetAttrs.initiative_formula += ADD + remarkableAthlete + '[remarkable athlete]'; - } - } else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') { - var jackOfAllTrades = getIntValue(v.jack_of_all_trades); - if (exists(jackOfAllTrades)) { - finalSetAttrs.initiative += jackOfAllTrades; - finalSetAttrs.initiative_formula += ADD + jackOfAllTrades + '[jack of all trades]'; - } - } - - var globalCheckBonus = v.global_check_bonus; - if (exists(globalCheckBonus)) { - finalSetAttrs.initiative_formula += ADD + globalCheckBonus + '[global check bonus]'; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:dexterity_mod change:dexterity_check_bonus change:initiative_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_check_bonus', function () { - updateInitiative(); + const globalCheckBonus = v.global_check_bonus; + if (exists(globalCheckBonus)) { + finalSetAttrs.initiative_formula += ` + ${globalCheckBonus}[global check bonus]`; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:dexterity_mod change:dexterity_check_bonus change:initiative_bonus change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_check_bonus', () => { + updateInitiative(); }); -function updateWeight () { - var collectionArray = ['weight_attacks', 'weight_armor', 'weight_equipment', 'weight_coinage', 'weight_misc']; - var finalSetAttrs = {}; +const updateWeight = () => { + const collectionArray = ['weight_attacks', 'weight_ammo', 'weight_armor', 'weight_equipment', 'weight_coinage']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - finalSetAttrs.weight_total = (getFloatValue(v.weight_attacks) + getFloatValue(v.weight_armor) + getFloatValue(v.weight_equipment) + getFloatValue(v.weight_coinage) + getFloatValue(v.weight_misc)).round(2); - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:weight_attacks change:weight_armor change:weight_equipment change:weight_coinage change:weight_misc', function () { - updateWeight(); + getAttrs(collectionArray, (v) => { + finalSetAttrs.weight_total = round((getFloatValue(v.weight_attacks) + getFloatValue(v.weight_ammo) + getFloatValue(v.weight_armor) + getFloatValue(v.weight_equipment) + getFloatValue(v.weight_coinage)), 2); + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:weight_attacks change:weight_ammo change:weight_armor change:weight_equipment change:weight_coinage', () => { + updateWeight(); +}); +const updateAttackToggle = (v, finalSetAttrs, repeatingString, options) => { + const attackParse = { + attackAbility: options.attackAbility, + parseName: 'attack', + toggleField: 'roll_toggle', + toggleFieldSetTo: '@{roll_toggle_var}', + triggerFields: ['type'], + }; + parseAttackComponent(v, repeatingString, finalSetAttrs, attackParse); + + let attackFormula = ''; + const attackToggle = v[`${repeatingString}roll_toggle`]; + + let toHit = 0; + if (!attackToggle || attackToggle === '@{roll_toggle_var}') { + const proficiency = v[`${repeatingString}proficiency`]; + if (!proficiency || proficiency === 'on') { + const pb = getIntValue(v.pb); + toHit += pb; + attackFormula += `${pb}[proficient]`; + } else { + attackFormula += '0[unproficient]'; + } + + let attackAbility = v[`${repeatingString}attack_ability`]; + if (isUndefined(attackAbility) && v[`${repeatingString}type`] === 'Ranged Weapon') { + attackAbility = '@{dexterity_mod}'; + finalSetAttrs[`${repeatingString}attack_ability`] = attackAbility; + } else if (finalSetAttrs[`${repeatingString}attack_ability`]) { + attackAbility = finalSetAttrs[`${repeatingString}attack_ability`]; + } + attackAbility = getAbilityValue(v, attackAbility, options.defaultAbility); + if (exists(attackAbility)) { + toHit += attackAbility; + attackFormula += ` + ${attackAbility}[${getAbilityShortName(v[`${repeatingString}attack_ability`])}]`; + } + + const attackBonus = getIntValue(v[`${repeatingString}attack_bonus`]); + if (exists(attackBonus)) { + toHit += attackBonus; + attackFormula += ` + ${attackBonus}[bonus]`; + } + + if (exists(options.globalAttackBonus)) { + if (!isNaN(options.globalAttackBonus)) { + toHit += getIntValue(options.globalAttackBonus); + } + attackFormula += ` + ${options.globalAttackBonus}[${options.globalAttackBonusLabel}]`; + } + + if (!v[`${repeatingString}type`] || v[`${repeatingString}type`] === 'Melee Weapon') { + if (exists(options.globalMeleeAttackBonus)) { + if (!isNaN(options.globalMeleeAttackBonus)) { + toHit += getIntValue(options.globalMeleeAttackBonus); + } + attackFormula += ` + ${options.globalMeleeAttackBonus}[global melee attack bonus]`; + } + } else if (v[`${repeatingString}type`] === 'Ranged Weapon') { + if (exists(options.globalRangedAttackBonus)) { + if (!isNaN(options.globalRangedAttackBonus)) { + toHit += getIntValue(options.globalRangedAttackBonus); + } + attackFormula += ` + ${options.globalRangedAttackBonus}[global ranged attack bonus]`; + } + } + finalSetAttrs[`${repeatingString}attack_formula`] = attackFormula; + } + if (options.type === 'attack') { + finalSetAttrs[`${repeatingString}to_hit`] = toHit; + } +}; + +const updateSavingThrowToggle = (v, finalSetAttrs, repeatingString, options) => { + const savingThrowParse = { + parseName: 'savingThrow', + toggleField: 'saving_throw_toggle', + toggleFieldSetTo: '@{saving_throw_toggle_var}', + triggerFields: ['saving_throw_vs_ability'], + }; + parseAttackComponent(v, repeatingString, finalSetAttrs, savingThrowParse); + + const savingThrowToggle = v[`${repeatingString}saving_throw_toggle`]; + if (savingThrowToggle === '@{saving_throw_toggle_var}') { + let savingThrowDC = 8 + getIntValue(v.pb); + let savingThrowAbility = v[`${repeatingString}saving_throw_ability`]; + if (!savingThrowAbility && savingThrowAbility !== '0') { + savingThrowAbility = v.default_ability; + finalSetAttrs[`${repeatingString}saving_throw_ability`] = v.default_ability; + } + + savingThrowDC += getAbilityValue(v, savingThrowAbility, 'strength_mod'); + if (options && options.bonusDC) { + savingThrowDC += getIntValue(options.bonusDC); + } + savingThrowDC += getIntValue(v[`${repeatingString}saving_throw_bonus`]); + finalSetAttrs[`${repeatingString}saving_throw_dc`] = savingThrowDC; + } +}; + +const updateDamageToggle = (v, finalSetAttrs, repeatingString, options) => { + const damageParse = { + addCastingModifier: exists(v[`${repeatingString}add_casting_modifier`]), + parseName: 'damage', + toggleField: 'damage_toggle', + toggleFieldSetTo: '@{damage_toggle_var}', + triggerFields: ['damage'], + }; + parseAttackComponent(v, repeatingString, finalSetAttrs, damageParse); + + let damageString = ''; + let damageFormula = ''; + const damageToggle = v[`${repeatingString}damage_toggle`]; + let damageAbility; + let damageType; + + if (!damageToggle || damageToggle === '@{damage_toggle_var}') { + let damageAddition = 0; + + const damage = v[`${repeatingString}damage`]; + if (exists(damage)) { + damageString += damage; + damageFormula += `${damage}[damage]`; + } + + if (!options.defaultDamageAbility) { + options.defaultDamageAbility = 0; + } + + damageAbility = v[`${repeatingString}damage_ability`]; + if (isUndefined(damageAbility) && v[`${repeatingString}type`] === 'Ranged Weapon') { + damageAbility = '@{dexterity_mod}'; + finalSetAttrs[`${repeatingString}damage_ability`] = damageAbility; + } + if (exists(damageAbility) || options.defaultDamageAbility) { + const damageAbilityValue = getAbilityValue(v, damageAbility, options.defaultDamageAbility); + if (exists(damageAbilityValue)) { + damageAddition += damageAbilityValue; + damageFormula += `${addOrSubtract(damageFormula, damageAbilityValue)}[${getAbilityShortName(v[`${repeatingString}damage_ability`])}]`; + } + } + + const damageBonus = getIntValue(v[`${repeatingString}damage_bonus`]); + if (exists(damageBonus)) { + damageAddition += damageBonus; + if (damageFormula !== '') { + damageFormula += ' + '; + } + damageFormula += `${damageBonus}[bonus]`; + } + + if (exists(options.globalDamageBonus)) { + if (!isNaN(options.globalDamageBonus)) { + damageAddition += getIntValue(options.globalDamageBonus); + } else { + damageString += ` + ${options.globalDamageBonus}`; + } + damageFormula += ` + ${options.globalDamageBonus}[global damage bonus]`; + } + + if (options && options.globalMeleeDamageBonus && !v[`${repeatingString}type`] || v[`${repeatingString}type`] === 'Melee Weapon') { + if (!isNaN(options.globalMeleeDamageBonus)) { + damageAddition += getIntValue(options.globalMeleeDamageBonus); + } else { + damageString += ` + ${options.globalMeleeDamageBonus}`; + } + if (damageFormula !== '') { + damageFormula += ' + '; + } + damageFormula += `${options.globalMeleeDamageBonus}[global melee damage bonus]`; + } else if (options && options.globalRangedDamageBonus && v[`${repeatingString}type`] === 'Ranged Weapon') { + if (!isNaN(options.globalRangedDamageBonus)) { + damageAddition += getIntValue(options.globalRangedDamageBonus); + } else { + damageString += ` + ${options.globalRangedDamageBonus}`; + } + if (damageFormula !== '') { + damageFormula += ' + '; + } + damageFormula += `${options.globalRangedDamageBonus}[global ranged damage bonus]`; + } + + if (exists(damageAddition)) { + damageString += addOrSubtract(damageString, damageAddition); + } + + damageType = v[`${repeatingString}damage_type`]; + if (exists(damageType)) { + if (hasUpperCase(damageType)) { + damageType = damageType.toLowerCase(); + finalSetAttrs[`${repeatingString}damage_type`] = damageType; + } + damageString += ` ${damageType}`; + } + } + if (!exists(damageFormula)) { + damageFormula = 0; + } + finalSetAttrs[`${repeatingString}damage_formula`] = damageFormula; + + const secondDamageParse = { + parseName: 'secondDamage', + toggleField: 'second_damage_toggle', + toggleFieldSetTo: '@{second_damage_toggle_var}', + triggerFields: ['second_damage'], + }; + parseAttackComponent(v, repeatingString, finalSetAttrs, secondDamageParse); + + let secondDamageFormula = ''; + + const secondDamageToggle = fromVOrFinalSetAttrs(v, finalSetAttrs, `${repeatingString}second_damage_toggle`); + if (secondDamageToggle === '@{second_damage_toggle_var}') { + let secondDamageAddition = 0; + const secondDamage = v[`${repeatingString}second_damage`]; + if (exists(secondDamage)) { + damageString += ` + ${secondDamage}`; + secondDamageFormula += `${secondDamage}[second damage]`; + } + + let secondDamageAbility = v[`${repeatingString}second_damage_ability`]; + if (exists(secondDamageAbility)) { + secondDamageAbility = getAbilityValue(v, secondDamageAbility); + if (exists(secondDamageAbility)) { + secondDamageAddition += secondDamageAbility; + secondDamageFormula += `${addOrSubtract(secondDamageFormula, secondDamageAbility)}[${getAbilityShortName(v[`${repeatingString}second_damage_ability`])}]`; + } + } + + const secondDamageBonus = getIntValue(v[`${repeatingString}second_damage_bonus`]); + if (exists(secondDamageBonus)) { + secondDamageAddition += secondDamageBonus; + if (secondDamageFormula !== '') { + secondDamageFormula += ' + '; + } + secondDamageFormula += `${secondDamageBonus}[bonus]`; + } + + if (exists(secondDamageAddition)) { + damageString += addOrSubtract(damageString, secondDamageAddition); + } + + let secondDamageType = v[`${repeatingString}second_damage_type`]; + if (exists(secondDamageType)) { + if (hasUpperCase(secondDamageType)) { + secondDamageType = secondDamageType.toLowerCase(); + finalSetAttrs[`${repeatingString}second_damage_type`] = secondDamageType; + } + damageString += ` ${secondDamageType}`; + } + + if (isUndefined(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('damageProperties') === -1) { + const damageProperties = v[`${repeatingString}properties`]; + if (exists(damageProperties)) { + if (damageProperties.indexOf('Versatile') !== -1) { + if (!exists(damageAbility)) { + damageAbility = '@{strength_mod}'; + } + finalSetAttrs[`${repeatingString}second_damage_ability`] = damageAbility; + finalSetAttrs[`${repeatingString}second_damage_type`] = damageType; + } + if (!finalSetAttrs[`${repeatingString}parsed`]) { + finalSetAttrs[`${repeatingString}parsed`] = ''; + } + finalSetAttrs[`${repeatingString}parsed`] += ' damageProperties'; + } + } + } + if (!exists(secondDamageFormula)) { + secondDamageFormula = 0; + } + finalSetAttrs[`${repeatingString}second_damage_formula`] = secondDamageFormula; + if (options.type === 'attack') { + finalSetAttrs[`${repeatingString}damage_string`] = damageString; + } +}; + +const updateHealToggle = (v, finalSetAttrs, repeatingString) => { + const healParse = { + addCastingModifier: exists(v[`${repeatingString}add_casting_modifier`]), + parseName: 'heal', + toggleField: 'heal_toggle', + toggleFieldSetTo: '@{heal_toggle_var}', + triggerFields: ['heal'], + }; + parseAttackComponent(v, repeatingString, finalSetAttrs, healParse); + + let healFormula = '@{heal}[heal]'; + const healToggle = v[`${repeatingString}heal_toggle`]; + if (healToggle === '@{heal_toggle_var}') { + let healAbility = v[`${repeatingString}heal_ability`]; + healAbility = getAbilityValue(v, healAbility); + if (exists(healAbility)) { + healFormula += ` + ${healAbility}[${getAbilityShortName(v[`${repeatingString}heal_ability`])}]`; + } + + const healBonus = getIntValue(v[`${repeatingString}heal_bonus`]); + if (exists(healBonus)) { + healFormula += ` + ${healBonus}[bonus]`; + } + + if (exists(v.global_spell_heal_bonus)) { + healFormula += ' + @{global_spell_heal_bonus}[global spell heal bonus]'; + } + if (v[`${repeatingString}heal_query_toggle`] === '@{heal_query}') { + healFormula += ' + @{heal_query_toggle}[query amount]'; + } + + finalSetAttrs[`${repeatingString}heal_formula`] = healFormula; + } +}; + +const updateHigherLevelToggle = (v, finalSetAttrs, repeatingString) => { + const higherLevelParse = { + addCastingModifier: exists(v[`${repeatingString}add_casting_modifier`]), + parseName: 'higherLevel', + toggleField: 'higher_level_toggle', + toggleFieldSetTo: '@{higher_level_toggle_var}', + triggerFields: ['higher_level_dice', 'higher_level_die', 'second_higher_level_dice', 'second_higher_level_die', 'higher_level_heal'], + }; + parseAttackComponent(v, repeatingString, finalSetAttrs, higherLevelParse); + + const higherLevelToggle = v[`${repeatingString}higher_level_toggle`]; + if (exists(higherLevelToggle) && higherLevelToggle === '@{higher_level_toggle_var}') { + let spellLevelQuery = '?{Spell Level'; + + const spellLevel = getIntValue(v[`${repeatingString}spell_level`]); + for (let i = spellLevel; i <= 9; i++) { + spellLevelQuery += `|${i}`; + } + spellLevelQuery += '}'; + finalSetAttrs[`${repeatingString}higher_level_query`] = spellLevelQuery; + + const damageToggle = v[`${repeatingString}damage_toggle`]; + if (damageToggle && damageToggle === '@{damage_toggle_var}') { + finalSetAttrs[`${repeatingString}damage_formula`] += ' + ((@{higher_level_query} - @{spell_level}) * @{higher_level_dice})@{higher_level_die}[higher lvl]'; + } + + const secondDamageToggle = v[`${repeatingString}second_damage_toggle`]; + if (secondDamageToggle && secondDamageToggle === '@{second_damage_toggle_var}') { + finalSetAttrs[`${repeatingString}second_damage_formula`] += ' + ((@{higher_level_query} - @{spell_level}) * @{second_higher_level_dice})@{second_higher_level_die}[higher lvl]'; + } + + const healToggle = v[`${repeatingString}heal_toggle`]; + if (healToggle && healToggle === '@{heal_toggle_var}') { + finalSetAttrs[`${repeatingString}heal_formula`] += ' + ((@{higher_level_query} - @{spell_level}) * @{higher_level_dice})@{higher_level_die}[higher lvl] + (@{higher_level_heal} * (@{higher_level_query} - @{spell_level}))[higher lvl flat amount]'; + } + } +}; + +const findAmmo = (name, callback) => { + const repeatingItem = 'repeating_ammo'; + const collectionArray = []; + + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}qty`); + } + + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + if (v[`${repeatingString}name`] === name) { + callback(`@{${repeatingString}qty}`); + } + } + console.log(`cannot find ammo field by the name ${name}`); + }); + }); +}; + +const updateAction = (type, rowId) => { + const repeatingItem = `repeating_${type}`; + const collectionArray = ['pb', 'strength_mod', 'finesse_mod', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability']; + const finalSetAttrs = {}; + + const rechargeRegex = /\s*?\((?:Recharge\s*?(\d+\-\d+|\d+)|Recharges\safter\sa\s(.*))\)/gi; + const rechargeDayRegex = /\s*?\((\d+\/Day)\)/gi; + + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`${ABILITIES[i]}_mod`); + } + + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}type`); + collectionArray.push(`${repeatingString}roll_toggle`); + collectionArray.push(`${repeatingString}to_hit`); + collectionArray.push(`${repeatingString}attack_formula`); + collectionArray.push(`${repeatingString}proficiency`); + collectionArray.push(`${repeatingString}attack_ability`); + collectionArray.push(`${repeatingString}attack_bonus`); + collectionArray.push(`${repeatingString}saving_throw_toggle`); + collectionArray.push(`${repeatingString}saving_throw_ability`); + collectionArray.push(`${repeatingString}saving_throw_bonus`); + collectionArray.push(`${repeatingString}saving_throw_dc`); + collectionArray.push(`${repeatingString}damage_toggle`); + collectionArray.push(`${repeatingString}damage_formula`); + collectionArray.push(`${repeatingString}damage`); + collectionArray.push(`${repeatingString}damage_ability`); + collectionArray.push(`${repeatingString}damage_bonus`); + collectionArray.push(`${repeatingString}damage_type`); + collectionArray.push(`${repeatingString}second_damage_toggle`); + collectionArray.push(`${repeatingString}second_damage_formula`); + collectionArray.push(`${repeatingString}second_damage`); + collectionArray.push(`${repeatingString}second_damage_ability`); + collectionArray.push(`${repeatingString}second_damage_bonus`); + collectionArray.push(`${repeatingString}second_damage_type`); + collectionArray.push(`${repeatingString}damage_string`); + collectionArray.push(`${repeatingString}heal_toggle`); + collectionArray.push(`${repeatingString}heal`); + collectionArray.push(`${repeatingString}heal_ability`); + collectionArray.push(`${repeatingString}heal_bonus`); + collectionArray.push(`${repeatingString}heal_query_toggle`); + collectionArray.push(`${repeatingString}parsed`); + collectionArray.push(`${repeatingString}recharge`); + collectionArray.push(`${repeatingString}recharge_display`); + collectionArray.push(`${repeatingString}extras_toggle`); + collectionArray.push(`${repeatingString}freetext`); + } + + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + + const actionName = v[`${repeatingString}name`]; + if (!isUndefined(actionName)) { + const rechargeResult = rechargeRegex.exec(actionName); + if (rechargeResult) { + finalSetAttrs[`${repeatingString}recharge`] = rechargeResult[1] || rechargeResult[2]; + finalSetAttrs[`${repeatingString}name`] = actionName.replace(rechargeRegex, ''); + } + const rechargeDayResult = rechargeDayRegex.exec(actionName); + if (rechargeDayResult) { + finalSetAttrs[`${repeatingString}recharge`] = rechargeDayResult[1] || rechargeDayResult[2]; + finalSetAttrs[`${repeatingString}name`] = actionName.replace(rechargeDayRegex, ''); + } + } + const recharge = fromVOrFinalSetAttrs(v, finalSetAttrs, `${repeatingString}recharge`); + if (exists(recharge)) { + if (recharge.indexOf('/Day') !== -1 || recharge.indexOf('/day') !== -1) { + finalSetAttrs[`${repeatingString}recharge_display`] = ` (${recharge})`; + } else { + finalSetAttrs[`${repeatingString}recharge_display`] = ` (Recharge ${recharge})`; + } + } else if (exists(v[`${repeatingString}recharge_display`])) { + finalSetAttrs[`${repeatingString}recharge_display`] = ''; + } + + let attackOptions = {}; + if (type !== 'trait') { + attackOptions = { + defaultAbility: 'strength_mod', + globalAttackBonus: v.global_attack_bonus, + globalAttackBonusLabel: 'global attack bonus', + globalMeleeAttackBonus: v.global_melee_attack_bonus, + globalRangedAttackBonus: v.global_ranged_attack_bonus, + type: 'attack', + }; + } + updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions); + + updateSavingThrowToggle(v, finalSetAttrs, repeatingString); + + let damageOptions = {}; + if (type !== 'trait') { + damageOptions = { + defaultDamageAbility: 'strength_mod', + globalDamageBonus: v.global_damage_bonus, + globalMeleeDamageBonus: v.global_melee_damage_bonus, + globalRangedDamageBonus: v.global_ranged_damage_bonus, + type: 'attack', + }; + } + updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions); + + updateHealToggle(v, finalSetAttrs, repeatingString); + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:repeating_trait', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_trait', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'freetext' && repeatingInfo.field !== 'parsed' && repeatingInfo.field !== 'recharge_display') { + updateAction('trait', repeatingInfo.rowId); + } +}); +on('change:repeating_action', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_action', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'freetext' && repeatingInfo.field !== 'parsed' && repeatingInfo.field !== 'recharge_display') { + updateAction('action', repeatingInfo.rowId); + } +}); +on('change:repeating_reaction', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_reaction', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'freetext' && repeatingInfo.field !== 'parsed' && repeatingInfo.field !== 'recharge_display') { + updateAction('reaction', repeatingInfo.rowId); + } +}); +on('change:repeating_legendaryaction', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_legendaryaction', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'freetext' && repeatingInfo.field !== 'parsed' && repeatingInfo.field !== 'recharge_display') { + updateAction('legendaryaction', repeatingInfo.rowId); + } +}); +on('change:repeating_lairaction', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_lairaction', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'parsed' && repeatingInfo.field !== 'recharge_display') { + updateAction('lairaction', repeatingInfo.rowId); + } }); -on('change:repeating_attack', function (eventInfo) { - var changedField = getRepeatingField('repeating_attack', eventInfo); - if (changedField !== 'toggle_details' && changedField !== 'to_hit' && changedField !== 'attack_formula' && changedField !== 'damage_formula' && changedField !== 'second_damage_formula' && changedField !== 'damage_string' && changedField !== 'saving_throw_dc' && changedField !== 'parsed') { - var rowId = getRowId('repeating_attack', eventInfo); - updateAttack(rowId); - } - /*updateAttackQuery();*/ +const updateAttack = (rowId) => { + const repeatingItem = 'repeating_attack'; + const collectionArray = ['pb', 'strength_mod', 'finesse_mod', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability']; + const finalSetAttrs = {}; + + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`${ABILITIES[i]}_mod`); + } + + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}type`); + collectionArray.push(`${repeatingString}roll_toggle`); + collectionArray.push(`${repeatingString}to_hit`); + collectionArray.push(`${repeatingString}attack_formula`); + collectionArray.push(`${repeatingString}proficiency`); + collectionArray.push(`${repeatingString}attack_ability`); + collectionArray.push(`${repeatingString}attack_bonus`); + collectionArray.push(`${repeatingString}ammo_toggle_var`); + collectionArray.push(`${repeatingString}ammo_field_name`); + collectionArray.push(`${repeatingString}saving_throw_toggle`); + collectionArray.push(`${repeatingString}saving_throw_ability`); + collectionArray.push(`${repeatingString}saving_throw_bonus`); + collectionArray.push(`${repeatingString}saving_throw_dc`); + collectionArray.push(`${repeatingString}damage_toggle`); + collectionArray.push(`${repeatingString}damage_formula`); + collectionArray.push(`${repeatingString}damage`); + collectionArray.push(`${repeatingString}damage_ability`); + collectionArray.push(`${repeatingString}damage_bonus`); + collectionArray.push(`${repeatingString}damage_type`); + collectionArray.push(`${repeatingString}second_damage_toggle`); + collectionArray.push(`${repeatingString}second_damage_formula`); + collectionArray.push(`${repeatingString}second_damage`); + collectionArray.push(`${repeatingString}second_damage_ability`); + collectionArray.push(`${repeatingString}second_damage_bonus`); + collectionArray.push(`${repeatingString}second_damage_type`); + collectionArray.push(`${repeatingString}damage_string`); + collectionArray.push(`${repeatingString}modifiers`); + collectionArray.push(`${repeatingString}properties`); + collectionArray.push(`${repeatingString}weight`); + collectionArray.push(`${repeatingString}parsed`); + } + + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + + const attackName = v[`${repeatingString}name`]; + if (isUndefined(attackName)) { + return; + } + + if (isUndefined(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('modifiers') === -1) { + const attackModifiers = v[`${repeatingString}modifiers`]; + if (exists(attackModifiers)) { + const attackBonus = attackModifiers.replace(/.*(?:Melee|Ranged) Attacks \+(\d+).*/gi, '$1'); + const damageBonus = attackModifiers.replace(/.*(?:Melee|Ranged) Damage \+(\d+).*/gi, '$1'); + + finalSetAttrs[`${repeatingString}attack_bonus`] = attackBonus; + finalSetAttrs[`${repeatingString}damage_bonus`] = damageBonus; + if (!finalSetAttrs[`${repeatingString}parsed`]) { + finalSetAttrs[`${repeatingString}parsed`] = ''; + } + finalSetAttrs[`${repeatingString}parsed`] += ' modifiers'; + } + } + if (isUndefined(v[`${repeatingString}parsed`]) || v[`${repeatingString}parsed`].indexOf('attackProperties') === -1) { + const attackProperties = v[`${repeatingString}properties`]; + if (exists(attackProperties)) { + if (attackProperties.indexOf('Reach') !== -1) { + finalSetAttrs[`${repeatingString}reach`] = '10 ft'; + } else if (v[`${repeatingString}type`] === 'Melee Weapon') { + finalSetAttrs[`${repeatingString}reach`] = '5 ft'; + } + if (attackProperties.indexOf('Finesse') !== -1) { + finalSetAttrs[`${repeatingString}attack_ability`] = '@{finesse_mod}'; + finalSetAttrs[`${repeatingString}damage_ability`] = '@{finesse_mod}'; + } + if (!finalSetAttrs[`${repeatingString}parsed`]) { + finalSetAttrs[`${repeatingString}parsed`] = ''; + } + finalSetAttrs[`${repeatingString}parsed`] += ' attackProperties'; + } + } + + const attackOptions = { + defaultAbility: 'strength_mod', + globalAttackBonus: v.global_attack_bonus, + globalAttackBonusLabel: 'global attack bonus', + globalMeleeAttackBonus: v.global_melee_attack_bonus, + globalRangedAttackBonus: v.global_ranged_attack_bonus, + type: 'attack', + }; + updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions); + + const ammoName = v[`${repeatingString}ammo_field_name`]; + if (!isUndefined(ammoName)) { + findAmmo(ammoName, (ammoQtyName) => { + const setAmmo = {}; + setAmmo[`${repeatingString}ammo_toggle_var`] = `{{ammo=[[${ammoQtyName}-@{ammo_auto_use}]]}} {{ammo_name=${ammoName}}}`; + setFinalAttrs(v, setAmmo); + }); + } + + updateSavingThrowToggle(v, finalSetAttrs, repeatingString); + + const damageOptions = { + defaultDamageAbility: 'strength_mod', + globalDamageBonus: v.global_damage_bonus, + globalMeleeDamageBonus: v.global_melee_damage_bonus, + globalRangedDamageBonus: v.global_ranged_damage_bonus, + type: 'attack', + }; + updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions); + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:repeating_attack', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_attack', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'toggle_details' && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'parsed') { + updateAttack(repeatingInfo.row); + } }); -on('change:repeating_attack:carried change:repeating_attack:weight change:repeating_attack:ammo change:repeating_attack:ammo_weight remove:repeating_attack', function () { - var options = { - collection: 'attack', - toggle: 'carried', - qty: 'ammo' - }; - var sumItems = [ - { - addOnAfterQty: 'weight', - fieldToAdd: 'ammo_weight', - itemTotal: 'weight_total', - totalField: 'weight_attacks' - } - ]; - sumRepeating(options, sumItems); +on('change:repeating_attack:carried change:repeating_attack:weight remove:repeating_attack', () => { + const options = { + collection: 'attack', + toggle: 'carried', + }; + const sumItems = [ + { + fieldToAdd: 'weight', + itemTotal: 'weight_total', + totalField: 'weight_attacks', + }, + ]; + sumRepeating(options, sumItems); }); -on('change:global_attack_bonus change:global_melee_attack_bonus change:global_ranged_attack_bonus change:global_damage_bonus change:global_melee_damage_bonus change:global_ranged_damage_bonus', function () { - updateAttack(); +on('change:global_attack_bonus change:global_melee_attack_bonus change:global_ranged_attack_bonus change:global_damage_bonus change:global_melee_damage_bonus change:global_ranged_damage_bonus', () => { + updateAttack(); + updateAction('action'); + updateAction('reaction'); + updateAction('legendaryaction'); + updateAction('lairaction'); }); -function updateAttackToggle (v, finalSetAttrs, repeatingString, options) { - var attackParse = { - attackAbility: options.attackAbility, - parseName: 'attack', - toggleField: 'roll_toggle', - toggleFieldSetTo: '@{roll_toggle_var}', - triggerFields: ['type'] - }; - parseAttackComponent(v, repeatingString, finalSetAttrs, attackParse); - - var attackFormula = ''; - var attackToggle = v[repeatingString + 'roll_toggle']; - - var toHit = 0; - if (!attackToggle || attackToggle === '@{roll_toggle_var}') { - var proficiency = v[repeatingString + 'proficiency']; - if (!proficiency || proficiency === 'on') { - var pb = getIntValue(v.pb); - toHit += pb; - attackFormula += pb + '[proficient]'; - } else { - attackFormula += 0 + '[unproficient]'; - } - - if (isUndefined(v[repeatingString + 'ammo']) && isUndefined(finalSetAttrs[repeatingString + 'ammo_weight']) && v[repeatingString + 'type'] === 'Ranged Weapon') { - finalSetAttrs[repeatingString + 'ammo'] = '1'; - finalSetAttrs[repeatingString + 'ammo_weight'] = '.02'; - } - - var attackAbility = v[repeatingString + 'attack_ability']; - if (isUndefined(attackAbility) && v[repeatingString + 'type'] === 'Ranged Weapon') { - attackAbility = '@{dexterity_mod}'; - finalSetAttrs[repeatingString + 'attack_ability'] = attackAbility; - } else if (finalSetAttrs[repeatingString + 'attack_ability']) { - attackAbility = finalSetAttrs[repeatingString + 'attack_ability']; - } - attackAbility = getAbilityValue(v, attackAbility, options.defaultAbility); - if (exists(attackAbility)) { - toHit += attackAbility; - attackFormula += ADD + attackAbility + '[' + getAbilityShortName(v[repeatingString + 'attack_ability']) + ']'; - } - - var attackBonus = getIntValue(v[repeatingString + 'attack_bonus']); - if (exists(attackBonus)) { - toHit += attackBonus; - attackFormula += ADD + attackBonus + '[bonus]'; - } - - if (exists(options.globalAttackBonus)) { - if (!isNaN(options.globalAttackBonus)) { - toHit += getIntValue(options.globalAttackBonus); - } - attackFormula += ADD + options.globalAttackBonus + '[' + options.globalAttackBonusLabel + ']'; - } - - if (!v[repeatingString + 'type'] || v[repeatingString + 'type'] === 'Melee Weapon') { - if (exists(options.globalMeleeAttackBonus)) { - if (!isNaN(options.globalMeleeAttackBonus)) { - toHit += getIntValue(options.globalMeleeAttackBonus); - } - attackFormula += ADD + options.globalMeleeAttackBonus + '[global melee attack bonus]'; - } - } else if (v[repeatingString + 'type'] === 'Ranged Weapon') { - if (exists(options.globalRangedAttackBonus)) { - if (!isNaN(options.globalRangedAttackBonus)) { - toHit += getIntValue(options.globalRangedAttackBonus); - } - attackFormula += ADD + options.globalRangedAttackBonus + '[global ranged attack bonus]'; - } - } - } - if (options.type === 'attack') { - finalSetAttrs[repeatingString + 'to_hit'] = toHit; - } - finalSetAttrs[repeatingString + 'attack_formula'] = attackFormula; -} - -function updateSavingThrowToggle (v, finalSetAttrs, repeatingString, options) { - var savingThrowParse = { - parseName: 'savingThrow', - toggleField: 'saving_throw_toggle', - toggleFieldSetTo: '@{saving_throw_toggle_var}', - triggerFields: ['saving_throw_vs_ability'] - }; - parseAttackComponent(v, repeatingString, finalSetAttrs, savingThrowParse); - - var savingThrowToggle = v[repeatingString + 'saving_throw_toggle']; - if (savingThrowToggle === '@{saving_throw_toggle_var}') { - var savingThrowDC = 8 + getIntValue(v.pb); - var savingThrowAbility = v[repeatingString + 'saving_throw_ability']; - if (!savingThrowAbility && savingThrowAbility !== '0') { - savingThrowAbility = v.default_ability; - finalSetAttrs[repeatingString + 'saving_throw_ability'] = v.default_ability; - } - - savingThrowDC += getAbilityValue(v, savingThrowAbility, 'strength_mod'); - if (options && options.bonusDC) { - savingThrowDC += getIntValue(options.bonusDC); - } - savingThrowDC += getIntValue(v[repeatingString + 'saving_throw_bonus']); - finalSetAttrs[repeatingString + 'saving_throw_dc'] = savingThrowDC; - } -} - -function updateDamageToggle (v, finalSetAttrs, repeatingString, options) { - var damageParse = { - addCastingModifier: exists(v[repeatingString + 'add_casting_modifier']), - parseName: 'damage', - toggleField: 'damage_toggle', - toggleFieldSetTo: '@{damage_toggle_var}', - triggerFields: ['damage'] - }; - parseAttackComponent(v, repeatingString, finalSetAttrs, damageParse); - - var damageString = ''; - var damageFormula = ''; - var damageToggle = v[repeatingString + 'damage_toggle']; - var damageAbility; - var damageType; - - if (!damageToggle || damageToggle === '@{damage_toggle_var}') { - var damageAddition = 0; - - var damage = v[repeatingString + 'damage']; - if (exists(damage)) { - damageString += damage; - damageFormula += damage + '[damage]'; - } - - if (!options.defaultDamageAbility) { - options.defaultDamageAbility = 0; - } - - damageAbility = v[repeatingString + 'damage_ability']; - if (isUndefined(damageAbility) && v[repeatingString + 'type'] === 'Ranged Weapon') { - damageAbility = '@{dexterity_mod}'; - finalSetAttrs[repeatingString + 'damage_ability'] = damageAbility; - } - if (exists(damageAbility) || options.defaultDamageAbility) { - var damageAbilityValue = getAbilityValue(v, damageAbility, options.defaultDamageAbility); - if (exists(damageAbilityValue)) { - damageAddition += damageAbilityValue; - damageFormula += addOrSubtract(damageFormula, damageAbilityValue) + '[' + getAbilityShortName(v[repeatingString + 'damage_ability']) + ']'; - } - } - - var damageBonus = getIntValue(v[repeatingString + 'damage_bonus']); - if (exists(damageBonus)) { - damageAddition += damageBonus; - if (damageFormula !== '') { - damageFormula += ADD; - } - damageFormula += damageBonus + '[bonus]'; - } - - if (exists(options.globalDamageBonus)) { - if (!isNaN(options.globalDamageBonus)) { - damageAddition += getIntValue(options.globalDamageBonus); - } else { - damageString += ADD + options.globalDamageBonus; - } - damageFormula += ADD + options.globalDamageBonus + '[global damage bonus]'; - } - - if (options && options.globalMeleeDamageBonus && !v[repeatingString + 'type'] || v[repeatingString + 'type'] === 'Melee Weapon') { - if (!isNaN(options.globalMeleeDamageBonus)) { - damageAddition += getIntValue(options.globalMeleeDamageBonus); - } else { - damageString += ADD + options.globalMeleeDamageBonus; - } - if (damageFormula !== '') { - damageFormula += ADD; - } - damageFormula += options.globalMeleeDamageBonus + '[global melee damage bonus]'; - } else if (options && options.globalRangedDamageBonus && v[repeatingString + 'type'] === 'Ranged Weapon') { - if (!isNaN(options.globalRangedDamageBonus)) { - damageAddition += getIntValue(options.globalRangedDamageBonus); - } else { - damageString += ADD + options.globalRangedDamageBonus; - } - if (damageFormula !== '') { - damageFormula += ADD; - } - damageFormula += options.globalRangedDamageBonus + '[global ranged damage bonus]'; - } - - if (exists(damageAddition)) { - damageString += addOrSubtract(damageString, damageAddition); - } - - damageType = v[repeatingString + 'damage_type']; - if (exists(damageType)) { - if (hasUpperCase(damageType)) { - damageType = damageType.toLowerCase(); - finalSetAttrs[repeatingString + 'damage_type'] = damageType; - } - damageString += SPACE + damageType; - } - } - if (!exists(damageFormula)) { - damageFormula = 0; - } - finalSetAttrs[repeatingString + 'damage_formula'] = damageFormula; - - var secondDamageParse = { - parseName: 'secondDamage', - toggleField: 'second_damage_toggle', - toggleFieldSetTo: '@{second_damage_toggle_var}', - triggerFields: ['second_damage'] - }; - parseAttackComponent(v, repeatingString, finalSetAttrs, secondDamageParse); - - var secondDamageFormula = ''; - - var secondDamageToggle = fromVOrFinalSetAttrs(v, finalSetAttrs, repeatingString + 'second_damage_toggle'); - if (secondDamageToggle === '@{second_damage_toggle_var}') { - var secondDamageAddition = 0; - var secondDamage = v[repeatingString + 'second_damage']; - if (exists(secondDamage)) { - damageString += ADD + secondDamage; - secondDamageFormula += secondDamage + '[second damage]'; - } - - var secondDamageAbility = v[repeatingString + 'second_damage_ability']; - if (exists(secondDamageAbility)) { - secondDamageAbility = getAbilityValue(v, secondDamageAbility); - if (exists(secondDamageAbility)) { - secondDamageAddition += secondDamageAbility; - secondDamageFormula += addOrSubtract(secondDamageFormula, secondDamageAbility) + '[' + getAbilityShortName(v[repeatingString + 'second_damage_ability']) + ']'; - } - } - - var secondDamageBonus = getIntValue(v[repeatingString + 'second_damage_bonus']); - if (exists(secondDamageBonus)) { - secondDamageAddition += secondDamageBonus; - if (secondDamageFormula !== '') { - secondDamageFormula += ADD; - } - secondDamageFormula += secondDamageBonus + '[bonus]'; - } - - if (exists(secondDamageAddition)) { - damageString += addOrSubtract(damageString, secondDamageAddition); - } - - var secondDamageType = v[repeatingString + 'second_damage_type']; - if (exists(secondDamageType)) { - if (hasUpperCase(secondDamageType)) { - secondDamageType = secondDamageType.toLowerCase(); - finalSetAttrs[repeatingString + 'second_damage_type'] = secondDamageType; - } - damageString += SPACE + secondDamageType; - } - - if (isUndefined(v[repeatingString + 'parsed']) || v[repeatingString + 'parsed'].indexOf('damageProperties') === -1) { - var damageProperties = v[repeatingString + 'properties']; - if (exists(damageProperties)) { - if (damageProperties.indexOf('Versatile') !== -1) { - if (!exists(damageAbility)) { - damageAbility = '@{strength_mod}'; - } - finalSetAttrs[repeatingString + 'second_damage_ability'] = damageAbility; - finalSetAttrs[repeatingString + 'second_damage_type'] = damageType; - } - if (!finalSetAttrs[repeatingString + 'parsed']) { - finalSetAttrs[repeatingString + 'parsed'] = ''; - } - finalSetAttrs[repeatingString + 'parsed'] += ' damageProperties'; - } - } - - } - if (!exists(secondDamageFormula)) { - secondDamageFormula = 0; - } - finalSetAttrs[repeatingString + 'second_damage_formula'] = secondDamageFormula; - if (options.type === 'attack') { - finalSetAttrs[repeatingString + 'damage_string'] = damageString; - } -} - -function updateHealToggle (v, finalSetAttrs, repeatingString) { - var healParse = { - addCastingModifier: exists(v[repeatingString + 'add_casting_modifier']), - parseName: 'heal', - toggleField: 'heal_toggle', - toggleFieldSetTo: '@{heal_toggle_var}', - triggerFields: ['heal'] - }; - parseAttackComponent(v, repeatingString, finalSetAttrs, healParse); - - var healFormula = '@{heal}[heal]'; - var healToggle = v[repeatingString + 'heal_toggle']; - if (healToggle === '@{heal_toggle_var}') { - var healAbility = v[repeatingString + 'heal_ability']; - healAbility = getAbilityValue(v, healAbility); - if (exists(healAbility)) { - healFormula += ADD + healAbility + '[' + getAbilityShortName(v[repeatingString + 'heal_ability']) + ']'; - } - - var healBonus = getIntValue(v[repeatingString + 'heal_bonus']); - if (exists(healBonus)) { - healFormula += ADD + healBonus + '[bonus]'; - } - - if (exists(v.global_spell_heal_bonus)) { - healFormula += ADD + '@{global_spell_heal_bonus}[global spell heal bonus]'; - } - - finalSetAttrs[repeatingString + 'heal_formula'] = healFormula; - } -} - -function updateHigherLevelToggle (v, finalSetAttrs, repeatingString) { - var higherLevelParse = { - addCastingModifier: exists(v[repeatingString + 'add_casting_modifier']), - parseName: 'higherLevel', - toggleField: 'higher_level_toggle', - toggleFieldSetTo: '@{higher_level_toggle_var}', - triggerFields: ['higher_level_dice', 'higher_level_die', 'second_higher_level_dice', 'second_higher_level_die', 'higher_level_heal'] - }; - parseAttackComponent(v, repeatingString, finalSetAttrs, higherLevelParse); - - var higherLevelToggle = v[repeatingString + 'higher_level_toggle']; - if (exists(higherLevelToggle) && higherLevelToggle === '@{higher_level_toggle_var}') { - var spellLevelQuery = '?{Spell Level'; - - var spellLevel = getIntValue(v[repeatingString + 'spell_level']); - for (var i = spellLevel; i <= 9; i++) { - spellLevelQuery += '|' + i; - } - spellLevelQuery += '}'; - finalSetAttrs[repeatingString + 'higher_level_query'] = spellLevelQuery; - - var damageToggle = v[repeatingString + 'damage_toggle']; - if (damageToggle && damageToggle === '@{damage_toggle_var}') { - finalSetAttrs[repeatingString + 'damage_formula'] += ADD + '((@{higher_level_query} - @{spell_level}) * @{higher_level_dice})@{higher_level_die}[higher lvl]'; - } - - var secondDamageToggle = v[repeatingString + 'second_damage_toggle']; - if (secondDamageToggle && secondDamageToggle === '@{second_damage_toggle_var}') { - finalSetAttrs[repeatingString + 'second_damage_formula'] += ADD + '((@{higher_level_query} - @{spell_level}) * @{second_higher_level_dice})@{second_higher_level_die}[higher lvl]'; - } - - var healToggle = v[repeatingString + 'heal_toggle']; - if (healToggle && healToggle === '@{heal_toggle_var}') { - finalSetAttrs[repeatingString + 'heal_formula'] += ADD + '((@{higher_level_query} - @{spell_level}) * @{higher_level_dice})@{higher_level_die}[higher lvl] + (@{higher_level_heal} * (@{higher_level_query} - @{spell_level}))[higher lvl flat amount]'; - } - } -} - -function updateAttackQuery () { - var repeatingItem = 'repeating_attack'; - var collectionArray = []; - var finalSetAttrs = {}; - - finalSetAttrs.attack_query_var = '?{Attack'; - - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'reach'); - collectionArray.push(repeatingString + 'range'); - collectionArray.push(repeatingString + 'ammo'); - collectionArray.push(repeatingString + 'to_hit'); - collectionArray.push(repeatingString + 'attack_formula'); - collectionArray.push(repeatingString + 'roll_toggle'); - collectionArray.push(repeatingString + 'saving_throw_toggle'); - collectionArray.push(repeatingString + 'damage_toggle'); - collectionArray.push(repeatingString + 'reach'); - collectionArray.push(repeatingString + 'second_damage_toggle'); - collectionArray.push(repeatingString + 'extras_toggle'); - } - - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; - - finalSetAttrs.attack_query_var += '|' + v[repeatingString + 'name'] + ','; - finalSetAttrs.attack_query_var += ' {{title=' + v[repeatingString + 'name'] + '}}'; - finalSetAttrs.attack_query_var += '{{reach=' + emptyIfUndefined(v[repeatingString + 'reach']) + '}}'; - finalSetAttrs.attack_query_var += '{{range=' + emptyIfUndefined(v[repeatingString + 'range']) + '}}'; - finalSetAttrs.attack_query_var += '{{ammo=' + emptyIfUndefined(v[repeatingString + 'ammo']) + '}}'; - finalSetAttrs.attack_query_var += '' + emptyIfUndefined(v[repeatingString + 'roll_toggle']); - finalSetAttrs.attack_query_var += '' + emptyIfUndefined(v[repeatingString + 'saving_throw_toggle']); - finalSetAttrs.attack_query_var += '' + emptyIfUndefined(v[repeatingString + 'damage_toggle']); - finalSetAttrs.attack_query_var += '' + emptyIfUndefined(v[repeatingString + 'second_damage_toggle']); - finalSetAttrs.attack_query_var += '' + emptyIfUndefined(v[repeatingString + 'extras_toggle']); - } - finalSetAttrs.attack_query_var += '}'; - setFinalAttrs(v, finalSetAttrs); - }); - }); -} - -function updateAttack (rowId) { - var repeatingItem = 'repeating_attack'; - var collectionArray = ['pb', 'strength_mod', 'finesse_mod', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability']; - var finalSetAttrs = {}; - - for (var i = 0; i < ABILITIES.length; i++) { - collectionArray.push(ABILITIES[i] + '_mod'); - } - - getSectionIDs(repeatingItem, function (ids) { - if (rowId) { - ids = []; - ids.push(rowId); - } - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'type'); - collectionArray.push(repeatingString + 'roll_toggle'); - collectionArray.push(repeatingString + 'to_hit'); - collectionArray.push(repeatingString + 'attack_formula'); - collectionArray.push(repeatingString + 'proficiency'); - collectionArray.push(repeatingString + 'attack_ability'); - collectionArray.push(repeatingString + 'attack_bonus'); - collectionArray.push(repeatingString + 'saving_throw_toggle'); - collectionArray.push(repeatingString + 'saving_throw_ability'); - collectionArray.push(repeatingString + 'saving_throw_bonus'); - collectionArray.push(repeatingString + 'saving_throw_dc'); - collectionArray.push(repeatingString + 'damage_toggle'); - collectionArray.push(repeatingString + 'damage_formula'); - collectionArray.push(repeatingString + 'damage'); - collectionArray.push(repeatingString + 'damage_ability'); - collectionArray.push(repeatingString + 'damage_bonus'); - collectionArray.push(repeatingString + 'damage_type'); - collectionArray.push(repeatingString + 'second_damage_toggle'); - collectionArray.push(repeatingString + 'second_damage_formula'); - collectionArray.push(repeatingString + 'second_damage'); - collectionArray.push(repeatingString + 'second_damage_ability'); - collectionArray.push(repeatingString + 'second_damage_bonus'); - collectionArray.push(repeatingString + 'second_damage_type'); - collectionArray.push(repeatingString + 'damage_string'); - collectionArray.push(repeatingString + 'modifiers'); - collectionArray.push(repeatingString + 'properties'); - collectionArray.push(repeatingString + 'weight'); - collectionArray.push(repeatingString + 'ammo'); - collectionArray.push(repeatingString + 'ammo_weight'); - collectionArray.push(repeatingString + 'parsed'); - } - - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; - - var attackName = v[repeatingString + 'name']; - if (isUndefined(attackName)) { - return; - } - - if (isUndefined(v[repeatingString + 'parsed']) || v[repeatingString + 'parsed'].indexOf('modifiers') === -1) { - var attackModifiers = v[repeatingString + 'modifiers']; - if (exists(attackModifiers)) { - var attackBonus = attackModifiers.replace(/.*(?:Melee|Ranged) Attacks \+(\d+).*/gi, '$1'); - var damageBonus = attackModifiers.replace(/.*(?:Melee|Ranged) Damage \+(\d+).*/gi, '$1'); - - finalSetAttrs[repeatingString + 'attack_bonus'] = attackBonus; - finalSetAttrs[repeatingString + 'damage_bonus'] = damageBonus; - if (!finalSetAttrs[repeatingString + 'parsed']) { - finalSetAttrs[repeatingString + 'parsed'] = ''; - } - finalSetAttrs[repeatingString + 'parsed'] += ' modifiers'; - } - } - if (isUndefined(v[repeatingString + 'parsed']) || v[repeatingString + 'parsed'].indexOf('attackProperties') === -1) { - var attackProperties = v[repeatingString + 'properties']; - if (exists(attackProperties)) { - if (attackProperties.indexOf('Reach') !== -1) { - finalSetAttrs[repeatingString + 'reach'] = '10 ft'; - } else if (v[repeatingString + 'type'] === 'Melee Weapon') { - finalSetAttrs[repeatingString + 'reach'] = '5 ft'; - } - if (attackProperties.indexOf('Finesse') !== -1) { - finalSetAttrs[repeatingString + 'attack_ability'] = '@{finesse_mod}'; - finalSetAttrs[repeatingString + 'damage_ability'] = '@{finesse_mod}'; - } - if (attackProperties.indexOf('Thrown') !== -1) { - var ammoWeight = parseFloat(v[repeatingString + 'weight']); - finalSetAttrs[repeatingString + 'ammo'] = 1; - finalSetAttrs[repeatingString + 'ammo_weight'] = ammoWeight; - finalSetAttrs[repeatingString + 'weight'] = 0; - } - if (!finalSetAttrs[repeatingString + 'parsed']) { - finalSetAttrs[repeatingString + 'parsed'] = ''; - } - finalSetAttrs[repeatingString + 'parsed'] += ' attackProperties'; - } - } - - var attackOptions = { - defaultAbility: 'strength_mod', - globalAttackBonus: v.global_attack_bonus, - globalAttackBonusLabel: 'global attack bonus', - globalMeleeAttackBonus: v.global_melee_attack_bonus, - globalRangedAttackBonus: v.global_ranged_attack_bonus, - type: 'attack' - }; - updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions); - - updateSavingThrowToggle(v, finalSetAttrs, repeatingString); - - var damageOptions = { - defaultDamageAbility: 'strength_mod', - globalDamageBonus: v.global_damage_bonus, - globalMeleeDamageBonus: v.global_melee_damage_bonus, - globalRangedDamageBonus: v.global_ranged_damage_bonus, - type: 'attack' - }; - updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions); - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} - -function updateSpell (rowId) { - var repeatingItem = 'repeating_spell'; - var collectionArray = ['pb', 'finesse_mod', 'global_spell_attack_bonus', 'global_spell_damage_bonus', 'global_spell_dc_bonus', 'global_spell_heal_bonus', 'default_ability']; - var finalSetAttrs = {}; - - for (var i = 0; i < ABILITIES.length; i++) { - collectionArray.push(ABILITIES[i] + '_mod'); - } - - getSectionIDs(repeatingItem, function (ids) { - if (rowId) { - ids = []; - ids.push(rowId); - } - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'type'); - collectionArray.push(repeatingString + 'roll_toggle'); - collectionArray.push(repeatingString + 'to_hit'); - collectionArray.push(repeatingString + 'attack_formula'); - collectionArray.push(repeatingString + 'proficiency'); - collectionArray.push(repeatingString + 'attack_ability'); - collectionArray.push(repeatingString + 'attack_bonus'); - collectionArray.push(repeatingString + 'saving_throw_toggle'); - collectionArray.push(repeatingString + 'saving_throw_ability'); - collectionArray.push(repeatingString + 'saving_throw_vs_ability'); - collectionArray.push(repeatingString + 'saving_throw_bonus'); - collectionArray.push(repeatingString + 'saving_throw_dc'); - collectionArray.push(repeatingString + 'damage_toggle'); - collectionArray.push(repeatingString + 'damage_formula'); - collectionArray.push(repeatingString + 'damage'); - collectionArray.push(repeatingString + 'damage_ability'); - collectionArray.push(repeatingString + 'damage_bonus'); - collectionArray.push(repeatingString + 'damage_type'); - collectionArray.push(repeatingString + 'second_damage_toggle'); - collectionArray.push(repeatingString + 'second_damage_formula'); - collectionArray.push(repeatingString + 'second_damage'); - collectionArray.push(repeatingString + 'second_damage_ability'); - collectionArray.push(repeatingString + 'second_damage_bonus'); - collectionArray.push(repeatingString + 'second_damage_type'); - collectionArray.push(repeatingString + 'damage_string'); - collectionArray.push(repeatingString + 'parsed'); - collectionArray.push(repeatingString + 'spell_level'); - collectionArray.push(repeatingString + 'casting_time'); - collectionArray.push(repeatingString + 'components'); - collectionArray.push(repeatingString + 'heal_toggle'); - collectionArray.push(repeatingString + 'heal'); - collectionArray.push(repeatingString + 'heal_ability'); - collectionArray.push(repeatingString + 'heal_bonus'); - collectionArray.push(repeatingString + 'add_casting_modifier'); - collectionArray.push(repeatingString + 'higher_level_toggle'); - collectionArray.push(repeatingString + 'higher_level_dice'); - collectionArray.push(repeatingString + 'higher_level_die'); - collectionArray.push(repeatingString + 'second_higher_level_dice'); - collectionArray.push(repeatingString + 'second_higher_level_die'); - collectionArray.push(repeatingString + 'higher_level_heal'); - collectionArray.push(repeatingString + 'components_verbal'); - collectionArray.push(repeatingString + 'components_somatic'); - collectionArray.push(repeatingString + 'components_material'); - collectionArray.push(repeatingString + 'duration'); - collectionArray.push(repeatingString + 'concentration'); - collectionArray.push(repeatingString + 'concentration_text'); - } - - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; - - var spellLevel = getIntValue(v[repeatingString + 'spell_level']); - if (spellLevel === 0) { - finalSetAttrs[repeatingString + 'spell_level'] = spellLevel; - } - if (spellLevel === 0) { - finalSetAttrs[repeatingString + 'is_prepared'] = 'on'; - } - finalSetAttrs[repeatingString + 'friendly_level'] = ordinalSpellLevel(spellLevel); - - var concentration = v[repeatingString + 'concentration']; - if (concentration === 'Yes') { - finalSetAttrs[repeatingString + 'concentration_text'] = 'Concentration, '; - } else { - finalSetAttrs[repeatingString + 'concentration_text'] = ''; - } - if (v.duration) { - finalSetAttrs.duration = lowercaseWords(v.duration); - } - - var spellComponents = v[repeatingString + 'components']; - finalSetAttrs[repeatingString + 'components_verbal'] = 0; - finalSetAttrs[repeatingString + 'components_somatic'] = 0; - finalSetAttrs[repeatingString + 'components_material'] = 0; - if (exists(spellComponents)) { - if (spellComponents.indexOf('V') !== -1) { - finalSetAttrs[repeatingString + 'components_verbal'] = 1; - } - if (spellComponents.indexOf('S') !== -1) { - finalSetAttrs[repeatingString + 'components_somatic'] = 1; - } - if (spellComponents.indexOf('M') !== -1) { - finalSetAttrs[repeatingString + 'components_material'] = 1; - } - } - - var attackOptions = { - attackAbility: true, - globalAttackBonus: v.global_spell_attack_bonus, - type: 'spell' - }; - updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions); - - var savingThrowOptions = { - bonusDC: v.global_spell_dc_bonus - }; - updateSavingThrowToggle(v, finalSetAttrs, repeatingString, savingThrowOptions); - - var damageOptions = { - globalDamageBonus: v.global_spell_damage_bonus, - type: 'spell' - }; - updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions); - - updateHealToggle(v, finalSetAttrs, repeatingString); - - updateHigherLevelToggle(v, finalSetAttrs, repeatingString); - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} - -on('change:repeating_spell', function (eventInfo) { - var changedField = getRepeatingField('repeating_spell', eventInfo); - if (changedField !== 'toggle_details' && changedField !== 'to_hit' && changedField !== 'attack_formula' && changedField !== 'damage_formula' && changedField !== 'second_damage_formula' && changedField !== 'damage_string' && changedField !== 'saving_throw_dc' && changedField !== 'heal_formula' && changedField !== 'higher_level_query' && changedField !== 'parsed') { - console.log('spell changedField', changedField); - var rowId = getRowId('repeating_spell', eventInfo); - updateSpell(rowId); - } +const updateSpell = (rowId) => { + const repeatingItem = 'repeating_spell'; + const collectionArray = ['is_npc', 'pb', 'finesse_mod', 'global_spell_attack_bonus', 'global_spell_damage_bonus', 'global_spell_dc_bonus', 'global_spell_heal_bonus', 'default_ability', 'caster_level']; + const finalSetAttrs = {}; + + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`${ABILITIES[i]}_mod`); + } + + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}type`); + collectionArray.push(`${repeatingString}roll_toggle`); + collectionArray.push(`${repeatingString}to_hit`); + collectionArray.push(`${repeatingString}attack_formula`); + collectionArray.push(`${repeatingString}proficiency`); + collectionArray.push(`${repeatingString}attack_ability`); + collectionArray.push(`${repeatingString}attack_bonus`); + collectionArray.push(`${repeatingString}saving_throw_toggle`); + collectionArray.push(`${repeatingString}saving_throw_ability`); + collectionArray.push(`${repeatingString}saving_throw_vs_ability`); + collectionArray.push(`${repeatingString}saving_throw_bonus`); + collectionArray.push(`${repeatingString}saving_throw_dc`); + collectionArray.push(`${repeatingString}damage_toggle`); + collectionArray.push(`${repeatingString}damage_formula`); + collectionArray.push(`${repeatingString}damage`); + collectionArray.push(`${repeatingString}damage_ability`); + collectionArray.push(`${repeatingString}damage_bonus`); + collectionArray.push(`${repeatingString}damage_type`); + collectionArray.push(`${repeatingString}second_damage_toggle`); + collectionArray.push(`${repeatingString}second_damage_formula`); + collectionArray.push(`${repeatingString}second_damage`); + collectionArray.push(`${repeatingString}second_damage_ability`); + collectionArray.push(`${repeatingString}second_damage_bonus`); + collectionArray.push(`${repeatingString}second_damage_type`); + collectionArray.push(`${repeatingString}damage_string`); + collectionArray.push(`${repeatingString}parsed`); + collectionArray.push(`${repeatingString}spell_level`); + collectionArray.push(`${repeatingString}casting_time`); + collectionArray.push(`${repeatingString}components`); + collectionArray.push(`${repeatingString}heal_toggle`); + collectionArray.push(`${repeatingString}heal`); + collectionArray.push(`${repeatingString}heal_ability`); + collectionArray.push(`${repeatingString}heal_bonus`); + collectionArray.push(`${repeatingString}heal_query_toggle`); + collectionArray.push(`${repeatingString}add_casting_modifier`); + collectionArray.push(`${repeatingString}higher_level_toggle`); + collectionArray.push(`${repeatingString}higher_level_dice`); + collectionArray.push(`${repeatingString}higher_level_die`); + collectionArray.push(`${repeatingString}second_higher_level_dice`); + collectionArray.push(`${repeatingString}second_higher_level_die`); + collectionArray.push(`${repeatingString}higher_level_heal`); + collectionArray.push(`${repeatingString}components_verbal`); + collectionArray.push(`${repeatingString}components_somatic`); + collectionArray.push(`${repeatingString}components_material`); + collectionArray.push(`${repeatingString}duration`); + collectionArray.push(`${repeatingString}concentration`); + collectionArray.push(`${repeatingString}concentration_text`); + } + + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + + const spellLevel = getIntValue(v[`${repeatingString}spell_level`]); + if (spellLevel === 0) { + finalSetAttrs[`${repeatingString}spell_level`] = spellLevel; + } + if (spellLevel === 0) { + finalSetAttrs[`${repeatingString}is_prepared`] = 'on'; + } + finalSetAttrs[`${repeatingString}friendly_level`] = ordinalSpellLevel(spellLevel); + + const concentration = v[`${repeatingString}concentration`]; + if (concentration === 'Yes') { + finalSetAttrs[`${repeatingString}concentration_text`] = 'Concentration, '; + } else { + finalSetAttrs[`${repeatingString}concentration_text`] = ''; + } + if (v.duration) { + finalSetAttrs.duration = lowercaseWords(v.duration); + } + + const spellComponents = v[`${repeatingString}components`]; + finalSetAttrs[`${repeatingString}components_verbal`] = 0; + finalSetAttrs[`${repeatingString}components_somatic`] = 0; + finalSetAttrs[`${repeatingString}components_material`] = 0; + if (exists(spellComponents)) { + if (spellComponents.indexOf('V') !== -1) { + finalSetAttrs[`${repeatingString}components_verbal`] = 1; + } + if (spellComponents.indexOf('S') !== -1) { + finalSetAttrs[`${repeatingString}components_somatic`] = 1; + } + if (spellComponents.indexOf('M') !== -1) { + finalSetAttrs[`${repeatingString}components_material`] = 1; + } + } + + const attackOptions = { + attackAbility: true, + globalAttackBonus: v.global_spell_attack_bonus, + type: 'spell', + }; + updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions); + + const savingThrowOptions = { + bonusDC: v.global_spell_dc_bonus, + }; + updateSavingThrowToggle(v, finalSetAttrs, repeatingString, savingThrowOptions); + + const damageOptions = { + globalDamageBonus: v.global_spell_damage_bonus, + type: 'spell', + }; + updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions); + + if (getIntValue(v.is_npc) === 1 && v.caster_level && v[`${repeatingString}damage`] && v[`${repeatingString}damage`].indexOf('@{level}') !== -1) { + finalSetAttrs[`${repeatingString}damage`] = v[`${repeatingString}damage`].replace('@{level}', '@{caster_level}'); + } + + updateHealToggle(v, finalSetAttrs, repeatingString); + + updateHigherLevelToggle(v, finalSetAttrs, repeatingString); + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:repeating_spell', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_spell', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'toggle_details' && repeatingInfo.field !== 'to_hit' && repeatingInfo.field !== 'attack_formula' && repeatingInfo.field !== 'damage_formula' && repeatingInfo.field !== 'second_damage_formula' && repeatingInfo.field !== 'damage_string' && repeatingInfo.field !== 'saving_throw_dc' && repeatingInfo.field !== 'heal_formula' && repeatingInfo.field !== 'higher_level_query' && repeatingInfo.field !== 'parsed') { + console.log('spell repeatingInfo.field', repeatingInfo.field); + updateSpell(repeatingInfo.rowId); + } }); -on('change:global_spell_attack_bonus change:global_spell_damage_bonus change:global_spell_dc_bonus change:global_spell_heal_bonus', function () { - updateSpell(); +on('change:global_spell_attack_bonus change:global_spell_damage_bonus change:global_spell_dc_bonus change:global_spell_heal_bonus', () => { + updateSpell(); }); -function updateD20Mod () { - var collectionArray = ['halfling_luck']; - var finalSetAttrs = {}; +const updateClassFeature = (rowId) => { + const repeatingItem = 'repeating_classfeature'; + const collectionArray = ['pb', 'finesse_mod', 'default_ability']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - if (v.halfling_luck === 'on') { - finalSetAttrs.d20_mod = 'ro<1[halfling luck]'; - } else { - finalSetAttrs.d20_mod = ''; - } - setFinalAttrs(v, finalSetAttrs); - }); -} + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`${ABILITIES[i]}_mod`); + } -on('change:halfling_luck', function () { - updateD20Mod(); + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}saving_throw_toggle`); + collectionArray.push(`${repeatingString}saving_throw_ability`); + collectionArray.push(`${repeatingString}saving_throw_vs_ability`); + collectionArray.push(`${repeatingString}saving_throw_bonus`); + collectionArray.push(`${repeatingString}saving_throw_dc`); + collectionArray.push(`${repeatingString}damage_toggle`); + collectionArray.push(`${repeatingString}damage_formula`); + collectionArray.push(`${repeatingString}damage`); + collectionArray.push(`${repeatingString}damage_ability`); + collectionArray.push(`${repeatingString}damage_bonus`); + collectionArray.push(`${repeatingString}damage_type`); + collectionArray.push(`${repeatingString}second_damage_toggle`); + collectionArray.push(`${repeatingString}second_damage_formula`); + collectionArray.push(`${repeatingString}second_damage`); + collectionArray.push(`${repeatingString}second_damage_ability`); + collectionArray.push(`${repeatingString}second_damage_bonus`); + collectionArray.push(`${repeatingString}second_damage_type`); + collectionArray.push(`${repeatingString}damage_string`); + collectionArray.push(`${repeatingString}heal_toggle`); + collectionArray.push(`${repeatingString}heal`); + collectionArray.push(`${repeatingString}heal_ability`); + collectionArray.push(`${repeatingString}heal_bonus`); + collectionArray.push(`${repeatingString}heal_query_toggle`); + collectionArray.push(`${repeatingString}add_casting_modifier`); + } + + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + + const damageOptions = { + type: 'attack', + }; + updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions); + const savingThrowOptions = {}; + updateSavingThrowToggle(v, finalSetAttrs, repeatingString, savingThrowOptions); + updateHealToggle(v, finalSetAttrs, repeatingString); + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:repeating_classfeature', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_classfeature', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'toggle_extras' && repeatingInfo.field !== 'heal_formula' && repeatingInfo.field !== 'freetext' && repeatingInfo.field !== 'freeform') { + console.log('class feature repeatingInfo.field', repeatingInfo.field); + updateClassFeature(repeatingInfo.rowId); + } }); -function updateAbilityChecksMacro () { - var repeatingItem = 'repeating_skill'; - var collectionArray = ['ability_checks_query_var', 'ability_checks_macro_var']; - var finalSetAttrs = {}; +const updateClassFeatureToggleToNewVer = () => { + const repeatingItem = 'repeating_classfeature'; + const collectionArray = []; + const finalSetAttrs = {}; - finalSetAttrs.ability_checks_query_var = '?{Ability Check'; - finalSetAttrs.ability_checks_macro_var = ''; + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}heal_toggle`); + } - for (var i = 0; i < ABILITIES.length; i++) { - finalSetAttrs.ability_checks_query_var += '|' + ABILITIES[i].capitalize() + ', {{title=' + ABILITIES[i].capitalize() + '}} {{roll1=[[d20@{d20_mod} + @{' + ABILITIES[i] + '_check_mod}]]}} {{roll2=[[d20@{d20_mod} + @{' + ABILITIES[i] + '_check_mod}]]}}'; - finalSetAttrs.ability_checks_macro_var += '[' + ABILITIES[i].capitalize() + '](~' + ABILITIES[i] + '_check)'; - if (i < ABILITIES.length - 1) { - finalSetAttrs.ability_checks_macro_var += ', '; - } - } + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'ability'); - } + const healToggled = v[`${repeatingString}heal_toggle`]; + if (!isUndefined(healToggled)) { + updateClassFeature(); + return; + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; - finalSetAttrs.ability_checks_query_var += '|' + v[repeatingString + 'name'] + ', {{title=' + v[repeatingString + 'name'] + ' (' + getAbilityShortName(v[repeatingString + 'ability']).capitalize() + ')}} {{roll1=[[d20@{d20_mod} + @{' + repeatingString + 'formula' + '}]]}} {{roll2=[[d20@{d20_mod} + @{' + repeatingString + 'formula' + '}]]}}'; - finalSetAttrs.ability_checks_macro_var += ', '; - finalSetAttrs.ability_checks_macro_var += '[' + v[repeatingString + 'name'] + '](~repeating_skill_' + ids[j] + '_skill)'; - } - finalSetAttrs.ability_checks_query_var += '}'; - setFinalAttrs(v, finalSetAttrs); - }); - }); -} +function updateD20Mod() { + const collectionArray = ['halfling_luck']; + const finalSetAttrs = {}; -function updateSkill (rowId) { - var repeatingItem = 'repeating_skill'; - var collectionArray = ['jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'pb', 'exp', 'global_check_bonus']; - var finalSetAttrs = {}; - - for (var i = 0; i < ABILITIES.length; i++) { - collectionArray.push(ABILITIES[i] + '_mod'); - collectionArray.push(ABILITIES[i] + '_check_bonus'); - } - - getSectionIDs(repeatingItem, function (ids) { - if (rowId) { - ids = []; - ids.push(rowId); - } - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'proficiency'); - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'ability'); - collectionArray.push(repeatingString + 'bonus'); - } - - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; - - var skillName = v[repeatingString + 'name']; - if (isUndefined(skillName)) { - return; - } - - var ability = getAbilityModName(v[repeatingString + 'ability']); - var abilityName = getAbilityName(v[repeatingString + 'ability']); - finalSetAttrs[repeatingString + 'ability_short_name'] = getAbilityShortName(ability, true); - - var total = 0; - var totalFormula = ''; - var proficiency = v[repeatingString + 'proficiency']; - if (!proficiency || proficiency === 'unproficient') { - if ((abilityName === 'strength' || abilityName === 'dexterity' || abilityName === 'constitution') && v.remarkable_athlete_toggle === '@{remarkable_athlete}') { - var remarkableAthlete = getIntValue(v.remarkable_athlete); - total += remarkableAthlete; - totalFormula += remarkableAthlete + '[remarkable athlete]'; - } else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') { - var jackOfAllTrades = getIntValue(v.jack_of_all_trades); - total += jackOfAllTrades; - totalFormula += jackOfAllTrades + '[jack of all trades]'; - } else { - totalFormula += 0 + '[unproficient]'; - } - } else if (proficiency === 'proficient') { - var pb = getIntValue(v.pb); - total += pb; - totalFormula += pb + '[proficient]'; - } else if (proficiency === 'expertise') { - var exp = getIntValue(v.exp); - total += exp; - totalFormula += exp + '[expertise]'; - } - - var skillAbility = getAbilityValue(v, ability, 'strength_mod'); - if (exists(skillAbility)) { - total += skillAbility; - totalFormula += ADD + skillAbility + '[' + getAbilityShortName(ability) + ']'; - } - - var skillBonus = getIntValue(v[repeatingString + 'bonus']); - if (exists(skillBonus)) { - total += skillBonus; - totalFormula += ADD + skillBonus + '[bonus]'; - } - - var skillAbilityName = getAbilityName(ability); - if (exists(skillAbilityName)) { - var checkBonus = v[skillAbilityName + '_check_bonus']; - if (exists(checkBonus)) { - checkBonus = getIntValue(checkBonus); - total += checkBonus; - totalFormula += ADD + checkBonus + '[' + getAbilityShortName(ability) + ' check bonus]'; - } - } - - var globalCheckBonus = v.global_check_bonus; - if (exists(globalCheckBonus)) { - if (!isNaN(globalCheckBonus)) { - total += getIntValue(globalCheckBonus); - } - totalFormula += ADD + globalCheckBonus + '[global check bonus]'; - } - - var totalWithSign = total; - if (total >= 0) { - totalWithSign = '+' + total; - } - - finalSetAttrs[repeatingString + 'total'] = total; - finalSetAttrs[repeatingString + 'total_with_sign'] = totalWithSign; - finalSetAttrs[repeatingString + 'formula'] = totalFormula; - } - setFinalAttrs(v, finalSetAttrs); - updateAbilityChecksMacro(); - }); - }); -} - -on('change:repeating_skill', function (eventInfo) { - var changedField = getRepeatingField('repeating_skill', eventInfo); - if (changedField !== 'ability_short_name' && changedField !== 'total' && changedField !== 'total_with_sign' && changedField !== 'formula') { - var rowId = getRowId('repeating_skill', eventInfo); - updateSkill(rowId); - } -}); -on('remove:repeating_skill', function () { - updateAbilityChecksMacro(); -}); -on('change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_check_bonus change:strength_check_bonus change:dexterity_check_bonus change:constitution_check_bonus change:intelligence_check_bonus change:wisdom_check_bonus change:charisma_check_bonus', function () { - updateSkill(); -}); - -function updateSkillsFromSRD () { - var repeatingItem = 'repeating_skill'; - var collectionArray = ['skills_srd', 'level', 'challenge', 'strength_mod', 'dexterity_mod', 'constitution_mod', 'intelligence_mod', 'wisdom_mod', 'charisma_mod']; - var finalSetAttrs = {}; - - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'ability'); - } - getAttrs(collectionArray, function (v) { - var skillsFromSRD = v.skills_srd; - var skillsObj = {}; - var pb = getPB(v.level, v.challenge); - var expertise = pb * 2; - var skillName; - var repeatingString; - - if (!isUndefined(skillsFromSRD)) { - for (var j = 0; j < ids.length; j++) { - repeatingString = repeatingItem + '_' + ids[j] + '_'; - skillName = v[repeatingString + 'name']; - skillsObj[skillName] = ids[j]; - } - - var re = /(\w+)\s?((?:\+|\-)\d+)/gi; - while (match = re.exec(skillsFromSRD)) { - if (match && match[1] && match[2]) { - skillName = match[1]; - if (skillsObj[skillName]) { - var skillId = skillsObj[skillName]; - repeatingString = repeatingItem + '_' + skillId + '_'; - - var skillAbility = v[repeatingString + 'ability']; - var abilityValue = getAbilityValue(v, skillAbility); - var skillBonus = getIntValue(match[2]) - abilityValue; - - if (skillBonus >= expertise) { - finalSetAttrs[repeatingString + 'proficiency'] = 'expertise'; - if (skillBonus > expertise) { - finalSetAttrs[repeatingString + 'bonus'] = skillBonus - expertise; - } - } else if (skillBonus >= pb) { - finalSetAttrs[repeatingString + 'proficiency'] = 'proficient'; - if (skillBonus > pb) { - finalSetAttrs[repeatingString + 'bonus'] = skillBonus - pb; - } - } - } else { - console.log(skillName + ' does not exist in the list of skills'); - } - } - } - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} -on('change:skills_srd', function () { - updateSkillsFromSRD(); -}); - -function updateSavingThrows () { - updateSavingThrow('strength'); - updateSavingThrow('dexterity'); - updateSavingThrow('constitution'); - updateSavingThrow('intelligence'); - updateSavingThrow('wisdom'); - updateSavingThrow('charisma'); -} - -function updateSavingThrow (ability) { - var collectionArray = ['pb', ability + '_mod', ability + '_save_prof', ability + '_save_bonus', 'global_saving_throw_bonus']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - var proficiency = v[ability + '_save_prof']; - var abilityMod = getIntValue(v[ability + '_mod']); - var total = abilityMod; - var totalFormula = abilityMod + '[' + getAbilityShortName(ability) + ']'; - - if (proficiency === '@{PB}') { - var pb = getIntValue(v.pb); - total += pb; - totalFormula += ADD + pb + '[proficient]'; - } - - var abilitySavingThrowBonus = getIntValue(v[ability + '_save_bonus']); - if (exists(abilitySavingThrowBonus)) { - total += abilitySavingThrowBonus; - totalFormula += ADD + abilitySavingThrowBonus + '[' + getAbilityShortName(ability) + 'saving throw bonus]'; - } - - var globalSavingThrowBonus = v.global_saving_throw_bonus; - if (!isUndefined(globalSavingThrowBonus)) { - if (!isNaN(globalSavingThrowBonus)) { - total += getIntValue(globalSavingThrowBonus); - } - totalFormula += ADD + globalSavingThrowBonus + '[global saving throw bonus]'; - } - - var savingThrowWithSign = total; - if (total >= 0) { - savingThrowWithSign = '+' + total; - } - - finalSetAttrs[ability + '_saving_throw_mod'] = totalFormula; - finalSetAttrs[ability + '_saving_throw_mod_with_sign'] = savingThrowWithSign; - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:pb change:strength_mod change:strength_save_prof change:strength_save_bonus change:global_saving_throw_bonus', function () { - updateSavingThrow('strength'); -}); -on('change:pb change:dexterity_mod change:dexterity_save_prof change:dexterity_save_bonus change:global_saving_throw_bonus', function () { - updateSavingThrow('dexterity'); -}); -on('change:pb change:constitution_mod change:constitution_save_prof change:constitution_save_bonus change:global_saving_throw_bonus', function () { - updateSavingThrow('constitution'); -}); -on('change:pb change:intelligence_mod change:intelligence_save_prof change:intelligence_save_bonus change:global_saving_throw_bonus', function () { - updateSavingThrow('intelligence'); -}); -on('change:pb change:wisdom_mod change:wisdom_save_prof change:wisdom_save_bonus change:global_saving_throw_bonus', function () { - updateSavingThrow('wisdom'); -}); -on('change:pb change:charisma_mod change:charisma_save_prof change:charisma_save_bonus change:global_saving_throw_bonus', function () { - updateSavingThrow('charisma'); -}); - -function updateSavingThrowsFromSRD () { - var collectionArray = ['saving_throws_srd']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - var savingThrowsFromSRD = v.saving_throws_srd; - var pbVar = '@{PB}'; - - if (savingThrowsFromSRD.indexOf('Str') !== -1) { - finalSetAttrs.strength_save_prof = pbVar; - } - if (savingThrowsFromSRD.indexOf('Dex') !== -1) { - finalSetAttrs.dexterity_save_prof = pbVar; - } - if (savingThrowsFromSRD.indexOf('Con') !== -1) { - finalSetAttrs.constitution_save_prof = pbVar; - } - if (savingThrowsFromSRD.indexOf('Int') !== -1) { - finalSetAttrs.intelligence_save_prof = pbVar; - } - if (savingThrowsFromSRD.indexOf('Wis') !== -1) { - finalSetAttrs.wisdom_save_prof = pbVar; - } - if (savingThrowsFromSRD.indexOf('Cha') !== -1) { - finalSetAttrs.charisma_save_prof = pbVar; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:saving_throws_srd', function () { - updateSavingThrowsFromSRD(); -}); - -function updateSpellsFromSRD () { - var collectionArray = ['spells_srd']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - var spells = v.spells_srd.split(', '); - - for (var i = 0; i < spells.length; i++) { - var newRowId = generateRowID(); - var repeatingString = 'repeating_spell_' + newRowId + '_'; - finalSetAttrs[repeatingString + 'name'] = spells[i]; + getAttrs(collectionArray, (v) => { + if (v.halfling_luck === 'on') { + finalSetAttrs.d20_mod = 'ro<1[halfling luck]'; + } else { + finalSetAttrs.d20_mod = ''; } setFinalAttrs(v, finalSetAttrs); }); } -on('change:spells_srd', function () { + +on('change:halfling_luck', () => { + updateD20Mod(); +}); + +const updateAbilityChecksMacro = () => { + const repeatingItem = 'repeating_skill'; + const collectionArray = ['ability_checks_query_var', 'ability_checks_macro_var']; + const finalSetAttrs = {}; + + finalSetAttrs.ability_checks_query_var = '?{Ability Check'; + finalSetAttrs.ability_checks_macro_var = ''; + + for (let i = 0; i < ABILITIES.length; i++) { + finalSetAttrs.ability_checks_query_var += `|${capitalize(ABILITIES[i])},{{title=${capitalize(ABILITIES[i])}}} {{roll1=[[@{preroll}d20@{postroll}@{d20_mod} + @{${ABILITIES[i]}_check_mod}]]}} @{roll_setting}@{d20_mod} + @{${ABILITIES[i]}_check_mod}]]}}`; + finalSetAttrs.ability_checks_macro_var += `[${capitalize(ABILITIES[i])}](~${ABILITIES[i]}_check)`; + if (i < ABILITIES.length - 1) { + finalSetAttrs.ability_checks_macro_var += ', '; + } + } + + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}ability`); + } + + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + finalSetAttrs.ability_checks_query_var += `|${v[`${repeatingString}name`]}, {{title=${v[`${repeatingString}name`]} (${capitalize(getAbilityShortName(v[`${repeatingString}ability`]))})}} {{roll1=[[@{preroll}d20@{postroll}@{d20_mod} + @{${repeatingString}formula}]]}} @{roll_setting}@{d20_mod} + @{${repeatingString}formula}]]}}`; + finalSetAttrs.ability_checks_macro_var += ', '; + finalSetAttrs.ability_checks_macro_var += `[${v[`${repeatingString}name`]}](~repeating_skill_${ids[j]}_skill)`; + } + finalSetAttrs.ability_checks_query_var += '}'; + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; + +const updatePreAndPostRoll = () => { + const collectionArray = ['roll_setting', 'roll_info', 'preroll', 'postroll']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + finalSetAttrs.roll_info = ''; + finalSetAttrs.preroll = ''; + finalSetAttrs.postroll = ''; + + if (v.roll_setting === '@{roll_advantage}') { + finalSetAttrs.roll_info = '{{advantage=1}}'; + finalSetAttrs.preroll = 2; + finalSetAttrs.postroll = 'kh1'; + } else if (v.roll_setting === '@{roll_disadvantage}') { + finalSetAttrs.roll_info = '{{disadvantage=1}}'; + finalSetAttrs.preroll = 2; + finalSetAttrs.postroll = 'kl1'; + } + + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:roll_setting', () => { + updatePreAndPostRoll(); +}); + +const updateSkill = (rowId) => { + const repeatingItem = 'repeating_skill'; + const collectionArray = ['jack_of_all_trades_toggle', 'jack_of_all_trades', 'remarkable_athlete_toggle', 'remarkable_athlete', 'pb', 'exp', 'global_check_bonus']; + const finalSetAttrs = {}; + + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`${ABILITIES[i]}_mod`); + collectionArray.push(`${ABILITIES[i]}_check_bonus`); + } + + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}proficiency`); + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}ability`); + collectionArray.push(`${repeatingString}bonus`); + collectionArray.push(`${repeatingString}ability_short_name`); + collectionArray.push(`${repeatingString}formula`); + collectionArray.push(`${repeatingString}total`); + collectionArray.push(`${repeatingString}total_with_sign`); + } + + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + + const skillName = v[`${repeatingString}name`]; + if (isUndefined(skillName)) { + return; + } + + const ability = getAbilityModName(v[`${repeatingString}ability`]); + const abilityName = getAbilityName(v[`${repeatingString}ability`]); + finalSetAttrs[`${repeatingString}ability_short_name`] = getAbilityShortName(ability, true); + + let total = 0; + let totalFormula = ''; + const proficiency = v[`${repeatingString}proficiency`]; + if (!proficiency || proficiency === 'unproficient') { + if ((abilityName === 'strength' || abilityName === 'dexterity' || abilityName === 'constitution') && v.remarkable_athlete_toggle === '@{remarkable_athlete}') { + const remarkableAthlete = getIntValue(v.remarkable_athlete); + total += remarkableAthlete; + totalFormula += `${remarkableAthlete}[remarkable athlete]`; + } else if (v.jack_of_all_trades_toggle === '@{jack_of_all_trades}') { + const jackOfAllTrades = getIntValue(v.jack_of_all_trades); + total += jackOfAllTrades; + totalFormula += `${jackOfAllTrades}[jack of all trades]`; + } else { + totalFormula += '0[unproficient]'; + } + } else if (proficiency === 'proficient') { + const pb = getIntValue(v.pb); + total += pb; + totalFormula += `${pb}[proficient]`; + } else if (proficiency === 'expertise') { + const exp = getIntValue(v.exp); + total += exp; + totalFormula += `${exp}[expertise]`; + } + + const skillAbility = getAbilityValue(v, ability, 'strength_mod'); + if (exists(skillAbility)) { + total += skillAbility; + totalFormula += ` + ${skillAbility}[${getAbilityShortName(ability)}]`; + } + + const skillBonus = getIntValue(v[`${repeatingString}bonus`]); + if (exists(skillBonus)) { + total += skillBonus; + totalFormula += ` + ${skillBonus}[bonus]`; + } + + const skillAbilityName = getAbilityName(ability); + if (exists(skillAbilityName)) { + let checkBonus = v[`${skillAbilityName}_check_bonus`]; + if (exists(checkBonus)) { + checkBonus = getIntValue(checkBonus); + total += checkBonus; + totalFormula += ` + ${checkBonus}[${getAbilityShortName(ability)} check bonus]`; + } + } + + const globalCheckBonus = v.global_check_bonus; + if (exists(globalCheckBonus)) { + if (!isNaN(globalCheckBonus)) { + total += getIntValue(globalCheckBonus); + } + totalFormula += ` + ${globalCheckBonus}[global check bonus]`; + } + + let totalWithSign = total; + if (total >= 0) { + totalWithSign = `+${total}`; + } + + finalSetAttrs[`${repeatingString}total`] = total; + finalSetAttrs[`${repeatingString}total_with_sign`] = totalWithSign; + finalSetAttrs[`${repeatingString}formula`] = totalFormula; + } + setFinalAttrs(v, finalSetAttrs); + updateAbilityChecksMacro(); + }); + }); +}; + +on('change:repeating_skill', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_skill', eventInfo); + if (repeatingInfo && repeatingInfo.field !== 'ability_short_name' && repeatingInfo.field !== 'total' && repeatingInfo.field !== 'total_with_sign' && repeatingInfo.field !== 'formula') { + updateSkill(repeatingInfo.rowId); + } +}); +on('remove:repeating_skill', () => { + updateAbilityChecksMacro(); +}); +on('change:jack_of_all_trades_toggle change:jack_of_all_trades change:remarkable_athlete_toggle change:remarkable_athlete change:global_check_bonus change:strength_check_bonus change:dexterity_check_bonus change:constitution_check_bonus change:intelligence_check_bonus change:wisdom_check_bonus change:charisma_check_bonus', () => { + updateSkill(); +}); + +const updateSkillsFromSRD = () => { + const repeatingItem = 'repeating_skill'; + const collectionArray = ['skills_srd', 'level', 'challenge', 'strength_mod', 'dexterity_mod', 'constitution_mod', 'intelligence_mod', 'wisdom_mod', 'charisma_mod']; + const finalSetAttrs = {}; + + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}ability`); + } + getAttrs(collectionArray, (v) => { + const skillsFromSRD = v.skills_srd; + const skillsObj = {}; + const pb = getPB(v.level, v.challenge); + const expertise = pb * 2; + let skillName; + let repeatingString; + + if (!isUndefined(skillsFromSRD)) { + for (let j = 0; j < ids.length; j++) { + repeatingString = `${repeatingItem}_${ids[j]}_`; + skillName = v[`${repeatingString}name`]; + skillsObj[skillName] = ids[j]; + } + + const re = /(\w+)\s?((?:\+|\-)\d+)/gi; + let match; + while ((match = re.exec(skillsFromSRD)) !== null) { + if (match && match[1] && match[2]) { + skillName = match[1]; + if (skillsObj[skillName]) { + const skillId = skillsObj[skillName]; + repeatingString = `${repeatingItem}_${skillId}_`; + + const skillAbility = v[`${repeatingString}ability`]; + const abilityValue = getAbilityValue(v, skillAbility); + const skillBonus = getIntValue(match[2]) - abilityValue; + + if (skillBonus >= expertise) { + finalSetAttrs[`${repeatingString}proficiency`] = 'expertise'; + if (skillBonus > expertise) { + finalSetAttrs[`${repeatingString}bonus`] = skillBonus - expertise; + } + } else if (skillBonus >= pb) { + finalSetAttrs[`${repeatingString}proficiency`] = 'proficient'; + if (skillBonus > pb) { + finalSetAttrs[`${repeatingString}bonus`] = skillBonus - pb; + } + } + } else { + console.log(`${skillName} does not exist in the list of skills`); + } + } + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:skills_srd', () => { + updateSkillsFromSRD(); +}); + +const updateSavingThrow = (ability) => { + const collectionArray = ['pb', `${ability}_mod`, `${ability}_save_prof`, `${ability}_save_bonus`, 'global_saving_throw_bonus']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + const proficiency = v[`${ability}_save_prof`]; + const abilityMod = getIntValue(v[`${ability}_mod`]); + let total = abilityMod; + let totalFormula = `${abilityMod}[${getAbilityShortName(ability)}]`; + + if (proficiency === '@{PB}') { + const pb = getIntValue(v.pb); + total += pb; + totalFormula += ` + ${pb}[proficient]`; + } + + const abilitySavingThrowBonus = getIntValue(v[`${ability}_save_bonus`]); + if (exists(abilitySavingThrowBonus)) { + total += abilitySavingThrowBonus; + totalFormula += ` + ${abilitySavingThrowBonus}[${getAbilityShortName(ability)}saving throw bonus]`; + } + + const globalSavingThrowBonus = v.global_saving_throw_bonus; + if (!isUndefined(globalSavingThrowBonus)) { + if (!isNaN(globalSavingThrowBonus)) { + total += getIntValue(globalSavingThrowBonus); + } + totalFormula += ` + ${globalSavingThrowBonus}[global saving throw bonus]`; + } + + let savingThrowWithSign = total; + if (total >= 0) { + savingThrowWithSign = `+${total}`; + } + + finalSetAttrs[`${ability}_saving_throw_mod`] = totalFormula; + finalSetAttrs[`${ability}_saving_throw_mod_with_sign`] = savingThrowWithSign; + setFinalAttrs(v, finalSetAttrs); + }); +}; +const updateSavingThrows = () => { + updateSavingThrow('strength'); + updateSavingThrow('dexterity'); + updateSavingThrow('constitution'); + updateSavingThrow('intelligence'); + updateSavingThrow('wisdom'); + updateSavingThrow('charisma'); +}; +on('change:pb change:strength_mod change:strength_save_prof change:strength_save_bonus change:global_saving_throw_bonus', () => { + updateSavingThrow('strength'); +}); +on('change:pb change:dexterity_mod change:dexterity_save_prof change:dexterity_save_bonus change:global_saving_throw_bonus', () => { + updateSavingThrow('dexterity'); +}); +on('change:pb change:constitution_mod change:constitution_save_prof change:constitution_save_bonus change:global_saving_throw_bonus', () => { + updateSavingThrow('constitution'); +}); +on('change:pb change:intelligence_mod change:intelligence_save_prof change:intelligence_save_bonus change:global_saving_throw_bonus', () => { + updateSavingThrow('intelligence'); +}); +on('change:pb change:wisdom_mod change:wisdom_save_prof change:wisdom_save_bonus change:global_saving_throw_bonus', () => { + updateSavingThrow('wisdom'); +}); +on('change:pb change:charisma_mod change:charisma_save_prof change:charisma_save_bonus change:global_saving_throw_bonus', () => { + updateSavingThrow('charisma'); +}); + +const updateSavingThrowsFromSRD = () => { + const collectionArray = ['saving_throws_srd']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + const savingThrowsFromSRD = v.saving_throws_srd; + const pbVar = '@{PB}'; + + if (savingThrowsFromSRD.indexOf('Str') !== -1) { + finalSetAttrs.strength_save_prof = pbVar; + } + if (savingThrowsFromSRD.indexOf('Dex') !== -1) { + finalSetAttrs.dexterity_save_prof = pbVar; + } + if (savingThrowsFromSRD.indexOf('Con') !== -1) { + finalSetAttrs.constitution_save_prof = pbVar; + } + if (savingThrowsFromSRD.indexOf('Int') !== -1) { + finalSetAttrs.intelligence_save_prof = pbVar; + } + if (savingThrowsFromSRD.indexOf('Wis') !== -1) { + finalSetAttrs.wisdom_save_prof = pbVar; + } + if (savingThrowsFromSRD.indexOf('Cha') !== -1) { + finalSetAttrs.charisma_save_prof = pbVar; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:saving_throws_srd', () => { + updateSavingThrowsFromSRD(); +}); + +const updateSpellsFromSRD = () => { + const collectionArray = ['spells_srd']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + const spells = v.spells_srd.split(', '); + + for (let i = 0; i < spells.length; i++) { + const newRowId = generateRowID(); + const repeatingString = `repeating_spell_${newRowId}_`; + finalSetAttrs[`${repeatingString}name`] = spells[i]; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:spells_srd', () => { updateSpellsFromSRD(); }); -function updateAttachers () { - var repeatingItem = 'repeating_attacher'; - var collectionArray = ['attacher_initiative', 'attacher_death_saving_throw', 'attacher_hit_dice', 'attacher_attack', 'attacher_spell', 'attacher_skill']; - var finalSetAttrs = {}; - var itemsToPush = ['initiative', 'death_saving_throw', 'hit_dice', 'attack', 'spell', 'skill']; +const updateAttachers = () => { + const repeatingItem = 'repeating_attacher'; + const collectionArray = ['attacher_initiative', 'attacher_death_saving_throw', 'attacher_hit_dice', 'attacher_attack', 'attacher_spell', 'attacher_skill']; + const finalSetAttrs = {}; + const itemsToPush = ['initiative', 'death_saving_throw', 'hit_dice', 'attack', 'spell', 'skill']; - for (var i = 0; i < ABILITIES.length; i++) { - collectionArray.push('attacher_' + ABILITIES[i] + '_check'); - collectionArray.push('attacher_' + ABILITIES[i] + '_saving_throw'); - itemsToPush.push(ABILITIES[i] + '_check'); - itemsToPush.push(ABILITIES[i] + '_saving_throw'); - } + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`attacher_${ABILITIES[i]}_check`); + collectionArray.push(`attacher_${ABILITIES[i]}_saving_throw`); + itemsToPush.push(`${ABILITIES[i]}_check`); + itemsToPush.push(`${ABILITIES[i]}_saving_throw`); + } - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'freetext'); - collectionArray.push(repeatingString + 'freeform'); + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}freetext`); + collectionArray.push(`${repeatingString}freeform`); - for (var x = 0; x < itemsToPush.length; x++) { - collectionArray.push(repeatingString + itemsToPush[x] + '_attacher'); - finalSetAttrs['attacher_' + itemsToPush[x]] = ' '; - } - } - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; + for (let x = 0; x < itemsToPush.length; x++) { + collectionArray.push(`${repeatingString}${itemsToPush[x]}_attacher`); + finalSetAttrs[`attacher_${itemsToPush[x]}`] = ' '; + } + } + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; - for (var x = 0; x < itemsToPush.length; x++) { - var attacher = v[repeatingString + itemsToPush[x] + '_attacher']; - if (exists(attacher) && attacher === 'on') { + for (let x = 0; x < itemsToPush.length; x++) { + const attacher = v[`${repeatingString}${itemsToPush[x]}_attacher`]; + if (exists(attacher) && attacher === 'on') { + const attacherName = v[`${repeatingString}name`] || ''; - var attacherName = v[repeatingString + 'name'] || ''; + const freeText = v[`${repeatingString}freetext`]; + if (exists(attacherName) && exists(freeText)) { + finalSetAttrs[`attacher_${itemsToPush[x]}`] += `{{${attacherName}=${freeText}}} `; + } + const freeForm = v[`${repeatingString}freeform`]; + if (exists(freeForm)) { + finalSetAttrs[`attacher_${itemsToPush[x]}`] += `${freeForm} `; + } + } + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; - var freeText = v[repeatingString + 'freetext']; - if (exists(attacherName) && exists(freeText)) { - finalSetAttrs['attacher_' + itemsToPush[x]] += '{{' + attacherName + '=' + freeText + '}}' + ' '; - } - var freeForm = v[repeatingString + 'freeform']; - if (exists(freeForm)) { - finalSetAttrs['attacher_' + itemsToPush[x]] += freeForm + ' '; - } - } - } - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} - -on('change:repeating_attacher remove:repeating_attacher', function () { - updateAttachers(); +on('change:repeating_attacher remove:repeating_attacher', () => { + updateAttachers(); }); -function updateNPCChallenge () { - var collectionArray = ['challenge', 'xp']; - var finalSetAttrs = {}; +const updateNPCChallenge = () => { + const collectionArray = ['challenge', 'xp']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - var challenge = v.challenge; - var xpPerChallenge = { - 0: 0, - '1/8': 25, - '1/4': 50, - '1/2': 100, - 1: 200, - 2: 450, - 3: 700, - 4: 1100, - 5: 1800, - 6: 2300, - 7: 2900, - 8: 3900, - 9: 5000, - 10: 5900, - 11: 7200, - 12: 8400, - 13: 10000, - 14: 11500, - 15: 13000, - 16: 15000, - 17: 18000, - 18: 20000, - 19: 22000, - 20: 25000, - 21: 33000, - 22: 41000, - 23: 50000, - 24: 62000, - 25: 75000, - 26: 90000, - 27: 105000, - 28: 120000, - 29: 135000, - 30: 155000 - }; + getAttrs(collectionArray, (v) => { + const challenge = v.challenge; + const xpPerChallenge = { + 0: 0, + '1/8': 25, + '1/4': 50, + '1/2': 100, + 1: 200, + 2: 450, + 3: 700, + 4: 1100, + 5: 1800, + 6: 2300, + 7: 2900, + 8: 3900, + 9: 5000, + 10: 5900, + 11: 7200, + 12: 8400, + 13: 10000, + 14: 11500, + 15: 13000, + 16: 15000, + 17: 18000, + 18: 20000, + 19: 22000, + 20: 25000, + 21: 33000, + 22: 41000, + 23: 50000, + 24: 62000, + 25: 75000, + 26: 90000, + 27: 105000, + 28: 120000, + 29: 135000, + 30: 155000, + }; - finalSetAttrs.xp = xpPerChallenge[challenge]; - finalSetAttrs.xp_readable = numberWithCommas(finalSetAttrs.xp); + finalSetAttrs.xp = xpPerChallenge[challenge]; + finalSetAttrs.xp_readable = numberWithCommas(finalSetAttrs.xp); - finalSetAttrs.level = challenge; - if (finalSetAttrs.level < 1) { - finalSetAttrs.level = 1; - } - setFinalAttrs(v, finalSetAttrs); - }); -} + finalSetAttrs.level = challenge; + if (finalSetAttrs.level < 1) { + finalSetAttrs.level = 1; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; -on('change:challenge', function () { - updateNPCChallenge(); +on('change:challenge', () => { + updateNPCChallenge(); }); -function updateNPCHPFromSRD () { - var collectionArray = ['hp_srd', 'constitution', 'constitution_mod', 'constitution_bonus', 'global_ability_bonus']; - var finalSetAttrs = {}; +const updateNPCHPFromSRD = () => { + const collectionArray = ['hp_srd', 'constitution', 'constitution_mod', 'constitution_bonus', 'global_ability_bonus']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { + getAttrs(collectionArray, (v) => { if (exists(v.hp_srd)) { - var match = v.hp_srd.match(/\((\d+)d(\d+)(?:\s?(?:\+|\-)\s?(\d+))?\)/i); + const match = v.hp_srd.match(/\((\d+)d(\d+)(?:\s?(\+|\-)\s?(\d+))?\)/i); if (!match || !match[1] || !match[2]) { console.log('Character doesn\'t have valid HP/HD format'); } else { - var hdNum = getIntValue(match[1]); + const hdNum = getIntValue(match[1]); - var conMod = getIntValue(v.constitution_mod); + let conMod = getIntValue(v.constitution_mod); if (!conMod) { - var conScore = getIntValue(v.constitution); - var conBonus = getIntValue(v.constitution_bonus); - var globalAbilityBonus = getIntValue(v.global_ability_bonus); + const conScore = getIntValue(v.constitution); + const conBonus = getIntValue(v.constitution_bonus); + const globalAbilityBonus = getIntValue(v.global_ability_bonus); conMod = getAbilityMod((conScore + conBonus + globalAbilityBonus)); } finalSetAttrs.hit_dice = hdNum; - finalSetAttrs.hit_die = 'd' + getIntValue(match[2]); + finalSetAttrs.hit_die = `d${getIntValue(match[2])}`; - var hpExpectedBonus = hdNum * conMod; - var hpBonus = getIntValue(match[3]); + const hpExpectedBonus = hdNum * conMod; + const hpBonusSign = match[3]; + const hpBonus = getIntValue(match[4]); if (hpBonus !== hpExpectedBonus) { - finalSetAttrs.hp_extra = hpBonus - hpExpectedBonus; + if (hpBonusSign === '-') { + finalSetAttrs.hp_extra = hpBonus + hpExpectedBonus; + } else { + finalSetAttrs.hp_extra = hpBonus - hpExpectedBonus; + } } } } setFinalAttrs(v, finalSetAttrs); }); -} -on('change:hp_srd', function () { +}; +on('change:hp_srd', () => { updateNPCHPFromSRD(); }); -function updateNPCHP () { - var collectionArray = ['hit_dice', 'hit_die', 'hp_extra', 'constitution_mod']; - var finalSetAttrs = {}; +const updateNPCHP = () => { + const collectionArray = ['HP', 'HP_max', 'hp_formula', 'hit_dice', 'hit_die', 'hp_extra', 'constitution_mod']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - var hdNum = getIntValue(v.hit_dice); - var hdSize = getIntValue(v.hit_die.replace('d', '')); - var hdAverage = (hdSize / 2) + 0.5; - var hpFormula = hdNum + 'd' + hdSize; - var conMod = getIntValue(v.constitution_mod); - var totalHP = Math.floor(hdNum * hdAverage); - var amount; + getAttrs(collectionArray, (v) => { + const hdNum = getIntValue(v.hit_dice); + const hdSize = getIntValue(v.hit_die.replace('d', '')); + const hdAverage = (hdSize / 2) + 0.5; + let hpFormula = `${hdNum}d${hdSize}`; + const conMod = getIntValue(v.constitution_mod); + let totalHP = Math.floor(hdNum * hdAverage); + let amount; - if (conMod !== 0) { - var bonusHP = hdNum * conMod; - totalHP += bonusHP; - hpFormula += addOrSubtract(hpFormula, bonusHP); - } + if (conMod !== 0) { + const bonusHP = hdNum * conMod; + totalHP += bonusHP; + hpFormula += addOrSubtract(hpFormula, bonusHP); + } - if (exists(v.hp_extra)) { - var regex = (/(?:(\+|\-)\s)?(\d+)(?:d(\d+))?/gi); - var splitFormula; + if (exists(v.hp_extra)) { + const regex = (/(?:(\+|\-)\s)?(\d+)(?:d(\d+))?/gi); + let splitFormula; - while (splitFormula = regex.exec(v.hp_extra)) { - if (!splitFormula || !splitFormula[2]) { - console.log('Character doesn\'t have valid hp formula'); - } else { - amount = 0; + while ((splitFormula = regex.exec(v.hp_extra)) !== null) { + if (!splitFormula || !splitFormula[2]) { + console.log('Character doesn\'t have valid hp formula'); + } else { + amount = 0; - if (!splitFormula[3]) { - amount = getIntValue(splitFormula[2]); - } else { - var extraHdNum = getIntValue(splitFormula[2]); - var extraHdSize = getIntValue(splitFormula[3]); - var extraHdAverage = (extraHdSize / 2) + 0.5; - amount = Math.floor(extraHdNum * extraHdAverage); - } + if (!splitFormula[3]) { + amount = getIntValue(splitFormula[2]); + } else { + const extraHdNum = getIntValue(splitFormula[2]); + const extraHdSize = getIntValue(splitFormula[3]); + const extraHdAverage = (extraHdSize / 2) + 0.5; + amount = Math.floor(extraHdNum * extraHdAverage); + } - if (!splitFormula[1] || splitFormula[1] === '+') { - totalHP += amount; - hpFormula += ADD + amount; - } else if (splitFormula[1] === '-') { - totalHP -= amount; - hpFormula += SUBTRACT + amount; - } - } - v.hp_extra.replace(splitFormula[0], ''); - } - } + if (!splitFormula[1] || splitFormula[1] === '+') { + totalHP += amount; + hpFormula += ` + ${amount}`; + } else if (splitFormula[1] === '-') { + totalHP -= amount; + hpFormula += ` - ${amount}`; + } + } + v.hp_extra.replace(splitFormula[0], ''); + } + } - if (totalHP) { - finalSetAttrs.hp = totalHP; - finalSetAttrs.hp_max = totalHP; - finalSetAttrs.hp_formula = hpFormula; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:hit_dice change:hit_die change:hp_extra change:constitution_mod', function () { - updateNPCHP(); + if (totalHP) { + finalSetAttrs.HP = totalHP; + finalSetAttrs.HP_max = totalHP; + finalSetAttrs.hp_formula = hpFormula; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:hit_dice change:hit_die change:hp_extra change:constitution_mod', () => { + updateNPCHP(); }); -function updateNPCAC () { - var collectionArray = ['ac_srd', 'ac', 'ac_note', 'dexterity_mod']; - var finalSetAttrs = {}; +const updateNPCAC = () => { + const collectionArray = ['ac_srd', 'ac', 'ac_note', 'dexterity_mod']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - if (exists(v.ac_srd)) { - var match = v.ac_srd.match(/(\d+)\s?(.*)/); - if (match && match[1]) { - finalSetAttrs.ac = match[1]; - } - if (match && match[2]) { - finalSetAttrs.ac_note = match[2].replace(/\(|\)/g, ''); - } - } - setFinalAttrs(v, finalSetAttrs); - }); -} + getAttrs(collectionArray, (v) => { + if (exists(v.ac_srd)) { + const match = v.ac_srd.match(/(\d+)\s?(.*)/); + if (match && match[1]) { + finalSetAttrs.AC = match[1]; + } + if (match && match[2]) { + finalSetAttrs.ac_note = match[2].replace(/\(|\)/g, ''); + } + } + setFinalAttrs(v, finalSetAttrs); + }); +}; -on('change:ac_srd', function () { - updateNPCAC(); +on('change:ac_srd', () => { + updateNPCAC(); }); -function setDefaultAbility (v, finalSetAttrs) { - var abilityScores = [getIntValue(v.intelligence), getIntValue(v.wisdom), getIntValue(v.charisma)]; - var highestAbilityScore = Math.max.apply(Math, abilityScores); - var highestAbilityName = 'intelligence'; +const setDefaultAbility = (v, finalSetAttrs) => { + const abilityScores = [getIntValue(v.intelligence), getIntValue(v.wisdom), getIntValue(v.charisma)]; + const highestAbilityScore = Math.max.apply(Math, abilityScores); + let highestAbilityName = 'intelligence'; - if (highestAbilityScore === abilityScores[1]) { - highestAbilityName = 'wisdom'; - } else if (highestAbilityScore === abilityScores[2]) { - highestAbilityName = 'charisma'; - } + if (highestAbilityScore === abilityScores[1]) { + highestAbilityName = 'wisdom'; + } else if (highestAbilityScore === abilityScores[2]) { + highestAbilityName = 'charisma'; + } - finalSetAttrs.default_ability = '@{' + highestAbilityName + '_mod}'; -} + finalSetAttrs.default_ability = `@{${highestAbilityName}_mod}`; +}; -function updateNPCContent () { - var collectionArray = ['content_srd']; - var finalSetAttrs = {}; +const updateNPCContent = () => { + const collectionArray = ['content_srd']; + const finalSetAttrs = {}; - for (var i = 0; i < ABILITIES.length; i++) { - collectionArray.push(ABILITIES[i]); - } + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(ABILITIES[i]); + } - getAttrs(collectionArray, function (v) { - var content = v.content_srd; - var legendaryActions; - var reactions; - var actions; - var traits; - var re = /\@(.*)\@:\s([^@]+)/gi; - var match; - var newRowId; - var repeatingString; + getAttrs(collectionArray, (v) => { + let content = v.content_srd; + let legendaryActions; + let reactions; + let actions; + let traits; + const re = /\@(.*)\@:\s([^@]+)/gi; + let match; + let newRowId; + let repeatingString; - setDefaultAbility(v, finalSetAttrs); + setDefaultAbility(v, finalSetAttrs); - if (exists(content)) { - if (content.indexOf('Legendary Actions') !== -1) { - var legendaryActionsSplit = content.split(/Legendary Actions\n/); - legendaryActions = legendaryActionsSplit[1]; - content = legendaryActionsSplit[0]; - } - if (exists(legendaryActions)) { - var legendaryActionAmount = 3; - var legendaryActionsMatch = legendaryActions.match(/Can take (\d+) Legendary Actions/gi); + if (exists(content)) { + if (content.indexOf('Legendary Actions') !== -1) { + const legendaryActionsSplit = content.split(/Legendary Actions\n/); + legendaryActions = legendaryActionsSplit[1]; + content = legendaryActionsSplit[0]; + } + if (exists(legendaryActions)) { + let legendaryActionAmount = 3; + const legendaryActionsMatch = legendaryActions.match(/Can take (\d+) Legendary Actions/gi); - if (legendaryActionsMatch && legendaryActionsMatch[1]) { - legendaryActionAmount = legendaryActionAmount[1]; - } + if (legendaryActionsMatch && legendaryActionsMatch[1]) { + legendaryActionAmount = legendaryActionAmount[1]; + } - finalSetAttrs.legendary_action_amount = legendaryActionAmount; + finalSetAttrs.legendary_action_amount = legendaryActionAmount; - while (match = re.exec(legendaryActions.replace(/\*\*/g, '@'))) { - if (match && match[1] && match[2]) { - newRowId = generateRowID(); - repeatingString = 'repeating_legendaryaction_' + newRowId + '_'; - finalSetAttrs[repeatingString + 'name'] = match[1]; - finalSetAttrs[repeatingString + 'freetext'] = match[2].trim(); - } else { - console.log('Character doesn\'t have a valid legendary action format'); - } - } - } - if (content.indexOf('Reactions') !== -1) { - var reactionsSplit = content.split(/Reactions\n/); - reactions = reactionsSplit[1]; - content = reactionsSplit[0]; - } - if (exists(reactions)) { - while (match = re.exec(reactions.replace(/\*\*/g, '@'))) { - if (match && match[1] && match[2]) { - newRowId = generateRowID(); - repeatingString = 'repeating_reaction_' + newRowId + '_'; - finalSetAttrs[repeatingString + 'name'] = match[1]; - finalSetAttrs[repeatingString + 'freetext'] = match[2].trim(); - } else { - console.log('Character doesn\'t have a valid reaction format'); - } - } - } - if (content.indexOf('Actions') !== -1) { - var actionsSplit = content.split(/Actions\n/); - actions = actionsSplit[1]; - content = actionsSplit[0]; - } - if (exists(actions)) { - while (match = re.exec(actions.replace(/\*\*/g, '@'))) { - if (match && match[1] && match[2]) { - newRowId = generateRowID(); - repeatingString = 'repeating_action_' + newRowId + '_'; - finalSetAttrs[repeatingString + 'name'] = match[1]; - finalSetAttrs[repeatingString + 'freetext'] = match[2].trim(); - } else { - console.log('Character doesn\'t have a valid action format'); - } - } - } + while ((match = re.exec(legendaryActions.replace(/\*\*/g, '@'))) !== null) { + if (match && match[1] && match[2]) { + newRowId = generateRowID(); + repeatingString = `repeating_legendaryaction_${newRowId}_`; + finalSetAttrs[`${repeatingString}name`] = match[1]; + finalSetAttrs[`${repeatingString}freetext`] = match[2].trim(); + } else { + console.log('Character doesn\'t have a valid legendary action format'); + } + } + } + if (content.indexOf('Reactions') !== -1) { + const reactionsSplit = content.split(/Reactions\n/); + reactions = reactionsSplit[1]; + content = reactionsSplit[0]; + } + if (exists(reactions)) { + while ((match = re.exec(reactions.replace(/\*\*/g, '@'))) !== null) { + if (match && match[1] && match[2]) { + newRowId = generateRowID(); + repeatingString = `repeating_reaction_${newRowId}_`; + finalSetAttrs[`${repeatingString}name`] = match[1]; + finalSetAttrs[`${repeatingString}freetext`] = match[2].trim(); + } else { + console.log('Character doesn\'t have a valid reaction format'); + } + } + } + if (content.indexOf('Actions') !== -1) { + const actionsSplit = content.split(/Actions\n/); + actions = actionsSplit[1]; + content = actionsSplit[0]; + } + if (exists(actions)) { + while ((match = re.exec(actions.replace(/\*\*/g, '@'))) !== null) { + if (match && match[1] && match[2]) { + newRowId = generateRowID(); + repeatingString = `repeating_action_${newRowId}_`; + finalSetAttrs[`${repeatingString}name`] = match[1]; + finalSetAttrs[`${repeatingString}freetext`] = match[2].trim(); + } else { + console.log('Character doesn\'t have a valid action format'); + } + } + } - if (content.indexOf('Traits') !== -1) { - var traitsSplit = content.split(/Traits\n/); - traits = traitsSplit[1]; - content = traitsSplit[0]; - } - if (exists(traits)) { - while (match = re.exec(traits.replace(/\*\*/g, '@'))) { - if (match && match[1] && match[2]) { - newRowId = generateRowID(); - repeatingString = 'repeating_trait_' + newRowId + '_'; - finalSetAttrs[repeatingString + 'name'] = match[1]; - finalSetAttrs[repeatingString + 'freetext'] = match[2].trim(); - } else { - console.log('Character doesn\'t have a valid trait format'); - } - } - } - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:content_srd', function () { - updateNPCContent(); + if (content.indexOf('Traits') !== -1) { + const traitsSplit = content.split(/Traits\n/); + traits = traitsSplit[1]; + content = traitsSplit[0]; + } + if (exists(traits)) { + while ((match = re.exec(traits.replace(/\*\*/g, '@'))) !== null) { + if (match && match[1] && match[2]) { + newRowId = generateRowID(); + repeatingString = `repeating_trait_${newRowId}_`; + finalSetAttrs[`${repeatingString}name`] = match[1]; + const text = match[2].trim(); + finalSetAttrs[`${repeatingString}display_text`] = text; + finalSetAttrs[`${repeatingString}freetext`] = text; + } else { + console.log('Character doesn\'t have a valid trait format'); + } + } + } + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:content_srd', () => { + updateNPCContent(); }); -function updateAction (type, rowId) { - var repeatingItem = 'repeating_' + type; - var collectionArray = ['pb', 'strength_mod', 'finesse_mod', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability']; - var finalSetAttrs = {}; +const displayTextForTraits = () => { + const repeatingItem = 'repeating_trait'; + const collectionArray = []; + const finalSetAttrs = {}; - var rechargeRegex = /\s*?\((?:Recharge\s*?(\d+\-\d+|\d+)|Recharges\safter\sa\s(.*))\)/gi; - var rechargeDayRegex = /\s*?\((\d+\/Day)\)/gi; + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}display_text`); + collectionArray.push(`${repeatingString}freetext`); + } - for (var i = 0; i < ABILITIES.length; i++) { - collectionArray.push(ABILITIES[i] + '_mod'); - } + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; - getSectionIDs(repeatingItem, function (ids) { - if (rowId) { - ids = []; - ids.push(rowId); - } - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'type'); - collectionArray.push(repeatingString + 'roll_toggle'); - collectionArray.push(repeatingString + 'to_hit'); - collectionArray.push(repeatingString + 'attack_formula'); - collectionArray.push(repeatingString + 'proficiency'); - collectionArray.push(repeatingString + 'attack_ability'); - collectionArray.push(repeatingString + 'attack_bonus'); - collectionArray.push(repeatingString + 'saving_throw_toggle'); - collectionArray.push(repeatingString + 'saving_throw_ability'); - collectionArray.push(repeatingString + 'saving_throw_bonus'); - collectionArray.push(repeatingString + 'saving_throw_dc'); - collectionArray.push(repeatingString + 'damage_toggle'); - collectionArray.push(repeatingString + 'damage_formula'); - collectionArray.push(repeatingString + 'damage'); - collectionArray.push(repeatingString + 'damage_ability'); - collectionArray.push(repeatingString + 'damage_bonus'); - collectionArray.push(repeatingString + 'damage_type'); - collectionArray.push(repeatingString + 'second_damage_toggle'); - collectionArray.push(repeatingString + 'second_damage_formula'); - collectionArray.push(repeatingString + 'second_damage'); - collectionArray.push(repeatingString + 'second_damage_ability'); - collectionArray.push(repeatingString + 'second_damage_bonus'); - collectionArray.push(repeatingString + 'second_damage_type'); - collectionArray.push(repeatingString + 'damage_string'); - collectionArray.push(repeatingString + 'heal_toggle'); - collectionArray.push(repeatingString + 'heal'); - collectionArray.push(repeatingString + 'heal_ability'); - collectionArray.push(repeatingString + 'heal_bonus'); - collectionArray.push(repeatingString + 'parsed'); - collectionArray.push(repeatingString + 'recharge'); - collectionArray.push(repeatingString + 'recharge_display'); - } + if (isUndefined(v.display_text)) { + finalSetAttrs[`${repeatingString}display_text`] = v[`${repeatingString}freetext`]; + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; - getAttrs(collectionArray, function (v) { - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; +const parseDamage = (finalSetAttrs, repeatingString, freetext, regex, name, spellMods, meleeMods, spellAttack, rangedAttack, dexMod) => { + const damageParseRegex = /(\d+d?\d+)(?:\s?(?:\+|\-)\s?(\d+))?/gi; + const damage = regex.exec(freetext); + let damageBonus; + if (damage) { + /* + 1 is damage without dice. Example '1' + 2 is damage with dice. Example '2d6+4' + 3 is damage type. Example 'slashing' or 'lightning or thunder' + */ + if (damage[1]) { + damageBonus = damage[1]; + } + if (damage[2]) { + const damageParsed = damageParseRegex.exec(damage[2]); + if (damageParsed) { + if (damageParsed[1]) { + finalSetAttrs[repeatingString + name] = damageParsed[1]; + } + if (damageParsed[2]) { + damageBonus = damageParsed[2]; + } + } + } + damageBonus = getCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, `${name}_ability`, damageBonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod); + if (damage[3]) { + finalSetAttrs[`${repeatingString}${name}_type`] = damage[3]; + } + if (damageBonus) { + finalSetAttrs[`${repeatingString}${name}_bonus`] = damageBonus; + } + freetext = freetext.replace(regex, ''); + finalSetAttrs[`${repeatingString}${name}_toggle`] = `@{${name}_toggle_var}`; + } else { + finalSetAttrs[`${repeatingString}${name}_toggle`] = 0; + } + return freetext; +}; - var actionName = v[repeatingString + 'name']; - if (isUndefined(actionName)) { - return; - } else { - var rechargeResult = rechargeRegex.exec(actionName); - if (rechargeResult) { - finalSetAttrs[repeatingString + 'recharge'] = rechargeResult[1] || rechargeResult[2]; - finalSetAttrs[repeatingString + 'name'] = actionName.replace(rechargeRegex, ''); - } - var rechargeDayResult = rechargeDayRegex.exec(actionName); - if (rechargeDayResult) { - finalSetAttrs[repeatingString + 'recharge'] = rechargeDayResult[1] || rechargeDayResult[2]; - finalSetAttrs[repeatingString + 'name'] = actionName.replace(rechargeDayRegex, ''); - } - } - var recharge = fromVOrFinalSetAttrs(v, finalSetAttrs, repeatingString + 'recharge'); - if (exists(recharge)) { - if (recharge.indexOf('/Day') !== -1 || recharge.indexOf('/day') !== -1) { - finalSetAttrs[repeatingString + 'recharge_display'] = ' (' + recharge + ')'; - } else { - finalSetAttrs[repeatingString + 'recharge_display'] = ' (Recharge ' + recharge + ')'; - } - } else if (exists(v[repeatingString + 'recharge_display'])) { - finalSetAttrs[repeatingString + 'recharge_display'] = ''; - } +const parseAction = (rowId, type) => { + const repeatingItem = `repeating_${type}`; + const collectionArray = ['level', 'challenge', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability']; + const finalSetAttrs = {}; - var attackOptions = {}; - if (type !== 'trait') { - attackOptions = { - defaultAbility: 'strength_mod', - globalAttackBonus: v.global_attack_bonus, - globalAttackBonusLabel: 'global attack bonus', - globalMeleeAttackBonus: v.global_melee_attack_bonus, - globalRangedAttackBonus: v.global_ranged_attack_bonus, - type: 'attack' - }; - } - updateAttackToggle(v, finalSetAttrs, repeatingString, attackOptions); + const damageType = /((?:[\w]+|[\w]+\s(?:or|and)\s[\w]+)(?:\s*?\([\w\s]+\))?)\s*?damage\s?(\([\w\'\s]+\))?/; + const damageSyntax = /(?:(\d+)|.*?\(([\dd\s\+\-]*)\).*?)\s*?/; + const altDamageSyntax = /(?:\,\s*?or\s*?)/; + const plus = /\s*?plus\s*?/; + const savingThrowRe = /(?:DC)\s*?(\d+)\s*?([a-zA-Z]*)\s*?(?:saving throw)/; + const saveSuccess = /or\s(.*)?\son a successful one./; + const damageRegex = new RegExp(damageSyntax.source + damageType.source, 'i'); + const damagePlusRegex = new RegExp(plus.source + damageSyntax.source + damageType.source, 'i'); + const altDamageRegex = new RegExp(altDamageSyntax.source + damageSyntax.source + damageType.source, 'i'); + const savingThrowRegex = new RegExp(savingThrowRe.source, 'i'); + const saveSuccessRegex = new RegExp(saveSuccess.source, 'i'); - updateSavingThrowToggle(v, finalSetAttrs, repeatingString); + const typeRegex = /(melee|ranged|melee or ranged)\s*(spell|weapon)\s*/gi; + const toHitRegex = /:\s?\+\s?(\d+)\s*(?:to hit)/gi; + const reachRegex = /(?:reach)\s?(\d+)\s?(?:ft)/gi; + const rangeRegex = /(?:range)\s?(\d+)\/(\d+)\s?(ft)/gi; + const spellcastingRegex = /(\d+)\w+\slevel\s\((\d+)\s?slot(?:s)?\)/gi; + const spellcastingLevelRegex = /(\d+)(?:st|dn|rd|th)-level spellcaster/i; + const spellcastingAbilityRegex = /spellcasting ability is (\w+)/i; - var damageOptions = {}; - if (type !== 'trait') { - damageOptions = { - defaultDamageAbility: 'strength_mod', - globalDamageBonus: v.global_damage_bonus, - globalMeleeDamageBonus: v.global_melee_damage_bonus, - globalRangedDamageBonus: v.global_ranged_damage_bonus, - type: 'attack' - }; - } - updateDamageToggle(v, finalSetAttrs, repeatingString, damageOptions); + for (let i = 0; i < ABILITIES.length; i++) { + collectionArray.push(`${ABILITIES[i]}_mod`); + } - updateHealToggle(v, finalSetAttrs, repeatingString); - } - setFinalAttrs(v, finalSetAttrs); - }); - }); -} -on('change:repeating_trait', function (eventInfo) { - var changedField = getRepeatingField('repeating_trait', eventInfo); - if (changedField !== 'to_hit' && changedField !== 'attack_formula' && changedField !== 'damage_formula' && changedField !== 'second_damage_formula' && changedField !== 'damage_string' && changedField !== 'saving_throw_dc' && changedField !== 'parsed' && changedField !== 'recharge_display') { - console.log('trait changedField', changedField); - var rowId = getRowId('repeating_trait', eventInfo); - updateAction('trait', rowId); - } + getSectionIDs(repeatingItem, (ids) => { + if (rowId) { + ids = []; + ids.push(rowId); + } + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}freetext`); + } + + getAttrs(collectionArray, (v) => { + const pb = getPB(v.level, v.challenge); + const strMod = getIntValue(v.strength_mod); + const dexMod = getIntValue(v.dexterity_mod); + const conMod = getIntValue(v.constitution_mod); + const intMod = getIntValue(v.intelligence_mod); + const wisMod = getIntValue(v.wisdom_mod); + const chaMod = getIntValue(v.charisma_mod); + const meleeMods = [strMod, dexMod]; + const spellMods = [intMod, wisMod, chaMod]; + const abilityMods = [strMod, dexMod, conMod, intMod, wisMod, chaMod]; + + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; + + let rangedAttack = false; + let spellAttack = false; + + const name = v[`${repeatingString}name`]; + let freetext = v[`${repeatingString}freetext`]; + + if (name && name.indexOf('Spellcasting') !== -1) { + const spellcastingSearch = spellcastingAbilityRegex.exec(freetext); + if (spellcastingSearch && spellcastingSearch[1]) { + const spellcastingAbility = spellcastingSearch[1].toLowerCase(); + finalSetAttrs.default_ability = `@{${spellcastingAbility}_mod}`; + } + const spellcastingLevelSearch = spellcastingLevelRegex.exec(freetext); + if (spellcastingLevelSearch && spellcastingLevelSearch[1]) { + finalSetAttrs.caster_level = spellcastingLevelSearch[1]; + } + + let match; + while ((match = spellcastingRegex.exec(freetext)) !== null) { + if (match && match[1] && match[2]) { + finalSetAttrs[`spell_slots_l${match[1]}_bonus`] = match[2]; + } + } + } + + const actionType = typeRegex.exec(freetext); + if (actionType) { + if (actionType[1]) { + actionType[1] = actionType[1].toLowerCase(); + if (actionType[1] === 'melee') { + finalSetAttrs[`${repeatingString}type`] = 'Melee Weapon'; + } + if (actionType[1] === 'ranged') { + finalSetAttrs[`${repeatingString}type`] = 'Ranged Weapon'; + rangedAttack = true; + } + if (actionType[1] === 'melee or ranged') { + finalSetAttrs[`${repeatingString}type`] = 'Other'; + } + } + if (actionType[2]) { + actionType[2] = actionType[2].toLowerCase(); + if (actionType[2] === 'spell') { + spellAttack = true; + } + } + freetext = freetext.replace(typeRegex, ''); + } + + const reach = reachRegex.exec(freetext); + if (reach && reach[1]) { + finalSetAttrs[`${repeatingString}reach`] = `${reach[1]}ft.`; + freetext = freetext.replace(reachRegex, ''); + } + const range = rangeRegex.exec(freetext); + if (range && range[1] && range[2]) { + finalSetAttrs[`${repeatingString}range`] = `${range[1]}ft.`; + freetext = freetext.replace(rangeRegex, ''); + } + + const toHit = toHitRegex.exec(freetext); + if (toHit && toHit[1]) { + let hitBonus = toHit[1]; + hitBonus -= pb; + + hitBonus = getCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, 'attack_ability', hitBonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod); + + if (hitBonus) { + finalSetAttrs[`${repeatingString}attack_bonus`] = hitBonus; + } + freetext = freetext.replace(toHitRegex, ''); + finalSetAttrs[`${repeatingString}roll_toggle`] = '@{roll_toggle_var}'; + } else { + finalSetAttrs[`${repeatingString}roll_toggle`] = '0'; + } + + const savingThrow = savingThrowRegex.exec(freetext); + if (savingThrow) { + if (savingThrow[1]) { + let savingThrowTotal = savingThrow[1]; + savingThrowTotal -= 8; + savingThrowTotal -= pb; + + savingThrowTotal = getAnyCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, 'saving_throw_ability', savingThrowTotal, abilityMods); + + if (savingThrowTotal) { + finalSetAttrs[`${repeatingString}saving_throw_bonus`] = savingThrowTotal; + } + freetext = freetext.replace(savingThrowRegex, ''); + finalSetAttrs[`${repeatingString}saving_throw_toggle`] = '@{saving_throw_toggle_var}'; + } + if (savingThrow[2]) { + finalSetAttrs[`${repeatingString}saving_throw_vs_ability`] = savingThrow[2]; + } + const halfDamage = saveSuccessRegex.exec(freetext); + if (halfDamage && halfDamage[1]) { + finalSetAttrs[`${repeatingString}saving_throw_success`] = halfDamage[1]; + freetext = freetext.replace(saveSuccessRegex, ''); + } + } else { + finalSetAttrs[`${repeatingString}saving_throw_toggle`] = '0'; + } + + freetext = parseDamage(finalSetAttrs, repeatingString, freetext, damageRegex, 'damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); + freetext = parseDamage(finalSetAttrs, repeatingString, freetext, altDamageRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); + freetext = parseDamage(finalSetAttrs, repeatingString, freetext, damagePlusRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); + if (!exists(finalSetAttrs[`${repeatingString}second_damage`])) { + freetext = parseDamage(finalSetAttrs, repeatingString, freetext, damageRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); + } + + finalSetAttrs[`${repeatingString}extras_toggle`] = '@{extras_var}'; + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:repeating_trait:freetext', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_trait', eventInfo); + parseAction(repeatingInfo.rowId, 'trait'); }); -on('change:repeating_action', function (eventInfo) { - var changedField = getRepeatingField('repeating_action', eventInfo); - if (changedField !== 'to_hit' && changedField !== 'attack_formula' && changedField !== 'damage_formula' && changedField !== 'second_damage_formula' && changedField !== 'damage_string' && changedField !== 'saving_throw_dc' && changedField !== 'parsed' && changedField !== 'recharge_display') { - console.log('action changedField', changedField); - var rowId = getRowId('repeating_action', eventInfo); - updateAction('action', rowId); - } +on('change:repeating_action:freetext', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_action', eventInfo); + parseAction(repeatingInfo.rowId, 'action'); }); -on('change:repeating_reaction', function (eventInfo) { - var changedField = getRepeatingField('repeating_reaction', eventInfo); - if (changedField !== 'to_hit' && changedField !== 'attack_formula' && changedField !== 'damage_formula' && changedField !== 'second_damage_formula' && changedField !== 'damage_string' && changedField !== 'saving_throw_dc' && changedField !== 'parsed' && changedField !== 'recharge_display') { - console.log('reaction changedField', changedField); - var rowId = getRowId('repeating_reaction', eventInfo); - updateAction('reaction', rowId); - } +on('change:repeating_reaction:freetext', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_reaction', eventInfo); + parseAction(repeatingInfo.rowId, 'reaction'); }); -on('change:repeating_legendaryaction', function (eventInfo) { - var changedField = getRepeatingField('repeating_legendaryaction', eventInfo); - if (changedField !== 'to_hit' && changedField !== 'attack_formula' && changedField !== 'damage_formula' && changedField !== 'second_damage_formula' && changedField !== 'damage_string' && changedField !== 'saving_throw_dc' && changedField !== 'parsed' && changedField !== 'recharge_display') { - console.log('legendaryaction changedField', changedField); - var rowId = getRowId('repeating_legendaryaction', eventInfo); - updateAction('legendaryaction', rowId); - } +on('change:repeating_legendaryaction:freetext', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_legendaryaction', eventInfo); + parseAction(repeatingInfo.rowId, 'legendaryaction'); }); -on('change:repeating_lairaction', function (eventInfo) { - var changedField = getRepeatingField('repeating_lairaction', eventInfo); - if (changedField !== 'to_hit' && changedField !== 'attack_formula' && changedField !== 'damage_formula' && changedField !== 'second_damage_formula' && changedField !== 'damage_string' && changedField !== 'saving_throw_dc' && changedField !== 'parsed' && changedField !== 'recharge_display') { - console.log('lairaction changedField', changedField); - var rowId = getRowId('repeating_lairaction', eventInfo); - updateAction('lairaction', rowId); - } +on('change:repeating_lairaction:freetext', (eventInfo) => { + const repeatingInfo = getRepeatingInfo('repeating_lairaction', eventInfo); + parseAction(repeatingInfo.rowId, 'lairaction'); }); -function parseDamage (finalSetAttrs, repeatingString, freetext, regex, name, spellMods, meleeMods, spellAttack, rangedAttack, dexMod) { - var damageParseRegex = /(\d+d?\d+)(?:\s?(?:\+|\-)\s?(\d+))?/gi; - var damage = regex.exec(freetext); - var damageBonus; - if (damage) { - /* - 1 is damage without dice. Example '1' - 2 is damage with dice. Example '2d6+4' - 3 is damage type. Example 'slashing' or 'lightning or thunder' - */ - if (damage[1]) { - damageBonus = damage[1]; - } - if (damage[2]) { - var damageParsed = damageParseRegex.exec(damage[2]); - if (damageParsed) { - if (damageParsed[1]) { - finalSetAttrs[repeatingString + name] = damageParsed[1]; - } - if (damageParsed[2]) { - damageBonus = damageParsed[2]; - } - } - } - damageBonus = getCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, name + '_ability', damageBonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod); - if (damage[3]) { - finalSetAttrs[repeatingString + name + '_type'] = damage[3]; - } - if (damageBonus) { - finalSetAttrs[repeatingString + name + '_bonus'] = damageBonus; - } - freetext = freetext.replace(regex, ''); - finalSetAttrs[repeatingString + name + '_toggle'] = '@{' + name + '_toggle_var}'; - } else { - finalSetAttrs[repeatingString + name + '_toggle'] = 0; - } - return freetext; -} +const countAction = (type) => { + const repeatingItem = `repeating_${type}`; + const collectionArray = [`${type}s_exist`]; + const finalSetAttrs = {}; -function parseAction (rowId, type) { - var repeatingItem = 'repeating_' + type; - var collectionArray = ['level', 'challenge', 'global_attack_bonus', 'global_melee_attack_bonus', 'global_ranged_attack_bonus', 'global_damage_bonus', 'global_melee_damage_bonus', 'global_ranged_damage_bonus', 'default_ability']; - var finalSetAttrs = {}; + finalSetAttrs[`${type}s_exist`] = 0; - var damageType = /((?:[\w]+|[\w]+\s(?:or|and)\s[\w]+)(?:\s*?\([\w\s]+\))?)\s*?damage\s?(\([\w\'\s]+\))?/; - var damageSyntax = /(?:(\d+)|.*?\(([\dd\s\+\-]*)\).*?)\s*?/; - var altDamageSyntax = /(?:\,\s*?or\s*?)/; - var plus = /\s*?plus\s*?/; - var savingThrow = /(?:DC)\s*?(\d+)\s*?([a-zA-Z]*)\s*?(?:saving throw)/; - var saveSuccess = /or\s(.*)?\son a successful one./; - var damageRegex = new RegExp(damageSyntax.source + damageType.source, 'i'); - var damagePlusRegex = new RegExp(plus.source + damageSyntax.source + damageType.source, 'i'); - var altDamageRegex = new RegExp(altDamageSyntax.source + damageSyntax.source + damageType.source, 'i'); - var savingThrowRegex = new RegExp(savingThrow.source, 'i'); - var saveSuccessRegex = new RegExp(saveSuccess.source, 'i'); - - var typeRegex = /(melee|ranged|melee or ranged)\s*(spell|weapon)\s*/gi; - var toHitRegex = /:\s?\+\s?(\d+)\s*(?:to hit)/gi; - var reachRegex = /(?:reach)\s?(\d+)\s?(?:ft)/gi; - var rangeRegex = /(?:range)\s?(\d+)\/(\d+)\s?(ft)/gi; - var spellcastingRegex = /(\d+)\w+\slevel\s\((\d+)\s?slot(?:s)?\)/gi; - var spellcastingAbilityRegex = /spellcasting ability is (\w+)/i; - - for (var i = 0; i < ABILITIES.length; i++) { - collectionArray.push(ABILITIES[i] + '_mod'); - } - - getSectionIDs(repeatingItem, function (ids) { - if (rowId) { - ids = []; - ids.push(rowId); - } - for (var i = 0; i < ids.length; i++) { - var repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'freetext'); - } - - getAttrs(collectionArray, function (v) { - var pb = getPB(v.level, v.challenge); - var strMod = getIntValue(v.strength_mod); - var dexMod = getIntValue(v.dexterity_mod); - var conMod = getIntValue(v.constitution_mod); - var intMod = getIntValue(v.intelligence_mod); - var wisMod = getIntValue(v.wisdom_mod); - var chaMod = getIntValue(v.charisma_mod); - var meleeMods = [strMod, dexMod]; - var spellMods = [intMod, wisMod, chaMod]; - var abilityMods = [strMod, dexMod, conMod, intMod, wisMod, chaMod]; - - for (var j = 0; j < ids.length; j++) { - var repeatingString = repeatingItem + '_' + ids[j] + '_'; - - var rangedAttack = false; - var spellAttack = false; - - var name = v[repeatingString + 'name']; - var freetext = v[repeatingString + 'freetext']; - - if (name === 'Spellcasting') { - var spellcastingSearch = spellcastingAbilityRegex.exec(freetext); - if (spellcastingSearch && spellcastingSearch[1]) { - var spellcastingAbility = spellcastingSearch[1].toLowerCase(); - finalSetAttrs.default_ability = '@{' + spellcastingAbility + '_mod}'; - } - while (match = spellcastingRegex.exec(freetext)) { - if (match && match[1] && match[2]) { - finalSetAttrs['spell_slots_l' + match[1] + '_bonus'] = match[2]; - } - } - } - - var actionType = typeRegex.exec(freetext); - if (actionType) { - if (actionType[1]) { - actionType[1] = type[1].toLowerCase(); - if (actionType[1] === 'melee') { - finalSetAttrs[repeatingString + 'type'] = 'Melee Weapon'; - } - if (actionType[1] === 'ranged') { - finalSetAttrs[repeatingString + 'type'] = 'Ranged Weapon'; - rangedAttack = true; - } - if (actionType[1] === 'melee or ranged') { - finalSetAttrs[repeatingString + 'type'] = 'Other'; - } - } - if (actionType[2]) { - actionType[2] = type[2].toLowerCase(); - if (actionType[2] === 'spell') { - spellAttack = true; - } - } - freetext = freetext.replace(typeRegex, ''); - } - - var reach = reachRegex.exec(freetext); - if (reach && reach[1]) { - finalSetAttrs[repeatingString + 'reach'] = reach[1] + 'ft.'; - freetext = freetext.replace(reachRegex, ''); - } - var range = rangeRegex.exec(freetext); - if (range && range[1] && range[2]) { - finalSetAttrs[repeatingString + 'range'] = range[1] + 'ft.'; - freetext = freetext.replace(rangeRegex, ''); - } - - var toHit = toHitRegex.exec(freetext); - if (toHit && toHit[1]) { - var hitBonus = toHit[1]; - hitBonus -= pb; - - hitBonus = getCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, 'attack_ability', hitBonus, spellMods, meleeMods, spellAttack, rangedAttack, dexMod); - - if (hitBonus) { - finalSetAttrs[repeatingString + 'attack_bonus'] = hitBonus; - } - freetext = freetext.replace(toHitRegex, ''); - finalSetAttrs[repeatingString + 'roll_toggle'] = '@{roll_toggle_var}'; - } else { - finalSetAttrs[repeatingString + 'roll_toggle'] = '0'; - } - - var savingThrow = savingThrowRegex.exec(freetext); - if (savingThrow) { - if (savingThrow[1]) { - var savingThrowTotal = savingThrow[1]; - savingThrowTotal -= 8; - savingThrowTotal -= pb; - - savingThrowTotal = getAnyCorrectAbilityBasedOnBonus(finalSetAttrs, repeatingString, 'saving_throw_ability', savingThrowTotal, abilityMods); - - if (savingThrowTotal) { - finalSetAttrs[repeatingString + 'saving_throw_bonus'] = savingThrowTotal; - } - freetext = freetext.replace(savingThrowRegex, ''); - finalSetAttrs[repeatingString + 'saving_throw_toggle'] = '@{saving_throw_toggle_var}'; - } - if (savingThrow[2]) { - finalSetAttrs[repeatingString + 'saving_throw_vs_ability'] = savingThrow[2]; - } - var halfDamage = saveSuccessRegex.exec(freetext); - if (halfDamage && halfDamage[1]) { - finalSetAttrs[repeatingString + 'saving_throw_success'] = halfDamage[1]; - freetext = freetext.replace(saveSuccessRegex, ''); - } - } else { - finalSetAttrs[repeatingString + 'saving_throw_toggle'] = '0'; - } - - freetext = parseDamage(finalSetAttrs, repeatingString, freetext, damageRegex, 'damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); - freetext = parseDamage(finalSetAttrs, repeatingString, freetext, altDamageRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); - freetext = parseDamage(finalSetAttrs, repeatingString, freetext, damagePlusRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); - if (!exists(finalSetAttrs[repeatingString + 'second_damage'])) { - freetext = parseDamage(finalSetAttrs, repeatingString, freetext, damageRegex, 'second_damage', spellMods, meleeMods, spellAttack, rangedAttack, dexMod); - } - - finalSetAttrs[repeatingString + 'extras_toggle'] = '@{extas_var}'; - } - setFinalAttrs(v, finalSetAttrs); - for (var x = 0; x < ids.length; x++) { - updateAction(type, ids[x]); - } - }); - }); -} -on('change:repeating_trait:freetext', function (eventInfo) { - var rowId = getRowId('repeating_trait', eventInfo); - parseAction(rowId, 'trait'); + getSectionIDs(repeatingItem, (ids) => { + if (ids.length > 0) { + finalSetAttrs[`${type}s_exist`] = 1; + } + getAttrs(collectionArray, (v) => { + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:repeating_trait remove:repeating_trait', () => { + countAction('trait'); }); -on('change:repeating_action:freetext', function (eventInfo) { - var rowId = getRowId('repeating_action', eventInfo); - parseAction(rowId, 'action'); +on('change:repeating_action remove:repeating_action', () => { + countAction('action'); }); -on('change:repeating_reaction:freetext', function (eventInfo) { - var rowId = getRowId('repeating_reaction', eventInfo); - parseAction(rowId, 'reaction'); +on('change:repeating_reaction remove:repeating_reaction', () => { + countAction('reaction'); }); -on('change:repeating_legendaryaction:freetext', function (eventInfo) { - var rowId = getRowId('repeating_legendaryaction', eventInfo); - parseAction(rowId, 'legendaryaction'); +on('change:repeating_legendaryaction remove:repeating_legendaryaction', () => { + countAction('legendaryaction'); }); -on('change:repeating_lairaction:freetext', function (eventInfo) { - var rowId = getRowId('repeating_lairaction', eventInfo); - parseAction(rowId, 'lairaction'); +on('change:repeating_lairaction remove:repeating_lairaction', () => { + countAction('lairaction'); }); -function countAction (type) { - var repeatingItem = 'repeating_' + type; - var finalSetAttrs = {}; +const switchToNPC = () => { + const collectionArray = ['is_npc', 'size']; + const finalSetAttrs = {}; - finalSetAttrs[type + 's_exist'] = 0; + getAttrs(collectionArray, (v) => { + const isNPC = getIntValue(v.is_npc) === 1; - getSectionIDs(repeatingItem, function (ids) { - if (ids.length > 0) { - finalSetAttrs[type + 's_exist'] = 1; - } - setFinalAttrs({}, finalSetAttrs); - }); -} -on('change:repeating_trait remove:repeating_trait', function () { - countAction('trait'); -}); -on('change:repeating_action remove:repeating_action', function () { - countAction('action'); -}); -on('change:repeating_reaction remove:repeating_reaction', function () { - countAction('reaction'); -}); -on('change:repeating_legendaryaction remove:repeating_legendaryaction', function () { - countAction('legendaryaction'); -}); -on('change:repeating_lairaction remove:repeating_lairaction', function () { - countAction('lairaction'); + if (isNPC && isUndefined(v.size)) { + finalSetAttrs.size = 'Large'; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:is_npc', () => { + switchToNPC(); }); +const updateSize = () => { + const collectionArray = ['size']; + const finalSetAttrs = {}; -function switchToNPC () { - var collectionArray = ['is_npc', 'size']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - var isNPC = getIntValue(v.is_npc) === 1; - - if (isNPC && isUndefined(v.size)) { - finalSetAttrs.size = 'Large'; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:is_npc', function () { - switchToNPC(); + getAttrs(collectionArray, (v) => { + const creatureSize = v.size || 'Large'; + const sizeToHdSize = { + Tiny: 4, + Small: 6, + Medium: 8, + Large: 10, + Huge: 12, + Gargantuan: 20, + }; + finalSetAttrs.hit_die = `d${sizeToHdSize[creatureSize]}`; + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:size', () => { + updateSize(); }); -function updateSize () { - var collectionArray = ['size']; - var finalSetAttrs = {}; +const updateType = () => { + const collectionArray = ['type']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - var creatureSize = v.size || 'Large'; - var sizeToHdSize = { - Tiny: 4, - Small: 6, - Medium: 8, - Large: 10, - Huge: 12, - Gargantuan: 20 - }; - finalSetAttrs.hit_die = 'd' + sizeToHdSize[creatureSize]; - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:size', function () { - updateSize(); + getAttrs(collectionArray, (v) => { + if (v.type) { + finalSetAttrs.type = lowercaseWords(v.type); + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:type', () => { + updateType(); }); -function updateType () { - var collectionArray = ['type']; - var finalSetAttrs = {}; +const updateAlignment = () => { + const collectionArray = ['alignment', 'is_npc']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - if (v.type) { - finalSetAttrs.type = lowercaseWords(v.type); - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:type', function () { - updateType(); + getAttrs(collectionArray, (v) => { + if (v.alignment && v.is_npc) { + finalSetAttrs.alignment = lowercaseWords(v.alignment); + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:alignment', () => { + updateAlignment(); }); -function updateAlignment () { - var collectionArray = ['alignment']; - var finalSetAttrs = {}; +const updateSenses = () => { + const collectionArray = ['senses']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - if (v.alignment) { - finalSetAttrs.alignment = lowercaseWords(v.alignment); - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:alignment', function () { - updateAlignment(); + getAttrs(collectionArray, (v) => { + if (v.senses) { + finalSetAttrs.senses_exist = 1; + finalSetAttrs.senses = lowercaseWords(v.senses); + } else { + finalSetAttrs.senses_exist = 0; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:senses', () => { + updateSenses(); }); -function updateSenses () { - var collectionArray = ['senses']; - var finalSetAttrs = {}; +const updateLanguages = () => { + const collectionArray = ['languages']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - if (v.senses) { - finalSetAttrs.senses_exist = 1; - finalSetAttrs.senses = lowercaseWords(v.senses); - } else { - finalSetAttrs.senses_exist = 0; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:senses', function () { - updateSenses(); + getAttrs(collectionArray, (v) => { + if (v.languages) { + finalSetAttrs.languages_exist = 1; + } else { + finalSetAttrs.languages_exist = 0; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:languages', () => { + updateLanguages(); }); -function updateLanguages () { - var collectionArray = ['languages']; - var finalSetAttrs = {}; +const updateSpeed = () => { + const collectionArray = ['npc_speed']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - if (v.languages) { - finalSetAttrs.languages_exist = 1; - } else { - finalSetAttrs.languages_exist = 0; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:languages', function () { - updateLanguages(); + getAttrs(collectionArray, (v) => { + finalSetAttrs.npc_speed = lowercaseWords(v.npc_speed); + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:npc_speed', () => { + updateSpeed(); }); -function updateSpeed () { - var collectionArray = ['npc_speed']; - var finalSetAttrs = {}; +const updateACNote = () => { + const collectionArray = ['ac_note']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - finalSetAttrs.npc_speed = lowercaseWords(v.npc_speed); - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:npc_speed', function () { - updateSpeed(); + getAttrs(collectionArray, (v) => { + finalSetAttrs.ac_note = lowercaseWords(v.ac_note); + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:ac_note', () => { + updateACNote(); }); -function updateACNote () { - var collectionArray = ['ac_note']; - var finalSetAttrs = {}; +const updateDamageVulnerabilities = () => { + const collectionArray = ['damage_vulnerabilities']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - finalSetAttrs.ac_note = lowercaseWords(v.ac_note); - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:ac_note', function () { - updateACNote(); + getAttrs(collectionArray, (v) => { + if (v.damage_vulnerabilities) { + finalSetAttrs.damage_vulnerabilities_exist = 1; + finalSetAttrs.damage_vulnerabilities = lowercaseDamageTypes(v.damage_vulnerabilities); + } else { + finalSetAttrs.damage_vulnerabilities_exist = 0; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:damage_vulnerabilities', () => { + updateDamageVulnerabilities(); +}); +const updateDamageResistances = () => { + const collectionArray = ['damage_resistances']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + if (v.damage_resistances) { + finalSetAttrs.damage_resistances_exist = 1; + finalSetAttrs.damage_resistances = lowercaseDamageTypes(v.damage_resistances); + } else { + finalSetAttrs.damage_resistances_exist = 0; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:damage_resistances', () => { + updateDamageResistances(); +}); +const updateDamageImmunities = () => { + const collectionArray = ['damage_immunities']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + if (v.damage_immunities) { + finalSetAttrs.damage_immunities_exist = 1; + finalSetAttrs.damage_immunities = lowercaseDamageTypes(v.damage_immunities); + } else { + finalSetAttrs.damage_immunities_exist = 0; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:damage_immunities', () => { + updateDamageImmunities(); +}); +const updateConditionImmunities = () => { + const collectionArray = ['condition_immunities']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + if (v.condition_immunities) { + finalSetAttrs.condition_immunities_exist = 1; + finalSetAttrs.condition_immunities = lowercaseDamageTypes(v.condition_immunities); + } else { + finalSetAttrs.condition_immunities_exist = 0; + } + setFinalAttrs(v, finalSetAttrs); + }); +}; +on('change:condition_immunities', () => { + updateConditionImmunities(); }); -function updateDamageVulnerabilities () { - var collectionArray = ['damage_vulnerabilities']; - var finalSetAttrs = {}; +const updateLanguageSelection = () => { + const collectionArray = ['lang']; + const finalSetAttrs = {}; - getAttrs(collectionArray, function (v) { - if (v.damage_vulnerabilities) { - finalSetAttrs.damage_vulnerabilities_exist = 1; - finalSetAttrs.damage_vulnerabilities = lowercaseDamageTypes(v.damage_vulnerabilities); - } else { - finalSetAttrs.damage_vulnerabilities_exist = 0; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:damage_vulnerabilities', function () { - updateDamageVulnerabilities(); -}); -function updateDamageResistances () { - var collectionArray = ['damage_resistances']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - if (v.damage_resistances) { - finalSetAttrs.damage_resistances_exist = 1; - finalSetAttrs.damage_resistances = lowercaseDamageTypes(v.damage_resistances); - } else { - finalSetAttrs.damage_resistances_exist = 0; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:damage_resistances', function () { - updateDamageResistances(); -}); -function updateDamageImmunities () { - var collectionArray = ['damage_immunities']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - if (v.damage_immunities) { - finalSetAttrs.damage_immunities_exist = 1; - finalSetAttrs.damage_immunities = lowercaseDamageTypes(v.damage_immunities); - } else { - finalSetAttrs.damage_immunities_exist = 0; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:damage_immunities', function () { - updateDamageImmunities(); -}); -function updateConditionImmunities () { - var collectionArray = ['condition_immunities']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - if (v.condition_immunities) { - finalSetAttrs.condition_immunities_exist = 1; - finalSetAttrs.condition_immunities = lowercaseDamageTypes(v.condition_immunities); - } else { - finalSetAttrs.condition_immunities_exist = 0; - } - setFinalAttrs(v, finalSetAttrs); - }); -} -on('change:condition_immunities', function () { - updateConditionImmunities(); -}); - -function updateLanguageSelection() { - var collectionArray = ['lang']; - var finalSetAttrs = {}; - - getAttrs(collectionArray, function (v) { - var language = v.lang; + getAttrs(collectionArray, (v) => { + const language = v.lang; if (language) { if (language === 'English') { @@ -3335,196 +4497,356 @@ function updateLanguageSelection() { } setFinalAttrs(v, finalSetAttrs); }); -} +}; -function setSkillStorageNames () { - var repeatingItem = 'repeating_skill'; - var collectionArray = ['lang']; - var finalSetAttrs = {}; +const resourcesToClassFeatures = () => { + const repeatingItem = 'repeating_resource'; + const newRepeatingItem = 'repeating_classfeature'; + const collectionArray = []; + const finalSetAttrs = {}; - var repeatingString; - - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'storage_name'); - } - - getAttrs(collectionArray, function (v) { - var language = v.lang; - if (!language || language === 'en') { - for (var i = 0; i < ids.length; i++) { - repeatingString = repeatingItem + '_' + ids[i] + '_'; - - var name = v[repeatingString + 'name']; - if (!isUndefined(name)) { - var storageName = skills.names.en.getKeyByValue(name); - - if (storageName && isUndefined(v[repeatingString + 'storage_name'])) { - finalSetAttrs[repeatingString + 'storage_name'] = storageName; - } - } - } - setFinalAttrs(v, finalSetAttrs); - } - }); - }); -} -function generateSkills () { - var repeatingItem = 'repeating_skill'; - var collectionArray = ['lang']; - var finalSetAttrs = {}; - - var repeatingString; - - getSectionIDs(repeatingItem, function (ids) { - for (var i = 0; i < ids.length; i++) { - repeatingString = repeatingItem + '_' + ids[i] + '_'; - collectionArray.push(repeatingString + 'name'); - collectionArray.push(repeatingString + 'ability'); + let repeatingString; + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}uses`); + collectionArray.push(`${repeatingString}uses_max`); + collectionArray.push(`${repeatingString}toggle_details`); + collectionArray.push(`${repeatingString}recharge`); + collectionArray.push(`${repeatingString}extras_toggle`); + collectionArray.push(`${repeatingString}freetext`); + collectionArray.push(`${repeatingString}freeform`); } - getAttrs(collectionArray, function (v) { - var language = v.lang; - if (!language || !skills.names[language]) { - language = 'en'; + getAttrs(collectionArray, (v) => { + console.log('v', v); + for (let i = 0; i < ids.length; i++) { + repeatingString = `${repeatingItem}_${ids[i]}_`; + const newRowId = generateRowID(); + const newRepeatingString = `${newRepeatingItem}_${newRowId}_`; + + finalSetAttrs[`${newRepeatingString}name`] = v[`${repeatingString}name`]; + finalSetAttrs[`${newRepeatingString}uses`] = v[`${repeatingString}uses`]; + finalSetAttrs[`${newRepeatingString}uses_max`] = v[`${repeatingString}uses_max`]; + finalSetAttrs[`${newRepeatingString}toggle_details`] = v[`${repeatingString}toggle_details`]; + finalSetAttrs[`${newRepeatingString}recharge`] = v[`${repeatingString}recharge`]; + finalSetAttrs[`${newRepeatingString}extras_toggle`] = v[`${repeatingString}extras_toggle`]; + finalSetAttrs[`${newRepeatingString}freetext`] = v[`${repeatingString}freetext`]; + finalSetAttrs[`${newRepeatingString}freeform`] = v[`${repeatingString}freeform`]; } - - var x = 0; - Object.keys(skills.abilities).forEach(function(key) { - var name = skills.names[language][key]; - var ability = skills.abilities[key]; - var skillId; - - if (ids[x]) { - skillId = ids[x]; - } else { - skillId = generateRowID(); - } - repeatingString = repeatingItem + '_' + skillId + '_'; - finalSetAttrs[repeatingString + 'name'] = name; - finalSetAttrs[repeatingString + 'storage_name'] = key; - finalSetAttrs[repeatingString + 'ability'] = '@{' + ability + '_mod}'; - updateSkill(skillId); - - x++; - }); + console.log('resourcesToClassFeatures', finalSetAttrs); setFinalAttrs(v, finalSetAttrs); }); }); -} -on('change:lang', function () { +}; + +const setSkillStorageNames = () => { + const repeatingItem = 'repeating_skill'; + const collectionArray = ['lang']; + const finalSetAttrs = {}; + + let repeatingString; + + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}storage_name`); + collectionArray.push(`${repeatingString}name`); + } + + getAttrs(collectionArray, (v) => { + const language = v.lang; + if (!language || language === 'en') { + for (let i = 0; i < ids.length; i++) { + repeatingString = `${repeatingItem}_${ids[i]}_`; + + const name = v[`${repeatingString}name`]; + if (!isUndefined(name)) { + const storageName = getKeyByValue(TRANSLATIONS.en.SKILLS, name); + if (storageName && isUndefined(v[`${repeatingString}storage_name`])) { + finalSetAttrs[`${repeatingString}storage_name`] = storageName; + } + } + } + setFinalAttrs(v, finalSetAttrs); + } + }); + }); +}; +const generateSkills = () => { + const repeatingItem = 'repeating_skill'; + const collectionArray = ['lang']; + const finalSetAttrs = {}; + + let repeatingString; + + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}name`); + collectionArray.push(`${repeatingString}ability`); + } + + getAttrs(collectionArray, (v) => { + const language = v.lang || 'en'; + + let x = 0; + + for (const prop in SKILLS) { + if (SKILLS.hasOwnProperty(prop)) { + let skillId; + if (ids[x]) { + skillId = ids[x]; + } else { + skillId = generateRowID(); + } + repeatingString = `${repeatingItem}_${skillId}_`; + + finalSetAttrs[`${repeatingString}storage_name`] = prop; + finalSetAttrs[`${repeatingString}name`] = translate(language, `SKILLS.${prop}`); + + finalSetAttrs[`${repeatingString}ability`] = `@{${SKILLS[prop]}_mod}`; + updateSkill(skillId); + + x++; + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; +on('change:lang', () => { generateSkills(); + updateLevels(); }); -on('change:generate_skills', function () { +on('change:generate_skills', () => { generateSkills(); }); -function sheetOpened () { - var collectionArray = ['version', 'strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma']; - var finalSetAttrs = {}; +on('change:pb', () => { + updateSkill(); + updateAttack(); + updateSpell(); + updateJackOfAllTrades(); + updateRemarkableAthlete(); + updateAction('trait'); + updateAction('action'); + updateAction('reaction'); + updateAction('legendaryaction'); + updateAction('lairaction'); +}); - getAttrs(collectionArray, function (v) { - var version = v.version; +const extasToExtrasFix = (repeatingItem) => { + const collectionArray = []; + const finalSetAttrs = {}; - if (!version) { - updatePb(); + getSectionIDs(repeatingItem, (ids) => { + for (let i = 0; i < ids.length; i++) { + const repeatingString = `${repeatingItem}_${ids[i]}_`; + collectionArray.push(`${repeatingString}extas_toggle`); + } - var setAbilities = {}; - if (isUndefined(v.strength)) { - setAbilities.strength = 10; - setAbilities.strength_mod = 0; - setAbilities.strength_mod_with_sign = '+0'; - } - if (isUndefined(v.dexterity)) { - setAbilities.dexterity = 10; - setAbilities.dexterity_mod = 0; - setAbilities.dexterity_mod_with_sign = '+0'; - } - if (isUndefined(v.constitution)) { - setAbilities.constitution = 10; - setAbilities.constitution_mod = 0; - setAbilities.constitution_mod_with_sign = '+0'; - } - if (isUndefined(v.intelligence)) { - setAbilities.intelligence = 10; - setAbilities.intelligence_mod = 0; - setAbilities.intelligence_mod_with_sign = '+0'; - } - if (isUndefined(v.wisdom)) { - setAbilities.wisdom = 10; - setAbilities.wisdom_mod = 0; - setAbilities.wisdom_mod_with_sign = '+0'; - } - if (isUndefined(v.charisma)) { - setAbilities.charisma = 10; - setAbilities.charisma_mod = 0; - setAbilities.charisma_mod_with_sign = '+0'; - } - setFinalAttrs(v, setAbilities); + getAttrs(collectionArray, (v) => { + for (let j = 0; j < ids.length; j++) { + const repeatingString = `${repeatingItem}_${ids[j]}_`; - finalSetAttrs.edit_mode = 'on'; + const extrasToggle = v[`${repeatingString}extas_toggle`]; + if (!isUndefined(extrasToggle)) { + finalSetAttrs[`${repeatingString}extras_toggle`] = extrasToggle; + } + } + setFinalAttrs(v, finalSetAttrs); + }); + }); +}; + +const sheetOpened = () => { + const collectionArray = ['version', 'strength', 'dexterity', 'constitution', 'intelligence', 'wisdom', 'charisma', 'import_data']; + const finalSetAttrs = {}; + + getAttrs(collectionArray, (v) => { + const version = v.version; + + if (!version) { + updatePb(); + + const setAbilities = {}; + if (isUndefined(v.strength)) { + setAbilities.strength = 10; + setAbilities.strength_mod = 0; + setAbilities.strength_mod_with_sign = '+0'; + } + if (isUndefined(v.dexterity)) { + setAbilities.dexterity = 10; + setAbilities.dexterity_mod = 0; + setAbilities.dexterity_mod_with_sign = '+0'; + } + if (isUndefined(v.constitution)) { + setAbilities.constitution = 10; + setAbilities.constitution_mod = 0; + setAbilities.constitution_mod_with_sign = '+0'; + } + if (isUndefined(v.intelligence)) { + setAbilities.intelligence = 10; + setAbilities.intelligence_mod = 0; + setAbilities.intelligence_mod_with_sign = '+0'; + } + if (isUndefined(v.wisdom)) { + setAbilities.wisdom = 10; + setAbilities.wisdom_mod = 0; + setAbilities.wisdom_mod_with_sign = '+0'; + } + if (isUndefined(v.charisma)) { + setAbilities.charisma = 10; + setAbilities.charisma_mod = 0; + setAbilities.charisma_mod_with_sign = '+0'; + } + setFinalAttrs(v, setAbilities); + + if (!v.import_data) { + finalSetAttrs.edit_mode = 'on'; + } generateSkills(); - updateSavingThrows(); - updateLevels(); - updateAbilityChecksMacro(); - } + updateSavingThrows(); + updateLevels(); + updateAbilityChecksMacro(); + updateInitiative(); + updateArmor(); + } - if (versionCompare(version, '2.0.10') < 0) { - updateAbilityModifiers(); - } + if (versionCompare(version, '2.0.10') < 0) { + updateAbilityModifiers(); + } - if (versionCompare(version, '2.0.14') < 0) { - console.log('in if'); - updateSkill(); - updateSavingThrows(); - } - if (versionCompare(version, '2.1.0') < 0) { - updateNPCChallenge(); - updateDamageVulnerabilities(); - updateDamageResistances(); - updateDamageImmunities(); - updateConditionImmunities(); - updateLanguages(); - updateSenses(); - } - if (versionCompare(version, '2.1.3') < 0) { - updateType(); - updateAlignment(); - } + if (versionCompare(version, '2.0.14') < 0) { + updateSkill(); + updateSavingThrows(); + } + if (versionCompare(version, '2.1.0') < 0) { + updateNPCChallenge(); + updateDamageVulnerabilities(); + updateDamageResistances(); + updateDamageImmunities(); + updateConditionImmunities(); + updateLanguages(); + updateSenses(); + } + if (versionCompare(version, '2.1.3') < 0) { + updateType(); + updateAlignment(); + } if (versionCompare(version, '2.1.5') < 0) { updateLevels(); updateNPCAC(); updateLanguageSelection(); } - if (versionCompare(version, '2.1.7') < 0) { - setSkillStorageNames(); - } - if (versionCompare(version, '2.1.10') < 0) { - updateSavingThrows(); - updateAttack(); - } - if (versionCompare(version, '2.1.11') < 0) { - updateLevels(); - updateAbilityChecksMacro(); - } - if (versionCompare(version, '2.1.13') < 0) { - weighEquipment(); - updateSpell(); - } + if (versionCompare(version, '2.1.7') < 0) { + setSkillStorageNames(); + } + if (versionCompare(version, '2.1.10') < 0) { + updateSavingThrows(); + updateAttack(); + } + if (versionCompare(version, '2.1.11') < 0) { + updateLevels(); + updateAbilityChecksMacro(); + } + if (versionCompare(version, '2.1.13') < 0) { + weighEquipment(); + updateSpell(); + } + if (versionCompare(version, '2.1.14') < 0) { + updateLevels(); + } + if (versionCompare(version, '2.1.15') < 0) { + updateLevels(); + displayTextForTraits(); + } + if (versionCompare(version, '2.2.1') < 0) { + updateAbilityModifiers(); + } + if (versionCompare(version, '2.2.2') < 0) { + resourcesToClassFeatures(); + } + if (versionCompare(version, '2.2.4') < 0) { + updateInitiative(); + } + if (versionCompare(version, '2.2.5') < 0) { + weighAmmo(); + } + if (versionCompare(version, '2.2.6') < 0) { + updateClassFeatureToggleToNewVer(); + updateLevels(); + extasToExtrasFix('repeating_attack'); + extasToExtrasFix('repeating_action'); + extasToExtrasFix('repeating_spell'); + } + if (versionCompare(version, '2.2.8') < 0) { + updateAttack(); + } + if (versionCompare(version, '2.2.11') < 0) { + setClassFeatures(); + } + if (versionCompare(version, '2.2.12') < 0) { + updateAbilityChecksMacro(); + } + if (versionCompare(version, '2.2.15') < 0) { + updateAbilityChecksMacro(); + updatePreAndPostRoll(); + } - if (!version || version !== currentVersion) { - finalSetAttrs.version = currentVersion; - } - setFinalAttrs(v, finalSetAttrs); + if (!version || version !== currentVersion) { + finalSetAttrs.version = currentVersion; + } - updateInitiative(); - updateArmor(); - }); -} + setFinalAttrs(v, finalSetAttrs); + }); +}; -on('sheet:opened', function () { - sheetOpened(); +const importData = () => { + getAttrs(['import_data'], v => { + if (v.import_data) { + const finalSetAttrs = {}; + const importObject = JSON.parse(v.import_data); + + if (importObject.npc) { + for (const prop in importObject.npc) { + if (importObject.npc.hasOwnProperty(prop)) { + finalSetAttrs[prop] = importObject.npc[prop]; + } + } + } + if (importObject.spells) { + importObject.spells.forEach(spell => { + const newRowId = generateRowID(); + const repeatingString = `repeating_spell_${newRowId}_`; + for (const prop in spell) { + if (spell.hasOwnProperty(prop)) { + finalSetAttrs[`${repeatingString}${prop}`] = spell[prop]; + } + } + }); + } + finalSetAttrs.import_data = ''; + finalSetAttrs.import_data_present = 'off'; + setFinalAttrs(v, finalSetAttrs); + } + }); +}; + +const deleteImportData = () => { + setFinalAttrs({}, { + import_data: '', + import_data_present: 'off', + }); +}; + +on('change:accept_import', importData); +on('change:reject_import', deleteImportData); + + +on('sheet:opened', () => { + sheetOpened(); }); diff --git a/D&D_5e_Reshaped/precompiled/components/spells/sorceryPoints.html b/D&D_5e_Reshaped/precompiled/components/spells/sorceryPoints.html deleted file mode 100644 index 527b353536..0000000000 --- a/D&D_5e_Reshaped/precompiled/components/spells/sorceryPoints.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
-
-
?
-
{{'SORCERY_POINTS_RECHARGE_TOOLTIP' | translate}}
-
-
-
-
- -
-
/
-
- -
-
-
- {{'SORCERY_POINTS' | translate}} -
-
\ No newline at end of file diff --git a/D&D_5e_Reshaped/precompiled/components/spells/spell.html b/D&D_5e_Reshaped/precompiled/components/spells/spell.html index c08cc32fe4..e27e7a368c 100644 --- a/D&D_5e_Reshaped/precompiled/components/spells/spell.html +++ b/D&D_5e_Reshaped/precompiled/components/spells/spell.html @@ -30,25 +30,25 @@ - y + y -
+
@@ -180,8 +180,10 @@
-
+
+ ( + )
diff --git a/D&D_5e_Reshaped/precompiled/components/spells/spell_slots_points.html b/D&D_5e_Reshaped/precompiled/components/spells/spellSlots.html similarity index 97% rename from D&D_5e_Reshaped/precompiled/components/spells/spell_slots_points.html rename to D&D_5e_Reshaped/precompiled/components/spells/spellSlots.html index eb4ddcfc3c..cb946320e6 100644 --- a/D&D_5e_Reshaped/precompiled/components/spells/spell_slots_points.html +++ b/D&D_5e_Reshaped/precompiled/components/spells/spellSlots.html @@ -1,6 +1,6 @@
- {{'SPELL_SLOTS' | translate}} - {{'SPELL_POINTS' | translate}} + {{'SPELL_SLOTS' | translate}} + {{'SPELL_POINTS' | translate}}
diff --git a/D&D_5e_Reshaped/precompiled/components/spells/spellcasting_bonuses.html b/D&D_5e_Reshaped/precompiled/components/spells/spellcastingBonuses.html similarity index 100% rename from D&D_5e_Reshaped/precompiled/components/spells/spellcasting_bonuses.html rename to D&D_5e_Reshaped/precompiled/components/spells/spellcastingBonuses.html diff --git a/D&D_5e_Reshaped/precompiled/components/spells/spells.html b/D&D_5e_Reshaped/precompiled/components/spells/spells.html index 212286e022..80bc551331 100644 --- a/D&D_5e_Reshaped/precompiled/components/spells/spells.html +++ b/D&D_5e_Reshaped/precompiled/components/spells/spells.html @@ -4,35 +4,35 @@
- Filters - {{'PREPARED' | translate}} - {{'RITUAL' | translate}} + Filters + {{'PREPARED' | translate}} + {{'RITUAL' | translate}} - {{'CANTRIPS' | translate}}123456789{{'ALL' | translate}} + {{'CANTRIPS' | translate}}123456789{{'ALL' | translate}} - {{'REACTION' | translate}}{{'BONUS' | translate}}{{'ACTION' | translate}}{{'ALL' | translate}} + {{'REACTION' | translate}}{{'BONUS' | translate}}{{'ACTION' | translate}}{{'ALL' | translate}} {{'SPELL_CAN_HAVE' | translate}}: - {{'CONCENTRATION' | translate}} - V - S - M + {{'CONCENTRATION' | translate}} + V + S + M
-
{{'SPELL' | translate}}
+
{{'SPELL' | translate}}
{{'LEVEL' | translate}}
-
{{'CASTING_TIME' | translate}}
+
{{'CASTING_TIME' | translate}}
{{'CONC' | translate}}
-
{{'SPELL' | translate}}
+
{{'SPELL' | translate}}
{{'LEVEL' | translate}}
-
{{'CASTING_TIME' | translate}}
+
{{'CASTING_TIME' | translate}}
{{'CONC' | translate}}
@@ -45,16 +45,10 @@
- //= include spell_slots_points.html -
- //= include sorceryPoints.html -
-
- //= include warlockSlots.html -
+ //= include spellSlots.html
- //= include spellcasting_bonuses.html + //= include spellcastingBonuses.html
{{'BONUSES_AND_PENALTIES' | translate}}
diff --git a/D&D_5e_Reshaped/precompiled/components/spells/warlockSlots.html b/D&D_5e_Reshaped/precompiled/components/spells/warlockSlots.html deleted file mode 100644 index 9065a59592..0000000000 --- a/D&D_5e_Reshaped/precompiled/components/spells/warlockSlots.html +++ /dev/null @@ -1,24 +0,0 @@ -
-
-
-
?
-
{{'WARLOCK_SLOTS_RECHARGE_TOOLTIP' | translate}}
-
-
-
-
-
-
- -
-
/
-
- -
-
-
-
-
- {{'WARLOCK_SPELL_SLOTS' | translate}} -
-
diff --git a/D&D_5e_Reshaped/precompiled/components/npc/traits.html b/D&D_5e_Reshaped/precompiled/components/traits/traits.html similarity index 60% rename from D&D_5e_Reshaped/precompiled/components/npc/traits.html rename to D&D_5e_Reshaped/precompiled/components/traits/traits.html index ac88aaf5ae..60509a5a99 100644 --- a/D&D_5e_Reshaped/precompiled/components/npc/traits.html +++ b/D&D_5e_Reshaped/precompiled/components/traits/traits.html @@ -1,19 +1,18 @@
-
- -
-
-
- -
-
+
+
+ +
+
-
{{'TYPE' | translate}}
-
+
{{'TYPE' | translate}}
+
-
- +
+ -
{{'RECHARGE' | translate}}
-
+
{{'RECHARGE' | translate}}
+
+
+ y +
+
+ +
{{'DISPLAY_TEXT' | translate}}
//= include ../actionComponents/savingThrow.html diff --git a/D&D_5e_Reshaped/precompiled/gulpfile.js b/D&D_5e_Reshaped/precompiled/gulpfile.js index ee24f7ee0a..ed55a1c3e4 100644 --- a/D&D_5e_Reshaped/precompiled/gulpfile.js +++ b/D&D_5e_Reshaped/precompiled/gulpfile.js @@ -1,18 +1,22 @@ -var gulp = require('gulp'); -var include = require('gulp-include'); -var inject = require('gulp-inject'); -var minifyHTML = require('gulp-minify-html'); -var minifyCss = require('gulp-minify-css'); -var concat = require('gulp-concat'); -var sass = require('gulp-sass'); -var jshint = require('gulp-jshint'); -var sassLint = require('gulp-sass-lint'); -var replace = require('gulp-replace-task'); -var rename = require('gulp-rename'); -var change = require('gulp-change'); -var fs = require('fs'); +'use strict'; -var translations = {}; +const gulp = require('gulp'); +const include = require('gulp-include'); +const inject = require('gulp-inject'); +const minifyHTML = require('gulp-minify-html'); +const minifyCss = require('gulp-minify-css'); +const concat = require('gulp-concat'); +const sass = require('gulp-sass'); +const sassLint = require('gulp-sass-lint'); +const replaceTask = require('gulp-replace-task'); +const rename = require('gulp-rename'); +const change = require('gulp-change'); +const fs = require('fs'); +const babel = require('gulp-babel'); +const eslint = require('gulp-eslint'); +const wrapper = require('gulp-wrapper'); + +const translations = {}; String.prototype.capitalize = function () { return this.replace(/\w\S*/g, function (txt) { @@ -33,9 +37,9 @@ function getTranslation () { function objByString (o, s) { s = s.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties s = s.replace(/^\./, ''); // strip a leading dot - var a = s.split('.'); - for (var i = 0, n = a.length; i < n; ++i) { - var k = a[i]; + const a = s.split('.'); + for (let i = 0, n = a.length; i < n; ++i) { + const k = a[i]; if (k in o) { o = o[k]; } else { @@ -51,7 +55,7 @@ function getTranslationsIfTheyDontExist () { } } function translationWrapper (lang, key) { - var translation = objByString(translations[lang], key); + let translation = objByString(translations[lang], key); if(!translation) { translation = objByString(translations.en, key) @@ -61,13 +65,13 @@ function translationWrapper (lang, key) { } function translate (key) { getTranslationsIfTheyDontExist(); - var translation = translationWrapper('en', key) + translationWrapper('de', key) + translationWrapper('fr', key) + translationWrapper('ru', key); + const translation = translationWrapper('en', key) + translationWrapper('de', key) + translationWrapper('fr', key) + translationWrapper('ru', key); return translation; } function duplicate(file, limit, start) { - var template = file.contents.toString('utf8'); - var s = []; + const template = file.contents.toString('utf8'); + const s = []; if (!start) { start = 0; @@ -75,7 +79,7 @@ function duplicate(file, limit, start) { limit += start; } - for (var i = start; i < limit; i++) { + for (let i = start; i < limit; i++) { s.push(template .replace(/\x7B\x7Bnum\x7D\x7D/g, i.toString()) ); @@ -86,7 +90,7 @@ function duplicate(file, limit, start) { gulp.task('preCompile', function () { return gulp.src('./D&D_5e.html') .pipe(include()) - .pipe(replace({ + .pipe(replaceTask({ patterns: [ { match: /\x7B\x7B'([A-Za-z_0-9\.]+)'\s\|\stranslate\x7D\x7D/g, @@ -99,20 +103,10 @@ gulp.task('preCompile', function () { .pipe(minifyHTML({ whitespace: true })) - .pipe(replace({ - patterns: [ - { - match: /text\/worker/g, - replacement: function () { - return '"text/worker"'; - } - } - ] - })) .pipe(gulp.dest('../')); }); -var sassConfig = { +const sassConfig = { rules: { 'clean-import-paths': 0, 'force-element-nesting': 0, @@ -130,23 +124,60 @@ gulp.task('sass', function () { .pipe(sassLint.failOnError()) */ .pipe(sass().on('error', sass.logError)) - .pipe(gulp.dest('../')); -}); - -gulp.task('minify-css', ['sass'], function () { - return gulp.src('../D&D_5e.css') .pipe(minifyCss()) .pipe(gulp.dest('../')); }); -gulp.task('jshint', function() { - return gulp.src('components/sheetWorkers.js') - .pipe(jshint()) - .pipe(jshint.reporter('jshint-stylish')); +var esLintConfig = { + parser: 'babel-eslint', + extends: 'airbnb/base', + rules: { + 'arrow-body-style': 0, + 'indent': 0, + 'max-len': 0, + 'no-cond-assign': 0, + 'no-console': 0, + 'no-param-reassign': 0, + 'no-undef': 0 + } +}; +gulp.task('lint', function() { + return gulp.src(['components/sheetWorkers.js']) + .pipe(eslint(esLintConfig)) + .pipe(eslint.format()) + .pipe(eslint.failAfterError()); }); -gulp.task('compile', ['preCompile', 'minify-css', 'jshint'], function () { - return gulp.src(['../D&D_5e.html', './components/rollTemplate.html']) +gulp.task('compileJS', function() { + return gulp.src(['components/sheetWorkers.js']) + .pipe(replaceTask({ + patterns: [ + { + match: /(let TRANSLATIONS;)/i, + replacement: function () { + let translations = {}; + translations.de = JSON.parse(fs.readFileSync('./translations/de.json')); + translations.en = JSON.parse(fs.readFileSync('./translations/en.json')); + translations.fr = JSON.parse(fs.readFileSync('./translations/fr.json')); + translations.ru = JSON.parse(fs.readFileSync('./translations/ru.json')); + return `const TRANSLATIONS = ${JSON.stringify(translations)};`; + } + } + ] + })) + .pipe(babel({ + presets: ['es2015'], + comments: false + })) + .pipe(wrapper({ + header: '' + })) + .pipe(gulp.dest('./')); +}); + +gulp.task('compile', ['preCompile', 'sass', 'compileJS'], function () { + return gulp.src(['../D&D_5e.html', './sheetWorkers.js', './components/rollTemplate.html']) .pipe(concat('D&D_5e.html')) .pipe(gulp.dest('../')); }); diff --git a/D&D_5e_Reshaped/precompiled/package.json b/D&D_5e_Reshaped/precompiled/package.json index 84f9e5613b..494810ab63 100644 --- a/D&D_5e_Reshaped/precompiled/package.json +++ b/D&D_5e_Reshaped/precompiled/package.json @@ -1,26 +1,28 @@ { "name": "dnd_5e_shaped_character_sheet", - "version": "2.1.13", + "version": "2.2.16", "bin": "./", "description": "D&D 5e Shaped character sheet on Roll20.net", "main": "gulpfile.js", "dependencies": {}, "devDependencies": { + "babel-eslint": "4.1.6", + "eslint-config-airbnb": "3.1.0", "gulp": "^3.9.0", + "gulp-babel": "6.1.2", "gulp-change": "^1.0.0", "gulp-concat": "^2.6.0", "gulp-include": "^2.1.0", "gulp-inject": "^3.0.0", + "gulp-eslint": "1.1.1", "gulp-minify-css": "^1.2.2", "gulp-minify-html": "^1.0.4", "gulp-rename": "^1.2.2", "gulp-replace-task": "^0.11.0", "gulp-sass": "^2.1.1", "gulp-sass-lint": "^1.1.1", - "gulp-uglify": "^1.5.1", - "jshint": "^2.9.1", - "gulp-jshint": "^2.0.0", - "jshint-stylish": "^2.1.0" + "gulp-wrapper": "1.0.0", + "babel-preset-es2015": "6.6.0" }, "scripts": {}, "repository": { diff --git a/D&D_5e_Reshaped/precompiled/translations/de.json b/D&D_5e_Reshaped/precompiled/translations/de.json index d89ed4cffa..cb22949178 100644 --- a/D&D_5e_Reshaped/precompiled/translations/de.json +++ b/D&D_5e_Reshaped/precompiled/translations/de.json @@ -108,24 +108,24 @@ "CASTING_TIME": "Zauberzeit", "CHALLENGE": "Herausforderung", "CHARACTER": "Charakter", - "CHARACTER_NAME": "Charakter Name", - "CHARACTER_NAME_ON_ROLL_TEMPLATES": "Charakter Name auf allen Würfen", + "CHARACTER_NAME": "Charaktename", + "CHARACTER_NAME_ON_ROLL_TEMPLATES": "Charaktername bei allen Würfen", "CHECK": "Check", - "CHECK_BONUS": "Check bonus", + "CHECK_BONUS": "Check-Bonus", "CLASS": "Klasse", "CLASS_AND_LEVEL": "Klasse & Stufe", "CLASS_LEVELS": "Klassenstufen", "CLIMB": "Klettern", - "COIN_CONVERSION_GP_PER_CP": "Kupfer pro Gold (standard 100)", - "COIN_CONVERSION_GP_PER_SP": "Silber pro Gold (standard 10)", - "COIN_CONVERSION_GP_PER_EP": "Elektrum pro Gold (standard 2)", - "COIN_CONVERSION_GP_PER_PP": "Gold pro Platinum (standard 10)", + "COIN_CONVERSION_GP_PER_CP": "Kupfer pro Gold (100)", + "COIN_CONVERSION_GP_PER_SP": "Silber pro Gold (10)", + "COIN_CONVERSION_GP_PER_EP": "Elektrum pro Gold (2)", + "COIN_CONVERSION_GP_PER_PP": "Gold pro Platinum (10)", "COINAGE": "Münzen", - "COINS_CP": "KP", - "COINS_SP": "SP", - "COINS_EP": "EP", - "COINS_GP": "GP", - "COINS_PP": "PP", + "COINS_CP": "KM", + "COINS_SP": "SM", + "COINS_EP": "EM", + "COINS_GP": "GM", + "COINS_PP": "PM", "COMPONENTS": "Komponenten", "CONC": "Konz.", "CONCENTRATION": "Konzentration", @@ -180,30 +180,30 @@ "HALFLING_LUCK": "Halblings Glück", "HEAL": "Heilung", "HEIGHT": "Höhe", - "HIDE_NPC_INFO": "Hide NPC info", - "HIDE_NPC_INFO_ACTION_FREETEXT": "Hide Action freetext", - "HIDE_NPC_INFO_EFFECT": "Hide Effect", + "HIDE_NPC_INFO": "Verstecke NPC Info", + "HIDE_NPC_INFO_ACTION_FREETEXT": "Verstecke Action Freitexte", + "HIDE_NPC_INFO_EFFECT": "Verstecke Effekt", "HIDE_NPC_INFO_NOTE": "Please see the wiki. You'll need to use a browser extension to change the css to show certain parts", - "HIDE_NPC_INFO_RECHARGE": "Hide Recharge", - "HIDE_NPC_INFO_SAVING_THROW_DC": "Hide Saving throw DC", - "HIDE_NPC_INFO_SAVING_THROW_FAILURE": "Hide Saving throw failure", - "HIDE_NPC_INFO_SAVING_THROW_SUCCESS": "Hide Saving throw success", - "HIDE_NPC_INFO_SPELL_CONTENT": "Hide Spell content", - "HIGHER_LEVEL": "Higher level", - "HIT_DICE": "Hit dice", - "HIT_POINTS": "Hit Points", - "HIT_POINTS_TEMP": "Temp HP", + "HIDE_NPC_INFO_RECHARGE": "Verstecke Wiederaufladung", + "HIDE_NPC_INFO_SAVING_THROW_DC": "Verstecke Rettungswurf SG", + "HIDE_NPC_INFO_SAVING_THROW_FAILURE": "Verstecke Rettungswurf Fehlschlag", + "HIDE_NPC_INFO_SAVING_THROW_SUCCESS": "Verstecke Rettungswurf Erfolg", + "HIDE_NPC_INFO_SPELL_CONTENT": "Verstecke Zauberinfo", + "HIGHER_LEVEL": "Höhere Stufe", + "HIT_DICE": "Trefferwürfel", + "HIT_POINTS": "Trefferpunkte", + "HIT_POINTS_TEMP": "Temp TP", "HOVER": "Schweben", "IDEALS": "Ideale", "INITIATIVE": "Initiative", - "INITIATIVE_BONUS": "Initiative bonus", + "INITIATIVE_BONUS": "Initiative Bonus", "INITIATIVE_BREAK_TIES": "Break Initiative Ties", - "INITIATIVE_ROLL": "Initiative Roll", + "INITIATIVE_ROLL": "Initiative Wurf", "INSPIRATION": "Inspiration", "JACK_OF_ALL_TRADES": "Jack of all trades", "LAIR_ACTIONS": "Lair Actions", "LANGUAGES": "Sprachen", - "LEGENDARY_ACTIONS": "Legendary actions", + "LEGENDARY_ACTIONS": "Legendäre Aktionen", "LEGENDARY_ACTIONS_TEXT_1": "The", "LEGENDARY_ACTIONS_TEXT_2": "can take", "LEGENDARY_ACTIONS_TEXT_3": "legendary actions, choosing from the options below. Only one legendary option can be used at a time and only at the end of another creature's turn. The", @@ -211,7 +211,7 @@ "LEVEL": "Stufe", "MACROS": "Makros", "MAX": "Max", - "MEDIUM_ARMOR_MAX_DEX": "Medium armor max dex", + "MEDIUM_ARMOR_MAX_DEX": "Mittlere Rüstung Max Gesch.", "MELEE": "Nahkampf", "MISC": "Sonstiges", "MISCELLANEOUS_NOTES": "Sonstige Notizen", @@ -221,9 +221,9 @@ "OTHER_PROFICIENCIES_AND_LANGUAGES": "Andere Befähigungen", "OUTPUT": "Ausgabe", "OUTPUT_DEATH_SAVING_THROWS": "Todesrettungswürfe", - "OUTPUT_SHEET": "Sheet output", - "OUTPUT_INITIATIVE": "Initiative output", - "PERSONALITY_TRAITS": "Personality traits", + "OUTPUT_SHEET": "Bogen Ausgabe", + "OUTPUT_INITIATIVE": "Initiative Ausgabe", + "PERSONALITY_TRAITS": "Persönlichkeitsmerkmale", "PREPARED": "Vorbereitet", "PROF": "Befähigt", "PROFICIENCIES": "Befähigungen", @@ -233,12 +233,12 @@ "PC": "PC", "RACE": "Rasse", "RANGE": "Reichweite", - "RANGED": "Reichweite", - "REACH": "Reichweite", + "RANGED": "Fernkampf", + "REACH": "Bereich", "REACTION": "Reaktion", "REACTIONS": "Reaktionen", "RECHARGE": "Aufladung", - "REMARKABLE_ATHLETE": "Remarkable Athlete", + "REMARKABLE_ATHLETE": "Herausragender Athlet", "RESISTANCES_AND_IMMUNITIES": "Resistenzen & Immunitäten", "RESOURCES": "Ressourcen", "RITUAL": "Ritual", @@ -250,15 +250,15 @@ "SAVING_THROWS": "Rettungswürfe", "SENSES": "Sinne", "SHOW_ALL": "Zeige alles", - "SHOW_TARGET_AC_ON_ATTACKS": "Show Target's AC on Attacks", - "SHOW_TARGET_NAME_ON_ATTACKS": "Show Target's Name on Attacks and Saves", + "SHOW_TARGET_AC_ON_ATTACKS": "Zeige Ziel-RK bei Angriffen", + "SHOW_TARGET_NAME_ON_ATTACKS": "Zeige Ziel-Name bei Angriffen", "SIZE": "Größe", "SKILL": "Fertigkeit", "SKILLS_TITLE": "Fertigkeiten", - "SKIN": "Haut", + "SKIN": "Hautfarbe", "SORCERY_POINTS": "Hexpunkte", "SORCERY_POINTS_RECHARGE_TOOLTIP": "Recharges on a long rest (4 recharge on a short rest if lvl 20)", - "SPEED": "Geschwindigkeit", + "SPEED": "Geschw.", "SPELL": "Zauber", "SPELLCASTING": "Zaubern", "SPELL_CAN_HAVE": "Zauber kann haben", @@ -273,7 +273,7 @@ "SWIM": "Schwimmen", "TARGET": "Ziel", "TOTAL": "Gesamt", - "TREMORSENSE": "Bebensinn", + "TREMORSENSE": "Erschütterungssinn", "TRUESIGHT": "Wahrsicht", "TYPE": "Typ", "VISION": "Sicht", diff --git a/D&D_5e_Reshaped/precompiled/translations/en.json b/D&D_5e_Reshaped/precompiled/translations/en.json index 184298dd46..c776c9a351 100644 --- a/D&D_5e_Reshaped/precompiled/translations/en.json +++ b/D&D_5e_Reshaped/precompiled/translations/en.json @@ -34,6 +34,202 @@ "SHORT_NAME": "Cha" } }, + "CLASS_FEATURES": { + "ACTION_SURGE": "Action Surge", + "ACTION_SURGE_TEXT": "On your turn, you can take one additional action on top of your regular action and a possible bonus action.", + "ARCANE_RECOVERY": "Arcane Recovery", + "ARCANE_RECOVERY_TEXT": "You have learned to regain some of your magical energy by studying your spellbook. Once per day when you finish a short rest, you can choose expended spell slots to recover. The spell slots can have a combined level of [[round(@{wizard_level} / 2)]] (half your wizard level rounded up), and none of the slots can be 6th level or higher.\nFor example, if you're a 4th-level wizard, you can recover up to two levels worth of spell slots. You can recover either a 2nd-level spell slot or two 1st-level spell slots.", + "ARCHDRUID": "Archdruid", + "ARCHDRUID_TEXT": "You can use your Wild Shape an unlimited number of times.\nAdditionally, you can ignore the verbal and somatic components of your druid spells, as well as any material components that lack a cost and aren't consumed by a spell. You gain this benefit in both your normal shape and your beast shape from Wild Shape.", + "AURA_OF_COURAGE": "Aura of Courage", + "AURA_OF_COURAGE_TEXT": "You and friendly creatures within AURA_RANGE feet of you can't be frightened while you are conscious.", + "AURA_OF_PROTECTION": "Aura of Protection", + "AURA_OF_PROTECTION_TEXT": "Whenever you or a friendly creature within AURA_RANGE feet of you must make a saving throw, the creature gains a bonus to the saving throw equal to [[@{charisma_mod}]] (with a minimum bonus of +1). You must be conscious to grant this bonus.", + "BARDIC_INSPIRATION": "Bardic Inspiration", + "BARDIC_INSPIRATION_TEXT": "You can inspire others through stirring words or music. To do so, you use a bonus action on your turn to choose one creature other than yourself within 60 feet of you who can hear you. That creature gains one Bardic Inspiration die, a d6.\nOnce within the next 10 minutes, the creature can roll the die and add the number rolled to one ability check, attack roll, or saving throw it makes. The creature can wait until after it rolls the d20 before deciding to use the Bardic Inspiration die, but must decide before the GM says whether the roll succeeds or fails. Once the Bardic Inspiration die is rolled, it is lost. A creature can have only one Bardic Inspiration die at a time.", + "BEAST_SPELLS": "Beast Spells", + "BEAST_SPELLS_TEXT": "You can cast many of your druid spells in any shape you assume using Wild Shape. You can perform the somatic and verbal components of a druid spell while in a beast shape, but you aren't able to provide material components", + "BLINDSENSE": "Blindsense", + "BLINDSENSE_TEXT": "If you are able to hear, you are aware of the location of any hidden or invisible creature within 10 feet of you.", + "BRUTAL_CRITICAL": "Brutal Critical", + "BRUTAL_CRITICAL_TEXT": "You can roll one additional weapon damage die when determining the extra damage for a critical hit with a melee attack.\nThis increases to two additional dice at 13th level and three additional dice at 17th level.", + "CHANNEL_DIVINITY": "Channel Divinity", + "CHANNEL_DIVINITY_CLERIC_TEXT": "You gain the ability to channel divine energy directly from your deity, using that energy to fuel magical effects. You start with two such effects: Turn Undead and an effect determined by your domain. Some domains grant you additional effects as you advance in levels, as noted in the domain description", + "CHANNEL_DIVINITY_PALADIN_TEXT": "Your oath allows you to channel divine energy to fuel magical effects. Each Channel Divinity option provided by your oath explains how to use it.", + "CHANNEL_DIVINITY_TURN_UNDEAD": "Turn Undead (Channel Divinity)", + "CHANNEL_DIVINITY_TURN_UNDEAD_TEXT": "As an action,you present your holy symbol and speak a prayer censuring the undead. Each undead that can see or hear you within 30 feet of you must make a Wisdom saving throw. If the creature fails its saving throw, it is turned for 1 minute or until it takes any damage.\nA turned creature must spend its turns trying to move as far away from you as it can, and it can't willingly move to a space within 30 feet of you. It also can't take reactions. For its action, it can use only the Dash action or try to escape from an effect that prevents it from moving. If there's nowhere to move, the creature can use the Dodge action.", + "CHANNEL_DIVINITY_TURN_UNDEAD_TEXT_PART_2": "Starting at 5th level, when an undead fails its saving throw against your Turn Undead feature, the creature is instantly destroyed if its challenge rating is CHALLENGE_RATING or lower", + "COUNTERCHARM": "Countercharm", + "COUNTERCHARM_TEXT": "You gain the ability to use musical notes or words of power to disrupt mind-influencing effects. As an action, you can start a performance that lasts until the end of your next turn. During that time, you and any friendly creatures within 30 feet of you have advantage on saving throws against being frightened or charmed. A creature must be able to hear you to gain this benefit. The performance ends early if you are incapacitated or silenced or if you voluntarily end it (no action required).", + "CUNNING_ACTION": "Cunning Action", + "CUNNING_ACTION_TEXT": "Your quick thinking and agility allow you to move and act quickly. You can take a bonus action on each of your turns in combat. This action can be used only to take the Dash, Disengage, or Hide action.", + "DANGER_SENSE": "Danger Sense", + "DANGER_SENSE_TEXT": "You have advantage on Dexterity saving throws against effects that you can see, such as traps and spells. To gain this benefit, you can't be blinded, deafened, or incapacitated.", + "DEFLECT_MISSILES": "Deflect Missiles", + "DEFLECT_MISSILES_TEXT": "You can use your reaction to deflect or catch the missile when you are hit by a ranged weapon attack. When you do so, the damage you take from the attack is reduced by [[d10 + @{dexterity_mod}[dex] + @{monk_level}[monk level]]].\nIf you reduce the damage to 0, you can catch the missile if it is small enough for you to hold in one hand and you have at least one hand free. Ifyou catch a missile in this way, you can spend 1 ki point to make a ranged attack with the weapon or piece of ammunition you just caught, as part of the same reaction. You make this attack with proficiency, regardless of your weapon proficiencies, and themissile counts as a monk weapon for the attack, which has a normal range of 20 feet and a long range of 60 feet", + "DIAMOND_SOUL": "Diamond Soul", + "DIAMOND_SOUL_TEXT": "Your mastery of ki grants you proficiency in all saving throws.\nAdditionally, whenever you make a saving throw and fail, you can spend 1 ki point to reroll it and take the second result.", + "DIVINE_INTERVENTION": "Divine Intervention", + "DIVINE_INTERVENTION_TEXT": "You can call on your deity to intervene on your behalf when your need is great.\nImploring your deity's aid requires you to use your action. Describe the assistance you seek, and roll percentile dice. If you roll a number equal to or lower than your cleric level, your deity intervenes. The GM chooses the nature of the intervention; the effect of any cleric spell or cleric domain spell would be appropriate.\nIf your deity intervenes, you can't use thisfeature again for 7 days. Otherwise, you can use it again after you finish a long rest.\nAt 20th level, your call for intervention succeeds automatically, no roll required.", + "DIVINE_HEALTH": "Divine Health", + "DIVINE_HEALTH_TEXT": "The divine magic flowing through you makes you immune to disease.", + "DIVINE_SENSE": "Divine Sense", + "DIVINE_SENSE_TEXT": "The presence of strong evil registers on your senses like a noxious odor, and powerful good rings like heavenly music in your ears. As an action, you can open your awareness to detect such forces. Until the end of your next turn, you know the location of any celestial, fiend, or undead within 60 feet of you that is not behind total cover. You know the type (celestial, fiend, or undead) of any being whose presence you sense, but not its identity (the vampire Count Strahd von Zarovich, for instance). Within the same radius, you also detect the presence of any place or object that has been consecrated or desecrated, as with the hallow spell.", + "DIVINE_SMITE": "Divine Smite", + "DIVINE_SMITE_TEXT": "When you hit a creature with a melee weapon attack, you can expend one spell slot to deal radiant damage to the target, in addition to the weapon's damage. The extra damage is 2d8 for a 1st-level spell slot, plus 1d8 for each spell level higher than 1st, to a maximum of 5d8. The damage increases by 1d8 if the target is an undead or a fiend.", + "CLEANSING_TOUCH": "Cleaning Touch", + "CLEANSING_TOUCH_TEXT": "You can use your action to end one spell on yourself or on one willing creature that you touch.", + "ELDRITCH_INVOCATIONS": "Eldritch Invocations", + "ELDRITCH_INVOCATIONS_TEXT": "In your study of occult lore, you have unearthed eldritch invocations, fragments of forbidden knowledge that imbue you with an abiding magical ability.\nYou know NUMBER_OF_INVOCATIONS_KNOWN eldritch invocations.\nAdditionally, when you gain a level in this class, you can choose one of the invocations you know and replace it with another invocation that you could learn at that level.", + "ELDRITCH_MASTER": "Eldritch Master", + "ELDRITCH_MASTER_TEXT": "You can draw on your inner reserve of mystical power while entreating your patron to regain expended spell slots. You can spend 1 minute entreating your patron for aid to regain all your expended spell slots from your Pact Magic feature.", + "ELUSIVE": "Elusive", + "ELUSIVE_TEXT": "You are so evasive that attackers rarely gain the upper hand against you. No attack roll has advantage against you while you aren't incapacitated.", + "EMPTY_BODY": "Empty Body", + "EMPTY_BODY_TEXT": "You can use your action to spend 4 ki points to become invisible for 1 minute. During that time, you also have resistance to all damage but force damage.\nAdditionally, you can spend 8 ki points to cast the astral projection spell, without needing material components. When you do so, you can't take any other creatures with you.", + "EVASION": "Evasion", + "EVASION_TEXT": "Your instinctive agility lets you dodge out of the way of certain area effects, such as a blue dragon's lightning breath or a fireball spell. When you are subjected to an effect that allows you to make a Dexterity saving throw to take only half damage, you instead take no damage if you succeed on the saving throw, and only half damage if you fail.", + "EXPERTISE": "Expertise", + "EXPERTISE_BARD_TEXT": "Choose two of your skill proficiencies. Your proficiency bonus is doubled for any ability check you make that uses either of the chosen proficiencies.\nAt 10th level, you can choose another two skill proficiencies to gain this benefit.", + "EXPERTISE_ROGUE_TEXT": "Choose two of your skill proficiencies, or one of your skill proficiencies and your proficiency with thieves' tools. Your proficiency bonus is doubled for any ability check you make that uses either of the chosen proficiencies.\nAt 6th level, you can choose two more of your proficiencies (in skills or with thieves' tools) to gain this benefit.", + "EXTRA_ATTACK": "Extra Attack", + "EXTRA_ATTACK_TEXT": "You can attack NUMBER_OF_TIMES, instead of once, whenever you take the Attack action on your turn.", + "EXTRA_ATTACK_TWICE": "twice", + "EXTRA_ATTACK_THREE": "three times", + "EXTRA_ATTACK_FOUR": "four times", + "FOE_SLAYER": "Foe Slayer", + "FOE_SLAYER_TEXT": "You become an unparalleled hunter of your enemies. Once on each of your turns, you can add your Wisdom modifier to the attack roll or the damage roll of an attack you make against one of your favored enemies. You can choose to use this feature before or after the roll, but before any effects of the roll are applied.", + "FAST_MOVEMENT": "Fast Movement", + "FAST_MOVEMENT_TEXT": "Your speed increases by 10 feet while you aren't wearing heavy armor.", + "FAVORED_ENEMY": "Favored Enemy", + "FAVORED_ENEMY_TEXT": "You have significant experience studying, tracking, hunting, and even talking to a certain type of enemy.\nChoose a type of favored enemy: aberrations, beasts, celestials, constructs, dragons, elementals, fey, fiends, giants, monstrosities, oozes, plants, or undead. Alternatively, you can select two races of humanoid (such as gnolls and orcs) as favored enemies.\nYou have advantage on Wisdom (Survival) checks to track your favored enemies, as well as on Intelligence checks to recall information about them.\nWhen you gain this feature, you also learn one language of your choice that is spoken by your favored enemies, if they speak one at all.\nYou choose one additional favored enemy, as well as an associated language, at 6th and 14th level. As you gain levels, your choices should reflect the types of monsters you have encountered on your adventures.", + "FERAL_INSTINCT": "Feral Instinct", + "FERAL_INSTINCT_TEXT": "Your instincts are so honed that you have advantage on initiative rolls.\nAdditionally, if you are surprised at the beginning of combat and aren't incapacitated, you can act normally on your first turn, but only if you enter your rage before doing anything else on that turn.", + "FERAL_SENSES": "Feral Senses", + "FERAL_SENSES_TEXT": "You gain preternatural senses that help you fight creatures you can't see. When you attack a creature you can't see, your inability to see it doesn't impose disadvantage on your attack rolls against it.\nYou are also aware of the location of any invisible creature within 30 feet of you, provided that the creature isn't hidden from you and you aren't blinded or deafened.", + "FIGHTING_STYLE": "Fighting Style", + "FIGHTING_STYLE_TEXT": "You adopt a particular style of fighting as your specialty. Choose one of the following options. You can't take a Fighting Style option more than once, even if you later get to choose again.", + "FIGHTING_STYLE_FIGHTER_OPTIONS": "Archery, Defense, Dueling, Great Weapon Fighting, Protection, or Two-Weapon Fighting.", + "FIGHTING_STYLE_PALADIN_OPTIONS": "Defense, Dueling, Great Weapon Fighting, or Protection.", + "FIGHTING_STYLE_RANGER_OPTIONS": "Archery, Defense, Dueling, or Two-Weapon Fighting.", + "FLEXIBLE_CASTING": "Flexible Casting", + "FLEXIBLE_CASTING_TEXT": "Creating Spell Slots. You can transform unexpended sorcery points into one spell slot as a bonus action on your turn. You can create spell slots no higher in level than 5th.Any spell slot you create with this feature vanishes when you finish a long rest.\nSpell Slot Sorcery Point Cost\n 1st 2\n 2nd 3\n 3rd 4\n 4th 6\n 5th 7\nConverting a Spell Slot to Sorcery Points. As a bonus action on your turn, you can expend one spell slot and gain a number of sorcery points equal to the slot's level.", + "FLURRY_OF_BLOWS": "Flurry of Blows", + "FLURRY_OF_BLOWS_TEXT": "Immediately after you take the Attack action on your turn, you can spend 1 ki point to make two unarmed strikes as a bonus action.", + "HIDE_IN_PLAIN_SIGHT": "Hide in Plain Sight", + "HIDE_IN_PLAIN_SIGHT_TEXT": "You can spend 1 minute creating camouflage for yourself. You must have access to fresh mud, dirt, plants, soot, and other naturally occurring materials with which to create your camouflage.\nOnce you are camouflaged in this way, you can try to hide by pressing yourself up against a solid surface, such as a tree or wall, that is at least as tall and wide as you are. You gain a +10 bonus to Dexterity (Stealth) checks as long as you remain there without moving or taking actions. Once you move or take an action or a reaction, you must camouflage yourself again to gain this benefit.", + "IMPROVED_DIVINE_SMITE": "Improved Divine Smite", + "IMPROVED_DIVINE_SMITE_TEXT": "You are so suffused with righteous might that all your melee weapon strikes carry divine power with them. Whenever you hit a creature with a melee weapon, the creature takes an extra 1d8 radiant damage. If you also use your Divine Smite with an attack, you add this damage to the extra damage of your Divine Smite.", + "INDOMITABLE": "Indomitable", + "INDOMITABLE_TEXT": "You can reroll a saving throw that you fail. If you do so, you must use the new roll.", + "INDOMITABLE_MIGHT": "Indomitable Might", + "INDOMITABLE_MIGHT_TEXT": "If your total for a Strength check is less than your Strength score, you can use that score in place of the total.", + "JACK_OF_ALL_TRADES": "Jack of All Trades", + "JACK_OF_ALL_TRADES_TEXT": "You can add half your proficiency bonus, rounded down, to any ability check you make that doesn't already include your proficiency bonus.", + "KI": "Ki", + "KI_TEXT": "Your training allows you to harness the mystic energy of ki. Your access to this energy is represented by a number of ki points.\nYou can spend these points to fuel various ki features. You start knowing three such features: Flurry of Blows, Patient Defense, and Step of the Wind. You learn more ki features as you gain levels in this class.\nWhen you spend a ki point, it is unavailable until you finish a short or long rest, at the end of which you draw all of your expended ki back into yourself. You must spend at least 30 minutes of the rest meditating to regain your ki points.", + "KI_EMPOWERED_STRIKES": "Ki-Empowered Strikes", + "KI_EMPOWERED_STRIKES_TEXT": "Your unarmed strikes count as magical for the purpose of overcoming resistance and immunity to nonmagical attacks and damage.", + "LANDS_STRIDE": "Land's Stride", + "LANDS_STRIDE_TEXT": "Moving through nonmagical difficult terrain costs you no extra movement. You can also pass through nonmagical plants without being slowed by them and without taking damage from them if they have thorns, spines, or a similar hazard.\nIn addition, you have advantage on saving throws against plants that are magically created or manipulated to impede movement, such those created by the entangle spell.", + "LAY_ON_HANDS": "Lay on Hands", + "LAY_ON_HANDS_TEXT": "Your blessed touch can heal wounds. As an action, you can touch a creature to restore a number of hit points to that creature.\nAlternatively, you can expend 5 hit points from your pool of healing to cure the target of one disease or neutralize one poison affecting it. You can cure multiple diseases and neutralize multiple poisons with a single use of Lay on Hands, expending hit points separately for each one.\nThis feature has no effect on undead and constructs.", + "MAGICAL_SECRETS": "Magical Secrets", + "MAGICAL_SECRETS_TEXT": "You have plundered magical knowledge from a wide spectrum of disciplines. Choose two spells from any class, including this one. A spell you choose must be of a level you can cast, as shown on the Bard table, or a cantrip.\nThe chosen spells count as bard spells for you and are included in the number in the Spells Known column of the Bard table.\nYou learn two additional spells from any class at 14th level and again at 18th level.", + "MARTIAL_ARTS": "Martial Arts", + "MARTIAL_ARTS_TEXT": "Your practice of martial arts gives you mastery of combat styles that use unarmed strikes and monk weapons, which are shortswords and any simple melee weapons that don't have the two-‑handed or heavy property.\nYou gain the following benefits while you are unarmed or wielding only monk weapons and you aren't wearing armor or wielding a shield:•\nYou can use Dexterity instead of Strength for the attack and damage rolls of your unarmed strikes and monk weapons.\n•You can roll a d4 in place of the normal damage of your unarmed strike or monk weapon. This die changes as you gain monk levels, as shown in the Martial Arts column of the Monk table.\n•When you use the Attack action with an unarmed strike or a monk weapon on your turn, you can make one unarmed strike as a bonus action. For example, if you take the Attack action and attack with a quarterstaff, you can also make an unarmed strike as a bonus action, assuming you haven't already taken a bonus action this turn.\nCertain monasteries use specialized forms of the monk weapons. For example, you might use a club that is two lengths of wood connected by a short chain (called a nunchaku) or a sickle with a shorter, straighter blade (called a kama). Whatever name you use for a monk weapon, you can use the game statistics provided for the weapon.", + "METAMAGIC": "Metamagic", + "METAMAGIC_TEXT": "You gain the ability to twist your spells to suit your needs. You gain two of the following Metamagic options of your choice. You gain another one at 10th and 17th level.\nYou can use only one Metamagic option on a spell when you cast it, unless otherwise noted.\nCareful Spell, Distant Spell, Empowered Spell, Extended Spell, Heightened Spell, Quickened Spell, Subtle Spell, Twinned Spell.", + "METAMAGIC_CAREFUL_SPELL": "Careful Spell", + "METAMAGIC_CAREFUL_SPELL_TEXT": "When you cast a spell that forces other creatures to make a saving throw, you can protect some of those creatures from the spell's full force. To do so, you spend 1 sorcery point and choose [[@{charisma_mod}]] of those creatures (minimum of one creature). A chosen creature automatically succeeds on its saving throw against the spell.", + "METAMAGIC_DISTANT_SPELL": "Distant Spell", + "METAMAGIC_DISTANT_SPELL_TEXT": "when you cast a spell that has a range of 5 feet or greater, you can spend 1 sorcery point to double the range of the spell.\nWhen you cast a spell that has a range of touch, you can spend 1 sorcery point to make the range of the spell 30 feet.", + "METAMAGIC_EMPOWERED_SPELL": "Empowered Spell", + "METAMAGIC_EMPOWERED_SPELL_TEXT": "When you roll damage for a spell, you can spend 1 sorcery point to reroll [[@{charisma_mod}]] damage dice (minimum of one). You must use the new rolls.\nYou can use Empowered Spell even if you have already used a different Metamagic option during the casting of the spell.", + "METAMAGIC_EXTENDED_SPELL": "Extended Spell", + "METAMAGIC_EXTENDED_SPELL_TEXT": "When you cast a spell that has a duration of 1 minute or longer, you can spend 1 sorcery point to double its duration, to a maximum duration of 24 hours.", + "METAMAGIC_HEIGHTENED_SPELL": "Heightened Spell", + "METAMAGIC_HEIGHTENED_SPELL_TEXT": "When you cast a spell that forces a creature to make a saving throw to resist its effects, you can spend 3 sorcery points to give one target of the spell disadvantage on its first saving throw made against the spell.", + "METAMAGIC_QUICKENED_SPELL": "Quickened Spell", + "METAMAGIC_QUICKENED_SPELL_TEXT": "When you cast a spell that has a casting time of 1 action, you can spend 2 sorcery points to change the casting time to 1 bonus action for this casting.", + "METAMAGIC_SUBTLE_SPELL": "Subtle Spell", + "METAMAGIC_SUBTLE_SPELL_TEXT": "When you cast a spell, you can spend 1 sorcery point to cast it without any somatic or verbal components.", + "METAMAGIC_TWINNED_SPELL": "Twinned Spell", + "METAMAGIC_TWINNED_SPELL_TEXT": "When you cast a spell that targets only one creature and doesn't have a range of self, you can spend a number of sorcery points equal to the spell's level to target a second creature in range with the same spell (1 sorcery point if the spell is a cantrip).\nTo be eligible, a spell must be incapable of targeting more than one creature at the spell's current level. For example, magic missile and scorching ray aren't eligible, but ray of frost and chromatic orb are.", + "MYSTIC_ARCANUM": "Mystic Arcanum", + "MYSTIC_ARCANUM_TEXT": "Your patron bestows upon you a magical secret called an arcanum. Choose one 6th-level spell from the warlock spell list as this arcanum.\nYou can cast your arcanum spell once without expending a spell slot. You must finish a long rest before you can do so again.\nAt higher levels, you gain more warlock spells of your choice that can be cast in this way: one 7th-level spell at 13th level, one 8th-level spell at 15th level, and one 9th-level spell at 17th level. You regain all uses of your Mystic Arcanum when you finish a long rest.", + "NATURAL_EXPLORER": "Natural Explorer", + "NATURAL_EXPLORER_TEXT": "You are particularly familiar with one type of natural environment and are adept at traveling and surviving in such regions. Choose one type of favored terrain: arctic, coast, desert, forest, grassland, mountain, or swamp. When you make an Intelligence or Wisdom check related to your favored terrain, your proficiency bonus is doubled if you are using a skill that you're proficient in.\nWhile traveling for an hour or more in your favored terrain, you gain the following benefits:\n•Difficult terrain doesn't slow your group's travel.\n•Your group can't become lost except by magical means.\n•Even when you are engaged in another activity while traveling (such as foraging, navigating, or tracking), you remain alert to danger.\n•If you are traveling alone, you can move stealthily at a normal pace.\n•When you forage, you find twice as much food as you normally would.\n•While tracking other creatures, you also learn their exact number, their sizes, and how long ago they passed through the area.\nYou choose additional favored terrain types at 6th and 10th level", + "PATIENT_DEFENSE": "Patient Defense", + "PATIENT_DEFENSE_TEXT": "You can spend 1 kipoint to take the Dodge action as a bonus action on your turn.", + "PERFECT_SELF": "Perfect Self", + "PERFECT_SELF_TEXT": "When you roll for initiative and have no ki points remaining, you regain 4 ki points.", + "PERSISTENT_RAGE": "Persistent Rage", + "PERSISTENT_RAGE_TEXT": "Your rage is so fierce that it ends early only if you fall unconscious or if you choose to end it.", + "PRIMAL_CHAMPION": "Primal Champion", + "PRIMAL_CHAMPION_TEXT": "You embody the power of the wilds. Your Strength and Constitution scores increase by 4. Your maximum for those scores is now 24.", + "PRIMEVAL_AWARENESS": "Primeval Awareness", + "PRIMEVAL_AWARENESS_TEXT": "You can use your action and expend one ranger spell slot to focus your awareness on the region around you. For 1 minute per level of the spell slot you expend, you can sense whether the following types of creatures are present within 1 mile of you (or within up to 6 miles if you are in your favored terrain): aberrations, celestials, dragons, elementals, fey, fiends, and undead. This feature doesn't reveal the creatures' location or number.", + "PURITY_OF_BODY": "Purity of Body", + "PURITY_OF_BODY_TEXT": "Your mastery of the ki flowing through you makes you immune to disease and poison.", + "RAGE": "Rage", + "RAGE_TEXT": "On your turn, you can enter a rage as a bonus action. While raging, you gain the following benefits if you aren't wearing heavy armor:\n•You have advantage on Strength checks and Strength saving throws.\n•When you make a melee weapon attack using Strength, you add RAGE_DAMAGE to that damage roll.\n•You have resistance to bludgeoning, piercing, and slashing damage\nIf you are able to cast spells, you can't cast them or concentrate on them while raging.\nYour rage lasts for 1 minute. It ends early if you are knocked unconscious or if your turn ends and you haven't attacked a hostile creature since your last turn or taken damage since then. You can also end your rage on your turn as a bonus action.", + "RECKLESS_ATTACK": "Reckless Attack", + "RECKLESS_ATTACK_TEXT": "When you make your first attack on your turn, you can decide to attack recklessly. Doing so gives you advantage on melee weapon attack rolls using Strength during this turn, but attack rolls against you have advantage until your next turn.", + "RELENTLESS_RAGE": "Relentless Rage", + "RELENTLESS_RAGE_TEXT": "Your rage can keep you fighting despite grievous wounds. If you drop to 0 hit points while you're raging and don't die outright, you can make a DC [[10]] Constitution saving throw. If you succeed, you drop to 1 hit point instead.\nEach time you use this feature after the first, the DC increases by 5. When you finish a short or long rest, the DC resets to 10", + "RELIABLE_TALENT": "Reliable Talent", + "RELIABLE_TALENT_TEXT": "You have refined your chosen skills until they approach perfection. Whenever you make an ability check that lets you add your proficiency bonus, you can treat a d20 roll of 9 or lower as a 10.", + "SECOND_WIND": "Second Wind", + "SECOND_WIND_TEXT": "On your turn, you can use a bonus action to regain hit points.", + "SIGNATURE_SPELLS": "Signature Spells", + "SIGNATURE_SPELLS_TEXT": "You gain mastery over two powerful spells and can cast them with little effort. Choose two 3rd-level wizard spells in your spellbook as your signature spells. You always have these spells prepared, they don't count against the number of spells you have prepared, and you can cast each of them once at 3rd level without expending a spell slot. When you do so, you can't do so again until you finish a short or long rest.\nIf you want to cast either spell at a higher level, you must expend a spell slot as normal.", + "SLIPPERY_MIND": "Slippery Mind", + "SLIPPERY_MIND_TEXT": "You have acquired greater mental strength. You gain proficiency in Wisdom saving throws.", + "SLOW_FALL": "Slow Fall", + "SLOW_FALL_TEXT": "You can use your reaction when you fall to reduce any falling damage you take by [[5 * @{monk_level}]].", + "SNEAK_ATTACK": "Sneak Attack", + "SNEAK_ATTACK_TEXT": "You know how to strike subtly and exploit a foe's distraction. Once per turn, you can deal extra damage to one creature you hit with an attack if you have advantage on the attack roll. The attack must use a finesse or a ranged weapon.\nYou don't need advantage on the attack roll if another enemy of the target is within 5 feet of it, that enemy isn't incapacitated, and you don't have disadvantage on the attack roll.", + "SONG_OF_REST": "Song of Rest", + "SONG_OF_REST_TEXT": "You can use soothing music or oration to help revitalize your wounded allies during a short rest. If you or any friendly creatures who can hear your performance regain hit points at the end of the short rest by spending one or more Hit Dice, each of those creatures regains extra hit points.", + "SPELL_MASTERY": "Spell Mastery", + "SPELL_MASTERY_TEXT": "You have achieved such mastery over certain spells that you can cast them at will. Choose a 1st-level wizard spell and a 2nd-level wizard spell that are in your spellbook. You can cast those spells at their lowest level without expending a spell slot when you have them prepared. If you want to cast either spell at a higher level, you must expend a spell slot as normal.\nBy spending 8 hours in study, you can exchange one or both of the spells you chose for different spells of the same levels.", + "SORCEROUS_RESTORATION": "Sorcerous Restoration", + "SORCEROUS_RESTORATION_TEXT": "You regain 4 expended sorcery points whenever you finish a short rest.", + "SORCERY_POINTS": "Sorcery Points", + "SORCERY_POINTS_TEXT": "You can use your sorcery points to gain additional spell slots, or sacrifice spell slots to gain additional sorcery points.", + "STEP_OF_THE_WIND": "Step of the Wind", + "STEP_OF_THE_WIND_TEXT": "You can spend 1 ki point to take the Disengage or Dash action as a bonus action on your turn, and your jump distance is doubled for the turn.", + "STILLNESS_OF_MIND": "Stillness of Mind", + "STILLNESS_OF_MIND_TEXT": "You can use your action to end one effect on yourself that is causing you to be charmed or frightened.", + "STROKE_OF_LUCK": "Stroke of Luck", + "STROKE_OF_LUCK_TEXT": "You have an uncanny knack for succeeding when you need to. If your attack misses a target within range, you can turn the miss into a hit. Alternatively, if you fail an ability check, you can treat the d20 roll as a 20.", + "STUNNING_STRIKE": "Stunning Strike", + "STUNNING_STRIKE_TEXT": "You can interfere with the flow of ki in an opponent's body. When you hit another creature with a melee weapon attack, you can spend 1 ki point to attempt a stunning strike.", + "SUPERIOR_INSPIRATION": "Superior Inspiration", + "SUPERIOR_INSPIRATION_TEXT": "When you roll initiative and have no uses of Bardic Inspiration left, you regain one use.", + "THIEVES_CANT": "Thieves' Cant", + "THIEVES_CANT_TEXT": "During your rogue training you learned thieves' cant, a secret mix of dialect, jargon, and code that allows you tohide messages in seemingly normal conversation. Only another creature that knows thieves' cant understands such messages. It takes four times longer to convey such a message than it does to speak the same idea plainly.\nIn addition, you understand a set of secret signs and symbols used to convey short, simple messages, such as whether an area is dangerous or the territory of a thieves' guild, whether loot is nearby, or whether the people in an area are easy marks or will provide a safe house for thieves onthe run.", + "TIMELESS_BODY": "Timeless Body", + "TIMELESS_BODY_DRUID_TEXT": "The primal magic that you wield causes you to age more slowly. For every 10 years that pass, your body ages only 1 year.", + "TIMELESS_BODY_MONK_TEXT": "Your ki sustains you sothat you suffer none of the frailty of old age, and you can't be aged magically. You can still die of old age, however. In addition, you no longer need food or water.", + "TONGUE_OF_THE_SUN_AND_MOON": "Tongue of the Sun and Moon", + "TONGUE_OF_THE_SUN_AND_MOON_TEXT": "You learn to touch the ki of other minds so that you understand all spoken languages. Moreover, any creature that can understand a language can understand what you say.", + "UNARMORED_DEFENSE": "Unarmored Defense", + "UNARMORED_DEFENSE_TEXT": "While you are not wearing any armor, your Armor Class equals 10 + your Dexterity modifier + your Constitution modifier. You can use a shield and still gain this benefit.", + "UNARMORED_MOVEMENT": "Unarmored Movement", + "UNARMORED_MOVEMENT_TEXT": "Your speed increases by UNARMORED_MOVEMENT_FEET feet while you are not wearing armor or wielding a shield. This bonus increases when you reach certain monk levels, as shown in the Monk table.\nAt 9th level, you gain the ability to move along vertical surfaces and across liquids on your turn without falling during the move.", + "UNCANNY_DODGE": "Uncanny Dodge", + "UNCANNY_DODGE_TEXT": "When an attacker that you can see hits you with an attack, you can use your reaction to halve the attack's damage against you", + "VANISH": "Vanish", + "VANISH_TEXT": "You can use the Hide action as a bonus action on your turn. Also, you can't be tracked by nonmagical means, unless you choose to leave a trail.", + "WARLOCK_SPELL_SLOTS": "Warlock Spell Slots", + "WARLOCK_SPELL_SLOTS_TEXT": "Spells cast at maximum level.", + "WILD_SHAPE": "Wild Shape", + "WILD_SHAPE_TEXT": "You can use your action to magically assume the shape of a beast that you have seen before. You can transform into any beast that has a challenge rating of CHALLENGE_RATING or lowerLIMITATIONS.\nYou can stay in a beast shape for [[floor(@{druid_level}/2)[half your druid level (rounded down)]]] hours. You then revert to your normal form unless you expend another use of this feature. You can revert to your normal form earlier by using a bonus action on your turn. You automatically revert if you fall unconscious, drop to 0 hit points, or die.\nWhile you are transformed, the following rules apply:\n•Your game statistics are replaced by the statistics of the beast, but you retain your alignment, personality, and Intelligence, Wisdom, and Charisma scores. You also retain all of your skill and saving throw proficiencies, in addition to gaining those of the creature. If the creature has the same proficiency as you and the bonus in its stat block is higher than yours, use the creature's bonus instead of yours. If the creature has any legendary or lair actions, you can't use them.\n•When you transform, you assume the beast's hit points and Hit Dice. When you revert to your normal form, you return to the number of hit points you had before you transformed. However, if you revert as a result of dropping to 0 hit points, any excess damage carries over to your normal form. For example, if you take 10 damage in animal form and have only 1 hit point left, you revert and take 9 damage. As long as the excess damage doesn't reduce your normal form to 0 hit points, you aren't knocked unconscious.\n•You can't cast spells, and your ability to speak or take any action that requires hands is limited to the capabilities of your beast form. Transforming doesn't break your concentration on a spell you've already cast, however, or prevent you from taking actions that are part of a spell, such as call lightning, that you've already cast.\n•You retain the benefit of any features from your class, race, or other source and can use them if the new form is physically capable of doing so. However, you can't use any of your special senses, such as darkvision, unless your new form also has that sense.\n•You choose whether your equipment falls to the ground in your space, merges into your new form, or is worn by it. Worn equipment functions as normal, but the GM decides whether it is practical for the new form to wear a piece of equipment, based on the creature's shape and size. Your equipment doesn't change size or shape to match the new form, and any equipment that the new form can't wear must either fall to the ground or merge with it. Equipment that merges with the form has no effect until you leave the form.", + "WILD_SHAPE_NO_FLYING": "that doesn't have a flying speed", + "WILD_SHAPE_NO_FLYING_OR_SWIMMING": "that doesn't have a flying or swimming speed" + }, "CLASSES": { "BARBARIAN": "Barbarian", "BARD": "Bard", @@ -69,8 +265,8 @@ "survival": "Survival" }, "ABILITY": "Ability", - "ABILITY_SCORE_BONUS": "Ability score bonus", - "ABILITY_CHECKS": "Ability Checks", + "ABILITY_SCORES": "Ability scores", + "ABILITY_CHECKS": "Ability checks", "ABILITY_CHECKS_QUERY": "Ability Checks Query", "AC": "AC", "AC_ARMORED": "Armored AC", @@ -82,6 +278,7 @@ "ALIGNMENT": "Alignment", "ALL": "All", "AMMO": "Ammo", + "AMMO_AUTO_USE": "Automatically use ammo", "AMMO_WEIGHT": "Ammo weight", "ARMOR": "Armor", "ARMOR_CLASS": "Armor Class", @@ -100,6 +297,7 @@ "BONUSES_AND_PENALTIES_TOOLTIP": "Auto add a bonus/penalty to rolls made using the sheet macros.
Usage: you acquire a magic item that gives +1 to your spell save DC, enter 1 in the spell save DC field. You are under the effects of the Bless spell, enter \"d4cs0cf0\" in both attack roll fields, and the saving throw one", "BURROW": "Burrow", "CALC": "Calc", + "CANCEL": "Cancel", "CANTRIP": "Cantrip", "CANTRIPS": "Cantrips", "CANTRIPS_KNOWN": "Cantrips known", @@ -115,12 +313,13 @@ "CHECK_BONUS": "Check bonus", "CLASS": "Class", "CLASS_AND_LEVEL": "Class & Level", + "CLASS_FEATURES_TITLE": "Class features", "CLASS_LEVELS": "Class levels", "CLIMB": "Climb", - "COIN_CONVERSION_GP_PER_CP": "Copper per Gold (default 100)", - "COIN_CONVERSION_GP_PER_SP": "Silver per Gold (default 10)", - "COIN_CONVERSION_GP_PER_EP": "Electrum per Gold (default 2)", - "COIN_CONVERSION_GP_PER_PP": "Gold per Platinum (default 10)", + "COIN_CONVERSION_GP_PER_CP": "Copper per Gold (100)", + "COIN_CONVERSION_GP_PER_SP": "Silver per Gold (10)", + "COIN_CONVERSION_GP_PER_EP": "Electrum per Gold (2)", + "COIN_CONVERSION_GP_PER_PP": "Gold per Platinum (10)", "COINAGE": "Coinage", "COINS_CP": "CP", "COINS_SP": "SP", @@ -150,7 +349,7 @@ "DEFAULT_ABILITY_TOOLTIP": "This will set the ability for saving throw DCs when importing a Spell or Attack. If \"Add Casting Modifier\" is also set on the importing item it will apply to the damage ability or heal ability as well.", "DICE": "Dice", "DIE": "Die", - "DIVINE_SMITE": "Divine Smite", + "DISPLAY_TEXT": "Display text", "DMG": "DMG", "DURATION": "Duration", "EFFECT": "Effect", @@ -185,6 +384,8 @@ "HEIGHT": "Height", "HIDE_NPC_INFO": "Hide NPC info", "HIDE_NPC_INFO_ACTION_FREETEXT": "Hide Action freetext", + "HIDE_NPC_INFO_ATTACK": "Hide Attack", + "HIDE_NPC_INFO_DAMAGE": "Hide Damage", "HIDE_NPC_INFO_EFFECT": "Hide Effect", "HIDE_NPC_INFO_NOTE": "Please see the wiki. You'll need to use a browser extension to change the css to show certain parts", "HIDE_NPC_INFO_RECHARGE": "Hide Recharge", @@ -198,6 +399,7 @@ "HIT_POINTS_TEMP": "Temp HP", "HOVER": "Hover", "IDEALS": "Ideals", + "IMPORT": "Import", "INITIATIVE": "Initiative", "INITIATIVE_BONUS": "Initiative bonus", "INITIATIVE_BREAK_TIES": "Break Initiative Ties", @@ -206,6 +408,7 @@ "JACK_OF_ALL_TRADES": "Jack of all trades", "LAIR_ACTIONS": "Lair Actions", "LANGUAGES": "Languages", + "LBS": "lbs", "LEGENDARY_ACTIONS": "Legendary actions", "LEGENDARY_ACTIONS_TEXT_1": "The", "LEGENDARY_ACTIONS_TEXT_2": "can take", @@ -218,6 +421,7 @@ "MEDIUM_ARMOR_MAX_DEX": "Medium armor max dex", "MELEE": "Melee", "MISC": "Misc", + "MISCELLANEOUS": "Miscellaneous", "MISCELLANEOUS_NOTES": "Miscellaneous notes", "MOVEMENT": "Movement", "NAME": "Name", @@ -249,10 +453,10 @@ "ROLL_OPTIONS": "Roll options", "SAVING_DC": "Saving DC", "SAVING_THROW": "Saving throw", - "SAVING_THROW_BONUS": "Saving throw bonus", "SAVING_THROW_DC": "Saving throw DC", - "SAVING_THROWS": "Saving Throws", + "SAVING_THROWS": "Saving throws", "SAVING_THROWS_QUERY": "Saving Throws Query", + "SECOND_WIND": "Second Wind", "SENSES": "Senses", "SHOW_ALL": "Show all", "SHOW_TARGET_AC_ON_ATTACKS": "Show Target's AC on Attacks", @@ -261,7 +465,6 @@ "SKILL": "Skill", "SKILLS_TITLE": "Skills", "SKIN": "Skin", - "SNEAK_ATTACK": "Sneak Attack", "SORCERY_POINTS": "Sorcery Points", "SORCERY_POINTS_RECHARGE_TOOLTIP": "Recharges on a long rest (4 recharge on a short rest if lvl 20)", "SPEED": "Speed", @@ -282,6 +485,7 @@ "TREMORSENSE": "Tremorsense", "TRUESIGHT": "Truesight", "TYPE": "Type", + "USES": "Uses", "VISION": "Vision", "WARLOCK_SLOTS_RECHARGE_TOOLTIP": "Recharges on a long or short rest and are all of the same level", "WARLOCK_SPELL_SLOTS": "Warlock spell slots", diff --git a/D&D_5e_Reshaped/precompiled/translations/fr.json b/D&D_5e_Reshaped/precompiled/translations/fr.json index 30cfa516ad..49264a4c76 100644 --- a/D&D_5e_Reshaped/precompiled/translations/fr.json +++ b/D&D_5e_Reshaped/precompiled/translations/fr.json @@ -116,10 +116,10 @@ "CLASS_AND_LEVEL": "Classes & Niveaux", "CLASS_LEVELS": "Niveaux de classe", "CLIMB": "Escalade", - "COIN_CONVERSION_GP_PER_CP": "Cuivre par Or (100 par défaut)", - "COIN_CONVERSION_GP_PER_SP": "Argent par Or (10 par défaut)", - "COIN_CONVERSION_GP_PER_EP": "Electrum par Or (2 par défaut)", - "COIN_CONVERSION_GP_PER_PP": "Or par Platine (10 par défaut)", + "COIN_CONVERSION_GP_PER_CP": "Cuivre par Or (100)", + "COIN_CONVERSION_GP_PER_SP": "Argent par Or (10)", + "COIN_CONVERSION_GP_PER_EP": "Electrum par Or (2)", + "COIN_CONVERSION_GP_PER_PP": "Or par Platine (10)", "COINAGE": "Monnaie", "COINS_CP": "PC", "COINS_SP": "PA", diff --git a/D&D_5e_Reshaped/precompiled/translations/ru.json b/D&D_5e_Reshaped/precompiled/translations/ru.json index 90dc1f120b..c287871080 100644 --- a/D&D_5e_Reshaped/precompiled/translations/ru.json +++ b/D&D_5e_Reshaped/precompiled/translations/ru.json @@ -63,7 +63,7 @@ "CARRYING_PUSH_DRAG_LIFT": "Можно поднять\\перенести", "CHARACTER_NAME": "Имя Персонажа", "CLASS_TITLE": "Класс", - "CLASS_FEATURES": "Способности Класса", + "CLASS_FEATURES_TITLE": "Способности Класса", "CLASSES_TITLE": "Классы", "COINAGE": "чеканка монет", "COINS_CP": "ММ", diff --git a/D&D_5e_Reshaped/sheet.json b/D&D_5e_Reshaped/sheet.json index 8356255a32..8e95c1a575 100644 --- a/D&D_5e_Reshaped/sheet.json +++ b/D&D_5e_Reshaped/sheet.json @@ -5,6 +5,6 @@ "roll20userid": "277007", "preview": "D&D5e.jpg", "compendium": "dnd5e", - "patreon": "https://www.patreon.com/mlenser", - "instructions": "This sheet is designed for use with D&D 5th edition. It has been designed to match the layout of the D&D 5e Character Sheet. Sheet help is available on the wiki - https://wiki.roll20.net/DnD5e_Shaped_Character_Sheet" + "instructions": , + "patreon": "https://www.patreon.com/mlenser" }