commit e3a8878bfb903ef11984eda5be5fa222d3520cf8 Author: Tim Evans (slaguru666) Date: Tue Mar 31 16:59:07 2026 +0100 chore: initial deploy — SLA Industries Foundry VTT Co-authored-by: slaguru666 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..12eee01 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +node_modules/ +npm-debug.log* +.npm/ +dist/ +*.min.css +.DS_Store +.DS_Store? +._* +Thumbs.db +.vscode/ +.idea/ +*.swp +worlds/ +*.tar.gz +*.tgz +*.zip diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..8acb5aa --- /dev/null +++ b/.npmignore @@ -0,0 +1,7 @@ +# IDE +.idea/ +.vs/ + +# Node Modules +node_modules/ +npm-debug.log \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..6b31477 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,6 @@ +SLA Mothership is a draft derivative of the unofficial Foundry Mothership system. + +Upstream project: +https://github.com/Futil/foundry-mothership + +SLA-specific draft additions in this package are part of the sla_industries_brp repository. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9138271 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +## MoSh | Unofficial Mothership RPG + +An unofficial implementation of Tuesday Knight's Mothership role playing system. Mothership is the property of Tuesday Knight Games, and can be purchased at https://mothershiprpg.com/ + +#### Features +- Full 1e AND 0e system support with conditions, rolltables, and macros for each +- Character sheets styled to resemble the official printout sheets +- Comprehensive automation for all checks, saves, attacks, wounds, and conditions +- Intuitive hotbar macros for key tasks that guide you through step-by-step +- Customizable ship and creature sheets with selectable stats +- Macro support for weapons, items, stats, and skills +- Includes optional house rules, like Calm and Android panic tables +- Custom Dice So Nice! themes for regular rolls, damage, and panic checks +- SLA Industries conversion layer with Flux, Ebb abilities, SLA tabs, and seeded gear +- SLA-aware operative generator and GM world tools for rapid setup +- Tier-aware Ebb casting with Flux state bands and panic escalation support +- Species/package presentation cards for faster SLA character review + +#### Screenshots +![Alt text](https://github.com/Futil/foundry-mothership/assets/982251/9d929554-8fcf-4fa1-b198-44c99b60434c "Screenshot") + diff --git a/css/mosh-original.css b/css/mosh-original.css new file mode 100644 index 0000000..55477cd --- /dev/null +++ b/css/mosh-original.css @@ -0,0 +1,2788 @@ +@import url("https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@400;500;600;700&family=Roboto+Mono:wght@400;500;700&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Martel:wght@400;800&family=Roboto:wght@300;400;500&display=swap"); +@import url('https://fonts.googleapis.com/css2?family=Hind:wght@300;400;500;600;700&display=swap'); + +@include-when-export url(https://fonts.loli.net/css?family=PT+Serif:400,400italic,700,700italic&subset=latin,cyrillic-ext,cyrillic,latin-ext); + +/* =========== */ + +/* pt-serif-regular - latin */ +@font-face { + font-family: 'Futura PT Book'; + font-style: normal; + font-weight: normal; + src: local('Futura PT Book'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* pt-serif-700 - latin */ +@font-face { + font-family: 'Futura PT Bold'; + font-style: normal; + font-weight: bold; + src: local('Futura PT Bold'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* pt-serif-700 - latin */ +@font-face { + font-family: 'Futura PT Cond Medium'; + font-style: normal; + font-weight: normal; + src: local('Futura PT Cond Medium'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* pt-serif-700 - latin */ +@font-face { + font-family: 'Futura PT Cond Bold'; + font-style: normal; + font-weight: bold; + src: local('Futura PT Cond Bold'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* Branding */ +#logo { + content: url("/systems/sla-mothership/images/icons/ui/system/logo.webp"); + width: 100px; + height: 50px; +} + +#pause>img { + background: none; + content: url("/systems/sla-mothership/images/icons/ui/system/pause.webp"); + width: 200px; + height: 200px; + top: -95px; + left: calc(50% - 100px); + opacity: .3; +} + +#pause { + background: none; +} + +#pause figcaption { + font-family: "Roboto", sans-serif; + color: #ffffff; + opacity: .3; + padding-left: 6px; +} + +/* Paragraph */ +p { + margin: 0em 0; +} + +/* Global styles */ +.window-app { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; +} + +.window-app .window-content { + background: #fff; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ +} + +.mosh ::-webkit-scrollbar-thumb { + outline: none; + border-radius: 3px; + background: black; + border: 1px solid white; +} + +.mosh .window-content{ + scrollbar-width: thin; + scrollbar-color: black #fff; +} + +.mosh .white{ + color:white; +} + +.mosh .darkgrey{ + color:rgb(92, 92, 92); +} +/* .chat-message, #chat-form, .textarea{ + background: white; +} */ + +.dice-tooltip .dice-rolls .roll.max { + color: #18520b; + filter: sepia(0.5) hue-rotate(60deg); +} +.dice-tooltip .dice-rolls .roll.min { + color: #aa0200; + filter: sepia(0.5) hue-rotate(340deg); +} + +.list-roll:hover, +.list-roll:focus, +.rollable:hover, .rollable:focus { + color: #000; + text-shadow: 0 0 10px rgb(112, 112, 112); + cursor: pointer; +} + +.grid, +.grid-2col { + display: grid; + grid-column: span 2 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 2px; + /* margin: 10px 0; */ + padding: 0; +} +.grid-1col { + grid-column: span 1 / span 1; + grid-template-columns: repeat(1, minmax(0, 1fr)); +} + +.widegap { + gap: 16px; +} + +.grid-3col { + grid-column: span 3 / span 3; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.grid-4col { + grid-column: span 4 / span 4; + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +.grid-5col { + grid-column: span 5 / span 5; + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.grid-6col { + grid-column: span 5 / span 5; + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.grid-7col { + grid-column: span 7 / span 7; + grid-template-columns: repeat(7, minmax(0, 1fr)); +} + +.grid-8col { + grid-column: span 8 / span 8; + grid-template-columns: repeat(8, minmax(0, 1fr)); +} + +.grid-9col { + grid-column: span 9 / span 9; + grid-template-columns: repeat(9, minmax(0, 1fr)); +} + +.grid-10col { + grid-column: span 10 / span 10; + grid-template-columns: repeat(10, minmax(0, 1fr)); +} + +.grid-11col { + grid-column: span 11 / span 11; + grid-template-columns: repeat(11, minmax(0, 1fr)); +} + +.grid-12col { + grid-column: span 12 / span 12; + grid-template-columns: repeat(12, minmax(0, 1fr)); +} + +.flex-group-center, +.flex-group-left, +.flex-group-right { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: center; + padding: 3px; + /* border: 1px solid #999; */ +} + +.flex-group-left { + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + text-align: left; +} + +.flex-group-right { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + text-align: right; +} + +.flex-center { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + text-align: center; +} + +.flex-between { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.flex { + display: flex; + justify-content:space-evenly; + align-items: center; + flex: auto; +} + + +/* Styles limited to mosh sheets */ +.mosh .item-form { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh input { + font-weight: inherit; + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh input, +.mosh textarea, +.mosh select { + color: #111317; +} + +.mosh input::placeholder, +.mosh textarea::placeholder { + color: #666b72; +} + +.mosh, +.mosh textarea, +.mosh select, +.mosh button, +.window-app .window-title { + font-family: "Josefin Sans", "Roboto", sans-serif; +} + +.mosh .center-icon{ + font-size: 42px; + align-items: center; + justify-content: center; + display: flex; +} + +.mosh .transponder input[type="checkbox"] { + /* display: none; */ + appearance: inherit; + border: 2px white; + border-style: double; + border-radius: 100px; +} + + +.mosh .transponder input[type="checkbox"]:checked, .mosh input[type="radio"]:checked { + background: white; + border-radius: 100px; + appearance: inherit; + animation: transponderblink 0.5s alternate infinite; + box-shadow: 0 0 15px white; +} + +.mosh .transponder input[type="checkbox"] span { + color: grey; + position: relative; + /* margin-left: -1rem; */ + display: inline-block; + right: -25px; + font-size: 17px; + font-weight: bold; + font-family: 'Roboto'; + bottom: 2px; +} + +.mosh .transponder input[type="checkbox"]:checked span { + color: grey; + position: relative; + /* margin-left: -1rem; */ + display: inline-block; + right: -25px; + font-size: 17px; + font-weight: bold; + font-family: 'Roboto'; + bottom: 2px; + /* text-shadow: 0 0 11px grey; */ +} + +@keyframes transponderblink { + from {background-color: black;} + to { + background-color: white; + } +} + +@keyframes transpondertextblink { + from {color: grey;} + to { + color: white; + } +} + +.mosh .char-header { + -webkit-box-flex: 0; + /* -ms-flex: 0 0 610px; + flex: 0 0 610px; */ + /* overflow: hidden; */ + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-bottom: 14px; +} + + + +.mosh .char-header .profile-img { + -webkit-box-flex: 0; + width: 100px; + height: 100px; + margin-right: 10px; + margin-top: 10px; +} + +.mosh .char-header .header-fields { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.mosh .char-header .header-grid { + display: grid; + grid-template-areas: + 'header header header' + 'abilities centercol saves ' + 'mobilehealth mobilehealth mobilehealth'; + grid-gap: 10px; + /* background-color: rgb(226, 226, 226); */ + padding: 2px; + grid-template-columns: 238px auto 100px; + container-type: inline-size; +} + +.mosh .abilities {grid-area: abilities;} +.mosh .saves {grid-area: saves;} + +.mosh .stress {grid-area: stress;} +.mosh .health {grid-area: centercol;} +@container (max-width: 610px) { + .mosh .health {grid-area: mobilehealth;} +} +.mosh .healthspread {width:96%;} + +.mosh .char-header h1.charname { + height: auto; + padding: 0px; + margin: 0px 0; + border-bottom: 0; +} + +.mosh .char-header h1.charname input { + width: 100%; + height: auto; + + background: #fff; + + padding-left: 1em; + border: 4px solid #111; + border-radius: 3em; + font-size: 0.9rem; + font-weight: bold; + text-align: left; +} + +.mosh .sheet-tabs { + -webkit-box-flex: 0; + -ms-flex: 0; + flex: 0; +} + +.mosh .sheet-body, +.mosh .sheet-body .tab, +.mosh .sheet-body .tab .editor { + height: 100%; +} + +.sheet nav.sheet-tabs { + background: + linear-gradient(90deg, rgba(16, 16, 16, 0.98), rgba(33, 20, 15, 0.98) 55%, rgba(16, 16, 16, 0.98)), + #111; + color: white; + padding: 8px 10px; + border-radius: 14px; + margin-top: 10px; + position: relative; + z-index: 2; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 10px 24px rgba(0, 0, 0, 0.14); +} + +.mosh .tox .tox-editor-container { + background: #fff; +} + +.mosh .tox .tox-edit-area { + padding: 0 8px; +} + +.mosh .origin { + width: 0; + height: 0; +} + +.mosh .seperatorLine{ + border-bottom: 2px solid #111; + height: 0; + width: 100%; +} + +.mosh .skill_training_frame{ + height: 47px; + background: rgb(230,230,230); + border-radius: 9px; + font-family: "Roboto", sans-serif; + font-size: 11pt; + font-weight: 400; + padding: 8px; +} +.mosh .skill_training_text{ + font-family: "Roboto", sans-serif; + font-size: 11pt; + font-weight: 500; + color: grey; +} + +.mosh .resource-label { + font-weight: bold; + text-transform: uppercase; + margin-bottom: 3px; + text-align: center; +} + +.mosh .faded-label { + text-transform: uppercase; + margin-bottom: 3px; + color:rgb(129, 129, 129); + font-weight:normal; + + text-align: left; + grid-column: 1/-1; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ + font-size: 1.1rem; + line-height: 1; + text-align: center; +} + +.mosh .tabs { + height: 40px; + border-top: 2px solid rgb(56, 56, 56); + border-bottom: 2px solid rgb(56, 56, 56); +} + +.mosh .tabs .item { + /* line-height: 40px; */ + font-weight: bold; +} + +.mosh .tabs .item.active { + text-decoration: underline; + text-shadow: none; +} + +.mosh .tabs .item.active::before { + font-family: "Font Awesome 6 Pro"; + content: "\f0da"; + color:white; + position: relative; + right: 6px; + margin-left: -1rem; + display: inline-block; +} + +.mosh .items-list { + list-style: none; + margin: 7px 0; + padding: 0; + /* overflow-y: auto; */ +} + +.mosh .items-list .item-header { + font-weight: bold; +} + +.mosh .items-list .item { + height: 35px; + line-height: 24px; + padding: 3px 0; + border-bottom: 1px solid #BBB; +} + +.mosh .skills-list .item { + height: 36px; + line-height: 21px; + padding: 3px 0; + border-bottom: 1px solid #BBB; +} + +.mosh .items-list .item .item-image { + -webkit-box-flex: 0; + -ms-flex: 0 0 24px; + flex: 0 0 24px; + margin-right: 5px; +} + +.mosh .roll-image { + -webkit-box-flex: 0; + flex: 0 24px; + margin-top: -3px; + margin-left: 11px; + margin-right: 0px; + width: 50px; + border-radius: 0 0 0 16px; + border: 1px solid #000; +} + +.mosh .items-list .item img { + display: block; +} + +.mosh .items-list .item-name { + margin: 0; +} + +.mosh .items-list .skill-name { + font-weight: bold; + font-size: 14px; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + color: white; + /* text-transform: uppercase; */ + margin-left: 0px; + background: #111; + padding: 2px; + /* padding-left: 8px; */ + border-radius: 21px; + text-align: center; + height: 27px; + overflow: hidden; +} + +.mosh .items-list .skill-stat { + font-size: medium; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + color: #111; + margin-left: 0px; + /* background: black; */ + padding: 2px; + padding-left: 8px; + border-radius: 21px; + text-align: center; + white-space: nowrap; +} + +.mosh .items-list .item-controls { + -webkit-box-flex: 0; + -ms-flex: 0 0 86px; + flex: 0 0 86px; + text-align: right; +} + +.mosh .button-black { + font-weight: bold; + font-size: 16px; + color: white; + margin-left: 0px; + background: #111; + border-radius: 21px; + text-align: center; + overflow: hidden; + padding: 10px; +} + +.button-black:hover, +.button-black:focus{ + /* color: #ffffff; */ + text-shadow: 0 0 10px rgb(112, 112, 112); + box-shadow: 0 0 10px 0px #9e9e9e; + background: #202020; + cursor: pointer; +} + +.mosh .button-grey { + font-weight: bold; + font-size: 16px; + color: white; + margin-left: 0px; + background: grey; + border-radius: 21px; + text-align: center; + overflow: hidden; + padding: 10px; +} + +.button-grey:hover, +.button-grey:focus{ + /* color: #494949; */ + text-shadow: 0 0 10px rgb(112, 112, 112); + box-shadow: 0 0 5px 0px #b9b9b9; + background: rgb(100, 100, 100); + cursor: pointer; + /* border: 1px solid #ffffff; */ +} + +.mosh .button-white { + font-weight: bold; + font-size: 16px; + color: #111; + margin-left: 0px; + background: white; + border-radius: 21px; + text-align: center; + overflow: hidden; + padding: 10px; + border: 3px solid #111; +} + +/* Dropdown Button */ +.mosh .dropbtn { + background-color: #111; + color: white; + padding: 16px; + font-size: 16px; + border: none; +} + +/* The container
- needed to position the dropdown content */ +.mosh.dropdown { + position: relative; + display: inline-block; +} + +/* Dropdown Content (Hidden by Default) */ +.mosh .dropdown-content { + display: none; + position: absolute; + background-color: #f1f1f1; + min-width: 160px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; +} + +/* Links inside the dropdown */ +.mosh .dropdown-content a { + color: black; + padding: 12px 16px; + text-decoration: none; + display: block; +} + +/* Change color of dropdown links on hover */ +.mosh .dropdown-content a:hover {background-color: #ddd;} + +/* Show the dropdown menu on hover */ +.mosh .dropdown:hover .dropdown-content {display: block;} + +/* Change the background color of the dropdown button when the dropdown content is shown */ +.mosh .dropdown:hover .dropbtn {background-color: #3d3d3d;} + + +.mosh .sbt-profile { + width: 100px; + height: auto; + border: 0; + padding: 10px; +} + +.mosh .sbt-crew-name .hidden-item-controls { + -webkit-box-flex: 0; + -ms-flex: 0 0 86px; + flex: 0 0 86px; + text-align: right; + display: none; +} + +.mosh .sbt-crew-name:hover .hidden-item-controls { + -webkit-box-flex: 0; + -ms-flex: 0 0 86px; + flex: 0 0 86px; + text-align: right; + display: inline; +} + +.mosh .sbt-deckplan{ + width: 100%; + height: auto; + border: 0; + + transition: 2s; +} + +.mosh .sbt-deckplan-parent{ + height: 185px; + overflow: auto; + transition: 2s; + border-radius: 10px; +} + +.mosh .sbt-deckplan-parent:hover { + z-index: 10000; + /* height: auto; */ +} + +.mosh .sbt-megadamage-menu { + padding: 15px; + /* font-size: 15px; */ +} + +.mosh .invert-title{ + mix-blend-mode: difference; +} + +.mosh .tab-select { + font-size: medium; + font-weight: bold; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + color: white; + text-align: center; +} + +.mosh .tab-select.active { + text-decoration: underline; + text-shadow: 0 0 10px white; +} + +/* .mosh .tab-select.active::before { + font-family: "Font Awesome 6 Pro"; + content: "\f0da"; + color:rgb(255, 113, 113); + position: relative; + right: 6px; + margin-left: -1rem; + display: inline-block; +} */ + +.mosh .stresstext { + width: 100%; + padding: 0.1rem; + color: white; + font-family: "Montserrat", "Arial Black", sans-serif; + font-size: 0.75rem; + font-weight: bold; + text-align: left; + text-transform: uppercase; +} + +.mosh .smallcircle-input { + margin: -0.15em; + height: 40px; + width: 40px; + padding: 0; + border: 4px solid #111; + border-radius: 3em; + font-size: 1rem; + font-weight: bold; + text-align: center; +} + +.mosh .mainstatmod-input { + height: 26px; + width: 28px; + /* padding: 0; */ + border: 0; + border-radius: 7.7em; + color: rgb(151, 100, 100); + font-size: 0.85rem; + font-weight: bold; + text-align: center; + margin-left: -22px; + z-index: 5; + background: white; + top: 8px; + left: 13px; + position: relative; + background: lightgrey; +} + +.mosh .mainsavemod-input { + height: 26px; + width: 28px; + /* padding: 0; */ + border: 0; + border-radius: 0.5em; + color: rgb(151, 100, 100); + font-size: 0.85rem; + font-weight: bold; + text-align: center; + margin-left: -22px; + z-index: 5; + background: white; + top: 7px; + left: 13px; + position: relative; + background: lightgrey; +} + +.mosh .mainstatmod-title { + position: relative; + color: lightgrey; + font-size: 1rem; + line-height: 1; + text-transform: uppercase; + margin-left: -38px; + pointer-events: none; + top: 13px; + left: 12px; +} + +.mosh .maxhealth-input { + margin: auto; + border: 0px solid #111; + font-size: 1.5rem; + font-weight: bold; + text-align: center; + background: transparent; +} + +.mosh .greyText{ + color: grey; +} + +.mosh .darkGreyText{ + color: rgb(56, 56, 56); +} + +.mosh .whiteText{ + color: white; +} + +.mosh .highlightText{ + color: orangered; +} + +.mosh .sizelarge{ + font-size: 1.1rem; +} + +.mosh .valuewrapper{ + grid-column: 1/-1; + display: grid; + align-items: start; + height: 40px; + padding: 0; + border: 3px solid #111; + border-radius: 1.5em; + background: 0; +} + +.mosh .textvaluewrapper{ + grid-column: 1/-1; + display: grid; + align-items: start; + height: 40px; + padding: 0; + border: 3px solid #111; + border-radius: 0.5em; + background: 0; +} + +.mosh .textvaluewrapper-input{ + margin: auto; + border: 0px solid #111; + font-size: 1rem; + font-weight: bold; + text-align: center; + background: transparent; +} + +.mosh .armorWrapper{ + grid-column: 1/-1; + display: grid; + align-items: start; + height: 40px; + padding: 0; + border: 2px solid #111; + border-radius: 0.3em; + background: black; + width: 100%; +} + +.mosh .blankstat{ + grid-template-rows: 0.3fr 1.1fr 0.4fr; + justify-self: center; + display: grid; + justify-items: center; +} + +.mosh .minmaxtopstat{ + grid-template-columns: 1fr 1fr; + grid-template-rows: 0.3fr 1.1fr 0.4fr; + justify-self: center; + display: grid; + justify-items: center; +} + +.mosh .minmaxwrapper{ + grid-column: 1/-1; + display: grid; + grid-template-columns: 1fr 1px 1fr; + align-items: start; + height: 40px; + padding: 0; + border: 3px solid #111; + border-radius: 1.5em; + background: white; +} + +.mosh .minmaxwrapper-black{ + grid-column: 1/-1; + display: grid; + grid-template-columns: 1fr 1px 1fr; + align-items: start; + height: 40px; + padding: 0; + border: 3px solid #111; + border-radius: 1.5em; + background: 0; + color: white; +} + +.mosh .minmaxtext{ + text-align: left; + grid-column: 1/-1; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ + font-size: 1rem; + font-weight: bold; + line-height: 1; + text-align: center; + text-transform: uppercase; +} + +.mosh .slant{ + border-right: 2px solid #111; + height: 100%; + transform: skewX(-15deg); +} + +.mosh .healthmaxtext{ + grid-column: span 1; + font-size: 0.7rem; + font-weight: bold; + line-height: 1; + text-align: center; + margin-top: 3px; +} + +.mosh .stresslabel { + border-top-left-radius: 2em; + border-bottom-left-radius: 2em; + background: #111; + padding: 0 0.5rem; +} + +.mosh .mainstatwrapper { + display: flex; + width: 95%; +} + +.mosh .mainstat { + position: relative; + display: grid; + grid-template-columns: 1fr 5em; + align-items: center; + gap: 0; + width: 98%; +} + +.mosh .circle-statwrapper { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + background: #e3e3e3; + border-radius: 15px; + padding: 9px 0px; + flex-direction: column; +} + +.mosh .circle-statwrapper-horizontal { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + background: #e3e3e3; + border-radius: 15px; + padding: 9px 0px; + flex-direction:row; +} + +.mosh .circle-statwrapper-vertical { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + background: #e3e3e3; + border-radius: 15px; + padding: 9px 0px; + flex-direction: column; +} + +.mosh .transparentBackground { + background: transparent; +} + +.mosh .section-vertical-flex { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + + +.mosh .circle-stat { + margin-top: 10px; + /* width: 98%; */ +} + +.mosh .creature-mainstat { + position: relative; + display: grid; + grid-template-columns: 1fr 3em; + align-items: center; + gap: 0; + width: 100%; +} +.mosh .mainstatlabel { + border-top-left-radius: 2em; + border-bottom-left-radius: 2em; + background: #111; + padding: 5px 0.5rem; + left: 5px; + position: relative; + height: 35px; +} + +.mosh .mainstattext { + width: 100%; + padding: 0.5rem; + color: white; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ + font-size: 1.3rem; + font-weight: bold; + text-align: left; + text-transform: uppercase; +} + + +.mosh .area-title { + width: 100%; + font-size: 1.0rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; + /* margin-bottom: 7px; */ + color: #363636; + font-family: 'Roboto'; +} + +.mosh .circlestatlabel { + padding: 6px; + text-align: center; +} + +.mosh .circlestattitle { + width: 100%; + font-size: 1.0rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; + /* margin-bottom: 7px; */ + color: grey; +} + +.mosh .black { + color: black; +} + +.mosh .grey { + color: grey; +} + +.mosh .circlestattext { + width: 100%; + font-size: 0.9rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; +} + +.mosh .circle-input { + margin: -0.15em; + height: 50px; + width: 50px; + padding: 0; + border: 3px solid #111; + border-radius: 3em; + font-size: 1.5rem; + font-weight: bold; + text-align: center; + background: white; + z-index: 5; +} + +.mosh .box1 { + display: none; +} + +.mosh .box2 { + color: green; + display: block; + display: flex; + align-items: center; + justify-content: center; +} + +.mosh .circle-input-swapper { + width: auto; + display: inline-block; +} + +.mosh .circle-input-swapper:enabled .box1 { + display: block; +} + +.mosh .circle-input-swapper:enabled .box2 { + display: none; +} + +.mosh .textarea-input { + font-family: "Roboto", sans-serif; + margin: -0.15em; + /* padding: 9px; */ + border: 2px solid #111; + border-radius: 15px; + font-size: 11pt; + color: white; + font-weight: 500; + background: #111; + resize: none; + min-height: 0; + overflow: hidden; +} + +.mosh .textarea-input-grey { + font-family: "Roboto", sans-serif; + border: 0; + border-radius: 0.8em; + font-size: 11pt; + font-weight: 500; + resize: none; + min-height: 0; + overflow: hidden; + text-align: center; +} + + +.mosh .square-input { + margin: -0.15em; + height: 42px; + width: 45px; + padding: 0; + border: 4px solid #111; + background-color: #fff; + border-radius: 0.5em; + font-size: 1.1rem; + font-weight: bold; + text-align: center; +} + +.mosh .armor-mod { + margin: 3px; + height: 24px; + width: 28px; + /* padding: 0; */ + border: 3px solid #111; + background-color: #111; + border-radius: 0.6em; + font-size: 0.9rem; + font-weight: bold; + text-align: center; + position: relative; + color: white; + top: -2px; + right: -19px; +} + +.mosh .savetext { + display: block; + margin-bottom: .2em; + width: 100%; + color: white; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + font-size: 0.8rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; +} + +.mosh .savebackground { + border-radius: 10px; + background: #111; + padding-bottom: 0.3rem; + padding-top: 0.4rem; + height: 225px; +} + +.mosh .header { + grid-area: header; + background-color: #000; + display: grid; + grid-template-columns: 0.25fr 1fr; + /* gap: 1.25rem; */ + align-items: center; + grid-column: 1/-1; + background: #111; + color: white; + font-family: "Montserrat", "Arial Black", sans-serif; + font-weight: bold; + text-transform: uppercase; + border-radius: 15px; +} + +.mosh .padding{ + padding: 5px; +} + +.mosh .actor-sidebar-tab{ + border-radius: 0 10px 10px 0; + /* z-index: -1; */ + box-shadow: 0 0 22px -6px; + border: 2px solid; + writing-mode: vertical-rl; + rotate: 180deg; + opacity: 0.5; +} + +.mosh .actor-sidebar-tab:hover{ + opacity: 1; +} + +.mosh .actor-sidebar-row{ + position: absolute; + display: flex; + flex-direction: column; + left: -20px; + top: 30px; + z-index: -1; + /* transition: 0.3s; */ + padding-left: 10px; +} + +.mosh .actor-sidebar-row:hover{ + left: -48px; +} + +.mosh .creature-header-grid { + display: grid; + grid-template-areas: + 'name header header' + 'line line line'; + background: #111; + +} + + +.mosh .creature-header { + display: flex ; + flex-direction: row-reverse; + align-items: center; + color: white; + font-family: "Montserrat", "Arial Black", sans-serif; + font-weight: bold; + text-transform: uppercase; + grid-area: header; + padding: 8px; +} + +.mosh .creature-description-grid{ + display: grid; + grid-template-columns: 1fr 15em; +} + +.mosh .creature-abilities{ + background: rgb(22, 22, 22); + margin: 12px; + border: 2px solid white; + outline: 5px solid rgb(22, 22, 22); + overflow: auto; + height: 375px; + border-radius: 10px; +} + +.mosh .ship-stats-grid{ + display: grid; + grid-template-columns: 17em 1fr 18em; +} + +.mosh .ship-sbt-stats-grid{ + display: grid; + grid-template-columns: 10em 1fr 16em; + gap: 10px; +} + +.mosh .sbt-crew-section{ + margin: 0px; + border: 2px solid white; + outline: 3px solid rgb(22, 22, 22); + overflow: auto; + height: 400px; + border-radius: 10px; + padding: 4px 6px; +} + +.mosh .sbt-text-area{ + font-family: "Roboto", sans-serif; + margin: -0.15em; + border: 2px solid #c5c5c5; + border-radius: 15px; + font-size: 11pt; + font-weight: bold; + background: #fff; + resize: none; + min-height: 0; + overflow: hidden; +} + +.mosh .sbt-megadamage{ + /* position: absolute; */ + /* left: 0; */ + /* background: white; + left: -300px; + width: 300px; + padding: 20px; + border-radius: 10px 0 0 10px; + height: 600px; + overflow-y: auto; + z-index: -1; */ + + position: absolute; + background: white; + left: -310px; + width: 300px; + padding: 20px; + border-radius: 10px; + z-index: -2; + transition: 1s; + height: auto; + overflow: hidden; +} + +.mosh .sbt-megadamage-open{ + left: -310px; + height: auto; +} + +.mosh .sbt-megadamage-closed{ + left: 0; + height: 0%; +} + +.mosh .sbt-crew-name { + text-align: center; + font-size: 1rem; + /* text-transform: uppercase; */ + color:black; + font-weight: bold; +} + +.mosh .sbt-crew-job { + height: auto; + font-size: 0.9rem; + color:rgb(129, 129, 129); + font-weight: bold; + font-style: italic; + text-align: center; +} + +.mosh .item-armor-grid { + display: grid; + grid-template-columns: 1fr 12em; + gap: 10px; +} + +.mosh .whiteline { + border-top: 3px solid white; + grid-area: line; + margin-top: 5px; + margin-bottom: 10px; + margin-left: 15px; + margin-right: 15px; +} + +.mosh .blackline { + border-top: 3px solid black; + grid-area: line; + margin-bottom: 5px; + margin-left: 15px; + margin-right: 15px; + margin-top: 5px; +} + +.mosh .greyline { + border-top: 3px solid grey; + grid-area: line; + margin-top: 5px; + margin-bottom: 10px; + margin-left: 15px; + margin-right: 15px; +} + +.mosh .headerinputfield { + margin: -0.15em; + height: auto; + width: 100%; + padding-left: 13px; + border: 2px solid #111; + background-color: #fff; + border-radius: 3em; + font-size: 1rem; + margin-right: 1em; +} + +.mosh .creaturename { + height: auto; + width: 100%; + padding-left: 13px; + font-size: 1.3rem; + font-weight: bold; + color:white; + text-transform: uppercase; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; +} + +.mosh .creaturestat { + margin-left: 4px; + height: auto; + font-size: 0.9rem; + text-transform: uppercase; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; + color:white; +} + +.mosh .creaturedescription { + height: 400px; + padding: 10px; + overflow-y: auto; +} +.mosh .creaturedescription .editor-content{ + overflow-y: visible; +} +.mosh .creaturedescription .editor{ + overflow: visible; +} + +.mosh .creature-ability-container { + padding: 4px; + margin-left: 2px; +} + +.mosh .creature-ability-title { + text-align: center; + font-size: 0.9rem; + text-transform: uppercase; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; + color:white; + font-weight: bold; +} + +.mosh .creature-ability-text { + height: auto; + font-size: 0.8rem; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; + color:white; +} + +.mosh .tox.tox-tinymce { + min-height: 100%; +} +.mosh .editor { + height: 100%; +} + +.noborder { + border: 0 !important; + background: 0 !important; +} + +.mosh .headerinputtext { + padding: 0.1rem; + color: white; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.95rem; + font-weight: bold; + text-align: left; + text-transform: uppercase; + margin-right: 10px; + margin-top: 3px; +} + +.mosh .headergrid { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + gap: 0.25rem; + padding: 1.45em 1em 1em; + /* margin-top: -11px; */ +} + +.mosh .sla-sheet-wordmark { + grid-column: 1 / -1; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 1.85rem; + font-weight: 700; + letter-spacing: 0.12em; + line-height: 0.95; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.92); + text-align: center; + margin-bottom: 0.35rem; + text-shadow: 0 0 10px rgba(208, 94, 26, 0.18); +} + +.mosh .headerinputfield input, +.mosh .charname input { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; + letter-spacing: 0.01em; +} + +.mosh .headernamegrid { + grid-column: 1/-2; +} + +.mosh .headerrankgrid { + /* grid-column: span 3; */ + display: inline-flex; +} + +.mosh .circle{ + color: rgb(22, 22, 22); + background: white; + border-radius: 10px; + /* border: 2px solid black; */ + width: 15px; + height: 15px; +} + +.mosh .circle-f{ /*Filled circle*/ + color: rgb(22, 22, 22); + background: rgb(100, 100, 100); + border-radius: 10px; + /* border: 2px solid black; */ + width: 15px; + height: 15px; +} + +.mosh .profile { + width: 140px; + height: auto; + padding: 6px; + border-radius: 10px; + border: 0; +} + +.mosh .rollcontainer { + border-radius: 10em; + background: #fff; + padding: 0 0.5rem; + padding-bottom: 0.1rem; + width: 100%; + border: 2px solid #111; + border-radius: 0em 0em 0em 0em; + font-family: "Josefin Sans", "Roboto", sans-serif; +} + +.mosh .sla-roll-outcome, +.mosh .sla-roll-result .dice-total { + transition: color 120ms ease, border-color 120ms ease, box-shadow 120ms ease; +} + +.mosh .sla-roll-outcome.sla-crit-success, +.mosh .sla-roll-result .dice-total.sla-crit-success { + color: #0f5c2e; + background: rgba(15, 92, 46, 0.08); +} + +.mosh .sla-roll-outcome.sla-crit-failure, +.mosh .sla-roll-result .dice-total.sla-crit-failure { + color: #8d1f18; + background: rgba(141, 31, 24, 0.08); +} + +.mosh .sla-roll-result.sla-crit-success .dice-total { + border-color: #0f5c2e; + box-shadow: 0 0 0 2px rgba(15, 92, 46, 0.18); +} + +.mosh .sla-roll-result.sla-crit-failure .dice-total { + border-color: #8d1f18; + box-shadow: 0 0 0 2px rgba(141, 31, 24, 0.18); +} + +.mosh .rollh1 { + width: 107%; + margin-top: 0; + margin-left: -9px; + font-size: 1.2rem; + font-weight: bold; + text-transform: uppercase; + background: #111; + color: white; + /* border-bottom-right-radius: 0.5em; */ + padding: 5px; +} + +.mosh .rollweaponh1 { + min-height: 32px; + height: auto; + margin-top: -15px; + margin-left: -8px; + margin-right: -11px; + font-size: 1.02rem; + font-weight: bold; + text-transform: uppercase; + background: #111; + /* border-bottom-right-radius: 1.5em; */ + color: white; + padding: 5px; + flex: auto; + width: 70%; + display: flex; + align-items: center; + line-height: 1.05; + white-space: normal; + word-break: break-word; + font-family: "Josefin Sans", "Roboto", sans-serif; + letter-spacing: 0.08em; +} + +.mosh .rollh2 { + font-size: 1.1rem; + font-weight: normal; + text-transform: uppercase; + line-height: 1; + text-align: center; + margin-top: 4px; + padding: 5px; +} + +.mosh .rollmods { + font-size: 0.8rem; + font-weight: normal; + text-transform: uppercase; + /* line-height: 1; */ + text-align: center; + margin-top: -8px; + margin-bottom: 3px; + padding: 5px; + color: grey; +} + +.mosh .rollattribute { + width: 100%; + padding: 0.5rem; + color: black; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + font-size: 0.9rem; + text-align: center; +} + +.mosh .roll-grid { + box-sizing: border-box; + display: grid; + grid-template-columns: repeat(4, 1fr); + align-items: center; + width: 100%; +} + +.mosh .roll-result { + padding: 8px; + border: 2px solid #111; + border-radius: 1em; + font-size: 1.5rem; + font-weight: bold; + text-align: center; + grid-column: 2/span 2; +} + + +.mosh .roll-target { + box-sizing: border-box; + display: grid; + grid-template-columns: 1fr 6rem; + align-items: center; + gap: 2.5rem; + padding: 0.8rem; + font-size: 0.9rem; + background: white; + border-radius: 1.5rem; + color: #111; + + font-family: "Montserrat", "Arial Black", sans-serif; + font-weight: bold; + text-transform: uppercase; + text-align: right; +} + +.mosh .roll-targetbox { + padding: 2px; + border: 2px solid #111; + border-radius: 0.3em; + font-size: 0.9rem; + font-weight: bold; + text-align: center; + margin-right: 0px; +} + +.mosh .roll-damage { + font-size: 0.9rem; + line-height: 1; + text-align: center; + margin-top: 4px; + padding: 5px; + color: rgb(117, 0, 0); + font-weight: normal; + text-transform: uppercase; + font-family: "Montserrat", "Arial Black", sans-serif; +} + +.mosh .roll-damagebox { + padding: 4px; + border: 2px solid rgb(117, 0, 0); + border-radius: 1em; + font-size: 1.2rem; + font-weight: bold; + text-align: center; + grid-column: 2/span 2; + color: rgb(117, 0, 0); + width: 70px; + margin: auto; +} + +.mosh .items-tab-grid{ + grid-template-columns: 50% 50%; +} +.mosh form.actor-generator div.fulllabel { + border-radius: 2em; +} +.mosh form.actor-generator div.ulinputfield { + min-height: 150px; +} +.mosh form.actor-generator .smalltext { + font-size: 0.7rem; +} +.mosh form.actor-generator div#generator-header-grid-1col { + grid-column: span 1/span 1; + grid-template-columns: repeat(1, minmax(0, 1fr)); +} +.mosh form.actor-generator .element-group { + margin-top: 10px; +} +.mosh form.actor-generator .credit-img { + height: 30px; + margin-top: 0%; +} +.mosh form.actor-generator .checkbox-round { + appearance: none; +} +.mosh form.actor-generator .checkbox-round:checked { + background-color: gray; +} +.mosh form.actor-generator .clicable-item { + cursor: pointer; +} +.mosh .characterGeneratorSkillPopup { + margin-bottom: 10px; +} +.mosh .characterGeneratorSkillPopup .skillpopupDescription { + text-align: center; + font-weight: bold; + padding-bottom: 0.2em; +} + +.mosh .characterGeneratorSkillPopup .center { + text-align: center; +} + +/* Dialog V2 - Macro Pop Ups */ + +/* Base dialog styling */ +.application.dialog.macro-popup-dialog { + background: rgb(255,255,255); + font-family: "Roboto", sans-serif; + color: #1A1915; +} + +/* Adjust dialog content gap */ +.macro-popup-dialog .dialog-content.standard-form { + gap: .5rem; +} + +/* Adjust dialog form gap */ +.macro-popup-dialog .dialog-form.standard-form { + gap: .5rem; +} + +/* MPD window header */ +.macro-popup-dialog .window-header { + background: rgb(25,25,25); +} + +/* MPD window content */ +.macro-popup-dialog .window-content { + padding: 10px; +} + +/* MPD macro window */ +.macro-popup-dialog .macro_window { + background: rgb(230,230,230); + border-radius: 9px; +} + +/* MPD macro image */ +.macro-popup-dialog .macro_img { + +} + +/* MPD macro desc */ +.macro-popup-dialog .macro_desc { + font-family: "Roboto", sans-serif; + font-size: 10.5pt; + font-weight: 400; + padding-top: 8px; + padding-left: 0px; + padding-right: 8px; + padding-bottom: 8px; +} + +/* MPD macro desc — title styling */ +.macro-popup-dialog .macro_desc h4 { + font-family: "Roboto", sans-serif; + font-size: 14pt; + font-weight: 400; + color: #1A1915; + border-bottom: 1px solid darkred; + margin-bottom: 8px; +} + +/* MPD macro prompt */ +.macro-popup-dialog .macro_prompt { + +} + +/* MPD grid layouts */ +.macro-popup-dialog .grid-1col { + grid-column: span 1 / span 1; + grid-template-columns: repeat(1, minmax(0, 1fr)); +} + +.macro-popup-dialog .grid-2col { + display: grid; + grid-column: span 2 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 2px; + padding: 0; +} + +.macro-popup-dialog .grid-3col { + grid-column: span 3 / span 3; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +/* update buttons to look more old school */ +.macro-popup-dialog .form-footer button { + background: rgb(230,230,230); + color: #1A1915; + border: 1px solid #222; + border-radius: 4px; + padding: 4px 10px; + font-size: 11pt; + font-weight: 500; + display: flex; + align-items: center; + gap: 6px; +} + +.macro-popup-dialog .form-footer button:hover { + background: #444; + color: #fff; + border-color: #111; +} + +/* Custom radio: kill native + theme accents */ +.macro-popup-dialog input[type="radio"] { + appearance: none; + -webkit-appearance: none; + accent-color: initial; /* ignore theme accent */ + box-sizing: border-box; + width: 16px; + height: 16px; + border: 2px solid #777; /* medium grey ring */ + border-radius: 50%; + background: #fff; /* white center when unchecked */ + display: inline-flex; /* center the pseudo-dot */ + align-items: center; + justify-content: center; + line-height: 0; + margin: 0 8px 0 2px; + vertical-align: middle; + + /* nuke any theme glow/orange */ + box-shadow: none !important; + outline: none; +} + +/* The inner dot (hidden until checked) */ +.macro-popup-dialog input[type="radio"]::before { + content: ""; + width: 8px; + height: 8px; + border-radius: 50%; + background: #111; /* dot color */ + transform: scale(0); + transition: transform 120ms ease-in-out; +} + +/* Checked = show the dot */ +.macro-popup-dialog input[type="radio"]:checked::before { + transform: scale(1); +} + +/* Checked = show the dot */ +.macro-popup-dialog input[type="radio"]:checked::after { + color: none !important; + width: 8px; + height: 8px; + border-radius: 50%; + transform: scale(0); + background: #ffffff; +} + +/* Hover/focus states (accessible, non-orange) */ +.macro-popup-dialog input[type="radio"]:hover { border-color: #5c5c5c; } +.macro-popup-dialog input[type="radio"]:focus-visible { + outline: 2px solid #9a9a9a; + outline-offset: 2px; +} + +/* If your theme highlights the whole row via :has(input:checked), strip it here */ +.macro-popup-dialog label:has(input[type="radio"]:checked) { + background: inherit !important; + box-shadow: none !important; +} + +.mosh .sla-panel { + margin-bottom: 14px; + padding: 12px; + border: 1px solid #18232e; + background: + linear-gradient(135deg, rgba(14, 26, 35, 0.96), rgba(34, 50, 64, 0.92)), + radial-gradient(circle at top right, rgba(224, 188, 84, 0.18), transparent 35%); + color: #f1f3f5; + border-radius: 10px; +} + +.mosh .sla-banner { + display: flex; + justify-content: space-between; + gap: 12px; + align-items: flex-start; + margin-bottom: 12px; +} + +.mosh .sla-kicker, +.mosh .sla-card-label, +.mosh .sla-chat-title, +.mosh.sla-chat-card .sla-chat-title { + font-family: "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 0.72rem; + font-weight: 700; +} + +.mosh .sla-title, +.mosh .sla-card-title { + font-family: "Josefin Sans", "Roboto", sans-serif; + font-size: 1.2rem; + line-height: 1.2; + font-weight: 700; +} + +.mosh .sla-tags, +.mosh .sla-tag-row, +.mosh .sla-note-list, +.mosh .sla-action-row { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.mosh .sla-tag, +.mosh .sla-note-pill { + display: inline-flex; + align-items: center; + padding: 4px 8px; + border-radius: 999px; + border: 1px solid rgba(17, 17, 17, 0.16); + background: rgba(17, 17, 17, 0.06); + color: #14181c; + font-size: 0.74rem; +} + +.mosh .sla-note-pill-wide { + width: 100%; + justify-content: flex-start; + border-radius: 12px; +} + +.mosh .sla-card-grid { + gap: 12px; + margin-bottom: 12px; +} + +.mosh .sla-card-label, +.mosh .sla-card-title { + color: #14181c; +} + +.mosh .sla-panel .sla-card, +.mosh .tab[data-tab="ebb"] .sla-card { + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.12); + color: #edf1f4; + backdrop-filter: blur(4px); + box-shadow: none; +} + +.mosh .sla-panel .sla-card-copy, +.mosh .tab[data-tab="ebb"] .sla-card-copy, +.mosh .sla-panel .sla-card-label, +.mosh .tab[data-tab="ebb"] .sla-card-label, +.mosh .sla-panel .sla-card-title, +.mosh .tab[data-tab="ebb"] .sla-card-title { + color: rgba(245, 247, 250, 0.9); +} + +.mosh .sla-panel .sla-tag, +.mosh .sla-panel .sla-note-pill, +.mosh .tab[data-tab="ebb"] .sla-tag, +.mosh .tab[data-tab="ebb"] .sla-note-pill { + border-color: rgba(255, 255, 255, 0.14); + background: rgba(255, 255, 255, 0.08); + color: #f4f6f8; +} + +.mosh .sla-card { + padding: 12px; + border-radius: 10px; + background: #f4efe6; + border: 1px solid rgba(17, 17, 17, 0.14); + color: #14181c; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45); +} + +.mosh .sla-card-copy, +.mosh .sla-chat-copy, +.mosh.sla-chat-card .sla-chat-copy { + margin-top: 6px; + line-height: 1.45; + color: #2d3338; +} + +.mosh .sla-flux-meter { + margin-top: 10px; + height: 10px; + border-radius: 999px; + overflow: hidden; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.12); +} + +.mosh .sla-flux-meter-fill { + height: 100%; + border-radius: inherit; + background: linear-gradient(90deg, rgba(81, 163, 109, 0.9), rgba(203, 161, 68, 0.92)); +} + +.mosh .sla-flux-meter-fill.frayed { + background: linear-gradient(90deg, rgba(203, 161, 68, 0.92), rgba(194, 112, 55, 0.96)); +} + +.mosh .sla-flux-meter-fill.breach, +.mosh .sla-flux-meter-fill.catastrophic { + background: linear-gradient(90deg, rgba(194, 112, 55, 0.96), rgba(161, 59, 59, 0.96)); +} + +.mosh .sla-flux-stage { + display: inline-flex; + margin-top: 8px; + padding: 5px 10px; + border-radius: 999px; + font-family: "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.08em; + font-weight: 700; +} + +.mosh .sla-flux-stage.stable { background: rgba(81, 163, 109, 0.25); color: #dff7e7; } +.mosh .sla-flux-stage.charged { background: rgba(203, 161, 68, 0.25); color: #fff2c8; } +.mosh .sla-flux-stage.frayed { background: rgba(194, 112, 55, 0.28); color: #ffe2cc; } +.mosh .sla-flux-stage.breach { background: rgba(161, 59, 59, 0.32); color: #ffd7d7; } +.mosh .sla-flux-stage.catastrophic { background: rgba(99, 31, 31, 0.5); color: #fff0f0; } + +.mosh .sla-action-row button, +.mosh .sla-generator button, +.mosh .sla-world-tools button { + border: 1px solid rgba(255, 255, 255, 0.12); + background: linear-gradient(180deg, #f0c24b, #b88619); + color: #10171d; + font-family: "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 700; +} + +.mosh .sla-action-row button:hover, +.mosh .sla-generator button:hover, +.mosh .sla-world-tools button:hover { + box-shadow: 0 0 0 1px rgba(255,255,255,0.12), 0 4px 18px rgba(240, 194, 75, 0.28); +} + +.mosh .sla-rule-list { + display: grid; + gap: 8px; + margin-top: 10px; +} + +.mosh .sla-rule-toggle { + display: grid; + grid-template-columns: 18px 1fr; + gap: 10px; + align-items: flex-start; + padding: 10px; + border-radius: 10px; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + cursor: pointer; +} + +.mosh .sla-rule-toggle input[type="checkbox"] { + cursor: pointer; +} + +.mosh .sla-rule-text { + display: grid; + gap: 4px; +} + +.mosh .sla-rule-title { + font-family: "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; + color: #f4f6f8; +} + +.mosh .sla-rule-summary { + color: rgba(245, 247, 250, 0.82); + line-height: 1.35; +} + +.mosh .sla-ability-list .item-header, +.mosh .sla-ability-list .item { + background: rgba(15, 20, 26, 0.92); + color: #edf1f4; +} + +.mosh .sla-ability-list .skill-stat, +.mosh .sla-ability-list .item-header .skill-stat, +.mosh .sla-ability-list .item-controls a, +.mosh .sla-ability-list .item-controls i { + color: #edf1f4; +} + +.mosh .sla-ability-list .item-controls a:hover, +.mosh .sla-ability-list .item-controls a:focus { + color: #f0c24b; +} + +.mosh .sla-chat-card, +.mosh.sla-chat-card { + padding: 10px; + border: 1px solid #1e2d39; + border-radius: 8px; + background: linear-gradient(180deg, rgba(17, 27, 36, 0.98), rgba(26, 40, 51, 0.98)); + color: #eff3f7; +} + +.mosh .sla-chat-card .sla-chat-copy, +.mosh.sla-chat-card .sla-chat-copy, +.mosh .sla-chat-card .sla-chat-title, +.mosh.sla-chat-card .sla-chat-title { + color: #eff3f7; +} + +.mosh .sla-sidebar-actions, +.directory-header .sla-sidebar-actions { + display: flex; + gap: 8px; + margin-top: 8px; + flex-wrap: wrap; +} + +.mosh .sla-sidebar-actions button, +.directory-header .sla-sidebar-actions button { + border: 1px solid rgba(224, 196, 160, 0.8); + background: rgba(15, 14, 24, 0.94); + color: #f6e5c8; + border-radius: 12px; + padding: 8px 12px; + font-family: "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; +} + +.mosh .sla-generator .resource, +.mosh .sla-world-tools .resource { + padding: 8px; + border-radius: 8px; + background: rgba(18, 27, 36, 0.88); + color: #eff3f7; +} + +.mosh .sla-briefing-card { + min-height: 100%; +} + +.mosh.sla-generator .sla-card, +.mosh .sla-generator .sla-card { + background: #f4f2ec; + border: 1px solid #c8c1b4; + color: #161a1e; +} + +.mosh.sla-generator .sla-card-copy, +.mosh.sla-generator .sla-card-title, +.mosh.sla-generator .sla-card-label, +.mosh.sla-generator .sla-note-pill, +.mosh .sla-generator .sla-card-copy, +.mosh .sla-generator .sla-card-title, +.mosh .sla-generator .sla-card-label, +.mosh .sla-generator .sla-note-pill, +.mosh.sla-generator p, +.mosh .sla-generator p { + color: #161a1e; +} + +.mosh.sla-generator .sla-note-pill, +.mosh .sla-generator .sla-note-pill { + background: rgba(22, 26, 30, 0.08); + border-color: rgba(22, 26, 30, 0.16); +} + +.mosh.sla-generator .resource-label, +.mosh .sla-generator .resource-label, +.mosh.sla-generator label.checkbox, +.mosh .sla-generator label.checkbox, +.mosh.sla-generator [data-briefing], +.mosh .sla-generator [data-briefing] { + color: #14181c; +} + +.mosh .sla-generator input, +.mosh .sla-generator select, +.mosh .sla-world-tools input, +.mosh .sla-world-tools select { + background: rgba(255, 255, 255, 0.92); + color: #101417; +} + +.mosh .headerinputtext, +.mosh .headerinputfield input, +.mosh .charname input, +.mosh .mainstattext, +.mosh .resource-label, +.mosh .healthmaxtext, +.mosh .skill-stat, +.mosh .skill-name, +.mosh .sheet-tabs .tab-select, +.mosh .item-header, +.mosh .mainstatmod-title { + font-family: "Futura PT Cond Medium", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh .sheet-tabs .tab-select { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 34px; + padding: 0 12px; + margin: 0 2px; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 0.08em; + color: rgba(255, 255, 255, 0.82); + transition: background 120ms ease, color 120ms ease, box-shadow 120ms ease; +} + +.mosh .sheet-tabs .tab-select:hover, +.mosh .sheet-tabs .tab-select.active { + background: linear-gradient(180deg, #f2eee7, #d9d0c5); + color: #151515; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18); +} + +.mosh .sla-panel input, +.mosh .sla-panel select { + background: rgba(34, 43, 51, 0.92); + color: #f2f5f7; + border: 1px solid rgba(212, 190, 148, 0.42); +} + +.mosh .sla-panel input::placeholder, +.mosh .sla-panel textarea::placeholder { + color: rgba(242, 245, 247, 0.58); +} + +.mosh .sla-panel textarea, +.mosh .tab[data-tab="special-rules"] textarea { + background: rgba(34, 43, 51, 0.92); + color: #f2f5f7; + border: 1px solid rgba(212, 190, 148, 0.32); +} + +.mosh .tab[data-tab="sla"] .resource-label, +.mosh .tab[data-tab="special-rules"] .resource-label, +.mosh .tab[data-tab="sla"] .sla-card-copy, +.mosh .tab[data-tab="special-rules"] .sla-card-copy, +.mosh .tab[data-tab="sla"] .sla-card-label, +.mosh .tab[data-tab="special-rules"] .sla-card-label, +.mosh .tab[data-tab="sla"] .sla-card-title, +.mosh .tab[data-tab="special-rules"] .sla-card-title, +.mosh .tab[data-tab="special-rules"] .sla-rule-title, +.mosh .tab[data-tab="special-rules"] .sla-rule-summary { + color: #f2f5f7; +} + +.mosh .tab[data-tab="sla"] .sla-note-pill, +.mosh .tab[data-tab="special-rules"] .sla-note-pill { + background: rgba(242, 238, 231, 0.12); + border-color: rgba(242, 238, 231, 0.18); + color: #f4f6f7; +} + +.mosh .trauma-response-box { + min-height: 92px; + max-height: 132px; + font-size: 0.92rem; + line-height: 1.25; + overflow-y: auto; + resize: vertical; +} + +.mosh .sla-skill-name-cell { + display: flex; + flex-direction: column; + gap: 2px; +} + +.mosh .sla-skill-name-cell small { + color: #626262; + font-size: 0.75rem; + line-height: 1.2; +} + +.mosh .sla-skill-name-cell .sla-skill-flag { + display: inline-flex; + align-items: center; + width: fit-content; + padding: 2px 8px; + border-radius: 999px; + background: rgba(141, 31, 24, 0.1); + color: #8d1f18; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.68rem; + letter-spacing: 0.05em; + text-transform: uppercase; +} + +.mosh .sla-ebb-skill-list { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + margin: 10px 0 8px; +} + +.mosh .sla-ebb-skill-roll { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 3px; + width: 100%; + padding: 10px 12px; + border: 1px solid rgba(17, 17, 17, 0.18); + border-radius: 12px; + background: linear-gradient(180deg, #fbfaf7, #ece6dc); + color: #141414; + text-align: left; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45); +} + +.mosh .sla-ebb-skill-roll:hover, +.mosh .sla-ebb-skill-roll:focus { + border-color: rgba(140, 52, 40, 0.55); + box-shadow: 0 0 0 2px rgba(140, 52, 40, 0.12); +} + +.mosh .sla-ebb-skill-roll span { + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.98rem; + letter-spacing: 0.03em; + text-transform: uppercase; +} + +.mosh .sla-ebb-skill-meta { + display: flex; + width: 100%; + justify-content: space-between; + align-items: center; + gap: 8px; +} + +.mosh .sla-ebb-skill-roll small { + color: #5a5a5a; + font-size: 0.73rem; + line-height: 1.2; +} + +.mosh .sla-ebb-skill-roll strong { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 46px; + padding: 3px 8px; + border-radius: 999px; + background: rgba(18, 60, 52, 0.12); + color: #173a34; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.8rem; + letter-spacing: 0.04em; +} + +.mosh .sla-drug-alerts { + display: grid; + gap: 8px; + margin: 0 0 12px; +} + +.mosh .sla-drug-alert { + display: grid; + grid-template-columns: 1fr auto; + gap: 6px; + padding: 10px 12px; + border: 2px solid #191919; + border-radius: 16px; + background: #f5f2ec; + color: #171717; +} + +.mosh .sla-drug-alert.active { + border-color: #4d7b39; + box-shadow: inset 0 0 0 1px rgba(77, 123, 57, 0.18); +} + +.mosh .sla-drug-alert.withdrawal, +.mosh .sla-drug-alert.withdrawal-check { + border-color: #8c3428; + box-shadow: inset 0 0 0 1px rgba(140, 52, 40, 0.18); +} + +.mosh .sla-drug-alert-main, +.mosh .sla-drug-alert-meta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.mosh .sla-drug-alert-main, +.mosh .sla-drug-alert-summary { + grid-column: 1; +} + +.mosh .sla-drug-alert-name { + font-weight: 700; + font-size: 1.05rem; + color: #111; +} + +.mosh .sla-drug-alert-state, +.mosh .sla-drug-alert-duration { + display: inline-flex; + align-items: center; + border-radius: 999px; + padding: 2px 10px; + font-size: 0.8rem; + font-weight: 700; + background: #111; + color: #f5f2ec; +} + +.mosh .sla-drug-alert-summary, +.mosh .drug-item-summary span { + color: #2c2c2c; + font-size: 0.86rem; + line-height: 1.35; +} + +.mosh .drug-item-summary { + display: flex; + flex-direction: column; + gap: 2px; +} + +.mosh .drug-use-btn, +.mosh .drug-close-btn { + border: 1px solid #111; + border-radius: 999px; + background: #111; + color: #f8f5ee; + font-family: "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; + padding: 4px 10px; + line-height: 1; + min-width: 56px; +} + +.mosh .drug-close-btn { + background: #efe4d5; + color: #141414; +} + +.mosh .sla-drug-alert .drug-close-btn { + grid-column: 2; + grid-row: 1 / span 2; + align-self: center; + justify-self: end; + min-width: 88px; +} + +.mosh .sla-drug-list .item-controls { + flex: 0 0 168px; + display: flex; + align-items: center; + justify-content: flex-end; + gap: 6px; +} + +.mosh .drug-use-btn:disabled, +.mosh .drug-close-btn:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +@media (max-width: 720px) { + .mosh .sla-banner { + flex-direction: column; + } +} +.mosh .description, +.mosh .description .body, +.mosh .rollcontainer .body { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; + color: #141414; +} + +.mosh .sla-chat-section { + margin: 0 0 12px; + padding: 10px 12px; + border: 1px solid #d7d7d7; + border-radius: 10px; + background: #fbfbfb; +} + +.mosh .sla-chat-section-success { + border-color: rgba(15, 92, 46, 0.4); + background: rgba(15, 92, 46, 0.08); +} + +.mosh .sla-chat-section-danger { + border-color: rgba(141, 31, 24, 0.4); + background: rgba(141, 31, 24, 0.08); +} + +.mosh .sla-chat-section-target { + border-color: rgba(35, 73, 98, 0.35); + background: rgba(35, 73, 98, 0.06); +} + +.mosh .sla-chat-section-damage { + border-color: rgba(141, 31, 24, 0.42); + background: rgba(141, 31, 24, 0.08); +} + +.mosh .sla-chat-section-heal { + border-color: rgba(18, 92, 46, 0.42); + background: rgba(18, 92, 46, 0.08); +} + +.mosh .sla-chat-section-ebb-meta { + border-color: rgba(23, 58, 52, 0.28); + background: rgba(23, 58, 52, 0.06); +} + +.mosh .sla-chat-section-title { + margin-bottom: 6px; + font-size: 0.8rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh.sla-ebb-chat .rollcontainer { + background: linear-gradient(180deg, #eef5f1, #dfe9e4); + border-color: #22463f; +} + +.mosh.sla-ebb-chat .rollweaponh1 { + background: linear-gradient(90deg, #143832, #295149); + color: #f4faf7; +} + +.mosh.sla-ebb-chat .description, +.mosh.sla-ebb-chat .description .body, +.mosh.sla-ebb-chat .rollcontainer .body { + color: #10201c; +} + +.mosh.sla-ebb-chat .sla-chat-section { + border-color: rgba(34, 70, 63, 0.24); + background: rgba(34, 70, 63, 0.07); +} + +.mosh.sla-ebb-chat .sla-chat-section-success { + border-color: rgba(18, 87, 56, 0.38); + background: rgba(18, 87, 56, 0.1); +} + +.mosh.sla-ebb-chat .sla-chat-section-danger { + border-color: rgba(125, 31, 24, 0.38); + background: rgba(125, 31, 24, 0.09); +} + +.mosh.sla-ebb-chat .sla-chat-section-damage { + border-color: rgba(141, 31, 24, 0.42); + background: rgba(141, 31, 24, 0.1); +} + +.mosh.sla-ebb-chat .sla-chat-section-heal { + border-color: rgba(18, 92, 46, 0.42); + background: rgba(18, 92, 46, 0.1); +} + +.mosh .sla-effect-number { + font-weight: 700; +} + +.mosh .sla-effect-damage { + color: #a61f1a; +} + +.mosh .sla-effect-heal { + color: #136235; +} + +.mosh .sla-chat-chip { + display: inline-block; + margin-bottom: 8px; + padding: 2px 8px; + border-radius: 999px; + background: #111; + color: #fff; + font-size: 0.8rem; + font-weight: 700; +} + +.mosh .sla-chat-list { + margin: 0; + padding-left: 20px; +} + +.mosh .sla-chat-list li { + margin: 0 0 4px; +} + +/* ── SLA Initiative Badges (combat tracker) ─────────────────────────── */ +.sla-initiative-badge { + display: inline-block; + font-size: 0.62em; + font-weight: bold; + padding: 1px 5px; + border-radius: 3px; + margin-left: 5px; + vertical-align: middle; + letter-spacing: 0.05em; + white-space: nowrap; + line-height: 1.4; +} +.sla-initiative-badge.sla-init-before { + color: #7ec87e; + background: #0a2010; + border: 1px solid #7ec87e; +} +.sla-initiative-badge.sla-init-after { + color: #e07070; + background: #200a0a; + border: 1px solid #e07070; +} +.sla-initiative-badge.sla-init-enemy { + color: #999; + background: #1a1a1a; + border: 1px solid #555; +} + +/* ── Combatant HP bar (combat tracker) ─────────────────────────────── */ +.sla-hp-bar-wrap { + height: 4px; + background: #1a1a1a; + border-radius: 2px; + margin-top: 2px; + overflow: hidden; + width: 100%; +} +.sla-hp-bar { + height: 100%; + border-radius: 2px; + transition: width 0.3s ease, background 0.3s ease; +} diff --git a/css/mosh-red.css b/css/mosh-red.css new file mode 100644 index 0000000..3ae6782 --- /dev/null +++ b/css/mosh-red.css @@ -0,0 +1,1018 @@ +/* + * SLA Mothership — Blood Contract Theme + * Cyberpunk horror aesthetic: deep blacks, arterial red accents, + * neon-edged UI panels. Loaded after mosh.css to override. + * + * Original theme preserved in: css/mosh-original.css + */ + +/* ── New Font Imports ─────────────────────────────────────────────────────── */ +@import url("https://fonts.googleapis.com/css2?family=Rajdhani:wght@400;500;600;700&family=Share+Tech+Mono&family=Orbitron:wght@400;500;700&display=swap"); + +/* ── CSS Variables (scoped to .mosh) ──────────────────────────────────────── */ +.mosh { + --sla-bg-deepest: #050305; + --sla-bg-base: #0a0608; + --sla-bg-elevated: #110a0a; + --sla-bg-card: #160b0b; + --sla-bg-input: #0e0808; + --sla-border-dim: #280a0a; + --sla-border-mid: #4a0e0e; + --sla-border-hot: #880000; + --sla-red: #cc1818; + --sla-red-bright: #e83030; + --sla-red-glow: #ff4040; + --sla-red-muted: #7a2020; + --sla-red-dark: #330808; + --sla-text: #e5d8cc; + --sla-text-mid: #a8948a; + --sla-text-dim: #5e4a42; + --sla-text-label: #c0a090; + --sla-gold: #c8a020; /* kept for critical crests */ +} + +/* ── Global Window ────────────────────────────────────────────────────────── */ +.mosh .window-content, +.window-app .window-content.mosh { + background: var(--sla-bg-base); + color: var(--sla-text); +} + +.mosh ::-webkit-scrollbar-thumb { + background: var(--sla-border-hot); + border: 1px solid var(--sla-red-dark); +} +.mosh ::-webkit-scrollbar-track { + background: var(--sla-bg-deepest); +} +.mosh .window-content { + scrollbar-color: var(--sla-border-hot) var(--sla-bg-deepest); +} + +/* ── Global Text Reset ────────────────────────────────────────────────────── */ +.mosh, +.mosh input, +.mosh textarea, +.mosh select, +.mosh button, +.mosh .window-title, +.mosh .sheet-body { + font-family: "Rajdhani", "Josefin Sans", "Roboto", sans-serif; + color: var(--sla-text); +} + +.mosh input, +.mosh textarea, +.mosh select { + color: var(--sla-text) !important; + background: var(--sla-bg-input) !important; + border-color: var(--sla-border-mid) !important; +} + +.mosh input::placeholder, +.mosh textarea::placeholder { + color: var(--sla-text-dim) !important; +} + +/* ── Rollable hover ───────────────────────────────────────────────────────── */ +.list-roll:hover, +.list-roll:focus, +.rollable:hover, +.rollable:focus { + color: var(--sla-red-glow) !important; + text-shadow: 0 0 8px rgba(255, 64, 64, 0.6); + cursor: pointer; +} + +/* ── Header area ──────────────────────────────────────────────────────────── */ +.mosh .header { + background: linear-gradient(135deg, #0d0505 0%, #1a0808 40%, #0d0505 100%); + color: var(--sla-text); + border: 1px solid var(--sla-border-mid); + border-radius: 15px; + position: relative; + overflow: hidden; +} + +/* Scan-line shimmer effect on header */ +.mosh .header::after { + content: ""; + position: absolute; + inset: 0; + background: repeating-linear-gradient( + 0deg, + transparent, + transparent 3px, + rgba(204, 24, 24, 0.022) 3px, + rgba(204, 24, 24, 0.022) 4px + ); + pointer-events: none; + border-radius: 15px; +} + +.mosh .sla-sheet-wordmark { + color: var(--sla-red-bright); + text-shadow: + 0 0 12px rgba(232, 48, 48, 0.55), + 0 0 28px rgba(232, 48, 48, 0.25); + letter-spacing: 0.18em; + font-family: "Orbitron", "Josefin Sans", sans-serif; +} + +.mosh .headerinputtext { + color: var(--sla-text-label); + font-family: "Rajdhani", "Josefin Sans", sans-serif; + letter-spacing: 0.1em; +} + +/* Red-bordered input fields in header */ +.mosh .headerinputfield { + background: var(--sla-bg-input) !important; + border: 2px solid var(--sla-border-mid) !important; + color: var(--sla-text) !important; +} + +.mosh .headerinputfield:focus-within { + border-color: var(--sla-red) !important; + box-shadow: 0 0 6px rgba(204, 24, 24, 0.35); +} + +/* ── Nav Tabs ─────────────────────────────────────────────────────────────── */ +.sheet nav.sheet-tabs { + background: linear-gradient(90deg, #0d0505 0%, #160a0a 50%, #0d0505 100%); + border: 1px solid var(--sla-border-mid); + box-shadow: + inset 0 0 0 1px rgba(200, 24, 24, 0.1), + 0 6px 20px rgba(0, 0, 0, 0.5); +} + +.mosh .tab-select { + color: var(--sla-text-mid); + font-family: "Rajdhani", "Josefin Sans", sans-serif; + font-size: 0.9rem; + letter-spacing: 0.06em; + text-transform: uppercase; + transition: color 0.15s ease, text-shadow 0.15s ease; +} + +.mosh .tab-select:hover { + color: var(--sla-red-glow); + text-shadow: 0 0 8px rgba(255, 64, 64, 0.45); +} + +.mosh .tab-select.active { + color: var(--sla-red-bright); + text-decoration: none; + text-shadow: 0 0 10px rgba(232, 48, 48, 0.6); + border-bottom: 2px solid var(--sla-red); + padding-bottom: 2px; +} + +/* Remove the original bullet before active tab, replace with a red marker */ +.mosh .tabs .item.active::before { + display: none; +} +.mosh .tab-select.active::before { + content: "▸"; + color: var(--sla-red); + margin-right: 3px; +} + +/* ── Stat Labels (.mainstatlabel) ─────────────────────────────────────────── */ +.mosh .mainstatlabel { + background: linear-gradient(90deg, #1a0808 0%, #110505 100%); + border-top-left-radius: 2em; + border-bottom-left-radius: 2em; + border: 1px solid var(--sla-border-mid); + border-right: none; + position: relative; +} + +/* Red left-edge accent bar on stat labels */ +.mosh .mainstatlabel::before { + content: ""; + position: absolute; + left: 0; + top: 20%; + height: 60%; + width: 3px; + background: var(--sla-red); + border-radius: 2px; + box-shadow: 0 0 6px var(--sla-red); +} + +.mosh .mainstattext { + color: var(--sla-text); + font-family: "Rajdhani", "Josefin Sans", sans-serif; + font-size: 1.2rem; + letter-spacing: 0.05em; +} + +/* ── Stat Circles (main value inputs) ────────────────────────────────────── */ +.mosh .circle-input { + background: var(--sla-bg-input) !important; + border: 3px solid var(--sla-border-hot) !important; + color: var(--sla-text) !important; + font-family: "Share Tech Mono", "Roboto Mono", monospace; + box-shadow: 0 0 8px rgba(136, 0, 0, 0.3); +} + +.mosh .circle-input:focus { + border-color: var(--sla-red-glow) !important; + box-shadow: 0 0 12px rgba(255, 64, 64, 0.45); +} + +.mosh .square-input { + background: var(--sla-bg-input) !important; + border: 4px solid var(--sla-border-hot) !important; + color: var(--sla-text) !important; + font-family: "Share Tech Mono", "Roboto Mono", monospace; +} + +.mosh .square-input:focus { + border-color: var(--sla-red-glow) !important; + box-shadow: 0 0 10px rgba(255, 64, 64, 0.4); +} + +.mosh .smallcircle-input { + background: var(--sla-bg-input) !important; + border-color: var(--sla-border-hot) !important; + color: var(--sla-text) !important; +} + +/* ── Saves Background ────────────────────────────────────────────────────── */ +.mosh .savebackground { + background: linear-gradient(180deg, #130808 0%, #0e0505 100%); + border: 1px solid var(--sla-border-mid); + box-shadow: inset 0 0 20px rgba(0, 0, 0, 0.5); +} + +.mosh .savetext { + color: var(--sla-text-label); + font-family: "Rajdhani", sans-serif; + font-size: 0.75rem; + letter-spacing: 0.1em; +} + +.mosh .mainsavemod-input, +.mosh .mainstatmod-input { + background: var(--sla-bg-elevated) !important; + color: var(--sla-red-bright) !important; + border-radius: 0.5em; + font-family: "Share Tech Mono", monospace; +} + +.mosh .mainstatmod-title { + color: var(--sla-border-hot); +} + +/* ── Health/stat wrappers ────────────────────────────────────────────────── */ +.mosh .circle-statwrapper, +.mosh .circle-statwrapper-horizontal, +.mosh .circle-statwrapper-vertical { + background: var(--sla-bg-elevated); + border: 1px solid var(--sla-border-dim); +} + +.mosh .valuewrapper { + border: 3px solid var(--sla-border-hot); + background: transparent; +} + +.mosh .minmaxwrapper { + background: var(--sla-bg-input); + border: 3px solid var(--sla-border-hot); + color: var(--sla-text); +} + +.mosh .minmaxwrapper-black { + background: transparent; + border: 3px solid var(--sla-border-hot); + color: var(--sla-text); +} + +.mosh .armorWrapper { + background: var(--sla-bg-deepest); + border: 2px solid var(--sla-border-mid); +} + +.mosh .slant { + border-right-color: var(--sla-border-hot); +} + +/* ── Item lists ───────────────────────────────────────────────────────────── */ +.mosh .items-list .item { + border-bottom: 1px solid var(--sla-border-dim); + color: var(--sla-text); +} + +.mosh .items-list .item:hover { + background: rgba(136, 0, 0, 0.08); +} + +.mosh .items-list .item-header { + color: var(--sla-text-label); + font-family: "Rajdhani", sans-serif; + letter-spacing: 0.08em; + text-transform: uppercase; + font-size: 0.8rem; + border-bottom: 1px solid var(--sla-border-hot); +} + +.mosh .items-list .skill-name { + background: linear-gradient(90deg, #1a0808, #110505); + color: var(--sla-text); + border: 1px solid var(--sla-border-dim); + font-family: "Rajdhani", sans-serif; + letter-spacing: 0.04em; +} + +.mosh .items-list .skill-name:hover, +.mosh .items-list .skill-name.weapon-roll:hover { + background: linear-gradient(90deg, #2a0a0a, #1a0808); + border-color: var(--sla-red-muted); +} + +.mosh .items-list .skill-stat { + color: var(--sla-text-mid); + font-family: "Share Tech Mono", monospace; + font-size: 0.82rem; +} + +/* Item control icons */ +.mosh .items-list .item-controls a { + color: var(--sla-text-dim); +} +.mosh .items-list .item-controls a:hover { + color: var(--sla-red-bright); +} + +/* ── Buttons ──────────────────────────────────────────────────────────────── */ +.mosh .button-black { + background: linear-gradient(135deg, #1a0808, #0d0505); + border: 1px solid var(--sla-border-hot); + color: var(--sla-text); + box-shadow: inset 0 0 0 1px rgba(200, 24, 24, 0.1); +} + +.button-black:hover, +.button-black:focus { + background: #2a0a0a; + box-shadow: 0 0 10px rgba(204, 24, 24, 0.45), inset 0 0 0 1px var(--sla-red); + text-shadow: 0 0 8px rgba(255, 64, 64, 0.6); + color: var(--sla-red-glow); +} + +/* ── XP / Pip circles ────────────────────────────────────────────────────── */ +.mosh .circle { + background: var(--sla-bg-elevated); + border: 1px solid var(--sla-border-mid); + color: var(--sla-text-dim); +} + +.mosh .circle-f { + background: var(--sla-red-muted); + border: 1px solid var(--sla-red); +} + +/* ── SLA card/panel components ───────────────────────────────────────────── */ +.mosh .sla-card { + background: var(--sla-bg-card); + border: 1px solid var(--sla-border-mid); + border-radius: 8px; + padding: 10px; + position: relative; +} + +/* Corner bracket flourish on cards */ +.mosh .sla-card::before { + content: ""; + position: absolute; + top: -1px; + left: -1px; + width: 14px; + height: 14px; + border-top: 2px solid var(--sla-red); + border-left: 2px solid var(--sla-red); + border-radius: 2px 0 0 0; +} + +.mosh .sla-card::after { + content: ""; + position: absolute; + bottom: -1px; + right: -1px; + width: 14px; + height: 14px; + border-bottom: 2px solid var(--sla-red-muted); + border-right: 2px solid var(--sla-red-muted); + border-radius: 0 0 2px 0; +} + +.mosh .sla-panel { + background: var(--sla-bg-base); +} + +/* ── Separator lines ──────────────────────────────────────────────────────── */ +.mosh .seperatorLine { + border-bottom: 1px solid var(--sla-border-mid); +} + +.mosh .whiteline { + border-top: 2px solid var(--sla-border-hot); +} + +.mosh .blackline { + border-top: 1px solid var(--sla-border-dim); +} + +.mosh .greyline { + border-top: 1px dashed var(--sla-border-mid); +} + +/* ── Area/Section titles ──────────────────────────────────────────────────── */ +.mosh .area-title { + color: var(--sla-text-label); + font-family: "Rajdhani", sans-serif; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.mosh .circlestattitle { + color: var(--sla-text-mid); + font-family: "Rajdhani", sans-serif; +} + +.mosh .faded-label { + color: var(--sla-text-dim); + font-family: "Rajdhani", sans-serif; + letter-spacing: 0.1em; +} + +/* ── Skill Training ───────────────────────────────────────────────────────── */ +.mosh .skill_training_frame { + background: var(--sla-bg-elevated); + border: 1px solid var(--sla-border-dim); + color: var(--sla-text); +} + +.mosh .skill_training_text { + color: var(--sla-text-mid); +} + +/* ── Textarea inputs ──────────────────────────────────────────────────────── */ +.mosh .textarea-input { + background: var(--sla-bg-elevated) !important; + border: 2px solid var(--sla-border-mid) !important; + color: var(--sla-text) !important; +} + +.mosh .textarea-input-grey { + background: var(--sla-bg-elevated) !important; + color: var(--sla-text-mid) !important; +} + +.mosh .sbt-text-area { + background: var(--sla-bg-input) !important; + border-color: var(--sla-border-mid) !important; + color: var(--sla-text) !important; +} + +/* ── Armor wrapper ────────────────────────────────────────────────────────── */ +.mosh .armor-mod { + background: var(--sla-red-dark); + border-color: var(--sla-border-hot); + color: var(--sla-text); +} + +/* ── Profile image ───────────────────────────────────────────────────────── */ +.mosh .profile { + border: 2px solid var(--sla-border-hot); + box-shadow: 0 0 12px rgba(136, 0, 0, 0.4); + border-radius: 10px; +} + +/* ── Highlights ───────────────────────────────────────────────────────────── */ +.mosh .highlightText { + color: var(--sla-red-bright); + text-shadow: 0 0 6px rgba(232, 48, 48, 0.45); +} + +.mosh .greyText { color: var(--sla-text-mid); } +.mosh .darkGreyText { color: var(--sla-text); } /* override: dark-on-dark → readable */ +.mosh .whiteText { color: var(--sla-text); } +.mosh .black { color: var(--sla-text); } +.mosh .grey { color: var(--sla-text-mid); } +.mosh .darkgrey { color: var(--sla-text-dim); } +.mosh .white { color: var(--sla-text); } + +/* ── Rollcontainer (chat output base) ────────────────────────────────────── */ +.mosh .rollcontainer { + background: var(--sla-bg-elevated); + border: 2px solid var(--sla-border-mid); + color: var(--sla-text); +} + +/* ── Crit success/failure colours — keep readable on dark ────────────────── */ +.mosh .sla-roll-outcome.sla-crit-success, +.mosh .sla-roll-result .dice-total.sla-crit-success { + color: #50c87a; + background: rgba(80, 200, 122, 0.1); +} + +.mosh .sla-roll-outcome.sla-crit-failure, +.mosh .sla-roll-result .dice-total.sla-crit-failure { + color: var(--sla-red-bright); + background: rgba(232, 48, 48, 0.1); +} + +.mosh .sla-roll-result.sla-crit-success .dice-total { + border-color: #50c87a; + box-shadow: 0 0 0 2px rgba(80, 200, 122, 0.25); +} + +.mosh .sla-roll-result.sla-crit-failure .dice-total { + border-color: var(--sla-red); + box-shadow: 0 0 0 2px rgba(204, 24, 24, 0.25); +} + +/* ── Chat sections ────────────────────────────────────────────────────────── */ +.mosh .sla-chat-section { + background: var(--sla-bg-elevated); + border-color: var(--sla-border-mid); +} + +.mosh .sla-chat-section-success { + border-color: rgba(80, 200, 122, 0.45); + background: rgba(80, 200, 122, 0.07); +} + +.mosh .sla-chat-section-danger, +.mosh .sla-chat-section-damage { + border-color: rgba(220, 40, 40, 0.45); + background: rgba(220, 40, 40, 0.08); +} + +.mosh .sla-chat-chip { + background: var(--sla-red-dark); + border: 1px solid var(--sla-border-hot); + color: var(--sla-text); +} + +.mosh .sla-chat-section-title { + color: var(--sla-text-label); + font-family: "Rajdhani", sans-serif; + letter-spacing: 0.1em; +} + +.mosh .description, +.mosh .description .body, +.mosh .rollcontainer .body { + color: var(--sla-text); + font-family: "Rajdhani", "Josefin Sans", sans-serif; +} + +/* ── Roll weapon header ───────────────────────────────────────────────────── */ +.mosh .rollweaponh1 { + background: linear-gradient(90deg, #1a0606, #2a0a0a); + color: var(--sla-text); + border-bottom: 1px solid var(--sla-border-hot); +} + +/* ── Drug system ──────────────────────────────────────────────────────────── */ +.mosh .sla-drug-alert-duration { + background: var(--sla-red-dark); + color: var(--sla-text-label); + border: 1px solid var(--sla-border-hot); +} + +.mosh .sla-drug-alert-summary, +.mosh .drug-item-summary span { + color: var(--sla-text-mid); +} + +.mosh .drug-use-btn { + background: var(--sla-red-dark); + border-color: var(--sla-border-hot); + color: var(--sla-text); +} + +.mosh .drug-use-btn:hover { + background: #440a0a; + border-color: var(--sla-red-bright); +} + +.mosh .drug-close-btn { + background: var(--sla-bg-elevated); + border-color: var(--sla-border-mid); + color: var(--sla-text-mid); +} + +/* ── Stresslabel / stresstext ─────────────────────────────────────────────── */ +.mosh .stresslabel { + background: var(--sla-red-dark); + border-right: 2px solid var(--sla-red); +} + +.mosh .stresstext { + color: var(--sla-text); + font-family: "Rajdhani", sans-serif; + letter-spacing: 0.08em; +} + +/* ── Creature sheet ───────────────────────────────────────────────────────── */ +.mosh .creature-header-grid { + background: linear-gradient(135deg, #1a0606, #0a0404); +} + +.mosh .creature-header { + color: var(--sla-text); +} + +.mosh .creature-abilities { + background: #100808; + border: 2px solid var(--sla-border-hot); + outline: 5px solid #0a0505; +} + +.mosh .creature-ability-title { + color: var(--sla-text); + font-family: "Rajdhani", sans-serif; + letter-spacing: 0.08em; +} + +.mosh .creature-ability-text { + color: var(--sla-text-mid); +} + +/* ── Ability buttons ──────────────────────────────────────────────────────── */ +.mosh .sla-ability-use-btn, +.mosh .ability-use, +.mosh .ability-use-trigger { + color: var(--sla-red-bright); +} + +.mosh .sla-ability-use-btn:hover, +.mosh .ability-use:hover, +.mosh .ability-use-trigger:hover { + color: var(--sla-red-glow); + text-shadow: 0 0 6px rgba(255, 64, 64, 0.5); +} + +/* ── Ebb flux bar ─────────────────────────────────────────────────────────── */ +.mosh .sla-flux-bar-fill { + background: linear-gradient(90deg, #440088, #8800cc) !important; +} + +/* ── Prometheus regeneration badge ───────────────────────────────────────── */ +.mosh .sla-prometheus-badge { + background: var(--sla-red-dark); + border: 1px solid var(--sla-red); + color: var(--sla-text); +} + +/* ── Banner and fleet controls ────────────────────────────────────────────── */ +.mosh .sla-banner { + background: linear-gradient(90deg, #1a0606, #0d0404, #1a0606); + border: 1px solid var(--sla-border-mid); +} + +/* ── Transponder blink (keep dramatic on dark) ────────────────────────────── */ +@keyframes transponderblink { + from { background-color: var(--sla-bg-deepest); box-shadow: none; } + to { background-color: var(--sla-red-bright); box-shadow: 0 0 12px var(--sla-red-bright); } +} + +.mosh .transponder input[type="checkbox"]:checked, +.mosh input[type="radio"]:checked { + background: var(--sla-red-bright); + border-color: var(--sla-red-glow); + box-shadow: 0 0 15px var(--sla-red); + animation: transponderblink 0.6s alternate infinite; +} + +/* ── SLA-specific panel (rules, ebb, etc.) ────────────────────────────────── */ +.mosh .sla-species-rule, +.mosh .sla-rule-toggle { + background: var(--sla-bg-elevated); + border-color: var(--sla-border-dim); + color: var(--sla-text); +} + +.mosh .sla-species-rule:hover, +.mosh .sla-rule-toggle:hover { + border-color: var(--sla-border-mid); + background: #1a0c0c; +} + +/* ── Condition pips ──────────────────────────────────────────────────────── */ +.mosh .treatment-button { + color: var(--sla-text-mid); +} +.mosh .treatment-button:hover { + color: var(--sla-red-bright); +} + +/* ── Notes / Biography editors ────────────────────────────────────────────── */ +.mosh .tox .tox-editor-container { + background: var(--sla-bg-elevated); +} +.mosh .tox-edit-area { + color: var(--sla-text); +} + +/* ── Dice tooltip min/max rolls ───────────────────────────────────────────── */ +.dice-tooltip .dice-rolls .roll.max { + color: #50c87a; +} +.dice-tooltip .dice-rolls .roll.min { + color: var(--sla-red-bright); +} + +/* ── HP bar in combat tracker — red theme variant ────────────────────────── */ +.sla-hp-bar-wrap { + background: #0a0404; +} + +/* ── Initiative badges — enhanced for dark theme ────────────────────────── */ +.sla-initiative-badge.sla-init-before { + color: #60e080; + background: #041408; + border: 1px solid #40b050; + box-shadow: 0 0 5px rgba(64, 176, 80, 0.3); +} + +.sla-initiative-badge.sla-init-after { + color: var(--sla-red-bright); + background: #120404; + border: 1px solid var(--sla-red); + box-shadow: 0 0 5px rgba(204, 24, 24, 0.35); +} + +.sla-initiative-badge.sla-init-enemy { + color: #cc8040; + background: #100808; + border: 1px solid #884422; + box-shadow: 0 0 4px rgba(136, 68, 34, 0.3); +} + +/* ── Weapon list special notes tooltip hint ───────────────────────────────── */ +.mosh .weapon-roll[title]:hover::after { + content: attr(title); + position: absolute; + bottom: calc(100% + 4px); + left: 0; + background: #1a0808; + color: var(--sla-text-label); + border: 1px solid var(--sla-border-hot); + border-radius: 4px; + padding: 3px 7px; + font-size: 0.75rem; + font-family: "Rajdhani", sans-serif; + white-space: nowrap; + z-index: 100; + box-shadow: 0 2px 8px rgba(0,0,0,0.7); + pointer-events: none; +} +.mosh .weapon-roll { + position: relative; +} + +/* ── Traits tab extra styling ─────────────────────────────────────────────── */ +.mosh .trait-effect-roll { + transition: color 0.12s, text-shadow 0.12s; +} +.mosh .trait-effect-roll:hover { + color: var(--sla-red-glow) !important; + text-shadow: 0 0 8px rgba(255, 64, 64, 0.5); +} + +/* ── Generic link/control colours ────────────────────────────────────────── */ +.mosh a { + color: var(--sla-text-mid); +} +.mosh a:hover { + color: var(--sla-red-bright); + text-shadow: 0 0 6px rgba(232, 48, 48, 0.4); +} + +/* ── Combat tracker — NPC enemy row tint ─────────────────────────────────── */ +#combat-tracker .combatant.sla-npc-enemy { + background: rgba(50, 5, 5, 0.35); + border-left: 2px solid var(--sla-red-muted); +} + +/* ── Select/Dropdowns ─────────────────────────────────────────────────────── */ +.mosh select option { + background: var(--sla-bg-elevated); + color: var(--sla-text); +} + +/* ── Number inputs monospace ─────────────────────────────────────────────── */ +.mosh input[data-dtype="Number"] { + font-family: "Share Tech Mono", "Roboto Mono", monospace; +} + +/* ── Header name input .noborder ──────────────────────────────────────────── */ +.mosh .noborder { + color: var(--sla-text) !important; + caret-color: var(--sla-red); +} + +/* ── Macro popup dialogs ─────────────────────────────────────────────────── */ +.mosh .macro_window, +.macro-popup-dialog .window-content { + background: var(--sla-bg-elevated); + color: var(--sla-text); +} + +/* ── Readability fixes: dark-text-on-dark overrides ─────────────────────── */ + +/* skill-stat colour (was #111 in mosh.css) — already covered above but + making explicit for safety */ +.mosh .items-list .skill-stat, +.mosh .skill-stat { + color: var(--sla-text-mid) !important; +} + +/* Crew name was color:black */ +.mosh .sbt-crew-name { + color: var(--sla-text) !important; +} + +/* Dropdown links were color:black on white background */ +.mosh .dropdown-content { + background: var(--sla-bg-elevated); + border: 1px solid var(--sla-border-mid); +} +.mosh .dropdown-content a { + color: var(--sla-text-mid) !important; +} +.mosh .dropdown-content a:hover { + background: #1a0808; + color: var(--sla-red-bright) !important; +} + +/* drug stat label (color:#111) */ +.mosh .sla-drug-stat-label { + color: var(--sla-text-mid) !important; +} + +/* SBT panel text */ +.mosh .sbt-crew-job { + color: var(--sla-text-mid) !important; +} + +/* Rollcontainer body text */ +.mosh .description, +.mosh .description .body, +.mosh .rollcontainer .body, +.mosh .rollcontainer { + color: var(--sla-text) !important; +} + +/* Any remaining black/dark utility class on dark bg */ +.mosh .black { + color: var(--sla-text) !important; +} +.mosh .darkgrey, +.mosh .darkGreyText { + color: var(--sla-text) !important; /* override: was sla-text-dim (#5e4a42) — unreadable on dark bg */ +} +/* Health / stat value inputs specifically */ +.mosh .maxhealth-input, +.mosh .maxhealth-input.darkGreyText { + color: var(--sla-text) !important; + background: var(--sla-bg-input) !important; +} + +/* Input fields — catch-all for any we missed */ +.mosh input:not([type="checkbox"]):not([type="radio"]) { + background: var(--sla-bg-input) !important; + color: var(--sla-text) !important; +} + +/* ── Skills lock & used — Blood Contract overrides ────────────────────── */ +.mosh .skill-bonus-locked { + color: var(--sla-text-dim) !important; +} +.mosh .skill-used-check { + accent-color: var(--sla-red-bright) !important; +} +.mosh .sla-skills-lock-toggle { + color: var(--sla-text-mid); +} +.mosh .sla-skills-lock-toggle:hover { + color: var(--sla-red-glow); +} +/* ── Health reset — Blood Contract ────────────────────────────────────── */ +.mosh .sla-health-reset { + color: var(--sla-text-mid); +} +.mosh .sla-health-reset:hover { + color: var(--sla-red-glow); + text-shadow: 0 0 6px rgba(255, 64, 64, 0.5); +} +/* ── Theme toggle button — Blood Contract ─────────────────────────────── */ +.mosh .sla-theme-toggle { + color: var(--sla-red-muted); +} +.mosh .sla-theme-toggle:hover { + color: var(--sla-red-glow) !important; + text-shadow: 0 0 8px rgba(255, 64, 64, 0.6); +} + +/* Make the sheet body itself dark */ +.mosh .sheet-body, +.mosh form.flexcol { + background: var(--sla-bg-base); +} + +/* Tab content panels */ +.mosh .tab { + background: var(--sla-bg-base); + color: var(--sla-text); +} + +/* ── Quick Roll Bar — Blood Contract ──────────────────────────────────── */ +.mosh .sla-quick-roll-bar button { + background: linear-gradient(135deg, #1a0808, #110505) !important; + border: 1px solid var(--sla-border-hot) !important; + color: var(--sla-text-label) !important; + font-family: "Rajdhani", sans-serif; +} +.mosh .sla-quick-roll-bar button:hover { + background: #2a0a0a !important; + border-color: var(--sla-red) !important; + color: var(--sla-red-glow) !important; + box-shadow: 0 0 8px rgba(204, 24, 24, 0.4); + text-shadow: 0 0 6px rgba(255, 64, 64, 0.5); +} + +/* ── Remaining dark-text-on-dark fixes ────────────────────────────────── */ + +/* area-title used in some panels */ +.mosh .area-title, +.mosh .circlestatlabel { + color: var(--sla-text-mid) !important; +} + +/* roll-target — the white roll result boxes in the sheet */ +.mosh .roll-target { + background: var(--sla-bg-card) !important; + color: var(--sla-text) !important; + border: 1px solid var(--sla-border-hot) !important; +} +.mosh .roll-targetbox { + border-color: var(--sla-red-muted) !important; + color: var(--sla-text) !important; +} + +/* button-white used in some dialogs/panels */ +.mosh .button-white { + background: var(--sla-bg-elevated) !important; + color: var(--sla-text) !important; + border-color: var(--sla-border-hot) !important; +} + +/* item-controls icons — slightly more visible */ +.mosh .items-list .item-controls a { + color: var(--sla-text-mid) !important; +} + +/* skill_training_text inside pip circles */ +.mosh .skill_training_text { + color: var(--sla-text) !important; +} + +/* ── Card / item panel labels & copy — hardcoded dark in mosh.css ─────── */ +/* .sla-card-label / .sla-card-title have color:#14181c in mosh.css */ +.mosh .sla-card-label, +.mosh .sla-card-title, +.mosh .sla-kicker { + color: var(--sla-red-muted) !important; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +/* .sla-card-copy / .sla-chat-copy have color:#2d3338 in mosh.css */ +.mosh .sla-card-copy, +.mosh .sla-chat-copy, +.mosh.sla-chat-card .sla-chat-copy { + color: var(--sla-text-mid) !important; +} + +/* .sla-tag / .sla-note-pill have color:#14181c in mosh.css */ +.mosh .sla-tag, +.mosh .sla-note-pill { + color: var(--sla-text) !important; + background: rgba(200, 24, 24, 0.08) !important; + border-color: var(--sla-border-mid) !important; +} + +/* FIELD SKILL DECK label row that appears under Skills header */ +.mosh .sla-skill-deck-label, +.mosh .items-header .item-name, +.mosh .items-header span { + color: var(--sla-text-mid) !important; +} diff --git a/css/mosh.css b/css/mosh.css new file mode 100644 index 0000000..27e3b2d --- /dev/null +++ b/css/mosh.css @@ -0,0 +1,4358 @@ +@import url("https://fonts.googleapis.com/css2?family=Josefin+Sans:wght@400;500;600;700&family=Roboto+Mono:wght@400;500;700&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Martel:wght@400;800&family=Roboto:wght@300;400;500&display=swap"); +@import url('https://fonts.googleapis.com/css2?family=Hind:wght@300;400;500;600;700&display=swap'); + +@include-when-export url(https://fonts.loli.net/css?family=PT+Serif:400,400italic,700,700italic&subset=latin,cyrillic-ext,cyrillic,latin-ext); + +/* =========== */ + +/* pt-serif-regular - latin */ +@font-face { + font-family: 'Futura PT Book'; + font-style: normal; + font-weight: normal; + src: local('Futura PT Book'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* pt-serif-700 - latin */ +@font-face { + font-family: 'Futura PT Bold'; + font-style: normal; + font-weight: bold; + src: local('Futura PT Bold'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* pt-serif-700 - latin */ +@font-face { + font-family: 'Futura PT Cond Medium'; + font-style: normal; + font-weight: normal; + src: local('Futura PT Cond Medium'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* pt-serif-700 - latin */ +@font-face { + font-family: 'Futura PT Cond Bold'; + font-style: normal; + font-weight: bold; + src: local('Futura PT Cond Bold'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; +} + +/* Branding */ +#logo { + content: url("/systems/sla-mothership/images/icons/ui/system/logo.webp"); + width: 100px; + height: 50px; +} + +#pause>img { + background: none; + content: url("/systems/sla-mothership/images/icons/ui/system/pause.webp"); + width: 200px; + height: 200px; + top: -95px; + left: calc(50% - 100px); + opacity: .3; +} + +#pause { + background: none; +} + +#pause figcaption { + font-family: "Roboto", sans-serif; + color: #ffffff; + opacity: .3; + padding-left: 6px; +} + +/* Paragraph */ +p { + margin: 0em 0; +} + +/* Global styles */ +.window-app { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; +} + +.window-app .window-content { + background: #fff; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ +} + +.mosh ::-webkit-scrollbar-thumb { + outline: none; + border-radius: 3px; + background: black; + border: 1px solid white; +} + +.mosh .window-content{ + scrollbar-width: thin; + scrollbar-color: black #fff; +} + +.mosh .white{ + color:white; +} + +.mosh .darkgrey{ + color:rgb(92, 92, 92); +} +/* .chat-message, #chat-form, .textarea{ + background: white; +} */ + +.dice-tooltip .dice-rolls .roll.max { + color: #18520b; + filter: sepia(0.5) hue-rotate(60deg); +} +.dice-tooltip .dice-rolls .roll.min { + color: #aa0200; + filter: sepia(0.5) hue-rotate(340deg); +} + +.list-roll:hover, +.list-roll:focus, +.rollable:hover, .rollable:focus { + color: #000; + text-shadow: 0 0 10px rgb(112, 112, 112); + cursor: pointer; +} + +.grid, +.grid-2col { + display: grid; + grid-column: span 2 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 2px; + /* margin: 10px 0; */ + padding: 0; +} +.grid-1col { + grid-column: span 1 / span 1; + grid-template-columns: repeat(1, minmax(0, 1fr)); +} + +.widegap { + gap: 16px; +} + +.grid-3col { + grid-column: span 3 / span 3; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.grid-4col { + grid-column: span 4 / span 4; + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +.grid-5col { + grid-column: span 5 / span 5; + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.grid-6col { + grid-column: span 5 / span 5; + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.grid-7col { + grid-column: span 7 / span 7; + grid-template-columns: repeat(7, minmax(0, 1fr)); +} + +.grid-8col { + grid-column: span 8 / span 8; + grid-template-columns: repeat(8, minmax(0, 1fr)); +} + +.grid-9col { + grid-column: span 9 / span 9; + grid-template-columns: repeat(9, minmax(0, 1fr)); +} + +.grid-10col { + grid-column: span 10 / span 10; + grid-template-columns: repeat(10, minmax(0, 1fr)); +} + +.grid-11col { + grid-column: span 11 / span 11; + grid-template-columns: repeat(11, minmax(0, 1fr)); +} + +.grid-12col { + grid-column: span 12 / span 12; + grid-template-columns: repeat(12, minmax(0, 1fr)); +} + +.flex-group-center, +.flex-group-left, +.flex-group-right { + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + text-align: center; + padding: 3px; + /* border: 1px solid #999; */ +} + +.flex-group-left { + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + text-align: left; +} + +.flex-group-right { + -webkit-box-pack: end; + -ms-flex-pack: end; + justify-content: flex-end; + text-align: right; +} + +.flex-center { + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center; + -webkit-box-pack: center; + -ms-flex-pack: center; + justify-content: center; + text-align: center; +} + +.flex-between { + -webkit-box-pack: justify; + -ms-flex-pack: justify; + justify-content: space-between; +} + +.flex { + display: flex; + justify-content:space-evenly; + align-items: center; + flex: auto; +} + + +/* Styles limited to mosh sheets */ +.mosh .item-form { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh input { + font-weight: inherit; + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh input, +.mosh textarea, +.mosh select { + color: #111317; +} + +.mosh input::placeholder, +.mosh textarea::placeholder { + color: #666b72; +} + +.mosh, +.mosh textarea, +.mosh select, +.mosh button, +.window-app .window-title { + font-family: "Josefin Sans", "Roboto", sans-serif; +} + +.mosh .center-icon{ + font-size: 42px; + align-items: center; + justify-content: center; + display: flex; +} + +.mosh .transponder input[type="checkbox"] { + /* display: none; */ + appearance: inherit; + border: 2px white; + border-style: double; + border-radius: 100px; +} + + +.mosh .transponder input[type="checkbox"]:checked, .mosh input[type="radio"]:checked { + background: white; + border-radius: 100px; + appearance: inherit; + animation: transponderblink 0.5s alternate infinite; + box-shadow: 0 0 15px white; +} + +.mosh .transponder input[type="checkbox"] span { + color: grey; + position: relative; + /* margin-left: -1rem; */ + display: inline-block; + right: -25px; + font-size: 17px; + font-weight: bold; + font-family: 'Roboto'; + bottom: 2px; +} + +.mosh .transponder input[type="checkbox"]:checked span { + color: grey; + position: relative; + /* margin-left: -1rem; */ + display: inline-block; + right: -25px; + font-size: 17px; + font-weight: bold; + font-family: 'Roboto'; + bottom: 2px; + /* text-shadow: 0 0 11px grey; */ +} + +@keyframes transponderblink { + from {background-color: black;} + to { + background-color: white; + } +} + +@keyframes transpondertextblink { + from {color: grey;} + to { + color: white; + } +} + +.mosh .char-header { + -webkit-box-flex: 0; + /* -ms-flex: 0 0 610px; + flex: 0 0 610px; */ + /* overflow: hidden; */ + display: -webkit-box; + display: -ms-flexbox; + display: flex; + -webkit-box-orient: horizontal; + -webkit-box-direction: normal; + -ms-flex-direction: row; + flex-direction: row; + -ms-flex-wrap: wrap; + flex-wrap: wrap; + -webkit-box-pack: start; + -ms-flex-pack: start; + justify-content: flex-start; + margin-bottom: 14px; +} + + + +.mosh .char-header .profile-img { + -webkit-box-flex: 0; + width: 100px; + height: 100px; + margin-right: 10px; + margin-top: 10px; +} + +.mosh .char-header .header-fields { + -webkit-box-flex: 1; + -ms-flex: 1; + flex: 1; +} + +.mosh .char-header .header-grid { + display: grid; + grid-template-areas: + 'header header header' + 'abilities centercol saves ' + 'mobilehealth mobilehealth mobilehealth'; + grid-gap: 10px; + /* background-color: rgb(226, 226, 226); */ + padding: 2px; + grid-template-columns: 238px auto 100px; + container-type: inline-size; +} + +.mosh .abilities {grid-area: abilities;} +.mosh .saves {grid-area: saves;} + +.mosh .stress {grid-area: stress;} +.mosh .health {grid-area: centercol;} +@container (max-width: 610px) { + .mosh .health {grid-area: mobilehealth;} +} +.mosh .healthspread {width:96%;} + +.mosh .char-header h1.charname { + height: auto; + padding: 0px; + margin: 0px 0; + border-bottom: 0; +} + +.mosh .char-header h1.charname input { + width: 100%; + height: auto; + + background: #fff; + + padding-left: 1em; + border: 4px solid #111; + border-radius: 3em; + font-size: 0.9rem; + font-weight: bold; + text-align: left; +} + +.mosh .sheet-tabs { + -webkit-box-flex: 0; + -ms-flex: 0; + flex: 0; +} + +.mosh .sheet-body, +.mosh .sheet-body .tab, +.mosh .sheet-body .tab .editor { + height: 100%; +} + +.sheet nav.sheet-tabs { + background: + linear-gradient(90deg, rgba(16, 16, 16, 0.98), rgba(33, 20, 15, 0.98) 55%, rgba(16, 16, 16, 0.98)), + #111; + color: white; + padding: 8px 10px; + border-radius: 14px; + margin-top: 10px; + position: relative; + z-index: 2; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 10px 24px rgba(0, 0, 0, 0.14); +} + +.mosh .tox .tox-editor-container { + background: #fff; +} + +.mosh .tox .tox-edit-area { + padding: 0 8px; +} + +.mosh .origin { + width: 0; + height: 0; +} + +.mosh .seperatorLine{ + border-bottom: 2px solid #111; + height: 0; + width: 100%; +} + +.mosh .skill_training_frame{ + height: 47px; + background: rgb(230,230,230); + border-radius: 9px; + font-family: "Roboto", sans-serif; + font-size: 11pt; + font-weight: 400; + padding: 8px; +} +.mosh .skill_training_text{ + font-family: "Roboto", sans-serif; + font-size: 11pt; + font-weight: 500; + color: grey; +} + +.mosh .resource-label { + font-weight: bold; + text-transform: uppercase; + margin-bottom: 3px; + text-align: center; +} + +.mosh .faded-label { + text-transform: uppercase; + margin-bottom: 3px; + color:rgb(129, 129, 129); + font-weight:normal; + + text-align: left; + grid-column: 1/-1; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ + font-size: 1.1rem; + line-height: 1; + text-align: center; +} + +.mosh .tabs { + height: 40px; + border-top: 2px solid rgb(56, 56, 56); + border-bottom: 2px solid rgb(56, 56, 56); +} + +.mosh .tabs .item { + /* line-height: 40px; */ + font-weight: bold; +} + +.mosh .tabs .item.active { + text-decoration: underline; + text-shadow: none; +} + +.mosh .tabs .item.active::before { + font-family: "Font Awesome 6 Pro"; + content: "\f0da"; + color:white; + position: relative; + right: 6px; + margin-left: -1rem; + display: inline-block; +} + +.mosh .items-list { + list-style: none; + margin: 7px 0; + padding: 0; + /* overflow-y: auto; */ +} + +.mosh .items-list .item-header { + font-weight: bold; +} + +.mosh .items-list .item { + height: 35px; + line-height: 24px; + padding: 3px 0; + border-bottom: 1px solid #BBB; +} + +.mosh .skills-list .item { + height: 36px; + line-height: 21px; + padding: 3px 0; + border-bottom: 1px solid #BBB; +} + +.mosh .items-list .item .item-image { + -webkit-box-flex: 0; + -ms-flex: 0 0 24px; + flex: 0 0 24px; + margin-right: 5px; +} + +.mosh .roll-image { + -webkit-box-flex: 0; + flex: 0 24px; + margin-top: -3px; + margin-left: 11px; + margin-right: 0px; + width: 50px; + border-radius: 0 0 0 16px; + border: 1px solid #000; +} + +.mosh .items-list .item img { + display: block; +} + +.mosh .items-list .item-name { + margin: 0; +} + +.mosh .items-list .skill-name { + font-weight: bold; + font-size: 14px; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + color: white; + /* text-transform: uppercase; */ + margin-left: 0px; + background: #111; + padding: 2px; + /* padding-left: 8px; */ + border-radius: 21px; + text-align: center; + height: 27px; + overflow: hidden; +} + +.mosh .items-list .skill-stat { + font-size: medium; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + color: #111; + margin-left: 0px; + /* background: black; */ + padding: 2px; + padding-left: 8px; + border-radius: 21px; + text-align: center; + white-space: nowrap; +} + +.mosh .items-list .item-controls { + -webkit-box-flex: 0; + -ms-flex: 0 0 86px; + flex: 0 0 86px; + text-align: right; +} + +.mosh .button-black { + font-weight: bold; + font-size: 16px; + color: white; + margin-left: 0px; + background: #111; + border-radius: 21px; + text-align: center; + overflow: hidden; + padding: 10px; +} + +.button-black:hover, +.button-black:focus{ + /* color: #ffffff; */ + text-shadow: 0 0 10px rgb(112, 112, 112); + box-shadow: 0 0 10px 0px #9e9e9e; + background: #202020; + cursor: pointer; +} + +.mosh .button-grey { + font-weight: bold; + font-size: 16px; + color: white; + margin-left: 0px; + background: grey; + border-radius: 21px; + text-align: center; + overflow: hidden; + padding: 10px; +} + +.button-grey:hover, +.button-grey:focus{ + /* color: #494949; */ + text-shadow: 0 0 10px rgb(112, 112, 112); + box-shadow: 0 0 5px 0px #b9b9b9; + background: rgb(100, 100, 100); + cursor: pointer; + /* border: 1px solid #ffffff; */ +} + +.mosh .button-white { + font-weight: bold; + font-size: 16px; + color: #111; + margin-left: 0px; + background: white; + border-radius: 21px; + text-align: center; + overflow: hidden; + padding: 10px; + border: 3px solid #111; +} + +/* Dropdown Button */ +.mosh .dropbtn { + background-color: #111; + color: white; + padding: 16px; + font-size: 16px; + border: none; +} + +/* The container
- needed to position the dropdown content */ +.mosh.dropdown { + position: relative; + display: inline-block; +} + +/* Dropdown Content (Hidden by Default) */ +.mosh .dropdown-content { + display: none; + position: absolute; + background-color: #f1f1f1; + min-width: 160px; + box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); + z-index: 1; +} + +/* Links inside the dropdown */ +.mosh .dropdown-content a { + color: black; + padding: 12px 16px; + text-decoration: none; + display: block; +} + +/* Change color of dropdown links on hover */ +.mosh .dropdown-content a:hover {background-color: #ddd;} + +/* Show the dropdown menu on hover */ +.mosh .dropdown:hover .dropdown-content {display: block;} + +/* Change the background color of the dropdown button when the dropdown content is shown */ +.mosh .dropdown:hover .dropbtn {background-color: #3d3d3d;} + + +.mosh .sbt-profile { + width: 100px; + height: auto; + border: 0; + padding: 10px; +} + +.mosh .sbt-crew-name .hidden-item-controls { + -webkit-box-flex: 0; + -ms-flex: 0 0 86px; + flex: 0 0 86px; + text-align: right; + display: none; +} + +.mosh .sbt-crew-name:hover .hidden-item-controls { + -webkit-box-flex: 0; + -ms-flex: 0 0 86px; + flex: 0 0 86px; + text-align: right; + display: inline; +} + +.mosh .sbt-deckplan{ + width: 100%; + height: auto; + border: 0; + + transition: 2s; +} + +.mosh .sbt-deckplan-parent{ + height: 185px; + overflow: auto; + transition: 2s; + border-radius: 10px; +} + +.mosh .sbt-deckplan-parent:hover { + z-index: 10000; + /* height: auto; */ +} + +.mosh .sbt-megadamage-menu { + padding: 15px; + /* font-size: 15px; */ +} + +.mosh .invert-title{ + mix-blend-mode: difference; +} + +.mosh .tab-select { + font-size: medium; + font-weight: bold; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + color: white; + text-align: center; +} + +.mosh .tab-select.active { + text-decoration: underline; + text-shadow: 0 0 10px white; +} + +/* .mosh .tab-select.active::before { + font-family: "Font Awesome 6 Pro"; + content: "\f0da"; + color:rgb(255, 113, 113); + position: relative; + right: 6px; + margin-left: -1rem; + display: inline-block; +} */ + +.mosh .stresstext { + width: 100%; + padding: 0.1rem; + color: white; + font-family: "Montserrat", "Arial Black", sans-serif; + font-size: 0.75rem; + font-weight: bold; + text-align: left; + text-transform: uppercase; +} + +.mosh .smallcircle-input { + margin: -0.15em; + height: 40px; + width: 40px; + padding: 0; + border: 4px solid #111; + border-radius: 3em; + font-size: 1rem; + font-weight: bold; + text-align: center; +} + +.mosh .mainstatmod-input { + height: 26px; + width: 28px; + /* padding: 0; */ + border: 0; + border-radius: 7.7em; + color: rgb(151, 100, 100); + font-size: 0.85rem; + font-weight: bold; + text-align: center; + margin-left: -22px; + z-index: 5; + background: white; + top: 8px; + left: 13px; + position: relative; + background: lightgrey; +} + +.mosh .mainsavemod-input { + height: 26px; + width: 28px; + /* padding: 0; */ + border: 0; + border-radius: 0.5em; + color: #11161b; + font-size: 0.85rem; + font-weight: bold; + text-align: center; + margin-left: -22px; + z-index: 5; + background: white; + top: 7px; + left: 13px; + position: relative; + background: lightgrey; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.mosh .mainstatmod-title { + position: relative; + color: lightgrey; + font-size: 1rem; + line-height: 1; + text-transform: uppercase; + margin-left: -38px; + pointer-events: none; + top: 13px; + left: 12px; +} + +.mosh .maxhealth-input { + margin: auto; + border: 0px solid #111; + font-size: 1.5rem; + font-weight: bold; + text-align: center; + background: transparent; +} + +.mosh .greyText{ + color: grey; +} + +.mosh .darkGreyText{ + color: rgb(56, 56, 56); +} + +.mosh .whiteText{ + color: white; +} + +.mosh .highlightText{ + color: orangered; +} + +.mosh .sizelarge{ + font-size: 1.1rem; +} + +.mosh .valuewrapper{ + grid-column: 1/-1; + display: grid; + align-items: start; + height: 40px; + padding: 0; + border: 3px solid #111; + border-radius: 1.5em; + background: 0; +} + +.mosh .textvaluewrapper{ + grid-column: 1/-1; + display: grid; + align-items: start; + height: 40px; + padding: 0; + border: 3px solid #111; + border-radius: 0.5em; + background: 0; +} + +.mosh .textvaluewrapper-input{ + margin: auto; + border: 0px solid #111; + font-size: 1rem; + font-weight: bold; + text-align: center; + background: transparent; +} + +.mosh .armorWrapper{ + grid-column: 1/-1; + display: grid; + align-items: start; + height: 40px; + padding: 0; + border: 2px solid #111; + border-radius: 0.3em; + background: black; + width: 100%; +} + +.mosh .blankstat{ + grid-template-rows: 0.3fr 1.1fr 0.4fr; + justify-self: center; + display: grid; + justify-items: center; +} + +.mosh .minmaxtopstat{ + grid-template-columns: 1fr 1fr; + grid-template-rows: auto 44px auto; + row-gap: 4px; + justify-self: center; + display: grid; + justify-items: center; + align-items: center; + width: 100%; + min-width: 0; +} + +.mosh .minmaxwrapper{ + grid-column: 1/-1; + display: grid; + grid-template-columns: 1fr 1px 1fr; + align-items: stretch; + height: 40px; + width: 100%; + min-width: 0; + padding: 0; + border: 3px solid #111; + border-radius: 1.5em; + background: white; + overflow: hidden; + box-sizing: border-box; +} + +.mosh .minmaxwrapper-black{ + grid-column: 1/-1; + display: grid; + grid-template-columns: 1fr 1px 1fr; + align-items: start; + height: 40px; + padding: 0; + border: 3px solid #111; + border-radius: 1.5em; + background: 0; + color: white; +} + +.mosh .minmaxtext{ + text-align: left; + grid-column: 1/-1; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ + font-size: 1rem; + font-weight: bold; + line-height: 1; + text-align: center; + text-transform: uppercase; +} + +.mosh .slant{ + border-right: 2px solid #111; + height: 100%; + transform: skewX(-15deg); +} + +.mosh .healthmaxtext{ + grid-column: span 1; + font-size: 0.7rem; + font-weight: bold; + line-height: 1; + text-align: center; + margin-top: 0; +} + +.mosh .stresslabel { + border-top-left-radius: 2em; + border-bottom-left-radius: 2em; + background: #111; + padding: 0 0.5rem; +} + +.mosh .mainstatwrapper { + display: flex; + width: 95%; +} + +.mosh .mainstat { + position: relative; + display: grid; + grid-template-columns: 1fr 5em; + align-items: center; + gap: 0; + width: 98%; +} + +.mosh .circle-statwrapper { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + background: #e3e3e3; + border-radius: 15px; + padding: 9px 0px; + flex-direction: column; +} + +.mosh .circle-statwrapper-horizontal { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + background: #e3e3e3; + border-radius: 15px; + padding: 9px 0px; + flex-direction:row; +} + +.mosh .circle-statwrapper-vertical { + display: flex; + width: 100%; + align-items: center; + justify-content: center; + background: #e3e3e3; + border-radius: 15px; + padding: 9px 0px; + flex-direction: column; +} + +.mosh .transparentBackground { + background: transparent; +} + +.mosh .section-vertical-flex { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + + +.mosh .circle-stat { + margin-top: 10px; + /* width: 98%; */ +} + +.mosh .creature-mainstat { + position: relative; + display: grid; + grid-template-columns: 1fr 3em; + align-items: center; + gap: 0; + width: 100%; +} +.mosh .mainstatlabel { + border-top-left-radius: 2em; + border-bottom-left-radius: 2em; + background: #111; + padding: 5px 0.5rem; + left: 5px; + position: relative; + height: 35px; +} + +.mosh .mainstattext { + width: 100%; + padding: 0.5rem; + color: white; + /* font-family: "Montserrat", "Arial Black", sans-serif; */ + font-size: 1.3rem; + font-weight: bold; + text-align: left; + text-transform: uppercase; +} + + +.mosh .area-title { + width: 100%; + font-size: 1.0rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; + /* margin-bottom: 7px; */ + color: #363636; + font-family: 'Roboto'; +} + +.mosh .circlestatlabel { + padding: 6px; + text-align: center; +} + +.mosh .circlestattitle { + width: 100%; + font-size: 1.0rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; + /* margin-bottom: 7px; */ + color: grey; +} + +.mosh .black { + color: black; +} + +.mosh .grey { + color: grey; +} + +.mosh .circlestattext { + width: 100%; + font-size: 0.9rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; +} + +.mosh .circle-input { + margin: -0.15em; + height: 50px; + width: 50px; + padding: 0; + border: 3px solid #111; + border-radius: 3em; + font-size: 1.5rem; + font-weight: bold; + text-align: center; + background: white; + z-index: 5; +} + +.mosh .box1 { + display: none; +} + +.mosh .box2 { + color: green; + display: block; + display: flex; + align-items: center; + justify-content: center; +} + +.mosh .circle-input-swapper { + width: auto; + display: inline-block; +} + +.mosh .circle-input-swapper:enabled .box1 { + display: block; +} + +.mosh .circle-input-swapper:enabled .box2 { + display: none; +} + +.mosh .textarea-input { + font-family: "Roboto", sans-serif; + margin: -0.15em; + /* padding: 9px; */ + border: 2px solid #111; + border-radius: 15px; + font-size: 11pt; + color: white; + font-weight: 500; + background: #111; + resize: none; + min-height: 0; + overflow: hidden; +} + +.mosh .textarea-input-grey { + font-family: "Roboto", sans-serif; + border: 0; + border-radius: 0.8em; + font-size: 11pt; + font-weight: 500; + resize: none; + min-height: 0; + overflow: hidden; + text-align: center; +} + + +.mosh .square-input { + margin: -0.15em; + height: 42px; + width: 45px; + padding: 0; + border: 4px solid #111; + background-color: #fff; + border-radius: 0.5em; + font-size: 1.1rem; + font-weight: bold; + text-align: center; +} + +.mosh .armor-mod { + margin: 3px; + height: 24px; + width: 28px; + /* padding: 0; */ + border: 3px solid #111; + background-color: #111; + border-radius: 0.6em; + font-size: 0.9rem; + font-weight: bold; + text-align: center; + position: relative; + color: white; + top: -2px; + right: -19px; +} + +.mosh .savetext { + display: block; + margin-bottom: .2em; + width: 100%; + color: white; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + font-size: 0.8rem; + font-weight: bold; + text-align: center; + text-transform: uppercase; +} + +.mosh .savebackground { + border-radius: 10px; + background: #111; + padding-bottom: 0.3rem; + padding-top: 0.4rem; + height: 225px; +} + +.mosh .header { + grid-area: header; + background-color: #000; + display: grid; + grid-template-columns: 0.25fr 1fr; + /* gap: 1.25rem; */ + align-items: center; + grid-column: 1/-1; + background: #111; + color: white; + font-family: "Montserrat", "Arial Black", sans-serif; + font-weight: bold; + text-transform: uppercase; + border-radius: 15px; +} + +.mosh .padding{ + padding: 5px; +} + +.mosh .actor-sidebar-tab{ + border-radius: 0 10px 10px 0; + /* z-index: -1; */ + box-shadow: 0 0 22px -6px; + border: 2px solid; + writing-mode: vertical-rl; + rotate: 180deg; + opacity: 0.5; +} + +.mosh .actor-sidebar-tab:hover{ + opacity: 1; +} + +.mosh .actor-sidebar-row{ + position: absolute; + display: flex; + flex-direction: column; + left: -20px; + top: 30px; + z-index: -1; + /* transition: 0.3s; */ + padding-left: 10px; +} + +.mosh .actor-sidebar-row:hover{ + left: -48px; +} + +.mosh .creature-header-grid { + display: grid; + grid-template-areas: + 'name header header' + 'line line line'; + background: #111; + +} + + +.mosh .creature-header { + display: flex ; + flex-direction: row-reverse; + align-items: center; + color: white; + font-family: "Montserrat", "Arial Black", sans-serif; + font-weight: bold; + text-transform: uppercase; + grid-area: header; + padding: 8px; +} + +.mosh .creature-description-grid{ + display: grid; + grid-template-columns: 1fr 15em; +} + +.mosh .creature-abilities{ + background: rgb(22, 22, 22); + margin: 12px; + border: 2px solid white; + outline: 5px solid rgb(22, 22, 22); + overflow: auto; + height: 375px; + border-radius: 10px; +} + +.mosh .ship-stats-grid{ + display: grid; + grid-template-columns: 17em 1fr 18em; +} + +.mosh .ship-sbt-stats-grid{ + display: grid; + grid-template-columns: 10em 1fr 16em; + gap: 10px; +} + +.mosh .sbt-crew-section{ + margin: 0px; + border: 2px solid white; + outline: 3px solid rgb(22, 22, 22); + overflow: auto; + height: 400px; + border-radius: 10px; + padding: 4px 6px; +} + +.mosh .sbt-text-area{ + font-family: "Roboto", sans-serif; + margin: -0.15em; + border: 2px solid #c5c5c5; + border-radius: 15px; + font-size: 11pt; + font-weight: bold; + background: #fff; + resize: none; + min-height: 0; + overflow: hidden; +} + +.mosh .sbt-megadamage{ + /* position: absolute; */ + /* left: 0; */ + /* background: white; + left: -300px; + width: 300px; + padding: 20px; + border-radius: 10px 0 0 10px; + height: 600px; + overflow-y: auto; + z-index: -1; */ + + position: absolute; + background: white; + left: -310px; + width: 300px; + padding: 20px; + border-radius: 10px; + z-index: -2; + transition: 1s; + height: auto; + overflow: hidden; +} + +.mosh .sbt-megadamage-open{ + left: -310px; + height: auto; +} + +.mosh .sbt-megadamage-closed{ + left: 0; + height: 0%; +} + +.mosh .sbt-crew-name { + text-align: center; + font-size: 1rem; + /* text-transform: uppercase; */ + color:black; + font-weight: bold; +} + +.mosh .sbt-crew-job { + height: auto; + font-size: 0.9rem; + color:rgb(129, 129, 129); + font-weight: bold; + font-style: italic; + text-align: center; +} + +.mosh .item-armor-grid { + display: grid; + grid-template-columns: 1fr 12em; + gap: 10px; +} + +.mosh .whiteline { + border-top: 3px solid white; + grid-area: line; + margin-top: 5px; + margin-bottom: 10px; + margin-left: 15px; + margin-right: 15px; +} + +.mosh .blackline { + border-top: 3px solid black; + grid-area: line; + margin-bottom: 5px; + margin-left: 15px; + margin-right: 15px; + margin-top: 5px; +} + +.mosh .greyline { + border-top: 3px solid grey; + grid-area: line; + margin-top: 5px; + margin-bottom: 10px; + margin-left: 15px; + margin-right: 15px; +} + +.mosh .headerinputfield { + margin: 0; + height: auto; + width: 100%; + padding-left: 0; + padding-right: 0; + border: 2px solid #111; + background-color: #fff; + border-radius: 3em; + font-size: 1rem; + margin-right: 0; + min-width: 0; + overflow: hidden; + box-sizing: border-box; + display: flex; + align-items: center; + min-height: 2.1rem; +} + +.mosh .sla-header-input, +.mosh .header-field { + min-width: 0; +} + +.mosh .creaturename { + height: auto; + width: 100%; + padding-left: 13px; + font-size: 1.3rem; + font-weight: bold; + color:white; + text-transform: uppercase; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; +} + +.mosh .creaturestat { + margin-left: 4px; + height: auto; + font-size: 0.9rem; + text-transform: uppercase; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; + color:white; +} + +.mosh .creaturedescription { + height: 400px; + padding: 10px; + overflow-y: auto; +} +.mosh .creaturedescription .editor-content{ + overflow-y: visible; +} +.mosh .creaturedescription .editor{ + overflow: visible; +} + +.mosh .creature-ability-container { + padding: 4px; + margin-left: 2px; +} + +.mosh .creature-ability-title { + text-align: center; + font-size: 0.9rem; + text-transform: uppercase; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; + color:white; + font-weight: bold; +} + +.mosh .creature-ability-text { + height: auto; + font-size: 0.8rem; + font-family: "Century Gothic", "Diadact Gothic", sans-serif; + color:white; +} + +.mosh .tox.tox-tinymce { + min-height: 100%; +} +.mosh .editor { + height: 100%; +} + +.noborder { + border: 0 !important; + background: 0 !important; +} + +.mosh .headerinputtext { + padding: 0.1rem; + color: white; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.95rem; + font-weight: bold; + text-align: left; + text-transform: uppercase; + margin-right: 10px; + margin-top: 3px; +} + +.mosh .headergrid { + display: grid; + grid-template-columns: 1.2fr 1.2fr 1.1fr 0.95fr 1fr 1fr 1fr; + grid-template-rows: auto auto auto; + gap: 0.35rem 0.5rem; + padding: 1.45em 1em 1em; + /* margin-top: -11px; */ + align-items: end; +} + +.mosh .sla-sheet-wordmark { + grid-column: 1 / -1; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 1.85rem; + font-weight: 700; + letter-spacing: 0.12em; + line-height: 0.95; + text-transform: uppercase; + color: rgba(255, 255, 255, 0.92); + text-align: center; + margin-bottom: 0.35rem; + text-shadow: 0 0 10px rgba(208, 94, 26, 0.18); +} + +.mosh.sheet.actor.character .window-header .header-button.configure-actor, +.mosh.sheet.actor.character .window-header .header-button.sheet-theme-toggle { + min-width: 30px; + padding: 0 6px; + font-size: 0; +} + +.mosh.sheet.actor.character .window-header .header-button.configure-actor span, +.mosh.sheet.actor.character .window-header .header-button.sheet-theme-toggle span { + display: none; +} + +.mosh.sheet.actor.character .window-header .header-button.configure-actor i, +.mosh.sheet.actor.character .window-header .header-button.sheet-theme-toggle i { + margin: 0; + font-size: 0.9rem; +} + +.mosh .headerinputfield input, +.mosh .charname input { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; + letter-spacing: 0.01em; + min-width: 0; + width: 100%; + box-sizing: border-box; + display: block; + padding: 0 14px; + line-height: 1.1; + height: 100%; + border-radius: 999px !important; + border: 0 !important; + background: transparent !important; + outline: none; + appearance: none; + -webkit-appearance: none; +} + +.mosh .headernamegrid, +.mosh .header-field-name { + grid-column: 1 / span 3; + grid-row: 2; +} + +.mosh .header-field-credits { + grid-column: 4; + grid-row: 3; +} + +.mosh .header-field-lad { + grid-column: 1 / span 3; + grid-row: 3; + align-self: start; +} + +.mosh .header-field-class { + grid-column: 4 / span 2; + grid-row: 2; +} + +.mosh .header-field-race { + grid-column: 6 / span 2; + grid-row: 2; +} + +.mosh .header-field-sla-rank { + grid-column: 5; + grid-row: 3; +} + +.mosh .header-field-height { + grid-column: 6; + grid-row: 3; +} + +.mosh .header-field-weight { + grid-column: 7; + grid-row: 3; +} + +.mosh .sla-header-checkbox { + display: inline-flex; + align-items: center; + gap: 0.45rem; + min-height: 2rem; + padding: 0.25rem 0.9rem; + border: 2px solid #111; + border-radius: 999px; + background: #fff; + color: #111; + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; + cursor: pointer; + box-sizing: border-box; +} + +.mosh .sla-header-checkbox input[type="checkbox"] { + margin: 0; + width: 1rem; + height: 1rem; + accent-color: #c99d23; + cursor: pointer; +} + +.mosh .sla-header-checkbox span { + line-height: 1; + white-space: nowrap; +} + +.mosh .header-field-compact .headerinputfield { + min-height: 34px; + padding-left: 0; +} + +.mosh .header-field-compact .headerinputfield input { + font-size: 0.9rem; +} + +.mosh .header-field-compact .headerinputtext { + font-size: 0.82rem; +} + +.mosh .headerrankgrid { + /* grid-column: span 3; */ + display: inline-flex; +} + +.mosh .circle{ + color: rgb(22, 22, 22); + background: white; + border-radius: 10px; + /* border: 2px solid black; */ + width: 15px; + height: 15px; +} + +.mosh .circle-f{ /*Filled circle*/ + color: rgb(22, 22, 22); + background: rgb(100, 100, 100); + border-radius: 10px; + /* border: 2px solid black; */ + width: 15px; + height: 15px; +} + +.mosh .profile { + width: 140px; + height: auto; + padding: 6px; + border-radius: 10px; + border: 0; +} + +.mosh .rollcontainer { + border-radius: 10em; + background: #fff; + padding: 0 0.5rem; + padding-bottom: 0.1rem; + width: 100%; + border: 2px solid #111; + border-radius: 0em 0em 0em 0em; + font-family: "Josefin Sans", "Roboto", sans-serif; +} + +.mosh .sla-roll-outcome, +.mosh .sla-roll-result .dice-total { + transition: color 120ms ease, border-color 120ms ease, box-shadow 120ms ease; +} + +.mosh .sla-roll-outcome.sla-crit-success, +.mosh .sla-roll-result .dice-total.sla-crit-success { + color: #0f5c2e; + background: rgba(15, 92, 46, 0.08); +} + +.mosh .sla-roll-outcome.sla-crit-failure, +.mosh .sla-roll-result .dice-total.sla-crit-failure { + color: #8d1f18; + background: rgba(141, 31, 24, 0.08); +} + +.mosh .sla-roll-result.sla-crit-success .dice-total { + border-color: #0f5c2e; + box-shadow: 0 0 0 2px rgba(15, 92, 46, 0.18); +} + +.mosh .sla-roll-result.sla-crit-failure .dice-total { + border-color: #8d1f18; + box-shadow: 0 0 0 2px rgba(141, 31, 24, 0.18); +} + +.mosh .rollh1 { + width: 107%; + margin-top: 0; + margin-left: -9px; + font-size: 1.2rem; + font-weight: bold; + text-transform: uppercase; + background: #111; + color: white; + /* border-bottom-right-radius: 0.5em; */ + padding: 5px; +} + +.mosh .rollweaponh1 { + min-height: 32px; + height: auto; + margin-top: -15px; + margin-left: -8px; + margin-right: -11px; + font-size: 1.02rem; + font-weight: bold; + text-transform: uppercase; + background: #111; + /* border-bottom-right-radius: 1.5em; */ + color: white; + padding: 5px; + flex: auto; + width: 70%; + display: flex; + align-items: center; + line-height: 1.05; + white-space: normal; + word-break: break-word; + font-family: "Josefin Sans", "Roboto", sans-serif; + letter-spacing: 0.08em; +} + +.mosh .rollh2 { + font-size: 1.1rem; + font-weight: normal; + text-transform: uppercase; + line-height: 1; + text-align: center; + margin-top: 4px; + padding: 5px; +} + +.mosh .rollmods { + font-size: 0.8rem; + font-weight: normal; + text-transform: uppercase; + /* line-height: 1; */ + text-align: center; + margin-top: -8px; + margin-bottom: 3px; + padding: 5px; + color: grey; +} + +.mosh .rollattribute { + width: 100%; + padding: 0.5rem; + color: black; + /* font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; */ + font-size: 0.9rem; + text-align: center; +} + +.mosh .roll-grid { + box-sizing: border-box; + display: grid; + grid-template-columns: repeat(4, 1fr); + align-items: center; + width: 100%; +} + +.mosh .roll-result { + padding: 8px; + border: 2px solid #111; + border-radius: 1em; + font-size: 1.5rem; + font-weight: bold; + text-align: center; + grid-column: 2/span 2; +} + + +.mosh .roll-target { + box-sizing: border-box; + display: grid; + grid-template-columns: 1fr 6rem; + align-items: center; + gap: 2.5rem; + padding: 0.8rem; + font-size: 0.9rem; + background: white; + border-radius: 1.5rem; + color: #111; + + font-family: "Montserrat", "Arial Black", sans-serif; + font-weight: bold; + text-transform: uppercase; + text-align: right; +} + +.mosh .roll-targetbox { + padding: 2px; + border: 2px solid #111; + border-radius: 0.3em; + font-size: 0.9rem; + font-weight: bold; + text-align: center; + margin-right: 0px; +} + +.mosh .roll-damage { + font-size: 0.9rem; + line-height: 1; + text-align: center; + margin-top: 4px; + padding: 5px; + color: rgb(117, 0, 0); + font-weight: normal; + text-transform: uppercase; + font-family: "Montserrat", "Arial Black", sans-serif; +} + +.mosh .roll-damagebox { + padding: 4px; + border: 2px solid rgb(117, 0, 0); + border-radius: 1em; + font-size: 1.2rem; + font-weight: bold; + text-align: center; + grid-column: 2/span 2; + color: rgb(117, 0, 0); + width: 70px; + margin: auto; +} + +.mosh .items-tab-grid{ + grid-template-columns: 50% 50%; +} +.mosh form.actor-generator div.fulllabel { + border-radius: 2em; +} +.mosh form.actor-generator div.ulinputfield { + min-height: 150px; +} +.mosh form.actor-generator .smalltext { + font-size: 0.7rem; +} +.mosh form.actor-generator div#generator-header-grid-1col { + grid-column: span 1/span 1; + grid-template-columns: repeat(1, minmax(0, 1fr)); +} +.mosh form.actor-generator .element-group { + margin-top: 10px; +} +.mosh form.actor-generator .credit-img { + height: 30px; + margin-top: 0%; +} +.mosh form.actor-generator .checkbox-round { + appearance: none; +} +.mosh form.actor-generator .checkbox-round:checked { + background-color: gray; +} +.mosh form.actor-generator .clicable-item { + cursor: pointer; +} +.mosh .characterGeneratorSkillPopup { + margin-bottom: 10px; +} +.mosh .characterGeneratorSkillPopup .skillpopupDescription { + text-align: center; + font-weight: bold; + padding-bottom: 0.2em; +} + +.mosh .characterGeneratorSkillPopup .center { + text-align: center; +} + +/* Dialog V2 - Macro Pop Ups */ + +/* Base dialog styling */ +.application.dialog.macro-popup-dialog { + background: rgb(255,255,255); + font-family: "Roboto", sans-serif; + color: #1A1915; +} + +/* Adjust dialog content gap */ +.macro-popup-dialog .dialog-content.standard-form { + gap: .5rem; +} + +/* Adjust dialog form gap */ +.macro-popup-dialog .dialog-form.standard-form { + gap: .5rem; +} + +/* MPD window header */ +.macro-popup-dialog .window-header { + background: rgb(25,25,25); +} + +/* MPD window content */ +.macro-popup-dialog .window-content { + padding: 10px; +} + +/* MPD macro window */ +.macro-popup-dialog .macro_window { + background: rgb(230,230,230); + border-radius: 9px; +} + +/* MPD macro image */ +.macro-popup-dialog .macro_img { + +} + +/* MPD macro desc */ +.macro-popup-dialog .macro_desc { + font-family: "Roboto", sans-serif; + font-size: 10.5pt; + font-weight: 400; + padding-top: 8px; + padding-left: 0px; + padding-right: 8px; + padding-bottom: 8px; +} + +/* MPD macro desc — title styling */ +.macro-popup-dialog .macro_desc h4 { + font-family: "Roboto", sans-serif; + font-size: 14pt; + font-weight: 400; + color: #1A1915; + border-bottom: 1px solid darkred; + margin-bottom: 8px; +} + +/* MPD macro prompt */ +.macro-popup-dialog .macro_prompt { + +} + +/* MPD grid layouts */ +.macro-popup-dialog .grid-1col { + grid-column: span 1 / span 1; + grid-template-columns: repeat(1, minmax(0, 1fr)); +} + +.macro-popup-dialog .grid-2col { + display: grid; + grid-column: span 2 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 2px; + padding: 0; +} + +.macro-popup-dialog .grid-3col { + grid-column: span 3 / span 3; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +/* update buttons to look more old school */ +.macro-popup-dialog .form-footer button { + background: rgb(230,230,230); + color: #1A1915; + border: 1px solid #222; + border-radius: 4px; + padding: 4px 10px; + font-size: 11pt; + font-weight: 500; + display: flex; + align-items: center; + gap: 6px; +} + +.macro-popup-dialog .form-footer button:hover { + background: #444; + color: #fff; + border-color: #111; +} + +/* Custom radio: kill native + theme accents */ +.macro-popup-dialog input[type="radio"] { + appearance: none; + -webkit-appearance: none; + accent-color: initial; /* ignore theme accent */ + box-sizing: border-box; + width: 16px; + height: 16px; + border: 2px solid #777; /* medium grey ring */ + border-radius: 50%; + background: #fff; /* white center when unchecked */ + display: inline-flex; /* center the pseudo-dot */ + align-items: center; + justify-content: center; + line-height: 0; + margin: 0 8px 0 2px; + vertical-align: middle; + + /* nuke any theme glow/orange */ + box-shadow: none !important; + outline: none; +} + +/* The inner dot (hidden until checked) */ +.macro-popup-dialog input[type="radio"]::before { + content: ""; + width: 8px; + height: 8px; + border-radius: 50%; + background: #111; /* dot color */ + transform: scale(0); + transition: transform 120ms ease-in-out; +} + +/* Checked = show the dot */ +.macro-popup-dialog input[type="radio"]:checked::before { + transform: scale(1); +} + +/* Checked = show the dot */ +.macro-popup-dialog input[type="radio"]:checked::after { + color: none !important; + width: 8px; + height: 8px; + border-radius: 50%; + transform: scale(0); + background: #ffffff; +} + +/* Hover/focus states (accessible, non-orange) */ +.macro-popup-dialog input[type="radio"]:hover { border-color: #5c5c5c; } +.macro-popup-dialog input[type="radio"]:focus-visible { + outline: 2px solid #9a9a9a; + outline-offset: 2px; +} + +/* If your theme highlights the whole row via :has(input:checked), strip it here */ +.macro-popup-dialog label:has(input[type="radio"]:checked) { + background: inherit !important; + box-shadow: none !important; +} + +.mosh .sla-panel { + margin-bottom: 14px; + padding: 12px; + border: 1px solid #18232e; + background: + linear-gradient(135deg, rgba(14, 26, 35, 0.96), rgba(34, 50, 64, 0.92)), + radial-gradient(circle at top right, rgba(224, 188, 84, 0.18), transparent 35%); + color: #f1f3f5; + border-radius: 10px; +} + +.mosh .sla-banner { + display: flex; + justify-content: space-between; + gap: 12px; + align-items: flex-start; + margin-bottom: 12px; +} + +.mosh .sla-kicker, +.mosh .sla-card-label, +.mosh .sla-chat-title, +.mosh.sla-chat-card .sla-chat-title { + font-family: "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.12em; + font-size: 0.72rem; + font-weight: 700; +} + +.mosh .sla-title, +.mosh .sla-card-title { + font-family: "Josefin Sans", "Roboto", sans-serif; + font-size: 1.2rem; + line-height: 1.2; + font-weight: 700; +} + +.mosh .sla-tags, +.mosh .sla-tag-row, +.mosh .sla-note-list, +.mosh .sla-action-row { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.mosh .sla-tag, +.mosh .sla-note-pill { + display: inline-flex; + align-items: center; + padding: 4px 8px; + border-radius: 999px; + border: 1px solid rgba(17, 17, 17, 0.16); + background: rgba(17, 17, 17, 0.06); + color: #14181c; + font-size: 0.74rem; +} + +.mosh .sla-note-pill-wide { + width: 100%; + justify-content: flex-start; + border-radius: 12px; +} + +.mosh .sla-card-grid { + gap: 12px; + margin-bottom: 12px; +} + +.mosh .sla-card-label, +.mosh .sla-card-title { + color: #14181c; +} + +.mosh .sla-panel .sla-card, +.mosh .tab[data-tab="ebb"] .sla-card { + background: rgba(255, 255, 255, 0.08); + border: 1px solid rgba(255, 255, 255, 0.12); + color: #edf1f4; + backdrop-filter: blur(4px); + box-shadow: none; +} + +.mosh .sla-panel .sla-card-copy, +.mosh .tab[data-tab="ebb"] .sla-card-copy, +.mosh .sla-panel .sla-card-label, +.mosh .tab[data-tab="ebb"] .sla-card-label, +.mosh .sla-panel .sla-card-title, +.mosh .tab[data-tab="ebb"] .sla-card-title { + color: rgba(245, 247, 250, 0.9); +} + +.mosh .sla-panel .sla-tag, +.mosh .sla-panel .sla-note-pill, +.mosh .tab[data-tab="ebb"] .sla-tag, +.mosh .tab[data-tab="ebb"] .sla-note-pill { + border-color: rgba(255, 255, 255, 0.14); + background: rgba(255, 255, 255, 0.08); + color: #f4f6f8; +} + +.mosh .sla-card { + padding: 12px; + border-radius: 10px; + background: #f4efe6; + border: 1px solid rgba(17, 17, 17, 0.14); + color: #14181c; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45); +} + +.mosh .sla-card-copy, +.mosh .sla-chat-copy, +.mosh.sla-chat-card .sla-chat-copy { + margin-top: 6px; + line-height: 1.45; + color: #2d3338; +} + +.mosh .tab[data-tab="skills"] .sla-card, +.mosh .tab[data-tab="weapons"] .sla-card, +.mosh .tab[data-tab="items"] .sla-card, +.mosh .tab[data-tab="traits"] .sla-card { + background: #f3ede3 !important; + color: #18130f !important; + border: 1px solid rgba(24, 19, 15, 0.14); +} + +.mosh .tab[data-tab="skills"] .sla-card-label, +.mosh .tab[data-tab="weapons"] .sla-card-label, +.mosh .tab[data-tab="items"] .sla-card-label, +.mosh .tab[data-tab="traits"] .sla-card-label, +.mosh .tab[data-tab="skills"] .sla-card-title, +.mosh .tab[data-tab="weapons"] .sla-card-title, +.mosh .tab[data-tab="items"] .sla-card-title, +.mosh .tab[data-tab="traits"] .sla-card-title, +.mosh .tab[data-tab="skills"] .sla-card-copy, +.mosh .tab[data-tab="weapons"] .sla-card-copy, +.mosh .tab[data-tab="items"] .sla-card-copy, +.mosh .tab[data-tab="traits"] .sla-card-copy { + color: #18130f !important; +} + +.mosh .sla-flux-meter { + margin-top: 10px; + height: 10px; + border-radius: 999px; + overflow: hidden; + background: rgba(255, 255, 255, 0.1); + border: 1px solid rgba(255, 255, 255, 0.12); +} + +.mosh .sla-flux-meter-fill { + height: 100%; + border-radius: inherit; + background: linear-gradient(90deg, rgba(81, 163, 109, 0.9), rgba(203, 161, 68, 0.92)); +} + +.mosh .sla-flux-meter-fill.frayed { + background: linear-gradient(90deg, rgba(203, 161, 68, 0.92), rgba(194, 112, 55, 0.96)); +} + +.mosh .sla-flux-meter-fill.breach, +.mosh .sla-flux-meter-fill.catastrophic { + background: linear-gradient(90deg, rgba(194, 112, 55, 0.96), rgba(161, 59, 59, 0.96)); +} + +.mosh .sla-flux-stage { + display: inline-flex; + margin-top: 8px; + padding: 5px 10px; + border-radius: 999px; + font-family: "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.08em; + font-weight: 700; +} + +.mosh .sla-flux-stage.stable { background: rgba(81, 163, 109, 0.25); color: #dff7e7; } +.mosh .sla-flux-stage.charged { background: rgba(203, 161, 68, 0.25); color: #fff2c8; } +.mosh .sla-flux-stage.frayed { background: rgba(194, 112, 55, 0.28); color: #ffe2cc; } +.mosh .sla-flux-stage.breach { background: rgba(161, 59, 59, 0.32); color: #ffd7d7; } +.mosh .sla-flux-stage.catastrophic { background: rgba(99, 31, 31, 0.5); color: #fff0f0; } + +.mosh .sla-action-row button, +.mosh .sla-generator button, +.mosh .sla-world-tools button { + border: 1px solid rgba(255, 255, 255, 0.12); + background: linear-gradient(180deg, #f0c24b, #b88619); + color: #10171d; + font-family: "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 700; + flex: 0 0 auto; + width: auto; + min-width: 0; + padding: 6px 10px; + line-height: 1.1; +} + +.mosh .sla-action-row button:hover, +.mosh .sla-generator button:hover, +.mosh .sla-world-tools button:hover { + box-shadow: 0 0 0 1px rgba(255,255,255,0.12), 0 4px 18px rgba(240, 194, 75, 0.28); +} + +.mosh .sla-rule-list { + display: grid; + gap: 8px; + margin-top: 10px; +} + +.mosh .sla-rule-toggle { + display: grid; + grid-template-columns: 18px 1fr; + gap: 10px; + align-items: flex-start; + padding: 10px; + border-radius: 10px; + background: rgba(255, 255, 255, 0.06); + border: 1px solid rgba(255, 255, 255, 0.1); + cursor: pointer; +} + +.mosh .sla-rule-toggle input[type="checkbox"] { + cursor: pointer; +} + +.mosh .sla-rule-text { + display: grid; + gap: 4px; +} + +.mosh .sla-rule-title { + font-family: "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; + color: #f4f6f8; +} + +.mosh .sla-rule-summary { + color: rgba(245, 247, 250, 0.82); + line-height: 1.35; +} + +.mosh .sla-ability-list .item-header, +.mosh .sla-ability-list .item { + background: rgba(15, 20, 26, 0.92); + color: #edf1f4; +} + +.mosh .sla-ability-list .skill-stat, +.mosh .sla-ability-list .item-header .skill-stat, +.mosh .sla-ability-list .item-controls a, +.mosh .sla-ability-list .item-controls i { + color: #edf1f4; +} + +.mosh .sla-ability-list .item-controls a:hover, +.mosh .sla-ability-list .item-controls a:focus { + color: #f0c24b; +} + +.mosh .sla-chat-card, +.mosh.sla-chat-card { + padding: 10px; + border: 1px solid #1e2d39; + border-radius: 8px; + background: linear-gradient(180deg, rgba(17, 27, 36, 0.98), rgba(26, 40, 51, 0.98)); + color: #eff3f7; +} + +.mosh .sla-chat-card .sla-chat-copy, +.mosh.sla-chat-card .sla-chat-copy, +.mosh .sla-chat-card .sla-chat-title, +.mosh.sla-chat-card .sla-chat-title { + color: #eff3f7; +} + +.mosh .sla-sidebar-actions, +.directory-header .sla-sidebar-actions { + display: flex; + gap: 8px; + margin-top: 8px; + flex-wrap: wrap; +} + +.mosh .sla-sidebar-actions button, +.directory-header .sla-sidebar-actions button { + border: 1px solid rgba(224, 196, 160, 0.8); + background: rgba(15, 14, 24, 0.94); + color: #f6e5c8; + border-radius: 12px; + padding: 8px 12px; + font-family: "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; +} + +.mosh .weapon-ammo { + display: flex; + flex-direction: column; + gap: 2px; + align-items: center; + justify-content: center; + min-width: 110px; +} + +.mosh .sla-weapon-ammo-primary { + font-size: 0.8rem; + font-weight: 700; + line-height: 1.15; +} + +.mosh .sla-weapon-ammo-secondary { + font-size: 0.68rem; + color: #5d6670; + line-height: 1.1; +} + +.mosh .sla-save-action-strip { + display: flex; + gap: 6px; + justify-content: center; + margin-top: 8px; +} + +.mosh .sla-mainstat-action-strip { + display: flex; + justify-content: center; + margin-top: 10px; +} + +.mosh .sla-sheet-action { + border: 1px solid rgba(255, 255, 255, 0.14); + background: linear-gradient(180deg, #f0c24b, #b88619); + color: #10171d; + font-family: "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.05em; + font-weight: 700; + flex: 0 0 auto; + width: auto; + min-width: 86px; + padding: 6px 14px; + line-height: 1.1; + min-height: 34px; + border-radius: 999px; +} + +.mosh .sla-sheet-action:hover { + box-shadow: 0 0 0 1px rgba(255,255,255,0.12), 0 4px 18px rgba(240, 194, 75, 0.28); +} + +.mosh .sla-rule-readonly { + cursor: default; +} + +.mosh .sla-rule-readonly input[type="checkbox"] { + pointer-events: none; +} + +.mosh.sla-sheet-theme-legacy .sla-sheet-wordmark { + color: #faf5e8 !important; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.35); + letter-spacing: 0.12em; +} + +.mosh.sla-sheet-theme-legacy .header, +.mosh.sla-sheet-theme-legacy .header-fields { + background: linear-gradient(180deg, #2a140f, #110d0c) !important; +} + +.window-app.sla-window-theme-legacy .mosh .header, +.window-app.sla-window-theme-legacy .mosh .header-fields { + background: linear-gradient(180deg, #e8dcc7, #cbb392) !important; +} + +.mosh.sla-sheet-theme-legacy .sheet-tabs, +.mosh.sla-sheet-theme-legacy .tab-select, +.mosh.sla-sheet-theme-legacy .items-list .item-header { + background: #15110f !important; + color: #f3eee2 !important; +} + +.mosh.sla-sheet-theme-legacy .sla-panel, +.mosh.sla-sheet-theme-legacy .sla-card { + background: #ede3d2 !important; + color: #14181c !important; + box-shadow: 0 0 0 1px rgba(34, 20, 14, 0.18); +} + +.mosh.sla-sheet-theme-legacy .sla-card-copy, +.mosh.sla-sheet-theme-legacy .sla-card-label, +.mosh.sla-sheet-theme-legacy .sla-card-title, +.mosh.sla-sheet-theme-legacy .sla-tag, +.mosh.sla-sheet-theme-legacy .sla-note-pill, +.mosh.sla-sheet-theme-legacy .sla-rule-title, +.mosh.sla-sheet-theme-legacy .sla-rule-summary { + color: #14181c; +} + +.mosh.sla-sheet-theme-legacy .sla-panel .sla-card, +.mosh.sla-sheet-theme-legacy .tab[data-tab="ebb"] .sla-card { + background: #f2ede4; + border: 1px solid rgba(17, 17, 17, 0.14); + color: #14181c; +} + +.mosh.sla-sheet-theme-legacy .sla-panel .sla-card-copy, +.mosh.sla-sheet-theme-legacy .tab[data-tab="ebb"] .sla-card-copy, +.mosh.sla-sheet-theme-legacy .sla-panel .sla-card-label, +.mosh.sla-sheet-theme-legacy .tab[data-tab="ebb"] .sla-card-label, +.mosh.sla-sheet-theme-legacy .sla-panel .sla-card-title, +.mosh.sla-sheet-theme-legacy .tab[data-tab="ebb"] .sla-card-title, +.mosh.sla-sheet-theme-legacy .sla-panel .sla-tag, +.mosh.sla-sheet-theme-legacy .sla-panel .sla-note-pill, +.mosh.sla-sheet-theme-legacy .tab[data-tab="ebb"] .sla-tag, +.mosh.sla-sheet-theme-legacy .tab[data-tab="ebb"] .sla-note-pill { + color: #14181c; +} + +.mosh.sla-sheet-theme-legacy .sla-rule-toggle { + background: rgba(17, 17, 17, 0.04); + border-color: rgba(17, 17, 17, 0.14); +} + +.mosh.sla-sheet-theme-legacy, +.mosh.sla-sheet-theme-legacy .sheet-body, +.mosh.sla-sheet-theme-legacy .items-list, +.mosh.sla-sheet-theme-legacy .item.flexrow, +.mosh.sla-sheet-theme-legacy .tab { + background: #f5efe3 !important; + color: #17120f !important; +} + +.mosh.sla-sheet-theme-legacy .savebackground, +.mosh.sla-sheet-theme-legacy .health, +.mosh.sla-sheet-theme-legacy .abilities { + background: #efe4d3 !important; + border: 1px solid rgba(42, 20, 15, 0.22); + border-radius: 14px; +} + +.window-app.sla-window-theme-legacy .mosh .savebackground, +.window-app.sla-window-theme-legacy .mosh .health, +.window-app.sla-window-theme-legacy .mosh .abilities { + background: #efe4d3 !important; + border: 1px solid rgba(42, 20, 15, 0.22) !important; + border-radius: 14px; +} + +.mosh.sla-sheet-theme-legacy .resource.mainstat .mainstatlabel, +.mosh.sla-sheet-theme-legacy .savetext, +.mosh.sla-sheet-theme-legacy .item-header, +.mosh.sla-sheet-theme-legacy .sheet-tabs { + background: #1a1311 !important; + color: #f7efe1 !important; +} + +.mosh.sla-sheet-theme-legacy .sheet-tabs .tab-select:hover, +.mosh.sla-sheet-theme-legacy .sheet-tabs .tab-select.active { + background: linear-gradient(180deg, #d9c2a2, #b8925e) !important; + color: #1a140f !important; + box-shadow: 0 0 0 1px rgba(31, 20, 14, 0.28); +} + +.window-app.sla-window-theme-legacy .mosh, +.window-app.sla-window-theme-legacy .mosh .sheet-body, +.window-app.sla-window-theme-legacy .mosh .tab, +.window-app.sla-window-theme-legacy .mosh .items-list { + background: #f5efe3 !important; + color: #17120f !important; +} + +.window-app.sla-window-theme-legacy .mosh .sheet-tabs { + background: linear-gradient(90deg, rgba(228, 214, 190, 0.98), rgba(196, 167, 126, 0.98) 55%, rgba(228, 214, 190, 0.98)) !important; +} + +.window-app.sla-window-theme-legacy .mosh .sheet-tabs .tab-select { + color: #2b1e16 !important; +} + +.window-app.sla-window-theme-legacy .mosh .sheet-tabs .tab-select:hover, +.window-app.sla-window-theme-legacy .mosh .sheet-tabs .tab-select.active { + background: linear-gradient(180deg, #3b251b, #1f1510) !important; + color: #f6ebd9 !important; +} + +.window-app.sla-window-theme-legacy .mosh .header, +.window-app.sla-window-theme-legacy .mosh .header-fields { + background: linear-gradient(180deg, #e8dcc7, #cbb392) !important; +} + +.window-app.sla-window-theme-legacy .mosh .headerinputtext, +.window-app.sla-window-theme-legacy .mosh .headerinputfield input, +.window-app.sla-window-theme-legacy .mosh .charname input, +.window-app.sla-window-theme-legacy .mosh .sla-sheet-wordmark { + color: #2a1c14 !important; + text-shadow: none !important; +} + +.window-app.sla-window-theme-legacy .mosh .headerinputfield, +.window-app.sla-window-theme-legacy .mosh .minmaxwrapper, +.window-app.sla-window-theme-legacy .mosh .circle-input, +.window-app.sla-window-theme-legacy .mosh .square-input { + background: #fffaf1 !important; + border-color: rgba(42, 20, 15, 0.28) !important; +} + +.window-app.sla-window-theme-legacy .mosh .sla-header-checkbox { + background: #fffaf1 !important; + color: #17120f !important; + border-color: rgba(42, 20, 15, 0.28) !important; +} + +.window-app.sla-window-theme-legacy .mosh .mainstatlabel, +.window-app.sla-window-theme-legacy .mosh .stresslabel, +.window-app.sla-window-theme-legacy .mosh .items-list .item-header { + background: #2d1e17 !important; + color: #f6ebd9 !important; +} + +.window-app.sla-window-theme-legacy .mosh .mainstattext, +.window-app.sla-window-theme-legacy .mosh .savetext { + color: #f6ebd9 !important; +} + +.window-app.sla-window-theme-legacy .mosh .sla-carry-summary { + background: rgba(244, 236, 223, 0.96) !important; + color: #241913 !important; + border-color: rgba(42, 20, 15, 0.2) !important; +} + +.window-app.sla-window-theme-legacy .mosh .sla-carry-summary-title, +.window-app.sla-window-theme-legacy .mosh .sla-carry-summary-main, +.window-app.sla-window-theme-legacy .mosh .sla-carry-summary-meta { + color: #241913 !important; +} + +.mosh.sla-sheet-theme-legacy .circle-input, +.mosh.sla-sheet-theme-legacy .square-input, +.mosh.sla-sheet-theme-legacy .mainstatmod-input, +.mosh.sla-sheet-theme-legacy .mainsavemod-input, +.mosh.sla-sheet-theme-legacy .headerinputfield, +.mosh.sla-sheet-theme-legacy .headerinputfield input, +.mosh.sla-sheet-theme-legacy .maxhealth-input, +.mosh.sla-sheet-theme-legacy .sla-panel input, +.mosh.sla-sheet-theme-legacy .sla-panel textarea, +.mosh.sla-sheet-theme-legacy .sla-panel select { + background: #fffaf1 !important; + color: #17120f !important; + border-color: rgba(42, 20, 15, 0.28) !important; +} + +.mosh.sla-sheet-theme-legacy .sla-sheet-action { + background: linear-gradient(180deg, #d9c2a2, #b28a58) !important; + color: #1b140f !important; +} + +.window-app.sla-window-theme-legacy .mosh .health .resource-label, +.window-app.sla-window-theme-legacy .mosh .health .minmaxtext, +.window-app.sla-window-theme-legacy .mosh .health .healthmaxtext, +.window-app.sla-window-theme-legacy .mosh .health .area-title, +.window-app.sla-window-theme-legacy .mosh .health .faded-label, +.window-app.sla-window-theme-legacy .mosh .savebackground .resource-label, +.window-app.sla-window-theme-legacy .mosh .savebackground .savetext, +.window-app.sla-window-theme-legacy .mosh .abilities .resource-label, +.window-app.sla-window-theme-legacy .mosh .abilities .mainstatmod-title { + color: #2b1e16 !important; + text-shadow: none !important; +} + +.window-app.sla-window-theme-legacy .window-content, +.window-content.sla-window-theme-legacy { + background: linear-gradient(180deg, #eadfcd, #d8c2a1) !important; +} + +.window-app.sla-window-theme-modern .window-content, +.window-content.sla-window-theme-modern { + background: linear-gradient(180deg, #1a2430, #0d1218) !important; +} + +.window-app.sla-window-theme-legacy .window-header, +.window-content.sla-window-theme-legacy .window-header, +.window-app.sla-window-theme-legacy .window-title { + background: linear-gradient(180deg, #694833, #2f2118) !important; + color: #f4e8d2 !important; +} + +.window-app.sla-window-theme-modern .window-header, +.window-content.sla-window-theme-modern .window-header, +.window-app.sla-window-theme-modern .window-title { + background: linear-gradient(180deg, #243445, #121a23) !important; + color: #e8eff5 !important; +} + +.mosh .sla-generator .resource, +.mosh .sla-world-tools .resource { + padding: 8px; + border-radius: 8px; + background: rgba(18, 27, 36, 0.88); + color: #eff3f7; +} + +.mosh .sla-briefing-card { + min-height: 100%; +} + +.mosh.sla-generator .sla-card, +.mosh .sla-generator .sla-card { + background: #f4f2ec; + border: 1px solid #c8c1b4; + color: #161a1e; +} + +.mosh.sla-generator .sla-card-copy, +.mosh.sla-generator .sla-card-title, +.mosh.sla-generator .sla-card-label, +.mosh.sla-generator .sla-note-pill, +.mosh .sla-generator .sla-card-copy, +.mosh .sla-generator .sla-card-title, +.mosh .sla-generator .sla-card-label, +.mosh .sla-generator .sla-note-pill, +.mosh.sla-generator p, +.mosh .sla-generator p { + color: #161a1e; +} + +.mosh.sla-generator .sla-note-pill, +.mosh .sla-generator .sla-note-pill { + background: rgba(22, 26, 30, 0.08); + border-color: rgba(22, 26, 30, 0.16); +} + +.mosh.sla-generator .resource-label, +.mosh .sla-generator .resource-label, +.mosh.sla-generator label.checkbox, +.mosh .sla-generator label.checkbox, +.mosh.sla-generator [data-briefing], +.mosh .sla-generator [data-briefing] { + color: #14181c; +} + +.mosh .sla-generator input, +.mosh .sla-generator select, +.mosh .sla-world-tools input, +.mosh .sla-world-tools select { + background: rgba(255, 255, 255, 0.92); + color: #101417; +} + +.mosh .headerinputtext, +.mosh .headerinputfield input, +.mosh .charname input, +.mosh .mainstattext, +.mosh .resource-label, +.mosh .healthmaxtext, +.mosh .skill-stat, +.mosh .skill-name, +.mosh .sheet-tabs .tab-select, +.mosh .item-header, +.mosh .mainstatmod-title { + font-family: "Futura PT Cond Medium", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh .sheet-tabs .tab-select { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 34px; + padding: 0 12px; + margin: 0 2px; + border-radius: 999px; + text-transform: uppercase; + letter-spacing: 0.08em; + color: rgba(255, 255, 255, 0.82); + transition: background 120ms ease, color 120ms ease, box-shadow 120ms ease; +} + +.mosh .sheet-tabs .tab-select:hover, +.mosh .sheet-tabs .tab-select.active { + background: linear-gradient(180deg, #f2eee7, #d9d0c5); + color: #151515; + box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.18); +} + +.mosh .sla-panel input, +.mosh .sla-panel select { + background: rgba(34, 43, 51, 0.92); + color: #f2f5f7; + border: 1px solid rgba(212, 190, 148, 0.42); +} + +.mosh .sla-panel input::placeholder, +.mosh .sla-panel textarea::placeholder { + color: rgba(242, 245, 247, 0.58); +} + +.mosh .sla-panel textarea, +.mosh .tab[data-tab="special-rules"] textarea { + background: rgba(34, 43, 51, 0.92); + color: #f2f5f7; + border: 1px solid rgba(212, 190, 148, 0.32); +} + +.mosh .tab[data-tab="sla"] .resource-label, +.mosh .tab[data-tab="special-rules"] .resource-label, +.mosh .tab[data-tab="sla"] .sla-card-copy, +.mosh .tab[data-tab="special-rules"] .sla-card-copy, +.mosh .tab[data-tab="sla"] .sla-card-label, +.mosh .tab[data-tab="special-rules"] .sla-card-label, +.mosh .tab[data-tab="sla"] .sla-card-title, +.mosh .tab[data-tab="special-rules"] .sla-card-title, +.mosh .tab[data-tab="special-rules"] .sla-rule-title, +.mosh .tab[data-tab="special-rules"] .sla-rule-summary { + color: #f2f5f7; +} + +.mosh .tab[data-tab="sla"] .sla-note-pill, +.mosh .tab[data-tab="special-rules"] .sla-note-pill { + background: rgba(242, 238, 231, 0.12); + border-color: rgba(242, 238, 231, 0.18); + color: #f4f6f7; +} + +.mosh .tab[data-tab="sla"] .sla-card, +.mosh .tab[data-tab="sla"] .sla-card-copy, +.mosh .tab[data-tab="sla"] .sla-card-label, +.mosh .tab[data-tab="sla"] .sla-card-title, +.mosh .tab[data-tab="sla"] .sla-note-pill, +.window-app.sla-window-theme-modern .mosh .tab[data-tab="sla"] .sla-card, +.window-app.sla-window-theme-modern .mosh .tab[data-tab="sla"] .sla-card-copy, +.window-app.sla-window-theme-modern .mosh .tab[data-tab="sla"] .sla-card-label, +.window-app.sla-window-theme-modern .mosh .tab[data-tab="sla"] .sla-card-title, +.window-app.sla-window-theme-modern .mosh .tab[data-tab="sla"] .sla-note-pill { + color: #18130f !important; +} + +.mosh .tab[data-tab="sla"] .sla-card { + background: #f3ede3 !important; + border: 1px solid rgba(24, 19, 15, 0.14) !important; +} + +.mosh .tab[data-tab="sla"] .sla-note-pill, +.window-app.sla-window-theme-modern .mosh .tab[data-tab="sla"] .sla-note-pill { + background: rgba(255, 255, 255, 0.38) !important; + border-color: rgba(24, 19, 15, 0.14) !important; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.35); +} + +.mosh.sla-sheet-theme-legacy .tab[data-tab="sla"] .sla-card, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="sla"] .sla-card { + background: #ece1cf !important; + border: 1px solid rgba(33, 23, 16, 0.16) !important; +} + +.mosh.sla-sheet-theme-legacy .tab[data-tab="sla"] .sla-card, +.mosh.sla-sheet-theme-legacy .tab[data-tab="sla"] .sla-card-copy, +.mosh.sla-sheet-theme-legacy .tab[data-tab="sla"] .sla-card-label, +.mosh.sla-sheet-theme-legacy .tab[data-tab="sla"] .sla-card-title, +.mosh.sla-sheet-theme-legacy .tab[data-tab="sla"] .sla-note-pill, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="sla"] .sla-card, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="sla"] .sla-card-copy, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="sla"] .sla-card-label, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="sla"] .sla-card-title, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="sla"] .sla-note-pill { + color: #211710 !important; +} + +.mosh.sla-sheet-theme-legacy .tab[data-tab="sla"] .sla-note-pill, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="sla"] .sla-note-pill { + background: rgba(255, 251, 245, 0.45) !important; + border-color: rgba(33, 23, 16, 0.16) !important; +} + +.mosh .trauma-response-box { + min-height: 92px; + max-height: 132px; + font-size: 0.92rem; + line-height: 1.25; + overflow-y: auto; + resize: vertical; +} + +.mosh .sla-stat-heading { + color: #eaf2f8 !important; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 1.08rem; + font-weight: 700; + letter-spacing: 0.05em; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.45); +} + +.mosh .sla-stat-subheading { + color: #d7e1e8 !important; + font-size: 0.72rem; + font-weight: 700; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.35); +} + +.mosh .sla-trauma-heading { + display: block; + margin-bottom: 4px; + text-align: center; +} + +.mosh .sla-armor-track { + background: #050608 !important; + border-color: #111 !important; +} + +.mosh .sla-armor-value-cell { + color: #f4f7fb !important; + justify-content: center; + align-items: center; +} + +.mosh .sla-armor-main { + color: #f4f7fb !important; + font-weight: 700; +} + +.mosh .sla-armor-cover-bonus { + color: #f7d88f !important; +} + +.mosh .sla-armor-divider { + border-right-color: rgba(255, 255, 255, 0.95) !important; +} + +.mosh .health .resource-label, +.mosh .health .minmaxtext, +.mosh .health .healthmaxtext, +.mosh .health .area-title, +.mosh .health .faded-label, +.mosh .savebackground .resource-label, +.mosh .savebackground .savetext, +.mosh .abilities .resource-label, +.mosh .abilities .mainstatmod-title { + color: #dce8f2 !important; +} + +.mosh .health .resource-label, +.mosh .health .minmaxtext, +.mosh .savebackground .resource-label, +.mosh .savebackground .savetext { + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.42); +} + +.mosh .health .healthmaxtext, +.mosh .abilities .mainstatmod-title { + color: #b7c7d4 !important; +} + +.mosh .health .faded-label, +.mosh .health .area-title { + color: #c9d7e2 !important; +} + +.mosh .health label.resource-label.minmaxtext, +.mosh .health div.resource-label, +.mosh .health .healthmaxtext, +.mosh .savebackground .savetext, +.mosh .savebackground .resource-label, +.mosh .abilities .resource-label { + color: #dce8f2 !important; +} + +.mosh .sla-skill-name-cell { + display: flex; + flex-direction: column; + gap: 2px; +} + +.mosh .sla-skill-name-cell small { + color: #626262; + font-size: 0.75rem; + line-height: 1.2; +} + +.mosh.sla-sheet-theme-modern .header, +.mosh.sla-sheet-theme-modern .health, +.mosh.sla-sheet-theme-modern .abilities, +.mosh.sla-sheet-theme-modern .savebackground { + background: linear-gradient(180deg, #1f2834, #10161d) !important; + border: 1px solid rgba(93, 131, 166, 0.2); +} + +.window-app.sla-window-theme-modern .mosh .header, +.window-app.sla-window-theme-modern .mosh .health, +.window-app.sla-window-theme-modern .mosh .abilities, +.window-app.sla-window-theme-modern .mosh .savebackground { + background: linear-gradient(180deg, #1f2834, #10161d) !important; + border: 1px solid rgba(93, 131, 166, 0.2) !important; +} + +.mosh.sla-sheet-theme-modern .health .resource-label, +.mosh.sla-sheet-theme-modern .health .minmaxtext, +.mosh.sla-sheet-theme-modern .health .healthmaxtext, +.mosh.sla-sheet-theme-modern .health .area-title, +.mosh.sla-sheet-theme-modern .health .faded-label, +.mosh.sla-sheet-theme-modern .savebackground .resource-label, +.mosh.sla-sheet-theme-modern .savebackground .savetext, +.mosh.sla-sheet-theme-modern .abilities .resource-label, +.mosh.sla-sheet-theme-modern .abilities .mainstatmod-title { + color: #dce8f2 !important; +} + +.window-app.sla-window-theme-modern .mosh .health .resource-label, +.window-app.sla-window-theme-modern .mosh .health .minmaxtext, +.window-app.sla-window-theme-modern .mosh .health .healthmaxtext, +.window-app.sla-window-theme-modern .mosh .health .area-title, +.window-app.sla-window-theme-modern .mosh .health .faded-label, +.window-app.sla-window-theme-modern .mosh .savebackground .resource-label, +.window-app.sla-window-theme-modern .mosh .savebackground .savetext, +.window-app.sla-window-theme-modern .mosh .abilities .resource-label, +.window-app.sla-window-theme-modern .mosh .abilities .mainstatmod-title { + color: #dce8f2 !important; +} + +.mosh.sla-sheet-theme-modern .health .resource-label, +.mosh.sla-sheet-theme-modern .health .minmaxtext, +.mosh.sla-sheet-theme-modern .savebackground .resource-label, +.mosh.sla-sheet-theme-modern .savebackground .savetext { + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.42); +} + +.mosh.sla-sheet-theme-modern .health .healthmaxtext, +.mosh.sla-sheet-theme-modern .abilities .mainstatmod-title { + color: #b7c7d4 !important; +} + +.mosh.sla-sheet-theme-modern .health .faded-label, +.mosh.sla-sheet-theme-modern .health .area-title { + color: #c9d7e2 !important; +} + +.window-app.sla-window-theme-modern .mosh .health .resource-label, +.window-app.sla-window-theme-modern .mosh .health .minmaxtext, +.window-app.sla-window-theme-modern .mosh .savebackground .resource-label, +.window-app.sla-window-theme-modern .mosh .savebackground .savetext { + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.42) !important; +} + +.mosh.sla-sheet-theme-modern .sla-stat-heading, +.window-app.sla-window-theme-modern .mosh .sla-stat-heading { + color: #e7f0f8 !important; +} + +.mosh[data-sla-theme="modern"] .sla-stat-heading { + color: #e7f0f8 !important; +} + +.mosh.sla-sheet-theme-modern .sla-stat-subheading, +.window-app.sla-window-theme-modern .mosh .sla-stat-subheading { + color: #d2dde6 !important; +} + +.mosh[data-sla-theme="modern"] .sla-stat-subheading { + color: #d2dde6 !important; +} + +.mosh.sla-sheet-theme-modern .sla-sheet-wordmark { + color: #cfe5f7 !important; + text-shadow: 0 0 14px rgba(86, 135, 178, 0.22); +} + +.window-app.sla-window-theme-modern .mosh .sla-sheet-wordmark { + color: #cfe5f7 !important; + text-shadow: 0 0 14px rgba(86, 135, 178, 0.22) !important; +} + +.mosh.sla-sheet-theme-modern .sheet-tabs { + background: linear-gradient(90deg, rgba(15, 22, 31, 0.98), rgba(26, 39, 54, 0.98) 55%, rgba(15, 22, 31, 0.98)) !important; +} + +.window-app.sla-window-theme-modern .mosh .sheet-tabs { + background: linear-gradient(90deg, rgba(15, 22, 31, 0.98), rgba(26, 39, 54, 0.98) 55%, rgba(15, 22, 31, 0.98)) !important; +} + +.mosh.sla-sheet-theme-modern .sheet-tabs .tab-select:hover, +.mosh.sla-sheet-theme-modern .sheet-tabs .tab-select.active { + background: linear-gradient(180deg, #d9e4ef, #aabccd) !important; + color: #0f1419 !important; +} + +.window-app.sla-window-theme-modern .mosh .sheet-tabs .tab-select:hover, +.window-app.sla-window-theme-modern .mosh .sheet-tabs .tab-select.active { + background: linear-gradient(180deg, #d9e4ef, #aabccd) !important; + color: #0f1419 !important; +} + +.mosh.sla-sheet-theme-modern .headerinputfield, +.mosh.sla-sheet-theme-modern .headerinputfield input, +.mosh.sla-sheet-theme-modern .mainstatmod-input, +.mosh.sla-sheet-theme-modern .mainsavemod-input, +.mosh.sla-sheet-theme-modern .circle-input, +.mosh.sla-sheet-theme-modern .square-input, +.mosh.sla-sheet-theme-modern .minmaxwrapper { + background: #f7f8fa !important; + color: #11161b !important; +} + +.window-app.sla-window-theme-modern .mosh .headerinputfield, +.window-app.sla-window-theme-modern .mosh .headerinputfield input, +.window-app.sla-window-theme-modern .mosh .mainstatmod-input, +.window-app.sla-window-theme-modern .mosh .mainsavemod-input, +.window-app.sla-window-theme-modern .mosh .circle-input, +.window-app.sla-window-theme-modern .mosh .square-input, +.window-app.sla-window-theme-modern .mosh .minmaxwrapper { + background: #f7f8fa !important; + color: #11161b !important; +} + +.window-app.sla-window-theme-modern .mosh .sla-header-checkbox { + background: #f7f8fa !important; + color: #11161b !important; + border-color: rgba(17, 22, 27, 0.24) !important; +} + +.mosh.sla-sheet-theme-modern .textarea-input { + background: #11161d; + color: #f4f7fa; +} + +.mosh.sla-sheet-theme-modern .item-header { + background: rgba(16, 22, 30, 0.94); + border-bottom: 1px solid rgba(217, 227, 237, 0.2); +} + +.mosh.sla-sheet-theme-modern .items-list .item-header .skill-stat, +.mosh.sla-sheet-theme-modern .items-list .item-header .item-controls a, +.mosh.sla-sheet-theme-modern .items-list .item-header .item-controls i, +.mosh.sla-sheet-theme-modern .items-list .skill-stat, +.mosh.sla-sheet-theme-modern .items-list .item-controls a, +.mosh.sla-sheet-theme-modern .items-list .item-controls i, +.mosh.sla-sheet-theme-modern .weapon-shots, +.mosh.sla-sheet-theme-modern .weapon-reload, +.mosh.sla-sheet-theme-modern .weapon-fire-mode, +.mosh.sla-sheet-theme-modern .weapon-ammo, +.mosh.sla-sheet-theme-modern .sla-card-copy { + color: #e7eef4 !important; +} + +.mosh.sla-sheet-theme-modern .items-list .skill-name { + background: #0b0f14; + color: #ffffff; +} + +.mosh.sla-sheet-theme-modern .sla-skill-name-cell small, +.mosh.sla-sheet-theme-modern .sla-weapon-ammo-secondary, +.mosh.sla-sheet-theme-modern .sla-carry-row-text { + color: #b7c5d1 !important; +} + +.mosh.sla-sheet-theme-modern .sla-skill-trait-mod { + color: #f2a26d; +} + +.mosh.sla-sheet-theme-legacy .items-list .item-header { + background: rgba(242, 236, 226, 0.94); + border-bottom: 1px solid rgba(31, 20, 14, 0.18); +} + +.mosh.sla-sheet-theme-legacy .health .resource-label, +.mosh.sla-sheet-theme-legacy .health .minmaxtext, +.mosh.sla-sheet-theme-legacy .health .healthmaxtext, +.mosh.sla-sheet-theme-legacy .health .area-title, +.mosh.sla-sheet-theme-legacy .health .faded-label, +.mosh.sla-sheet-theme-legacy .savebackground .resource-label, +.mosh.sla-sheet-theme-legacy .savebackground .savetext, +.mosh.sla-sheet-theme-legacy .abilities .resource-label, +.mosh.sla-sheet-theme-legacy .abilities .mainstatmod-title { + color: #f0e3cf !important; + text-shadow: 0 1px 0 rgba(0, 0, 0, 0.35); +} + +.mosh.sla-sheet-theme-legacy .items-list .item-header .skill-stat, +.mosh.sla-sheet-theme-legacy .items-list .skill-stat, +.mosh.sla-sheet-theme-legacy .items-list .item-controls a, +.mosh.sla-sheet-theme-legacy .items-list .item-controls i, +.mosh.sla-sheet-theme-legacy .weapon-shots, +.mosh.sla-sheet-theme-legacy .weapon-reload, +.mosh.sla-sheet-theme-legacy .weapon-fire-mode, +.mosh.sla-sheet-theme-legacy .weapon-ammo, +.mosh.sla-sheet-theme-legacy .sla-card-copy { + color: #17120f !important; +} + +.mosh.sla-sheet-theme-legacy .items-list .skill-name { + background: #1a1311; + color: #f8efe3; +} + +.mosh.sla-sheet-theme-legacy .tab[data-tab="skills"] .sla-card, +.mosh.sla-sheet-theme-legacy .tab[data-tab="weapons"] .sla-card, +.mosh.sla-sheet-theme-legacy .tab[data-tab="items"] .sla-card, +.mosh.sla-sheet-theme-legacy .tab[data-tab="traits"] .sla-card, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="skills"] .sla-card, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="weapons"] .sla-card, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="items"] .sla-card, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="traits"] .sla-card { + background: #ece1cf !important; + color: #211710 !important; +} + +.mosh.sla-sheet-theme-legacy .tab[data-tab="skills"] .sla-card-label, +.mosh.sla-sheet-theme-legacy .tab[data-tab="weapons"] .sla-card-label, +.mosh.sla-sheet-theme-legacy .tab[data-tab="items"] .sla-card-label, +.mosh.sla-sheet-theme-legacy .tab[data-tab="traits"] .sla-card-label, +.mosh.sla-sheet-theme-legacy .tab[data-tab="skills"] .sla-card-copy, +.mosh.sla-sheet-theme-legacy .tab[data-tab="weapons"] .sla-card-copy, +.mosh.sla-sheet-theme-legacy .tab[data-tab="items"] .sla-card-copy, +.mosh.sla-sheet-theme-legacy .tab[data-tab="traits"] .sla-card-copy, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="skills"] .sla-card-label, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="weapons"] .sla-card-label, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="items"] .sla-card-label, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="traits"] .sla-card-label, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="skills"] .sla-card-copy, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="weapons"] .sla-card-copy, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="items"] .sla-card-copy, +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="traits"] .sla-card-copy { + color: #211710 !important; +} + +.mosh.sla-sheet-theme-legacy .sla-skill-name-cell small, +.mosh.sla-sheet-theme-legacy .sla-weapon-ammo-secondary, +.mosh.sla-sheet-theme-legacy .sla-carry-row-text { + color: #53473f !important; +} + +.mosh.sla-sheet-theme-legacy .sla-stat-heading, +.window-app.sla-window-theme-legacy .mosh .sla-stat-heading { + color: #2e2018 !important; + text-shadow: none !important; +} + +.mosh[data-sla-theme="legacy"] .sla-stat-heading { + color: #2e2018 !important; + text-shadow: none !important; +} + +.mosh.sla-sheet-theme-legacy .sla-stat-subheading, +.window-app.sla-window-theme-legacy .mosh .sla-stat-subheading { + color: #5c4938 !important; + text-shadow: none !important; +} + +.mosh[data-sla-theme="legacy"] .sla-stat-subheading { + color: #5c4938 !important; + text-shadow: none !important; +} + +.mosh .sla-skill-trait-mod { + display: block; + margin-top: 2px; + font-size: 0.68rem; + line-height: 1.1; + color: #7e2a17; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.mosh .sla-inline-mini-button { + display: inline-flex; + align-items: center; + justify-content: center; + margin-left: 0; + padding: 3px 10px; + min-height: 24px; + border-radius: 999px; + border: 1px solid rgba(212, 190, 148, 0.45); + background: rgba(242, 238, 231, 0.14); + color: #f2f5f7; + font-size: 0.72rem; + line-height: 1; + cursor: pointer; + position: relative; + top: -4px; +} + +.mosh .sla-health-label-row { + grid-column: 1 / -1; + display: flex; + align-items: center; + justify-content: center; + gap: 8px; + min-height: 18px; +} + +.mosh .sla-health-label-row .resource-label { + margin-bottom: 0; +} + +.mosh .health { + padding: 12px 14px 16px; + box-sizing: border-box; +} + +.mosh .sla-front-strip { + margin: 0 0 10px; +} + +.mosh .sla-carry-summary { + margin: 8px 6px 0; + padding: 10px 14px; + border-radius: 14px; + background: rgba(19, 29, 37, 0.9); + border: 1px solid rgba(212, 190, 148, 0.24); + color: #f2f5f7; +} + +.mosh .sla-carry-summary.over { + border-color: rgba(182, 64, 38, 0.7); + box-shadow: 0 0 0 1px rgba(182, 64, 38, 0.18), 0 0 18px rgba(182, 64, 38, 0.18); +} + +.mosh .sla-carry-summary-title { + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.08em; + font-size: 0.78rem; + color: #f7d88f; +} + +.mosh .sla-carry-summary-main { + font-size: 1.05rem; + font-weight: 700; + margin-top: 2px; +} + +.mosh .sla-carry-summary-meta, +.mosh .sla-carry-row-text { + display: block; + margin-top: 3px; + font-size: 0.72rem; + line-height: 1.2; + color: #cfd6db; +} + +.mosh .sla-carry-toggle-row { + display: inline-flex; + gap: 4px; + align-items: center; + justify-content: center; + flex-wrap: nowrap; +} + +.mosh .sla-carry-toggle { + border: 1px solid rgba(212, 190, 148, 0.35); + background: rgba(242, 238, 231, 0.08); + color: #f2f5f7; + border-radius: 999px; + padding: 2px 8px; + min-width: 46px; + font-size: 0.68rem; + line-height: 1; + cursor: pointer; +} + +.mosh .sla-carry-toggle.active { + background: rgba(212, 190, 148, 0.88); + color: #16110d; + border-color: rgba(212, 190, 148, 0.95); +} + +.mosh .sla-carry-summary-inline { + margin: 0; + display: grid; + grid-template-columns: auto auto 1fr; + gap: 10px 14px; + align-items: center; +} + +.mosh .sla-carry-summary-inline .sla-carry-summary-title, +.mosh .sla-carry-summary-inline .sla-carry-summary-main, +.mosh .sla-carry-summary-inline .sla-carry-summary-meta { + margin: 0; +} + +.mosh .sla-carry-summary-inline .sla-carry-summary-meta { + font-size: 0.76rem; +} + +.mosh .tab[data-tab="weapons"] .items-list .item, +.mosh .tab[data-tab="items"] .items-list .item, +.mosh .tab[data-tab="skills"] .items-list .item { + min-height: 50px; + height: auto; + align-items: center; +} + +.mosh .tab[data-tab="weapons"] .items-list .item-header, +.mosh .tab[data-tab="items"] .items-list .item-header, +.mosh .tab[data-tab="skills"] .items-list .item-header { + background: rgba(16, 22, 30, 0.96) !important; + color: #edf2f7 !important; +} + +.mosh .tab[data-tab="weapons"] .items-list > li.item:not(.item-header):nth-of-type(odd), +.mosh .tab[data-tab="items"] .items-list > li.item:not(.item-header):nth-of-type(odd), +.mosh .tab[data-tab="skills"] .items-list > li.item:not(.item-header):nth-of-type(odd) { + background: rgba(18, 24, 33, 0.98) !important; + color: #edf2f7 !important; +} + +.mosh .tab[data-tab="weapons"] .items-list > li.item:not(.item-header):nth-of-type(even), +.mosh .tab[data-tab="items"] .items-list > li.item:not(.item-header):nth-of-type(even), +.mosh .tab[data-tab="skills"] .items-list > li.item:not(.item-header):nth-of-type(even) { + background: rgba(30, 38, 49, 0.98) !important; + color: #edf2f7 !important; +} + +.mosh .tab[data-tab="weapons"] .items-list > li.item:not(.item-header), +.mosh .tab[data-tab="items"] .items-list > li.item:not(.item-header), +.mosh .tab[data-tab="skills"] .items-list > li.item:not(.item-header) { + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.025), inset 0 -1px 0 rgba(255, 255, 255, 0.02); +} + +.mosh .tab[data-tab="weapons"] .items-list .skill-stat, +.mosh .tab[data-tab="items"] .items-list .skill-stat, +.mosh .tab[data-tab="skills"] .items-list .skill-stat, +.mosh .tab[data-tab="weapons"] .items-list .item-controls, +.mosh .tab[data-tab="items"] .items-list .item-controls, +.mosh .tab[data-tab="skills"] .items-list .item-controls { + display: flex; + align-items: center; + justify-content: center; + min-height: 42px; +} + +.mosh .tab[data-tab="weapons"] .items-list .item-controls, +.mosh .tab[data-tab="items"] .items-list .item-controls, +.mosh .tab[data-tab="skills"] .items-list .item-controls { + justify-content: flex-end; +} + +.mosh .tab[data-tab="weapons"] .items-list .item-header .skill-stat, +.mosh .tab[data-tab="items"] .items-list .item-header .skill-stat, +.mosh .tab[data-tab="skills"] .items-list .item-header .skill-stat, +.mosh .tab[data-tab="weapons"] .items-list .item-header .item-controls a, +.mosh .tab[data-tab="items"] .items-list .item-header .item-controls a, +.mosh .tab[data-tab="skills"] .items-list .item-header .item-controls a, +.mosh .tab[data-tab="weapons"] .items-list .item-header .item-controls i, +.mosh .tab[data-tab="items"] .items-list .item-header .item-controls i, +.mosh .tab[data-tab="skills"] .items-list .item-header .item-controls i { + color: #d9e6f1 !important; +} + +.mosh .tab[data-tab="weapons"] .items-list .skill-stat, +.mosh .tab[data-tab="items"] .items-list .skill-stat, +.mosh .tab[data-tab="skills"] .items-list .skill-stat, +.mosh .tab[data-tab="weapons"] .items-list .item-controls a, +.mosh .tab[data-tab="items"] .items-list .item-controls a, +.mosh .tab[data-tab="skills"] .items-list .item-controls a, +.mosh .tab[data-tab="weapons"] .items-list .item-controls i, +.mosh .tab[data-tab="items"] .items-list .item-controls i, +.mosh .tab[data-tab="skills"] .items-list .item-controls i, +.mosh .tab[data-tab="weapons"] .weapon-shots, +.mosh .tab[data-tab="weapons"] .weapon-reload, +.mosh .tab[data-tab="weapons"] .weapon-fire-mode, +.mosh .tab[data-tab="weapons"] .weapon-ammo, +.mosh .tab[data-tab="weapons"] .sla-weapon-ammo-primary, +.mosh .tab[data-tab="weapons"] .sla-weapon-ammo-secondary, +.mosh .tab[data-tab="skills"] .sla-skill-trait-mod, +.mosh .tab[data-tab="skills"] .sla-skill-name-cell small, +.mosh .tab[data-tab="items"] .sla-carry-row-text, +.mosh .tab[data-tab="weapons"] .sla-carry-row-text { + color: #edf2f7 !important; +} + +.mosh .tab[data-tab="skills"] .sla-skill-trait-mod { + color: #f2b07e !important; +} + +.mosh .tab[data-tab="weapons"] .items-list .item-controls a:hover, +.mosh .tab[data-tab="items"] .items-list .item-controls a:hover, +.mosh .tab[data-tab="skills"] .items-list .item-controls a:hover, +.mosh .tab[data-tab="weapons"] .items-list .item-controls a:focus, +.mosh .tab[data-tab="items"] .items-list .item-controls a:focus, +.mosh .tab[data-tab="skills"] .items-list .item-controls a:focus { + color: #f0c24b !important; +} + +.mosh .tab[data-tab="items"] .sla-carry-toggle, +.mosh .tab[data-tab="weapons"] .sla-carry-toggle { + color: #edf2f7 !important; +} + +.mosh.sla-sheet-theme-legacy .tab[data-tab="weapons"] .items-list > li.item:not(.item-header):nth-of-type(odd), +.mosh.sla-sheet-theme-legacy .tab[data-tab="items"] .items-list > li.item:not(.item-header):nth-of-type(odd), +.mosh.sla-sheet-theme-legacy .tab[data-tab="skills"] .items-list > li.item:not(.item-header):nth-of-type(odd), +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="weapons"] .items-list > li.item:not(.item-header):nth-of-type(odd), +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="items"] .items-list > li.item:not(.item-header):nth-of-type(odd), +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="skills"] .items-list > li.item:not(.item-header):nth-of-type(odd) { + background: rgba(238, 230, 216, 0.98) !important; + color: #17120f !important; +} + +.mosh.sla-sheet-theme-legacy .tab[data-tab="weapons"] .items-list > li.item:not(.item-header):nth-of-type(even), +.mosh.sla-sheet-theme-legacy .tab[data-tab="items"] .items-list > li.item:not(.item-header):nth-of-type(even), +.mosh.sla-sheet-theme-legacy .tab[data-tab="skills"] .items-list > li.item:not(.item-header):nth-of-type(even), +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="weapons"] .items-list > li.item:not(.item-header):nth-of-type(even), +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="items"] .items-list > li.item:not(.item-header):nth-of-type(even), +.window-app.sla-window-theme-legacy .mosh .tab[data-tab="skills"] .items-list > li.item:not(.item-header):nth-of-type(even) { + background: rgba(226, 217, 201, 0.98) !important; + color: #17120f !important; +} + +.mosh .tab[data-tab="items"] .sla-carry-toggle.active, +.mosh .tab[data-tab="weapons"] .sla-carry-toggle.active { + color: #16110d !important; +} + +.mosh .tab[data-tab="weapons"] .sla-card .sla-sheet-action, +.mosh .tab[data-tab="items"] .sla-card .sla-sheet-action, +.mosh .tab[data-tab="skills"] .sla-card .sla-sheet-action, +.mosh .tab[data-tab="traits"] .sla-card .sla-sheet-action { + color: #13100d !important; +} + +.mosh .sla-weapon-state { + display: inline-flex; + align-items: center; + width: fit-content; + padding: 2px 8px; + border-radius: 999px; + font-size: 0.68rem; + line-height: 1; + text-transform: uppercase; + letter-spacing: 0.05em; + border: 1px solid rgba(255, 255, 255, 0.14); +} + +.mosh .sla-weapon-state-ready { + background: rgba(44, 122, 74, 0.18); + color: #9be0b1; +} + +.mosh .sla-weapon-state-low { + background: rgba(177, 104, 28, 0.18); + color: #f2cb8d; +} + +.mosh .sla-weapon-state-empty { + background: rgba(149, 41, 34, 0.18); + color: #ff9c89; +} + +.mosh .sla-traits-toolbar { + display: flex; + gap: 8px; + align-items: center; + margin-bottom: 12px; +} + +.mosh .sla-traits-audit { + display: grid; + grid-template-columns: repeat(3, minmax(0, 1fr)); + gap: 8px 12px; + padding: 12px; + border-radius: 12px; + margin-bottom: 12px; + background: rgba(19, 29, 37, 0.86); + border: 1px solid rgba(212, 190, 148, 0.24); + color: #f2f5f7; +} + +.mosh .sla-traits-audit.warn { + border-color: rgba(182, 64, 38, 0.55); + box-shadow: 0 0 0 1px rgba(182, 64, 38, 0.18), 0 0 18px rgba(182, 64, 38, 0.18); +} + +.mosh .sla-traits-audit strong { + color: #f7d88f; +} + +.mosh .sla-traits-audit-pulse { + animation: slaTraitsPulse 1.35s ease-in-out infinite; +} + +.mosh .sla-trait-audit-line { + grid-column: 1 / -1; +} + +.mosh .sla-trait-list { + list-style: none; + margin: 0; + padding: 0; + border: 1px solid rgba(212, 190, 148, 0.18); + border-radius: 12px; + overflow: hidden; +} + +.mosh .sla-trait-row { + display: grid; + grid-template-columns: 56px minmax(0, 1.2fr) 88px 110px 110px minmax(0, 1.8fr) 56px; + gap: 8px; + align-items: center; + padding: 10px 12px; + background: rgba(18, 27, 36, 0.78); + border-bottom: 1px solid rgba(212, 190, 148, 0.12); +} + +.mosh .sla-trait-head { + background: rgba(8, 13, 19, 0.92); + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + text-transform: uppercase; + letter-spacing: 0.06em; +} + +.mosh .sla-trait-row:last-child { + border-bottom: 0; +} + +.mosh .sla-trait-icon img { + width: 32px; + height: 32px; + object-fit: cover; + border-radius: 8px; +} + +.mosh .sla-trait-name, +.mosh .sla-trait-effect { + color: #f2f5f7; +} + +.mosh .sla-trait-rank, +.mosh .sla-trait-type, +.mosh .sla-trait-status { + color: #d7dde1; + font-size: 0.86rem; +} + +.mosh .sla-trait-error, +.mosh .sla-trait-warn { + display: inline-flex; + margin-left: 6px; + padding: 2px 8px; + border-radius: 999px; + font-size: 0.72rem; + background: rgba(255, 255, 255, 0.08); +} + +.mosh .sla-trait-error { + color: #ff9c89; +} + +.mosh .sla-trait-warn { + color: #f0c24b; +} + +.mosh .sla-trait-balance-status.warn { + color: #ff8f7e; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.mosh .sla-trait-balance-status.ok { + color: #9be0b1; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.04em; +} + +.mosh .sla-trait-picker-row { + display: flex; + gap: 10px; + align-items: center; +} + +.mosh .sla-trait-picker-row select { + flex: 1; +} + +@keyframes slaTraitsPulse { + 0%, + 100% { + transform: translateY(0); + box-shadow: 0 0 0 1px rgba(182, 64, 38, 0.18), 0 0 12px rgba(182, 64, 38, 0.12); + } + 50% { + transform: translateY(-1px); + box-shadow: 0 0 0 1px rgba(207, 71, 43, 0.28), 0 0 20px rgba(207, 71, 43, 0.28); + } +} + +.mosh .sla-skill-name-cell .sla-skill-flag { + display: inline-flex; + align-items: center; + width: fit-content; + padding: 2px 8px; + border-radius: 999px; + background: rgba(141, 31, 24, 0.1); + color: #8d1f18; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.68rem; + letter-spacing: 0.05em; + text-transform: uppercase; +} + +.mosh .sla-ebb-skill-list { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + margin: 10px 0 8px; +} + +.mosh .sla-ebb-skill-roll { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 3px; + width: 100%; + padding: 10px 12px; + border: 1px solid rgba(17, 17, 17, 0.18); + border-radius: 12px; + background: linear-gradient(180deg, #fbfaf7, #ece6dc); + color: #141414; + text-align: left; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.45); +} + +.mosh .sla-ebb-skill-roll:hover, +.mosh .sla-ebb-skill-roll:focus { + border-color: rgba(140, 52, 40, 0.55); + box-shadow: 0 0 0 2px rgba(140, 52, 40, 0.12); +} + +.mosh .sla-ebb-skill-roll span { + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.98rem; + letter-spacing: 0.03em; + text-transform: uppercase; +} + +.mosh .sla-ebb-skill-meta { + display: flex; + width: 100%; + justify-content: space-between; + align-items: center; + gap: 8px; +} + +.mosh .sla-ebb-skill-roll small { + color: #5a5a5a; + font-size: 0.73rem; + line-height: 1.2; +} + +.mosh .sla-ebb-skill-roll strong { + display: inline-flex; + align-items: center; + justify-content: center; + min-width: 46px; + padding: 3px 8px; + border-radius: 999px; + background: rgba(18, 60, 52, 0.12); + color: #173a34; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.8rem; + letter-spacing: 0.04em; +} + +.mosh .sla-drug-alerts { + display: grid; + gap: 8px; + margin: 0 0 12px; +} + +.mosh .sla-drug-alert { + display: grid; + grid-template-columns: 1fr auto; + gap: 6px; + padding: 10px 12px; + border: 2px solid #191919; + border-radius: 16px; + background: #f5f2ec; + color: #171717; +} + +.mosh .sla-drug-alert.active { + border-color: #4d7b39; + box-shadow: inset 0 0 0 1px rgba(77, 123, 57, 0.18); +} + +.mosh .sla-drug-alert.withdrawal, +.mosh .sla-drug-alert.withdrawal-check { + border-color: #8c3428; + box-shadow: inset 0 0 0 1px rgba(140, 52, 40, 0.18); +} + +.mosh .sla-drug-alert-main, +.mosh .sla-drug-alert-meta { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.mosh .sla-drug-alert-main, +.mosh .sla-drug-alert-summary { + grid-column: 1; +} + +.mosh .sla-drug-alert-name { + font-weight: 700; + font-size: 1.05rem; + color: #111; +} + +.mosh .sla-drug-alert-state, +.mosh .sla-drug-alert-duration { + display: inline-flex; + align-items: center; + border-radius: 999px; + padding: 2px 10px; + font-size: 0.8rem; + font-weight: 700; + background: #111; + color: #f5f2ec; +} + +.mosh .sla-drug-alert-summary, +.mosh .drug-item-summary span { + color: #2c2c2c; + font-size: 0.86rem; + line-height: 1.35; +} + +.mosh .drug-item-summary { + display: flex; + flex-direction: column; + gap: 2px; +} + +.mosh .drug-use-btn, +.mosh .drug-close-btn { + border: 1px solid #111; + border-radius: 999px; + background: #111; + color: #f8f5ee; + font-family: "Josefin Sans", "Roboto", sans-serif; + font-weight: 700; + padding: 4px 10px; + line-height: 1; + min-width: 56px; +} + +.mosh .drug-close-btn { + background: #efe4d5; + color: #141414; +} + +.mosh .sla-drug-alert .drug-close-btn { + grid-column: 2; + grid-row: 1 / span 2; + align-self: center; + justify-self: end; + min-width: 88px; +} + +.mosh .sla-drug-list .item-controls { + flex: 0 0 168px; + display: flex; + align-items: center; + justify-content: flex-end; + gap: 6px; +} + +.mosh .drug-use-btn:disabled, +.mosh .drug-close-btn:disabled { + opacity: 0.45; + cursor: not-allowed; +} + +@media (max-width: 720px) { + .mosh .sla-banner { + flex-direction: column; + } +} +.mosh .description, +.mosh .description .body, +.mosh .rollcontainer .body { + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; + color: #141414; +} + +.mosh .sla-chat-section { + margin: 0 0 12px; + padding: 10px 12px; + border: 1px solid #d7d7d7; + border-radius: 10px; + background: #fbfbfb; +} + +.mosh .sla-chat-section-success { + border-color: rgba(15, 92, 46, 0.4); + background: rgba(15, 92, 46, 0.08); +} + +.mosh .sla-chat-section-danger { + border-color: rgba(141, 31, 24, 0.4); + background: rgba(141, 31, 24, 0.08); +} + +.mosh .sla-chat-section-target { + border-color: rgba(35, 73, 98, 0.35); + background: rgba(35, 73, 98, 0.06); +} + +.mosh .sla-chat-section-damage { + border-color: rgba(141, 31, 24, 0.42); + background: rgba(141, 31, 24, 0.08); +} + +.mosh .sla-chat-section-heal { + border-color: rgba(18, 92, 46, 0.42); + background: rgba(18, 92, 46, 0.08); +} + +.mosh .sla-chat-section-ebb-meta { + border-color: rgba(23, 58, 52, 0.28); + background: rgba(23, 58, 52, 0.06); +} + +.mosh .sla-chat-section-title { + margin-bottom: 6px; + font-size: 0.8rem; + font-weight: 700; + letter-spacing: 0.08em; + text-transform: uppercase; + font-family: "Futura PT Cond Bold", "Josefin Sans", "Roboto", sans-serif; +} + +.mosh.sla-ebb-chat .rollcontainer { + background: linear-gradient(180deg, #eef5f1, #dfe9e4); + border-color: #22463f; +} + +.mosh.sla-ebb-chat .rollweaponh1 { + background: linear-gradient(90deg, #143832, #295149); + color: #f4faf7; +} + +.mosh.sla-ebb-chat .description, +.mosh.sla-ebb-chat .description .body, +.mosh.sla-ebb-chat .rollcontainer .body { + color: #10201c; +} + +.mosh.sla-ebb-chat .sla-chat-section { + border-color: rgba(34, 70, 63, 0.24); + background: rgba(34, 70, 63, 0.07); +} + +.mosh.sla-ebb-chat .sla-chat-section-success { + border-color: rgba(18, 87, 56, 0.38); + background: rgba(18, 87, 56, 0.1); +} + +.mosh.sla-ebb-chat .sla-chat-section-danger { + border-color: rgba(125, 31, 24, 0.38); + background: rgba(125, 31, 24, 0.09); +} + +.mosh.sla-ebb-chat .sla-chat-section-damage { + border-color: rgba(141, 31, 24, 0.42); + background: rgba(141, 31, 24, 0.1); +} + +.mosh.sla-ebb-chat .sla-chat-section-heal { + border-color: rgba(18, 92, 46, 0.42); + background: rgba(18, 92, 46, 0.1); +} + +.mosh .sla-effect-number { + font-weight: 700; +} + +.mosh .sla-effect-damage { + color: #a61f1a; +} + +.mosh .sla-effect-heal { + color: #136235; +} + +.mosh .sla-chat-chip { + display: inline-block; + margin-bottom: 8px; + padding: 2px 8px; + border-radius: 999px; + background: #111; + color: #fff; + font-size: 0.8rem; + font-weight: 700; +} + +.mosh .sla-chat-list { + margin: 0; + padding-left: 20px; +} + +.mosh .sla-chat-list li { + margin: 0 0 4px; +} + +.mosh .sla-wound-effect-link { + display: inline-flex; + align-items: center; + gap: 0.35rem; + padding: 0.18rem 0.55rem; + border: 1px solid rgba(39, 45, 56, 0.28); + border-radius: 0.45rem; + background: #f5f5f5; + color: #272d38; + font-family: "Futura PT Book", "Josefin Sans", "Roboto", sans-serif; + font-size: 0.95rem; + line-height: 1.1; + cursor: pointer; +} + +.mosh .sla-wound-effect-link:hover, +.mosh .sla-wound-effect-link:focus { + background: #ffd55d; + color: #111; + border-color: rgba(17, 17, 17, 0.4); + box-shadow: 0 0 0 2px rgba(255, 213, 93, 0.18); +} + +.mosh.sla-dossier-sheet .char-header .header-grid { + grid-template-areas: + "header header" + "abilities saves" + "centercol centercol"; + grid-template-columns: minmax(0, 1fr) 124px; + gap: 12px; +} + +.mosh.sla-dossier-sheet .header { + grid-template-columns: 132px 1fr; + border-radius: 18px; + overflow: hidden; + box-shadow: 0 12px 28px rgba(0, 0, 0, 0.2); +} + +.mosh.sla-dossier-sheet .headergrid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-template-rows: auto auto auto auto; + gap: 0.45rem 0.7rem; + padding: 1.2rem 1rem 0.95rem; +} + +.mosh.sla-dossier-sheet .headergrid { + grid-template-columns: 1.1fr 1.1fr 0.9fr 1fr 1fr; +} + +.mosh.sla-dossier-sheet .sla-sheet-wordmark { + grid-column: 1 / -1; + text-align: left; + font-size: 2.2rem; + letter-spacing: 0.1em; + margin-bottom: 0.55rem; +} + +.mosh.sla-dossier-sheet .header-field-name { + grid-column: 1 / span 3; + grid-row: 2; +} + +.mosh.sla-dossier-sheet .header-field-credits { + grid-column: 3; + grid-row: 3; +} + +.mosh.sla-dossier-sheet .header-field-lad { + grid-column: 1 / span 2; + grid-row: 3; + align-self: start; +} + +.mosh.sla-dossier-sheet .header-field-class { + grid-column: 4; + grid-row: 2; +} + +.mosh.sla-dossier-sheet .header-field-race { + grid-column: 5; + grid-row: 2; +} + +.mosh.sla-dossier-sheet .header-field-sla-rank { + grid-column: 3; + grid-row: 4; +} + +.mosh.sla-dossier-sheet .header-field-height { + grid-column: 4; + grid-row: 4; +} + +.mosh.sla-dossier-sheet .header-field-weight { + grid-column: 5; + grid-row: 4; +} + +.mosh.sla-dossier-sheet .abilities, +.mosh.sla-dossier-sheet .savebackground, +.mosh.sla-dossier-sheet .health { + border-radius: 16px; + overflow: hidden; +} + +.mosh.sla-dossier-sheet .savebackground { + height: auto !important; + min-height: 320px; + padding: 12px 10px 10px; +} + +.mosh.sla-dossier-sheet .abilities { + padding: 8px 0 10px; +} + +.mosh.sla-dossier-sheet .health { + padding: 10px 6px 12px; +} + +.mosh.sla-dossier-sheet .sla-front-strip { + margin: 4px 0 14px; +} + +.mosh.sla-dossier-sheet .sheet-tabs { + border-radius: 14px; + padding: 6px; +} + +.mosh.sla-dossier-sheet .sheet-tabs .tab-select { + border-radius: 10px; + min-height: 38px; +} + +/* Final front-page theme overrides */ +.window-app.sla-window-theme-modern .mosh .health .sla-stat-heading, +.window-app.sla-window-theme-modern .mosh .health .sla-stat-subheading, +.window-app.sla-window-theme-modern .mosh .health .resource-label, +.window-app.sla-window-theme-modern .mosh .health .healthmaxtext, +.window-app.sla-window-theme-modern .mosh .health .sla-trauma-heading, +.window-app.sla-window-theme-modern .mosh .savebackground .resource-label, +.window-app.sla-window-theme-modern .mosh .savebackground .savetext, +.window-app.sla-window-theme-modern .mosh .abilities .resource-label, +.mosh[data-sla-theme="modern"] .health .sla-stat-heading, +.mosh[data-sla-theme="modern"] .health .sla-stat-subheading, +.mosh[data-sla-theme="modern"] .health .resource-label, +.mosh[data-sla-theme="modern"] .health .healthmaxtext, +.mosh[data-sla-theme="modern"] .health .sla-trauma-heading, +.mosh[data-sla-theme="modern"] .savebackground .resource-label, +.mosh[data-sla-theme="modern"] .savebackground .savetext, +.mosh[data-sla-theme="modern"] .abilities .resource-label { + color: #e2ebf3 !important; + text-shadow: none !important; +} + +.window-app.sla-window-theme-legacy .mosh .health .sla-stat-heading, +.window-app.sla-window-theme-legacy .mosh .health .sla-stat-subheading, +.window-app.sla-window-theme-legacy .mosh .health .resource-label, +.window-app.sla-window-theme-legacy .mosh .health .healthmaxtext, +.window-app.sla-window-theme-legacy .mosh .health .sla-trauma-heading, +.window-app.sla-window-theme-legacy .mosh .savebackground .resource-label, +.window-app.sla-window-theme-legacy .mosh .savebackground .savetext, +.window-app.sla-window-theme-legacy .mosh .abilities .resource-label, +.mosh[data-sla-theme="legacy"] .health .sla-stat-heading, +.mosh[data-sla-theme="legacy"] .health .sla-stat-subheading, +.mosh[data-sla-theme="legacy"] .health .resource-label, +.mosh[data-sla-theme="legacy"] .health .healthmaxtext, +.mosh[data-sla-theme="legacy"] .health .sla-trauma-heading, +.mosh[data-sla-theme="legacy"] .savebackground .resource-label, +.mosh[data-sla-theme="legacy"] .savebackground .savetext, +.mosh[data-sla-theme="legacy"] .abilities .resource-label { + color: #2b1e16 !important; + text-shadow: none !important; +} + +.window-app.sla-window-theme-modern .mosh .sla-armor-track, +.mosh[data-sla-theme="modern"] .sla-armor-track { + background: #f7f8fa !important; + border-color: #111 !important; +} + +.window-app.sla-window-theme-modern .mosh .sla-armor-track .sla-armor-main, +.window-app.sla-window-theme-modern .mosh .sla-armor-track .sla-armor-cover-bonus, +.mosh[data-sla-theme="modern"] .sla-armor-track .sla-armor-main, +.mosh[data-sla-theme="modern"] .sla-armor-track .sla-armor-cover-bonus { + color: #11161b !important; +} + +.window-app.sla-window-theme-modern .mosh .sla-armor-divider, +.mosh[data-sla-theme="modern"] .sla-armor-divider { + border-right-color: rgba(17, 22, 27, 0.75) !important; +} + +.window-app.sla-window-theme-legacy .mosh .sla-armor-track, +.mosh[data-sla-theme="legacy"] .sla-armor-track { + background: #17110d !important; + border-color: #17110d !important; +} + +.window-app.sla-window-theme-legacy .mosh .sla-armor-track .sla-armor-main, +.window-app.sla-window-theme-legacy .mosh .sla-armor-track .sla-armor-cover-bonus, +.mosh[data-sla-theme="legacy"] .sla-armor-track .sla-armor-main, +.mosh[data-sla-theme="legacy"] .sla-armor-track .sla-armor-cover-bonus { + color: #fff8ee !important; +} + +.window-app.sla-window-theme-legacy .mosh .sla-armor-divider, +.mosh[data-sla-theme="legacy"] .sla-armor-divider { + border-right-color: rgba(255, 248, 238, 0.75) !important; +} + +.window-app.sla-window-theme-modern .mosh .health .minmaxwrapper, +.window-app.sla-window-theme-modern .mosh .health .maxhealth-input, +.mosh[data-sla-theme="modern"] .health .minmaxwrapper, +.mosh[data-sla-theme="modern"] .health .maxhealth-input { + color: #11161b !important; +} + +.window-app.sla-window-theme-legacy .mosh .health .minmaxwrapper, +.window-app.sla-window-theme-legacy .mosh .health .maxhealth-input, +.mosh[data-sla-theme="legacy"] .health .minmaxwrapper, +.mosh[data-sla-theme="legacy"] .health .maxhealth-input { + color: #17120f !important; +} + +.mosh .sla-snapshot-card, +.mosh .sla-snapshot-card .sla-card-label, +.mosh .sla-snapshot-card .sla-card-title, +.mosh .sla-snapshot-card .sla-card-copy, +.mosh .sla-snapshot-pill, +.mosh .sla-snapshot-pill *, +.window-app .mosh .sla-snapshot-card, +.window-app .mosh .sla-snapshot-card .sla-card-label, +.window-app .mosh .sla-snapshot-card .sla-card-title, +.window-app .mosh .sla-snapshot-card .sla-card-copy, +.window-app .mosh .sla-snapshot-pill, +.window-app .mosh .sla-snapshot-pill * { + color: #1c1713 !important; + text-shadow: none !important; +} + +.mosh .sla-snapshot-card { + background: #f3ede3 !important; + border: 1px solid rgba(28, 23, 19, 0.14) !important; +} + +.mosh .sla-snapshot-pill, +.window-app .mosh .sla-snapshot-pill { + background: rgba(255, 255, 255, 0.42) !important; + border: 1px solid rgba(28, 23, 19, 0.12) !important; + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.45); +} + +.mosh.sla-sheet-theme-legacy .sla-snapshot-card, +.window-app.sla-window-theme-legacy .mosh .sla-snapshot-card, +.mosh[data-sla-theme="legacy"] .sla-snapshot-card { + background: #ece1cf !important; + border: 1px solid rgba(33, 23, 16, 0.16) !important; +} + +.mosh.sla-sheet-theme-legacy .sla-snapshot-card, +.mosh.sla-sheet-theme-legacy .sla-snapshot-card .sla-card-label, +.mosh.sla-sheet-theme-legacy .sla-snapshot-pill, +.mosh.sla-sheet-theme-legacy .sla-snapshot-pill *, +.window-app.sla-window-theme-legacy .mosh .sla-snapshot-card, +.window-app.sla-window-theme-legacy .mosh .sla-snapshot-card .sla-card-label, +.window-app.sla-window-theme-legacy .mosh .sla-snapshot-pill, +.window-app.sla-window-theme-legacy .mosh .sla-snapshot-pill *, +.mosh[data-sla-theme="legacy"] .sla-snapshot-card, +.mosh[data-sla-theme="legacy"] .sla-snapshot-card .sla-card-label, +.mosh[data-sla-theme="legacy"] .sla-snapshot-pill, +.mosh[data-sla-theme="legacy"] .sla-snapshot-pill * { + color: #241911 !important; +} + +/* SLA Initiative Badges (combat tracker) */ +.sla-initiative-badge { + display: inline-block; + font-size: 0.62em; + font-weight: 700; + padding: 1px 6px; + border-radius: 4px; + margin-left: 6px; + vertical-align: middle; + letter-spacing: 0.05em; + white-space: nowrap; + line-height: 1.4; +} + +.sla-initiative-badge.sla-init-before { + color: #7fe38d; + background: #08170d; + border: 1px solid #4eb765; + box-shadow: 0 0 5px rgba(78, 183, 101, 0.24); +} + +.sla-initiative-badge.sla-init-after { + color: #f28b8b; + background: #1c0909; + border: 1px solid #cc5050; + box-shadow: 0 0 5px rgba(204, 80, 80, 0.22); +} + +.sla-initiative-badge.sla-init-enemy { + color: #d1a06e; + background: #1a120c; + border: 1px solid #8a5a31; +} diff --git a/data/characterCreator.json b/data/characterCreator.json new file mode 100644 index 0000000..e69de29 diff --git a/data/characterImport.json b/data/characterImport.json new file mode 100644 index 0000000..e69de29 diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..98141b4 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,50 @@ +const gulp = require('gulp'); +const prefix = require('gulp-autoprefixer'); +const sourcemaps = require('gulp-sourcemaps'); +const sass = require('gulp-sass'); + +/* ----------------------------------------- */ +/* Compile Sass +/* ----------------------------------------- */ + +// Small error handler helper function. +function handleError(err) { + console.log(err.toString()); + this.emit('end'); +} + +const SYSTEM_SCSS = ["scss/**/*.scss"]; +function compileScss() { + // Configure options for sass output. For example, 'expanded' or 'nested' + let options = { + outputStyle: 'expanded' + }; + return gulp.src(SYSTEM_SCSS) + .pipe( + sass(options) + .on('error', handleError) + ) + .pipe(prefix({ + cascade: false + })) + .pipe(gulp.dest("./css")) +} +const css = gulp.series(compileScss); + +/* ----------------------------------------- */ +/* Watch Updates +/* ----------------------------------------- */ + +function watchUpdates() { + gulp.watch(SYSTEM_SCSS, css); +} + +/* ----------------------------------------- */ +/* Export Tasks +/* ----------------------------------------- */ + +exports.default = gulp.series( + compileScss, + watchUpdates +); +exports.css = css; diff --git a/images/Galloway_Top.png b/images/Galloway_Top.png new file mode 100644 index 0000000..7ef272d Binary files /dev/null and b/images/Galloway_Top.png differ diff --git a/images/icons/dark-grey/conditions/Coward.png b/images/icons/dark-grey/conditions/Coward.png new file mode 100644 index 0000000..18cbd2a Binary files /dev/null and b/images/icons/dark-grey/conditions/Coward.png differ diff --git a/images/icons/dark-grey/conditions/Deflated.png b/images/icons/dark-grey/conditions/Deflated.png new file mode 100644 index 0000000..b44078e Binary files /dev/null and b/images/icons/dark-grey/conditions/Deflated.png differ diff --git a/images/icons/dark-grey/conditions/Doomed.png b/images/icons/dark-grey/conditions/Doomed.png new file mode 100644 index 0000000..97b0af1 Binary files /dev/null and b/images/icons/dark-grey/conditions/Doomed.png differ diff --git a/images/icons/dark-grey/conditions/Frightened.png b/images/icons/dark-grey/conditions/Frightened.png new file mode 100644 index 0000000..8cf0a00 Binary files /dev/null and b/images/icons/dark-grey/conditions/Frightened.png differ diff --git a/images/icons/dark-grey/conditions/Haunted.png b/images/icons/dark-grey/conditions/Haunted.png new file mode 100644 index 0000000..5caf0ad Binary files /dev/null and b/images/icons/dark-grey/conditions/Haunted.png differ diff --git a/images/icons/dark-grey/conditions/LossOfConfidence.png b/images/icons/dark-grey/conditions/LossOfConfidence.png new file mode 100644 index 0000000..9ce8e63 Binary files /dev/null and b/images/icons/dark-grey/conditions/LossOfConfidence.png differ diff --git a/images/icons/dark-grey/conditions/Nightmares.png b/images/icons/dark-grey/conditions/Nightmares.png new file mode 100644 index 0000000..4e8d7da Binary files /dev/null and b/images/icons/dark-grey/conditions/Nightmares.png differ diff --git a/images/icons/dark-grey/conditions/Spiraling.png b/images/icons/dark-grey/conditions/Spiraling.png new file mode 100644 index 0000000..aa499ac Binary files /dev/null and b/images/icons/dark-grey/conditions/Spiraling.png differ diff --git a/images/icons/dark-grey/created_by.txt b/images/icons/dark-grey/created_by.txt new file mode 100644 index 0000000..d2cdb01 --- /dev/null +++ b/images/icons/dark-grey/created_by.txt @@ -0,0 +1,3 @@ +Created by Grey-Mongrel! + +Link for external downloads: https://drive.google.com/drive/folders/1A-AFKvPAnsxpkpVPMxHbWOkwzk9MnqTg?usp=sharing \ No newline at end of file diff --git a/images/icons/dark-grey/skills/Archaeology.png b/images/icons/dark-grey/skills/Archaeology.png new file mode 100644 index 0000000..fcb4e00 Binary files /dev/null and b/images/icons/dark-grey/skills/Archaeology.png differ diff --git a/images/icons/dark-grey/skills/Art.png b/images/icons/dark-grey/skills/Art.png new file mode 100644 index 0000000..ecef0a2 Binary files /dev/null and b/images/icons/dark-grey/skills/Art.png differ diff --git a/images/icons/dark-grey/skills/Artificial intelligence.png b/images/icons/dark-grey/skills/Artificial intelligence.png new file mode 100644 index 0000000..8c00b75 Binary files /dev/null and b/images/icons/dark-grey/skills/Artificial intelligence.png differ diff --git a/images/icons/dark-grey/skills/Asteroid Mining.png b/images/icons/dark-grey/skills/Asteroid Mining.png new file mode 100644 index 0000000..8124388 Binary files /dev/null and b/images/icons/dark-grey/skills/Asteroid Mining.png differ diff --git a/images/icons/dark-grey/skills/Athletics.png b/images/icons/dark-grey/skills/Athletics.png new file mode 100644 index 0000000..0aae373 Binary files /dev/null and b/images/icons/dark-grey/skills/Athletics.png differ diff --git a/images/icons/dark-grey/skills/Botany.png b/images/icons/dark-grey/skills/Botany.png new file mode 100644 index 0000000..b4b8765 Binary files /dev/null and b/images/icons/dark-grey/skills/Botany.png differ diff --git a/images/icons/dark-grey/skills/Chemistry.png b/images/icons/dark-grey/skills/Chemistry.png new file mode 100644 index 0000000..ae7b693 Binary files /dev/null and b/images/icons/dark-grey/skills/Chemistry.png differ diff --git a/images/icons/dark-grey/skills/Command.png b/images/icons/dark-grey/skills/Command.png new file mode 100644 index 0000000..1fe8490 Binary files /dev/null and b/images/icons/dark-grey/skills/Command.png differ diff --git a/images/icons/dark-grey/skills/Computers.png b/images/icons/dark-grey/skills/Computers.png new file mode 100644 index 0000000..4c77bbf Binary files /dev/null and b/images/icons/dark-grey/skills/Computers.png differ diff --git a/images/icons/dark-grey/skills/Cybernetics.png b/images/icons/dark-grey/skills/Cybernetics.png new file mode 100644 index 0000000..28c02c3 Binary files /dev/null and b/images/icons/dark-grey/skills/Cybernetics.png differ diff --git a/images/icons/dark-grey/skills/Ecology.png b/images/icons/dark-grey/skills/Ecology.png new file mode 100644 index 0000000..7285377 Binary files /dev/null and b/images/icons/dark-grey/skills/Ecology.png differ diff --git a/images/icons/dark-grey/skills/Engineering.png b/images/icons/dark-grey/skills/Engineering.png new file mode 100644 index 0000000..680fc1b Binary files /dev/null and b/images/icons/dark-grey/skills/Engineering.png differ diff --git a/images/icons/dark-grey/skills/Exobiology.png b/images/icons/dark-grey/skills/Exobiology.png new file mode 100644 index 0000000..a94b4cc Binary files /dev/null and b/images/icons/dark-grey/skills/Exobiology.png differ diff --git a/images/icons/dark-grey/skills/Explosives.png b/images/icons/dark-grey/skills/Explosives.png new file mode 100644 index 0000000..e076c36 Binary files /dev/null and b/images/icons/dark-grey/skills/Explosives.png differ diff --git a/images/icons/dark-grey/skills/Field Medicine.png b/images/icons/dark-grey/skills/Field Medicine.png new file mode 100644 index 0000000..954a584 Binary files /dev/null and b/images/icons/dark-grey/skills/Field Medicine.png differ diff --git a/images/icons/dark-grey/skills/Firearms.png b/images/icons/dark-grey/skills/Firearms.png new file mode 100644 index 0000000..7e5b3bc Binary files /dev/null and b/images/icons/dark-grey/skills/Firearms.png differ diff --git a/images/icons/dark-grey/skills/Geology.png b/images/icons/dark-grey/skills/Geology.png new file mode 100644 index 0000000..25c25e9 Binary files /dev/null and b/images/icons/dark-grey/skills/Geology.png differ diff --git a/images/icons/dark-grey/skills/Gunnery.png b/images/icons/dark-grey/skills/Gunnery.png new file mode 100644 index 0000000..0e5ccd6 Binary files /dev/null and b/images/icons/dark-grey/skills/Gunnery.png differ diff --git a/images/icons/dark-grey/skills/Hacking.png b/images/icons/dark-grey/skills/Hacking.png new file mode 100644 index 0000000..7943ebf Binary files /dev/null and b/images/icons/dark-grey/skills/Hacking.png differ diff --git a/images/icons/dark-grey/skills/HandToHand.png b/images/icons/dark-grey/skills/HandToHand.png new file mode 100644 index 0000000..7a786b2 Binary files /dev/null and b/images/icons/dark-grey/skills/HandToHand.png differ diff --git a/images/icons/dark-grey/skills/Hyperspace.png b/images/icons/dark-grey/skills/Hyperspace.png new file mode 100644 index 0000000..4862499 Binary files /dev/null and b/images/icons/dark-grey/skills/Hyperspace.png differ diff --git a/images/icons/dark-grey/skills/Industrial Equipment.png b/images/icons/dark-grey/skills/Industrial Equipment.png new file mode 100644 index 0000000..4b536fa Binary files /dev/null and b/images/icons/dark-grey/skills/Industrial Equipment.png differ diff --git a/images/icons/dark-grey/skills/Jurry-Rigging.png b/images/icons/dark-grey/skills/Jurry-Rigging.png new file mode 100644 index 0000000..ee33e90 Binary files /dev/null and b/images/icons/dark-grey/skills/Jurry-Rigging.png differ diff --git a/images/icons/dark-grey/skills/Linguistics.png b/images/icons/dark-grey/skills/Linguistics.png new file mode 100644 index 0000000..b4e642e Binary files /dev/null and b/images/icons/dark-grey/skills/Linguistics.png differ diff --git a/images/icons/dark-grey/skills/Maths.png b/images/icons/dark-grey/skills/Maths.png new file mode 100644 index 0000000..5afcafc Binary files /dev/null and b/images/icons/dark-grey/skills/Maths.png differ diff --git a/images/icons/dark-grey/skills/Mechanical Repair.png b/images/icons/dark-grey/skills/Mechanical Repair.png new file mode 100644 index 0000000..e4ff870 Binary files /dev/null and b/images/icons/dark-grey/skills/Mechanical Repair.png differ diff --git a/images/icons/dark-grey/skills/Military Training.png b/images/icons/dark-grey/skills/Military Training.png new file mode 100644 index 0000000..3014555 Binary files /dev/null and b/images/icons/dark-grey/skills/Military Training.png differ diff --git a/images/icons/dark-grey/skills/Mysticism.png b/images/icons/dark-grey/skills/Mysticism.png new file mode 100644 index 0000000..edcde62 Binary files /dev/null and b/images/icons/dark-grey/skills/Mysticism.png differ diff --git a/images/icons/dark-grey/skills/Pathology.png b/images/icons/dark-grey/skills/Pathology.png new file mode 100644 index 0000000..7074fcd Binary files /dev/null and b/images/icons/dark-grey/skills/Pathology.png differ diff --git a/images/icons/dark-grey/skills/Pharmacology.png b/images/icons/dark-grey/skills/Pharmacology.png new file mode 100644 index 0000000..54b72c2 Binary files /dev/null and b/images/icons/dark-grey/skills/Pharmacology.png differ diff --git a/images/icons/dark-grey/skills/Physics.png b/images/icons/dark-grey/skills/Physics.png new file mode 100644 index 0000000..16418e0 Binary files /dev/null and b/images/icons/dark-grey/skills/Physics.png differ diff --git a/images/icons/dark-grey/skills/Piloting.png b/images/icons/dark-grey/skills/Piloting.png new file mode 100644 index 0000000..4815aba Binary files /dev/null and b/images/icons/dark-grey/skills/Piloting.png differ diff --git a/images/icons/dark-grey/skills/Planetology.png b/images/icons/dark-grey/skills/Planetology.png new file mode 100644 index 0000000..12eabec Binary files /dev/null and b/images/icons/dark-grey/skills/Planetology.png differ diff --git a/images/icons/dark-grey/skills/Psychology.png b/images/icons/dark-grey/skills/Psychology.png new file mode 100644 index 0000000..266ce67 Binary files /dev/null and b/images/icons/dark-grey/skills/Psychology.png differ diff --git a/images/icons/dark-grey/skills/Rimwise.png b/images/icons/dark-grey/skills/Rimwise.png new file mode 100644 index 0000000..4bea897 Binary files /dev/null and b/images/icons/dark-grey/skills/Rimwise.png differ diff --git a/images/icons/dark-grey/skills/Robotics.png b/images/icons/dark-grey/skills/Robotics.png new file mode 100644 index 0000000..284e088 Binary files /dev/null and b/images/icons/dark-grey/skills/Robotics.png differ diff --git a/images/icons/dark-grey/skills/Sophontology.png b/images/icons/dark-grey/skills/Sophontology.png new file mode 100644 index 0000000..02a0d26 Binary files /dev/null and b/images/icons/dark-grey/skills/Sophontology.png differ diff --git a/images/icons/dark-grey/skills/Surgery.png b/images/icons/dark-grey/skills/Surgery.png new file mode 100644 index 0000000..69fb140 Binary files /dev/null and b/images/icons/dark-grey/skills/Surgery.png differ diff --git a/images/icons/dark-grey/skills/Tactics.png b/images/icons/dark-grey/skills/Tactics.png new file mode 100644 index 0000000..b4d9cb6 Binary files /dev/null and b/images/icons/dark-grey/skills/Tactics.png differ diff --git a/images/icons/dark-grey/skills/Theology.png b/images/icons/dark-grey/skills/Theology.png new file mode 100644 index 0000000..221d814 Binary files /dev/null and b/images/icons/dark-grey/skills/Theology.png differ diff --git a/images/icons/dark-grey/skills/Wilderness Survival.png b/images/icons/dark-grey/skills/Wilderness Survival.png new file mode 100644 index 0000000..90e44a7 Binary files /dev/null and b/images/icons/dark-grey/skills/Wilderness Survival.png differ diff --git a/images/icons/dark-grey/skills/Xenoesotericism.png b/images/icons/dark-grey/skills/Xenoesotericism.png new file mode 100644 index 0000000..b46ba94 Binary files /dev/null and b/images/icons/dark-grey/skills/Xenoesotericism.png differ diff --git a/images/icons/dark-grey/skills/Zero-G.png b/images/icons/dark-grey/skills/Zero-G.png new file mode 100644 index 0000000..1da516a Binary files /dev/null and b/images/icons/dark-grey/skills/Zero-G.png differ diff --git a/images/icons/dark-grey/skills/Zoology.png b/images/icons/dark-grey/skills/Zoology.png new file mode 100644 index 0000000..e7bc6b3 Binary files /dev/null and b/images/icons/dark-grey/skills/Zoology.png differ diff --git a/images/icons/dark-grey/weapons/BoardingAxe.png b/images/icons/dark-grey/weapons/BoardingAxe.png new file mode 100644 index 0000000..53b6f02 Binary files /dev/null and b/images/icons/dark-grey/weapons/BoardingAxe.png differ diff --git a/images/icons/dark-grey/weapons/Crowbar.png b/images/icons/dark-grey/weapons/Crowbar.png new file mode 100644 index 0000000..d996f76 Binary files /dev/null and b/images/icons/dark-grey/weapons/Crowbar.png differ diff --git a/images/icons/dark-grey/weapons/FlameThrower_01.png b/images/icons/dark-grey/weapons/FlameThrower_01.png new file mode 100644 index 0000000..2a2f77a Binary files /dev/null and b/images/icons/dark-grey/weapons/FlameThrower_01.png differ diff --git a/images/icons/dark-grey/weapons/FlareGun.png b/images/icons/dark-grey/weapons/FlareGun.png new file mode 100644 index 0000000..b71d0ee Binary files /dev/null and b/images/icons/dark-grey/weapons/FlareGun.png differ diff --git a/images/icons/dark-grey/weapons/FoamGun.png b/images/icons/dark-grey/weapons/FoamGun.png new file mode 100644 index 0000000..3d2eedd Binary files /dev/null and b/images/icons/dark-grey/weapons/FoamGun.png differ diff --git a/images/icons/dark-grey/weapons/Grenade_01.png b/images/icons/dark-grey/weapons/Grenade_01.png new file mode 100644 index 0000000..fa88f12 Binary files /dev/null and b/images/icons/dark-grey/weapons/Grenade_01.png differ diff --git a/images/icons/dark-grey/weapons/Grenade_02.png b/images/icons/dark-grey/weapons/Grenade_02.png new file mode 100644 index 0000000..d2d06a7 Binary files /dev/null and b/images/icons/dark-grey/weapons/Grenade_02.png differ diff --git a/images/icons/dark-grey/weapons/Grenade_03.png b/images/icons/dark-grey/weapons/Grenade_03.png new file mode 100644 index 0000000..b48aaca Binary files /dev/null and b/images/icons/dark-grey/weapons/Grenade_03.png differ diff --git a/images/icons/dark-grey/weapons/Grenade_04.png b/images/icons/dark-grey/weapons/Grenade_04.png new file mode 100644 index 0000000..79d0c01 Binary files /dev/null and b/images/icons/dark-grey/weapons/Grenade_04.png differ diff --git a/images/icons/dark-grey/weapons/HandWelder_01.png b/images/icons/dark-grey/weapons/HandWelder_01.png new file mode 100644 index 0000000..67b6a7e Binary files /dev/null and b/images/icons/dark-grey/weapons/HandWelder_01.png differ diff --git a/images/icons/dark-grey/weapons/HandWelder_02.png b/images/icons/dark-grey/weapons/HandWelder_02.png new file mode 100644 index 0000000..fa30537 Binary files /dev/null and b/images/icons/dark-grey/weapons/HandWelder_02.png differ diff --git a/images/icons/dark-grey/weapons/Knife.png b/images/icons/dark-grey/weapons/Knife.png new file mode 100644 index 0000000..63a626e Binary files /dev/null and b/images/icons/dark-grey/weapons/Knife.png differ diff --git a/images/icons/dark-grey/weapons/LaserCutter.png b/images/icons/dark-grey/weapons/LaserCutter.png new file mode 100644 index 0000000..4bc846b Binary files /dev/null and b/images/icons/dark-grey/weapons/LaserCutter.png differ diff --git a/images/icons/dark-grey/weapons/MachineGun_01.png b/images/icons/dark-grey/weapons/MachineGun_01.png new file mode 100644 index 0000000..dceb71c Binary files /dev/null and b/images/icons/dark-grey/weapons/MachineGun_01.png differ diff --git a/images/icons/dark-grey/weapons/MachineGun_02.png b/images/icons/dark-grey/weapons/MachineGun_02.png new file mode 100644 index 0000000..5dfcac6 Binary files /dev/null and b/images/icons/dark-grey/weapons/MachineGun_02.png differ diff --git a/images/icons/dark-grey/weapons/NailGun_01.png b/images/icons/dark-grey/weapons/NailGun_01.png new file mode 100644 index 0000000..dac0889 Binary files /dev/null and b/images/icons/dark-grey/weapons/NailGun_01.png differ diff --git a/images/icons/dark-grey/weapons/PulseRifle_01.png b/images/icons/dark-grey/weapons/PulseRifle_01.png new file mode 100644 index 0000000..c7cddaa Binary files /dev/null and b/images/icons/dark-grey/weapons/PulseRifle_01.png differ diff --git a/images/icons/dark-grey/weapons/PulseRifle_02.png b/images/icons/dark-grey/weapons/PulseRifle_02.png new file mode 100644 index 0000000..bfc61be Binary files /dev/null and b/images/icons/dark-grey/weapons/PulseRifle_02.png differ diff --git a/images/icons/dark-grey/weapons/Revolver_01.png b/images/icons/dark-grey/weapons/Revolver_01.png new file mode 100644 index 0000000..2d2ca8b Binary files /dev/null and b/images/icons/dark-grey/weapons/Revolver_01.png differ diff --git a/images/icons/dark-grey/weapons/Revolver_02.png b/images/icons/dark-grey/weapons/Revolver_02.png new file mode 100644 index 0000000..47eefaf Binary files /dev/null and b/images/icons/dark-grey/weapons/Revolver_02.png differ diff --git a/images/icons/dark-grey/weapons/RiggingGun_01.png b/images/icons/dark-grey/weapons/RiggingGun_01.png new file mode 100644 index 0000000..153e976 Binary files /dev/null and b/images/icons/dark-grey/weapons/RiggingGun_01.png differ diff --git a/images/icons/dark-grey/weapons/SMG_01.png b/images/icons/dark-grey/weapons/SMG_01.png new file mode 100644 index 0000000..891524b Binary files /dev/null and b/images/icons/dark-grey/weapons/SMG_01.png differ diff --git a/images/icons/dark-grey/weapons/SMG_02.png b/images/icons/dark-grey/weapons/SMG_02.png new file mode 100644 index 0000000..69daac9 Binary files /dev/null and b/images/icons/dark-grey/weapons/SMG_02.png differ diff --git a/images/icons/dark-grey/weapons/Scalpel.png b/images/icons/dark-grey/weapons/Scalpel.png new file mode 100644 index 0000000..d7a251d Binary files /dev/null and b/images/icons/dark-grey/weapons/Scalpel.png differ diff --git a/images/icons/dark-grey/weapons/Shotgun_01.png b/images/icons/dark-grey/weapons/Shotgun_01.png new file mode 100644 index 0000000..baf4720 Binary files /dev/null and b/images/icons/dark-grey/weapons/Shotgun_01.png differ diff --git a/images/icons/dark-grey/weapons/Shotgun_02.png b/images/icons/dark-grey/weapons/Shotgun_02.png new file mode 100644 index 0000000..1959592 Binary files /dev/null and b/images/icons/dark-grey/weapons/Shotgun_02.png differ diff --git a/images/icons/dark-grey/weapons/Shotgun_03.png b/images/icons/dark-grey/weapons/Shotgun_03.png new file mode 100644 index 0000000..6a1be0d Binary files /dev/null and b/images/icons/dark-grey/weapons/Shotgun_03.png differ diff --git a/images/icons/dark-grey/weapons/Shotgun_04.png b/images/icons/dark-grey/weapons/Shotgun_04.png new file mode 100644 index 0000000..fa671d5 Binary files /dev/null and b/images/icons/dark-grey/weapons/Shotgun_04.png differ diff --git a/images/icons/dark-grey/weapons/Shotgun_05.png b/images/icons/dark-grey/weapons/Shotgun_05.png new file mode 100644 index 0000000..7467824 Binary files /dev/null and b/images/icons/dark-grey/weapons/Shotgun_05.png differ diff --git a/images/icons/dark-grey/weapons/SmartGun_01.png b/images/icons/dark-grey/weapons/SmartGun_01.png new file mode 100644 index 0000000..9e982b8 Binary files /dev/null and b/images/icons/dark-grey/weapons/SmartGun_01.png differ diff --git a/images/icons/dark-grey/weapons/SmartGun_02.png b/images/icons/dark-grey/weapons/SmartGun_02.png new file mode 100644 index 0000000..122c790 Binary files /dev/null and b/images/icons/dark-grey/weapons/SmartGun_02.png differ diff --git a/images/icons/dark-grey/weapons/TranqPistol.png b/images/icons/dark-grey/weapons/TranqPistol.png new file mode 100644 index 0000000..037361c Binary files /dev/null and b/images/icons/dark-grey/weapons/TranqPistol.png differ diff --git a/images/icons/dark-grey/weapons/Unarmed.png b/images/icons/dark-grey/weapons/Unarmed.png new file mode 100644 index 0000000..71600a6 Binary files /dev/null and b/images/icons/dark-grey/weapons/Unarmed.png differ diff --git a/images/icons/dark-grey/weapons/Vibechete.png b/images/icons/dark-grey/weapons/Vibechete.png new file mode 100644 index 0000000..95f8356 Binary files /dev/null and b/images/icons/dark-grey/weapons/Vibechete.png differ diff --git a/images/icons/dark-grey/weapons/Wrench.png b/images/icons/dark-grey/weapons/Wrench.png new file mode 100644 index 0000000..7efab11 Binary files /dev/null and b/images/icons/dark-grey/weapons/Wrench.png differ diff --git a/images/icons/modern_inventory_icons/black/ammunition_b_01.PNG b/images/icons/modern_inventory_icons/black/ammunition_b_01.PNG new file mode 100644 index 0000000..103c61c Binary files /dev/null and b/images/icons/modern_inventory_icons/black/ammunition_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/ammunition_b_02.png b/images/icons/modern_inventory_icons/black/ammunition_b_02.png new file mode 100644 index 0000000..1c4f577 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/ammunition_b_02.png differ diff --git a/images/icons/modern_inventory_icons/black/ammunition_b_03.png b/images/icons/modern_inventory_icons/black/ammunition_b_03.png new file mode 100644 index 0000000..c0f8acb Binary files /dev/null and b/images/icons/modern_inventory_icons/black/ammunition_b_03.png differ diff --git a/images/icons/modern_inventory_icons/black/antidote_b_01.png b/images/icons/modern_inventory_icons/black/antidote_b_01.png new file mode 100644 index 0000000..93baa06 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/antidote_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/awl_b_01.png b/images/icons/modern_inventory_icons/black/awl_b_01.png new file mode 100644 index 0000000..ea6a7ca Binary files /dev/null and b/images/icons/modern_inventory_icons/black/awl_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/axe_b_01.PNG b/images/icons/modern_inventory_icons/black/axe_b_01.PNG new file mode 100644 index 0000000..91b90e7 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/axe_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/bag_b_01.png b/images/icons/modern_inventory_icons/black/bag_b_01.png new file mode 100644 index 0000000..cf136ae Binary files /dev/null and b/images/icons/modern_inventory_icons/black/bag_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/bandages_b_01.png b/images/icons/modern_inventory_icons/black/bandages_b_01.png new file mode 100644 index 0000000..f5eda14 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/bandages_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/barrel_b_01.PNG b/images/icons/modern_inventory_icons/black/barrel_b_01.PNG new file mode 100644 index 0000000..70d93dc Binary files /dev/null and b/images/icons/modern_inventory_icons/black/barrel_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/battery_b_01.png b/images/icons/modern_inventory_icons/black/battery_b_01.png new file mode 100644 index 0000000..b57198e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/battery_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/beer_b_01.PNG b/images/icons/modern_inventory_icons/black/beer_b_01.PNG new file mode 100644 index 0000000..6ea1a28 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/beer_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/bolt_b_01.PNG b/images/icons/modern_inventory_icons/black/bolt_b_01.PNG new file mode 100644 index 0000000..b0faa1e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/bolt_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/book_b_01.PNG b/images/icons/modern_inventory_icons/black/book_b_01.PNG new file mode 100644 index 0000000..792d1c2 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/book_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/bottle_b_01.PNG b/images/icons/modern_inventory_icons/black/bottle_b_01.PNG new file mode 100644 index 0000000..716fa5a Binary files /dev/null and b/images/icons/modern_inventory_icons/black/bottle_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/box_b_01.PNG b/images/icons/modern_inventory_icons/black/box_b_01.PNG new file mode 100644 index 0000000..976c57f Binary files /dev/null and b/images/icons/modern_inventory_icons/black/box_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/box_b_02.PNG b/images/icons/modern_inventory_icons/black/box_b_02.PNG new file mode 100644 index 0000000..c0e90b8 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/box_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/box_b_03.png b/images/icons/modern_inventory_icons/black/box_b_03.png new file mode 100644 index 0000000..8888ab9 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/box_b_03.png differ diff --git a/images/icons/modern_inventory_icons/black/brush_b_01.png b/images/icons/modern_inventory_icons/black/brush_b_01.png new file mode 100644 index 0000000..4897848 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/brush_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/bucket_b_01.png b/images/icons/modern_inventory_icons/black/bucket_b_01.png new file mode 100644 index 0000000..747b705 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/bucket_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/calendar_b_01.PNG b/images/icons/modern_inventory_icons/black/calendar_b_01.PNG new file mode 100644 index 0000000..2b6e609 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/calendar_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/calendar_b_02.PNG b/images/icons/modern_inventory_icons/black/calendar_b_02.PNG new file mode 100644 index 0000000..32b25ad Binary files /dev/null and b/images/icons/modern_inventory_icons/black/calendar_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/cane_b_01.PNG b/images/icons/modern_inventory_icons/black/cane_b_01.PNG new file mode 100644 index 0000000..d33ec89 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/cane_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/cards_b_01.png b/images/icons/modern_inventory_icons/black/cards_b_01.png new file mode 100644 index 0000000..5259bda Binary files /dev/null and b/images/icons/modern_inventory_icons/black/cards_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/chocolate_b_01.PNG b/images/icons/modern_inventory_icons/black/chocolate_b_01.PNG new file mode 100644 index 0000000..271afc5 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/chocolate_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/clew_b_01.PNG b/images/icons/modern_inventory_icons/black/clew_b_01.PNG new file mode 100644 index 0000000..82c888f Binary files /dev/null and b/images/icons/modern_inventory_icons/black/clew_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/club_b_01.png b/images/icons/modern_inventory_icons/black/club_b_01.png new file mode 100644 index 0000000..4b9fa5c Binary files /dev/null and b/images/icons/modern_inventory_icons/black/club_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/corkscrew_b_01.png b/images/icons/modern_inventory_icons/black/corkscrew_b_01.png new file mode 100644 index 0000000..b86d22e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/corkscrew_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/crowbar_b_01.png b/images/icons/modern_inventory_icons/black/crowbar_b_01.png new file mode 100644 index 0000000..832c1cb Binary files /dev/null and b/images/icons/modern_inventory_icons/black/crowbar_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/donut_b_01.png b/images/icons/modern_inventory_icons/black/donut_b_01.png new file mode 100644 index 0000000..3e6049e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/donut_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/dynamite_b_01.png b/images/icons/modern_inventory_icons/black/dynamite_b_01.png new file mode 100644 index 0000000..7608441 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/dynamite_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/extinguisher_b_01.png b/images/icons/modern_inventory_icons/black/extinguisher_b_01.png new file mode 100644 index 0000000..9ab01bc Binary files /dev/null and b/images/icons/modern_inventory_icons/black/extinguisher_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/fertilizers_b_01.PNG b/images/icons/modern_inventory_icons/black/fertilizers_b_01.PNG new file mode 100644 index 0000000..1445f93 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/fertilizers_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/flash_drive_b_02.PNG b/images/icons/modern_inventory_icons/black/flash_drive_b_02.PNG new file mode 100644 index 0000000..4b12dcf Binary files /dev/null and b/images/icons/modern_inventory_icons/black/flash_drive_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/flashlight_b_01.PNG b/images/icons/modern_inventory_icons/black/flashlight_b_01.PNG new file mode 100644 index 0000000..cb9e03d Binary files /dev/null and b/images/icons/modern_inventory_icons/black/flashlight_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/flask_b_01.PNG b/images/icons/modern_inventory_icons/black/flask_b_01.PNG new file mode 100644 index 0000000..815b491 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/flask_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/flask_b_02.PNG b/images/icons/modern_inventory_icons/black/flask_b_02.PNG new file mode 100644 index 0000000..229e587 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/flask_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/gaff_b_01.png b/images/icons/modern_inventory_icons/black/gaff_b_01.png new file mode 100644 index 0000000..1a91b78 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/gaff_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/gears_b_01.png b/images/icons/modern_inventory_icons/black/gears_b_01.png new file mode 100644 index 0000000..f85bbae Binary files /dev/null and b/images/icons/modern_inventory_icons/black/gears_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/gift_b_01.png b/images/icons/modern_inventory_icons/black/gift_b_01.png new file mode 100644 index 0000000..48bedb0 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/gift_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/glasses_b_01.PNG b/images/icons/modern_inventory_icons/black/glasses_b_01.PNG new file mode 100644 index 0000000..2b02d0e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/glasses_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/gun_b_01.png b/images/icons/modern_inventory_icons/black/gun_b_01.png new file mode 100644 index 0000000..b178c98 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/gun_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/hammer_b_01.PNG b/images/icons/modern_inventory_icons/black/hammer_b_01.PNG new file mode 100644 index 0000000..0b9a412 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/hammer_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/helmet_b_01.PNG b/images/icons/modern_inventory_icons/black/helmet_b_01.PNG new file mode 100644 index 0000000..9098731 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/helmet_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/insulating_tape_b_01.png b/images/icons/modern_inventory_icons/black/insulating_tape_b_01.png new file mode 100644 index 0000000..5c5bf59 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/insulating_tape_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/jerrycan_b_01.PNG b/images/icons/modern_inventory_icons/black/jerrycan_b_01.PNG new file mode 100644 index 0000000..3b11308 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/jerrycan_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/key_b_01.png b/images/icons/modern_inventory_icons/black/key_b_01.png new file mode 100644 index 0000000..1403e53 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/key_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/key_b_02.png b/images/icons/modern_inventory_icons/black/key_b_02.png new file mode 100644 index 0000000..24b97b1 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/key_b_02.png differ diff --git a/images/icons/modern_inventory_icons/black/key_b_03.png b/images/icons/modern_inventory_icons/black/key_b_03.png new file mode 100644 index 0000000..2e7dcd3 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/key_b_03.png differ diff --git a/images/icons/modern_inventory_icons/black/key_b_04.png b/images/icons/modern_inventory_icons/black/key_b_04.png new file mode 100644 index 0000000..56ad5e9 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/key_b_04.png differ diff --git a/images/icons/modern_inventory_icons/black/key_b_05.png b/images/icons/modern_inventory_icons/black/key_b_05.png new file mode 100644 index 0000000..7b990ab Binary files /dev/null and b/images/icons/modern_inventory_icons/black/key_b_05.png differ diff --git a/images/icons/modern_inventory_icons/black/knife_b_01.PNG b/images/icons/modern_inventory_icons/black/knife_b_01.PNG new file mode 100644 index 0000000..cc2cb4a Binary files /dev/null and b/images/icons/modern_inventory_icons/black/knife_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/knife_b_02.PNG b/images/icons/modern_inventory_icons/black/knife_b_02.PNG new file mode 100644 index 0000000..018aa17 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/knife_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/letter_b_01.png b/images/icons/modern_inventory_icons/black/letter_b_01.png new file mode 100644 index 0000000..d76c7fd Binary files /dev/null and b/images/icons/modern_inventory_icons/black/letter_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/lightbulb_b_01.PNG b/images/icons/modern_inventory_icons/black/lightbulb_b_01.PNG new file mode 100644 index 0000000..1fab035 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/lightbulb_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/lighter_b_01.png b/images/icons/modern_inventory_icons/black/lighter_b_01.png new file mode 100644 index 0000000..9bdc4d1 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/lighter_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/magnifier_b_01.png b/images/icons/modern_inventory_icons/black/magnifier_b_01.png new file mode 100644 index 0000000..e6ac9c3 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/magnifier_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/medicine_b_01.png b/images/icons/modern_inventory_icons/black/medicine_b_01.png new file mode 100644 index 0000000..61c395d Binary files /dev/null and b/images/icons/modern_inventory_icons/black/medicine_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/medicine_chest_b_01.PNG b/images/icons/modern_inventory_icons/black/medicine_chest_b_01.PNG new file mode 100644 index 0000000..85b5a5e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/medicine_chest_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/money_b_01.PNG b/images/icons/modern_inventory_icons/black/money_b_01.PNG new file mode 100644 index 0000000..119e523 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/money_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/mouthpiece_b_01.PNG b/images/icons/modern_inventory_icons/black/mouthpiece_b_01.PNG new file mode 100644 index 0000000..3dde4ef Binary files /dev/null and b/images/icons/modern_inventory_icons/black/mouthpiece_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/nail_b_01.PNG b/images/icons/modern_inventory_icons/black/nail_b_01.PNG new file mode 100644 index 0000000..950ea63 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/nail_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/needle_b_01.png b/images/icons/modern_inventory_icons/black/needle_b_01.png new file mode 100644 index 0000000..b01be98 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/needle_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/nippers_b_01.png b/images/icons/modern_inventory_icons/black/nippers_b_01.png new file mode 100644 index 0000000..01afe12 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/nippers_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/note_b_01.PNG b/images/icons/modern_inventory_icons/black/note_b_01.PNG new file mode 100644 index 0000000..6d9b0f1 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/note_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/note_b_02.PNG b/images/icons/modern_inventory_icons/black/note_b_02.PNG new file mode 100644 index 0000000..f6b6bf2 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/note_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/nut_b_01.png b/images/icons/modern_inventory_icons/black/nut_b_01.png new file mode 100644 index 0000000..fe6f923 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/nut_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/packaging_b_01.PNG b/images/icons/modern_inventory_icons/black/packaging_b_01.PNG new file mode 100644 index 0000000..6a30127 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/packaging_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/pad_b_01.PNG b/images/icons/modern_inventory_icons/black/pad_b_01.PNG new file mode 100644 index 0000000..8f41110 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pad_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/pass_b_01.png b/images/icons/modern_inventory_icons/black/pass_b_01.png new file mode 100644 index 0000000..a3f77e2 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pass_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/passport_b_01.PNG b/images/icons/modern_inventory_icons/black/passport_b_01.PNG new file mode 100644 index 0000000..34c46fd Binary files /dev/null and b/images/icons/modern_inventory_icons/black/passport_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/patch_b_01.png b/images/icons/modern_inventory_icons/black/patch_b_01.png new file mode 100644 index 0000000..cb2d1ee Binary files /dev/null and b/images/icons/modern_inventory_icons/black/patch_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/pencil_b_01.png b/images/icons/modern_inventory_icons/black/pencil_b_01.png new file mode 100644 index 0000000..0419229 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pencil_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/phone_b_01.PNG b/images/icons/modern_inventory_icons/black/phone_b_01.PNG new file mode 100644 index 0000000..722693e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/phone_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/pills_b_01.png b/images/icons/modern_inventory_icons/black/pills_b_01.png new file mode 100644 index 0000000..dd8baf7 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pills_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/pills_b_02.png b/images/icons/modern_inventory_icons/black/pills_b_02.png new file mode 100644 index 0000000..de4c3a4 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pills_b_02.png differ diff --git a/images/icons/modern_inventory_icons/black/pills_b_03.png b/images/icons/modern_inventory_icons/black/pills_b_03.png new file mode 100644 index 0000000..00db94f Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pills_b_03.png differ diff --git a/images/icons/modern_inventory_icons/black/pin_b_01.png b/images/icons/modern_inventory_icons/black/pin_b_01.png new file mode 100644 index 0000000..1f213ee Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pin_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/pipe_b_01.PNG b/images/icons/modern_inventory_icons/black/pipe_b_01.PNG new file mode 100644 index 0000000..78df451 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pipe_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/plant_b_01.png b/images/icons/modern_inventory_icons/black/plant_b_01.png new file mode 100644 index 0000000..01c808b Binary files /dev/null and b/images/icons/modern_inventory_icons/black/plant_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/pot_b_01.png b/images/icons/modern_inventory_icons/black/pot_b_01.png new file mode 100644 index 0000000..6da6d1d Binary files /dev/null and b/images/icons/modern_inventory_icons/black/pot_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/print_b_01.png b/images/icons/modern_inventory_icons/black/print_b_01.png new file mode 100644 index 0000000..1ed690e Binary files /dev/null and b/images/icons/modern_inventory_icons/black/print_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/rag_b_01.png b/images/icons/modern_inventory_icons/black/rag_b_01.png new file mode 100644 index 0000000..f4526c2 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/rag_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/rake_b_01.PNG b/images/icons/modern_inventory_icons/black/rake_b_01.PNG new file mode 100644 index 0000000..c6082ce Binary files /dev/null and b/images/icons/modern_inventory_icons/black/rake_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/rasp_b_01.PNG b/images/icons/modern_inventory_icons/black/rasp_b_01.PNG new file mode 100644 index 0000000..4a7ec88 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/rasp_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/razor_b_01.PNG b/images/icons/modern_inventory_icons/black/razor_b_01.PNG new file mode 100644 index 0000000..e287261 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/razor_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/razor_b_02.PNG b/images/icons/modern_inventory_icons/black/razor_b_02.PNG new file mode 100644 index 0000000..6030dba Binary files /dev/null and b/images/icons/modern_inventory_icons/black/razor_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/ring_b_01.PNG b/images/icons/modern_inventory_icons/black/ring_b_01.PNG new file mode 100644 index 0000000..3d15d02 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/ring_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/rope_b_01.png b/images/icons/modern_inventory_icons/black/rope_b_01.png new file mode 100644 index 0000000..02c7bbf Binary files /dev/null and b/images/icons/modern_inventory_icons/black/rope_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/saw_b_01.PNG b/images/icons/modern_inventory_icons/black/saw_b_01.PNG new file mode 100644 index 0000000..0e73f43 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/saw_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/screw_b_01.PNG b/images/icons/modern_inventory_icons/black/screw_b_01.PNG new file mode 100644 index 0000000..785fedc Binary files /dev/null and b/images/icons/modern_inventory_icons/black/screw_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/shovel_b_01.PNG b/images/icons/modern_inventory_icons/black/shovel_b_01.PNG new file mode 100644 index 0000000..9b1993a Binary files /dev/null and b/images/icons/modern_inventory_icons/black/shovel_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/soda_b_01.PNG b/images/icons/modern_inventory_icons/black/soda_b_01.PNG new file mode 100644 index 0000000..c290114 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/soda_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/spring_b_01.png b/images/icons/modern_inventory_icons/black/spring_b_01.png new file mode 100644 index 0000000..cdee37f Binary files /dev/null and b/images/icons/modern_inventory_icons/black/spring_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/stairs_b_01.png b/images/icons/modern_inventory_icons/black/stairs_b_01.png new file mode 100644 index 0000000..7ed9064 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/stairs_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/syringe_b_01.png b/images/icons/modern_inventory_icons/black/syringe_b_01.png new file mode 100644 index 0000000..92a60a3 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/syringe_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/tape_b_01.png b/images/icons/modern_inventory_icons/black/tape_b_01.png new file mode 100644 index 0000000..6324899 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/tape_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/tomato_soup_b_01.PNG b/images/icons/modern_inventory_icons/black/tomato_soup_b_01.PNG new file mode 100644 index 0000000..d62b3a7 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/tomato_soup_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/trowel_b_01.PNG b/images/icons/modern_inventory_icons/black/trowel_b_01.PNG new file mode 100644 index 0000000..51a9e39 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/trowel_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/watch_b_01.png b/images/icons/modern_inventory_icons/black/watch_b_01.png new file mode 100644 index 0000000..9355f85 Binary files /dev/null and b/images/icons/modern_inventory_icons/black/watch_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/water_b_01.png b/images/icons/modern_inventory_icons/black/water_b_01.png new file mode 100644 index 0000000..e9cdf8d Binary files /dev/null and b/images/icons/modern_inventory_icons/black/water_b_01.png differ diff --git a/images/icons/modern_inventory_icons/black/whistle_b_01.PNG b/images/icons/modern_inventory_icons/black/whistle_b_01.PNG new file mode 100644 index 0000000..232de2c Binary files /dev/null and b/images/icons/modern_inventory_icons/black/whistle_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/wire_b_01.PNG b/images/icons/modern_inventory_icons/black/wire_b_01.PNG new file mode 100644 index 0000000..815012f Binary files /dev/null and b/images/icons/modern_inventory_icons/black/wire_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/black/wire_b_02.PNG b/images/icons/modern_inventory_icons/black/wire_b_02.PNG new file mode 100644 index 0000000..e4c393b Binary files /dev/null and b/images/icons/modern_inventory_icons/black/wire_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/black/wrench_b_01.PNG b/images/icons/modern_inventory_icons/black/wrench_b_01.PNG new file mode 100644 index 0000000..ed6480f Binary files /dev/null and b/images/icons/modern_inventory_icons/black/wrench_b_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/ammunition_t_01.PNG b/images/icons/modern_inventory_icons/transparent/ammunition_t_01.PNG new file mode 100644 index 0000000..7338617 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/ammunition_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/ammunition_t_02.png b/images/icons/modern_inventory_icons/transparent/ammunition_t_02.png new file mode 100644 index 0000000..64a2718 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/ammunition_t_02.png differ diff --git a/images/icons/modern_inventory_icons/transparent/ammunition_t_03.png b/images/icons/modern_inventory_icons/transparent/ammunition_t_03.png new file mode 100644 index 0000000..28e53d9 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/ammunition_t_03.png differ diff --git a/images/icons/modern_inventory_icons/transparent/antidote_t_01.png b/images/icons/modern_inventory_icons/transparent/antidote_t_01.png new file mode 100644 index 0000000..7ead683 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/antidote_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/awl_t_01.png b/images/icons/modern_inventory_icons/transparent/awl_t_01.png new file mode 100644 index 0000000..edd3d95 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/awl_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/axe_t_01.PNG b/images/icons/modern_inventory_icons/transparent/axe_t_01.PNG new file mode 100644 index 0000000..a66b8ec Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/axe_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/bag_t_01.png b/images/icons/modern_inventory_icons/transparent/bag_t_01.png new file mode 100644 index 0000000..23f976f Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/bag_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/bandages_t_01.png b/images/icons/modern_inventory_icons/transparent/bandages_t_01.png new file mode 100644 index 0000000..bd5b56f Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/bandages_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/barrel_b_02.PNG b/images/icons/modern_inventory_icons/transparent/barrel_b_02.PNG new file mode 100644 index 0000000..370deae Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/barrel_b_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/battery_t_01.png b/images/icons/modern_inventory_icons/transparent/battery_t_01.png new file mode 100644 index 0000000..4d608ce Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/battery_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/beer_t_01.PNG b/images/icons/modern_inventory_icons/transparent/beer_t_01.PNG new file mode 100644 index 0000000..917bf49 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/beer_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/bolt_t_01.PNG b/images/icons/modern_inventory_icons/transparent/bolt_t_01.PNG new file mode 100644 index 0000000..018d0c5 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/bolt_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/book_t_01.PNG b/images/icons/modern_inventory_icons/transparent/book_t_01.PNG new file mode 100644 index 0000000..53f9102 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/book_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/bottle_t_01.PNG b/images/icons/modern_inventory_icons/transparent/bottle_t_01.PNG new file mode 100644 index 0000000..925b0b1 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/bottle_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/box_t_01.PNG b/images/icons/modern_inventory_icons/transparent/box_t_01.PNG new file mode 100644 index 0000000..0cfb2fb Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/box_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/box_t_02.PNG b/images/icons/modern_inventory_icons/transparent/box_t_02.PNG new file mode 100644 index 0000000..d0af39c Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/box_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/box_t_03.png b/images/icons/modern_inventory_icons/transparent/box_t_03.png new file mode 100644 index 0000000..fe53aff Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/box_t_03.png differ diff --git a/images/icons/modern_inventory_icons/transparent/brush_t_01.png b/images/icons/modern_inventory_icons/transparent/brush_t_01.png new file mode 100644 index 0000000..f6b8f2d Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/brush_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/bucket_t_01.png b/images/icons/modern_inventory_icons/transparent/bucket_t_01.png new file mode 100644 index 0000000..35e714d Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/bucket_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/calendar_t_01.PNG b/images/icons/modern_inventory_icons/transparent/calendar_t_01.PNG new file mode 100644 index 0000000..94d00c9 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/calendar_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/calendar_t_02.PNG b/images/icons/modern_inventory_icons/transparent/calendar_t_02.PNG new file mode 100644 index 0000000..6ecc79a Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/calendar_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/cane_t_01.PNG b/images/icons/modern_inventory_icons/transparent/cane_t_01.PNG new file mode 100644 index 0000000..ddcdac5 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/cane_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/cards_t_01.png b/images/icons/modern_inventory_icons/transparent/cards_t_01.png new file mode 100644 index 0000000..92368ee Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/cards_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/chocolate_t_01.PNG b/images/icons/modern_inventory_icons/transparent/chocolate_t_01.PNG new file mode 100644 index 0000000..4029881 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/chocolate_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/clew_t_01.PNG b/images/icons/modern_inventory_icons/transparent/clew_t_01.PNG new file mode 100644 index 0000000..c2b5591 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/clew_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/club_t_01.png b/images/icons/modern_inventory_icons/transparent/club_t_01.png new file mode 100644 index 0000000..96ed48e Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/club_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/corkscrew_t_01.png b/images/icons/modern_inventory_icons/transparent/corkscrew_t_01.png new file mode 100644 index 0000000..b331f56 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/corkscrew_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/crowbar_t_01.png b/images/icons/modern_inventory_icons/transparent/crowbar_t_01.png new file mode 100644 index 0000000..7d53703 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/crowbar_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/donut_t_01.png b/images/icons/modern_inventory_icons/transparent/donut_t_01.png new file mode 100644 index 0000000..2e2945b Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/donut_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/dynamite_t_01.png b/images/icons/modern_inventory_icons/transparent/dynamite_t_01.png new file mode 100644 index 0000000..d5864d0 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/dynamite_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/extinguisher_t_01.png b/images/icons/modern_inventory_icons/transparent/extinguisher_t_01.png new file mode 100644 index 0000000..533413e Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/extinguisher_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/fertilizers_t_01.PNG b/images/icons/modern_inventory_icons/transparent/fertilizers_t_01.PNG new file mode 100644 index 0000000..25b67c8 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/fertilizers_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/flash_drive_t_02.PNG b/images/icons/modern_inventory_icons/transparent/flash_drive_t_02.PNG new file mode 100644 index 0000000..0cb504b Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/flash_drive_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/flashlight_t_01.PNG b/images/icons/modern_inventory_icons/transparent/flashlight_t_01.PNG new file mode 100644 index 0000000..1e39115 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/flashlight_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/flask_t_01.PNG b/images/icons/modern_inventory_icons/transparent/flask_t_01.PNG new file mode 100644 index 0000000..cf10b87 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/flask_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/flask_t_02.PNG b/images/icons/modern_inventory_icons/transparent/flask_t_02.PNG new file mode 100644 index 0000000..b6eec31 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/flask_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/gaff_t_01.png b/images/icons/modern_inventory_icons/transparent/gaff_t_01.png new file mode 100644 index 0000000..cb9aa7f Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/gaff_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/gears_t_01.png b/images/icons/modern_inventory_icons/transparent/gears_t_01.png new file mode 100644 index 0000000..c45b60a Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/gears_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/gift_t_01.png b/images/icons/modern_inventory_icons/transparent/gift_t_01.png new file mode 100644 index 0000000..6e4365e Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/gift_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/glasses_t_01.PNG b/images/icons/modern_inventory_icons/transparent/glasses_t_01.PNG new file mode 100644 index 0000000..f1a7f16 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/glasses_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/gun_t_01.png b/images/icons/modern_inventory_icons/transparent/gun_t_01.png new file mode 100644 index 0000000..6bab046 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/gun_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/hammer_t_01.PNG b/images/icons/modern_inventory_icons/transparent/hammer_t_01.PNG new file mode 100644 index 0000000..f899081 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/hammer_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/helmet_t_01.PNG b/images/icons/modern_inventory_icons/transparent/helmet_t_01.PNG new file mode 100644 index 0000000..af1663f Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/helmet_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/insulating_tape_t_01.png b/images/icons/modern_inventory_icons/transparent/insulating_tape_t_01.png new file mode 100644 index 0000000..e614df6 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/insulating_tape_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/jerrycan_t_01.PNG b/images/icons/modern_inventory_icons/transparent/jerrycan_t_01.PNG new file mode 100644 index 0000000..e119a42 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/jerrycan_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/key_t_01.png b/images/icons/modern_inventory_icons/transparent/key_t_01.png new file mode 100644 index 0000000..ba2569d Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/key_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/key_t_02.png b/images/icons/modern_inventory_icons/transparent/key_t_02.png new file mode 100644 index 0000000..dca6452 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/key_t_02.png differ diff --git a/images/icons/modern_inventory_icons/transparent/key_t_03.png b/images/icons/modern_inventory_icons/transparent/key_t_03.png new file mode 100644 index 0000000..cbbb0d8 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/key_t_03.png differ diff --git a/images/icons/modern_inventory_icons/transparent/key_t_04.png b/images/icons/modern_inventory_icons/transparent/key_t_04.png new file mode 100644 index 0000000..1bebf54 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/key_t_04.png differ diff --git a/images/icons/modern_inventory_icons/transparent/key_t_05.png b/images/icons/modern_inventory_icons/transparent/key_t_05.png new file mode 100644 index 0000000..f328c04 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/key_t_05.png differ diff --git a/images/icons/modern_inventory_icons/transparent/knife_t_01.PNG b/images/icons/modern_inventory_icons/transparent/knife_t_01.PNG new file mode 100644 index 0000000..13ea9ca Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/knife_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/knife_t_02.PNG b/images/icons/modern_inventory_icons/transparent/knife_t_02.PNG new file mode 100644 index 0000000..29df08a Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/knife_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/letter_t_01.png b/images/icons/modern_inventory_icons/transparent/letter_t_01.png new file mode 100644 index 0000000..812921e Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/letter_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/lightbulb_t_01.PNG b/images/icons/modern_inventory_icons/transparent/lightbulb_t_01.PNG new file mode 100644 index 0000000..df240d2 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/lightbulb_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/lighter_t_01.png b/images/icons/modern_inventory_icons/transparent/lighter_t_01.png new file mode 100644 index 0000000..e178df1 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/lighter_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/magnifier_t_01.png b/images/icons/modern_inventory_icons/transparent/magnifier_t_01.png new file mode 100644 index 0000000..2f74be7 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/magnifier_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/medicine_chest_t_01.PNG b/images/icons/modern_inventory_icons/transparent/medicine_chest_t_01.PNG new file mode 100644 index 0000000..dfcbd03 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/medicine_chest_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/medicine_t_01.png b/images/icons/modern_inventory_icons/transparent/medicine_t_01.png new file mode 100644 index 0000000..0c4c49b Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/medicine_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/money_t_01.PNG b/images/icons/modern_inventory_icons/transparent/money_t_01.PNG new file mode 100644 index 0000000..9017c77 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/money_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/mouthpiece_t_01.PNG b/images/icons/modern_inventory_icons/transparent/mouthpiece_t_01.PNG new file mode 100644 index 0000000..f246da1 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/mouthpiece_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/nail_t_01.PNG b/images/icons/modern_inventory_icons/transparent/nail_t_01.PNG new file mode 100644 index 0000000..6d7c654 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/nail_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/needle_t_01.png b/images/icons/modern_inventory_icons/transparent/needle_t_01.png new file mode 100644 index 0000000..3f7ff4b Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/needle_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/nippers_t_01.png b/images/icons/modern_inventory_icons/transparent/nippers_t_01.png new file mode 100644 index 0000000..db7b5d2 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/nippers_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/note_t_01.PNG b/images/icons/modern_inventory_icons/transparent/note_t_01.PNG new file mode 100644 index 0000000..13aaa12 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/note_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/note_t_02.PNG b/images/icons/modern_inventory_icons/transparent/note_t_02.PNG new file mode 100644 index 0000000..e901211 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/note_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/nut_t_01.png b/images/icons/modern_inventory_icons/transparent/nut_t_01.png new file mode 100644 index 0000000..c87dac7 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/nut_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/packaging_t_01.PNG b/images/icons/modern_inventory_icons/transparent/packaging_t_01.PNG new file mode 100644 index 0000000..ddae9a8 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/packaging_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/pad_t_01.PNG b/images/icons/modern_inventory_icons/transparent/pad_t_01.PNG new file mode 100644 index 0000000..858e8d8 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pad_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/pass_t_01.png b/images/icons/modern_inventory_icons/transparent/pass_t_01.png new file mode 100644 index 0000000..a37264a Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pass_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/passport_t_01.PNG b/images/icons/modern_inventory_icons/transparent/passport_t_01.PNG new file mode 100644 index 0000000..636a17d Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/passport_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/patch_t_01.png b/images/icons/modern_inventory_icons/transparent/patch_t_01.png new file mode 100644 index 0000000..c1db076 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/patch_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/pencil_t_01.png b/images/icons/modern_inventory_icons/transparent/pencil_t_01.png new file mode 100644 index 0000000..edfad7c Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pencil_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/phone_t_01.PNG b/images/icons/modern_inventory_icons/transparent/phone_t_01.PNG new file mode 100644 index 0000000..e51636a Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/phone_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/pills_t_01.png b/images/icons/modern_inventory_icons/transparent/pills_t_01.png new file mode 100644 index 0000000..07058e9 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pills_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/pills_t_02.png b/images/icons/modern_inventory_icons/transparent/pills_t_02.png new file mode 100644 index 0000000..e36139d Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pills_t_02.png differ diff --git a/images/icons/modern_inventory_icons/transparent/pills_t_03.png b/images/icons/modern_inventory_icons/transparent/pills_t_03.png new file mode 100644 index 0000000..69c0be8 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pills_t_03.png differ diff --git a/images/icons/modern_inventory_icons/transparent/pin_t_01.png b/images/icons/modern_inventory_icons/transparent/pin_t_01.png new file mode 100644 index 0000000..7a9204c Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pin_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/pipe_t_01.PNG b/images/icons/modern_inventory_icons/transparent/pipe_t_01.PNG new file mode 100644 index 0000000..242e6b6 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pipe_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/plant_t_01.png b/images/icons/modern_inventory_icons/transparent/plant_t_01.png new file mode 100644 index 0000000..84f4a26 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/plant_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/pot_t_01.png b/images/icons/modern_inventory_icons/transparent/pot_t_01.png new file mode 100644 index 0000000..88ec04b Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/pot_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/print_t_01.png b/images/icons/modern_inventory_icons/transparent/print_t_01.png new file mode 100644 index 0000000..aefae10 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/print_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/rag_t_01.png b/images/icons/modern_inventory_icons/transparent/rag_t_01.png new file mode 100644 index 0000000..9f14cb8 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/rag_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/rake_t_01.PNG b/images/icons/modern_inventory_icons/transparent/rake_t_01.PNG new file mode 100644 index 0000000..d953307 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/rake_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/rasp_t_01.PNG b/images/icons/modern_inventory_icons/transparent/rasp_t_01.PNG new file mode 100644 index 0000000..dc69dc9 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/rasp_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/razor_t_01.PNG b/images/icons/modern_inventory_icons/transparent/razor_t_01.PNG new file mode 100644 index 0000000..a9cafbe Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/razor_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/razor_t_02.PNG b/images/icons/modern_inventory_icons/transparent/razor_t_02.PNG new file mode 100644 index 0000000..2867a28 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/razor_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/ring_t_01.PNG b/images/icons/modern_inventory_icons/transparent/ring_t_01.PNG new file mode 100644 index 0000000..d2b7e63 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/ring_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/rope_t_01.png b/images/icons/modern_inventory_icons/transparent/rope_t_01.png new file mode 100644 index 0000000..aabfa68 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/rope_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/saw_t_01.PNG b/images/icons/modern_inventory_icons/transparent/saw_t_01.PNG new file mode 100644 index 0000000..56da470 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/saw_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/screw_t_01.PNG b/images/icons/modern_inventory_icons/transparent/screw_t_01.PNG new file mode 100644 index 0000000..be37761 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/screw_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/shovel_t_01.PNG b/images/icons/modern_inventory_icons/transparent/shovel_t_01.PNG new file mode 100644 index 0000000..aa71188 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/shovel_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/soda_t_01.PNG b/images/icons/modern_inventory_icons/transparent/soda_t_01.PNG new file mode 100644 index 0000000..ca7f16a Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/soda_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/spring_t_01.png b/images/icons/modern_inventory_icons/transparent/spring_t_01.png new file mode 100644 index 0000000..8da36b3 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/spring_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/stairs_t_01.png b/images/icons/modern_inventory_icons/transparent/stairs_t_01.png new file mode 100644 index 0000000..537b388 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/stairs_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/syringe_t_01.png b/images/icons/modern_inventory_icons/transparent/syringe_t_01.png new file mode 100644 index 0000000..28e7468 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/syringe_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/tape_t_01.png b/images/icons/modern_inventory_icons/transparent/tape_t_01.png new file mode 100644 index 0000000..7495b15 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/tape_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/tomato_soup_t_01.PNG b/images/icons/modern_inventory_icons/transparent/tomato_soup_t_01.PNG new file mode 100644 index 0000000..61485db Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/tomato_soup_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/trowel_t_01.PNG b/images/icons/modern_inventory_icons/transparent/trowel_t_01.PNG new file mode 100644 index 0000000..9ddf2c6 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/trowel_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/watch_t_01.png b/images/icons/modern_inventory_icons/transparent/watch_t_01.png new file mode 100644 index 0000000..1f5bf35 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/watch_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/water_t_01.png b/images/icons/modern_inventory_icons/transparent/water_t_01.png new file mode 100644 index 0000000..cb86511 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/water_t_01.png differ diff --git a/images/icons/modern_inventory_icons/transparent/whistle_t_01.PNG b/images/icons/modern_inventory_icons/transparent/whistle_t_01.PNG new file mode 100644 index 0000000..782b8ff Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/whistle_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/wire_t_01.PNG b/images/icons/modern_inventory_icons/transparent/wire_t_01.PNG new file mode 100644 index 0000000..48f00bd Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/wire_t_01.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/wire_t_02.PNG b/images/icons/modern_inventory_icons/transparent/wire_t_02.PNG new file mode 100644 index 0000000..63f5014 Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/wire_t_02.PNG differ diff --git a/images/icons/modern_inventory_icons/transparent/wrench_t_01.PNG b/images/icons/modern_inventory_icons/transparent/wrench_t_01.PNG new file mode 100644 index 0000000..82ad54e Binary files /dev/null and b/images/icons/modern_inventory_icons/transparent/wrench_t_01.PNG differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s01.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s01.png new file mode 100644 index 0000000..56cb359 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s02.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s02.png new file mode 100644 index 0000000..8b82c97 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s03.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s03.png new file mode 100644 index 0000000..46cb50e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s04.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s04.png new file mode 100644 index 0000000..bee8e06 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s05.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s05.png new file mode 100644 index 0000000..d69dc33 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s06.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s06.png new file mode 100644 index 0000000..3841e14 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s07.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s07.png new file mode 100644 index 0000000..cfebc71 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s08.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s08.png new file mode 100644 index 0000000..d2e99ec Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s09.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s09.png new file mode 100644 index 0000000..89da0d2 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/ammunition_s10.png b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s10.png new file mode 100644 index 0000000..01c0dfd Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/ammunition_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s01.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s01.png new file mode 100644 index 0000000..8949630 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s02.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s02.png new file mode 100644 index 0000000..65d17d1 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s03.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s03.png new file mode 100644 index 0000000..4eb4d3f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s04.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s04.png new file mode 100644 index 0000000..cb211b4 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s05.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s05.png new file mode 100644 index 0000000..85e6df9 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s06.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s06.png new file mode 100644 index 0000000..60e3d2d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s07.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s07.png new file mode 100644 index 0000000..91ed0a9 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s08.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s08.png new file mode 100644 index 0000000..464d3c1 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s09.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s09.png new file mode 100644 index 0000000..2839d9f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/armor_s10.png b/images/icons/sci-fi_armor_icons_png/bg/armor_s10.png new file mode 100644 index 0000000..16a24d0 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/armor_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s01.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s01.png new file mode 100644 index 0000000..bd0c539 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s02.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s02.png new file mode 100644 index 0000000..0845c9c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s03.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s03.png new file mode 100644 index 0000000..47bfd92 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s04.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s04.png new file mode 100644 index 0000000..62ac7e2 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s05.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s05.png new file mode 100644 index 0000000..dffcc97 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s06.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s06.png new file mode 100644 index 0000000..ff29890 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s07.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s07.png new file mode 100644 index 0000000..1729a1e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s08.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s08.png new file mode 100644 index 0000000..68dd0d0 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s09.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s09.png new file mode 100644 index 0000000..d62165c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/belt_s10.png b/images/icons/sci-fi_armor_icons_png/bg/belt_s10.png new file mode 100644 index 0000000..5a6dadf Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/belt_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s01.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s01.png new file mode 100644 index 0000000..2acc2f6 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s02.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s02.png new file mode 100644 index 0000000..219bd4f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s03.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s03.png new file mode 100644 index 0000000..06ac1be Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s04.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s04.png new file mode 100644 index 0000000..e39fd42 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s05.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s05.png new file mode 100644 index 0000000..b3c6bc4 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s06.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s06.png new file mode 100644 index 0000000..1cb8a4a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s07.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s07.png new file mode 100644 index 0000000..0673815 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s08.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s08.png new file mode 100644 index 0000000..0a2cbbb Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s09.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s09.png new file mode 100644 index 0000000..fd1a181 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/boots_s10.png b/images/icons/sci-fi_armor_icons_png/bg/boots_s10.png new file mode 100644 index 0000000..8108d9f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/boots_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s01.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s01.png new file mode 100644 index 0000000..2cf7051 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s02.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s02.png new file mode 100644 index 0000000..7211b85 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s03.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s03.png new file mode 100644 index 0000000..e125c79 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s04.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s04.png new file mode 100644 index 0000000..194f724 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s05.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s05.png new file mode 100644 index 0000000..7f4a008 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s06.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s06.png new file mode 100644 index 0000000..b1f943e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s07.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s07.png new file mode 100644 index 0000000..7c8dd4c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s08.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s08.png new file mode 100644 index 0000000..5c64ea3 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s09.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s09.png new file mode 100644 index 0000000..4aa675a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/bracers_s10.png b/images/icons/sci-fi_armor_icons_png/bg/bracers_s10.png new file mode 100644 index 0000000..d2890df Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/bracers_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s01.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s01.png new file mode 100644 index 0000000..1a3aed6 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s02.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s02.png new file mode 100644 index 0000000..5678d4d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s03.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s03.png new file mode 100644 index 0000000..a3a3108 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s04.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s04.png new file mode 100644 index 0000000..c243b5a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s05.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s05.png new file mode 100644 index 0000000..7cb1f16 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s06.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s06.png new file mode 100644 index 0000000..7a96f35 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s07.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s07.png new file mode 100644 index 0000000..209a63d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s08.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s08.png new file mode 100644 index 0000000..6429cb1 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s09.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s09.png new file mode 100644 index 0000000..d6292e1 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/gloves_s10.png b/images/icons/sci-fi_armor_icons_png/bg/gloves_s10.png new file mode 100644 index 0000000..2176b9a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/gloves_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s01.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s01.png new file mode 100644 index 0000000..9adc54f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s02.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s02.png new file mode 100644 index 0000000..e0de9aa Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s03.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s03.png new file mode 100644 index 0000000..d8f7007 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s04.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s04.png new file mode 100644 index 0000000..2987a7d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s05.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s05.png new file mode 100644 index 0000000..a3ec832 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s06.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s06.png new file mode 100644 index 0000000..6f7ebb4 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s07.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s07.png new file mode 100644 index 0000000..b4fb051 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s08.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s08.png new file mode 100644 index 0000000..dd2f75f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s09.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s09.png new file mode 100644 index 0000000..26b83a5 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/helmet_s10.png b/images/icons/sci-fi_armor_icons_png/bg/helmet_s10.png new file mode 100644 index 0000000..29dda74 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/helmet_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s01.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s01.png new file mode 100644 index 0000000..357dad3 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s02.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s02.png new file mode 100644 index 0000000..9af3db6 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s03.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s03.png new file mode 100644 index 0000000..bd68e54 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s04.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s04.png new file mode 100644 index 0000000..fc09def Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s05.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s05.png new file mode 100644 index 0000000..76fa3dc Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s06.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s06.png new file mode 100644 index 0000000..ab04f75 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s07.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s07.png new file mode 100644 index 0000000..10ec6a8 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s08.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s08.png new file mode 100644 index 0000000..a336677 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s09.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s09.png new file mode 100644 index 0000000..d312690 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/pants_s10.png b/images/icons/sci-fi_armor_icons_png/bg/pants_s10.png new file mode 100644 index 0000000..ea034f5 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/pants_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s01.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s01.png new file mode 100644 index 0000000..f14aea4 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s02.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s02.png new file mode 100644 index 0000000..9081d57 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s03.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s03.png new file mode 100644 index 0000000..72db078 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s04.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s04.png new file mode 100644 index 0000000..4a8d1f7 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s05.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s05.png new file mode 100644 index 0000000..4b07faf Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s06.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s06.png new file mode 100644 index 0000000..7c60748 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s07.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s07.png new file mode 100644 index 0000000..c2aaa20 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s08.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s08.png new file mode 100644 index 0000000..68851ce Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s09.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s09.png new file mode 100644 index 0000000..4234e0e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/shoulders_s10.png b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s10.png new file mode 100644 index 0000000..a3e1d6a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/shoulders_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s01.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s01.png new file mode 100644 index 0000000..6f25f79 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s02.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s02.png new file mode 100644 index 0000000..77cb18f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s03.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s03.png new file mode 100644 index 0000000..52860f8 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s04.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s04.png new file mode 100644 index 0000000..a2f122d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s05.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s05.png new file mode 100644 index 0000000..4337ed6 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s06.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s06.png new file mode 100644 index 0000000..1b00d26 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s07.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s07.png new file mode 100644 index 0000000..943d38b Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s08.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s08.png new file mode 100644 index 0000000..0ff7d03 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s09.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s09.png new file mode 100644 index 0000000..2bacd43 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/bg/weapon_s10.png b/images/icons/sci-fi_armor_icons_png/bg/weapon_s10.png new file mode 100644 index 0000000..0779ab0 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/bg/weapon_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s01.png new file mode 100644 index 0000000..0201112 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s02.png new file mode 100644 index 0000000..394d7d5 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s03.png new file mode 100644 index 0000000..fec9a25 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s04.png new file mode 100644 index 0000000..c51a859 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s05.png new file mode 100644 index 0000000..be18ef5 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s06.png new file mode 100644 index 0000000..89a3f6e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s07.png new file mode 100644 index 0000000..31beeba Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s08.png new file mode 100644 index 0000000..dcd0102 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s09.png new file mode 100644 index 0000000..605928a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s10.png new file mode 100644 index 0000000..55ec33b Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/ammunition_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s01.png new file mode 100644 index 0000000..529788b Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s02.png new file mode 100644 index 0000000..c7d2943 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s03.png new file mode 100644 index 0000000..1c983c6 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s04.png new file mode 100644 index 0000000..851d585 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s05.png new file mode 100644 index 0000000..368851e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s06.png new file mode 100644 index 0000000..0ac6dfb Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s07.png new file mode 100644 index 0000000..34ff454 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s08.png new file mode 100644 index 0000000..37a4d0b Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s09.png new file mode 100644 index 0000000..623d1bd Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/armor_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/armor_s10.png new file mode 100644 index 0000000..a043666 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/armor_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s01.png new file mode 100644 index 0000000..eca8d0b Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s02.png new file mode 100644 index 0000000..840de20 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s03.png new file mode 100644 index 0000000..6fda06f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s04.png new file mode 100644 index 0000000..20305fb Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s05.png new file mode 100644 index 0000000..f9898a0 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s06.png new file mode 100644 index 0000000..9cddcf4 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s07.png new file mode 100644 index 0000000..5d31613 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s08.png new file mode 100644 index 0000000..48ca726 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s09.png new file mode 100644 index 0000000..f627fce Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/belt_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/belt_s10.png new file mode 100644 index 0000000..3872edd Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/belt_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s01.png new file mode 100644 index 0000000..e9c75ed Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s02.png new file mode 100644 index 0000000..fd9ca61 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s03.png new file mode 100644 index 0000000..de21895 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s04.png new file mode 100644 index 0000000..97bf91c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s05.png new file mode 100644 index 0000000..a59a896 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s06.png new file mode 100644 index 0000000..c566c9a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s07.png new file mode 100644 index 0000000..2faec61 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s08.png new file mode 100644 index 0000000..9645b9f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s09.png new file mode 100644 index 0000000..be24950 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/boots_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/boots_s10.png new file mode 100644 index 0000000..3e32aec Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/boots_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s01.png new file mode 100644 index 0000000..97fd84c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s02.png new file mode 100644 index 0000000..067cc61 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s03.png new file mode 100644 index 0000000..14f9cd2 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s04.png new file mode 100644 index 0000000..adf2c88 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s05.png new file mode 100644 index 0000000..82de2e3 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s06.png new file mode 100644 index 0000000..b28a26d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s07.png new file mode 100644 index 0000000..3886103 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s08.png new file mode 100644 index 0000000..af60171 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s09.png new file mode 100644 index 0000000..a34e1d3 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/bracers_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s10.png new file mode 100644 index 0000000..62d1c92 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/bracers_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s01.png new file mode 100644 index 0000000..2a1e687 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s02.png new file mode 100644 index 0000000..fe5ab03 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s03.png new file mode 100644 index 0000000..ce3df35 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s04.png new file mode 100644 index 0000000..7633b84 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s05.png new file mode 100644 index 0000000..6e50d29 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s06.png new file mode 100644 index 0000000..ecfc162 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s07.png new file mode 100644 index 0000000..a129007 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s08.png new file mode 100644 index 0000000..6e285a3 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s09.png new file mode 100644 index 0000000..e5ac3ab Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/gloves_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s10.png new file mode 100644 index 0000000..2e6c02d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/gloves_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s01.png new file mode 100644 index 0000000..57dd018 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s02.png new file mode 100644 index 0000000..24e91fb Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s03.png new file mode 100644 index 0000000..051af4e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s04.png new file mode 100644 index 0000000..1a95d2f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s05.png new file mode 100644 index 0000000..6f4176b Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s06.png new file mode 100644 index 0000000..e892d6f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s07.png new file mode 100644 index 0000000..4df2e2e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s08.png new file mode 100644 index 0000000..42f3d61 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s09.png new file mode 100644 index 0000000..323ae24 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/helmet_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s10.png new file mode 100644 index 0000000..8ee596c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/helmet_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s01.png new file mode 100644 index 0000000..5aa0db3 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s02.png new file mode 100644 index 0000000..b9f369c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s03.png new file mode 100644 index 0000000..b32f980 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s04.png new file mode 100644 index 0000000..25377ce Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s05.png new file mode 100644 index 0000000..24b3ca6 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s06.png new file mode 100644 index 0000000..edb94ae Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s07.png new file mode 100644 index 0000000..7cdb83e Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s08.png new file mode 100644 index 0000000..379970c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s09.png new file mode 100644 index 0000000..cf66666 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/pants_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/pants_s10.png new file mode 100644 index 0000000..60e0aab Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/pants_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s01.png new file mode 100644 index 0000000..cb21757 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s02.png new file mode 100644 index 0000000..bd2f4ac Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s03.png new file mode 100644 index 0000000..fb6ccd5 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s04.png new file mode 100644 index 0000000..949ecee Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s05.png new file mode 100644 index 0000000..f79192d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s06.png new file mode 100644 index 0000000..ecc208f Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s07.png new file mode 100644 index 0000000..dd2fbfd Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s08.png new file mode 100644 index 0000000..d44b039 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s09.png new file mode 100644 index 0000000..30d4b8b Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s10.png new file mode 100644 index 0000000..265bc25 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/shoulders_s10.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s01.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s01.png new file mode 100644 index 0000000..e93ba5a Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s01.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s02.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s02.png new file mode 100644 index 0000000..4e7c08d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s02.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s03.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s03.png new file mode 100644 index 0000000..cd8a029 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s03.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s04.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s04.png new file mode 100644 index 0000000..5c2165d Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s04.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s05.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s05.png new file mode 100644 index 0000000..66e1ba0 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s05.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s06.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s06.png new file mode 100644 index 0000000..5914ecb Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s06.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s07.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s07.png new file mode 100644 index 0000000..a6c0291 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s07.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s08.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s08.png new file mode 100644 index 0000000..7f38c22 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s08.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s09.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s09.png new file mode 100644 index 0000000..1535914 Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s09.png differ diff --git a/images/icons/sci-fi_armor_icons_png/transparent/weapon_s10.png b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s10.png new file mode 100644 index 0000000..e79875c Binary files /dev/null and b/images/icons/sci-fi_armor_icons_png/transparent/weapon_s10.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_01.png b/images/icons/sci-fi_icons/black/ammunition/amm_01.png new file mode 100644 index 0000000..c0960df Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_01.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_02.PNG b/images/icons/sci-fi_icons/black/ammunition/amm_02.PNG new file mode 100644 index 0000000..bf0373a Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_02.PNG differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_03.PNG b/images/icons/sci-fi_icons/black/ammunition/amm_03.PNG new file mode 100644 index 0000000..6c2f2a4 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_03.PNG differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_04.PNG b/images/icons/sci-fi_icons/black/ammunition/amm_04.PNG new file mode 100644 index 0000000..ff4f57c Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_04.PNG differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_05.png b/images/icons/sci-fi_icons/black/ammunition/amm_05.png new file mode 100644 index 0000000..902f7f0 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_05.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_06.png b/images/icons/sci-fi_icons/black/ammunition/amm_06.png new file mode 100644 index 0000000..6cc8e86 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_06.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_07.png b/images/icons/sci-fi_icons/black/ammunition/amm_07.png new file mode 100644 index 0000000..9f8510e Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_07.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_08.png b/images/icons/sci-fi_icons/black/ammunition/amm_08.png new file mode 100644 index 0000000..f5ddab4 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_08.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_09.png b/images/icons/sci-fi_icons/black/ammunition/amm_09.png new file mode 100644 index 0000000..0612b0a Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_09.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_10.png b/images/icons/sci-fi_icons/black/ammunition/amm_10.png new file mode 100644 index 0000000..a7ddbb0 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_10.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_11.PNG b/images/icons/sci-fi_icons/black/ammunition/amm_11.PNG new file mode 100644 index 0000000..b04b0e4 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_11.PNG differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_12.PNG b/images/icons/sci-fi_icons/black/ammunition/amm_12.PNG new file mode 100644 index 0000000..ac7e02c Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_12.PNG differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_13.png b/images/icons/sci-fi_icons/black/ammunition/amm_13.png new file mode 100644 index 0000000..eb03e6e Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_13.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_14.png b/images/icons/sci-fi_icons/black/ammunition/amm_14.png new file mode 100644 index 0000000..64ffab4 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_14.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_15.png b/images/icons/sci-fi_icons/black/ammunition/amm_15.png new file mode 100644 index 0000000..ea197c6 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_15.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_16.png b/images/icons/sci-fi_icons/black/ammunition/amm_16.png new file mode 100644 index 0000000..3c6f432 Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_16.png differ diff --git a/images/icons/sci-fi_icons/black/ammunition/amm_17.png b/images/icons/sci-fi_icons/black/ammunition/amm_17.png new file mode 100644 index 0000000..30bf2ce Binary files /dev/null and b/images/icons/sci-fi_icons/black/ammunition/amm_17.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_01.png b/images/icons/sci-fi_icons/black/armor/armor_01.png new file mode 100644 index 0000000..4bd892f Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_01.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_02.png b/images/icons/sci-fi_icons/black/armor/armor_02.png new file mode 100644 index 0000000..7d28df0 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_02.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_03.png b/images/icons/sci-fi_icons/black/armor/armor_03.png new file mode 100644 index 0000000..c67001e Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_03.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_04.png b/images/icons/sci-fi_icons/black/armor/armor_04.png new file mode 100644 index 0000000..a675c27 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_04.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_05.PNG b/images/icons/sci-fi_icons/black/armor/armor_05.PNG new file mode 100644 index 0000000..5faee3c Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_05.PNG differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_06.PNG b/images/icons/sci-fi_icons/black/armor/armor_06.PNG new file mode 100644 index 0000000..bf665b9 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_06.PNG differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_07.PNG b/images/icons/sci-fi_icons/black/armor/armor_07.PNG new file mode 100644 index 0000000..595d279 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_07.PNG differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_08.PNG b/images/icons/sci-fi_icons/black/armor/armor_08.PNG new file mode 100644 index 0000000..d128316 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_08.PNG differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_09.png b/images/icons/sci-fi_icons/black/armor/armor_09.png new file mode 100644 index 0000000..081f1c1 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_09.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_10.png b/images/icons/sci-fi_icons/black/armor/armor_10.png new file mode 100644 index 0000000..985cf98 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_10.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_11.png b/images/icons/sci-fi_icons/black/armor/armor_11.png new file mode 100644 index 0000000..e98c6cc Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_11.png differ diff --git a/images/icons/sci-fi_icons/black/armor/armor_12.png b/images/icons/sci-fi_icons/black/armor/armor_12.png new file mode 100644 index 0000000..abc18a8 Binary files /dev/null and b/images/icons/sci-fi_icons/black/armor/armor_12.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_01.PNG b/images/icons/sci-fi_icons/black/boxes/boxes_01.PNG new file mode 100644 index 0000000..7470979 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_01.PNG differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_02.png b/images/icons/sci-fi_icons/black/boxes/boxes_02.png new file mode 100644 index 0000000..4adaca6 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_02.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_03.png b/images/icons/sci-fi_icons/black/boxes/boxes_03.png new file mode 100644 index 0000000..be386a4 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_03.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_04.png b/images/icons/sci-fi_icons/black/boxes/boxes_04.png new file mode 100644 index 0000000..1f55246 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_04.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_05.png b/images/icons/sci-fi_icons/black/boxes/boxes_05.png new file mode 100644 index 0000000..dabec73 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_05.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_06.png b/images/icons/sci-fi_icons/black/boxes/boxes_06.png new file mode 100644 index 0000000..a7b90e7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_06.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_07.png b/images/icons/sci-fi_icons/black/boxes/boxes_07.png new file mode 100644 index 0000000..a1fdff3 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_07.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_08.png b/images/icons/sci-fi_icons/black/boxes/boxes_08.png new file mode 100644 index 0000000..885b18b Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_08.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_09.png b/images/icons/sci-fi_icons/black/boxes/boxes_09.png new file mode 100644 index 0000000..623a0f9 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_09.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_10.png b/images/icons/sci-fi_icons/black/boxes/boxes_10.png new file mode 100644 index 0000000..6fddc76 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_10.png differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_11.PNG b/images/icons/sci-fi_icons/black/boxes/boxes_11.PNG new file mode 100644 index 0000000..f57268d Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_11.PNG differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_12.PNG b/images/icons/sci-fi_icons/black/boxes/boxes_12.PNG new file mode 100644 index 0000000..12c037a Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_12.PNG differ diff --git a/images/icons/sci-fi_icons/black/boxes/boxes_13.PNG b/images/icons/sci-fi_icons/black/boxes/boxes_13.PNG new file mode 100644 index 0000000..ef57da9 Binary files /dev/null and b/images/icons/sci-fi_icons/black/boxes/boxes_13.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_01.png b/images/icons/sci-fi_icons/black/guns/guns_01.png new file mode 100644 index 0000000..f02a3ba Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_01.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_02.png b/images/icons/sci-fi_icons/black/guns/guns_02.png new file mode 100644 index 0000000..7c691b3 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_02.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_03.png b/images/icons/sci-fi_icons/black/guns/guns_03.png new file mode 100644 index 0000000..4a1b908 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_03.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_04.png b/images/icons/sci-fi_icons/black/guns/guns_04.png new file mode 100644 index 0000000..079a359 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_04.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_05.png b/images/icons/sci-fi_icons/black/guns/guns_05.png new file mode 100644 index 0000000..988e9f8 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_05.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_06.png b/images/icons/sci-fi_icons/black/guns/guns_06.png new file mode 100644 index 0000000..9546713 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_06.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_07.png b/images/icons/sci-fi_icons/black/guns/guns_07.png new file mode 100644 index 0000000..e0ffdce Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_07.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_08.png b/images/icons/sci-fi_icons/black/guns/guns_08.png new file mode 100644 index 0000000..4f66b42 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_08.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_09.png b/images/icons/sci-fi_icons/black/guns/guns_09.png new file mode 100644 index 0000000..198f11c Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_09.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_10.png b/images/icons/sci-fi_icons/black/guns/guns_10.png new file mode 100644 index 0000000..b5e1c3d Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_10.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_11.png b/images/icons/sci-fi_icons/black/guns/guns_11.png new file mode 100644 index 0000000..bc688bb Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_11.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_12.png b/images/icons/sci-fi_icons/black/guns/guns_12.png new file mode 100644 index 0000000..fcf1a28 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_12.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_13.png b/images/icons/sci-fi_icons/black/guns/guns_13.png new file mode 100644 index 0000000..3e0e7f7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_13.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_14.png b/images/icons/sci-fi_icons/black/guns/guns_14.png new file mode 100644 index 0000000..732334e Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_14.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_15.png b/images/icons/sci-fi_icons/black/guns/guns_15.png new file mode 100644 index 0000000..9a57e83 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_15.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_16.png b/images/icons/sci-fi_icons/black/guns/guns_16.png new file mode 100644 index 0000000..d7ee6ee Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_16.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_17.png b/images/icons/sci-fi_icons/black/guns/guns_17.png new file mode 100644 index 0000000..dbc38a7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_17.png differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_18.PNG b/images/icons/sci-fi_icons/black/guns/guns_18.PNG new file mode 100644 index 0000000..45bcdfc Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_18.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_19.PNG b/images/icons/sci-fi_icons/black/guns/guns_19.PNG new file mode 100644 index 0000000..11fad10 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_19.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_20.PNG b/images/icons/sci-fi_icons/black/guns/guns_20.PNG new file mode 100644 index 0000000..ed27643 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_20.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_21.PNG b/images/icons/sci-fi_icons/black/guns/guns_21.PNG new file mode 100644 index 0000000..5fe44b7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_21.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_22.PNG b/images/icons/sci-fi_icons/black/guns/guns_22.PNG new file mode 100644 index 0000000..0ceecf1 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_22.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_23.PNG b/images/icons/sci-fi_icons/black/guns/guns_23.PNG new file mode 100644 index 0000000..c78c3fe Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_23.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_24.PNG b/images/icons/sci-fi_icons/black/guns/guns_24.PNG new file mode 100644 index 0000000..3828d16 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_24.PNG differ diff --git a/images/icons/sci-fi_icons/black/guns/guns_25.PNG b/images/icons/sci-fi_icons/black/guns/guns_25.PNG new file mode 100644 index 0000000..9d5d832 Binary files /dev/null and b/images/icons/sci-fi_icons/black/guns/guns_25.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_01.png b/images/icons/sci-fi_icons/black/parts/parts_01.png new file mode 100644 index 0000000..4188ab6 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_01.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_02.PNG b/images/icons/sci-fi_icons/black/parts/parts_02.PNG new file mode 100644 index 0000000..3d13083 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_02.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_03.PNG b/images/icons/sci-fi_icons/black/parts/parts_03.PNG new file mode 100644 index 0000000..c3f91f8 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_03.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_04.PNG b/images/icons/sci-fi_icons/black/parts/parts_04.PNG new file mode 100644 index 0000000..d98c027 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_04.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_05.PNG b/images/icons/sci-fi_icons/black/parts/parts_05.PNG new file mode 100644 index 0000000..9270157 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_05.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_06.png b/images/icons/sci-fi_icons/black/parts/parts_06.png new file mode 100644 index 0000000..3abc807 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_06.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_07.png b/images/icons/sci-fi_icons/black/parts/parts_07.png new file mode 100644 index 0000000..b34e9f5 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_07.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_08.png b/images/icons/sci-fi_icons/black/parts/parts_08.png new file mode 100644 index 0000000..aae37ea Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_08.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_09.png b/images/icons/sci-fi_icons/black/parts/parts_09.png new file mode 100644 index 0000000..6d42e6d Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_09.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_10.png b/images/icons/sci-fi_icons/black/parts/parts_10.png new file mode 100644 index 0000000..009d186 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_10.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_11.png b/images/icons/sci-fi_icons/black/parts/parts_11.png new file mode 100644 index 0000000..ea580ff Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_11.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_12.png b/images/icons/sci-fi_icons/black/parts/parts_12.png new file mode 100644 index 0000000..fc0ae8b Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_12.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_13.png b/images/icons/sci-fi_icons/black/parts/parts_13.png new file mode 100644 index 0000000..1abd187 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_13.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_14.png b/images/icons/sci-fi_icons/black/parts/parts_14.png new file mode 100644 index 0000000..0853de6 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_14.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_15.png b/images/icons/sci-fi_icons/black/parts/parts_15.png new file mode 100644 index 0000000..f2a4e7b Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_15.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_16.PNG b/images/icons/sci-fi_icons/black/parts/parts_16.PNG new file mode 100644 index 0000000..488f542 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_16.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_17.PNG b/images/icons/sci-fi_icons/black/parts/parts_17.PNG new file mode 100644 index 0000000..e56cef7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_17.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_18.PNG b/images/icons/sci-fi_icons/black/parts/parts_18.PNG new file mode 100644 index 0000000..53872f9 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_18.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_19.PNG b/images/icons/sci-fi_icons/black/parts/parts_19.PNG new file mode 100644 index 0000000..00bcbb7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_19.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_20.PNG b/images/icons/sci-fi_icons/black/parts/parts_20.PNG new file mode 100644 index 0000000..e230e69 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_20.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_21.png b/images/icons/sci-fi_icons/black/parts/parts_21.png new file mode 100644 index 0000000..5582a23 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_21.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_22.PNG b/images/icons/sci-fi_icons/black/parts/parts_22.PNG new file mode 100644 index 0000000..7d06fd6 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_22.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_23.PNG b/images/icons/sci-fi_icons/black/parts/parts_23.PNG new file mode 100644 index 0000000..e8f450e Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_23.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_24.PNG b/images/icons/sci-fi_icons/black/parts/parts_24.PNG new file mode 100644 index 0000000..a5ac34e Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_24.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_25.PNG b/images/icons/sci-fi_icons/black/parts/parts_25.PNG new file mode 100644 index 0000000..c3ca1b2 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_25.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_26.PNG b/images/icons/sci-fi_icons/black/parts/parts_26.PNG new file mode 100644 index 0000000..21eed6a Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_26.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_27.PNG b/images/icons/sci-fi_icons/black/parts/parts_27.PNG new file mode 100644 index 0000000..2b341dd Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_27.PNG differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_28.png b/images/icons/sci-fi_icons/black/parts/parts_28.png new file mode 100644 index 0000000..5cf53e6 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_28.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_29.png b/images/icons/sci-fi_icons/black/parts/parts_29.png new file mode 100644 index 0000000..9dc9ca7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_29.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_30.png b/images/icons/sci-fi_icons/black/parts/parts_30.png new file mode 100644 index 0000000..64d47cb Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_30.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_31.png b/images/icons/sci-fi_icons/black/parts/parts_31.png new file mode 100644 index 0000000..71b7059 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_31.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_32.png b/images/icons/sci-fi_icons/black/parts/parts_32.png new file mode 100644 index 0000000..e6c3979 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_32.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_33.png b/images/icons/sci-fi_icons/black/parts/parts_33.png new file mode 100644 index 0000000..bd8b335 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_33.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_34.png b/images/icons/sci-fi_icons/black/parts/parts_34.png new file mode 100644 index 0000000..e8d5aa1 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_34.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_35.png b/images/icons/sci-fi_icons/black/parts/parts_35.png new file mode 100644 index 0000000..833fd01 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_35.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_36.png b/images/icons/sci-fi_icons/black/parts/parts_36.png new file mode 100644 index 0000000..68a0bbc Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_36.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_37.png b/images/icons/sci-fi_icons/black/parts/parts_37.png new file mode 100644 index 0000000..5bebcd7 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_37.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_38.png b/images/icons/sci-fi_icons/black/parts/parts_38.png new file mode 100644 index 0000000..a164b77 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_38.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_39.png b/images/icons/sci-fi_icons/black/parts/parts_39.png new file mode 100644 index 0000000..3be27b2 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_39.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_40.png b/images/icons/sci-fi_icons/black/parts/parts_40.png new file mode 100644 index 0000000..7f76606 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_40.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_41.png b/images/icons/sci-fi_icons/black/parts/parts_41.png new file mode 100644 index 0000000..4f042fb Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_41.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_42.png b/images/icons/sci-fi_icons/black/parts/parts_42.png new file mode 100644 index 0000000..5819d1e Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_42.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_43.png b/images/icons/sci-fi_icons/black/parts/parts_43.png new file mode 100644 index 0000000..9388d3f Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_43.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_44.png b/images/icons/sci-fi_icons/black/parts/parts_44.png new file mode 100644 index 0000000..745ce61 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_44.png differ diff --git a/images/icons/sci-fi_icons/black/parts/parts_45.png b/images/icons/sci-fi_icons/black/parts/parts_45.png new file mode 100644 index 0000000..2c737f6 Binary files /dev/null and b/images/icons/sci-fi_icons/black/parts/parts_45.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_01.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_01.png new file mode 100644 index 0000000..74082ed Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_01.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_010.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_010.png new file mode 100644 index 0000000..dbde856 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_010.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_011.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_011.png new file mode 100644 index 0000000..29eca22 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_011.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_012.PNG b/images/icons/sci-fi_icons/transparent/ammunition/amm_012.PNG new file mode 100644 index 0000000..9acbb36 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_012.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_013.PNG b/images/icons/sci-fi_icons/transparent/ammunition/amm_013.PNG new file mode 100644 index 0000000..eadf585 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_013.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_014.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_014.png new file mode 100644 index 0000000..51c8ce3 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_014.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_015.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_015.png new file mode 100644 index 0000000..a3a037f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_015.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_016.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_016.png new file mode 100644 index 0000000..b24d3aa Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_016.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_017.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_017.png new file mode 100644 index 0000000..352bd08 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_017.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_018.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_018.png new file mode 100644 index 0000000..1d4b3a4 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_018.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_02.PNG b/images/icons/sci-fi_icons/transparent/ammunition/amm_02.PNG new file mode 100644 index 0000000..08a88a8 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_02.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_03.PNG b/images/icons/sci-fi_icons/transparent/ammunition/amm_03.PNG new file mode 100644 index 0000000..8b40429 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_03.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_04.PNG b/images/icons/sci-fi_icons/transparent/ammunition/amm_04.PNG new file mode 100644 index 0000000..3d550a4 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_04.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_05.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_05.png new file mode 100644 index 0000000..5dfe7ea Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_05.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_06.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_06.png new file mode 100644 index 0000000..da5b8fc Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_06.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_07.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_07.png new file mode 100644 index 0000000..37df6f5 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_07.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_08.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_08.png new file mode 100644 index 0000000..b1862c3 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_08.png differ diff --git a/images/icons/sci-fi_icons/transparent/ammunition/amm_09.png b/images/icons/sci-fi_icons/transparent/ammunition/amm_09.png new file mode 100644 index 0000000..c24f3a1 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/ammunition/amm_09.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_01.PNG b/images/icons/sci-fi_icons/transparent/armor/armor_01.PNG new file mode 100644 index 0000000..c3ca1b2 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_01.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_010.png b/images/icons/sci-fi_icons/transparent/armor/armor_010.png new file mode 100644 index 0000000..da2443e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_010.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_011.png b/images/icons/sci-fi_icons/transparent/armor/armor_011.png new file mode 100644 index 0000000..f246f73 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_011.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_012.png b/images/icons/sci-fi_icons/transparent/armor/armor_012.png new file mode 100644 index 0000000..021a432 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_012.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_013.png b/images/icons/sci-fi_icons/transparent/armor/armor_013.png new file mode 100644 index 0000000..abc18a8 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_013.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_02.png b/images/icons/sci-fi_icons/transparent/armor/armor_02.png new file mode 100644 index 0000000..36e323f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_02.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_03.png b/images/icons/sci-fi_icons/transparent/armor/armor_03.png new file mode 100644 index 0000000..beefee4 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_03.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_04.png b/images/icons/sci-fi_icons/transparent/armor/armor_04.png new file mode 100644 index 0000000..6fb2faf Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_04.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_05.png b/images/icons/sci-fi_icons/transparent/armor/armor_05.png new file mode 100644 index 0000000..a2197a1 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_05.png differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_06.PNG b/images/icons/sci-fi_icons/transparent/armor/armor_06.PNG new file mode 100644 index 0000000..6325e3e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_06.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_07.PNG b/images/icons/sci-fi_icons/transparent/armor/armor_07.PNG new file mode 100644 index 0000000..b9c909d Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_07.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_08.PNG b/images/icons/sci-fi_icons/transparent/armor/armor_08.PNG new file mode 100644 index 0000000..1f19498 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_08.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/armor/armor_09.PNG b/images/icons/sci-fi_icons/transparent/armor/armor_09.PNG new file mode 100644 index 0000000..d128316 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/armor/armor_09.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_01.PNG b/images/icons/sci-fi_icons/transparent/boxes/boxes_01.PNG new file mode 100644 index 0000000..4c27df8 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_01.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_010.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_010.png new file mode 100644 index 0000000..30d97bb Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_010.png differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_011.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_011.png new file mode 100644 index 0000000..7a6e57e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_011.png differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_012.PNG b/images/icons/sci-fi_icons/transparent/boxes/boxes_012.PNG new file mode 100644 index 0000000..5da936e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_012.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_02.PNG b/images/icons/sci-fi_icons/transparent/boxes/boxes_02.PNG new file mode 100644 index 0000000..e7aedba Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_02.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_03.PNG b/images/icons/sci-fi_icons/transparent/boxes/boxes_03.PNG new file mode 100644 index 0000000..59df0e9 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_03.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_04.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_04.png new file mode 100644 index 0000000..0d482fa Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_04.png differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_05.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_05.png new file mode 100644 index 0000000..4079e91 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_05.png differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_06.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_06.png new file mode 100644 index 0000000..f17a3ba Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_06.png differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_07.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_07.png new file mode 100644 index 0000000..6ec4c97 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_07.png differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_08.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_08.png new file mode 100644 index 0000000..2ce076f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_08.png differ diff --git a/images/icons/sci-fi_icons/transparent/boxes/boxes_09.png b/images/icons/sci-fi_icons/transparent/boxes/boxes_09.png new file mode 100644 index 0000000..15577f6 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/boxes/boxes_09.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_01.png b/images/icons/sci-fi_icons/transparent/guns/guns_01.png new file mode 100644 index 0000000..65a154c Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_01.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_010.png b/images/icons/sci-fi_icons/transparent/guns/guns_010.png new file mode 100644 index 0000000..e5929ce Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_010.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_011.png b/images/icons/sci-fi_icons/transparent/guns/guns_011.png new file mode 100644 index 0000000..4097d07 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_011.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_012.png b/images/icons/sci-fi_icons/transparent/guns/guns_012.png new file mode 100644 index 0000000..0eab9fd Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_012.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_013.png b/images/icons/sci-fi_icons/transparent/guns/guns_013.png new file mode 100644 index 0000000..ac6147d Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_013.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_014.png b/images/icons/sci-fi_icons/transparent/guns/guns_014.png new file mode 100644 index 0000000..00f8563 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_014.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_015.png b/images/icons/sci-fi_icons/transparent/guns/guns_015.png new file mode 100644 index 0000000..04d7797 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_015.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_016.png b/images/icons/sci-fi_icons/transparent/guns/guns_016.png new file mode 100644 index 0000000..526c6ab Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_016.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_017.png b/images/icons/sci-fi_icons/transparent/guns/guns_017.png new file mode 100644 index 0000000..9f73436 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_017.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_018.png b/images/icons/sci-fi_icons/transparent/guns/guns_018.png new file mode 100644 index 0000000..860cec9 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_018.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_019.png b/images/icons/sci-fi_icons/transparent/guns/guns_019.png new file mode 100644 index 0000000..ecfaf19 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_019.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_02.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_02.PNG new file mode 100644 index 0000000..815f751 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_02.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_020.png b/images/icons/sci-fi_icons/transparent/guns/guns_020.png new file mode 100644 index 0000000..57d636d Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_020.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_021.png b/images/icons/sci-fi_icons/transparent/guns/guns_021.png new file mode 100644 index 0000000..2c3336f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_021.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_022.png b/images/icons/sci-fi_icons/transparent/guns/guns_022.png new file mode 100644 index 0000000..268cee5 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_022.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_023.png b/images/icons/sci-fi_icons/transparent/guns/guns_023.png new file mode 100644 index 0000000..d48210a Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_023.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_024.png b/images/icons/sci-fi_icons/transparent/guns/guns_024.png new file mode 100644 index 0000000..9a07024 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_024.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_025.png b/images/icons/sci-fi_icons/transparent/guns/guns_025.png new file mode 100644 index 0000000..029b034 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_025.png differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_03.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_03.PNG new file mode 100644 index 0000000..3fb9f63 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_03.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_04.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_04.PNG new file mode 100644 index 0000000..dbbdcbf Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_04.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_05.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_05.PNG new file mode 100644 index 0000000..c46ca0e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_05.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_06.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_06.PNG new file mode 100644 index 0000000..1c5f556 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_06.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_07.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_07.PNG new file mode 100644 index 0000000..0c95c7f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_07.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_08.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_08.PNG new file mode 100644 index 0000000..fe67752 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_08.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/guns/guns_09.PNG b/images/icons/sci-fi_icons/transparent/guns/guns_09.PNG new file mode 100644 index 0000000..0ab79ce Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/guns/guns_09.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_01.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_01.PNG new file mode 100644 index 0000000..174c766 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_01.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_010.png b/images/icons/sci-fi_icons/transparent/parts/parts_010.png new file mode 100644 index 0000000..e3d56cb Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_010.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_011.png b/images/icons/sci-fi_icons/transparent/parts/parts_011.png new file mode 100644 index 0000000..087c904 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_011.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_012.png b/images/icons/sci-fi_icons/transparent/parts/parts_012.png new file mode 100644 index 0000000..9fd1390 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_012.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_013.png b/images/icons/sci-fi_icons/transparent/parts/parts_013.png new file mode 100644 index 0000000..3f14861 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_013.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_014.png b/images/icons/sci-fi_icons/transparent/parts/parts_014.png new file mode 100644 index 0000000..6f7ed4f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_014.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_015.png b/images/icons/sci-fi_icons/transparent/parts/parts_015.png new file mode 100644 index 0000000..b7b200e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_015.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_016.png b/images/icons/sci-fi_icons/transparent/parts/parts_016.png new file mode 100644 index 0000000..baa70f6 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_016.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_017.png b/images/icons/sci-fi_icons/transparent/parts/parts_017.png new file mode 100644 index 0000000..76391cb Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_017.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_018.png b/images/icons/sci-fi_icons/transparent/parts/parts_018.png new file mode 100644 index 0000000..e6c3979 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_018.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_019.png b/images/icons/sci-fi_icons/transparent/parts/parts_019.png new file mode 100644 index 0000000..dcc27c4 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_019.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_02.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_02.PNG new file mode 100644 index 0000000..909cb7c Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_02.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_020.png b/images/icons/sci-fi_icons/transparent/parts/parts_020.png new file mode 100644 index 0000000..83e63f8 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_020.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_021.png b/images/icons/sci-fi_icons/transparent/parts/parts_021.png new file mode 100644 index 0000000..7f8342f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_021.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_022.png b/images/icons/sci-fi_icons/transparent/parts/parts_022.png new file mode 100644 index 0000000..cc634aa Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_022.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_023.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_023.PNG new file mode 100644 index 0000000..7732deb Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_023.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_024.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_024.PNG new file mode 100644 index 0000000..edd8590 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_024.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_025.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_025.PNG new file mode 100644 index 0000000..45a0159 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_025.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_026.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_026.PNG new file mode 100644 index 0000000..849f5d1 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_026.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_027.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_027.PNG new file mode 100644 index 0000000..76e901e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_027.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_028.png b/images/icons/sci-fi_icons/transparent/parts/parts_028.png new file mode 100644 index 0000000..45e2355 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_028.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_029.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_029.PNG new file mode 100644 index 0000000..5733685 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_029.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_03.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_03.PNG new file mode 100644 index 0000000..a6f179b Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_03.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_030.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_030.PNG new file mode 100644 index 0000000..28a2c93 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_030.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_031.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_031.PNG new file mode 100644 index 0000000..8a44c4e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_031.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_032.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_032.PNG new file mode 100644 index 0000000..9d613ef Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_032.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_033.PNG b/images/icons/sci-fi_icons/transparent/parts/parts_033.PNG new file mode 100644 index 0000000..f1657bd Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_033.PNG differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_034.png b/images/icons/sci-fi_icons/transparent/parts/parts_034.png new file mode 100644 index 0000000..5812a12 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_034.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_035.png b/images/icons/sci-fi_icons/transparent/parts/parts_035.png new file mode 100644 index 0000000..62fdb49 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_035.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_036.png b/images/icons/sci-fi_icons/transparent/parts/parts_036.png new file mode 100644 index 0000000..bcfb225 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_036.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_037.png b/images/icons/sci-fi_icons/transparent/parts/parts_037.png new file mode 100644 index 0000000..ee5c0e9 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_037.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_038.png b/images/icons/sci-fi_icons/transparent/parts/parts_038.png new file mode 100644 index 0000000..3c48bc1 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_038.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_039.png b/images/icons/sci-fi_icons/transparent/parts/parts_039.png new file mode 100644 index 0000000..e4dbfaf Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_039.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_04.png b/images/icons/sci-fi_icons/transparent/parts/parts_04.png new file mode 100644 index 0000000..db0e37c Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_04.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_040.png b/images/icons/sci-fi_icons/transparent/parts/parts_040.png new file mode 100644 index 0000000..0aae81f Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_040.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_041.png b/images/icons/sci-fi_icons/transparent/parts/parts_041.png new file mode 100644 index 0000000..e8fb67c Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_041.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_042.png b/images/icons/sci-fi_icons/transparent/parts/parts_042.png new file mode 100644 index 0000000..831cd36 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_042.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_043.png b/images/icons/sci-fi_icons/transparent/parts/parts_043.png new file mode 100644 index 0000000..18bb0d6 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_043.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_05.png b/images/icons/sci-fi_icons/transparent/parts/parts_05.png new file mode 100644 index 0000000..92e0e8b Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_05.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_06.png b/images/icons/sci-fi_icons/transparent/parts/parts_06.png new file mode 100644 index 0000000..745ce61 Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_06.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_07.png b/images/icons/sci-fi_icons/transparent/parts/parts_07.png new file mode 100644 index 0000000..c0ddd9d Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_07.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_08.png b/images/icons/sci-fi_icons/transparent/parts/parts_08.png new file mode 100644 index 0000000..5819d1e Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_08.png differ diff --git a/images/icons/sci-fi_icons/transparent/parts/parts_09.png b/images/icons/sci-fi_icons/transparent/parts/parts_09.png new file mode 100644 index 0000000..4f042fb Binary files /dev/null and b/images/icons/sci-fi_icons/transparent/parts/parts_09.png differ diff --git a/images/icons/sla-ammo/10-gauge-he__AP.png b/images/icons/sla-ammo/10-gauge-he__AP.png new file mode 100644 index 0000000..c225722 Binary files /dev/null and b/images/icons/sla-ammo/10-gauge-he__AP.png differ diff --git a/images/icons/sla-ammo/10-gauge-he__HE.png b/images/icons/sla-ammo/10-gauge-he__HE.png new file mode 100644 index 0000000..40ab7aa Binary files /dev/null and b/images/icons/sla-ammo/10-gauge-he__HE.png differ diff --git a/images/icons/sla-ammo/10-gauge-he__HEAP.png b/images/icons/sla-ammo/10-gauge-he__HEAP.png new file mode 100644 index 0000000..7213641 Binary files /dev/null and b/images/icons/sla-ammo/10-gauge-he__HEAP.png differ diff --git a/images/icons/sla-ammo/10-gauge-he__STD.png b/images/icons/sla-ammo/10-gauge-he__STD.png new file mode 100644 index 0000000..6657842 Binary files /dev/null and b/images/icons/sla-ammo/10-gauge-he__STD.png differ diff --git a/images/icons/sla-ammo/10-gauge__AP.png b/images/icons/sla-ammo/10-gauge__AP.png new file mode 100644 index 0000000..d93749d Binary files /dev/null and b/images/icons/sla-ammo/10-gauge__AP.png differ diff --git a/images/icons/sla-ammo/10-gauge__HE.png b/images/icons/sla-ammo/10-gauge__HE.png new file mode 100644 index 0000000..a5baea4 Binary files /dev/null and b/images/icons/sla-ammo/10-gauge__HE.png differ diff --git a/images/icons/sla-ammo/10-gauge__HEAP.png b/images/icons/sla-ammo/10-gauge__HEAP.png new file mode 100644 index 0000000..7a2e6b1 Binary files /dev/null and b/images/icons/sla-ammo/10-gauge__HEAP.png differ diff --git a/images/icons/sla-ammo/10-gauge__STD.png b/images/icons/sla-ammo/10-gauge__STD.png new file mode 100644 index 0000000..98378a3 Binary files /dev/null and b/images/icons/sla-ammo/10-gauge__STD.png differ diff --git a/images/icons/sla-ammo/10mm-pistol__AP.png b/images/icons/sla-ammo/10mm-pistol__AP.png new file mode 100644 index 0000000..7f7c324 Binary files /dev/null and b/images/icons/sla-ammo/10mm-pistol__AP.png differ diff --git a/images/icons/sla-ammo/10mm-pistol__HE.png b/images/icons/sla-ammo/10mm-pistol__HE.png new file mode 100644 index 0000000..58ef473 Binary files /dev/null and b/images/icons/sla-ammo/10mm-pistol__HE.png differ diff --git a/images/icons/sla-ammo/10mm-pistol__HEAP.png b/images/icons/sla-ammo/10mm-pistol__HEAP.png new file mode 100644 index 0000000..2ded85b Binary files /dev/null and b/images/icons/sla-ammo/10mm-pistol__HEAP.png differ diff --git a/images/icons/sla-ammo/10mm-pistol__STD.png b/images/icons/sla-ammo/10mm-pistol__STD.png new file mode 100644 index 0000000..4952131 Binary files /dev/null and b/images/icons/sla-ammo/10mm-pistol__STD.png differ diff --git a/images/icons/sla-ammo/10mm-rifle__AP.png b/images/icons/sla-ammo/10mm-rifle__AP.png new file mode 100644 index 0000000..b4a37d0 Binary files /dev/null and b/images/icons/sla-ammo/10mm-rifle__AP.png differ diff --git a/images/icons/sla-ammo/10mm-rifle__HE.png b/images/icons/sla-ammo/10mm-rifle__HE.png new file mode 100644 index 0000000..43305ae Binary files /dev/null and b/images/icons/sla-ammo/10mm-rifle__HE.png differ diff --git a/images/icons/sla-ammo/10mm-rifle__HEAP.png b/images/icons/sla-ammo/10mm-rifle__HEAP.png new file mode 100644 index 0000000..1a6a3ef Binary files /dev/null and b/images/icons/sla-ammo/10mm-rifle__HEAP.png differ diff --git a/images/icons/sla-ammo/10mm-rifle__STD.png b/images/icons/sla-ammo/10mm-rifle__STD.png new file mode 100644 index 0000000..b08973b Binary files /dev/null and b/images/icons/sla-ammo/10mm-rifle__STD.png differ diff --git a/images/icons/sla-ammo/10mm-smg__AP.png b/images/icons/sla-ammo/10mm-smg__AP.png new file mode 100644 index 0000000..4fb1651 Binary files /dev/null and b/images/icons/sla-ammo/10mm-smg__AP.png differ diff --git a/images/icons/sla-ammo/10mm-smg__HE.png b/images/icons/sla-ammo/10mm-smg__HE.png new file mode 100644 index 0000000..09dbe13 Binary files /dev/null and b/images/icons/sla-ammo/10mm-smg__HE.png differ diff --git a/images/icons/sla-ammo/10mm-smg__HEAP.png b/images/icons/sla-ammo/10mm-smg__HEAP.png new file mode 100644 index 0000000..8b86442 Binary files /dev/null and b/images/icons/sla-ammo/10mm-smg__HEAP.png differ diff --git a/images/icons/sla-ammo/10mm-smg__STD.png b/images/icons/sla-ammo/10mm-smg__STD.png new file mode 100644 index 0000000..b6fe4c3 Binary files /dev/null and b/images/icons/sla-ammo/10mm-smg__STD.png differ diff --git a/images/icons/sla-ammo/12-gauge-he__AP.png b/images/icons/sla-ammo/12-gauge-he__AP.png new file mode 100644 index 0000000..c69c00b Binary files /dev/null and b/images/icons/sla-ammo/12-gauge-he__AP.png differ diff --git a/images/icons/sla-ammo/12-gauge-he__HE.png b/images/icons/sla-ammo/12-gauge-he__HE.png new file mode 100644 index 0000000..052b603 Binary files /dev/null and b/images/icons/sla-ammo/12-gauge-he__HE.png differ diff --git a/images/icons/sla-ammo/12-gauge-he__HEAP.png b/images/icons/sla-ammo/12-gauge-he__HEAP.png new file mode 100644 index 0000000..8fe1a23 Binary files /dev/null and b/images/icons/sla-ammo/12-gauge-he__HEAP.png differ diff --git a/images/icons/sla-ammo/12-gauge-he__STD.png b/images/icons/sla-ammo/12-gauge-he__STD.png new file mode 100644 index 0000000..eeb88cd Binary files /dev/null and b/images/icons/sla-ammo/12-gauge-he__STD.png differ diff --git a/images/icons/sla-ammo/12-gauge__AP.png b/images/icons/sla-ammo/12-gauge__AP.png new file mode 100644 index 0000000..0ec2715 Binary files /dev/null and b/images/icons/sla-ammo/12-gauge__AP.png differ diff --git a/images/icons/sla-ammo/12-gauge__HE.png b/images/icons/sla-ammo/12-gauge__HE.png new file mode 100644 index 0000000..12f92c4 Binary files /dev/null and b/images/icons/sla-ammo/12-gauge__HE.png differ diff --git a/images/icons/sla-ammo/12-gauge__HEAP.png b/images/icons/sla-ammo/12-gauge__HEAP.png new file mode 100644 index 0000000..ec38832 Binary files /dev/null and b/images/icons/sla-ammo/12-gauge__HEAP.png differ diff --git a/images/icons/sla-ammo/12-gauge__STD.png b/images/icons/sla-ammo/12-gauge__STD.png new file mode 100644 index 0000000..a6bd177 Binary files /dev/null and b/images/icons/sla-ammo/12-gauge__STD.png differ diff --git a/images/icons/sla-ammo/12mm__AP.png b/images/icons/sla-ammo/12mm__AP.png new file mode 100644 index 0000000..94cd8eb Binary files /dev/null and b/images/icons/sla-ammo/12mm__AP.png differ diff --git a/images/icons/sla-ammo/12mm__HE.png b/images/icons/sla-ammo/12mm__HE.png new file mode 100644 index 0000000..e0cefe6 Binary files /dev/null and b/images/icons/sla-ammo/12mm__HE.png differ diff --git a/images/icons/sla-ammo/12mm__HEAP.png b/images/icons/sla-ammo/12mm__HEAP.png new file mode 100644 index 0000000..c223fdb Binary files /dev/null and b/images/icons/sla-ammo/12mm__HEAP.png differ diff --git a/images/icons/sla-ammo/12mm__STD.png b/images/icons/sla-ammo/12mm__STD.png new file mode 100644 index 0000000..ddaab10 Binary files /dev/null and b/images/icons/sla-ammo/12mm__STD.png differ diff --git a/images/icons/sla-ammo/20mm-hedp__AP.png b/images/icons/sla-ammo/20mm-hedp__AP.png new file mode 100644 index 0000000..7a50db2 Binary files /dev/null and b/images/icons/sla-ammo/20mm-hedp__AP.png differ diff --git a/images/icons/sla-ammo/20mm-hedp__HE.png b/images/icons/sla-ammo/20mm-hedp__HE.png new file mode 100644 index 0000000..bb94996 Binary files /dev/null and b/images/icons/sla-ammo/20mm-hedp__HE.png differ diff --git a/images/icons/sla-ammo/20mm-hedp__HEAP.png b/images/icons/sla-ammo/20mm-hedp__HEAP.png new file mode 100644 index 0000000..4e28398 Binary files /dev/null and b/images/icons/sla-ammo/20mm-hedp__HEAP.png differ diff --git a/images/icons/sla-ammo/20mm-hedp__STD.png b/images/icons/sla-ammo/20mm-hedp__STD.png new file mode 100644 index 0000000..323d1aa Binary files /dev/null and b/images/icons/sla-ammo/20mm-hedp__STD.png differ diff --git a/images/icons/sla-ammo/25mm-he__AP.png b/images/icons/sla-ammo/25mm-he__AP.png new file mode 100644 index 0000000..5438607 Binary files /dev/null and b/images/icons/sla-ammo/25mm-he__AP.png differ diff --git a/images/icons/sla-ammo/25mm-he__HE.png b/images/icons/sla-ammo/25mm-he__HE.png new file mode 100644 index 0000000..5fca8bf Binary files /dev/null and b/images/icons/sla-ammo/25mm-he__HE.png differ diff --git a/images/icons/sla-ammo/25mm-he__HEAP.png b/images/icons/sla-ammo/25mm-he__HEAP.png new file mode 100644 index 0000000..6d23afe Binary files /dev/null and b/images/icons/sla-ammo/25mm-he__HEAP.png differ diff --git a/images/icons/sla-ammo/25mm-he__STD.png b/images/icons/sla-ammo/25mm-he__STD.png new file mode 100644 index 0000000..eb60a4d Binary files /dev/null and b/images/icons/sla-ammo/25mm-he__STD.png differ diff --git a/images/icons/sla-ammo/30mm-heat__AP.png b/images/icons/sla-ammo/30mm-heat__AP.png new file mode 100644 index 0000000..de798e7 Binary files /dev/null and b/images/icons/sla-ammo/30mm-heat__AP.png differ diff --git a/images/icons/sla-ammo/30mm-heat__HE.png b/images/icons/sla-ammo/30mm-heat__HE.png new file mode 100644 index 0000000..f1fbda2 Binary files /dev/null and b/images/icons/sla-ammo/30mm-heat__HE.png differ diff --git a/images/icons/sla-ammo/30mm-heat__HEAP.png b/images/icons/sla-ammo/30mm-heat__HEAP.png new file mode 100644 index 0000000..4c1f31c Binary files /dev/null and b/images/icons/sla-ammo/30mm-heat__HEAP.png differ diff --git a/images/icons/sla-ammo/30mm-heat__STD.png b/images/icons/sla-ammo/30mm-heat__STD.png new file mode 100644 index 0000000..450518c Binary files /dev/null and b/images/icons/sla-ammo/30mm-heat__STD.png differ diff --git a/images/icons/sla-ammo/3mm-smg__AP.png b/images/icons/sla-ammo/3mm-smg__AP.png new file mode 100644 index 0000000..7b8e1a8 Binary files /dev/null and b/images/icons/sla-ammo/3mm-smg__AP.png differ diff --git a/images/icons/sla-ammo/3mm-smg__HE.png b/images/icons/sla-ammo/3mm-smg__HE.png new file mode 100644 index 0000000..f1703d4 Binary files /dev/null and b/images/icons/sla-ammo/3mm-smg__HE.png differ diff --git a/images/icons/sla-ammo/3mm-smg__HEAP.png b/images/icons/sla-ammo/3mm-smg__HEAP.png new file mode 100644 index 0000000..19a2638 Binary files /dev/null and b/images/icons/sla-ammo/3mm-smg__HEAP.png differ diff --git a/images/icons/sla-ammo/3mm-smg__STD.png b/images/icons/sla-ammo/3mm-smg__STD.png new file mode 100644 index 0000000..08026d1 Binary files /dev/null and b/images/icons/sla-ammo/3mm-smg__STD.png differ diff --git a/images/icons/sla-ammo/3mm__AP.png b/images/icons/sla-ammo/3mm__AP.png new file mode 100644 index 0000000..ade23a4 Binary files /dev/null and b/images/icons/sla-ammo/3mm__AP.png differ diff --git a/images/icons/sla-ammo/3mm__HE.png b/images/icons/sla-ammo/3mm__HE.png new file mode 100644 index 0000000..8787e87 Binary files /dev/null and b/images/icons/sla-ammo/3mm__HE.png differ diff --git a/images/icons/sla-ammo/3mm__HEAP.png b/images/icons/sla-ammo/3mm__HEAP.png new file mode 100644 index 0000000..140833d Binary files /dev/null and b/images/icons/sla-ammo/3mm__HEAP.png differ diff --git a/images/icons/sla-ammo/3mm__STD.png b/images/icons/sla-ammo/3mm__STD.png new file mode 100644 index 0000000..df914e7 Binary files /dev/null and b/images/icons/sla-ammo/3mm__STD.png differ diff --git a/images/icons/sla-ammo/40mm-he-grenade__AP.png b/images/icons/sla-ammo/40mm-he-grenade__AP.png new file mode 100644 index 0000000..a79496a Binary files /dev/null and b/images/icons/sla-ammo/40mm-he-grenade__AP.png differ diff --git a/images/icons/sla-ammo/40mm-he-grenade__HE.png b/images/icons/sla-ammo/40mm-he-grenade__HE.png new file mode 100644 index 0000000..18de395 Binary files /dev/null and b/images/icons/sla-ammo/40mm-he-grenade__HE.png differ diff --git a/images/icons/sla-ammo/40mm-he-grenade__HEAP.png b/images/icons/sla-ammo/40mm-he-grenade__HEAP.png new file mode 100644 index 0000000..b0f6a26 Binary files /dev/null and b/images/icons/sla-ammo/40mm-he-grenade__HEAP.png differ diff --git a/images/icons/sla-ammo/40mm-he-grenade__STD.png b/images/icons/sla-ammo/40mm-he-grenade__STD.png new file mode 100644 index 0000000..ddfab3d Binary files /dev/null and b/images/icons/sla-ammo/40mm-he-grenade__STD.png differ diff --git a/images/icons/sla-ammo/40mm-smoke-gas__AP.png b/images/icons/sla-ammo/40mm-smoke-gas__AP.png new file mode 100644 index 0000000..ab8c37a Binary files /dev/null and b/images/icons/sla-ammo/40mm-smoke-gas__AP.png differ diff --git a/images/icons/sla-ammo/40mm-smoke-gas__HE.png b/images/icons/sla-ammo/40mm-smoke-gas__HE.png new file mode 100644 index 0000000..8c806b5 Binary files /dev/null and b/images/icons/sla-ammo/40mm-smoke-gas__HE.png differ diff --git a/images/icons/sla-ammo/40mm-smoke-gas__HEAP.png b/images/icons/sla-ammo/40mm-smoke-gas__HEAP.png new file mode 100644 index 0000000..ba1caf8 Binary files /dev/null and b/images/icons/sla-ammo/40mm-smoke-gas__HEAP.png differ diff --git a/images/icons/sla-ammo/40mm-smoke-gas__STD.png b/images/icons/sla-ammo/40mm-smoke-gas__STD.png new file mode 100644 index 0000000..a572565 Binary files /dev/null and b/images/icons/sla-ammo/40mm-smoke-gas__STD.png differ diff --git a/images/icons/sla-ammo/5mm-rifle__AP.png b/images/icons/sla-ammo/5mm-rifle__AP.png new file mode 100644 index 0000000..b080739 Binary files /dev/null and b/images/icons/sla-ammo/5mm-rifle__AP.png differ diff --git a/images/icons/sla-ammo/5mm-rifle__HE.png b/images/icons/sla-ammo/5mm-rifle__HE.png new file mode 100644 index 0000000..193d7e6 Binary files /dev/null and b/images/icons/sla-ammo/5mm-rifle__HE.png differ diff --git a/images/icons/sla-ammo/5mm-rifle__HEAP.png b/images/icons/sla-ammo/5mm-rifle__HEAP.png new file mode 100644 index 0000000..81c17a5 Binary files /dev/null and b/images/icons/sla-ammo/5mm-rifle__HEAP.png differ diff --git a/images/icons/sla-ammo/5mm-rifle__STD.png b/images/icons/sla-ammo/5mm-rifle__STD.png new file mode 100644 index 0000000..1332dfd Binary files /dev/null and b/images/icons/sla-ammo/5mm-rifle__STD.png differ diff --git a/images/icons/sla-ammo/5mm-smg__AP.png b/images/icons/sla-ammo/5mm-smg__AP.png new file mode 100644 index 0000000..aa7fe08 Binary files /dev/null and b/images/icons/sla-ammo/5mm-smg__AP.png differ diff --git a/images/icons/sla-ammo/5mm-smg__HE.png b/images/icons/sla-ammo/5mm-smg__HE.png new file mode 100644 index 0000000..4baca1d Binary files /dev/null and b/images/icons/sla-ammo/5mm-smg__HE.png differ diff --git a/images/icons/sla-ammo/5mm-smg__HEAP.png b/images/icons/sla-ammo/5mm-smg__HEAP.png new file mode 100644 index 0000000..aa14259 Binary files /dev/null and b/images/icons/sla-ammo/5mm-smg__HEAP.png differ diff --git a/images/icons/sla-ammo/5mm-smg__STD.png b/images/icons/sla-ammo/5mm-smg__STD.png new file mode 100644 index 0000000..ca3fafc Binary files /dev/null and b/images/icons/sla-ammo/5mm-smg__STD.png differ diff --git a/images/icons/sla-ammo/5mm__AP.png b/images/icons/sla-ammo/5mm__AP.png new file mode 100644 index 0000000..2bac9a4 Binary files /dev/null and b/images/icons/sla-ammo/5mm__AP.png differ diff --git a/images/icons/sla-ammo/5mm__HE.png b/images/icons/sla-ammo/5mm__HE.png new file mode 100644 index 0000000..c22999a Binary files /dev/null and b/images/icons/sla-ammo/5mm__HE.png differ diff --git a/images/icons/sla-ammo/5mm__HEAP.png b/images/icons/sla-ammo/5mm__HEAP.png new file mode 100644 index 0000000..19bc292 Binary files /dev/null and b/images/icons/sla-ammo/5mm__HEAP.png differ diff --git a/images/icons/sla-ammo/5mm__STD.png b/images/icons/sla-ammo/5mm__STD.png new file mode 100644 index 0000000..1caca53 Binary files /dev/null and b/images/icons/sla-ammo/5mm__STD.png differ diff --git a/images/icons/sla-ammo/7mm-rifle__AP.png b/images/icons/sla-ammo/7mm-rifle__AP.png new file mode 100644 index 0000000..5a8972a Binary files /dev/null and b/images/icons/sla-ammo/7mm-rifle__AP.png differ diff --git a/images/icons/sla-ammo/7mm-rifle__HE.png b/images/icons/sla-ammo/7mm-rifle__HE.png new file mode 100644 index 0000000..6dc7049 Binary files /dev/null and b/images/icons/sla-ammo/7mm-rifle__HE.png differ diff --git a/images/icons/sla-ammo/7mm-rifle__HEAP.png b/images/icons/sla-ammo/7mm-rifle__HEAP.png new file mode 100644 index 0000000..f2270d8 Binary files /dev/null and b/images/icons/sla-ammo/7mm-rifle__HEAP.png differ diff --git a/images/icons/sla-ammo/7mm-rifle__STD.png b/images/icons/sla-ammo/7mm-rifle__STD.png new file mode 100644 index 0000000..ab95522 Binary files /dev/null and b/images/icons/sla-ammo/7mm-rifle__STD.png differ diff --git a/images/icons/sla-ammo/8mm-rifle__AP.png b/images/icons/sla-ammo/8mm-rifle__AP.png new file mode 100644 index 0000000..915b673 Binary files /dev/null and b/images/icons/sla-ammo/8mm-rifle__AP.png differ diff --git a/images/icons/sla-ammo/8mm-rifle__HE.png b/images/icons/sla-ammo/8mm-rifle__HE.png new file mode 100644 index 0000000..f6559bd Binary files /dev/null and b/images/icons/sla-ammo/8mm-rifle__HE.png differ diff --git a/images/icons/sla-ammo/8mm-rifle__HEAP.png b/images/icons/sla-ammo/8mm-rifle__HEAP.png new file mode 100644 index 0000000..e566ef9 Binary files /dev/null and b/images/icons/sla-ammo/8mm-rifle__HEAP.png differ diff --git a/images/icons/sla-ammo/8mm-rifle__STD.png b/images/icons/sla-ammo/8mm-rifle__STD.png new file mode 100644 index 0000000..36bc54d Binary files /dev/null and b/images/icons/sla-ammo/8mm-rifle__STD.png differ diff --git a/images/icons/sla-ammo/8mm__AP.png b/images/icons/sla-ammo/8mm__AP.png new file mode 100644 index 0000000..56cb11c Binary files /dev/null and b/images/icons/sla-ammo/8mm__AP.png differ diff --git a/images/icons/sla-ammo/8mm__HE.png b/images/icons/sla-ammo/8mm__HE.png new file mode 100644 index 0000000..9951f18 Binary files /dev/null and b/images/icons/sla-ammo/8mm__HE.png differ diff --git a/images/icons/sla-ammo/8mm__HEAP.png b/images/icons/sla-ammo/8mm__HEAP.png new file mode 100644 index 0000000..95995d2 Binary files /dev/null and b/images/icons/sla-ammo/8mm__HEAP.png differ diff --git a/images/icons/sla-ammo/8mm__STD.png b/images/icons/sla-ammo/8mm__STD.png new file mode 100644 index 0000000..6bd8c11 Binary files /dev/null and b/images/icons/sla-ammo/8mm__STD.png differ diff --git a/images/icons/ui/attributes/armor.png b/images/icons/ui/attributes/armor.png new file mode 100644 index 0000000..3da0b58 Binary files /dev/null and b/images/icons/ui/attributes/armor.png differ diff --git a/images/icons/ui/attributes/battle.png b/images/icons/ui/attributes/battle.png new file mode 100644 index 0000000..425df85 Binary files /dev/null and b/images/icons/ui/attributes/battle.png differ diff --git a/images/icons/ui/attributes/body.png b/images/icons/ui/attributes/body.png new file mode 100644 index 0000000..584dd4e Binary files /dev/null and b/images/icons/ui/attributes/body.png differ diff --git a/images/icons/ui/attributes/combat.png b/images/icons/ui/attributes/combat.png new file mode 100644 index 0000000..5ab56e2 Binary files /dev/null and b/images/icons/ui/attributes/combat.png differ diff --git a/images/icons/ui/attributes/fear.png b/images/icons/ui/attributes/fear.png new file mode 100644 index 0000000..b87cb10 Binary files /dev/null and b/images/icons/ui/attributes/fear.png differ diff --git a/images/icons/ui/attributes/health.png b/images/icons/ui/attributes/health.png new file mode 100644 index 0000000..83058d3 Binary files /dev/null and b/images/icons/ui/attributes/health.png differ diff --git a/images/icons/ui/attributes/instinct.png b/images/icons/ui/attributes/instinct.png new file mode 100644 index 0000000..7aeba2d Binary files /dev/null and b/images/icons/ui/attributes/instinct.png differ diff --git a/images/icons/ui/attributes/intellect.png b/images/icons/ui/attributes/intellect.png new file mode 100644 index 0000000..44723c2 Binary files /dev/null and b/images/icons/ui/attributes/intellect.png differ diff --git a/images/icons/ui/attributes/loyalty.png b/images/icons/ui/attributes/loyalty.png new file mode 100644 index 0000000..97734ea Binary files /dev/null and b/images/icons/ui/attributes/loyalty.png differ diff --git a/images/icons/ui/attributes/sanity.png b/images/icons/ui/attributes/sanity.png new file mode 100644 index 0000000..591e11f Binary files /dev/null and b/images/icons/ui/attributes/sanity.png differ diff --git a/images/icons/ui/attributes/speed.png b/images/icons/ui/attributes/speed.png new file mode 100644 index 0000000..7f094a7 Binary files /dev/null and b/images/icons/ui/attributes/speed.png differ diff --git a/images/icons/ui/attributes/strength.png b/images/icons/ui/attributes/strength.png new file mode 100644 index 0000000..ba44481 Binary files /dev/null and b/images/icons/ui/attributes/strength.png differ diff --git a/images/icons/ui/attributes/systems.png b/images/icons/ui/attributes/systems.png new file mode 100644 index 0000000..7aaf4a1 Binary files /dev/null and b/images/icons/ui/attributes/systems.png differ diff --git a/images/icons/ui/attributes/thrusters.png b/images/icons/ui/attributes/thrusters.png new file mode 100644 index 0000000..3c7a3a2 Binary files /dev/null and b/images/icons/ui/attributes/thrusters.png differ diff --git a/images/icons/ui/conditions/addicted.png b/images/icons/ui/conditions/addicted.png new file mode 100644 index 0000000..66470eb Binary files /dev/null and b/images/icons/ui/conditions/addicted.png differ diff --git a/images/icons/ui/conditions/anxiety.png b/images/icons/ui/conditions/anxiety.png new file mode 100644 index 0000000..23aa01a Binary files /dev/null and b/images/icons/ui/conditions/anxiety.png differ diff --git a/images/icons/ui/conditions/bleeding.png b/images/icons/ui/conditions/bleeding.png new file mode 100644 index 0000000..c22ffd6 Binary files /dev/null and b/images/icons/ui/conditions/bleeding.png differ diff --git a/images/icons/ui/conditions/confused.png b/images/icons/ui/conditions/confused.png new file mode 100644 index 0000000..e443963 Binary files /dev/null and b/images/icons/ui/conditions/confused.png differ diff --git a/images/icons/ui/conditions/corrosive_atmosphere.png b/images/icons/ui/conditions/corrosive_atmosphere.png new file mode 100644 index 0000000..e3954fe Binary files /dev/null and b/images/icons/ui/conditions/corrosive_atmosphere.png differ diff --git a/images/icons/ui/conditions/coward.png b/images/icons/ui/conditions/coward.png new file mode 100644 index 0000000..c35a752 Binary files /dev/null and b/images/icons/ui/conditions/coward.png differ diff --git a/images/icons/ui/conditions/cryosickness.png b/images/icons/ui/conditions/cryosickness.png new file mode 100644 index 0000000..5fd9852 Binary files /dev/null and b/images/icons/ui/conditions/cryosickness.png differ diff --git a/images/icons/ui/conditions/data_loss.png b/images/icons/ui/conditions/data_loss.png new file mode 100644 index 0000000..362508e Binary files /dev/null and b/images/icons/ui/conditions/data_loss.png differ diff --git a/images/icons/ui/conditions/death_wish.png b/images/icons/ui/conditions/death_wish.png new file mode 100644 index 0000000..f2936cf Binary files /dev/null and b/images/icons/ui/conditions/death_wish.png differ diff --git a/images/icons/ui/conditions/deflated.png b/images/icons/ui/conditions/deflated.png new file mode 100644 index 0000000..9aed7e3 Binary files /dev/null and b/images/icons/ui/conditions/deflated.png differ diff --git a/images/icons/ui/conditions/detached.png b/images/icons/ui/conditions/detached.png new file mode 100644 index 0000000..ad959f4 Binary files /dev/null and b/images/icons/ui/conditions/detached.png differ diff --git a/images/icons/ui/conditions/distress.png b/images/icons/ui/conditions/distress.png new file mode 100644 index 0000000..0cb3e5e Binary files /dev/null and b/images/icons/ui/conditions/distress.png differ diff --git a/images/icons/ui/conditions/dizzy.png b/images/icons/ui/conditions/dizzy.png new file mode 100644 index 0000000..c44255b Binary files /dev/null and b/images/icons/ui/conditions/dizzy.png differ diff --git a/images/icons/ui/conditions/doomed.png b/images/icons/ui/conditions/doomed.png new file mode 100644 index 0000000..67a88ee Binary files /dev/null and b/images/icons/ui/conditions/doomed.png differ diff --git a/images/icons/ui/conditions/exhausted.png b/images/icons/ui/conditions/exhausted.png new file mode 100644 index 0000000..5aeda4b Binary files /dev/null and b/images/icons/ui/conditions/exhausted.png differ diff --git a/images/icons/ui/conditions/extreme_cold.png b/images/icons/ui/conditions/extreme_cold.png new file mode 100644 index 0000000..f093b44 Binary files /dev/null and b/images/icons/ui/conditions/extreme_cold.png differ diff --git a/images/icons/ui/conditions/extreme_heat.png b/images/icons/ui/conditions/extreme_heat.png new file mode 100644 index 0000000..ce33281 Binary files /dev/null and b/images/icons/ui/conditions/extreme_heat.png differ diff --git a/images/icons/ui/conditions/fatigue.png b/images/icons/ui/conditions/fatigue.png new file mode 100644 index 0000000..8126fe8 Binary files /dev/null and b/images/icons/ui/conditions/fatigue.png differ diff --git a/images/icons/ui/conditions/faulty_heuristics.png b/images/icons/ui/conditions/faulty_heuristics.png new file mode 100644 index 0000000..8ebcb21 Binary files /dev/null and b/images/icons/ui/conditions/faulty_heuristics.png differ diff --git a/images/icons/ui/conditions/frightened.png b/images/icons/ui/conditions/frightened.png new file mode 100644 index 0000000..64a3e78 Binary files /dev/null and b/images/icons/ui/conditions/frightened.png differ diff --git a/images/icons/ui/conditions/haunted.png b/images/icons/ui/conditions/haunted.png new file mode 100644 index 0000000..3418d4d Binary files /dev/null and b/images/icons/ui/conditions/haunted.png differ diff --git a/images/icons/ui/conditions/hypervigilance.png b/images/icons/ui/conditions/hypervigilance.png new file mode 100644 index 0000000..bfbbae1 Binary files /dev/null and b/images/icons/ui/conditions/hypervigilance.png differ diff --git a/images/icons/ui/conditions/irradiated.png b/images/icons/ui/conditions/irradiated.png new file mode 100644 index 0000000..66e770c Binary files /dev/null and b/images/icons/ui/conditions/irradiated.png differ diff --git a/images/icons/ui/conditions/killswitch.png b/images/icons/ui/conditions/killswitch.png new file mode 100644 index 0000000..18e8663 Binary files /dev/null and b/images/icons/ui/conditions/killswitch.png differ diff --git a/images/icons/ui/conditions/logic_core.png b/images/icons/ui/conditions/logic_core.png new file mode 100644 index 0000000..52796ff Binary files /dev/null and b/images/icons/ui/conditions/logic_core.png differ diff --git a/images/icons/ui/conditions/loss_of_confidence.png b/images/icons/ui/conditions/loss_of_confidence.png new file mode 100644 index 0000000..cd5fcb6 Binary files /dev/null and b/images/icons/ui/conditions/loss_of_confidence.png differ diff --git a/images/icons/ui/conditions/moral_compass.png b/images/icons/ui/conditions/moral_compass.png new file mode 100644 index 0000000..115e053 Binary files /dev/null and b/images/icons/ui/conditions/moral_compass.png differ diff --git a/images/icons/ui/conditions/nightmares.png b/images/icons/ui/conditions/nightmares.png new file mode 100644 index 0000000..52de742 Binary files /dev/null and b/images/icons/ui/conditions/nightmares.png differ diff --git a/images/icons/ui/conditions/software_bloat.png b/images/icons/ui/conditions/software_bloat.png new file mode 100644 index 0000000..e6d1b0f Binary files /dev/null and b/images/icons/ui/conditions/software_bloat.png differ diff --git a/images/icons/ui/conditions/spiraling.png b/images/icons/ui/conditions/spiraling.png new file mode 100644 index 0000000..dc90bb9 Binary files /dev/null and b/images/icons/ui/conditions/spiraling.png differ diff --git a/images/icons/ui/conditions/starving.png b/images/icons/ui/conditions/starving.png new file mode 100644 index 0000000..f2bbf75 Binary files /dev/null and b/images/icons/ui/conditions/starving.png differ diff --git a/images/icons/ui/conditions/suffocating.png b/images/icons/ui/conditions/suffocating.png new file mode 100644 index 0000000..1c28fc6 Binary files /dev/null and b/images/icons/ui/conditions/suffocating.png differ diff --git a/images/icons/ui/conditions/suspicious.png b/images/icons/ui/conditions/suspicious.png new file mode 100644 index 0000000..8fb0447 Binary files /dev/null and b/images/icons/ui/conditions/suspicious.png differ diff --git a/images/icons/ui/conditions/the_bends.png b/images/icons/ui/conditions/the_bends.png new file mode 100644 index 0000000..2b19934 Binary files /dev/null and b/images/icons/ui/conditions/the_bends.png differ diff --git a/images/icons/ui/conditions/the_shakes.png b/images/icons/ui/conditions/the_shakes.png new file mode 100644 index 0000000..eaac2f9 Binary files /dev/null and b/images/icons/ui/conditions/the_shakes.png differ diff --git a/images/icons/ui/conditions/toxic_atmosphere.png b/images/icons/ui/conditions/toxic_atmosphere.png new file mode 100644 index 0000000..cdb3deb Binary files /dev/null and b/images/icons/ui/conditions/toxic_atmosphere.png differ diff --git a/images/icons/ui/conditions/turing_test_failure.png b/images/icons/ui/conditions/turing_test_failure.png new file mode 100644 index 0000000..9cb570d Binary files /dev/null and b/images/icons/ui/conditions/turing_test_failure.png differ diff --git a/images/icons/ui/conditions/vocalization_failure.png b/images/icons/ui/conditions/vocalization_failure.png new file mode 100644 index 0000000..8874b38 Binary files /dev/null and b/images/icons/ui/conditions/vocalization_failure.png differ diff --git a/images/icons/ui/conditions/worship_danger.png b/images/icons/ui/conditions/worship_danger.png new file mode 100644 index 0000000..00bf52e Binary files /dev/null and b/images/icons/ui/conditions/worship_danger.png differ diff --git a/images/icons/ui/macros/create_character.png b/images/icons/ui/macros/create_character.png new file mode 100644 index 0000000..231b6ce Binary files /dev/null and b/images/icons/ui/macros/create_character.png differ diff --git a/images/icons/ui/macros/gain_stress.png b/images/icons/ui/macros/gain_stress.png new file mode 100644 index 0000000..5801672 Binary files /dev/null and b/images/icons/ui/macros/gain_stress.png differ diff --git a/images/icons/ui/macros/morale_check.png b/images/icons/ui/macros/morale_check.png new file mode 100644 index 0000000..68969e3 Binary files /dev/null and b/images/icons/ui/macros/morale_check.png differ diff --git a/images/icons/ui/macros/relieve_stress.png b/images/icons/ui/macros/relieve_stress.png new file mode 100644 index 0000000..462e26b Binary files /dev/null and b/images/icons/ui/macros/relieve_stress.png differ diff --git a/images/icons/ui/macros/reload.png b/images/icons/ui/macros/reload.png new file mode 100644 index 0000000..54d9fb6 Binary files /dev/null and b/images/icons/ui/macros/reload.png differ diff --git a/images/icons/ui/macros/rest_save.png b/images/icons/ui/macros/rest_save.png new file mode 100644 index 0000000..84f5388 Binary files /dev/null and b/images/icons/ui/macros/rest_save.png differ diff --git a/images/icons/ui/macros/save.png b/images/icons/ui/macros/save.png new file mode 100644 index 0000000..47048f8 Binary files /dev/null and b/images/icons/ui/macros/save.png differ diff --git a/images/icons/ui/macros/stat_check.png b/images/icons/ui/macros/stat_check.png new file mode 100644 index 0000000..aa3f3cc Binary files /dev/null and b/images/icons/ui/macros/stat_check.png differ diff --git a/images/icons/ui/macros/wound_roll.png b/images/icons/ui/macros/wound_roll.png new file mode 100644 index 0000000..aa57a26 Binary files /dev/null and b/images/icons/ui/macros/wound_roll.png differ diff --git a/images/icons/ui/rolltables/bankruptcy_save.png b/images/icons/ui/rolltables/bankruptcy_save.png new file mode 100644 index 0000000..4ed5956 Binary files /dev/null and b/images/icons/ui/rolltables/bankruptcy_save.png differ diff --git a/images/icons/ui/rolltables/death_save.png b/images/icons/ui/rolltables/death_save.png new file mode 100644 index 0000000..bf292c8 Binary files /dev/null and b/images/icons/ui/rolltables/death_save.png differ diff --git a/images/icons/ui/rolltables/distress_signal.png b/images/icons/ui/rolltables/distress_signal.png new file mode 100644 index 0000000..e1c6538 Binary files /dev/null and b/images/icons/ui/rolltables/distress_signal.png differ diff --git a/images/icons/ui/rolltables/maintenance_issues.png b/images/icons/ui/rolltables/maintenance_issues.png new file mode 100644 index 0000000..bc68c67 Binary files /dev/null and b/images/icons/ui/rolltables/maintenance_issues.png differ diff --git a/images/icons/ui/rolltables/megadamage_effects.png b/images/icons/ui/rolltables/megadamage_effects.png new file mode 100644 index 0000000..95d9493 Binary files /dev/null and b/images/icons/ui/rolltables/megadamage_effects.png differ diff --git a/images/icons/ui/rolltables/panic_check.png b/images/icons/ui/rolltables/panic_check.png new file mode 100644 index 0000000..b1c84dd Binary files /dev/null and b/images/icons/ui/rolltables/panic_check.png differ diff --git a/images/icons/ui/rolltables/wounds_bleeding.png b/images/icons/ui/rolltables/wounds_bleeding.png new file mode 100644 index 0000000..dc538c6 Binary files /dev/null and b/images/icons/ui/rolltables/wounds_bleeding.png differ diff --git a/images/icons/ui/rolltables/wounds_blunt_force.png b/images/icons/ui/rolltables/wounds_blunt_force.png new file mode 100644 index 0000000..f3c37da Binary files /dev/null and b/images/icons/ui/rolltables/wounds_blunt_force.png differ diff --git a/images/icons/ui/rolltables/wounds_fire_&_explosives.png b/images/icons/ui/rolltables/wounds_fire_&_explosives.png new file mode 100644 index 0000000..1202b17 Binary files /dev/null and b/images/icons/ui/rolltables/wounds_fire_&_explosives.png differ diff --git a/images/icons/ui/rolltables/wounds_gore_&_massive.png b/images/icons/ui/rolltables/wounds_gore_&_massive.png new file mode 100644 index 0000000..bb3c92d Binary files /dev/null and b/images/icons/ui/rolltables/wounds_gore_&_massive.png differ diff --git a/images/icons/ui/rolltables/wounds_gunshot.png b/images/icons/ui/rolltables/wounds_gunshot.png new file mode 100644 index 0000000..176d4d1 Binary files /dev/null and b/images/icons/ui/rolltables/wounds_gunshot.png differ diff --git a/images/icons/ui/system/logo.webp b/images/icons/ui/system/logo.webp new file mode 100644 index 0000000..1eea4f3 Binary files /dev/null and b/images/icons/ui/system/logo.webp differ diff --git a/images/icons/ui/system/mosh-background.webp b/images/icons/ui/system/mosh-background.webp new file mode 100644 index 0000000..7a6e058 Binary files /dev/null and b/images/icons/ui/system/mosh-background.webp differ diff --git a/images/icons/ui/system/mosh-repo.webp b/images/icons/ui/system/mosh-repo.webp new file mode 100644 index 0000000..f1b32ff Binary files /dev/null and b/images/icons/ui/system/mosh-repo.webp differ diff --git a/images/icons/ui/system/mosh-thumbnail.webp b/images/icons/ui/system/mosh-thumbnail.webp new file mode 100644 index 0000000..ddcdad8 Binary files /dev/null and b/images/icons/ui/system/mosh-thumbnail.webp differ diff --git a/images/icons/ui/system/pause.webp b/images/icons/ui/system/pause.webp new file mode 100644 index 0000000..b6fe0b6 Binary files /dev/null and b/images/icons/ui/system/pause.webp differ diff --git a/images/sla-assets/Ammo/10-gauge-he__AP.png b/images/sla-assets/Ammo/10-gauge-he__AP.png new file mode 100644 index 0000000..c225722 Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge-he__AP.png differ diff --git a/images/sla-assets/Ammo/10-gauge-he__HE.png b/images/sla-assets/Ammo/10-gauge-he__HE.png new file mode 100644 index 0000000..40ab7aa Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge-he__HE.png differ diff --git a/images/sla-assets/Ammo/10-gauge-he__HEAP.png b/images/sla-assets/Ammo/10-gauge-he__HEAP.png new file mode 100644 index 0000000..7213641 Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge-he__HEAP.png differ diff --git a/images/sla-assets/Ammo/10-gauge-he__STD.png b/images/sla-assets/Ammo/10-gauge-he__STD.png new file mode 100644 index 0000000..6657842 Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge-he__STD.png differ diff --git a/images/sla-assets/Ammo/10-gauge__AP.png b/images/sla-assets/Ammo/10-gauge__AP.png new file mode 100644 index 0000000..d93749d Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge__AP.png differ diff --git a/images/sla-assets/Ammo/10-gauge__HE.png b/images/sla-assets/Ammo/10-gauge__HE.png new file mode 100644 index 0000000..a5baea4 Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge__HE.png differ diff --git a/images/sla-assets/Ammo/10-gauge__HEAP.png b/images/sla-assets/Ammo/10-gauge__HEAP.png new file mode 100644 index 0000000..7a2e6b1 Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge__HEAP.png differ diff --git a/images/sla-assets/Ammo/10-gauge__STD.png b/images/sla-assets/Ammo/10-gauge__STD.png new file mode 100644 index 0000000..98378a3 Binary files /dev/null and b/images/sla-assets/Ammo/10-gauge__STD.png differ diff --git a/images/sla-assets/Ammo/10mm-pistol__AP.png b/images/sla-assets/Ammo/10mm-pistol__AP.png new file mode 100644 index 0000000..7f7c324 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-pistol__AP.png differ diff --git a/images/sla-assets/Ammo/10mm-pistol__HE.png b/images/sla-assets/Ammo/10mm-pistol__HE.png new file mode 100644 index 0000000..58ef473 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-pistol__HE.png differ diff --git a/images/sla-assets/Ammo/10mm-pistol__HEAP.png b/images/sla-assets/Ammo/10mm-pistol__HEAP.png new file mode 100644 index 0000000..2ded85b Binary files /dev/null and b/images/sla-assets/Ammo/10mm-pistol__HEAP.png differ diff --git a/images/sla-assets/Ammo/10mm-pistol__STD.png b/images/sla-assets/Ammo/10mm-pistol__STD.png new file mode 100644 index 0000000..4952131 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-pistol__STD.png differ diff --git a/images/sla-assets/Ammo/10mm-rifle__AP.png b/images/sla-assets/Ammo/10mm-rifle__AP.png new file mode 100644 index 0000000..b4a37d0 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-rifle__AP.png differ diff --git a/images/sla-assets/Ammo/10mm-rifle__HE.png b/images/sla-assets/Ammo/10mm-rifle__HE.png new file mode 100644 index 0000000..43305ae Binary files /dev/null and b/images/sla-assets/Ammo/10mm-rifle__HE.png differ diff --git a/images/sla-assets/Ammo/10mm-rifle__HEAP.png b/images/sla-assets/Ammo/10mm-rifle__HEAP.png new file mode 100644 index 0000000..1a6a3ef Binary files /dev/null and b/images/sla-assets/Ammo/10mm-rifle__HEAP.png differ diff --git a/images/sla-assets/Ammo/10mm-rifle__STD.png b/images/sla-assets/Ammo/10mm-rifle__STD.png new file mode 100644 index 0000000..b08973b Binary files /dev/null and b/images/sla-assets/Ammo/10mm-rifle__STD.png differ diff --git a/images/sla-assets/Ammo/10mm-smg__AP.png b/images/sla-assets/Ammo/10mm-smg__AP.png new file mode 100644 index 0000000..4fb1651 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-smg__AP.png differ diff --git a/images/sla-assets/Ammo/10mm-smg__HE.png b/images/sla-assets/Ammo/10mm-smg__HE.png new file mode 100644 index 0000000..09dbe13 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-smg__HE.png differ diff --git a/images/sla-assets/Ammo/10mm-smg__HEAP.png b/images/sla-assets/Ammo/10mm-smg__HEAP.png new file mode 100644 index 0000000..8b86442 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-smg__HEAP.png differ diff --git a/images/sla-assets/Ammo/10mm-smg__STD.png b/images/sla-assets/Ammo/10mm-smg__STD.png new file mode 100644 index 0000000..b6fe4c3 Binary files /dev/null and b/images/sla-assets/Ammo/10mm-smg__STD.png differ diff --git a/images/sla-assets/Ammo/12-gauge-he__AP.png b/images/sla-assets/Ammo/12-gauge-he__AP.png new file mode 100644 index 0000000..c69c00b Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge-he__AP.png differ diff --git a/images/sla-assets/Ammo/12-gauge-he__HE.png b/images/sla-assets/Ammo/12-gauge-he__HE.png new file mode 100644 index 0000000..052b603 Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge-he__HE.png differ diff --git a/images/sla-assets/Ammo/12-gauge-he__HEAP.png b/images/sla-assets/Ammo/12-gauge-he__HEAP.png new file mode 100644 index 0000000..8fe1a23 Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge-he__HEAP.png differ diff --git a/images/sla-assets/Ammo/12-gauge-he__STD.png b/images/sla-assets/Ammo/12-gauge-he__STD.png new file mode 100644 index 0000000..eeb88cd Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge-he__STD.png differ diff --git a/images/sla-assets/Ammo/12-gauge__AP.png b/images/sla-assets/Ammo/12-gauge__AP.png new file mode 100644 index 0000000..0ec2715 Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge__AP.png differ diff --git a/images/sla-assets/Ammo/12-gauge__HE.png b/images/sla-assets/Ammo/12-gauge__HE.png new file mode 100644 index 0000000..12f92c4 Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge__HE.png differ diff --git a/images/sla-assets/Ammo/12-gauge__HEAP.png b/images/sla-assets/Ammo/12-gauge__HEAP.png new file mode 100644 index 0000000..ec38832 Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge__HEAP.png differ diff --git a/images/sla-assets/Ammo/12-gauge__STD.png b/images/sla-assets/Ammo/12-gauge__STD.png new file mode 100644 index 0000000..a6bd177 Binary files /dev/null and b/images/sla-assets/Ammo/12-gauge__STD.png differ diff --git a/images/sla-assets/Ammo/12mm__AP.png b/images/sla-assets/Ammo/12mm__AP.png new file mode 100644 index 0000000..94cd8eb Binary files /dev/null and b/images/sla-assets/Ammo/12mm__AP.png differ diff --git a/images/sla-assets/Ammo/12mm__HE.png b/images/sla-assets/Ammo/12mm__HE.png new file mode 100644 index 0000000..e0cefe6 Binary files /dev/null and b/images/sla-assets/Ammo/12mm__HE.png differ diff --git a/images/sla-assets/Ammo/12mm__HEAP.png b/images/sla-assets/Ammo/12mm__HEAP.png new file mode 100644 index 0000000..c223fdb Binary files /dev/null and b/images/sla-assets/Ammo/12mm__HEAP.png differ diff --git a/images/sla-assets/Ammo/12mm__STD.png b/images/sla-assets/Ammo/12mm__STD.png new file mode 100644 index 0000000..ddaab10 Binary files /dev/null and b/images/sla-assets/Ammo/12mm__STD.png differ diff --git a/images/sla-assets/Ammo/20mm-hedp__AP.png b/images/sla-assets/Ammo/20mm-hedp__AP.png new file mode 100644 index 0000000..7a50db2 Binary files /dev/null and b/images/sla-assets/Ammo/20mm-hedp__AP.png differ diff --git a/images/sla-assets/Ammo/20mm-hedp__HE.png b/images/sla-assets/Ammo/20mm-hedp__HE.png new file mode 100644 index 0000000..bb94996 Binary files /dev/null and b/images/sla-assets/Ammo/20mm-hedp__HE.png differ diff --git a/images/sla-assets/Ammo/20mm-hedp__HEAP.png b/images/sla-assets/Ammo/20mm-hedp__HEAP.png new file mode 100644 index 0000000..4e28398 Binary files /dev/null and b/images/sla-assets/Ammo/20mm-hedp__HEAP.png differ diff --git a/images/sla-assets/Ammo/20mm-hedp__STD.png b/images/sla-assets/Ammo/20mm-hedp__STD.png new file mode 100644 index 0000000..323d1aa Binary files /dev/null and b/images/sla-assets/Ammo/20mm-hedp__STD.png differ diff --git a/images/sla-assets/Ammo/25mm-he__AP.png b/images/sla-assets/Ammo/25mm-he__AP.png new file mode 100644 index 0000000..5438607 Binary files /dev/null and b/images/sla-assets/Ammo/25mm-he__AP.png differ diff --git a/images/sla-assets/Ammo/25mm-he__HE.png b/images/sla-assets/Ammo/25mm-he__HE.png new file mode 100644 index 0000000..5fca8bf Binary files /dev/null and b/images/sla-assets/Ammo/25mm-he__HE.png differ diff --git a/images/sla-assets/Ammo/25mm-he__HEAP.png b/images/sla-assets/Ammo/25mm-he__HEAP.png new file mode 100644 index 0000000..6d23afe Binary files /dev/null and b/images/sla-assets/Ammo/25mm-he__HEAP.png differ diff --git a/images/sla-assets/Ammo/25mm-he__STD.png b/images/sla-assets/Ammo/25mm-he__STD.png new file mode 100644 index 0000000..eb60a4d Binary files /dev/null and b/images/sla-assets/Ammo/25mm-he__STD.png differ diff --git a/images/sla-assets/Ammo/30mm-heat__AP.png b/images/sla-assets/Ammo/30mm-heat__AP.png new file mode 100644 index 0000000..de798e7 Binary files /dev/null and b/images/sla-assets/Ammo/30mm-heat__AP.png differ diff --git a/images/sla-assets/Ammo/30mm-heat__HE.png b/images/sla-assets/Ammo/30mm-heat__HE.png new file mode 100644 index 0000000..f1fbda2 Binary files /dev/null and b/images/sla-assets/Ammo/30mm-heat__HE.png differ diff --git a/images/sla-assets/Ammo/30mm-heat__HEAP.png b/images/sla-assets/Ammo/30mm-heat__HEAP.png new file mode 100644 index 0000000..4c1f31c Binary files /dev/null and b/images/sla-assets/Ammo/30mm-heat__HEAP.png differ diff --git a/images/sla-assets/Ammo/30mm-heat__STD.png b/images/sla-assets/Ammo/30mm-heat__STD.png new file mode 100644 index 0000000..450518c Binary files /dev/null and b/images/sla-assets/Ammo/30mm-heat__STD.png differ diff --git a/images/sla-assets/Ammo/3mm-smg__AP.png b/images/sla-assets/Ammo/3mm-smg__AP.png new file mode 100644 index 0000000..7b8e1a8 Binary files /dev/null and b/images/sla-assets/Ammo/3mm-smg__AP.png differ diff --git a/images/sla-assets/Ammo/3mm-smg__HE.png b/images/sla-assets/Ammo/3mm-smg__HE.png new file mode 100644 index 0000000..f1703d4 Binary files /dev/null and b/images/sla-assets/Ammo/3mm-smg__HE.png differ diff --git a/images/sla-assets/Ammo/3mm-smg__HEAP.png b/images/sla-assets/Ammo/3mm-smg__HEAP.png new file mode 100644 index 0000000..19a2638 Binary files /dev/null and b/images/sla-assets/Ammo/3mm-smg__HEAP.png differ diff --git a/images/sla-assets/Ammo/3mm-smg__STD.png b/images/sla-assets/Ammo/3mm-smg__STD.png new file mode 100644 index 0000000..08026d1 Binary files /dev/null and b/images/sla-assets/Ammo/3mm-smg__STD.png differ diff --git a/images/sla-assets/Ammo/3mm__AP.png b/images/sla-assets/Ammo/3mm__AP.png new file mode 100644 index 0000000..ade23a4 Binary files /dev/null and b/images/sla-assets/Ammo/3mm__AP.png differ diff --git a/images/sla-assets/Ammo/3mm__HE.png b/images/sla-assets/Ammo/3mm__HE.png new file mode 100644 index 0000000..8787e87 Binary files /dev/null and b/images/sla-assets/Ammo/3mm__HE.png differ diff --git a/images/sla-assets/Ammo/3mm__HEAP.png b/images/sla-assets/Ammo/3mm__HEAP.png new file mode 100644 index 0000000..140833d Binary files /dev/null and b/images/sla-assets/Ammo/3mm__HEAP.png differ diff --git a/images/sla-assets/Ammo/3mm__STD.png b/images/sla-assets/Ammo/3mm__STD.png new file mode 100644 index 0000000..df914e7 Binary files /dev/null and b/images/sla-assets/Ammo/3mm__STD.png differ diff --git a/images/sla-assets/Ammo/40mm-he-grenade__AP.png b/images/sla-assets/Ammo/40mm-he-grenade__AP.png new file mode 100644 index 0000000..a79496a Binary files /dev/null and b/images/sla-assets/Ammo/40mm-he-grenade__AP.png differ diff --git a/images/sla-assets/Ammo/40mm-he-grenade__HE.png b/images/sla-assets/Ammo/40mm-he-grenade__HE.png new file mode 100644 index 0000000..18de395 Binary files /dev/null and b/images/sla-assets/Ammo/40mm-he-grenade__HE.png differ diff --git a/images/sla-assets/Ammo/40mm-he-grenade__HEAP.png b/images/sla-assets/Ammo/40mm-he-grenade__HEAP.png new file mode 100644 index 0000000..b0f6a26 Binary files /dev/null and b/images/sla-assets/Ammo/40mm-he-grenade__HEAP.png differ diff --git a/images/sla-assets/Ammo/40mm-he-grenade__STD.png b/images/sla-assets/Ammo/40mm-he-grenade__STD.png new file mode 100644 index 0000000..ddfab3d Binary files /dev/null and b/images/sla-assets/Ammo/40mm-he-grenade__STD.png differ diff --git a/images/sla-assets/Ammo/40mm-smoke-gas__AP.png b/images/sla-assets/Ammo/40mm-smoke-gas__AP.png new file mode 100644 index 0000000..ab8c37a Binary files /dev/null and b/images/sla-assets/Ammo/40mm-smoke-gas__AP.png differ diff --git a/images/sla-assets/Ammo/40mm-smoke-gas__HE.png b/images/sla-assets/Ammo/40mm-smoke-gas__HE.png new file mode 100644 index 0000000..8c806b5 Binary files /dev/null and b/images/sla-assets/Ammo/40mm-smoke-gas__HE.png differ diff --git a/images/sla-assets/Ammo/40mm-smoke-gas__HEAP.png b/images/sla-assets/Ammo/40mm-smoke-gas__HEAP.png new file mode 100644 index 0000000..ba1caf8 Binary files /dev/null and b/images/sla-assets/Ammo/40mm-smoke-gas__HEAP.png differ diff --git a/images/sla-assets/Ammo/40mm-smoke-gas__STD.png b/images/sla-assets/Ammo/40mm-smoke-gas__STD.png new file mode 100644 index 0000000..a572565 Binary files /dev/null and b/images/sla-assets/Ammo/40mm-smoke-gas__STD.png differ diff --git a/images/sla-assets/Ammo/5mm-rifle__AP.png b/images/sla-assets/Ammo/5mm-rifle__AP.png new file mode 100644 index 0000000..b080739 Binary files /dev/null and b/images/sla-assets/Ammo/5mm-rifle__AP.png differ diff --git a/images/sla-assets/Ammo/5mm-rifle__HE.png b/images/sla-assets/Ammo/5mm-rifle__HE.png new file mode 100644 index 0000000..193d7e6 Binary files /dev/null and b/images/sla-assets/Ammo/5mm-rifle__HE.png differ diff --git a/images/sla-assets/Ammo/5mm-rifle__HEAP.png b/images/sla-assets/Ammo/5mm-rifle__HEAP.png new file mode 100644 index 0000000..81c17a5 Binary files /dev/null and b/images/sla-assets/Ammo/5mm-rifle__HEAP.png differ diff --git a/images/sla-assets/Ammo/5mm-rifle__STD.png b/images/sla-assets/Ammo/5mm-rifle__STD.png new file mode 100644 index 0000000..1332dfd Binary files /dev/null and b/images/sla-assets/Ammo/5mm-rifle__STD.png differ diff --git a/images/sla-assets/Ammo/5mm-smg__AP.png b/images/sla-assets/Ammo/5mm-smg__AP.png new file mode 100644 index 0000000..aa7fe08 Binary files /dev/null and b/images/sla-assets/Ammo/5mm-smg__AP.png differ diff --git a/images/sla-assets/Ammo/5mm-smg__HE.png b/images/sla-assets/Ammo/5mm-smg__HE.png new file mode 100644 index 0000000..4baca1d Binary files /dev/null and b/images/sla-assets/Ammo/5mm-smg__HE.png differ diff --git a/images/sla-assets/Ammo/5mm-smg__HEAP.png b/images/sla-assets/Ammo/5mm-smg__HEAP.png new file mode 100644 index 0000000..aa14259 Binary files /dev/null and b/images/sla-assets/Ammo/5mm-smg__HEAP.png differ diff --git a/images/sla-assets/Ammo/5mm-smg__STD.png b/images/sla-assets/Ammo/5mm-smg__STD.png new file mode 100644 index 0000000..ca3fafc Binary files /dev/null and b/images/sla-assets/Ammo/5mm-smg__STD.png differ diff --git a/images/sla-assets/Ammo/5mm__AP.png b/images/sla-assets/Ammo/5mm__AP.png new file mode 100644 index 0000000..2bac9a4 Binary files /dev/null and b/images/sla-assets/Ammo/5mm__AP.png differ diff --git a/images/sla-assets/Ammo/5mm__HE.png b/images/sla-assets/Ammo/5mm__HE.png new file mode 100644 index 0000000..c22999a Binary files /dev/null and b/images/sla-assets/Ammo/5mm__HE.png differ diff --git a/images/sla-assets/Ammo/5mm__HEAP.png b/images/sla-assets/Ammo/5mm__HEAP.png new file mode 100644 index 0000000..19bc292 Binary files /dev/null and b/images/sla-assets/Ammo/5mm__HEAP.png differ diff --git a/images/sla-assets/Ammo/5mm__STD.png b/images/sla-assets/Ammo/5mm__STD.png new file mode 100644 index 0000000..1caca53 Binary files /dev/null and b/images/sla-assets/Ammo/5mm__STD.png differ diff --git a/images/sla-assets/Ammo/7mm-rifle__AP.png b/images/sla-assets/Ammo/7mm-rifle__AP.png new file mode 100644 index 0000000..5a8972a Binary files /dev/null and b/images/sla-assets/Ammo/7mm-rifle__AP.png differ diff --git a/images/sla-assets/Ammo/7mm-rifle__HE.png b/images/sla-assets/Ammo/7mm-rifle__HE.png new file mode 100644 index 0000000..6dc7049 Binary files /dev/null and b/images/sla-assets/Ammo/7mm-rifle__HE.png differ diff --git a/images/sla-assets/Ammo/7mm-rifle__HEAP.png b/images/sla-assets/Ammo/7mm-rifle__HEAP.png new file mode 100644 index 0000000..f2270d8 Binary files /dev/null and b/images/sla-assets/Ammo/7mm-rifle__HEAP.png differ diff --git a/images/sla-assets/Ammo/7mm-rifle__STD.png b/images/sla-assets/Ammo/7mm-rifle__STD.png new file mode 100644 index 0000000..ab95522 Binary files /dev/null and b/images/sla-assets/Ammo/7mm-rifle__STD.png differ diff --git a/images/sla-assets/Ammo/8mm-rifle__AP.png b/images/sla-assets/Ammo/8mm-rifle__AP.png new file mode 100644 index 0000000..915b673 Binary files /dev/null and b/images/sla-assets/Ammo/8mm-rifle__AP.png differ diff --git a/images/sla-assets/Ammo/8mm-rifle__HE.png b/images/sla-assets/Ammo/8mm-rifle__HE.png new file mode 100644 index 0000000..f6559bd Binary files /dev/null and b/images/sla-assets/Ammo/8mm-rifle__HE.png differ diff --git a/images/sla-assets/Ammo/8mm-rifle__HEAP.png b/images/sla-assets/Ammo/8mm-rifle__HEAP.png new file mode 100644 index 0000000..e566ef9 Binary files /dev/null and b/images/sla-assets/Ammo/8mm-rifle__HEAP.png differ diff --git a/images/sla-assets/Ammo/8mm-rifle__STD.png b/images/sla-assets/Ammo/8mm-rifle__STD.png new file mode 100644 index 0000000..36bc54d Binary files /dev/null and b/images/sla-assets/Ammo/8mm-rifle__STD.png differ diff --git a/images/sla-assets/Ammo/8mm__AP.png b/images/sla-assets/Ammo/8mm__AP.png new file mode 100644 index 0000000..56cb11c Binary files /dev/null and b/images/sla-assets/Ammo/8mm__AP.png differ diff --git a/images/sla-assets/Ammo/8mm__HE.png b/images/sla-assets/Ammo/8mm__HE.png new file mode 100644 index 0000000..9951f18 Binary files /dev/null and b/images/sla-assets/Ammo/8mm__HE.png differ diff --git a/images/sla-assets/Ammo/8mm__HEAP.png b/images/sla-assets/Ammo/8mm__HEAP.png new file mode 100644 index 0000000..95995d2 Binary files /dev/null and b/images/sla-assets/Ammo/8mm__HEAP.png differ diff --git a/images/sla-assets/Ammo/8mm__STD.png b/images/sla-assets/Ammo/8mm__STD.png new file mode 100644 index 0000000..6bd8c11 Binary files /dev/null and b/images/sla-assets/Ammo/8mm__STD.png differ diff --git a/images/sla-assets/Armor/2nd try/CAF.png b/images/sla-assets/Armor/2nd try/CAF.png new file mode 100644 index 0000000..c1f3422 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/CAF.png differ diff --git a/images/sla-assets/Armor/2nd try/Chippy.png b/images/sla-assets/Armor/2nd try/Chippy.png new file mode 100644 index 0000000..81840f3 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Chippy.png differ diff --git a/images/sla-assets/Armor/2nd try/Crackshot.png b/images/sla-assets/Armor/2nd try/Crackshot.png new file mode 100644 index 0000000..9820028 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Crackshot.png differ diff --git a/images/sla-assets/Armor/2nd try/Dark Night Power.png b/images/sla-assets/Armor/2nd try/Dark Night Power.png new file mode 100644 index 0000000..dc0cbd5 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Dark Night Power.png differ diff --git a/images/sla-assets/Armor/2nd try/Dodgybone.png b/images/sla-assets/Armor/2nd try/Dodgybone.png new file mode 100644 index 0000000..e085d56 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Dodgybone.png differ diff --git a/images/sla-assets/Armor/2nd try/Ebb Dethsuit.png b/images/sla-assets/Armor/2nd try/Ebb Dethsuit.png new file mode 100644 index 0000000..d9e00b6 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Ebb Dethsuit.png differ diff --git a/images/sla-assets/Armor/2nd try/Hazmat.png b/images/sla-assets/Armor/2nd try/Hazmat.png new file mode 100644 index 0000000..efe2671 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Hazmat.png differ diff --git a/images/sla-assets/Armor/2nd try/Heavy Thresher.png b/images/sla-assets/Armor/2nd try/Heavy Thresher.png new file mode 100644 index 0000000..c79d427 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Heavy Thresher.png differ diff --git a/images/sla-assets/Armor/2nd try/Light Thresher.png b/images/sla-assets/Armor/2nd try/Light Thresher.png new file mode 100644 index 0000000..61b474a Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Light Thresher.png differ diff --git a/images/sla-assets/Armor/2nd try/PP644 Body Blocker.png b/images/sla-assets/Armor/2nd try/PP644 Body Blocker.png new file mode 100644 index 0000000..2d7d665 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/PP644 Body Blocker.png differ diff --git a/images/sla-assets/Armor/2nd try/Riot Shield.png b/images/sla-assets/Armor/2nd try/Riot Shield.png new file mode 100644 index 0000000..465f5f7 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Riot Shield.png differ diff --git a/images/sla-assets/Armor/2nd try/SLA Combat Armor.png b/images/sla-assets/Armor/2nd try/SLA Combat Armor.png new file mode 100644 index 0000000..151d457 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/SLA Combat Armor.png differ diff --git a/images/sla-assets/Armor/2nd try/SLA Covert Vest.png b/images/sla-assets/Armor/2nd try/SLA Covert Vest.png new file mode 100644 index 0000000..ed4007e Binary files /dev/null and b/images/sla-assets/Armor/2nd try/SLA Covert Vest.png differ diff --git a/images/sla-assets/Armor/2nd try/SLA Heavy Assult.png b/images/sla-assets/Armor/2nd try/SLA Heavy Assult.png new file mode 100644 index 0000000..0051829 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/SLA Heavy Assult.png differ diff --git a/images/sla-assets/Armor/2nd try/SLA Patrole Armour.png b/images/sla-assets/Armor/2nd try/SLA Patrole Armour.png new file mode 100644 index 0000000..17374fd Binary files /dev/null and b/images/sla-assets/Armor/2nd try/SLA Patrole Armour.png differ diff --git a/images/sla-assets/Armor/2nd try/SLA Recon Mesh.png b/images/sla-assets/Armor/2nd try/SLA Recon Mesh.png new file mode 100644 index 0000000..bc54dd8 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/SLA Recon Mesh.png differ diff --git a/images/sla-assets/Armor/2nd try/Shiver Flak Vest.png b/images/sla-assets/Armor/2nd try/Shiver Flak Vest.png new file mode 100644 index 0000000..b82d6a0 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Shiver Flak Vest.png differ diff --git a/images/sla-assets/Armor/2nd try/Shiver.png b/images/sla-assets/Armor/2nd try/Shiver.png new file mode 100644 index 0000000..c692810 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Shiver.png differ diff --git a/images/sla-assets/Armor/2nd try/Shock Armor.png b/images/sla-assets/Armor/2nd try/Shock Armor.png new file mode 100644 index 0000000..212fe19 Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Shock Armor.png differ diff --git a/images/sla-assets/Armor/2nd try/Stealth Suit.png b/images/sla-assets/Armor/2nd try/Stealth Suit.png new file mode 100644 index 0000000..347cf0c Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Stealth Suit.png differ diff --git a/images/sla-assets/Armor/2nd try/Street Cloths.png b/images/sla-assets/Armor/2nd try/Street Cloths.png new file mode 100644 index 0000000..35ee14c Binary files /dev/null and b/images/sla-assets/Armor/2nd try/Street Cloths.png differ diff --git a/images/sla-assets/Armor/CAF Armour.png b/images/sla-assets/Armor/CAF Armour.png new file mode 100644 index 0000000..e017a34 Binary files /dev/null and b/images/sla-assets/Armor/CAF Armour.png differ diff --git a/images/sla-assets/Armor/Downtown Jacket.png b/images/sla-assets/Armor/Downtown Jacket.png new file mode 100644 index 0000000..7f38ef6 Binary files /dev/null and b/images/sla-assets/Armor/Downtown Jacket.png differ diff --git a/images/sla-assets/Armor/Exo Armor.png b/images/sla-assets/Armor/Exo Armor.png new file mode 100644 index 0000000..fb86703 Binary files /dev/null and b/images/sla-assets/Armor/Exo Armor.png differ diff --git a/images/sla-assets/Armor/Hard Armor.png b/images/sla-assets/Armor/Hard Armor.png new file mode 100644 index 0000000..fef2b05 Binary files /dev/null and b/images/sla-assets/Armor/Hard Armor.png differ diff --git a/images/sla-assets/Armor/Scout Armor.png b/images/sla-assets/Armor/Scout Armor.png new file mode 100644 index 0000000..ad89dfa Binary files /dev/null and b/images/sla-assets/Armor/Scout Armor.png differ diff --git a/images/sla-assets/Armor/Squad Shieled Power Armor.png b/images/sla-assets/Armor/Squad Shieled Power Armor.png new file mode 100644 index 0000000..78e7f7e Binary files /dev/null and b/images/sla-assets/Armor/Squad Shieled Power Armor.png differ diff --git a/images/sla-assets/Drugs/2nd try/Blaze UV.png b/images/sla-assets/Drugs/2nd try/Blaze UV.png new file mode 100644 index 0000000..ed524e3 Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Blaze UV.png differ diff --git a/images/sla-assets/Drugs/2nd try/Bozerker.png b/images/sla-assets/Drugs/2nd try/Bozerker.png new file mode 100644 index 0000000..9958d9c Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Bozerker.png differ diff --git a/images/sla-assets/Drugs/2nd try/Bubbles.png b/images/sla-assets/Drugs/2nd try/Bubbles.png new file mode 100644 index 0000000..15f4380 Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Bubbles.png differ diff --git a/images/sla-assets/Drugs/2nd try/Drum.png b/images/sla-assets/Drugs/2nd try/Drum.png new file mode 100644 index 0000000..e7d23be Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Drum.png differ diff --git a/images/sla-assets/Drugs/2nd try/Flip.png b/images/sla-assets/Drugs/2nd try/Flip.png new file mode 100644 index 0000000..c401c31 Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Flip.png differ diff --git a/images/sla-assets/Drugs/2nd try/Honesty.png b/images/sla-assets/Drugs/2nd try/Honesty.png new file mode 100644 index 0000000..a5e825d Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Honesty.png differ diff --git a/images/sla-assets/Drugs/2nd try/Push.png b/images/sla-assets/Drugs/2nd try/Push.png new file mode 100644 index 0000000..5b6175c Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Push.png differ diff --git a/images/sla-assets/Drugs/2nd try/Rush.png b/images/sla-assets/Drugs/2nd try/Rush.png new file mode 100644 index 0000000..fd90a01 Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Rush.png differ diff --git a/images/sla-assets/Drugs/2nd try/Slosh.png b/images/sla-assets/Drugs/2nd try/Slosh.png new file mode 100644 index 0000000..c3367f1 Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/Slosh.png differ diff --git a/images/sla-assets/Drugs/2nd try/shatter.png b/images/sla-assets/Drugs/2nd try/shatter.png new file mode 100644 index 0000000..3c2770e Binary files /dev/null and b/images/sla-assets/Drugs/2nd try/shatter.png differ diff --git a/images/sla-assets/Drugs/Calmline.png b/images/sla-assets/Drugs/Calmline.png new file mode 100644 index 0000000..c3b6efd Binary files /dev/null and b/images/sla-assets/Drugs/Calmline.png differ diff --git a/images/sla-assets/Drugs/Generated/blaze.svg b/images/sla-assets/Drugs/Generated/blaze.svg new file mode 100644 index 0000000..cee6d93 --- /dev/null +++ b/images/sla-assets/Drugs/Generated/blaze.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + B + + BLAZE UV + COMBAT + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/bozerker.svg b/images/sla-assets/Drugs/Generated/bozerker.svg new file mode 100644 index 0000000..0a6f483 --- /dev/null +++ b/images/sla-assets/Drugs/Generated/bozerker.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + Z + + BOZERKER + COMBAT + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/bubbles.svg b/images/sla-assets/Drugs/Generated/bubbles.svg new file mode 100644 index 0000000..faa4649 --- /dev/null +++ b/images/sla-assets/Drugs/Generated/bubbles.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + U + + BUBBLES + SOFT + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/drum.svg b/images/sla-assets/Drugs/Generated/drum.svg new file mode 100644 index 0000000..51857e9 --- /dev/null +++ b/images/sla-assets/Drugs/Generated/drum.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + D + + DRUM + COMBAT + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/flip.svg b/images/sla-assets/Drugs/Generated/flip.svg new file mode 100644 index 0000000..8c22936 --- /dev/null +++ b/images/sla-assets/Drugs/Generated/flip.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + F + + FLIP + SOCIAL + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/honesty.svg b/images/sla-assets/Drugs/Generated/honesty.svg new file mode 100644 index 0000000..f9337cc --- /dev/null +++ b/images/sla-assets/Drugs/Generated/honesty.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + H + + HONESTY + PSYCH + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/push.svg b/images/sla-assets/Drugs/Generated/push.svg new file mode 100644 index 0000000..105eaa6 --- /dev/null +++ b/images/sla-assets/Drugs/Generated/push.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + P + + PUSH + MEDICAL + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/rush.svg b/images/sla-assets/Drugs/Generated/rush.svg new file mode 100644 index 0000000..89b35a6 --- /dev/null +++ b/images/sla-assets/Drugs/Generated/rush.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + R + + RUSH + COMBAT + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/shatter.svg b/images/sla-assets/Drugs/Generated/shatter.svg new file mode 100644 index 0000000..624178f --- /dev/null +++ b/images/sla-assets/Drugs/Generated/shatter.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + S + + SHATTER + COMBAT + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Generated/slosh.svg b/images/sla-assets/Drugs/Generated/slosh.svg new file mode 100644 index 0000000..be07f9b --- /dev/null +++ b/images/sla-assets/Drugs/Generated/slosh.svg @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + L + + SLOSH + SOFT + \ No newline at end of file diff --git a/images/sla-assets/Drugs/Painkiller.png b/images/sla-assets/Drugs/Painkiller.png new file mode 100644 index 0000000..1aa0b2e Binary files /dev/null and b/images/sla-assets/Drugs/Painkiller.png differ diff --git a/images/sla-assets/Drugs/Redline.png b/images/sla-assets/Drugs/Redline.png new file mode 100644 index 0000000..c899998 Binary files /dev/null and b/images/sla-assets/Drugs/Redline.png differ diff --git a/images/sla-assets/Drugs/Rush.png b/images/sla-assets/Drugs/Rush.png new file mode 100644 index 0000000..9979a4c Binary files /dev/null and b/images/sla-assets/Drugs/Rush.png differ diff --git a/images/sla-assets/Drugs/Sedative.png b/images/sla-assets/Drugs/Sedative.png new file mode 100644 index 0000000..75b24c6 Binary files /dev/null and b/images/sla-assets/Drugs/Sedative.png differ diff --git a/images/sla-assets/Drugs/Stimulant.png b/images/sla-assets/Drugs/Stimulant.png new file mode 100644 index 0000000..bf764cc Binary files /dev/null and b/images/sla-assets/Drugs/Stimulant.png differ diff --git a/images/sla-assets/Drugs/UV.png b/images/sla-assets/Drugs/UV.png new file mode 100644 index 0000000..4f64d7c Binary files /dev/null and b/images/sla-assets/Drugs/UV.png differ diff --git a/images/sla-assets/Ebb/Awareness.png b/images/sla-assets/Ebb/Awareness.png new file mode 100644 index 0000000..2ee2f11 Binary files /dev/null and b/images/sla-assets/Ebb/Awareness.png differ diff --git a/images/sla-assets/Ebb/Blast.png b/images/sla-assets/Ebb/Blast.png new file mode 100644 index 0000000..1bdd369 Binary files /dev/null and b/images/sla-assets/Ebb/Blast.png differ diff --git a/images/sla-assets/Ebb/Communicate.png b/images/sla-assets/Ebb/Communicate.png new file mode 100644 index 0000000..9da40c4 Binary files /dev/null and b/images/sla-assets/Ebb/Communicate.png differ diff --git a/images/sla-assets/Ebb/Ebb Heal.png b/images/sla-assets/Ebb/Ebb Heal.png new file mode 100644 index 0000000..edee280 Binary files /dev/null and b/images/sla-assets/Ebb/Ebb Heal.png differ diff --git a/images/sla-assets/Ebb/Enhancement.png b/images/sla-assets/Ebb/Enhancement.png new file mode 100644 index 0000000..7a83a47 Binary files /dev/null and b/images/sla-assets/Ebb/Enhancement.png differ diff --git a/images/sla-assets/Ebb/Gore Cannon.png b/images/sla-assets/Ebb/Gore Cannon.png new file mode 100644 index 0000000..68568dc Binary files /dev/null and b/images/sla-assets/Ebb/Gore Cannon.png differ diff --git a/images/sla-assets/Ebb/Heal.png b/images/sla-assets/Ebb/Heal.png new file mode 100644 index 0000000..ac548ac Binary files /dev/null and b/images/sla-assets/Ebb/Heal.png differ diff --git a/images/sla-assets/Ebb/Protect.png b/images/sla-assets/Ebb/Protect.png new file mode 100644 index 0000000..7a6bee6 Binary files /dev/null and b/images/sla-assets/Ebb/Protect.png differ diff --git a/images/sla-assets/Ebb/Reality Fold.png b/images/sla-assets/Ebb/Reality Fold.png new file mode 100644 index 0000000..d26da4d Binary files /dev/null and b/images/sla-assets/Ebb/Reality Fold.png differ diff --git a/images/sla-assets/Ebb/Senses.png b/images/sla-assets/Ebb/Senses.png new file mode 100644 index 0000000..181b35b Binary files /dev/null and b/images/sla-assets/Ebb/Senses.png differ diff --git a/images/sla-assets/Ebb/Telekinesis.png b/images/sla-assets/Ebb/Telekinesis.png new file mode 100644 index 0000000..003b18c Binary files /dev/null and b/images/sla-assets/Ebb/Telekinesis.png differ diff --git a/images/sla-assets/Ebb/Thermal Blue.png b/images/sla-assets/Ebb/Thermal Blue.png new file mode 100644 index 0000000..9f71619 Binary files /dev/null and b/images/sla-assets/Ebb/Thermal Blue.png differ diff --git a/images/sla-assets/Ebb/Thermal Red.png b/images/sla-assets/Ebb/Thermal Red.png new file mode 100644 index 0000000..b3df856 Binary files /dev/null and b/images/sla-assets/Ebb/Thermal Red.png differ diff --git a/images/sla-assets/Ebb/Training/Death Squad.png b/images/sla-assets/Ebb/Training/Death Squad.png new file mode 100644 index 0000000..6266393 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Death Squad.png differ diff --git a/images/sla-assets/Ebb/Training/EBB Operative.png b/images/sla-assets/Ebb/Training/EBB Operative.png new file mode 100644 index 0000000..b1c7c48 Binary files /dev/null and b/images/sla-assets/Ebb/Training/EBB Operative.png differ diff --git a/images/sla-assets/Ebb/Training/INvestigation.png b/images/sla-assets/Ebb/Training/INvestigation.png new file mode 100644 index 0000000..4b6092b Binary files /dev/null and b/images/sla-assets/Ebb/Training/INvestigation.png differ diff --git a/images/sla-assets/Ebb/Training/Kick Murder Squad.png b/images/sla-assets/Ebb/Training/Kick Murder Squad.png new file mode 100644 index 0000000..8899e08 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Kick Murder Squad.png differ diff --git a/images/sla-assets/Ebb/Training/Kick Murder.png b/images/sla-assets/Ebb/Training/Kick Murder.png new file mode 100644 index 0000000..155bb9f Binary files /dev/null and b/images/sla-assets/Ebb/Training/Kick Murder.png differ diff --git a/images/sla-assets/Ebb/Training/Mechanic Tech Ops.png b/images/sla-assets/Ebb/Training/Mechanic Tech Ops.png new file mode 100644 index 0000000..b9ce9a5 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Mechanic Tech Ops.png differ diff --git a/images/sla-assets/Ebb/Training/Mechanic.png b/images/sla-assets/Ebb/Training/Mechanic.png new file mode 100644 index 0000000..daf36e1 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Mechanic.png differ diff --git a/images/sla-assets/Ebb/Training/Media.png b/images/sla-assets/Ebb/Training/Media.png new file mode 100644 index 0000000..bdf4fb4 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Media.png differ diff --git a/images/sla-assets/Ebb/Training/Medical.png b/images/sla-assets/Ebb/Training/Medical.png new file mode 100644 index 0000000..3a4b12d Binary files /dev/null and b/images/sla-assets/Ebb/Training/Medical.png differ diff --git a/images/sla-assets/Ebb/Training/Pilot.png b/images/sla-assets/Ebb/Training/Pilot.png new file mode 100644 index 0000000..64fdab3 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Pilot.png differ diff --git a/images/sla-assets/Ebb/Training/Scouting.png b/images/sla-assets/Ebb/Training/Scouting.png new file mode 100644 index 0000000..78ff6a1 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Scouting.png differ diff --git a/images/sla-assets/Ebb/Training/Special Ops.png b/images/sla-assets/Ebb/Training/Special Ops.png new file mode 100644 index 0000000..f9e4719 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Special Ops.png differ diff --git a/images/sla-assets/Ebb/Training/Strike Squad.png b/images/sla-assets/Ebb/Training/Strike Squad.png new file mode 100644 index 0000000..d8bda58 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Strike Squad.png differ diff --git a/images/sla-assets/Ebb/Training/Tech Ops.png b/images/sla-assets/Ebb/Training/Tech Ops.png new file mode 100644 index 0000000..d0673b0 Binary files /dev/null and b/images/sla-assets/Ebb/Training/Tech Ops.png differ diff --git a/images/sla-assets/Ebb/Training/media Elete.png b/images/sla-assets/Ebb/Training/media Elete.png new file mode 100644 index 0000000..4334c74 Binary files /dev/null and b/images/sla-assets/Ebb/Training/media Elete.png differ diff --git a/images/sla-assets/Ebb/Training/pilot and Navigation.png b/images/sla-assets/Ebb/Training/pilot and Navigation.png new file mode 100644 index 0000000..94f321d Binary files /dev/null and b/images/sla-assets/Ebb/Training/pilot and Navigation.png differ diff --git a/images/sla-assets/Gear/Ammo Box Sealed.png b/images/sla-assets/Gear/Ammo Box Sealed.png new file mode 100644 index 0000000..47a6cc6 Binary files /dev/null and b/images/sla-assets/Gear/Ammo Box Sealed.png differ diff --git a/images/sla-assets/Gear/Audio recorder.png b/images/sla-assets/Gear/Audio recorder.png new file mode 100644 index 0000000..373e119 Binary files /dev/null and b/images/sla-assets/Gear/Audio recorder.png differ diff --git a/images/sla-assets/Gear/Backpack.png b/images/sla-assets/Gear/Backpack.png new file mode 100644 index 0000000..546bed2 Binary files /dev/null and b/images/sla-assets/Gear/Backpack.png differ diff --git a/images/sla-assets/Gear/Boopa Audio.png b/images/sla-assets/Gear/Boopa Audio.png new file mode 100644 index 0000000..9e8408a Binary files /dev/null and b/images/sla-assets/Gear/Boopa Audio.png differ diff --git a/images/sla-assets/Gear/Boopa Medi Kit Advanced.png b/images/sla-assets/Gear/Boopa Medi Kit Advanced.png new file mode 100644 index 0000000..a99b72f Binary files /dev/null and b/images/sla-assets/Gear/Boopa Medi Kit Advanced.png differ diff --git a/images/sla-assets/Gear/Breaching Frame Charge.png b/images/sla-assets/Gear/Breaching Frame Charge.png new file mode 100644 index 0000000..b20b5bb Binary files /dev/null and b/images/sla-assets/Gear/Breaching Frame Charge.png differ diff --git a/images/sla-assets/Gear/Cable Ties.png b/images/sla-assets/Gear/Cable Ties.png new file mode 100644 index 0000000..a35fd3c Binary files /dev/null and b/images/sla-assets/Gear/Cable Ties.png differ diff --git a/images/sla-assets/Gear/Chem Light Sticks.png b/images/sla-assets/Gear/Chem Light Sticks.png new file mode 100644 index 0000000..2bf77ca Binary files /dev/null and b/images/sla-assets/Gear/Chem Light Sticks.png differ diff --git a/images/sla-assets/Gear/Climbing Harness.png b/images/sla-assets/Gear/Climbing Harness.png new file mode 100644 index 0000000..92a58e0 Binary files /dev/null and b/images/sla-assets/Gear/Climbing Harness.png differ diff --git a/images/sla-assets/Gear/Compass Magnetic.png b/images/sla-assets/Gear/Compass Magnetic.png new file mode 100644 index 0000000..d340003 Binary files /dev/null and b/images/sla-assets/Gear/Compass Magnetic.png differ diff --git a/images/sla-assets/Gear/Csnteen.png b/images/sla-assets/Gear/Csnteen.png new file mode 100644 index 0000000..943b8ad Binary files /dev/null and b/images/sla-assets/Gear/Csnteen.png differ diff --git a/images/sla-assets/Gear/Cybernetic Maintenance Kit.png b/images/sla-assets/Gear/Cybernetic Maintenance Kit.png new file mode 100644 index 0000000..5f9b79c Binary files /dev/null and b/images/sla-assets/Gear/Cybernetic Maintenance Kit.png differ diff --git a/images/sla-assets/Gear/Duct Tape Roll.png b/images/sla-assets/Gear/Duct Tape Roll.png new file mode 100644 index 0000000..639da47 Binary files /dev/null and b/images/sla-assets/Gear/Duct Tape Roll.png differ diff --git a/images/sla-assets/Gear/Ebb Damper.png b/images/sla-assets/Gear/Ebb Damper.png new file mode 100644 index 0000000..6dda8cb Binary files /dev/null and b/images/sla-assets/Gear/Ebb Damper.png differ diff --git a/images/sla-assets/Gear/Electric Lockpick.png b/images/sla-assets/Gear/Electric Lockpick.png new file mode 100644 index 0000000..7d80dff Binary files /dev/null and b/images/sla-assets/Gear/Electric Lockpick.png differ diff --git a/images/sla-assets/Gear/Entrenching Tool.png b/images/sla-assets/Gear/Entrenching Tool.png new file mode 100644 index 0000000..ce4ee48 Binary files /dev/null and b/images/sla-assets/Gear/Entrenching Tool.png differ diff --git a/images/sla-assets/Gear/Environment Scanner Standard.png b/images/sla-assets/Gear/Environment Scanner Standard.png new file mode 100644 index 0000000..1919988 Binary files /dev/null and b/images/sla-assets/Gear/Environment Scanner Standard.png differ diff --git a/images/sla-assets/Gear/Environment Scanner.png b/images/sla-assets/Gear/Environment Scanner.png new file mode 100644 index 0000000..0a567ce Binary files /dev/null and b/images/sla-assets/Gear/Environment Scanner.png differ diff --git a/images/sla-assets/Gear/Equipment Case Rugged.png b/images/sla-assets/Gear/Equipment Case Rugged.png new file mode 100644 index 0000000..e6e7fc4 Binary files /dev/null and b/images/sla-assets/Gear/Equipment Case Rugged.png differ diff --git a/images/sla-assets/Gear/Evidence Bags.png b/images/sla-assets/Gear/Evidence Bags.png new file mode 100644 index 0000000..cb1aec9 Binary files /dev/null and b/images/sla-assets/Gear/Evidence Bags.png differ diff --git a/images/sla-assets/Gear/Flares Pack of 6.png b/images/sla-assets/Gear/Flares Pack of 6.png new file mode 100644 index 0000000..60194e4 Binary files /dev/null and b/images/sla-assets/Gear/Flares Pack of 6.png differ diff --git a/images/sla-assets/Gear/FlashBang .png b/images/sla-assets/Gear/FlashBang .png new file mode 100644 index 0000000..3c1f244 Binary files /dev/null and b/images/sla-assets/Gear/FlashBang .png differ diff --git a/images/sla-assets/Gear/Forensic Kit.png b/images/sla-assets/Gear/Forensic Kit.png new file mode 100644 index 0000000..c5867cd Binary files /dev/null and b/images/sla-assets/Gear/Forensic Kit.png differ diff --git a/images/sla-assets/Gear/Grapple Gun.png b/images/sla-assets/Gear/Grapple Gun.png new file mode 100644 index 0000000..1bbb33e Binary files /dev/null and b/images/sla-assets/Gear/Grapple Gun.png differ diff --git a/images/sla-assets/Gear/Grooming Kit.png b/images/sla-assets/Gear/Grooming Kit.png new file mode 100644 index 0000000..fff3da2 Binary files /dev/null and b/images/sla-assets/Gear/Grooming Kit.png differ diff --git a/images/sla-assets/Gear/Headset Comms.png b/images/sla-assets/Gear/Headset Comms.png new file mode 100644 index 0000000..174ba99 Binary files /dev/null and b/images/sla-assets/Gear/Headset Comms.png differ diff --git a/images/sla-assets/Gear/Holo Projector.png b/images/sla-assets/Gear/Holo Projector.png new file mode 100644 index 0000000..ddece98 Binary files /dev/null and b/images/sla-assets/Gear/Holo Projector.png differ diff --git a/images/sla-assets/Gear/Interface Cabler.png b/images/sla-assets/Gear/Interface Cabler.png new file mode 100644 index 0000000..3defaa2 Binary files /dev/null and b/images/sla-assets/Gear/Interface Cabler.png differ diff --git a/images/sla-assets/Gear/Klippo MultiBand Comm.png b/images/sla-assets/Gear/Klippo MultiBand Comm.png new file mode 100644 index 0000000..c250862 Binary files /dev/null and b/images/sla-assets/Gear/Klippo MultiBand Comm.png differ diff --git a/images/sla-assets/Gear/Klippo Spray Hypo.png b/images/sla-assets/Gear/Klippo Spray Hypo.png new file mode 100644 index 0000000..c238df5 Binary files /dev/null and b/images/sla-assets/Gear/Klippo Spray Hypo.png differ diff --git a/images/sla-assets/Gear/Lockpick Set Professional.png b/images/sla-assets/Gear/Lockpick Set Professional.png new file mode 100644 index 0000000..9a5d4f8 Binary files /dev/null and b/images/sla-assets/Gear/Lockpick Set Professional.png differ diff --git a/images/sla-assets/Gear/MAC Knife.png b/images/sla-assets/Gear/MAC Knife.png new file mode 100644 index 0000000..1a84df8 Binary files /dev/null and b/images/sla-assets/Gear/MAC Knife.png differ diff --git a/images/sla-assets/Gear/MRE.png b/images/sla-assets/Gear/MRE.png new file mode 100644 index 0000000..efa4a7d Binary files /dev/null and b/images/sla-assets/Gear/MRE.png differ diff --git a/images/sla-assets/Gear/Maghold Boots.png b/images/sla-assets/Gear/Maghold Boots.png new file mode 100644 index 0000000..a4a5335 Binary files /dev/null and b/images/sla-assets/Gear/Maghold Boots.png differ diff --git a/images/sla-assets/Gear/Maghold Gloves.png b/images/sla-assets/Gear/Maghold Gloves.png new file mode 100644 index 0000000..b9a962c Binary files /dev/null and b/images/sla-assets/Gear/Maghold Gloves.png differ diff --git a/images/sla-assets/Gear/Medikit Disposable.png b/images/sla-assets/Gear/Medikit Disposable.png new file mode 100644 index 0000000..1c9f8b9 Binary files /dev/null and b/images/sla-assets/Gear/Medikit Disposable.png differ diff --git a/images/sla-assets/Gear/Mirros Signal.png b/images/sla-assets/Gear/Mirros Signal.png new file mode 100644 index 0000000..1b37360 Binary files /dev/null and b/images/sla-assets/Gear/Mirros Signal.png differ diff --git a/images/sla-assets/Gear/Motion Tracker.png b/images/sla-assets/Gear/Motion Tracker.png new file mode 100644 index 0000000..de015ed Binary files /dev/null and b/images/sla-assets/Gear/Motion Tracker.png differ diff --git a/images/sla-assets/Gear/Oyster Card.png b/images/sla-assets/Gear/Oyster Card.png new file mode 100644 index 0000000..d667ea1 Binary files /dev/null and b/images/sla-assets/Gear/Oyster Card.png differ diff --git a/images/sla-assets/Gear/Padlock.png b/images/sla-assets/Gear/Padlock.png new file mode 100644 index 0000000..883f421 Binary files /dev/null and b/images/sla-assets/Gear/Padlock.png differ diff --git a/images/sla-assets/Gear/Playng Cards.png b/images/sla-assets/Gear/Playng Cards.png new file mode 100644 index 0000000..f32060c Binary files /dev/null and b/images/sla-assets/Gear/Playng Cards.png differ diff --git a/images/sla-assets/Gear/Portable Genorator.png b/images/sla-assets/Gear/Portable Genorator.png new file mode 100644 index 0000000..4523be4 Binary files /dev/null and b/images/sla-assets/Gear/Portable Genorator.png differ diff --git a/images/sla-assets/Gear/Power Cell Extended.png b/images/sla-assets/Gear/Power Cell Extended.png new file mode 100644 index 0000000..a4dd243 Binary files /dev/null and b/images/sla-assets/Gear/Power Cell Extended.png differ diff --git a/images/sla-assets/Gear/Power Coupler.png b/images/sla-assets/Gear/Power Coupler.png new file mode 100644 index 0000000..4cbd4e6 Binary files /dev/null and b/images/sla-assets/Gear/Power Coupler.png differ diff --git a/images/sla-assets/Gear/Power SCell Standard.png b/images/sla-assets/Gear/Power SCell Standard.png new file mode 100644 index 0000000..e6795c2 Binary files /dev/null and b/images/sla-assets/Gear/Power SCell Standard.png differ diff --git a/images/sla-assets/Gear/Recharge Station Portable.png b/images/sla-assets/Gear/Recharge Station Portable.png new file mode 100644 index 0000000..58e3299 Binary files /dev/null and b/images/sla-assets/Gear/Recharge Station Portable.png differ diff --git a/images/sla-assets/Gear/Restraint Cuffs.png b/images/sla-assets/Gear/Restraint Cuffs.png new file mode 100644 index 0000000..cb45a9b Binary files /dev/null and b/images/sla-assets/Gear/Restraint Cuffs.png differ diff --git a/images/sla-assets/Gear/Rope.png b/images/sla-assets/Gear/Rope.png new file mode 100644 index 0000000..e47bf08 Binary files /dev/null and b/images/sla-assets/Gear/Rope.png differ diff --git a/images/sla-assets/Gear/Sleeping Bag.png b/images/sla-assets/Gear/Sleeping Bag.png new file mode 100644 index 0000000..6dc8924 Binary files /dev/null and b/images/sla-assets/Gear/Sleeping Bag.png differ diff --git a/images/sla-assets/Gear/Smoke Grenade.png b/images/sla-assets/Gear/Smoke Grenade.png new file mode 100644 index 0000000..bcf0092 Binary files /dev/null and b/images/sla-assets/Gear/Smoke Grenade.png differ diff --git a/images/sla-assets/Gear/Standard Binoculars.png b/images/sla-assets/Gear/Standard Binoculars.png new file mode 100644 index 0000000..99a7893 Binary files /dev/null and b/images/sla-assets/Gear/Standard Binoculars.png differ diff --git a/images/sla-assets/Gear/Thermal Blanket.png b/images/sla-assets/Gear/Thermal Blanket.png new file mode 100644 index 0000000..15c36fd Binary files /dev/null and b/images/sla-assets/Gear/Thermal Blanket.png differ diff --git a/images/sla-assets/Gear/Tool Kit Electronic.png b/images/sla-assets/Gear/Tool Kit Electronic.png new file mode 100644 index 0000000..702c970 Binary files /dev/null and b/images/sla-assets/Gear/Tool Kit Electronic.png differ diff --git a/images/sla-assets/Gear/Tool Kit General.png b/images/sla-assets/Gear/Tool Kit General.png new file mode 100644 index 0000000..b140c93 Binary files /dev/null and b/images/sla-assets/Gear/Tool Kit General.png differ diff --git a/images/sla-assets/Gear/Trauma Stabiliser.png b/images/sla-assets/Gear/Trauma Stabiliser.png new file mode 100644 index 0000000..ce06264 Binary files /dev/null and b/images/sla-assets/Gear/Trauma Stabiliser.png differ diff --git a/images/sla-assets/Gear/UV Multi Spectrum Torch.png b/images/sla-assets/Gear/UV Multi Spectrum Torch.png new file mode 100644 index 0000000..3c3f41d Binary files /dev/null and b/images/sla-assets/Gear/UV Multi Spectrum Torch.png differ diff --git a/images/sla-assets/Gear/Vehicle Repair Kit.png b/images/sla-assets/Gear/Vehicle Repair Kit.png new file mode 100644 index 0000000..0393fe3 Binary files /dev/null and b/images/sla-assets/Gear/Vehicle Repair Kit.png differ diff --git a/images/sla-assets/Gear/Vehicle Tool Kit.png b/images/sla-assets/Gear/Vehicle Tool Kit.png new file mode 100644 index 0000000..d4c007f Binary files /dev/null and b/images/sla-assets/Gear/Vehicle Tool Kit.png differ diff --git a/images/sla-assets/Gear/Vid Phone Portable.png b/images/sla-assets/Gear/Vid Phone Portable.png new file mode 100644 index 0000000..b51399f Binary files /dev/null and b/images/sla-assets/Gear/Vid Phone Portable.png differ diff --git a/images/sla-assets/Gear/Water Purify Tablets.png b/images/sla-assets/Gear/Water Purify Tablets.png new file mode 100644 index 0000000..fb43f4e Binary files /dev/null and b/images/sla-assets/Gear/Water Purify Tablets.png differ diff --git a/images/sla-assets/Gear/Webbing Tacktical Vest.png b/images/sla-assets/Gear/Webbing Tacktical Vest.png new file mode 100644 index 0000000..e50e48e Binary files /dev/null and b/images/sla-assets/Gear/Webbing Tacktical Vest.png differ diff --git a/images/sla-assets/Gear/binoculars Tacktical.png b/images/sla-assets/Gear/binoculars Tacktical.png new file mode 100644 index 0000000..7252d8f Binary files /dev/null and b/images/sla-assets/Gear/binoculars Tacktical.png differ diff --git a/images/sla-assets/Gear/camera Still video.png b/images/sla-assets/Gear/camera Still video.png new file mode 100644 index 0000000..3694205 Binary files /dev/null and b/images/sla-assets/Gear/camera Still video.png differ diff --git a/images/sla-assets/Gear/pprative organiser.png b/images/sla-assets/Gear/pprative organiser.png new file mode 100644 index 0000000..04bead8 Binary files /dev/null and b/images/sla-assets/Gear/pprative organiser.png differ diff --git a/images/sla-assets/Maps/slaguru6666_The_words_SLA_INDUSTRIES_in_neon_80s_grafitti_on__bbbf7678-0361-4632-8a3f-4134e9a764dc_1.png b/images/sla-assets/Maps/slaguru6666_The_words_SLA_INDUSTRIES_in_neon_80s_grafitti_on__bbbf7678-0361-4632-8a3f-4134e9a764dc_1.png new file mode 100644 index 0000000..0e15ea9 Binary files /dev/null and b/images/sla-assets/Maps/slaguru6666_The_words_SLA_INDUSTRIES_in_neon_80s_grafitti_on__bbbf7678-0361-4632-8a3f-4134e9a764dc_1.png differ diff --git a/images/sla-assets/PICS/2026-02-23_17-36-46.png b/images/sla-assets/PICS/2026-02-23_17-36-46.png new file mode 100644 index 0000000..ff39559 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_17-36-46.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-13-15.png b/images/sla-assets/PICS/2026-02-23_21-13-15.png new file mode 100644 index 0000000..2cafceb Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-13-15.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-13-43.png b/images/sla-assets/PICS/2026-02-23_21-13-43.png new file mode 100644 index 0000000..c1fb732 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-13-43.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-35-55.png b/images/sla-assets/PICS/2026-02-23_21-35-55.png new file mode 100644 index 0000000..1a11975 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-35-55.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-51-21.png b/images/sla-assets/PICS/2026-02-23_21-51-21.png new file mode 100644 index 0000000..a82de09 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-51-21.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-51-36.png b/images/sla-assets/PICS/2026-02-23_21-51-36.png new file mode 100644 index 0000000..2212ab8 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-51-36.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-53-43.png b/images/sla-assets/PICS/2026-02-23_21-53-43.png new file mode 100644 index 0000000..90f4d12 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-53-43.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-54-20.png b/images/sla-assets/PICS/2026-02-23_21-54-20.png new file mode 100644 index 0000000..5abf4ae Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-54-20.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-54-38.png b/images/sla-assets/PICS/2026-02-23_21-54-38.png new file mode 100644 index 0000000..30eb8f4 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-54-38.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-54-59.png b/images/sla-assets/PICS/2026-02-23_21-54-59.png new file mode 100644 index 0000000..3d89362 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-54-59.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-55-15.png b/images/sla-assets/PICS/2026-02-23_21-55-15.png new file mode 100644 index 0000000..daa875b Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-55-15.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-55-31.png b/images/sla-assets/PICS/2026-02-23_21-55-31.png new file mode 100644 index 0000000..5778dee Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-55-31.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-55-58.png b/images/sla-assets/PICS/2026-02-23_21-55-58.png new file mode 100644 index 0000000..1c1e8ed Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-55-58.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-57-35.png b/images/sla-assets/PICS/2026-02-23_21-57-35.png new file mode 100644 index 0000000..4c9a8d1 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-57-35.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-58-15.png b/images/sla-assets/PICS/2026-02-23_21-58-15.png new file mode 100644 index 0000000..56111f3 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-58-15.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-58-28.png b/images/sla-assets/PICS/2026-02-23_21-58-28.png new file mode 100644 index 0000000..28b1474 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-58-28.png differ diff --git a/images/sla-assets/PICS/2026-02-23_21-58-45.png b/images/sla-assets/PICS/2026-02-23_21-58-45.png new file mode 100644 index 0000000..b974d3a Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_21-58-45.png differ diff --git a/images/sla-assets/PICS/2026-02-23_22-13-23.png b/images/sla-assets/PICS/2026-02-23_22-13-23.png new file mode 100644 index 0000000..f113ca5 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_22-13-23.png differ diff --git a/images/sla-assets/PICS/2026-02-23_22-14-37.png b/images/sla-assets/PICS/2026-02-23_22-14-37.png new file mode 100644 index 0000000..67cb142 Binary files /dev/null and b/images/sla-assets/PICS/2026-02-23_22-14-37.png differ diff --git a/images/sla-assets/People/OTTO.png b/images/sla-assets/People/OTTO.png new file mode 100644 index 0000000..3e5e839 Binary files /dev/null and b/images/sla-assets/People/OTTO.png differ diff --git a/images/sla-assets/People/slaguru6666_34-year-old_tactical_detective_sharp_features_gra_a1892123-c066-41bc-8169-c6fa78eeaaed_3.png b/images/sla-assets/People/slaguru6666_34-year-old_tactical_detective_sharp_features_gra_a1892123-c066-41bc-8169-c6fa78eeaaed_3.png new file mode 100644 index 0000000..454cdd7 Binary files /dev/null and b/images/sla-assets/People/slaguru6666_34-year-old_tactical_detective_sharp_features_gra_a1892123-c066-41bc-8169-c6fa78eeaaed_3.png differ diff --git a/images/sla-assets/Skills/Athletics.png b/images/sla-assets/Skills/Athletics.png new file mode 100644 index 0000000..fd77840 Binary files /dev/null and b/images/sla-assets/Skills/Athletics.png differ diff --git a/images/sla-assets/Skills/Biofeedback.png b/images/sla-assets/Skills/Biofeedback.png new file mode 100644 index 0000000..b142e8d Binary files /dev/null and b/images/sla-assets/Skills/Biofeedback.png differ diff --git a/images/sla-assets/Skills/Brawl.png b/images/sla-assets/Skills/Brawl.png new file mode 100644 index 0000000..85960b0 Binary files /dev/null and b/images/sla-assets/Skills/Brawl.png differ diff --git a/images/sla-assets/Skills/Bureaucracy.png b/images/sla-assets/Skills/Bureaucracy.png new file mode 100644 index 0000000..3444975 Binary files /dev/null and b/images/sla-assets/Skills/Bureaucracy.png differ diff --git a/images/sla-assets/Skills/Climb.png b/images/sla-assets/Skills/Climb.png new file mode 100644 index 0000000..1601b4f Binary files /dev/null and b/images/sla-assets/Skills/Climb.png differ diff --git a/images/sla-assets/Skills/Command.png b/images/sla-assets/Skills/Command.png new file mode 100644 index 0000000..5cba791 Binary files /dev/null and b/images/sla-assets/Skills/Command.png differ diff --git a/images/sla-assets/Skills/Computer Systems.png b/images/sla-assets/Skills/Computer Systems.png new file mode 100644 index 0000000..34a4785 Binary files /dev/null and b/images/sla-assets/Skills/Computer Systems.png differ diff --git a/images/sla-assets/Skills/Craft.png b/images/sla-assets/Skills/Craft.png new file mode 100644 index 0000000..bd700ca Binary files /dev/null and b/images/sla-assets/Skills/Craft.png differ diff --git a/images/sla-assets/Skills/Dodge.png b/images/sla-assets/Skills/Dodge.png new file mode 100644 index 0000000..72519dc Binary files /dev/null and b/images/sla-assets/Skills/Dodge.png differ diff --git a/images/sla-assets/Skills/Drive Civilian.png b/images/sla-assets/Skills/Drive Civilian.png new file mode 100644 index 0000000..d7f0b29 Binary files /dev/null and b/images/sla-assets/Skills/Drive Civilian.png differ diff --git a/images/sla-assets/Skills/Drive Military.png b/images/sla-assets/Skills/Drive Military.png new file mode 100644 index 0000000..cd9be90 Binary files /dev/null and b/images/sla-assets/Skills/Drive Military.png differ diff --git a/images/sla-assets/Skills/EBB Awareness.png b/images/sla-assets/Skills/EBB Awareness.png new file mode 100644 index 0000000..45151e7 Binary files /dev/null and b/images/sla-assets/Skills/EBB Awareness.png differ diff --git a/images/sla-assets/Skills/EBB Blast.png b/images/sla-assets/Skills/EBB Blast.png new file mode 100644 index 0000000..00e4c8c Binary files /dev/null and b/images/sla-assets/Skills/EBB Blast.png differ diff --git a/images/sla-assets/Skills/EBB Blue Thermal.png b/images/sla-assets/Skills/EBB Blue Thermal.png new file mode 100644 index 0000000..03bc64b Binary files /dev/null and b/images/sla-assets/Skills/EBB Blue Thermal.png differ diff --git a/images/sla-assets/Skills/EBB Core.png b/images/sla-assets/Skills/EBB Core.png new file mode 100644 index 0000000..12f494b Binary files /dev/null and b/images/sla-assets/Skills/EBB Core.png differ diff --git a/images/sla-assets/Skills/EBB Reality Fold.png b/images/sla-assets/Skills/EBB Reality Fold.png new file mode 100644 index 0000000..95c082a Binary files /dev/null and b/images/sla-assets/Skills/EBB Reality Fold.png differ diff --git a/images/sla-assets/Skills/EBB Speciality.png b/images/sla-assets/Skills/EBB Speciality.png new file mode 100644 index 0000000..3f17111 Binary files /dev/null and b/images/sla-assets/Skills/EBB Speciality.png differ diff --git a/images/sla-assets/Skills/EBB Telekinesis.png b/images/sla-assets/Skills/EBB Telekinesis.png new file mode 100644 index 0000000..b3ee759 Binary files /dev/null and b/images/sla-assets/Skills/EBB Telekinesis.png differ diff --git a/images/sla-assets/Skills/EBB Thermal Red.png b/images/sla-assets/Skills/EBB Thermal Red.png new file mode 100644 index 0000000..52947b3 Binary files /dev/null and b/images/sla-assets/Skills/EBB Thermal Red.png differ diff --git a/images/sla-assets/Skills/Ebb Communicate.png b/images/sla-assets/Skills/Ebb Communicate.png new file mode 100644 index 0000000..24c8246 Binary files /dev/null and b/images/sla-assets/Skills/Ebb Communicate.png differ diff --git a/images/sla-assets/Skills/Fast Talk.png b/images/sla-assets/Skills/Fast Talk.png new file mode 100644 index 0000000..7f79e0f Binary files /dev/null and b/images/sla-assets/Skills/Fast Talk.png differ diff --git a/images/sla-assets/Skills/Firearm Auto.png b/images/sla-assets/Skills/Firearm Auto.png new file mode 100644 index 0000000..f5f8cd8 Binary files /dev/null and b/images/sla-assets/Skills/Firearm Auto.png differ diff --git a/images/sla-assets/Skills/Firearm Pistol.png b/images/sla-assets/Skills/Firearm Pistol.png new file mode 100644 index 0000000..e1545d4 Binary files /dev/null and b/images/sla-assets/Skills/Firearm Pistol.png differ diff --git a/images/sla-assets/Skills/Firearm Rifle:shotgun.png b/images/sla-assets/Skills/Firearm Rifle:shotgun.png new file mode 100644 index 0000000..ce41628 Binary files /dev/null and b/images/sla-assets/Skills/Firearm Rifle:shotgun.png differ diff --git a/images/sla-assets/Skills/Firearm SMG.png b/images/sla-assets/Skills/Firearm SMG.png new file mode 100644 index 0000000..cf8a05b Binary files /dev/null and b/images/sla-assets/Skills/Firearm SMG.png differ diff --git a/images/sla-assets/Skills/Formulate.png b/images/sla-assets/Skills/Formulate.png new file mode 100644 index 0000000..0e59751 Binary files /dev/null and b/images/sla-assets/Skills/Formulate.png differ diff --git a/images/sla-assets/Skills/Intimidate.png b/images/sla-assets/Skills/Intimidate.png new file mode 100644 index 0000000..afa1197 Binary files /dev/null and b/images/sla-assets/Skills/Intimidate.png differ diff --git a/images/sla-assets/Skills/Listen.png b/images/sla-assets/Skills/Listen.png new file mode 100644 index 0000000..dfec596 Binary files /dev/null and b/images/sla-assets/Skills/Listen.png differ diff --git a/images/sla-assets/Skills/Medical.png b/images/sla-assets/Skills/Medical.png new file mode 100644 index 0000000..84e4a81 Binary files /dev/null and b/images/sla-assets/Skills/Medical.png differ diff --git a/images/sla-assets/Skills/Melee 2H Blade.png b/images/sla-assets/Skills/Melee 2H Blade.png new file mode 100644 index 0000000..795a749 Binary files /dev/null and b/images/sla-assets/Skills/Melee 2H Blade.png differ diff --git a/images/sla-assets/Skills/Melee Axe.png b/images/sla-assets/Skills/Melee Axe.png new file mode 100644 index 0000000..56ed0e8 Binary files /dev/null and b/images/sla-assets/Skills/Melee Axe.png differ diff --git a/images/sla-assets/Skills/Melee Blade 1H.png b/images/sla-assets/Skills/Melee Blade 1H.png new file mode 100644 index 0000000..71debaa Binary files /dev/null and b/images/sla-assets/Skills/Melee Blade 1H.png differ diff --git a/images/sla-assets/Skills/Melee Club.png b/images/sla-assets/Skills/Melee Club.png new file mode 100644 index 0000000..739f1bc Binary files /dev/null and b/images/sla-assets/Skills/Melee Club.png differ diff --git a/images/sla-assets/Skills/Persuade.png b/images/sla-assets/Skills/Persuade.png new file mode 100644 index 0000000..9800d1a Binary files /dev/null and b/images/sla-assets/Skills/Persuade.png differ diff --git a/images/sla-assets/Skills/Pilot.png b/images/sla-assets/Skills/Pilot.png new file mode 100644 index 0000000..ef57ada Binary files /dev/null and b/images/sla-assets/Skills/Pilot.png differ diff --git a/images/sla-assets/Skills/Psychology.png b/images/sla-assets/Skills/Psychology.png new file mode 100644 index 0000000..2f760aa Binary files /dev/null and b/images/sla-assets/Skills/Psychology.png differ diff --git a/images/sla-assets/Skills/Rech Mechanical.png b/images/sla-assets/Skills/Rech Mechanical.png new file mode 100644 index 0000000..78a15bd Binary files /dev/null and b/images/sla-assets/Skills/Rech Mechanical.png differ diff --git a/images/sla-assets/Skills/SLA Info.png b/images/sla-assets/Skills/SLA Info.png new file mode 100644 index 0000000..9dab853 Binary files /dev/null and b/images/sla-assets/Skills/SLA Info.png differ diff --git a/images/sla-assets/Skills/Spot Hidden.png b/images/sla-assets/Skills/Spot Hidden.png new file mode 100644 index 0000000..a912d41 Binary files /dev/null and b/images/sla-assets/Skills/Spot Hidden.png differ diff --git a/images/sla-assets/Skills/Stealth.png b/images/sla-assets/Skills/Stealth.png new file mode 100644 index 0000000..80a540e Binary files /dev/null and b/images/sla-assets/Skills/Stealth.png differ diff --git a/images/sla-assets/Skills/Streetwise.png b/images/sla-assets/Skills/Streetwise.png new file mode 100644 index 0000000..64cf8a0 Binary files /dev/null and b/images/sla-assets/Skills/Streetwise.png differ diff --git a/images/sla-assets/Skills/Swim.png b/images/sla-assets/Skills/Swim.png new file mode 100644 index 0000000..9908dbb Binary files /dev/null and b/images/sla-assets/Skills/Swim.png differ diff --git a/images/sla-assets/Skills/THrow.png b/images/sla-assets/Skills/THrow.png new file mode 100644 index 0000000..d170610 Binary files /dev/null and b/images/sla-assets/Skills/THrow.png differ diff --git a/images/sla-assets/Skills/Tactics.png b/images/sla-assets/Skills/Tactics.png new file mode 100644 index 0000000..8776f47 Binary files /dev/null and b/images/sla-assets/Skills/Tactics.png differ diff --git a/images/sla-assets/Skills/Tech Computers and AI.png b/images/sla-assets/Skills/Tech Computers and AI.png new file mode 100644 index 0000000..a3a1970 Binary files /dev/null and b/images/sla-assets/Skills/Tech Computers and AI.png differ diff --git a/images/sla-assets/Skills/Tech Electronics.png b/images/sla-assets/Skills/Tech Electronics.png new file mode 100644 index 0000000..3c1f3ae Binary files /dev/null and b/images/sla-assets/Skills/Tech Electronics.png differ diff --git a/images/sla-assets/Skills/Tech Mechanical.png b/images/sla-assets/Skills/Tech Mechanical.png new file mode 100644 index 0000000..f734c8d Binary files /dev/null and b/images/sla-assets/Skills/Tech Mechanical.png differ diff --git a/images/sla-assets/Skills/Tech Military.png b/images/sla-assets/Skills/Tech Military.png new file mode 100644 index 0000000..ba20d9f Binary files /dev/null and b/images/sla-assets/Skills/Tech Military.png differ diff --git a/images/sla-assets/Special/Code of Honor.png b/images/sla-assets/Special/Code of Honor.png new file mode 100644 index 0000000..fd0f97f Binary files /dev/null and b/images/sla-assets/Special/Code of Honor.png differ diff --git a/images/sla-assets/Special/Cold Adapted.png b/images/sla-assets/Special/Cold Adapted.png new file mode 100644 index 0000000..c356d38 Binary files /dev/null and b/images/sla-assets/Special/Cold Adapted.png differ diff --git a/images/sla-assets/Special/Combat Drug User.png b/images/sla-assets/Special/Combat Drug User.png new file mode 100644 index 0000000..46b8444 Binary files /dev/null and b/images/sla-assets/Special/Combat Drug User.png differ diff --git a/images/sla-assets/Special/Compassion.png b/images/sla-assets/Special/Compassion.png new file mode 100644 index 0000000..0f4fb13 Binary files /dev/null and b/images/sla-assets/Special/Compassion.png differ diff --git a/images/sla-assets/Special/Ebb Fury.png b/images/sla-assets/Special/Ebb Fury.png new file mode 100644 index 0000000..c558584 Binary files /dev/null and b/images/sla-assets/Special/Ebb Fury.png differ diff --git a/images/sla-assets/Special/Ebb Sensitive.png b/images/sla-assets/Special/Ebb Sensitive.png new file mode 100644 index 0000000..e4da274 Binary files /dev/null and b/images/sla-assets/Special/Ebb Sensitive.png differ diff --git a/images/sla-assets/Special/Fast Reflexes.png b/images/sla-assets/Special/Fast Reflexes.png new file mode 100644 index 0000000..0055459 Binary files /dev/null and b/images/sla-assets/Special/Fast Reflexes.png differ diff --git a/images/sla-assets/Special/Field Surgeon.png b/images/sla-assets/Special/Field Surgeon.png new file mode 100644 index 0000000..beecb83 Binary files /dev/null and b/images/sla-assets/Special/Field Surgeon.png differ diff --git a/images/sla-assets/Special/Gut Feeling.png b/images/sla-assets/Special/Gut Feeling.png new file mode 100644 index 0000000..0319410 Binary files /dev/null and b/images/sla-assets/Special/Gut Feeling.png differ diff --git a/images/sla-assets/Special/Hard Hitting.png b/images/sla-assets/Special/Hard Hitting.png new file mode 100644 index 0000000..5bb7b4c Binary files /dev/null and b/images/sla-assets/Special/Hard Hitting.png differ diff --git a/images/sla-assets/Special/Healer.png b/images/sla-assets/Special/Healer.png new file mode 100644 index 0000000..ebf3a57 Binary files /dev/null and b/images/sla-assets/Special/Healer.png differ diff --git a/images/sla-assets/Special/Inquisitive.png b/images/sla-assets/Special/Inquisitive.png new file mode 100644 index 0000000..824f1d5 Binary files /dev/null and b/images/sla-assets/Special/Inquisitive.png differ diff --git a/images/sla-assets/Special/Menacing.png b/images/sla-assets/Special/Menacing.png new file mode 100644 index 0000000..6094520 Binary files /dev/null and b/images/sla-assets/Special/Menacing.png differ diff --git a/images/sla-assets/Special/Regeneration.png b/images/sla-assets/Special/Regeneration.png new file mode 100644 index 0000000..5cbeeaa Binary files /dev/null and b/images/sla-assets/Special/Regeneration.png differ diff --git a/images/sla-assets/Special/Sniper.png b/images/sla-assets/Special/Sniper.png new file mode 100644 index 0000000..0c291c9 Binary files /dev/null and b/images/sla-assets/Special/Sniper.png differ diff --git a/images/sla-assets/Special/True Grit.png b/images/sla-assets/Special/True Grit.png new file mode 100644 index 0000000..35ebf71 Binary files /dev/null and b/images/sla-assets/Special/True Grit.png differ diff --git a/images/sla-assets/Species/Advanced Carrion.png b/images/sla-assets/Species/Advanced Carrion.png new file mode 100644 index 0000000..c48da90 Binary files /dev/null and b/images/sla-assets/Species/Advanced Carrion.png differ diff --git a/images/sla-assets/Species/Brain Waster.png b/images/sla-assets/Species/Brain Waster.png new file mode 100644 index 0000000..70cb6c4 Binary files /dev/null and b/images/sla-assets/Species/Brain Waster.png differ diff --git a/images/sla-assets/Species/Ebon.png b/images/sla-assets/Species/Ebon.png new file mode 100644 index 0000000..3d2e757 Binary files /dev/null and b/images/sla-assets/Species/Ebon.png differ diff --git a/images/sla-assets/Species/Frother.png b/images/sla-assets/Species/Frother.png new file mode 100644 index 0000000..ed5a048 Binary files /dev/null and b/images/sla-assets/Species/Frother.png differ diff --git a/images/sla-assets/Species/Human.png b/images/sla-assets/Species/Human.png new file mode 100644 index 0000000..40257d1 Binary files /dev/null and b/images/sla-assets/Species/Human.png differ diff --git a/images/sla-assets/Species/Shaktar.png b/images/sla-assets/Species/Shaktar.png new file mode 100644 index 0000000..0e5261d Binary files /dev/null and b/images/sla-assets/Species/Shaktar.png differ diff --git a/images/sla-assets/Species/Stormer 313.png b/images/sla-assets/Species/Stormer 313.png new file mode 100644 index 0000000..425b979 Binary files /dev/null and b/images/sla-assets/Species/Stormer 313.png differ diff --git a/images/sla-assets/Species/Stormer 711.png b/images/sla-assets/Species/Stormer 711.png new file mode 100644 index 0000000..41746fd Binary files /dev/null and b/images/sla-assets/Species/Stormer 711.png differ diff --git a/images/sla-assets/Species/Wraith Raider.png b/images/sla-assets/Species/Wraith Raider.png new file mode 100644 index 0000000..f7af115 Binary files /dev/null and b/images/sla-assets/Species/Wraith Raider.png differ diff --git a/images/sla-assets/Traits/addiction-compulsion.png b/images/sla-assets/Traits/addiction-compulsion.png new file mode 100644 index 0000000..d275df0 Binary files /dev/null and b/images/sla-assets/Traits/addiction-compulsion.png differ diff --git a/images/sla-assets/Traits/allergy.png b/images/sla-assets/Traits/allergy.png new file mode 100644 index 0000000..e987734 Binary files /dev/null and b/images/sla-assets/Traits/allergy.png differ diff --git a/images/sla-assets/Traits/ambidextrous.png b/images/sla-assets/Traits/ambidextrous.png new file mode 100644 index 0000000..751e4e0 Binary files /dev/null and b/images/sla-assets/Traits/ambidextrous.png differ diff --git a/images/sla-assets/Traits/anger.png b/images/sla-assets/Traits/anger.png new file mode 100644 index 0000000..a2b339a Binary files /dev/null and b/images/sla-assets/Traits/anger.png differ diff --git a/images/sla-assets/Traits/anxiety.png b/images/sla-assets/Traits/anxiety.png new file mode 100644 index 0000000..f2ed3d6 Binary files /dev/null and b/images/sla-assets/Traits/anxiety.png differ diff --git a/images/sla-assets/Traits/arrogant.png b/images/sla-assets/Traits/arrogant.png new file mode 100644 index 0000000..ce54a36 Binary files /dev/null and b/images/sla-assets/Traits/arrogant.png differ diff --git a/images/sla-assets/Traits/attractive.png b/images/sla-assets/Traits/attractive.png new file mode 100644 index 0000000..142957a Binary files /dev/null and b/images/sla-assets/Traits/attractive.png differ diff --git a/images/sla-assets/Traits/chicken.png b/images/sla-assets/Traits/chicken.png new file mode 100644 index 0000000..c815e7a Binary files /dev/null and b/images/sla-assets/Traits/chicken.png differ diff --git a/images/sla-assets/Traits/contact.png b/images/sla-assets/Traits/contact.png new file mode 100644 index 0000000..3a06c12 Binary files /dev/null and b/images/sla-assets/Traits/contact.png differ diff --git a/images/sla-assets/Traits/debt.png b/images/sla-assets/Traits/debt.png new file mode 100644 index 0000000..a0c5edf Binary files /dev/null and b/images/sla-assets/Traits/debt.png differ diff --git a/images/sla-assets/Traits/depression.png b/images/sla-assets/Traits/depression.png new file mode 100644 index 0000000..d21c6d6 Binary files /dev/null and b/images/sla-assets/Traits/depression.png differ diff --git a/images/sla-assets/Traits/drug-addict.png b/images/sla-assets/Traits/drug-addict.png new file mode 100644 index 0000000..3c47ef7 Binary files /dev/null and b/images/sla-assets/Traits/drug-addict.png differ diff --git a/images/sla-assets/Traits/enemy.png b/images/sla-assets/Traits/enemy.png new file mode 100644 index 0000000..b989b47 Binary files /dev/null and b/images/sla-assets/Traits/enemy.png differ diff --git a/images/sla-assets/Traits/exceedingly-cool.png b/images/sla-assets/Traits/exceedingly-cool.png new file mode 100644 index 0000000..b9ebdd1 Binary files /dev/null and b/images/sla-assets/Traits/exceedingly-cool.png differ diff --git a/images/sla-assets/Traits/good-hearing.png b/images/sla-assets/Traits/good-hearing.png new file mode 100644 index 0000000..bf46057 Binary files /dev/null and b/images/sla-assets/Traits/good-hearing.png differ diff --git a/images/sla-assets/Traits/good-housing.png b/images/sla-assets/Traits/good-housing.png new file mode 100644 index 0000000..7cb5048 Binary files /dev/null and b/images/sla-assets/Traits/good-housing.png differ diff --git a/images/sla-assets/Traits/good-vision.png b/images/sla-assets/Traits/good-vision.png new file mode 100644 index 0000000..7b1d468 Binary files /dev/null and b/images/sla-assets/Traits/good-vision.png differ diff --git a/images/sla-assets/Traits/illness.png b/images/sla-assets/Traits/illness.png new file mode 100644 index 0000000..cc97d3c Binary files /dev/null and b/images/sla-assets/Traits/illness.png differ diff --git a/images/sla-assets/Traits/natural-aptitude-skill.png b/images/sla-assets/Traits/natural-aptitude-skill.png new file mode 100644 index 0000000..717d714 Binary files /dev/null and b/images/sla-assets/Traits/natural-aptitude-skill.png differ diff --git a/images/sla-assets/Traits/natural-aptitude-stat.png b/images/sla-assets/Traits/natural-aptitude-stat.png new file mode 100644 index 0000000..f0b1907 Binary files /dev/null and b/images/sla-assets/Traits/natural-aptitude-stat.png differ diff --git a/images/sla-assets/Traits/pacifist.png b/images/sla-assets/Traits/pacifist.png new file mode 100644 index 0000000..21df87c Binary files /dev/null and b/images/sla-assets/Traits/pacifist.png differ diff --git a/images/sla-assets/Traits/phobia.png b/images/sla-assets/Traits/phobia.png new file mode 100644 index 0000000..a8d94f4 Binary files /dev/null and b/images/sla-assets/Traits/phobia.png differ diff --git a/images/sla-assets/Traits/poor-hearing.png b/images/sla-assets/Traits/poor-hearing.png new file mode 100644 index 0000000..1805920 Binary files /dev/null and b/images/sla-assets/Traits/poor-hearing.png differ diff --git a/images/sla-assets/Traits/poor-housing.png b/images/sla-assets/Traits/poor-housing.png new file mode 100644 index 0000000..aa75c7a Binary files /dev/null and b/images/sla-assets/Traits/poor-housing.png differ diff --git a/images/sla-assets/Traits/poor-vision.png b/images/sla-assets/Traits/poor-vision.png new file mode 100644 index 0000000..07748dc Binary files /dev/null and b/images/sla-assets/Traits/poor-vision.png differ diff --git a/images/sla-assets/Traits/psychosis.png b/images/sla-assets/Traits/psychosis.png new file mode 100644 index 0000000..9acb50a Binary files /dev/null and b/images/sla-assets/Traits/psychosis.png differ diff --git a/images/sla-assets/Traits/savings.png b/images/sla-assets/Traits/savings.png new file mode 100644 index 0000000..23f3f21 Binary files /dev/null and b/images/sla-assets/Traits/savings.png differ diff --git a/images/sla-assets/Traits/sterile.png b/images/sla-assets/Traits/sterile.png new file mode 100644 index 0000000..8a721f3 Binary files /dev/null and b/images/sla-assets/Traits/sterile.png differ diff --git a/images/sla-assets/Traits/unattractive.png b/images/sla-assets/Traits/unattractive.png new file mode 100644 index 0000000..03ee59c Binary files /dev/null and b/images/sla-assets/Traits/unattractive.png differ diff --git a/images/sla-assets/Weapons/BLA Blitzer.png b/images/sla-assets/Weapons/BLA Blitzer.png new file mode 100644 index 0000000..9ab366e Binary files /dev/null and b/images/sla-assets/Weapons/BLA Blitzer.png differ diff --git a/images/sla-assets/Weapons/CAF Blade.png b/images/sla-assets/Weapons/CAF Blade.png new file mode 100644 index 0000000..34b7e0b Binary files /dev/null and b/images/sla-assets/Weapons/CAF Blade.png differ diff --git a/images/sla-assets/Weapons/CAF SMG.png b/images/sla-assets/Weapons/CAF SMG.png new file mode 100644 index 0000000..fb82fd3 Binary files /dev/null and b/images/sla-assets/Weapons/CAF SMG.png differ diff --git a/images/sla-assets/Weapons/Chainaxe1.png b/images/sla-assets/Weapons/Chainaxe1.png new file mode 100644 index 0000000..73d97b6 Binary files /dev/null and b/images/sla-assets/Weapons/Chainaxe1.png differ diff --git a/images/sla-assets/Weapons/Chainsaw1.png b/images/sla-assets/Weapons/Chainsaw1.png new file mode 100644 index 0000000..a475ace Binary files /dev/null and b/images/sla-assets/Weapons/Chainsaw1.png differ diff --git a/images/sla-assets/Weapons/Colapsable Baton.png b/images/sla-assets/Weapons/Colapsable Baton.png new file mode 100644 index 0000000..4c1ce1a Binary files /dev/null and b/images/sla-assets/Weapons/Colapsable Baton.png differ diff --git a/images/sla-assets/Weapons/FEN 204 Gunhead.png b/images/sla-assets/Weapons/FEN 204 Gunhead.png new file mode 100644 index 0000000..5af1d84 Binary files /dev/null and b/images/sla-assets/Weapons/FEN 204 Gunhead.png differ diff --git a/images/sla-assets/Weapons/FEN 204.png b/images/sla-assets/Weapons/FEN 204.png new file mode 100644 index 0000000..d7cf32b Binary files /dev/null and b/images/sla-assets/Weapons/FEN 204.png differ diff --git a/images/sla-assets/Weapons/FEN 209 Machine PIstol.png b/images/sla-assets/Weapons/FEN 209 Machine PIstol.png new file mode 100644 index 0000000..43fab81 Binary files /dev/null and b/images/sla-assets/Weapons/FEN 209 Machine PIstol.png differ diff --git a/images/sla-assets/Weapons/FEN 30-30.png b/images/sla-assets/Weapons/FEN 30-30.png new file mode 100644 index 0000000..28f7e6f Binary files /dev/null and b/images/sla-assets/Weapons/FEN 30-30.png differ diff --git a/images/sla-assets/Weapons/FEN 401 Shiver Pistol.png b/images/sla-assets/Weapons/FEN 401 Shiver Pistol.png new file mode 100644 index 0000000..bace25f Binary files /dev/null and b/images/sla-assets/Weapons/FEN 401 Shiver Pistol.png differ diff --git a/images/sla-assets/Weapons/FEN 603 Auto Pistol.png b/images/sla-assets/Weapons/FEN 603 Auto Pistol.png new file mode 100644 index 0000000..752362d Binary files /dev/null and b/images/sla-assets/Weapons/FEN 603 Auto Pistol.png differ diff --git a/images/sla-assets/Weapons/FEN 603.png b/images/sla-assets/Weapons/FEN 603.png new file mode 100644 index 0000000..c10de64 Binary files /dev/null and b/images/sla-assets/Weapons/FEN 603.png differ diff --git a/images/sla-assets/Weapons/FEN 703 Heavy Pistol.png b/images/sla-assets/Weapons/FEN 703 Heavy Pistol.png new file mode 100644 index 0000000..b393ed3 Binary files /dev/null and b/images/sla-assets/Weapons/FEN 703 Heavy Pistol.png differ diff --git a/images/sla-assets/Weapons/FEN 706.png b/images/sla-assets/Weapons/FEN 706.png new file mode 100644 index 0000000..70e64d1 Binary files /dev/null and b/images/sla-assets/Weapons/FEN 706.png differ diff --git a/images/sla-assets/Weapons/FEN 981 Sniper Rifle.png b/images/sla-assets/Weapons/FEN 981 Sniper Rifle.png new file mode 100644 index 0000000..b41de39 Binary files /dev/null and b/images/sla-assets/Weapons/FEN 981 Sniper Rifle.png differ diff --git a/images/sla-assets/Weapons/FEN AR Assault Rifle.png b/images/sla-assets/Weapons/FEN AR Assault Rifle.png new file mode 100644 index 0000000..6dc0a08 Binary files /dev/null and b/images/sla-assets/Weapons/FEN AR Assault Rifle.png differ diff --git a/images/sla-assets/Weapons/FEN AR.png b/images/sla-assets/Weapons/FEN AR.png new file mode 100644 index 0000000..19a0b62 Binary files /dev/null and b/images/sla-assets/Weapons/FEN AR.png differ diff --git a/images/sla-assets/Weapons/FEN Reaper LMG.png b/images/sla-assets/Weapons/FEN Reaper LMG.png new file mode 100644 index 0000000..1afaef9 Binary files /dev/null and b/images/sla-assets/Weapons/FEN Reaper LMG.png differ diff --git a/images/sla-assets/Weapons/FEN10 Street Sweeper.png b/images/sla-assets/Weapons/FEN10 Street Sweeper.png new file mode 100644 index 0000000..ea8e250 Binary files /dev/null and b/images/sla-assets/Weapons/FEN10 Street Sweeper.png differ diff --git a/images/sla-assets/Weapons/FEN701 Urban Carbine.png b/images/sla-assets/Weapons/FEN701 Urban Carbine.png new file mode 100644 index 0000000..9f9bb67 Binary files /dev/null and b/images/sla-assets/Weapons/FEN701 Urban Carbine.png differ diff --git a/images/sla-assets/Weapons/Frag Grenade.png b/images/sla-assets/Weapons/Frag Grenade.png new file mode 100644 index 0000000..0fa916b Binary files /dev/null and b/images/sla-assets/Weapons/Frag Grenade.png differ diff --git a/images/sla-assets/Weapons/GA 50 Finisher.png b/images/sla-assets/Weapons/GA 50 Finisher.png new file mode 100644 index 0000000..6dc8627 Binary files /dev/null and b/images/sla-assets/Weapons/GA 50 Finisher.png differ diff --git a/images/sla-assets/Weapons/GA 9442.png b/images/sla-assets/Weapons/GA 9442.png new file mode 100644 index 0000000..6e7e6de Binary files /dev/null and b/images/sla-assets/Weapons/GA 9442.png differ diff --git a/images/sla-assets/Weapons/GA 9443.png b/images/sla-assets/Weapons/GA 9443.png new file mode 100644 index 0000000..bc348a1 Binary files /dev/null and b/images/sla-assets/Weapons/GA 9443.png differ diff --git a/images/sla-assets/Weapons/GASH First.png b/images/sla-assets/Weapons/GASH First.png new file mode 100644 index 0000000..817fa47 Binary files /dev/null and b/images/sla-assets/Weapons/GASH First.png differ diff --git a/images/sla-assets/Weapons/GASH Pacifier Baton.png b/images/sla-assets/Weapons/GASH Pacifier Baton.png new file mode 100644 index 0000000..4550e99 Binary files /dev/null and b/images/sla-assets/Weapons/GASH Pacifier Baton.png differ diff --git a/images/sla-assets/Weapons/KPS Mangler .png b/images/sla-assets/Weapons/KPS Mangler .png new file mode 100644 index 0000000..b113551 Binary files /dev/null and b/images/sla-assets/Weapons/KPS Mangler .png differ diff --git a/images/sla-assets/Weapons/KPS Shotgun.png b/images/sla-assets/Weapons/KPS Shotgun.png new file mode 100644 index 0000000..b40cba1 Binary files /dev/null and b/images/sla-assets/Weapons/KPS Shotgun.png differ diff --git a/images/sla-assets/Weapons/MAC Knife.png b/images/sla-assets/Weapons/MAC Knife.png new file mode 100644 index 0000000..e58d164 Binary files /dev/null and b/images/sla-assets/Weapons/MAC Knife.png differ diff --git a/images/sla-assets/Weapons/MILA Grenage Launcher.png b/images/sla-assets/Weapons/MILA Grenage Launcher.png new file mode 100644 index 0000000..ea5bcd7 Binary files /dev/null and b/images/sla-assets/Weapons/MILA Grenage Launcher.png differ diff --git a/images/sla-assets/Weapons/Pacifier Baton.png b/images/sla-assets/Weapons/Pacifier Baton.png new file mode 100644 index 0000000..f283624 Binary files /dev/null and b/images/sla-assets/Weapons/Pacifier Baton.png differ diff --git a/images/sla-assets/Weapons/Power ClayMOre.png b/images/sla-assets/Weapons/Power ClayMOre.png new file mode 100644 index 0000000..ebbca3b Binary files /dev/null and b/images/sla-assets/Weapons/Power ClayMOre.png differ diff --git a/images/sla-assets/Weapons/SLA Blade.png b/images/sla-assets/Weapons/SLA Blade.png new file mode 100644 index 0000000..1e2ad10 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Blade.png differ diff --git a/images/sla-assets/Weapons/SLA Breach.png b/images/sla-assets/Weapons/SLA Breach.png new file mode 100644 index 0000000..3e72099 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Breach.png differ diff --git a/images/sla-assets/Weapons/SLA Carbine Rifle.png b/images/sla-assets/Weapons/SLA Carbine Rifle.png new file mode 100644 index 0000000..8b96ad1 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Carbine Rifle.png differ diff --git a/images/sla-assets/Weapons/SLA Combat KNife Standard.png b/images/sla-assets/Weapons/SLA Combat KNife Standard.png new file mode 100644 index 0000000..07f8404 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Combat KNife Standard.png differ diff --git a/images/sla-assets/Weapons/SLA Combat Shotgun.png b/images/sla-assets/Weapons/SLA Combat Shotgun.png new file mode 100644 index 0000000..d242c51 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Combat Shotgun.png differ diff --git a/images/sla-assets/Weapons/SLA Heavy Launcher.png b/images/sla-assets/Weapons/SLA Heavy Launcher.png new file mode 100644 index 0000000..39cd448 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Heavy Launcher.png differ diff --git a/images/sla-assets/Weapons/SLA MArksman Rifle.png b/images/sla-assets/Weapons/SLA MArksman Rifle.png new file mode 100644 index 0000000..158f323 Binary files /dev/null and b/images/sla-assets/Weapons/SLA MArksman Rifle.png differ diff --git a/images/sla-assets/Weapons/SLA Mono Knife.png b/images/sla-assets/Weapons/SLA Mono Knife.png new file mode 100644 index 0000000..3d0b270 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Mono Knife.png differ diff --git a/images/sla-assets/Weapons/SLA SUpport LMG.png b/images/sla-assets/Weapons/SLA SUpport LMG.png new file mode 100644 index 0000000..d5abb1c Binary files /dev/null and b/images/sla-assets/Weapons/SLA SUpport LMG.png differ diff --git a/images/sla-assets/Weapons/SLA Snare Launcher.png b/images/sla-assets/Weapons/SLA Snare Launcher.png new file mode 100644 index 0000000..679d318 Binary files /dev/null and b/images/sla-assets/Weapons/SLA Snare Launcher.png differ diff --git a/images/sla-assets/Weapons/Shacktar Claws.png b/images/sla-assets/Weapons/Shacktar Claws.png new file mode 100644 index 0000000..3daa78a Binary files /dev/null and b/images/sla-assets/Weapons/Shacktar Claws.png differ diff --git a/images/sla-assets/Weapons/Stormer Claws.png b/images/sla-assets/Weapons/Stormer Claws.png new file mode 100644 index 0000000..2066b51 Binary files /dev/null and b/images/sla-assets/Weapons/Stormer Claws.png differ diff --git a/images/sla-assets/Weapons/Vibro Sabre.png b/images/sla-assets/Weapons/Vibro Sabre.png new file mode 100644 index 0000000..e4d2824 Binary files /dev/null and b/images/sla-assets/Weapons/Vibro Sabre.png differ diff --git a/images/sla-assets/Weapons/Wraith Raider Claws.png b/images/sla-assets/Weapons/Wraith Raider Claws.png new file mode 100644 index 0000000..d37ce61 Binary files /dev/null and b/images/sla-assets/Weapons/Wraith Raider Claws.png differ diff --git a/lang/en.json b/lang/en.json new file mode 100644 index 0000000..a0ff12b --- /dev/null +++ b/lang/en.json @@ -0,0 +1,1145 @@ +{ + "Mosh":{ + "table": { + "death_save": { + "roll": { + "android": "You knock on death's door.", + "human": "You knock on death's door." + } + }, + "blunt_force_wound": { + "roll": { + "android": "You brace for the worst.", + "human": "You brace for the worst." + } + }, + "bleeding_wound": { + "roll": { + "android": "You brace for the worst.", + "human": "You brace for the worst." + } + }, + "gunshot_wound": { + "roll": { + "android": "You brace for the worst.", + "human": "You brace for the worst." + } + }, + "fire_explosives_wound": { + "roll": { + "android": "You brace for the worst.", + "human": "You brace for the worst." + } + }, + "gore_massive_wound": { + "roll": { + "android": "You brace for the worst.", + "human": "You brace for the worst." + } + }, + "panic_check": { + "roll": { + "android": "You lose motor control for a moment as your sensory inputs flicker.", + "human": "Your heartbeat races out of control and you start to feel dizzy." + }, + "success": { + "android": "System resources free up and you regain control.", + "human": "You take a deep breath and regain your composure." + } + }, + "distress_signal": { + "roll": { + "human": "You put your ship on emergency power, seal yourselves in cryopods, send out a Distress Signal, and wait for help. It’s a long shot, but sometimes it’s the only shot you’ve got. Will you be found?" + } + }, + "maintenance_issues": { + "roll": { + "human": "You perform a full inspection of the ship for wear and tear." + }, + "success": { + "human": "You find nothing wrong with the ship." + } + } + }, + "item": { + "condition": { + "add": { + "android": "You now suffer from this condition", + "human": "You now suffer from this condition" + }, + "increase": { + "android": "Your condition worsens.", + "human": "Your condition worsens." + }, + "bleed": { + "android": "Your sensors detect significant nanofluid loss.", + "human": "You feel dizzy as you bleed out." + }, + "radiation": { + "android": "Catastro▒ic d⟑ta ▓loss de|/~ ⋥t⋱d", + "human": "You stare into blackness and feel completely unable to pull yourself out of it." + }, + "cryo": { + "android": "Your systems malfunction from the condensation damage.", + "human": "You awaken cold and frigid, barely able to move." + } + } + }, + "attribute": { + "stress": { + "increase": { + "android": "Power surges through your chest and you start to overheat.", + "human": "You feel tightness in your chest and start to sweat." + }, + "increaseHeader": { + "android": "Stress Gained", + "human": "Stress Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png" + }, + "hitCeiling": { + "android": "System performance grinds to a halt.", + "human": "You hit rock bottom." + }, + "pastCeiling": { + "android": "You sense unrecoverable data loss.", + "human": "You feel a part of yourself drift away." + }, + "decrease": { + "android": "You soft-reset, purging unnecessary background processes.", + "human": "You feel a sense of calm wash over you." + }, + "decreaseHeader": { + "android": "Stress Relieved", + "human": "Stress Relieved" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png" + }, + "hitFloor": { + "android": "You attain perfect focus and clarity. ", + "human": "You attain complete peace of mind." + }, + "pastFloor": { + "android": "You are already as focused as possible.", + "human": "You are already as calm as possible." + } + }, + "calm": { + "increase": { + "android": "You soft-reset, purging unnecessary background processes.", + "human": "You feel a sense of calm wash over you." + }, + "increaseHeader": { + "android": "Calm Gained", + "human": "Calm Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png" + }, + "hitCeiling": { + "android": "You attain perfect focus and clarity.", + "human": "You attain complete peace of mind." + }, + "pastCeiling": { + "android": "You are already as focused as possible.", + "human": "You are already as calm as possible." + }, + "decrease": { + "android": "Power surges through your chest and you start to overheat.", + "human": "You feel tightness in your chest and start to sweat." + }, + "decreaseHeader": { + "android": "Calm Lost", + "human": "Calm Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png" + }, + "hitFloor": { + "android": "System performance grinds to a halt.", + "human": "You hit rock bottom." + }, + "pastFloor": { + "android": "You sense unrecoverable data loss.", + "human": "You feel a part of yourself drift away." + } + }, + "health": { + "increase": { + "android": "System resources free up and you feel energized.", + "human": "You feel a burst of energy." + }, + "increaseHeader": { + "android": "Health Gained", + "human": "Health Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitCeiling": { + "android": "You are now at full health.", + "human": "You are now at full health." + }, + "pastCeiling": { + "android": "You are already at full health.", + "human": "You are already at full health." + }, + "decrease": { + "android": "Your pain receptors indicate core damage.", + "human": "You wince from the pain." + }, + "decreaseHeader": { + "android": "Health Lost", + "human": "Health Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitFloor": { + "android": "Your pain receptors indicate core damage.", + "human": "Your pain receptors indicate core damage." + }, + "pastFloor": { + "android": "Your pain receptors indicate core damage.", + "human": "Your pain receptors indicate core damage." + } + }, + "hits": { + "increase": { + "android": "@UUID[Compendium.mosh.macros_hotbar_1e.ZzKgfEmRdvDfyBMS]{Make a Wound Check}", + "human": "@UUID[Compendium.mosh.macros_hotbar_1e.ZzKgfEmRdvDfyBMS]{Make a Wound Check}" + }, + "increaseHeader": { + "android": "Damaged", + "human": "Wounded" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitCeiling": { + "android": "The end draws near . . .

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Make a Death Save}", + "human": "The end draws near . . .

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Make a Death Save}" + }, + "pastCeiling": { + "android": "The end draws near . . .

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Make a Death Save}", + "human": "The end draws near . . .

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Make a Death Save}" + }, + "decrease": { + "android": "System resources free up and you feel energized.", + "human": "You feel a burst of energy." + }, + "decreaseHeader": { + "android": "Repaired", + "human": "Mended" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitFloor": { + "android": "You are now at full health.", + "human": "You are now at full health." + }, + "pastFloor": { + "android": "You are already at full health.", + "human": "You are already at full health." + } + }, + "strength": { + "check": { + "android": "You gain some confidence in your skills.", + "human": "You gain some confidence in your skills." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Strength Enhanced", + "human": "Strength Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/strength.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/strength.png" + }, + "hitCeiling": { + "android": "You are now at maximum strength.", + "human": "You are now at maximum strength." + }, + "pastCeiling": { + "android": "You are already at maximum strength.", + "human": "You are already at maximum strength." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Strength Impaired", + "human": "Strength Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/strength.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/strength.png" + }, + "hitFloor": { + "android": "You have no strength left.", + "human": "You have no strength left." + }, + "pastFloor": { + "android": "Your strength cannot get any lower.", + "human": "Your strength cannot get any lower." + } + }, + "speed": { + "check": { + "android": "You gain some confidence in your skills.", + "human": "You gain some confidence in your skills." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Speed Enhanced", + "human": "Speed Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/speed.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/speed.png" + }, + "hitCeiling": { + "android": "You are now at maximum speed.", + "human": "You are now at maximum speed." + }, + "pastCeiling": { + "android": "You are already at maximum speed.", + "human": "You are already at maximum speed." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Speed Impaired", + "human": "Speed Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/speed.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/speed.png" + }, + "hitFloor": { + "android": "You feel completely lethargic.", + "human": "You feel completely lethargic." + }, + "pastFloor": { + "android": "Your speed cannot get any lower.", + "human": "Your speed cannot get any lower." + } + }, + "intellect": { + "check": { + "android": "You gain some confidence in your skills.", + "human": "You gain some confidence in your skills." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Intellect Enhanced", + "human": "Intellect Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/intellect.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/intellect.png" + }, + "hitCeiling": { + "android": "You are now at maximum intellect.", + "human": "You are now at maximum intellect." + }, + "pastCeiling": { + "android": "You are already at maximum intellect.", + "human": "You are already at maximum intellect." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Intellect Impaired", + "human": "Intellect Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/intellect.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/intellect.png" + }, + "hitFloor": { + "android": "You feel utterly confused.", + "human": "You feel utterly confused." + }, + "pastFloor": { + "android": "Your intellect cannot get any lower.", + "human": "Your intellect cannot get any lower." + } + }, + "combat": { + "check": { + "android": "You gain some confidence in your skills.", + "human": "You gain some confidence in your skills." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Combat Enhanced", + "human": "Combat Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/combat.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/combat.png" + }, + "hitCeiling": { + "android": "You are now at maximum combat.", + "human": "You are now at maximum combat." + }, + "pastCeiling": { + "android": "You are already at maximum combat.", + "human": "You are already at maximum combat." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Combat Impaired", + "human": "Combat Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/combat.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/combat.png" + }, + "hitFloor": { + "android": "You can't imagine fighting anymore.", + "human": "You can't imagine fighting anymore." + }, + "pastFloor": { + "android": "Your combat cannot get any lower.", + "human": "Your combat cannot get any lower." + } + }, + "instinct": { + "check": { + "android": "You gain some confidence in your skills.", + "human": "You gain some confidence in your skills." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Instinct Enhanced", + "human": "Instinct Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/instinct.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/instinct.png" + }, + "hitCeiling": { + "android": "You are now at maximum instinct.", + "human": "You are now at maximum instinct." + }, + "pastCeiling": { + "android": "You are already at maximum instinct.", + "human": "You are already at maximum instinct." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Instinct Impaired", + "human": "Instinct Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/instinct.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/instinct.png" + }, + "hitFloor": { + "android": "You've lost your instincts.", + "human": "You've lost your instincts." + }, + "pastFloor": { + "android": "Your instinct cannot get any lower.", + "human": "Your instinct cannot get any lower." + } + }, + "loyalty": { + "check": { + "android": "You gain some confidence in your skills.", + "human": "You gain some confidence in your skills." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Loyalty Enhanced", + "human": "Loyalty Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png" + }, + "hitCeiling": { + "android": "You are now at maximum loyalty.", + "human": "You are now at maximum loyalty." + }, + "pastCeiling": { + "android": "You are already at maximum loyalty.", + "human": "You are already at maximum loyalty." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Loyalty Impaired", + "human": "Loyalty Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png" + }, + "hitFloor": { + "android": "You only care about yourself.", + "human": "You only care about yourself." + }, + "pastFloor": { + "android": "Your loyalty cannot get any lower.", + "human": "Your loyalty cannot get any lower." + } + }, + "sanity": { + "check": { + "android": "You gain some confidence in your abilities.", + "human": "You gain some confidence in your abilities." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Sanity Enhanced", + "human": "Sanity Increased" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/sanity.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/sanity.png" + }, + "hitCeiling": { + "android": "You are now at maximum sanity.", + "human": "You are now at maximum sanity." + }, + "pastCeiling": { + "android": "You are already at maximum sanity.", + "human": "You are already at maximum sanity." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Sanity Impaired", + "human": "Sanity Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/sanity.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/sanity.png" + }, + "hitFloor": { + "android": "You've lost your mind.", + "human": "You've lost your mind." + }, + "pastFloor": { + "android": "Your sanity cannot get any lower.", + "human": "Your sanity cannot get any lower." + } + }, + "fear": { + "check": { + "android": "You gain some confidence in your abilities.", + "human": "You gain some confidence in your abilities." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Bravery Enhanced", + "human": "Bravery Improved" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/fear.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/fear.png" + }, + "hitCeiling": { + "android": "You are now at maximum fear.", + "human": "You are now at maximum fear." + }, + "pastCeiling": { + "android": "You are already at maximum fear.", + "human": "You are already at maximum fear." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Bravery Impaired", + "human": "Bravery Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/fear.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/fear.png" + }, + "hitFloor": { + "android": "You are afraid of everything.", + "human": "You are afraid of everything." + }, + "pastFloor": { + "android": "Your fear cannot get any lower.", + "human": "Your fear cannot get any lower." + } + }, + "body": { + "check": { + "android": "You gain some confidence in your abilities.", + "human": "You gain some confidence in your abilities." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Body Enhanced", + "human": "Body Strengthened" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/body.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/body.png" + }, + "hitCeiling": { + "android": "You are now at maximum body.", + "human": "You are now at maximum body." + }, + "pastCeiling": { + "android": "You are already at maximum body.", + "human": "You are already at maximum body." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Body Impaired", + "human": "Body Weakened" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/body.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/body.png" + }, + "hitFloor": { + "android": "Your body feels weak and fragile.", + "human": "Your body feels weak and frail." + }, + "pastFloor": { + "android": "Your body cannot get any lower.", + "human": "Your body cannot get any lower." + } + }, + "armor": { + "check": { + "android": "You gain some confidence in your abilities.", + "human": "You gain some confidence in your abilities." + }, + "increase": { + "android": "Data recovered. Central partition data restored.", + "human": "You start to feel like yourself again." + }, + "increaseHeader": { + "android": "Armor Enhanced", + "human": "Armor Gained" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/armor.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/armor.png" + }, + "hitCeiling": { + "android": "You are now at maximum armor.", + "human": "You are now at maximum armor." + }, + "pastCeiling": { + "android": "You are already at maximum armor.", + "human": "You are already at maximum armor." + }, + "decrease": { + "android": "Central partition damage detected. Unrecoverable sectors found.", + "human": "You feel a part of yourself drift away." + }, + "decreaseHeader": { + "android": "Armor Impaired", + "human": "Armor Lost" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/armor.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/armor.png" + }, + "hitFloor": { + "android": "Nothing protects you now.", + "human": "Nothing protects you now." + }, + "pastFloor": { + "android": "Your armor cannot get any lower.", + "human": "Your armor cannot get any lower." + } + }, + "thrusters": { + "check": { + "human": "You successfully manuever the craft through danger." + }, + "increase": { + "human": "Thrusters upgraded. Agility, acceleration, and top speed have improved." + }, + "increaseHeader": { + "human": "Thrusters Enhanced" + }, + "increaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/thrusters.png" + }, + "hitCeiling": { + "human": "Your thrusters are at maximum." + }, + "pastCeiling": { + "human": "Your thrusters are already at maximum and cannot be improved further." + }, + "decrease": { + "human": "Thrusters damaged. Agility, acceleration, and top speed are impaired." + }, + "decreaseHeader": { + "human": "Thrusters Impaired" + }, + "decreaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/thrusters.png" + }, + "hitFloor": { + "human": "You've lost your thrusters." + }, + "pastFloor": { + "human": "Your thrusters are broken and cannot be damaged further." + } + }, + "battle": { + "check": { + "human": "You land a successful hit on the target." + }, + "increase": { + "human": "Targeting systems upgraded. Combat readiness has improved." + }, + "increaseHeader": { + "human": "Battle Enhanced" + }, + "increaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitCeiling": { + "human": "Your targeting systems are at maximum." + }, + "pastCeiling": { + "human": "Your targeting systems are already at maximum and cannot be improved further." + }, + "decrease": { + "human": "Targeting systems damaged. Combat readiness have been impaired." + }, + "decreaseHeader": { + "human": "Battle Impaired" + }, + "decreaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitFloor": { + "human": "You've lost your targeting systems." + }, + "pastFloor": { + "human": "Your targeting systems are broken and cannot be damaged further." + } + }, + "systems": { + "check": { + "human": "Your ship's systems are running smoothly." + }, + "increase": { + "human": "Systems upgraded. Sensors, computers, and other systems have improved." + }, + "increaseHeader": { + "human": "Systems Enhanced" + }, + "increaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitCeiling": { + "human": "Your ship's systems are at maximum." + }, + "pastCeiling": { + "human": "Your ship's systems are already at maximum and cannot be improved further." + }, + "decrease": { + "human": "Systems damaged. Sensors, computers, and other systems have been impaired." + }, + "decreaseHeader": { + "human": "Systems Impaired" + }, + "decreaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitFloor": { + "human": "You've lost your ship's systems." + }, + "pastFloor": { + "human": "Your ship's systems are broken and cannot be damaged further." + } + } + }, + "macro": { + "wound": { + "bleeding": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.1DD8i6eCS6nx2Ip0]{Bleeding}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.1DD8i6eCS6nx2Ip0]{Bleeding}" + }, + "bleeding_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.xr2o2PU5vdrR6fxQ]{Bleeding [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.xr2o2PU5vdrR6fxQ]{Bleeding [-]}" + }, + "bleeding_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.tFcWNddtZvlv7tsg]{Bleeding [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.tFcWNddtZvlv7tsg]{Bleeding [+]}" + }, + "blunt_force": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.TAjlQjA5AAy3qYL3]{Blunt Force}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.TAjlQjA5AAy3qYL3]{Blunt Force}" + }, + "blunt_force_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.k0zf8ZGivRguc0wb]{Blunt Force [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.k0zf8ZGivRguc0wb]{Blunt Force [-]}" + }, + "blunt_force_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.oL3GH0HoEPlP8vzG]{Blunt Force [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.oL3GH0HoEPlP8vzG]{Blunt Force [+]}" + }, + "fire_explosives": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.bZi1qKmcKLFvnhZ2]{Fire & Explosives}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.bZi1qKmcKLFvnhZ2]{Fire & Explosives}" + }, + "fire_explosives_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.7rYhbDAaFeok1Daq]{Fire & Explosives [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.7rYhbDAaFeok1Daq]{Fire & Explosives [-]}" + }, + "fire_explosives_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.dJnQKDf0AlwK27QD]{Fire & Explosives [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.dJnQKDf0AlwK27QD]{Fire & Explosives [+]}" + }, + "gore_massive": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.S9nnHKWYGSQmjQdp]{Gore}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.S9nnHKWYGSQmjQdp]{Gore}" + }, + "gore_massive_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.eQPuDgwv8evetFIk]{Gore [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.eQPuDgwv8evetFIk]{Gore [-]}" + }, + "gore_massive_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.DuVjNlE4lsnR7Emc]{Gore [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.DuVjNlE4lsnR7Emc]{Gore [+]}" + }, + "gunshot": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.XgCOLv9UunBddUyW]{Gunshot}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.XgCOLv9UunBddUyW]{Gunshot}" + }, + "gunshot_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.LTpa1ZYVZl4m9k6z]{Gunshot [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.LTpa1ZYVZl4m9k6z]{Gunshot [-]}" + }, + "gunshot_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.fnVATRHYJEUlS3pR]{Gunshot [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.fnVATRHYJEUlS3pR]{Gunshot [+]}" + } + } + }, + "CharacterGenerator":{ + "name": "Character Generator", + "CommonSkills": "Common Skills", + "CommonSkillExplanation": "This is a list of usual skill for this class to be used for random character generation.", + "StatOption": "Stats & Saves", + "StatOptionPopupTitle": "Class Attribute and Saves option", + "StatOptionPopupText": "Choose where to apply the bonus of:", + "SkillOption.Classerror": "You need to select a class first.", + "SkillOption.PopupTitle": "Choose your skills", + "SkillOption.PopupTrainedDescription": "Choose 1 Trained skill", + "SkillOption.PopupExpertDescription": "Choose 1 Expert skill", + "SkillOption.PopupMasterDescription": "Choose 1 Master skill", + "SkillOption.PopupFullMasterName": "Master Set", + "SkillOption.PopupFullMasterDescription": "Choose 1 Master skill, and an Expert and Trained Skill prerequisite.", + "SkillOption.PopupFullExpertName": "Expert Set", + "SkillOption.PopupFullExperDescription": "Choose 1 Expert skill, and Trained Skill prerequisite.", + "SkillOption.ChoiceWord": "Option", + "SkillOption.ChoiceText":"Choose 1 from these skill bonus options", + "Tables": "Tables", + "Table.Loadout": "Loadout Table", + "Table.Patch": "Patch Table", + "Table.Trinket": "Trinket Table", + "Error.NoClass": "You need to select a class first." + }, + "Add": "Add", + "AddOr":"Add Or", + "AddOption":"Add Option", + "AddGroup":"Add Group", + "AddASkill": "Add a Skill?", + "Advantage": "Advantage", + "AllStatsAndSavesDecreasedBy": "All stats and saves decreased by", + "Ammo": "Ammo", + "Ammunition": "Ammunition", + "AmmoType": "Ammo Type", + "AntiArmorAcronym": "AA", + "AntiArmor": "Anti Armor", + "AP": "AP", + "Armor": "Armor", + "ArmorName": "Armor Name", + "ArmorPoints": "Armor Points", + "Background": "Background", + "Bankruptcy": "Bankruptcy", + "BankruptcyCheck": "Bankruptcy Check", + "BankruptcySave": "Bankruptcy Save", + "Base": "Base", + "Battle": "Battle", + "Bio": "Bio", + "Body": "Body", + "BodySave": "Body Save", + "Bonus": "Bonus", + "Calm": "Calm", + "Cargo": "Cargo", + "CarryingCapacity": "Carrying Capacity", + "CLASS": "CLASS", + "classNewStatOptionEmptyError":"You must select at least two stat or saves", + "classNewSkillOptionSkillTip":"Save first.", + "Combat": "Combat", + "Condition": "Condition", + "Cost": "Cost", + "CreateCondition": "Create Condition", + "CreateItem": "Create Item", + "CreateSkill": "Create Skill", + "CreateWeapon": "Create Weapon", + "CreatureSettings": "Creature Settings", + "Credits": "Credits", + "Crew": "Crew", + "CriticalDamage": "Critical Damage", + "Cryopods": "Cryopods", + "CryofreezeDamage": "Cryofreeze Damage", + "Current": "Current", + "CurrentShots": "Current Shots", + "CurrentWeight": "Current Weight", + "Damage": "Damage", + "DeleteArmor": "Delete Armor", + "DeleteCondition": "Delete Condition", + "DeleteItem": "Delete Item", + "DeleteSkill": "Delete Skill", + "DeleteWeapon": "Delete Weapon", + "DeleteGroup": "Delete Group", + "DeleteOption": "Delete Option", + "Description": "Description", + "Disabled": "Disabled", + "Disadvantage": "Disadvantage", + "DistressSignal": "Distress Signal", + "DoNotAddASkillToThisRoll": "Do not add a skill to this roll.", + "DMGReduction": "DMG Reduction", + "DR": "DR", + "Fuel": "Fuel", + "Feature": "Feature", + "Features": "Features", + "EditArmor": "Edit Armor", + "EditCondition": "Edit Condition", + "EditItem": "Edit Item", + "EditSkill": "Edit Skill", + "EditWeapon": "Edit Weapon", + "Equipped": "Equipped", + "Emergency": "Emergency", + "Enabled": "Enabled", + "EnemyShips": "Enemy Ships", + "EscapePods": "Escape Pods", + "Fear": "Fear", + "Finances": "Finances", + "Health": "Health", + "HighScore": "High Score", + "Hits": "Hits", + "HullPoints": "Hull Points", + "Installed": "Installed", + "Instinct": "Instinct", + "Intellect": "Intellect", + "ItemName": "Item Name", + "Item": "Item", + "Items": "Items", + "Level": "Level", + "Loyalty": "Loyalty", + "Macros": "Macros", + "MaintenanceAndRepairs": "Maintenance & Repairs", + "MaintenanceCheck": "Maintenance Check", + "Major": "Major", + "Maximum": "Maximum", + "MaxShots": "Max Shots", + "MaxO2": "Max. O2", + "Megadamage": "Megadamage", + "Minimum": "Minimum", + "ModuleName": "Module Name", + "MoraleCheck": "Morale Check", + "MoraleCheckDescription": "After any Ship Round where an enemy takes MDMG, they must make a Morale Check. To make a Morale Check, roll 1d10. If they roll under their current MDMG, they may send a hail offering a ceasefire and to resume negotiations.", + "NA": "N/A", + "Name": "Name", + "Next": "Next", + "Normal": "Normal", + "Notes": "Notes", + "O2Remaining": "O2 Remaining", + "OK": "OK", + "OpenDeckplan": "Open Deckplan", + "Other": "Other", + "Oxygen": "Oxygen", + "PanicCheck": "Panic Check", + "Pronouns": "Pronouns", + "Quantity": "Quantity", + "RadiationDamage": "Radiation Damage", + "Range": "Range", + "RANK": "Rank", + "Repairs": "Repairs", + "Resolve": "Resolve", + "Robotic": "Robotic", + "RollingForGeneric": "Rolling for {name}", + "RollingForPanicEffect": "Rolling for panic effect...", + "RollingForMaintenanceIssue": "Rolling for maintenance issue...", + "Sanity": "Sanity", + "SaveBonus": "SaveBonus", + "Severity": "Severity", + "ShipIdentifier": "Ship Identifier", + "ShipWeaponBonus": "Ship Weapon Bonus", + "Shots": "Shots", + "ShotsPerFiring": "Shots per Firing", + "SkillBonus": "Skill Bonus", + "SkillName": "Skill Name", + "SkillRank": "Skill Rank", + "SkillRankTrained": "Trained", + "SkillRankExpert": "Expert", + "SkillRankMaster": "Master", + "Skills": "Skills", + "SkillsFixed": "Fixed Skills", + "SkillsPrerequisite": "Prerequisite Skills", + "SkillsOptionalAnd": "Selected Skills", + "SkillsOptionalOr": "Optional Skills", + "SkillTraining": "Skill Training", + "SpecialAbilities": "Special Abilities", + "Speed": "Speed", + "StatsAndSaves": "Stats & Saves", + "Strength": "Strength", + "Stress": "Stress", + "StressResponse": "Stress Response", + "Systems": "Systems", + "Thrusters": "Thrusters", + "Total": "Total", + "TraumaResponse": "Trauma Response", + "Transponder": "Transponder", + "Treatment": "Treatment", + "Upgrades": "Upgrades", + "UsesAmmo": "Uses Ammo", + "Value": "Value", + "WarpCores": "Warp Cores", + "WeaponName": "Weapon Name", + "Weapons": "Weapons", + "Weight": "Weight", + "Wounds": "Wounds", + "WoundEffect": "Wound Effect", + "XP": "XP", + "YouRolled90OrHigher": "You rolled 90 or higher, which is always considered a failure.", + "HEARTATTACKSHORTCIRCUITANDROIDS": "HEART ATTACK / SHORT CIRCUIT (ANDROIDS).", + "SHORTCIRCUIT": "SHORT CIRCUIT.", + "HEARTATTACK": "HEART ATTACK.", + "Relieve1Stressqbq694JMbXeZrHj": " Relieve 1 Stress.

@UUID[Compendium.macros_triggered_1e.qbq694JMbXeZrHjj]{-1 Stress}", + "Gain1d10Calmk2TtLFOG9mGaWVx31d10Calm":" Gain 1d10 Calm.

@UUID[Compendium.macros_triggered_1e.k2TtLFOG9mGaWVx3]{+1d10 Calm}", + "SelectAStat": "Select a Stat", + "ChooseTheStatForSkillCheck": "Choose the Stat that best suits the nature of this Skill Check. You will add your skill bonus to the Stat value for this roll", + "GivingYouAHigherNumber": "(giving you a higher number to roll under).", + "StrengthSkillExample": "Holding airlocks closed, carrying fallen comrades, climbing, pushing, jumping.", + "SpeedSkillExample": "Getting out of the cargo bay before the blast doors close, acting before someone (or something) else, running away.", + "IntellectSkillExample": "Recalling your training and experience under duress, thinking through difficult problems, inventing or fixing things.", + "CombatSkillExample": "Fighting for your life.", + "SelectYourRollType": "Select your roll type", + "ChooseAStat": "Choose a Stat", + "SwarmWoundShort":"W*", + "IfYouHaveARelevantSkill":"If you have a Skill that is relevant to the task at hand, you can add the Skill’s bonus to your Stat or Save before making your roll", + "HeavyCover": "Heavy Cover", + "Cover": "Cover", + "NoCover": "No Cover", + "LightCover": "Light Cover", + "InsignificantCover": "Insignificant Cover", + "SelectYourCurrentCoverSituation": "Select your current cover situation", + "TheEnvironmentCanProvideProtectionCalled": "The environment can provide protection called", + "IfYouShotWhileInCover": "If you shoot while in Cover, you are considered out of Cover until your next turn", + "ItCanBeDestroyedLikeArmor": "It can be destroyed, just like armor, whenever it is dealt Damage greater than or equal to its AP. Cover typically only protects against ranged attacks, but in some situations may help block a hand-to-hand attack.", + "YourCoverValuesAreDisplayedIn": "Your Cover values are displayed in", + "Orange": "orange", + "UnprotectedOutInTheOpen": "Unprotected, out in the open, etc.", + "WoodFurnitureDoorsShields": "Wood furniture/doors, body shields, etc.", + "TreesBulkheadWallMetalFurniture": "Trees, bulkhead walls, metal furniture, etc.", + "AirlockDoorsCementBeamsShips": "Airlock doors, cement beams, ships, etc.", + "DistressSignalTableExplanation": "Occasionally you may need to put your ship on emergency power, seal yourselves in cryopods, send out a Distress Signal, and wait for help. It’s a long shot, but sometimes it’s the only shot you’ve got. When this happens, roll on this table.", + "MaintenanceCheckExplanation1": "Eventually, your ship needs a tune-up, or sometimes a complete overhaul. When this happens, you’ll need to get it repaired.", + "MinorRepairs": "Minor Repairs", + "MayorRepairs": "Mayor Repairs", + "MinorRepairsExplanation" : "cover cosmetic damage, cleanup, and other handyman type work that can be handled in flight, usually within 2d10 days", + "MayorRepairsExplanation": "cover large scale structural or system damage, including repairing Megadamage and Hull, and can only be fixed in port.", + "BankrupcyCheckExplanation": "A slim minority of ships are owned by small banking firms who share ownership with the operators, fronting all costs of the vessel and taking most of the profits. In exchange, you get a ship and a relatively free hand in conducting your business on the Rim. Each year", + "OrQuarterAsDeterminedBWarden" : "or quarter, as determined by your Warden", + "MakeA": "make a", + "BankrupcySaveExplanationEnd": "to determine the financial health of the company", + "WeaponReloaded": "Weapon reloaded", + "Reload":"Reload", + "OutOfAmmo": "Out of ammo", + "OutOfAmmoNeedReload": "Out of ammo, you need to reload", + "WeaponIssue": "Weapon Issue", + "YouAddThisToYourInventory": "You add this to your inventory.", + "YouLearnThisSkill": "You learn this skill", + "YouAddAnotherOfThisToYourInventory": "You add another one of these to your inventory.", + "HealthZeroMessage": "Your health has hit zero and you must take a wound.", + "HealthZeroMessage2": "Your health has hit zero and you must take a wound. Your health has been reset to ", + "YouSenseTheWeightOfYourSetbacks": "You sense the weight of your setbacks.", + "Bankrupcy": "Bankrupcy", + "BankrupcySave": "Bankrupcy Save", + "RestSave": "Rest Save", + "Job": "Occupation", + "Class": "Class", + "Type": "Type", + "Owed": "Owed", + "Hull": "Hull", + "Modules": "Modules", + "DeckPlan": "Deck Plan", + "Stock": "Stock", + "Errors":{ + "SkillAlreadyInList":"This skill is already in the list.", + "NoDropTarget":"Something went wrong with the drop, please try again." + } + } +} diff --git a/lang/pt-BR.json b/lang/pt-BR.json new file mode 100644 index 0000000..49c8ea2 --- /dev/null +++ b/lang/pt-BR.json @@ -0,0 +1,1145 @@ +{ + "Mosh":{ + "table": { + "death_save": { + "roll": { + "android": "Você bate à porta da morte.", + "human": "Você bate à porta da morte." + } + }, + "blunt_force_wound": { + "roll": { + "android": "Você se prepara para o pior.", + "human": "Você se prepara para o pior." + } + }, + "bleeding_wound": { + "roll": { + "android": "Você se prepara para o pior.", + "human": "Você se prepara para o pior." + } + }, + "gunshot_wound": { + "roll": { + "android": "Você se prepara para o pior.", + "human": "Você se prepara para o pior." + } + }, + "fire_explosives_wound": { + "roll": { + "android": "Você se prepara para o pior.", + "human": "Você se prepara para o pior." + } + }, + "gore_massive_wound": { + "roll": { + "android": "Você se prepara para o pior.", + "human": "Você se prepara para o pior." + } + }, + "panic_check": { + "roll": { + "android": "Você perde o controle motor por um momento enquanto seus sensores piscam.", + "human": "Seu coração dispara descontroladamente e você começa a se sentir tonto." + }, + "success": { + "android": "Os recursos do sistema se estabilizam e você recupera o controle.", + "human": "Você respira fundo e recupera a compostura." + } + }, + "distress_signal": { + "roll": { + "human": "Você coloca sua nave em modo de emergência, se tranca nos criopods, envia um Sinal de Socorro e espera por ajuda. É uma chance remota, mas às vezes é a única opção. Você será encontrado?" + } + }, + "maintenance_issues": { + "roll": { + "human": "Você realiza uma inspeção completa na nave em busca de desgaste e avarias." + }, + "success": { + "human": "Você não encontra nada de errado com a nave." + } + } + }, + "item": { + "condition": { + "add": { + "android": "Agora você sofre dessa condição.", + "human": "Agora você sofre dessa condição." + }, + "increase": { + "android": "Sua condição piora.", + "human": "Sua condição piora." + }, + "bleed": { + "android": "Seus sensores detectam uma perda significativa de nanofluido.", + "human": "Você se sente tonto enquanto sangra." + }, + "radiation": { + "android": "Catastr▒fica p⟑rda de da▓os de|/~ ⋥t⋱d", + "human": "Você encara a escuridão e sente-se completamente incapaz de sair dela." + }, + "cryo": { + "android": "Seus sistemas falham devido aos danos por condensação.", + "human": "Você desperta gelado e rígido, mal conseguindo se mover." + } + } + }, + "attribute": { + "stress": { + "increase": { + "android": "Uma sobrecarga de energia percorre seu núcleo e você começa a superaquecer.", + "human": "Você sente um aperto no peito e começa a suar." + }, + "increaseHeader": { + "android": "Estresse Ganhado", + "human": "Estresse Ganhado" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png" + }, + "hitCeiling": { + "android": "O desempenho do sistema chega a um ponto de falha.", + "human": "Você atinge o fundo do poço." + }, + "pastCeiling": { + "android": "Você sente a perda de dados irreparável.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decrease": { + "android": "Você faz um reset suave, purgando processos em segundo plano desnecessários.", + "human": "Você sente uma sensação de calma invadir você." + }, + "decreaseHeader": { + "android": "Estresse Aliviado", + "human": "Estresse Aliviado" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png" + }, + "hitFloor": { + "android": "Você atinge foco e clareza perfeitos.", + "human": "Você atinge uma paz de espírito completa." + }, + "pastFloor": { + "android": "Você já está tão focado quanto possível.", + "human": "Você já está tão calmo quanto possível." + } + }, + "calm": { + "increase": { + "android": "Você faz um reset suave, purgando processos em segundo plano desnecessários.", + "human": "Você sente uma sensação de calma invadir você." + }, + "increaseHeader": { + "android": "Calma Ganha", + "human": "Calma Ganha" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/relieve_stress.png" + }, + "hitCeiling": { + "android": "Você atinge foco e clareza perfeitos.", + "human": "Você atinge uma paz de espírito completa." + }, + "pastCeiling": { + "android": "Você já está tão focado quanto possível.", + "human": "Você já está tão calmo quanto possível." + }, + "decrease": { + "android": "Uma sobrecarga de energia percorre seu núcleo e você começa a superaquecer.", + "human": "Você sente um aperto no peito e começa a suar." + }, + "decreaseHeader": { + "android": "Calma Perdida", + "human": "Calma Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png", + "human": "systems/sla-mothership/images/icons/ui/macros/gain_stress.png" + }, + "hitFloor": { + "android": "O desempenho do sistema chega a um ponto de falha.", + "human": "Você atinge o fundo do poço." + }, + "pastFloor": { + "android": "Você sente a perda de dados irreparável.", + "human": "Você sente uma parte de si mesmo se afastando." + } + }, + "health": { + "increase": { + "android": "Os recursos do sistema se estabilizam e você se sente energizado.", + "human": "Você sente uma explosão de energia." + }, + "increaseHeader": { + "android": "Vida Ganha", + "human": "Vida Ganha" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitCeiling": { + "android": "Você agora está com a vida cheia.", + "human": "Você agora está com a vida cheia." + }, + "pastCeiling": { + "android": "Você já está com a vida cheia.", + "human": "Você já está com a vida cheia." + }, + "decrease": { + "android": "Seus receptores de dor indicam danos no núcleo.", + "human": "Você estremece de dor." + }, + "decreaseHeader": { + "android": "Vida Perdida", + "human": "Vida Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitFloor": { + "android": "Seus receptores de dor indicam danos no núcleo.", + "human": "Seus receptores de dor indicam danos no núcleo." + }, + "pastFloor": { + "android": "Seus receptores de dor indicam danos no núcleo.", + "human": "Seus receptores de dor indicam danos no núcleo." + } + }, + "hits": { + "increase": { + "android": "@UUID[Compendium.mosh.macros_hotbar_1e.ZzKgfEmRdvDfyBMS]{Faça um Teste de Ferimento}", + "human": "@UUID[Compendium.mosh.macros_hotbar_1e.ZzKgfEmRdvDfyBMS]{Faça um Teste de Ferimento}" + }, + "increaseHeader": { + "android": "Dano", + "human": "Ferido" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitCeiling": { + "android": "O fim está próximo...

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Faça uma Salvaguarda de Morte}", + "human": "O fim está próximo...

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Faça uma Salvaguarda de Morte}" + }, + "pastCeiling": { + "android": "O fim está próximo...

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Faça uma Salvaguarda de Morte}", + "human": "O fim está próximo...

@UUID[Compendium.mosh.macros_hotbar_1e.NsRHfRuuNGPfkYVf]{Faça uma Salvaguarda de Morte}" + }, + "decrease": { + "android": "Os recursos do sistema se estabilizam e você se sente energizado.", + "human": "Você sente uma explosão de energia." + }, + "decreaseHeader": { + "android": "Reparado", + "human": "Curado" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/health.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/health.png" + }, + "hitFloor": { + "android": "Agora você está com a saúde plena.", + "human": "Agora você está com a saúde plena." + }, + "pastFloor": { + "android": "Você já está com a saúde plena.", + "human": "Você já está com a saúde plena." + } + }, + "strength": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Força Aumentada", + "human": "Força Ganha" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/strength.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/strength.png" + }, + "hitCeiling": { + "android": "Agora você está com força máxima.", + "human": "Agora você está com força máxima." + }, + "pastCeiling": { + "android": "Você já está com força máxima.", + "human": "Você já está com força máxima." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Força Prejudicada", + "human": "Força Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/strength.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/strength.png" + }, + "hitFloor": { + "android": "Você não tem mais força.", + "human": "Você não tem mais força." + }, + "pastFloor": { + "android": "Sua força não pode ficar mais baixa.", + "human": "Sua força não pode ficar mais baixa." + } + }, + "speed": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Velocidade Aumentada", + "human": "Velocidade Ganha" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/speed.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/speed.png" + }, + "hitCeiling": { + "android": "Agora você está com velocidade máxima.", + "human": "Agora você está com velocidade máxima." + }, + "pastCeiling": { + "android": "Você já está com velocidade máxima.", + "human": "Você já está com velocidade máxima." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Velocidade Prejudicada", + "human": "Velocidade Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/speed.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/speed.png" + }, + "hitFloor": { + "android": "Você se sente completamente letárgico.", + "human": "Você se sente completamente letárgico." + }, + "pastFloor": { + "android": "Sua velocidade não pode ficar mais baixa.", + "human": "Sua velocidade não pode ficar mais baixa." + } + }, + "intellect": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Intelecto Aumentado", + "human": "Intelecto Ganha" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/intellect.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/intellect.png" + }, + "hitCeiling": { + "android": "Agora você está com intelecto máximo.", + "human": "Agora você está com intelecto máximo." + }, + "pastCeiling": { + "android": "Você já está com intelecto máximo.", + "human": "Você já está com intelecto máximo." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Intelecto Prejudicado", + "human": "Intelecto Perdido" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/intellect.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/intellect.png" + }, + "hitFloor": { + "android": "Você se sente totalmente confuso.", + "human": "Você se sente totalmente confuso." + }, + "pastFloor": { + "android": "Seu intelecto não pode ficar mais baixo.", + "human": "Seu intelecto não pode ficar mais baixo." + } + }, + "combat": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Combate Aumentado", + "human": "Combate Ganhado" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/combat.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/combat.png" + }, + "hitCeiling": { + "android": "Agora você está no combate máximo.", + "human": "Agora você está no combate máximo." + }, + "pastCeiling": { + "android": "Você já está no combate máximo.", + "human": "Você já está no combate máximo." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Combate Prejudicado", + "human": "Combate Perdido" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/combat.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/combat.png" + }, + "hitFloor": { + "android": "Você não consegue mais imaginar lutar.", + "human": "Você não consegue mais imaginar lutar." + }, + "pastFloor": { + "android": "Seu combate não pode ficar mais baixo.", + "human": "Seu combate não pode ficar mais baixo." + } + }, + "instinct": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Instinto Aumentado", + "human": "Instinto Ganhado" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/instinct.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/instinct.png" + }, + "hitCeiling": { + "android": "Agora você está com instinto máximo.", + "human": "Agora você está com instinto máximo." + }, + "pastCeiling": { + "android": "Você já está com instinto máximo.", + "human": "Você já está com instinto máximo." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Instinto Prejudicado", + "human": "Instinto Perdido" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/instinct.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/instinct.png" + }, + "hitFloor": { + "android": "Você perdeu seus instintos.", + "human": "Você perdeu seus instintos." + }, + "pastFloor": { + "android": "Seu instinto não pode ficar mais baixo.", + "human": "Seu instinto não pode ficar mais baixo." + } + }, + "loyalty": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Lealdade Aumentada", + "human": "Lealdade Ganhada" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png" + }, + "hitCeiling": { + "android": "Agora você está com lealdade máxima.", + "human": "Agora você está com lealdade máxima." + }, + "pastCeiling": { + "android": "Você já está com lealdade máxima.", + "human": "Você já está com lealdade máxima." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Lealdade Prejudicada", + "human": "Lealdade Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/loyalty.png" + }, + "hitFloor": { + "android": "Você só se importa consigo mesmo.", + "human": "Você só se importa consigo mesmo." + }, + "pastFloor": { + "android": "Sua lealdade não pode ficar mais baixa.", + "human": "Sua lealdade não pode ficar mais baixa." + } + }, + "sanity": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Sanidade Aumentada", + "human": "Sanidade Aumentada" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/sanity.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/sanity.png" + }, + "hitCeiling": { + "android": "Agora você está com sanidade máxima.", + "human": "Agora você está com sanidade máxima." + }, + "pastCeiling": { + "android": "Você já está com sanidade máxima.", + "human": "Você já está com sanidade máxima." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Sanidade Prejudicada", + "human": "Sanidade Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/sanity.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/sanity.png" + }, + "hitFloor": { + "android": "Você perdeu a sanidade.", + "human": "Você perdeu a sanidade." + }, + "pastFloor": { + "android": "Sua sanidade não pode ficar mais baixa.", + "human": "Sua sanidade não pode ficar mais baixa." + } + }, + "fear": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Coragem Aumentada", + "human": "Coragem Melhorada" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/fear.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/fear.png" + }, + "hitCeiling": { + "android": "Agora você está com medo máximo.", + "human": "Agora você está com medo máximo." + }, + "pastCeiling": { + "android": "Você já está com medo máximo.", + "human": "Você já está com medo máximo." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Coragem Prejudicada", + "human": "Coragem Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/fear.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/fear.png" + }, + "hitFloor": { + "android": "Você tem medo de tudo.", + "human": "Você tem medo de tudo." + }, + "pastFloor": { + "android": "Seu medo não pode ficar mais baixo.", + "human": "Seu medo não pode ficar mais baixo." + } + }, + "body": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Corpo Aumentado", + "human": "Corpo Fortalecido" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/body.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/body.png" + }, + "hitCeiling": { + "android": "Agora você está com corpo máximo.", + "human": "Agora você está com corpo máximo." + }, + "pastCeiling": { + "android": "Você já está com corpo máximo.", + "human": "Você já está com corpo máximo." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Corpo Prejudicado", + "human": "Corpo Enfraquecido" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/body.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/body.png" + }, + "hitFloor": { + "android": "Seu corpo está fraco e frágil.", + "human": "Seu corpo está fraco e frágil." + }, + "pastFloor": { + "android": "Seu corpo não pode ficar mais baixo.", + "human": "Seu corpo não pode ficar mais baixo." + } + }, + "armor": { + "check": { + "android": "Você ganha um pouco de confiança em suas habilidades.", + "human": "Você ganha um pouco de confiança em suas habilidades." + }, + "increase": { + "android": "Dados recuperados. Partição central de dados restaurada.", + "human": "Você começa a se sentir como antes." + }, + "increaseHeader": { + "android": "Armadura Aumentada", + "human": "Armadura Ganha" + }, + "increaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/armor.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/armor.png" + }, + "hitCeiling": { + "android": "Agora você está com armadura máxima.", + "human": "Agora você está com armadura máxima." + }, + "pastCeiling": { + "android": "Você já está com armadura máxima.", + "human": "Você já está com armadura máxima." + }, + "decrease": { + "android": "Dano na partição central detectado. Setores irrecuperáveis encontrados.", + "human": "Você sente uma parte de si mesmo se afastando." + }, + "decreaseHeader": { + "android": "Armadura Prejudicada", + "human": "Armadura Perdida" + }, + "decreaseImg": { + "android": "systems/sla-mothership/images/icons/ui/attributes/armor.png", + "human": "systems/sla-mothership/images/icons/ui/attributes/armor.png" + }, + "hitFloor": { + "android": "Nada mais te protege agora.", + "human": "Nada mais te protege agora." + }, + "pastFloor": { + "android": "Sua armadura não pode ficar mais baixa.", + "human": "Sua armadura não pode ficar mais baixa." + } + }, + "thrusters": { + "check": { + "human": "Você manobra a nave com sucesso através do perigo." + }, + "increase": { + "human": "Propulsores atualizados. Agilidade, aceleração e velocidade máxima melhoraram." + }, + "increaseHeader": { + "human": "Propulsores Aumentados" + }, + "increaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/thrusters.png" + }, + "hitCeiling": { + "human": "Seus propulsores estão no máximo." + }, + "pastCeiling": { + "human": "Seus propulsores já estão no máximo e não podem ser melhorados mais." + }, + "decrease": { + "human": "Propulsores danificados. Agilidade, aceleração e velocidade máxima estão prejudicadas." + }, + "decreaseHeader": { + "human": "Propulsores Prejudicados" + }, + "decreaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/thrusters.png" + }, + "hitFloor": { + "human": "Você perdeu seus propulsores." + }, + "pastFloor": { + "human": "Seus propulsores estão quebrados e não podem ser danificados mais." + } + }, + "battle": { + "check": { + "human": "Você acerta um golpe bem-sucedido no alvo." + }, + "increase": { + "human": "Sistemas de mira atualizados. Prontidão para combate melhorada." + }, + "increaseHeader": { + "human": "Combate Aumentado" + }, + "increaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitCeiling": { + "human": "Seus sistemas de mira estão no máximo." + }, + "pastCeiling": { + "human": "Seus sistemas de mira já estão no máximo e não podem ser melhorados mais." + }, + "decrease": { + "human": "Sistemas de mira danificados. Prontidão para combate prejudicada." + }, + "decreaseHeader": { + "human": "Combate Prejudicado" + }, + "decreaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitFloor": { + "human": "Você perdeu seus sistemas de mira." + }, + "pastFloor": { + "human": "Seus sistemas de mira estão quebrados e não podem ser danificados mais." + } + }, + "systems": { + "check": { + "human": "Os sistemas da sua nave estão funcionando perfeitamente." + }, + "increase": { + "human": "Sistemas atualizados. Sensores, computadores e outros sistemas melhoraram." + }, + "increaseHeader": { + "human": "Sistemas Aumentados" + }, + "increaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitCeiling": { + "human": "Seus sistemas da sua nave estão no máximo." + }, + "pastCeiling": { + "human": "Os sistemas da sua nave já estão no máximo e não podem ser melhorados mais." + }, + "decrease": { + "human": "Sistemas danificados. Sensores, computadores e outros sistemas estão prejudicados." + }, + "decreaseHeader": { + "human": "Sistemas Prejudicados" + }, + "decreaseImg": { + "human": "systems/sla-mothership/images/icons/ui/attributes/battle.png" + }, + "hitFloor": { + "human": "Você perdeu os sistemas da sua nave." + }, + "pastFloor": { + "human": "Os sistemas da sua nave estão quebrados e não podem ser danificados mais." + } + } + }, + "macro": { + "wound": { + "bleeding": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.1DD8i6eCS6nx2Ip0]{Sangramento}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.1DD8i6eCS6nx2Ip0]{Sangramento}" + }, + "bleeding_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.xr2o2PU5vdrR6fxQ]{Sangramento [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.xr2o2PU5vdrR6fxQ]{Sangramento [-]}" + }, + "bleeding_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.tFcWNddtZvlv7tsg]{Sangramento [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.tFcWNddtZvlv7tsg]{Sangramento [+]}" + }, + "blunt_force": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.TAjlQjA5AAy3qYL3]{Força Contundente}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.TAjlQjA5AAy3qYL3]{Força Contundente}" + }, + "blunt_force_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.k0zf8ZGivRguc0wb]{Força Contundente [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.k0zf8ZGivRguc0wb]{Força Contundente [-]}" + }, + "blunt_force_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.oL3GH0HoEPlP8vzG]{Força Contundente [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.oL3GH0HoEPlP8vzG]{Força Contundente [+]}" + }, + "fire_explosives": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.bZi1qKmcKLFvnhZ2]{Fogo & Explosivos}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.bZi1qKmcKLFvnhZ2]{Fogo & Explosivos}" + }, + "fire_explosives_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.7rYhbDAaFeok1Daq]{Fogo & Explosivos [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.7rYhbDAaFeok1Daq]{Fogo & Explosivos [-]}" + }, + "fire_explosives_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.dJnQKDf0AlwK27QD]{Fogo & Explosivos [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.dJnQKDf0AlwK27QD]{Fogo & Explosivos [+]}" + }, + "gore_massive": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.S9nnHKWYGSQmjQdp]{Carniça}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.S9nnHKWYGSQmjQdp]{Carniça}" + }, + "gore_massive_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.eQPuDgwv8evetFIk]{Carniça [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.eQPuDgwv8evetFIk]{Carniça [-]}" + }, + "gore_massive_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.DuVjNlE4lsnR7Emc]{Carniça [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.DuVjNlE4lsnR7Emc]{Carniça [+]}" + }, + "gunshot": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.XgCOLv9UunBddUyW]{Disparo de Arma}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.XgCOLv9UunBddUyW]{Disparo de Arma}" + }, + "gunshot_dis": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.LTpa1ZYVZl4m9k6z]{Disparo de Arma [-]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.LTpa1ZYVZl4m9k6z]{Disparo de Arma [-]}" + }, + "gunshot_adv": { + "android": "@UUID[Compendium.mosh.macros_triggered_1e.fnVATRHYJEUlS3pR]{Disparo de Arma [+]}", + "human": "@UUID[Compendium.mosh.macros_triggered_1e.fnVATRHYJEUlS3pR]{Disparo de Arma [+]}" + } + } + }, + "CharacterGenerator": { + "name": "Gerador de Personagem", + "CommonSkills": "Habilidades Comuns", + "CommonSkillExplanation": "Esta é uma lista de habilidades usuais para esta classe, usadas para a geração aleatória de personagens.", + "StatOption": "Atributos & Salvaguardas", + "StatOptionPopupTitle": "Opção de Atributos e Salvaguardas da Classe", + "StatOptionPopupText": "Escolha onde aplicar o bônus de:", + "SkillOption.Classerror": "Você precisa selecionar uma classe primeiro.", + "SkillOption.PopupTitle": "Escolha suas habilidades", + "SkillOption.PopupTrainedDescription": "Escolha 1 habilidade Treinada", + "SkillOption.PopupExpertDescription": "Escolha 1 habilidade Expert", + "SkillOption.PopupMasterDescription": "Escolha 1 habilidade Mestre", + "SkillOption.PopupFullMasterName": "Conjunto Mestre", + "SkillOption.PopupFullMasterDescription": "Escolha 1 habilidade Mestre, e um requisito de habilidade Expert e Treinada.", + "SkillOption.PopupFullExpertName": "Conjunto Expert", + "SkillOption.PopupFullExperDescription": "Escolha 1 habilidade Expert, e requisito de habilidade Treinada.", + "SkillOption.ChoiceWord": "Opção", + "SkillOption.ChoiceText": "Escolha 1 dessas opções de bônus de habilidade", + "Tables": "Tabelas", + "Table.Loadout": "Tabela de Equipamento", + "Table.Patch": "Tabela de Conserto", + "Table.Trinket": "Tabela de Bijuteria", + "Error.NoClass": "Você precisa selecionar uma classe primeiro." + }, + "Add": "Adicionar", + "AddOr": "Adicionar ou", + "AddOption": "Adicionar Opção", + "AddGroup": "Adicionar Grupo", + "AddASkill": "Adicionar uma Habilidade?", + "Advantage": "Vantagem", + "AllStatsAndSavesDecreasedBy": "Todos os atributos e salvaguardas diminuídos por", + "Ammo": "Munição", + "Ammunition": "Munição", + "AmmoType": "Tipo de Munição", + "AntiArmorAcronym": "AA", + "AntiArmor": "Anti-armadura", + "AP": "AP", + "Armor": "Armadura", + "ArmorName": "Nome da Armadura", + "ArmorPoints": "Pontos de Armadura", + "Background": "Antecedentes", + "Bankruptcy": "Falência", + "BankruptcyCheck": "Cheque de Falência", + "BankruptcySave": "Salvaguarda de Falência", + "Base": "Base", + "Battle": "Batalha", + "Bio": "Bio", + "Body": "Corpo", + "BodySave": "Salvaguarda do Corpo", + "Bonus": "Bônus", + "Calm": "Calmo", + "Cargo": "Carga", + "CarryingCapacity": "Capacidade de Carga", + "CLASS": "CLASSE", + "classNewStatOptionEmptyError": "Você deve selecionar pelo menos dois atributos ou salvaguardas", + "classNewSkillOptionSkillTip": "Salve primeiro.", + "Combat": "Combate", + "Condition": "Condição", + "Cost": "Custo", + "CreateCondition": "Criar Condição", + "CreateItem": "Criar Item", + "CreateSkill": "Criar Habilidade", + "CreateWeapon": "Criar Arma", + "CreatureSettings": "Configurações de Criatura", + "Credits": "Créditos", + "Crew": "Tripulação", + "CriticalDamage": "Dano Crítico", + "Cryopods": "Cápsulas de Criogenia", + "CryofreezeDamage": "Dano por Congelamento Criogênico", + "Current": "Atual", + "CurrentShots": "Disparos Atuais", + "CurrentWeight": "Peso Atual", + "Damage": "Dano", + "DeleteArmor": "Deletar Armadura", + "DeleteCondition": "Deletar Condição", + "DeleteItem": "Deletar Item", + "DeleteSkill": "Deletar Habilidade", + "DeleteWeapon": "Deletar Arma", + "DeleteGroup": "Deletar Grupo", + "DeleteOption": "Deletar Opção", + "Description": "Descrição", + "Disabled": "Desabilitado", + "Disadvantage": "Desvantagem", + "DistressSignal": "Sinal de Socorro", + "DoNotAddASkillToThisRoll": "Não adicione uma habilidade a esta rolagem.", + "DMGReduction": "Redução de Dano", + "DR": "DR", + "Fuel": "Combustível", + "Feature": "Característica", + "Features": "Características", + "EditArmor": "Editar Armadura", + "EditCondition": "Editar Condição", + "EditItem": "Editar Item", + "EditSkill": "Editar Habilidade", + "EditWeapon": "Editar Arma", + "Equipped": "Equipado", + "Emergency": "Emergência", + "Enabled": "Habilitado", + "EnemyShips": "Naves Inimigas", + "EscapePods": "Cápsulas de Fuga", + "Fear": "Medo", + "Finances": "Finanças", + "Health": "Saúde", + "HighScore": "Pontuação Máxima", + "Hits": "Acertos", + "HullPoints": "Pontos de Casco", + "Installed": "Instalado", + "Instinct": "Instinto", + "Intellect": "Intelecto", + "ItemName": "Nome do Item", + "Item": "Item", + "Items": "Itens", + "Level": "Nível", + "Loyalty": "Lealdade", + "Macros": "Macros", + "MaintenanceAndRepairs": "Manutenção & Reparos", + "MaintenanceCheck": "Verificação de Manutenção", + "Major": "Maior", + "Maximum": "Máximo", + "MaxShots": "Máx. Tiros", + "MaxO2": "Máx. O2", + "Megadamage": "Megadano", + "Minimum": "Mínimo", + "ModuleName": "Nome do Módulo", + "MoraleCheck": "Cheque de Moral", + "MoraleCheckDescription": "Após qualquer rodada de nave onde um inimigo sofra MDMG, ele deve fazer um Cheque de Moral. Para fazer um Cheque de Moral, role 1d10. Se o valor obtido for menor que o MDMG atual, eles podem enviar uma comunicação oferecendo um cessar-fogo e retomando as negociações.", + "NA": "N/D", + "Name": "Nome", + "Next": "Próximo", + "Normal": "Normal", + "Notes": "Notas", + "O2Remaining": "O2 Restante", + "OK": "OK", + "OpenDeckplan": "Abrir Plano de Deck", + "Other": "Outro", + "Oxygen": "Oxigênio", + "PanicCheck": "Cheque de Pânico", + "Pronouns": "Pronomes", + "Quantity": "Quantidade", + "RadiationDamage": "Dano por Radiação", + "Range": "Alcance", + "RANK": "Posto", + "Repairs": "Reparos", + "Resolve": "Resolução", + "Robotic": "Robótico", + "RollingForGeneric": "Rolando para {name}", + "RollingForPanicEffect": "Rolando para efeito de pânico...", + "RollingForMaintenanceIssue": "Rolando para problema de manutenção...", + "Sanity": "Sanidade", + "SaveBonus": "Bônus de Salvaguarda", + "Severity": "Severidade", + "ShipIdentifier": "Identificador da Nave", + "ShipWeaponBonus": "Bônus de Arma de Nave", + "Shots": "Disparos", + "ShotsPerFiring": "Disparos por Disparo", + "SkillBonus": "Bônus de Habilidade", + "SkillName": "Nome da Habilidade", + "SkillRank": "Classificação de Habilidade", + "SkillRankTrained": "Treinado", + "SkillRankExpert": "Especializado", + "SkillRankMaster": "Mestre", + "Skills": "Habilidades", + "SkillsFixed": "Habilidades Fixas", + "SkillsPrerequisite": "Habilidades Pré-requisito", + "SkillsOptionalAnd": "Habilidades Selecionadas", + "SkillsOptionalOr": "Habilidades Opcionais", + "SkillTraining": "Treinamento de Habilidade", + "SpecialAbilities": "Habilidades Especiais", + "Speed": "Velocidade", + "StatsAndSaves": "Atributos & Salvaguardas", + "Strength": "Força", + "Stress": "Estresse", + "StressResponse": "Resposta ao Estresse", + "Systems": "Sistemas", + "Thrusters": "Propulsores", + "Total": "Total", + "TraumaResponse": "Resposta ao Trauma", + "Transponder": "Transponder", + "Treatment": "Tratamento", + "Upgrades": "Upgrades", + "UsesAmmo": "Usa Munição", + "Value": "Valor", + "WarpCores": "Núcleos de Dobra", + "WeaponName": "Nome da Arma", + "Weapons": "Armas", + "Weight": "Peso", + "Wounds": "Ferimentos", + "WoundEffect": "Efeito de Ferimento", + "XP": "XP", + "YouRolled90OrHigher": "Você rolou 90 ou mais, o que é sempre considerado uma falha.", + "HEARTATTACKSHORTCIRCUITANDROIDS": "ATAQUE CARDÍACO / CURTO-CIRCUITO (ANDRÓIDES).", + "SHORTCIRCUIT": "CURTO-CIRCUITO.", + "HEARTATTACK": "ATAQUE CARDÍACO.", + "Relieve1Stressqbq694JMbXeZrHj": "Aliviar 1 Estresse.

@UUID[Compendium.macros_triggered_1e.qbq694JMbXeZrHjj]{-1 Estresse}", + "Gain1d10Calmk2TtLFOG9mGaWVx31d10Calm": "Ganhar 1d10 Calma.

@UUID[Compendium.macros_triggered_1e.k2TtLFOG9mGaWVx3]{+1d10 Calma}", + "SelectAStat": "Selecione um Atributo", + "ChooseTheStatForSkillCheck": "Escolha o Atributo que melhor se adequa à natureza desta Verificação de Habilidade. Você adicionará o bônus da habilidade ao valor do Atributo para esta rolagem", + "GivingYouAHigherNumber": "(lhe dando um número maior para rolar abaixo).", + "StrengthSkillExample": "Segurar escotilhas fechadas, carregar camaradas caídos, escalar, empurrar, pular.", + "SpeedSkillExample": "Sair da baia de carga antes que as portas de explosão se fechem, agir antes de alguém (ou algo) mais, correr.", + "IntellectSkillExample": "Lembrar seu treinamento e experiência sob pressão, pensar em problemas difíceis, inventar ou consertar coisas.", + "CombatSkillExample": "Lutar pela sua vida.", + "SelectYourRollType": "Selecione o tipo de rolagem", + "ChooseAStat": "Escolha um Atributo", + "SwarmWoundShort": "W*", + "IfYouHaveARelevantSkill": "Se você tiver uma Habilidade relevante para a tarefa, pode adicionar o bônus dessa Habilidade ao seu Atributo ou Salvaguarda antes de fazer a rolagem", + "HeavyCover": "Cobertura Pesada", + "Cover": "Cobertura", + "NoCover": "Sem Cobertura", + "LightCover": "Cobertura Leve", + "InsignificantCover": "Cobertura Insignificante", + "SelectYourCurrentCoverSituation": "Selecione sua situação de cobertura atual", + "TheEnvironmentCanProvideProtectionCalled": "O ambiente pode fornecer proteção chamada", + "IfYouShotWhileInCover": "Se você disparar enquanto estiver em cobertura, será considerado fora de cobertura até o seu próximo turno.", + "ItCanBeDestroyedLikeArmor": "Pode ser destruído, assim como a armadura, sempre que receber dano maior ou igual ao seu AP. A cobertura normalmente protege apenas contra ataques à distância, mas em algumas situações pode ajudar a bloquear um ataque corpo a corpo.", + "YourCoverValuesAreDisplayedIn": "Os valores da sua cobertura são exibidos em", + "Orange": "laranja", + "UnprotectedOutInTheOpen": "Desprotegido, ao ar livre, etc.", + "WoodFurnitureDoorsShields": "Móveis/portas de madeira, escudos corporais, etc.", + "TreesBulkheadWallMetalFurniture": "Árvores, paredes de anteparo, móveis metálicos, etc.", + "AirlockDoorsCementBeamsShips": "Portas de escotilha, vigas de cimento, naves, etc.", + "DistressSignalTableExplanation": "Ocasionalmente, pode ser necessário colocar sua nave em energia de emergência, selar-se em cryopods, enviar um Sinal de Socorro e esperar por ajuda. É uma aposta arriscada, mas às vezes é a única chance que você tem. Quando isso acontecer, role nesta tabela.", + "MaintenanceCheckExplanation1": "Eventualmente, sua nave precisará de uma manutenção ou, às vezes, de uma revisão completa. Quando isso acontecer, será necessário realizar o reparo.", + "MinorRepairs": "Reparos Menores", + "MayorRepairs": "Reparos Maiores", + "MinorRepairsExplanation": "Cobrem danos cosméticos, limpeza e outros trabalhos de manutenção que podem ser feitos em voo, geralmente dentro de 2d10 dias.", + "MayorRepairsExplanation": "Cobrem danos estruturais ou sistêmicos em grande escala, incluindo reparos em Megadano e Casco, e só podem ser feitos no porto.", + "BankrupcyCheckExplanation": "Uma pequena minoria das naves é de propriedade de pequenas empresas bancárias que compartilham a posse com os operadores, financiando todos os custos da nave e ficando com a maior parte dos lucros. Em troca, você recebe uma nave e uma liberdade relativa para conduzir seus negócios na Fronteira. A cada ano", + "OrQuarterAsDeterminedBWarden": "ou trimestre, conforme determinado pelo seu Warden", + "MakeA": "faça um", + "BankrupcySaveExplanationEnd": "para determinar a saúde financeira da empresa", + "WeaponReloaded": "Arma recarregada", + "Reload": "Recarregar", + "OutOfAmmo": "Sem munição", + "OutOfAmmoNeedReload": "Sem munição, você precisa recarregar", + "WeaponIssue": "Problema com a arma", + "YouAddThisToYourInventory": "Você adiciona isso ao seu inventário.", + "YouLearnThisSkill": "Você aprende essa habilidade", + "YouAddAnotherOfThisToYourInventory": "Você adiciona mais um desses ao seu inventário.", + "HealthZeroMessage": "Sua saúde atingiu zero e você deve tomar um ferimento.", + "HealthZeroMessage2": "Sua saúde atingiu zero e você deve tomar um ferimento. Sua saúde foi redefinida para ", + "YouSenseTheWeightOfYourSetbacks": "Você sente o peso dos seus contratempos.", + "Bankrupcy": "Falência", + "BankrupcySave": "Salvaguarda de Falência", + "RestSave": "Salvaguarda de Descanso", + "Job": "Ocupação", + "Class": "Classe", + "Type": "Tipo", + "Owed": "Devida", + "Hull": "Casco", + "Modules": "módulos", + "DeckPlan": "Planta do Convés", + "Stock": "Stock", + "Errors":{ + "SkillAlreadyInList":"Essa habilidade já está na lista.", + "NoDropTarget":"Algo deu errado com o drop, tente novamente" + } + } +} diff --git a/lib/some-lib/some-lib.css b/lib/some-lib/some-lib.css new file mode 100644 index 0000000..e69de29 diff --git a/lib/some-lib/some-lib.min.js b/lib/some-lib/some-lib.min.js new file mode 100644 index 0000000..e69de29 diff --git a/module/actor/actor-sheet.js b/module/actor/actor-sheet.js new file mode 100644 index 0000000..8505c76 --- /dev/null +++ b/module/actor/actor-sheet.js @@ -0,0 +1,1399 @@ +import { SLAMothershipGenerator } from "../windows/sla-character-generator.js"; +import { SLADrugSystem } from "../sla-drug-system.js"; +import { buildSlaTraitRows, getSlaTraitOptionsByType, validateSlaTraitRows } from "../traits/sla-traits.js"; + +function isEbbSkillName(name = "") { + const clean = String(name ?? "").trim(); + return clean.startsWith("Ebb ") || ["Biofeedback", "Formulate", "Ebb (Core)"].includes(clean); +} + +function sortSkillCollection(skills = []) { + return [...skills].sort((left, right) => { + const leftCategory = String(left?.system?.sla?.category ?? "").trim().toLowerCase(); + const rightCategory = String(right?.system?.sla?.category ?? "").trim().toLowerCase(); + if (leftCategory !== rightCategory) return leftCategory.localeCompare(rightCategory); + return String(left?.name ?? "").localeCompare(String(right?.name ?? "")); + }); +} + +function dedupeSkillCollection(skills = []) { + const byName = new Map(); + for (const skill of skills) { + const key = String(skill?.name ?? "").trim().toLowerCase(); + if (!key) continue; + const current = byName.get(key); + const currentBonus = Number(current?.system?.bonus ?? 0) || 0; + const nextBonus = Number(skill?.system?.bonus ?? 0) || 0; + if (!current || nextBonus > currentBonus) { + byName.set(key, skill); + } + } + return Array.from(byName.values()); +} + +function normalizeTraitSkillKey(value = "") { + return String(value ?? "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, ""); +} + +function roundCarryWeight(value) { + return Math.round((Number(value ?? 0) || 0) * 10) / 10; +} + +function encToKg(enc) { + return roundCarryWeight((Number(enc ?? 0) || 0) * 1.5); +} + +function resolveItemWeight(itemDoc) { + const system = itemDoc?.system ?? {}; + const explicitWeight = Number(system.weight ?? 0); + const encValue = Number(system?.sla?.enc ?? 0); + if ((itemDoc?.type === "weapon" || itemDoc?.type === "armor") && encValue > 0) { + if (explicitWeight <= 0 || Math.abs(explicitWeight - encValue) < 0.001) { + return encToKg(encValue); + } + } + return roundCarryWeight(explicitWeight); +} + +function getCarryState(itemDoc) { + const system = itemDoc?.system ?? {}; + if (system.carryState) return String(system.carryState); + if (itemDoc?.type === "armor" && system.equipped) return "equipped"; + return "carried"; +} + +function buildCarryStateMeta(itemDoc) { + const state = getCarryState(itemDoc); + return { + state, + label: state === "equipped" ? "Equipped" : state === "stowed" ? "Stowed" : "Carried", + cssClass: state === "equipped" ? "equipped" : state === "stowed" ? "stowed" : "carried", + countsWeight: state !== "stowed" + }; +} + +function calculateCarryCapacity(actorSystem = {}) { + const strength = Math.max(0, Number(actorSystem?.stats?.strength?.value ?? 0) || 0); + const body = Math.max(0, Number(actorSystem?.stats?.body?.value ?? 0) || 0); + return roundCarryWeight(Math.max(10, (strength * 0.6) + (body * 0.4))); +} + +function buildTraitSkillPreview(traitRows = [], skillName = "") { + const key = normalizeTraitSkillKey(skillName); + const communicationSkills = new Set(["command", "fasttalk", "intimidate", "persuade", "streetwise"]); + const effects = []; + let flatMod = 0; + + const add = (amount, label) => { + const value = Number(amount ?? 0) || 0; + if (!value) return; + flatMod += value; + effects.push(`${label}: ${value >= 0 ? "+" : ""}${value}%`); + }; + + for (const row of traitRows) { + const rank = Math.max(1, Number(row?.slaTrait?.rank ?? 1) || 1); + switch (String(row?.slaTrait?.key ?? "")) { + case "good-hearing": + if (key === "listen") add(10 * rank, row.name); + break; + case "poor-hearing": + if (key === "listen") add(-10 * rank, row.name); + break; + case "good-vision": + if (key === "spothidden") add(10 * rank, row.name); + break; + case "poor-vision": + if (key === "spothidden") add(-10 * rank, row.name); + break; + case "attractive": + if (communicationSkills.has(key)) add(10 * rank, row.name); + break; + case "unattractive": + if (communicationSkills.has(key)) add(-10 * rank, row.name); + break; + case "depression": + if (communicationSkills.has(key)) add(-10 * rank, row.name); + break; + default: + break; + } + } + + return { + flatMod, + effects, + summary: effects.join(" | "), + modLabel: flatMod ? `${flatMod > 0 ? "+" : ""}${flatMod}` : "" + }; +} + +function decorateSkillWithTraitPreview(skill, traitRows = []) { + skill.system ??= {}; + const baseBonus = Number(skill.system.bonus ?? 0) || 0; + const preview = buildTraitSkillPreview(traitRows, skill.name); + skill.system.displayBonus = baseBonus + preview.flatMod; + skill.system.traitMod = preview.flatMod; + skill.system.traitEffects = preview.effects; + skill.slaTraitPreview = preview; + return skill; +} + +const SLA_SPECIES_RULES = { + Human: [ + { key: "adaptable", label: "Adaptable", summary: "Once per session, reroll one Stat check and take the better result.", optional: false, default: true } + ], + Frother: [ + { key: "berserkState", label: "Berserk State", summary: "On a failed Sanity Save, the Frother may enter Berserk instead of gaining Stress: +10 to Combat and Strength checks, but risks attacking the nearest target.", optional: true, default: true }, + { key: "drugMetabolism", label: "Drug Metabolism", summary: "No addiction roll for standard combat drugs, and one combat drug per scene can be taken without a Body Save penalty.", optional: true, default: true } + ], + Ebon: [ + { key: "ebbSensitivity", label: "Ebb Sensitivity", summary: "Automatically senses nearby Ebb use and rolls Sanity Saves at Disadvantage against reality-warping events.", optional: false, default: true }, + { key: "fluxPool", label: "Flux Pool", summary: "Flux begins at Intellect / 4 with a minimum reserve of 20, and recovers at 1 point per hour of rest.", optional: false, default: true } + ], + "Brain Waster": [ + { key: "ebbAggression", label: "Ebb Aggression", summary: "Damaging Ebb abilities add +1d5 damage.", optional: false, default: true }, + { key: "unnervingPresence", label: "Unnerving Presence", summary: "Nearby allies roll Fear Saves at Disadvantage when the Brain Waster channels Ebb.", optional: true, default: true } + ], + "Wraith Raider": [ + { key: "predatorSenses", label: "Predator Senses", summary: "Advantage on Speed-based perception, ambush detection, and initiative checks. Never surprised in natural or urban environments unless by supernatural means.", optional: false, default: true }, + { key: "naturalWeapons", label: "Natural Weapons", summary: "Claws deal Strength / 10 + 1d5 damage at Adjacent range and count as primary species weapons.", optional: false, default: true } + ], + Shaktar: [ + { key: "honourBound", label: "Honour Bound", summary: "Breaking a code of honour forces a Sanity Save or the Shaktar gains 1d3 Stress.", optional: true, default: true }, + { key: "naturalWeapons", label: "Natural Weapons", summary: "Claws deal Strength / 10 damage and grappling or restraining Strength checks gain Advantage.", optional: false, default: true } + ], + "Stormer 313 Malice": [ + { key: "prometheusRegeneration", label: "Prometheus Regeneration", summary: "At the end of every fourth combat round, recover 1d5 Health. Once wounds are healed, continue recovering 1 Health per round.", optional: true, default: true }, + { key: "biogeneticAggression", label: "Biogenetic Aggression", summary: "Disadvantage on Intellect checks involving diplomacy, deception detection, or abstract reasoning.", optional: false, default: true }, + { key: "financeChipMandatory", label: "Finance Chip Mandatory", summary: "The Karma finance chip is built in and cannot be removed.", optional: false, default: true } + ], + "Stormer 711 Xeno": [ + { key: "chameleonChitin", label: "Chameleon Chitin", summary: "Spend 1 action to become near-invisible while stationary. Detection is at Disadvantage until the Xeno moves.", optional: true, default: true }, + { key: "prometheusRegeneration", label: "Prometheus Regeneration", summary: "At the end of every fourth combat round, recover 1d5 Health.", optional: true, default: true }, + { key: "inhumanAppearance", label: "Inhuman Appearance", summary: "Social Intellect checks against other species are at Disadvantage because the Xeno is deeply unnerving.", optional: true, default: true } + ], + "Advanced Carrien": [ + { key: "socialPrejudice", label: "Social Prejudice", summary: "Track district or sponsor prejudice penalties until a source-grounded Carrien conversion replaces this draft entry.", optional: true, default: true } + ] +}; + +/** + * Extend the basic ActorSheet with some very simple modifications + * @extends {ActorSheet} + */ +export class MothershipActorSheet extends foundry.appv1.sheets.ActorSheet { + + constructor(...args) { + super(...args); + this._slaTraitPickerSelection ??= { + advantage: "", + disadvantage: "" + }; + } + + /** @override */ + static get defaultOptions() { + var options = { + classes: ["mosh", "sheet", "actor", "character"], + template: "systems/sla-mothership/templates/actor/actor-sheet.html", + width: 820, + height: 820, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "skills" }], + submitOnChange: true + } + return foundry.utils.mergeObject(super.defaultOptions, options); + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + const data = await super.getData(); + + data.dtypes = ["String", "Number", "Boolean"]; + + const superData = data.data.system; + + for (let attr of Object.values(data.data.system.attributes)) { + attr.isCheckbox = attr.dtype === "Boolean"; + } + + // Prepare items. + if (this.actor.type == 'character') { + this._prepareCharacterItems(data); + } + + + if (data.data.system.settings == null) { + data.data.system.settings = {}; + } + data.data.system.settings.useCalm = game.settings.get("sla-mothership", "useCalm"); + data.data.system.settings.hideWeight = game.settings.get("sla-mothership", "hideWeight"); + data.data.system.settings.firstEdition = game.settings.get("sla-mothership", "firstEdition"); + data.data.system.settings.androidPanic = game.settings.get("sla-mothership", "androidPanic"); + + superData.sla ??= {}; + superData.sla.operativeType ??= { value: "" }; + superData.sla.species ??= { value: "" }; + superData.sla.speciesNotes ??= { value: "" }; + superData.sla.trainingPackage ??= { value: "" }; + superData.sla.packageSummary ??= { value: "" }; + superData.sla.packageSkills ??= { value: "" }; + superData.sla.packageWealth ??= { value: "" }; + superData.sla.flux ??= { value: 0, min: 0, max: 0, label: "Flux" }; + superData.sla.fluxStage ??= { value: "" }; + superData.sla.bpn ??= { value: "" }; + superData.sla.scl ??= { value: "" }; + superData.sla.employer ??= { value: "" }; + superData.sla.sector ??= { value: "" }; + superData.sla.height ??= { value: "" }; + superData.sla.weightText ??= { value: "" }; + superData.sla.lad ??= false; + superData.sla.ebbRating ??= { value: 0 }; + superData.sla.ammoSpendTotal ??= { value: 0 }; + superData.sla.ammoLedger ??= { value: "" }; + superData.sla.fluxNotes ??= { value: "" }; + superData.sla.ebbNotes ??= { value: "" }; + superData.sla.speciesRules ??= {}; + const activeTheme = this.actor.getFlag("sla-mothership", "sheetTheme") || "modern"; + data.slaSheetTheme = activeTheme; + data.data.slaSheetTheme = activeTheme; + + data.data.enriched = []; + data.data.enriched.notes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(superData.notes, {async: true}); + data.data.enriched.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(superData.biography, {async: true}); + data.data.isEbbUser = this.actor.isSlaEbbUser?.() ?? false; + data.data.slaFlux = this.actor.getSlaFluxState?.() ?? { label: "Stable", description: "", cssClass: "stable", thresholds: "25% / 50% / 75% / 100%" }; + data.data.slaFluxGuidance = this.actor.getSlaFluxGuidance?.() ?? []; + const fluxValue = Number(superData.sla.flux?.value ?? 0); + const fluxMax = Math.max(0, Number(superData.sla.flux?.max ?? 0)); + data.data.slaFluxPercent = fluxMax > 0 ? Math.min(100, Math.max(0, Math.round((fluxValue / fluxMax) * 100))) : 0; + data.data.slaSpeciesTraitList = String(superData.sla.speciesNotes?.value ?? "").split(/\n+/).map((entry) => entry.trim()).filter(Boolean); + data.data.slaPackageSkillList = String(superData.sla.packageSkills?.value ?? "").split(/\s*,\s*/).map((entry) => entry.trim()).filter(Boolean); + data.data.slaSpeciesRules = getSpeciesRules(String(superData.sla.species?.value ?? "").trim(), superData.sla.speciesRules); + data.data.slaEnabledSpeciesRules = data.data.slaSpeciesRules.filter((rule) => rule.enabled); + data.data.slaEnabledSpeciesRuleCount = data.data.slaEnabledSpeciesRules.length; + data.data.slaPositiveTraitOptions = getSlaTraitOptionsByType("advantage"); + data.data.slaNegativeTraitOptions = getSlaTraitOptionsByType("disadvantage"); + data.data.slaTraitPickerSelection = { + advantage: String(this._slaTraitPickerSelection?.advantage ?? "").trim(), + disadvantage: String(this._slaTraitPickerSelection?.disadvantage ?? "").trim() + }; + data.data.slaPrometheusStatus = this.actor.getSlaPrometheusStatus?.() ?? { enabled: false, inCombat: false, currentRound: 0, roundsUntilPulse: null, pulseThisRound: false }; + const traitRows = buildSlaTraitRows(data.data.persTraits ?? []); + data.data.persTraitsEnhanced = traitRows; + data.data.traitCount = traitRows.length; + data.data.traitValidation = validateSlaTraitRows(traitRows); + data.data.skills = sortSkillCollection(dedupeSkillCollection((data.data.skills ?? []).map((skill) => { + const breakdown = this.actor.getSkillBreakdown?.(skill) ?? {}; + skill.system ??= {}; + skill.system.sla ??= {}; + skill.system.sla.category ||= breakdown.category ?? ""; + skill.slaBreakdown = breakdown; + skill.isEbbSkill = isEbbSkillName(skill.name); + skill.isCombatSkill = Boolean(skill.system.sla.combat); + return decorateSkillWithTraitPreview(skill, traitRows); + }))); + data.data.ebbSkills = sortSkillCollection(dedupeSkillCollection((data.data.ebbSkills ?? []).map((skill) => { + const breakdown = this.actor.getSkillBreakdown?.(skill) ?? {}; + skill.system ??= {}; + skill.system.sla ??= {}; + skill.system.sla.category ||= breakdown.category ?? ""; + skill.slaBreakdown = breakdown; + skill.isEbbSkill = true; + skill.isCombatSkill = Boolean(skill.system.sla.combat); + return decorateSkillWithTraitPreview(skill, traitRows); + }))); + const drugOverview = await SLADrugSystem.getActorOverview(this.actor); + data.data.drugAlerts = drugOverview.alerts; + data.data.drugRows = (drugOverview.rows ?? []).map((row) => { + const sourceItem = this.actor.items.get(row.itemId); + const carryMeta = sourceItem ? buildCarryStateMeta(sourceItem) : { state: "carried", label: "Carried", cssClass: "carried", countsWeight: true }; + const totalWeight = sourceItem + ? roundCarryWeight(resolveItemWeight(sourceItem) * Math.max(1, Number(sourceItem.system?.quantity ?? row.quantity ?? 1) || 1)) + : 0; + return { + ...row, + slaCarry: { + ...carryMeta, + totalWeight + } + }; + }); + data.data.slaStatModifierTitles = SLADrugSystem.getStatModifierTitles(this.actor); + const ammoItems = Array.from(this.actor.items ?? []).filter((item) => + item.type === "item" && String(item.system?.sla?.category ?? "").trim().toLowerCase() === "ammunition" + ); + data.data.slaAmmoInventory = { + stackCount: ammoItems.length, + roundCount: ammoItems.reduce((total, item) => total + (Number(item.system?.quantity ?? 0) || 0), 0) + }; + data.data.slaCarry = { + capacity: roundCarryWeight(Number(superData.weight?.capacity ?? 0) || 0), + current: roundCarryWeight(Number(superData.weight?.current ?? 0) || 0), + equipped: roundCarryWeight(Number(superData.weight?.equipped ?? 0) || 0), + carried: roundCarryWeight(Number(superData.weight?.carried ?? 0) || 0), + stowed: roundCarryWeight(Number(superData.weight?.stowed ?? 0) || 0), + available: roundCarryWeight(Number(superData.weight?.available ?? 0) || 0), + over: Boolean(superData.weight?.over), + state: String(superData.weight?.state ?? "Nominal") + }; + + + //SKILL XP BUTTONS + superData.xp.html = ''; + if (superData.xp.html == '') { + for (let i = 1; i <= 15; i++) { + if (i > superData.xp.value) { + if (i % 5) { + superData.xp.html += '
'; + } + else { //If a special one + let trainLevel = '
Trained
'; + if (i == 10) trainLevel = '
Expert
'; + else if (i == 15) trainLevel = '
Master
'; + superData.xp.html += '
' + trainLevel + '
'; + } + } + else { + if (i % 5) { + superData.xp.html += '
'; + } + else { //If a special one + let trainLevel = '
Trained
'; + if (i == 10) trainLevel = '
Expert
'; + else if (i == 15) trainLevel = '
Master
'; + superData.xp.html += '
' + trainLevel + '
'; + } + + } + } + } + //END SKILL XP + + return data.data; + } + + /** + * Organize and classify Items for Character sheets. + * + * @param {Object} actorData The actor to prepare. + * + * @return {undefined} + */ + _prepareCharacterItems(sheetData) { + const actorData = sheetData.data; + //console.log(sheetData); + ///console.log("sheetdata Above"); + // Initialize containers. + const gear = []; + const drugs = []; + const skills = []; + const ebbSkills = []; + const weapons = []; + const armors = []; + const conditions = []; + const abilities = []; + const persTraits = []; + + let curWeight = 0; + let equippedWeight = 0; + let carriedWeight = 0; + let stowedWeight = 0; + // Iterate through items, allocating to containers + // let totalWeight = 0; + for (let i of sheetData.items) { + let item = i.system; + i.img = i.img || DEFAULT_TOKEN; + const resolvedWeight = resolveItemWeight(i); + const carryMeta = buildCarryStateMeta(i); + const quantity = Math.max(1, Number(item.quantity ?? 1) || 1); + item.weightResolved = resolvedWeight; + item.carryState ??= carryMeta.state; + i.slaCarry = { + ...carryMeta, + weight: resolvedWeight, + totalWeight: roundCarryWeight(resolvedWeight * quantity) + }; + if (carryMeta.state === "equipped") equippedWeight += i.slaCarry.totalWeight; + else if (carryMeta.state === "stowed") stowedWeight += i.slaCarry.totalWeight; + else carriedWeight += i.slaCarry.totalWeight; + + if (i.type === 'item') { + gear.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'drug') { + drugs.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'skill') { + if (isEbbSkillName(i.name)) { + ebbSkills.push(i); + } else { + skills.push(i); + } + } else if (i.type === 'armor') { + armors.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'weapon') { + //We need to update this from the old system. + item.ranges ??= { short: 0, medium: 0, long: 0, value: "" }; + if (item.ranges.value == "" && item.ranges.medium > 0) { + item.ranges.value = item.ranges.short + "/" + item.ranges.medium + "/" + item.ranges.long; + item.ranges.medium = 0; + } + item.sla ??= {}; + if (item.useAmmo) { + item.ammoTag ??= "STD"; + item.ammoLoadedType ??= item.ammoTag ?? "STD"; + item.ammoCalibre ??= item.ammoType ?? ""; + item.ammoReserveStd ??= Math.max(0, Number(item.ammo ?? 0) || 0); + item.ammoReserveAp ??= 0; + item.ammoReserveHe ??= 0; + item.ammoReserveHeap ??= 0; + item.ammoReserve = getAmmoReserveTotal(item); + item.sla.fireModes ??= deriveWeaponFireModes(item); + item.sla.currentFireMode ??= parseWeaponFireModes(item.sla.fireModes)[0]?.label ?? "Single"; + item.shotsPerFire = getActiveFireMode(item)?.shots ?? Math.max(Number(item.shotsPerFire ?? 1) || 1, 1); + const ammoInventory = summarizeWeaponAmmoInventory(this.actor, item); + item.sla.ammoChoices = ammoInventory.choices; + item.sla.ammoReserve = ammoInventory.total; + item.sla.loadedAmmoLabel = item.ammoLoadedType ?? "STD"; + item.sla.loadedAmmoReserve = ammoInventory.byTag[item.ammoLoadedType ?? "STD"] ?? ammoInventory.total; + item.sla.loadedAmmoSummary = `${item.sla.loadedAmmoLabel} | ${item.sla.loadedAmmoReserve} carried`; + item.sla.calibreLabel = item.ammoCalibre || item.ammoType || "Unknown calibre"; + const currentShots = Math.max(0, Number(item.curShots ?? 0) || 0); + const maxShots = Math.max(0, Number(item.shots ?? 0) || 0); + if (currentShots <= 0) { + item.sla.ammoState = "Empty"; + item.sla.ammoStateClass = "empty"; + } else if (maxShots && currentShots <= Math.ceil(maxShots / 3)) { + item.sla.ammoState = "Low"; + item.sla.ammoStateClass = "low"; + } else { + item.sla.ammoState = "Ready"; + item.sla.ammoStateClass = "ready"; + } + item.sla.reserveSummary = `${currentShots}/${maxShots} loaded | ${item.sla.loadedAmmoReserve} spare`; + } + + weapons.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'condition') { + // We'll handle the pip html here. + if (item.treatment == null) { + item.treatment = { + "value": 0, + "html": "" + }; + } + let pipHtml = ""; + for (let i = 0; i < 3; i++) { + if (i < item.treatment.value) { + pipHtml += ''; + } + else { + pipHtml += ''; + } + } + + item.treatment.html = pipHtml; + + conditions.push(i); + } else if (i.type === 'ability') { + abilities.push(i); + } else if (i.type === 'persTrait') { + persTraits.push(i); + } + } + + if (actorData.system.weight == undefined) { + actorData.system.weight = { + "current": 0, + "capacity": 0 + }; + } + if (actorData.system.credits == undefined) { + actorData.system.credits = { + "value": 0, + }; + } + + actorData.system.weight.capacity = calculateCarryCapacity(actorData.system); + actorData.system.weight.current = roundCarryWeight(curWeight); + actorData.system.weight.equipped = roundCarryWeight(equippedWeight); + actorData.system.weight.carried = roundCarryWeight(carriedWeight); + actorData.system.weight.stowed = roundCarryWeight(stowedWeight); + actorData.system.weight.available = roundCarryWeight(actorData.system.weight.capacity - actorData.system.weight.current); + actorData.system.weight.over = actorData.system.weight.current > actorData.system.weight.capacity; + actorData.system.weight.state = actorData.system.weight.over ? "Overloaded" : actorData.system.weight.current > actorData.system.weight.capacity * 0.8 ? "Near Limit" : "Nominal"; + //console.log("Current Weight: " + curWeight + " Capacity: " + actorData.data.weight.capacity); + + // Assign and return + actorData.gear = gear; + actorData.drugs = drugs; + actorData.skills = skills; + actorData.ebbSkills = ebbSkills; + actorData.armors = armors; + actorData.weapons = weapons; + actorData.conditions = conditions; + actorData.abilities = abilities; + actorData.persTraits = persTraits.sort((left, right) => String(left?.name ?? "").localeCompare(String(right?.name ?? ""))); + + } + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + this._applyThemeClasses(html); + + // Everything below here is only needed if the sheet is editable + if (!this.options.editable) return; + + html.on('mousedown', '.char-pip-button', ev => { + + const div = $(ev.currentTarget); + const targetName = div.data("key"); + + let amount = this.actor.system.xp.value; + let newAmount = amount; + let max = div.data("max"); + let min = div.data("min"); + + if (event.button == 0) { + if (amount < max) { + newAmount = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > min) { + newAmount = Number(amount) - 1; + } + } + + this.actor.update({'system.xp.value': newAmount}); + + }); + + html.on('mousedown', '.treatment-button', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + + let amount = item.system.treatment.value; + + if (event.button == 0) { + if (amount < 3) { + item.system.treatment.value = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.treatment.value = Number(amount) - 1; + } + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + + // Update Inventory Item + html.find('.item-equip').click(ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + item.system.equipped = !item.system.equipped; + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + html.find('.sla-carry-toggle').click(async (ev) => { + ev.preventDefault(); + const li = ev.currentTarget.closest(".item"); + const targetState = String(ev.currentTarget.dataset.state ?? "carried"); + const item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + const currentState = getCarryState(item); + const nextState = currentState === targetState ? "carried" : targetState; + item.system ??= {}; + item.system.carryState = nextState; + if (item.type === "armor") item.system.equipped = nextState === "equipped"; + await this.actor.updateEmbeddedDocuments('Item', [item]); + this.render(false); + }); + + // Add Inventory Item + html.find('.item-create').click(this._onItemCreate.bind(this)); + + // Update Inventory Item + html.find('.item-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + item.sheet.render({force: true}); + }); + + html.find('.drug-use').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.useSlaDrug(li.dataset.itemId); + }); + + html.find('.drug-close').click(ev => { + const itemButton = ev.currentTarget; + const li = itemButton.closest(".item"); + const itemId = String(itemButton?.dataset?.itemId ?? li?.dataset?.itemId ?? "").trim(); + const drugId = String(itemButton?.dataset?.drugId ?? li?.dataset?.drugId ?? "").trim(); + if (!itemId && !drugId) { + ui.notifications.warn("No active drug could be identified to close."); + return; + } + this.actor.closeSlaDrug(itemId, drugId); + }); + + //Quantity adjuster + html.on('mousedown', '.item-quantity', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + let amount = item.system.quantity; + + if (event.button == 0) { + item.system.quantity = Number(amount) + 1; + } else if (event.button == 2) { + item.system.quantity = Number(amount) - 1; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //Severity adjuster + html.on('mousedown', '.severity', ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + + let amount = item.system.severity; + + if (event.button == 0) { + item.system.severity = Number(amount) + 1; + } else if (event.button == 2 && amount > 0) { + item.system.severity = Number(amount) - 1; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Delete Inventory Item + html.find('.item-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")]); + li.slideUp(200, () => this.render(false)); + }); + + //SKILLS + // Add Inventory Item + html.find('.skill-create').click(this._onSkillCreate.bind(this)); + + // Update Inventory Item + html.find('.skill-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const skill = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + skill.sheet.render({force: true}); + }); + + html.find('.ability-create').click(this._onItemCreate.bind(this)); + + html.find('.ability-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const ability = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + ability.sheet.render({force: true}); + }); + + html.find('.ability-use').click(ev => { + ev.preventDefault(); + ev.stopPropagation(); + const li = ev.currentTarget.closest(".item"); + this.actor.useSlaAbility(li.dataset.itemId); + }); + + html.find('.ability-use-trigger').click(ev => { + ev.preventDefault(); + ev.stopPropagation(); + const li = ev.currentTarget.closest(".item"); + this.actor.useSlaAbility(li.dataset.itemId); + }); + + //Weapons + // Add Inventory Item + html.find('.weapon-create').click(this._onItemCreate.bind(this)); + + // Update Inventory Item + html.find('.weapon-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const weapon = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + weapon.sheet.render({force: true}); + }); + + // Rollable Attribute + html.find('.stat-roll').click(ev => { + const div = $(ev.currentTarget); + const statName = div.data("key"); + this.actor.rollCheck(null, 'low', statName, null, null, null); + }); + + // Rollable Skill + html.find('.skill-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + this.actor.rollCheck(null, null, null, item.name, item.system.bonus, null); + }); + + html.find('.sla-ebb-skill-roll').click(ev => { + const itemId = ev.currentTarget.dataset.itemId; + if (!itemId) return; + this.actor.rollSlaEbbSkill(itemId); + }); + + html.find('.sla-rule-toggle input[type="checkbox"]').on('change', async ev => { + ev.stopPropagation(); + const checkbox = ev.currentTarget; + await this.actor.update({ [checkbox.name]: checkbox.checked }); + this.render(false); + }); + + html.find('.sla-rule-toggle').on('click', async ev => { + const checkbox = ev.currentTarget.querySelector('input[type="checkbox"]'); + if (!checkbox || ev.target === checkbox) return; + ev.preventDefault(); + const nextValue = !checkbox.checked; + checkbox.checked = nextValue; + await this.actor.update({ [checkbox.name]: nextValue }); + this.render(false); + }); + + // Rollable Weapon + html.find('.weapon-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + this.actor.rollWeaponAttack(item); + }); + + // Rollable Damage + html.find('.dmg-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + this.actor.rollCheck(null, null, 'damage', null, null, item); + }); + + // Rollable Item/Anything with a description that we want to click on. + html.find('.description-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.printDescription(li.dataset.itemId, { + event: ev + }); + }); + + html.on('mousedown', '.weapon-ammo', ev => { + ev.preventDefault(); + if (ev.button !== 0) return; + const li = ev.currentTarget.closest(".item"); + this.actor.promptWeaponReload(li.dataset.itemId); + }); + + html.on('mousedown', '.weapon-shots', ev => { + ev.preventDefault(); + if (ev.button !== 0) return; + const li = ev.currentTarget.closest(".item"); + this.actor.promptWeaponReload(li.dataset.itemId); + }); + + //Reload Shots + html.on('mousedown', '.weapon-reload', ev => { + ev.preventDefault(); + if (ev.button !== 0) return; + const li = ev.currentTarget.closest(".item"); + this.actor.promptWeaponReload(li.dataset.itemId); + }); + + html.on('mousedown', '.weapon-fire-mode', ev => { + ev.preventDefault(); + const li = ev.currentTarget.closest(".item"); + const direction = ev.button === 2 ? -1 : 1; + this.actor.cycleWeaponFireMode(li.dataset.itemId, direction); + }); + html.on('contextmenu', '.weapon-fire-mode', ev => { + ev.preventDefault(); + }); + + //increase AP + html.on('mousedown', '.armor-ap', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.armorPoints; + if (event.button == 0) { + item.system.armorPoints = Number(amount) + 1; + } else if (event.button == 2) { + if (amount > 0) { + item.system.armorPoints = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //increase DR + html.on('mousedown', '.armor-dr', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.damageReduction; + if (event.button == 0) { + item.system.damageReduction = Number(amount) + 1; + } else if (event.button == 2) { + if (amount > 0) { + item.system.damageReduction = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //increase oxygen + html.on('mousedown', '.armor-oxy', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.oxygenCurrent; + if (event.button == 0) { + if (amount < item.system.oxygenMax) { + item.system.oxygenCurrent = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.oxygenCurrent = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Calm - Panic Check + html.find('.calm-roll').click(ev => { + this.actor.rollCheck(null, 'low', 'fear', null, null, null); + }); + + // Stress - Panic Check + html.find('.stress-roll').click(ev => { + this.actor.rollCheck(null, 'low', 'fear', null, null, null); + }); + + html.find('.sla-flux-save').click(ev => { + this.actor.triggerSlaFluxPanic({ source: 'Flux control check', panicOnFailure: false }); + }); + + html.find('.sla-flux-panic').click(ev => { + this.actor.triggerSlaFluxPanic({ source: 'Manual Flux panic check', panicOnFailure: true, forcePanic: true }); + }); + + html.find('.sla-panic-button').click(ev => { + this.actor.rollTable("panicCheck", null, null, null, null, null, null); + }); + + html.find('.sla-wound-button').click(ev => { + this.actor.chooseSlaWoundTable?.(); + }); + + html.find('.trait-validate').click(() => { + const traitRows = buildSlaTraitRows(this.actor.items.filter((item) => item.type === "persTrait")); + const report = validateSlaTraitRows(traitRows); + const balance = Number(report?.rankBalance?.net ?? 0); + if (report.ok) { + ui.notifications.info(`Trait validation OK. Balance ${balance >= 0 ? "+" : ""}${balance}.`); + } else { + ui.notifications.warn(`Trait validation issues: ${report.errors.join(" ")}`); + } + this.render(false); + }); + + const captureTraitSelection = (ev) => { + ev.preventDefault(); + ev.stopPropagation(); + ev.stopImmediatePropagation(); + const type = String(ev.currentTarget?.dataset?.type ?? "").trim().toLowerCase(); + if (!type) return; + const value = String(ev.currentTarget?.value ?? "").trim(); + this._slaTraitPickerSelection ??= {}; + this._slaTraitPickerSelection[type] = value; + const pickerRow = ev.currentTarget.closest('.sla-trait-picker-row'); + if (pickerRow?.dataset) { + pickerRow.dataset.selectedTrait = value; + } + const addButton = pickerRow?.querySelector?.(`.sla-trait-add[data-type="${type}"]`); + if (addButton?.dataset) { + addButton.dataset.selectedTrait = value; + } + }; + + html.find('.sla-trait-select').on('change input', captureTraitSelection); + + html.find('.sla-trait-add').click(async (ev) => { + ev.preventDefault(); + ev.stopPropagation(); + ev.stopImmediatePropagation(); + const type = String(ev.currentTarget.dataset.type ?? "").trim().toLowerCase(); + const pickerRow = ev.currentTarget.closest('.sla-trait-picker-row'); + const select = pickerRow?.querySelector(`.sla-trait-select[data-type="${type}"]`) + ?? html.find(`.sla-trait-select[data-type="${type}"]`).get(0); + const selectedKey = String( + select?.value + ?? pickerRow?.dataset?.selectedTrait + ?? ev.currentTarget?.dataset?.selectedTrait + ?? this._slaTraitPickerSelection?.[type] + ?? "" + ).trim(); + if (!selectedKey) { + ui.notifications.warn(`Choose a ${type === "advantage" ? "positive" : "negative"} trait first.`); + return; + } + const options = type === "advantage" ? getSlaTraitOptionsByType("advantage") : getSlaTraitOptionsByType("disadvantage"); + const selected = options.find((entry) => entry.key === selectedKey); + if (!selected) return; + const existing = this.actor.items.find((item) => item.type === "persTrait" && String(item.name ?? "").trim().toLowerCase() === selected.label.toLowerCase()); + if (existing) { + ui.notifications.warn(`${selected.label} is already on this operative.`); + return; + } + await this.actor.createEmbeddedDocuments("Item", [{ + name: selected.label, + type: "persTrait", + img: type === "advantage" + ? "systems/sla-mothership/images/icons/ui/conditions/moral_compass.png" + : "systems/sla-mothership/images/icons/ui/conditions/anxiety.png", + system: { + base: 1, + xp: 0, + oppName: "", + basic: false, + improve: false, + oppimprove: false, + description: "", + gmDescription: "", + sla: { + traitType: type, + source: "SLA Trait Selector" + } + } + }]); + this._slaTraitPickerSelection ??= {}; + this._slaTraitPickerSelection[type] = ""; + if (pickerRow?.dataset) { + pickerRow.dataset.selectedTrait = ""; + } + if (ev.currentTarget?.dataset) { + ev.currentTarget.dataset.selectedTrait = ""; + } + if (select) select.value = ""; + }); + + html.find('.sla-health-reset').click(async (ev) => { + ev.preventDefault(); + const maxHealth = Math.max(0, Number(this.actor.system?.health?.max ?? 0) || 0); + await this.actor.update({ "system.health.value": maxHealth }); + ui.notifications.info(`Health reset to ${maxHealth}.`); + this.render(false); + }); + + html.find('.weapon-reload-all').click(async (ev) => { + ev.preventDefault(); + await this.actor.reloadAllCompatibleWeapons?.(); + this.render(false); + }); + + // Clicking on Armor + html.find('.armor-roll').click(ev => { + //roll panic check + this.actor.chooseCover(); + }); + + // Drag events for macros. + if (this.actor.isOwner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } + + } + + /* -------------------------------------------- */ + + /** + * Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onItemCreate(event) { + + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + + // Initialize a default name. + const name = type === "persTrait" ? "New Trait" : `New ${type.capitalize()}`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + data: data + }; + + // Remove the type from the dataset since it's in the itemData.type prop. + delete itemData.data["type"]; + + // Finally, create the item! + return this.actor.createEmbeddedDocuments("Item", [itemData]); + } + + /** + * Handle creating a new Owned skill for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onSkillCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + //const data = duplicate(header.dataset); + // Initialize a default name. + const name = `New Skill`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + system: data + }; + + let d = new foundry.applications.api.DialogV2({ + window: {title: `New Skill`}, + classes: ["macro-popup-dialog"], + content: ` +
+
+

Name

+
+ +
+
+
+

Rank

+
+ +
+ `, + buttons: [ + { + icon: 'fas fa-check', + action: "create", + label: "Create", + callback: (event, button, dialog) => { + var rank = button.form.querySelector('[id=\"rank\"]')?.value; + if (rank == "Trained") + itemData.system.bonus = 10; + if (rank == "Expert") + itemData.system.bonus = 15; + if (rank == "Master") + itemData.system.bonus = 20; + + itemData.system.rank = rank; + itemData.name = button.form.querySelector('[id=\"name\"]')?.value + this.actor.createEmbeddedDocuments("Item", [itemData]); + } + }, + { + icon: 'fas fa-times', + action: "cancel", + label: "Cancel", + callback: () => { } + } + ], + default: "roll", + close: () => { } + }); + d.render({force: true}); + + // Finally, create the item! + return; + } + + + /** + * Handle clickable rolls. + * @param {Event} event The originating click event + * @private + */ + _onRoll(event) { + event.preventDefault(); + const element = event.currentTarget; + const dataset = element.dataset; + + if (dataset.roll) { + let roll = new Roll(dataset.roll, this.actor.system); + let label = dataset.label ? `Rolling ${dataset.label} to score under ${dataset.target}` : ''; + roll.roll().toMessage({ + speaker: ChatMessage.getSpeaker({ actor: this.actor }), + flavor: label + }); + } + } + + async _updateObject(event, formData) { + const actor = this.object; + + var updateData; + updateData = foundry.utils.expandObject(formData); + + await actor.update(updateData, { + diff: false + }); + } + + /** + * Extend and override the sheet header buttons + * @override + */ + _getHeaderButtons() { + let buttons = super._getHeaderButtons(); + const canConfigure = game.user.isGM || this.actor.isOwner; + if (this.options.editable && canConfigure) { + buttons = [{ + label: "Theme", + class: 'sheet-theme-toggle', + icon: 'fas fa-palette', + onclick: (ev) => this._onToggleTheme(ev), + }, { + label: "Generator", + class: 'configure-actor', + icon: 'fas fa-cogs', + onclick: (ev) => this._onConfigureCreature(ev), + },].concat(buttons); + } + return buttons; + } + async _onToggleTheme(event) { + event.preventDefault(); + const currentTheme = (await this.actor.getFlag("sla-mothership", "sheetTheme")) || "modern"; + const nextTheme = currentTheme === "legacy" ? "modern" : "legacy"; + await this.actor.setFlag("sla-mothership", "sheetTheme", nextTheme); + this._setThemeClassState(nextTheme); + ui.notifications.info(`Character sheet theme: ${nextTheme === "legacy" ? "Legacy" : "Modern SLA"}`); + await this.render(true); + this._setThemeClassState(nextTheme); + } + _setThemeClassState(theme) { + const root = this.element?.[0] ?? null; + if (!root) return; + root.dataset.slaTheme = theme; + root.classList.remove("sla-sheet-theme-legacy", "sla-sheet-theme-modern"); + root.classList.add(`sla-sheet-theme-${theme}`); + if (this.element?.removeClass) { + this.element.removeClass("sla-sheet-theme-legacy sla-sheet-theme-modern"); + this.element.addClass(`sla-sheet-theme-${theme}`); + } + const windowApp = root.closest(".window-app"); + const windowContent = root.closest(".window-content"); + const windowHeader = windowApp?.querySelector?.(".window-header") ?? null; + if (windowApp) { + windowApp.dataset.slaTheme = theme; + windowApp.classList.remove("sla-window-theme-legacy", "sla-window-theme-modern"); + windowApp.classList.add(`sla-window-theme-${theme}`); + } + if (windowContent) { + windowContent.dataset.slaTheme = theme; + windowContent.classList.remove("sla-window-theme-legacy", "sla-window-theme-modern"); + windowContent.classList.add(`sla-window-theme-${theme}`); + } + if (windowHeader) { + windowHeader.dataset.slaTheme = theme; + windowHeader.classList.remove("sla-window-theme-legacy", "sla-window-theme-modern"); + windowHeader.classList.add(`sla-window-theme-${theme}`); + } + } + _applyThemeClasses(html) { + const root = html?.get?.(0) ?? html?.[0] ?? null; + if (!root) return; + const theme = this.actor.getFlag("sla-mothership", "sheetTheme") || "modern"; + root.classList.remove("sla-sheet-theme-legacy", "sla-sheet-theme-modern"); + root.classList.add(`sla-sheet-theme-${theme}`); + this._setThemeClassState(theme); + } + _onConfigureCreature(event) { + event.preventDefault(); + new SLAMothershipGenerator(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } +} + +export class MothershipActorSheetDossier extends MothershipActorSheet { + static get defaultOptions() { + const base = super.defaultOptions; + const classes = Array.from(new Set([...(base.classes ?? []), "sla-dossier-sheet"])); + return foundry.utils.mergeObject(base, { + classes, + width: 980, + height: 920 + }); + } +} + +function parseWeaponFireModes(raw) { + const modes = []; + for (const chunk of String(raw ?? "").split(/[\n,]+/)) { + const entry = chunk.trim(); + if (!entry) continue; + const match = entry.match(/^(.+?)(?:\s*[:=|-]\s*|\s*\(\s*)(\d+)\)?$/); + if (!match) continue; + modes.push({ + label: match[1].trim(), + shots: Math.max(1, Number(match[2]) || 1) + }); + } + return modes; +} + +function deriveWeaponFireModes(system) { + const shotsPerFire = Math.max(1, Number(system?.shotsPerFire ?? 1) || 1); + const special = String(system?.sla?.special ?? "").toLowerCase(); + const modes = [{ label: "Single", shots: 1 }]; + + if (shotsPerFire > 1) { + if (special.includes("auto") && shotsPerFire > 3) { + modes.push({ label: "Burst", shots: 3 }, { label: "Auto", shots: shotsPerFire }); + } else if (special.includes("auto")) { + modes.push({ label: "Auto", shots: shotsPerFire }); + } else if (special.includes("burst")) { + modes.push({ label: "Burst", shots: shotsPerFire }); + } else if (shotsPerFire === 2) { + modes.push({ label: "Double", shots: 2 }); + } else { + modes.push({ label: "Burst", shots: shotsPerFire }); + } + } + + return modes + .filter((mode, index, list) => list.findIndex((entry) => entry.label === mode.label && entry.shots === mode.shots) === index) + .map((mode) => `${mode.label}:${mode.shots}`) + .join(", "); +} + +function getActiveFireMode(system) { + const modes = parseWeaponFireModes(system?.sla?.fireModes); + const currentMode = String(system?.sla?.currentFireMode ?? "").trim().toLowerCase(); + return modes.find((mode) => mode.label.toLowerCase() === currentMode) ?? modes[0] ?? { label: "Single", shots: 1 }; +} + +function getAmmoReserveKey(tag = "STD") { + const normalized = String(tag ?? "STD").trim().toUpperCase(); + if (normalized === "AP") return "ammoReserveAp"; + if (normalized === "HE") return "ammoReserveHe"; + if (normalized === "HEAP") return "ammoReserveHeap"; + return "ammoReserveStd"; +} + +function getAmmoReserveTotal(system = {}) { + return ["ammoReserveStd", "ammoReserveAp", "ammoReserveHe", "ammoReserveHeap"] + .reduce((total, key) => total + Math.max(0, Number(system?.[key] ?? 0) || 0), 0); +} + +function summarizeWeaponAmmoInventory(actor, weapon = {}) { + const calibre = String(weapon?.ammoCalibre ?? weapon?.ammoType ?? "").trim(); + const allowedTags = new Set( + [ + weapon?.ammoAllowStd !== false ? "STD" : null, + weapon?.ammoAllowAp !== false ? "AP" : null, + weapon?.ammoAllowHe !== false ? "HE" : null, + weapon?.ammoAllowHeap !== false ? "HEAP" : null + ].filter(Boolean) + ); + + const matchingItems = Array.from(actor?.items ?? []).filter((item) => { + if (item.type !== "item") return false; + if (String(item.system?.sla?.category ?? "").trim().toLowerCase() !== "ammunition") return false; + const itemCalibre = String(item.system?.sla?.calibre ?? "").trim(); + if (calibre && itemCalibre && itemCalibre !== calibre) return false; + const tag = String(item.system?.sla?.ammoTag ?? "STD").trim().toUpperCase(); + return allowedTags.has(tag); + }); + + if (!matchingItems.length) { + return { + total: getAmmoReserveTotal(weapon), + byTag: { + STD: Math.max(0, Number(weapon?.ammoReserveStd ?? weapon?.ammo ?? 0) || 0), + AP: Math.max(0, Number(weapon?.ammoReserveAp ?? 0) || 0), + HE: Math.max(0, Number(weapon?.ammoReserveHe ?? 0) || 0), + HEAP: Math.max(0, Number(weapon?.ammoReserveHeap ?? 0) || 0) + }, + choices: [] + }; + } + + const byTag = { STD: 0, AP: 0, HE: 0, HEAP: 0 }; + for (const item of matchingItems) { + const tag = String(item.system?.sla?.ammoTag ?? "STD").trim().toUpperCase(); + byTag[tag] = (byTag[tag] ?? 0) + Math.max(0, Number(item.system?.quantity ?? 0) || 0); + } + + return { + total: Object.values(byTag).reduce((sum, value) => sum + value, 0), + byTag, + choices: matchingItems + }; +} + +function getSpeciesRules(speciesName, store = {}) { + const rules = SLA_SPECIES_RULES[speciesName] ?? []; + return rules.map((rule) => { + store[rule.key] ??= { + enabled: rule.default, + label: rule.label, + summary: rule.summary, + optional: rule.optional + }; + return { + key: rule.key, + label: rule.label, + summary: rule.summary, + optional: rule.optional, + enabled: Boolean(store[rule.key]?.enabled), + path: `system.sla.speciesRules.${rule.key}.enabled` + }; + }); +} diff --git a/module/actor/actor-sheet.js.bak-traits b/module/actor/actor-sheet.js.bak-traits new file mode 100644 index 0000000..4e99b36 --- /dev/null +++ b/module/actor/actor-sheet.js.bak-traits @@ -0,0 +1,1340 @@ +import { SLAMothershipGenerator } from "../windows/sla-character-generator.js"; +import { SLADrugSystem } from "../sla-drug-system.js"; +import { buildSlaTraitRows, getSlaTraitOptionsByType, validateSlaTraitRows } from "../traits/sla-traits.js"; + +function isEbbSkillName(name = "") { + const clean = String(name ?? "").trim(); + return clean.startsWith("Ebb ") || ["Biofeedback", "Formulate", "Ebb (Core)"].includes(clean); +} + +function sortSkillCollection(skills = []) { + return [...skills].sort((left, right) => { + const leftCategory = String(left?.system?.sla?.category ?? "").trim().toLowerCase(); + const rightCategory = String(right?.system?.sla?.category ?? "").trim().toLowerCase(); + if (leftCategory !== rightCategory) return leftCategory.localeCompare(rightCategory); + return String(left?.name ?? "").localeCompare(String(right?.name ?? "")); + }); +} + +function dedupeSkillCollection(skills = []) { + const byName = new Map(); + for (const skill of skills) { + const key = String(skill?.name ?? "").trim().toLowerCase(); + if (!key) continue; + const current = byName.get(key); + const currentBonus = Number(current?.system?.bonus ?? 0) || 0; + const nextBonus = Number(skill?.system?.bonus ?? 0) || 0; + if (!current || nextBonus > currentBonus) { + byName.set(key, skill); + } + } + return Array.from(byName.values()); +} + +function normalizeTraitSkillKey(value = "") { + return String(value ?? "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, ""); +} + +function roundCarryWeight(value) { + return Math.round((Number(value ?? 0) || 0) * 10) / 10; +} + +function encToKg(enc) { + return roundCarryWeight((Number(enc ?? 0) || 0) * 1.5); +} + +function resolveItemWeight(itemDoc) { + const system = itemDoc?.system ?? {}; + const explicitWeight = Number(system.weight ?? 0); + const encValue = Number(system?.sla?.enc ?? 0); + if ((itemDoc?.type === "weapon" || itemDoc?.type === "armor") && encValue > 0) { + if (explicitWeight <= 0 || Math.abs(explicitWeight - encValue) < 0.001) { + return encToKg(encValue); + } + } + return roundCarryWeight(explicitWeight); +} + +function getCarryState(itemDoc) { + const system = itemDoc?.system ?? {}; + if (system.carryState) return String(system.carryState); + if (itemDoc?.type === "armor" && system.equipped) return "equipped"; + return "carried"; +} + +function buildCarryStateMeta(itemDoc) { + const state = getCarryState(itemDoc); + return { + state, + label: state === "equipped" ? "Equipped" : state === "stowed" ? "Stowed" : "Carried", + cssClass: state === "equipped" ? "equipped" : state === "stowed" ? "stowed" : "carried", + countsWeight: state !== "stowed" + }; +} + +function calculateCarryCapacity(actorSystem = {}) { + const strength = Math.max(0, Number(actorSystem?.stats?.strength?.value ?? 0) || 0); + const body = Math.max(0, Number(actorSystem?.stats?.body?.value ?? 0) || 0); + return roundCarryWeight(Math.max(10, (strength * 0.6) + (body * 0.4))); +} + +function buildTraitSkillPreview(traitRows = [], skillName = "") { + const key = normalizeTraitSkillKey(skillName); + const communicationSkills = new Set(["command", "fasttalk", "intimidate", "persuade", "streetwise"]); + const effects = []; + let flatMod = 0; + + const add = (amount, label) => { + const value = Number(amount ?? 0) || 0; + if (!value) return; + flatMod += value; + effects.push(`${label}: ${value >= 0 ? "+" : ""}${value}%`); + }; + + for (const row of traitRows) { + const rank = Math.max(1, Number(row?.slaTrait?.rank ?? 1) || 1); + switch (String(row?.slaTrait?.key ?? "")) { + case "good-hearing": + if (key === "listen") add(10 * rank, row.name); + break; + case "poor-hearing": + if (key === "listen") add(-10 * rank, row.name); + break; + case "good-vision": + if (key === "spothidden") add(10 * rank, row.name); + break; + case "poor-vision": + if (key === "spothidden") add(-10 * rank, row.name); + break; + case "attractive": + if (communicationSkills.has(key)) add(10 * rank, row.name); + break; + case "unattractive": + if (communicationSkills.has(key)) add(-10 * rank, row.name); + break; + case "depression": + if (communicationSkills.has(key)) add(-10 * rank, row.name); + break; + default: + break; + } + } + + return { + flatMod, + effects, + summary: effects.join(" | "), + modLabel: flatMod ? `${flatMod > 0 ? "+" : ""}${flatMod}` : "" + }; +} + +function decorateSkillWithTraitPreview(skill, traitRows = []) { + skill.system ??= {}; + const baseBonus = Number(skill.system.bonus ?? 0) || 0; + const preview = buildTraitSkillPreview(traitRows, skill.name); + skill.system.displayBonus = baseBonus + preview.flatMod; + skill.system.traitMod = preview.flatMod; + skill.system.traitEffects = preview.effects; + skill.slaTraitPreview = preview; + return skill; +} + +const SLA_SPECIES_RULES = { + Human: [ + { key: "adaptable", label: "Adaptable", summary: "Once per session, reroll one Stat check and take the better result.", optional: false, default: true } + ], + Frother: [ + { key: "berserkState", label: "Berserk State", summary: "On a failed Sanity Save, the Frother may enter Berserk instead of gaining Stress: +10 to Combat and Strength checks, but risks attacking the nearest target.", optional: true, default: true }, + { key: "drugMetabolism", label: "Drug Metabolism", summary: "No addiction roll for standard combat drugs, and one combat drug per scene can be taken without a Body Save penalty.", optional: true, default: true } + ], + Ebon: [ + { key: "ebbSensitivity", label: "Ebb Sensitivity", summary: "Automatically senses nearby Ebb use and rolls Sanity Saves at Disadvantage against reality-warping events.", optional: false, default: true }, + { key: "fluxPool", label: "Flux Pool", summary: "Flux begins at Intellect / 4 with a minimum reserve of 20, and recovers at 1 point per hour of rest.", optional: false, default: true } + ], + "Brain Waster": [ + { key: "ebbAggression", label: "Ebb Aggression", summary: "Damaging Ebb abilities add +1d5 damage.", optional: false, default: true }, + { key: "unnervingPresence", label: "Unnerving Presence", summary: "Nearby allies roll Fear Saves at Disadvantage when the Brain Waster channels Ebb.", optional: true, default: true } + ], + "Wraith Raider": [ + { key: "predatorSenses", label: "Predator Senses", summary: "Advantage on Speed-based perception, ambush detection, and initiative checks. Never surprised in natural or urban environments unless by supernatural means.", optional: false, default: true }, + { key: "naturalWeapons", label: "Natural Weapons", summary: "Claws deal Strength / 10 + 1d5 damage at Adjacent range and count as primary species weapons.", optional: false, default: true } + ], + Shaktar: [ + { key: "honourBound", label: "Honour Bound", summary: "Breaking a code of honour forces a Sanity Save or the Shaktar gains 1d3 Stress.", optional: true, default: true }, + { key: "naturalWeapons", label: "Natural Weapons", summary: "Claws deal Strength / 10 damage and grappling or restraining Strength checks gain Advantage.", optional: false, default: true } + ], + "Stormer 313 Malice": [ + { key: "prometheusRegeneration", label: "Prometheus Regeneration", summary: "At the end of every fourth combat round, recover 1d5 Health. Once wounds are healed, continue recovering 1 Health per round.", optional: true, default: true }, + { key: "biogeneticAggression", label: "Biogenetic Aggression", summary: "Disadvantage on Intellect checks involving diplomacy, deception detection, or abstract reasoning.", optional: false, default: true }, + { key: "financeChipMandatory", label: "Finance Chip Mandatory", summary: "The Karma finance chip is built in and cannot be removed.", optional: false, default: true } + ], + "Stormer 711 Xeno": [ + { key: "chameleonChitin", label: "Chameleon Chitin", summary: "Spend 1 action to become near-invisible while stationary. Detection is at Disadvantage until the Xeno moves.", optional: true, default: true }, + { key: "prometheusRegeneration", label: "Prometheus Regeneration", summary: "At the end of every fourth combat round, recover 1d5 Health.", optional: true, default: true }, + { key: "inhumanAppearance", label: "Inhuman Appearance", summary: "Social Intellect checks against other species are at Disadvantage because the Xeno is deeply unnerving.", optional: true, default: true } + ], + "Advanced Carrien": [ + { key: "socialPrejudice", label: "Social Prejudice", summary: "Track district or sponsor prejudice penalties until a source-grounded Carrien conversion replaces this draft entry.", optional: true, default: true } + ] +}; + +/** + * Extend the basic ActorSheet with some very simple modifications + * @extends {ActorSheet} + */ +export class MothershipActorSheet extends foundry.appv1.sheets.ActorSheet { + + /** @override */ + static get defaultOptions() { + var options = { + classes: ["mosh", "sheet", "actor", "character"], + template: "systems/sla-mothership/templates/actor/actor-sheet.html", + width: 820, + height: 820, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "skills" }], + submitOnChange: true + } + return foundry.utils.mergeObject(super.defaultOptions, options); + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + const data = await super.getData(); + + data.dtypes = ["String", "Number", "Boolean"]; + + const superData = data.data.system; + + for (let attr of Object.values(data.data.system.attributes)) { + attr.isCheckbox = attr.dtype === "Boolean"; + } + + // Prepare items. + if (this.actor.type == 'character') { + this._prepareCharacterItems(data); + } + + + if (data.data.system.settings == null) { + data.data.system.settings = {}; + } + data.data.system.settings.useCalm = game.settings.get("sla-mothership", "useCalm"); + data.data.system.settings.hideWeight = game.settings.get("sla-mothership", "hideWeight"); + data.data.system.settings.firstEdition = game.settings.get("sla-mothership", "firstEdition"); + data.data.system.settings.androidPanic = game.settings.get("sla-mothership", "androidPanic"); + + superData.sla ??= {}; + superData.sla.operativeType ??= { value: "" }; + superData.sla.species ??= { value: "" }; + superData.sla.speciesNotes ??= { value: "" }; + superData.sla.trainingPackage ??= { value: "" }; + superData.sla.packageSummary ??= { value: "" }; + superData.sla.packageSkills ??= { value: "" }; + superData.sla.packageWealth ??= { value: "" }; + superData.sla.flux ??= { value: 0, min: 0, max: 0, label: "Flux" }; + superData.sla.fluxStage ??= { value: "" }; + superData.sla.bpn ??= { value: "" }; + superData.sla.scl ??= { value: "" }; + superData.sla.employer ??= { value: "" }; + superData.sla.sector ??= { value: "" }; + superData.sla.height ??= { value: "" }; + superData.sla.weightText ??= { value: "" }; + superData.sla.ebbRating ??= { value: 0 }; + superData.sla.ammoSpendTotal ??= { value: 0 }; + superData.sla.ammoLedger ??= { value: "" }; + superData.sla.fluxNotes ??= { value: "" }; + superData.sla.ebbNotes ??= { value: "" }; + superData.sla.speciesRules ??= {}; + const activeTheme = this.actor.getFlag("sla-mothership", "sheetTheme") || "modern"; + data.slaSheetTheme = activeTheme; + data.data.slaSheetTheme = activeTheme; + + data.data.enriched = []; + data.data.enriched.notes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(superData.notes, {async: true}); + data.data.enriched.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(superData.biography, {async: true}); + data.data.isEbbUser = this.actor.isSlaEbbUser?.() ?? false; + data.data.slaFlux = this.actor.getSlaFluxState?.() ?? { label: "Stable", description: "", cssClass: "stable", thresholds: "25% / 50% / 75% / 100%" }; + data.data.slaFluxGuidance = this.actor.getSlaFluxGuidance?.() ?? []; + const fluxValue = Number(superData.sla.flux?.value ?? 0); + const fluxMax = Math.max(0, Number(superData.sla.flux?.max ?? 0)); + data.data.slaFluxPercent = fluxMax > 0 ? Math.min(100, Math.max(0, Math.round((fluxValue / fluxMax) * 100))) : 0; + data.data.slaSpeciesTraitList = String(superData.sla.speciesNotes?.value ?? "").split(/\n+/).map((entry) => entry.trim()).filter(Boolean); + data.data.slaPackageSkillList = String(superData.sla.packageSkills?.value ?? "").split(/\s*,\s*/).map((entry) => entry.trim()).filter(Boolean); + data.data.slaSpeciesRules = getSpeciesRules(String(superData.sla.species?.value ?? "").trim(), superData.sla.speciesRules); + data.data.slaEnabledSpeciesRules = data.data.slaSpeciesRules.filter((rule) => rule.enabled); + data.data.slaEnabledSpeciesRuleCount = data.data.slaEnabledSpeciesRules.length; + data.data.slaPositiveTraitOptions = getSlaTraitOptionsByType("advantage"); + data.data.slaNegativeTraitOptions = getSlaTraitOptionsByType("disadvantage"); + data.data.slaPrometheusStatus = this.actor.getSlaPrometheusStatus?.() ?? { enabled: false, inCombat: false, currentRound: 0, roundsUntilPulse: null, pulseThisRound: false }; + const traitRows = buildSlaTraitRows(data.data.persTraits ?? []); + data.data.persTraitsEnhanced = traitRows; + data.data.traitCount = traitRows.length; + data.data.traitValidation = validateSlaTraitRows(traitRows); + data.data.skills = sortSkillCollection(dedupeSkillCollection((data.data.skills ?? []).map((skill) => { + const breakdown = this.actor.getSkillBreakdown?.(skill) ?? {}; + skill.system ??= {}; + skill.system.sla ??= {}; + skill.system.sla.category ||= breakdown.category ?? ""; + skill.slaBreakdown = breakdown; + skill.isEbbSkill = isEbbSkillName(skill.name); + skill.isCombatSkill = Boolean(skill.system.sla.combat); + return decorateSkillWithTraitPreview(skill, traitRows); + }))); + data.data.ebbSkills = sortSkillCollection(dedupeSkillCollection((data.data.ebbSkills ?? []).map((skill) => { + const breakdown = this.actor.getSkillBreakdown?.(skill) ?? {}; + skill.system ??= {}; + skill.system.sla ??= {}; + skill.system.sla.category ||= breakdown.category ?? ""; + skill.slaBreakdown = breakdown; + skill.isEbbSkill = true; + skill.isCombatSkill = Boolean(skill.system.sla.combat); + return decorateSkillWithTraitPreview(skill, traitRows); + }))); + const drugOverview = await SLADrugSystem.getActorOverview(this.actor); + data.data.drugAlerts = drugOverview.alerts; + data.data.drugRows = (drugOverview.rows ?? []).map((row) => { + const sourceItem = this.actor.items.get(row.itemId); + const carryMeta = sourceItem ? buildCarryStateMeta(sourceItem) : { state: "carried", label: "Carried", cssClass: "carried", countsWeight: true }; + const totalWeight = sourceItem + ? roundCarryWeight(resolveItemWeight(sourceItem) * Math.max(1, Number(sourceItem.system?.quantity ?? row.quantity ?? 1) || 1)) + : 0; + return { + ...row, + slaCarry: { + ...carryMeta, + totalWeight + } + }; + }); + data.data.slaStatModifierTitles = SLADrugSystem.getStatModifierTitles(this.actor); + const ammoItems = Array.from(this.actor.items ?? []).filter((item) => + item.type === "item" && String(item.system?.sla?.category ?? "").trim().toLowerCase() === "ammunition" + ); + data.data.slaAmmoInventory = { + stackCount: ammoItems.length, + roundCount: ammoItems.reduce((total, item) => total + (Number(item.system?.quantity ?? 0) || 0), 0) + }; + data.data.slaCarry = { + capacity: roundCarryWeight(Number(superData.weight?.capacity ?? 0) || 0), + current: roundCarryWeight(Number(superData.weight?.current ?? 0) || 0), + equipped: roundCarryWeight(Number(superData.weight?.equipped ?? 0) || 0), + carried: roundCarryWeight(Number(superData.weight?.carried ?? 0) || 0), + stowed: roundCarryWeight(Number(superData.weight?.stowed ?? 0) || 0), + available: roundCarryWeight(Number(superData.weight?.available ?? 0) || 0), + over: Boolean(superData.weight?.over), + state: String(superData.weight?.state ?? "Nominal") + }; + + + //SKILL XP BUTTONS + superData.xp.html = ''; + if (superData.xp.html == '') { + for (let i = 1; i <= 15; i++) { + if (i > superData.xp.value) { + if (i % 5) { + superData.xp.html += '
'; + } + else { //If a special one + let trainLevel = '
Trained
'; + if (i == 10) trainLevel = '
Expert
'; + else if (i == 15) trainLevel = '
Master
'; + superData.xp.html += '
' + trainLevel + '
'; + } + } + else { + if (i % 5) { + superData.xp.html += '
'; + } + else { //If a special one + let trainLevel = '
Trained
'; + if (i == 10) trainLevel = '
Expert
'; + else if (i == 15) trainLevel = '
Master
'; + superData.xp.html += '
' + trainLevel + '
'; + } + + } + } + } + //END SKILL XP + + return data.data; + } + + /** + * Organize and classify Items for Character sheets. + * + * @param {Object} actorData The actor to prepare. + * + * @return {undefined} + */ + _prepareCharacterItems(sheetData) { + const actorData = sheetData.data; + //console.log(sheetData); + ///console.log("sheetdata Above"); + // Initialize containers. + const gear = []; + const drugs = []; + const skills = []; + const ebbSkills = []; + const weapons = []; + const armors = []; + const conditions = []; + const abilities = []; + const persTraits = []; + + let curWeight = 0; + let equippedWeight = 0; + let carriedWeight = 0; + let stowedWeight = 0; + // Iterate through items, allocating to containers + // let totalWeight = 0; + for (let i of sheetData.items) { + let item = i.system; + i.img = i.img || DEFAULT_TOKEN; + const resolvedWeight = resolveItemWeight(i); + const carryMeta = buildCarryStateMeta(i); + const quantity = Math.max(1, Number(item.quantity ?? 1) || 1); + item.weightResolved = resolvedWeight; + item.carryState ??= carryMeta.state; + i.slaCarry = { + ...carryMeta, + weight: resolvedWeight, + totalWeight: roundCarryWeight(resolvedWeight * quantity) + }; + if (carryMeta.state === "equipped") equippedWeight += i.slaCarry.totalWeight; + else if (carryMeta.state === "stowed") stowedWeight += i.slaCarry.totalWeight; + else carriedWeight += i.slaCarry.totalWeight; + + if (i.type === 'item') { + gear.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'drug') { + drugs.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'skill') { + if (isEbbSkillName(i.name)) { + ebbSkills.push(i); + } else { + skills.push(i); + } + } else if (i.type === 'armor') { + armors.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'weapon') { + //We need to update this from the old system. + item.ranges ??= { short: 0, medium: 0, long: 0, value: "" }; + if (item.ranges.value == "" && item.ranges.medium > 0) { + item.ranges.value = item.ranges.short + "/" + item.ranges.medium + "/" + item.ranges.long; + item.ranges.medium = 0; + } + item.sla ??= {}; + if (item.useAmmo) { + item.ammoTag ??= "STD"; + item.ammoLoadedType ??= item.ammoTag ?? "STD"; + item.ammoCalibre ??= item.ammoType ?? ""; + item.ammoReserveStd ??= Math.max(0, Number(item.ammo ?? 0) || 0); + item.ammoReserveAp ??= 0; + item.ammoReserveHe ??= 0; + item.ammoReserveHeap ??= 0; + item.ammoReserve = getAmmoReserveTotal(item); + item.sla.fireModes ??= deriveWeaponFireModes(item); + item.sla.currentFireMode ??= parseWeaponFireModes(item.sla.fireModes)[0]?.label ?? "Single"; + item.shotsPerFire = getActiveFireMode(item)?.shots ?? Math.max(Number(item.shotsPerFire ?? 1) || 1, 1); + const ammoInventory = summarizeWeaponAmmoInventory(this.actor, item); + item.sla.ammoChoices = ammoInventory.choices; + item.sla.ammoReserve = ammoInventory.total; + item.sla.loadedAmmoLabel = item.ammoLoadedType ?? "STD"; + item.sla.loadedAmmoReserve = ammoInventory.byTag[item.ammoLoadedType ?? "STD"] ?? ammoInventory.total; + item.sla.loadedAmmoSummary = `${item.sla.loadedAmmoLabel} | ${item.sla.loadedAmmoReserve} carried`; + item.sla.calibreLabel = item.ammoCalibre || item.ammoType || "Unknown calibre"; + const currentShots = Math.max(0, Number(item.curShots ?? 0) || 0); + const maxShots = Math.max(0, Number(item.shots ?? 0) || 0); + if (currentShots <= 0) { + item.sla.ammoState = "Empty"; + item.sla.ammoStateClass = "empty"; + } else if (maxShots && currentShots <= Math.ceil(maxShots / 3)) { + item.sla.ammoState = "Low"; + item.sla.ammoStateClass = "low"; + } else { + item.sla.ammoState = "Ready"; + item.sla.ammoStateClass = "ready"; + } + item.sla.reserveSummary = `${currentShots}/${maxShots} loaded | ${item.sla.loadedAmmoReserve} spare`; + } + + weapons.push(i); + if (carryMeta.countsWeight) curWeight += i.slaCarry.totalWeight; + } else if (i.type === 'condition') { + // We'll handle the pip html here. + if (item.treatment == null) { + item.treatment = { + "value": 0, + "html": "" + }; + } + let pipHtml = ""; + for (let i = 0; i < 3; i++) { + if (i < item.treatment.value) { + pipHtml += ''; + } + else { + pipHtml += ''; + } + } + + item.treatment.html = pipHtml; + + conditions.push(i); + } else if (i.type === 'ability') { + abilities.push(i); + } else if (i.type === 'persTrait') { + persTraits.push(i); + } + } + + if (actorData.system.weight == undefined) { + actorData.system.weight = { + "current": 0, + "capacity": 0 + }; + } + if (actorData.system.credits == undefined) { + actorData.system.credits = { + "value": 0, + }; + } + + actorData.system.weight.capacity = calculateCarryCapacity(actorData.system); + actorData.system.weight.current = roundCarryWeight(curWeight); + actorData.system.weight.equipped = roundCarryWeight(equippedWeight); + actorData.system.weight.carried = roundCarryWeight(carriedWeight); + actorData.system.weight.stowed = roundCarryWeight(stowedWeight); + actorData.system.weight.available = roundCarryWeight(actorData.system.weight.capacity - actorData.system.weight.current); + actorData.system.weight.over = actorData.system.weight.current > actorData.system.weight.capacity; + actorData.system.weight.state = actorData.system.weight.over ? "Overloaded" : actorData.system.weight.current > actorData.system.weight.capacity * 0.8 ? "Near Limit" : "Nominal"; + //console.log("Current Weight: " + curWeight + " Capacity: " + actorData.data.weight.capacity); + + // Assign and return + actorData.gear = gear; + actorData.drugs = drugs; + actorData.skills = skills; + actorData.ebbSkills = ebbSkills; + actorData.armors = armors; + actorData.weapons = weapons; + actorData.conditions = conditions; + actorData.abilities = abilities; + actorData.persTraits = persTraits.sort((left, right) => String(left?.name ?? "").localeCompare(String(right?.name ?? ""))); + + } + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + this._applyThemeClasses(html); + + // Everything below here is only needed if the sheet is editable + if (!this.options.editable) return; + + html.on('mousedown', '.char-pip-button', ev => { + + const div = $(ev.currentTarget); + const targetName = div.data("key"); + + let amount = this.actor.system.xp.value; + let newAmount = amount; + let max = div.data("max"); + let min = div.data("min"); + + if (event.button == 0) { + if (amount < max) { + newAmount = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > min) { + newAmount = Number(amount) - 1; + } + } + + this.actor.update({'system.xp.value': newAmount}); + + }); + + html.on('mousedown', '.treatment-button', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + + let amount = item.system.treatment.value; + + if (event.button == 0) { + if (amount < 3) { + item.system.treatment.value = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.treatment.value = Number(amount) - 1; + } + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + + // Update Inventory Item + html.find('.item-equip').click(ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + item.system.equipped = !item.system.equipped; + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + html.find('.sla-carry-toggle').click(async (ev) => { + ev.preventDefault(); + const li = ev.currentTarget.closest(".item"); + const targetState = String(ev.currentTarget.dataset.state ?? "carried"); + const item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + const currentState = getCarryState(item); + const nextState = currentState === targetState ? "carried" : targetState; + item.system ??= {}; + item.system.carryState = nextState; + if (item.type === "armor") item.system.equipped = nextState === "equipped"; + await this.actor.updateEmbeddedDocuments('Item', [item]); + this.render(false); + }); + + // Add Inventory Item + html.find('.item-create').click(this._onItemCreate.bind(this)); + + // Update Inventory Item + html.find('.item-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + item.sheet.render({force: true}); + }); + + html.find('.drug-use').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.useSlaDrug(li.dataset.itemId); + }); + + html.find('.drug-close').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.closeSlaDrug(li.dataset.itemId, li.dataset.drugId ?? ""); + }); + + //Quantity adjuster + html.on('mousedown', '.item-quantity', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + let amount = item.system.quantity; + + if (event.button == 0) { + item.system.quantity = Number(amount) + 1; + } else if (event.button == 2) { + item.system.quantity = Number(amount) - 1; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //Severity adjuster + html.on('mousedown', '.severity', ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + + let amount = item.system.severity; + + if (event.button == 0) { + item.system.severity = Number(amount) + 1; + } else if (event.button == 2 && amount > 0) { + item.system.severity = Number(amount) - 1; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Delete Inventory Item + html.find('.item-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")]); + li.slideUp(200, () => this.render(false)); + }); + + //SKILLS + // Add Inventory Item + html.find('.skill-create').click(this._onSkillCreate.bind(this)); + + // Update Inventory Item + html.find('.skill-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const skill = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + skill.sheet.render({force: true}); + }); + + html.find('.ability-create').click(this._onItemCreate.bind(this)); + + html.find('.ability-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const ability = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + ability.sheet.render({force: true}); + }); + + html.find('.ability-use').click(ev => { + ev.preventDefault(); + ev.stopPropagation(); + const li = ev.currentTarget.closest(".item"); + this.actor.useSlaAbility(li.dataset.itemId); + }); + + html.find('.ability-use-trigger').click(ev => { + ev.preventDefault(); + ev.stopPropagation(); + const li = ev.currentTarget.closest(".item"); + this.actor.useSlaAbility(li.dataset.itemId); + }); + + //Weapons + // Add Inventory Item + html.find('.weapon-create').click(this._onItemCreate.bind(this)); + + // Update Inventory Item + html.find('.weapon-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const weapon = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + weapon.sheet.render({force: true}); + }); + + // Rollable Attribute + html.find('.stat-roll').click(ev => { + const div = $(ev.currentTarget); + const statName = div.data("key"); + this.actor.rollCheck(null, 'low', statName, null, null, null); + }); + + // Rollable Skill + html.find('.skill-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + this.actor.rollCheck(null, null, null, item.name, item.system.bonus, null); + }); + + html.find('.sla-ebb-skill-roll').click(ev => { + const itemId = ev.currentTarget.dataset.itemId; + if (!itemId) return; + this.actor.rollSlaEbbSkill(itemId); + }); + + html.find('.sla-rule-toggle input[type="checkbox"]').on('change', async ev => { + ev.stopPropagation(); + const checkbox = ev.currentTarget; + await this.actor.update({ [checkbox.name]: checkbox.checked }); + this.render(false); + }); + + html.find('.sla-rule-toggle').on('click', async ev => { + const checkbox = ev.currentTarget.querySelector('input[type="checkbox"]'); + if (!checkbox || ev.target === checkbox) return; + ev.preventDefault(); + const nextValue = !checkbox.checked; + checkbox.checked = nextValue; + await this.actor.update({ [checkbox.name]: nextValue }); + this.render(false); + }); + + // Rollable Weapon + html.find('.weapon-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + this.actor.rollWeaponAttack(item); + }); + + // Rollable Damage + html.find('.dmg-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + this.actor.rollCheck(null, null, 'damage', null, null, item); + }); + + // Rollable Item/Anything with a description that we want to click on. + html.find('.description-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.printDescription(li.dataset.itemId, { + event: ev + }); + }); + + html.on('mousedown', '.weapon-ammo', ev => { + ev.preventDefault(); + if (ev.button !== 0) return; + const li = ev.currentTarget.closest(".item"); + this.actor.promptWeaponReload(li.dataset.itemId); + }); + + html.on('mousedown', '.weapon-shots', ev => { + ev.preventDefault(); + if (ev.button !== 0) return; + const li = ev.currentTarget.closest(".item"); + this.actor.promptWeaponReload(li.dataset.itemId); + }); + + //Reload Shots + html.on('mousedown', '.weapon-reload', ev => { + ev.preventDefault(); + if (ev.button !== 0) return; + const li = ev.currentTarget.closest(".item"); + this.actor.promptWeaponReload(li.dataset.itemId); + }); + + html.on('mousedown', '.weapon-fire-mode', ev => { + ev.preventDefault(); + const li = ev.currentTarget.closest(".item"); + const direction = ev.button === 2 ? -1 : 1; + this.actor.cycleWeaponFireMode(li.dataset.itemId, direction); + }); + html.on('contextmenu', '.weapon-fire-mode', ev => { + ev.preventDefault(); + }); + + //increase AP + html.on('mousedown', '.armor-ap', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.armorPoints; + if (event.button == 0) { + item.system.armorPoints = Number(amount) + 1; + } else if (event.button == 2) { + if (amount > 0) { + item.system.armorPoints = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //increase DR + html.on('mousedown', '.armor-dr', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.damageReduction; + if (event.button == 0) { + item.system.damageReduction = Number(amount) + 1; + } else if (event.button == 2) { + if (amount > 0) { + item.system.damageReduction = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //increase oxygen + html.on('mousedown', '.armor-oxy', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.oxygenCurrent; + if (event.button == 0) { + if (amount < item.system.oxygenMax) { + item.system.oxygenCurrent = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.oxygenCurrent = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Calm - Panic Check + html.find('.calm-roll').click(ev => { + this.actor.rollCheck(null, 'low', 'fear', null, null, null); + }); + + // Stress - Panic Check + html.find('.stress-roll').click(ev => { + this.actor.rollCheck(null, 'low', 'fear', null, null, null); + }); + + html.find('.sla-flux-save').click(ev => { + this.actor.triggerSlaFluxPanic({ source: 'Flux control check', panicOnFailure: false }); + }); + + html.find('.sla-flux-panic').click(ev => { + this.actor.triggerSlaFluxPanic({ source: 'Manual Flux panic check', panicOnFailure: true, forcePanic: true }); + }); + + html.find('.sla-panic-button').click(ev => { + this.actor.rollTable("panicCheck", null, null, null, null, null, null); + }); + + html.find('.sla-wound-button').click(ev => { + this.actor.chooseSlaWoundTable?.(); + }); + + html.find('.trait-validate').click(() => { + const traitRows = buildSlaTraitRows(this.actor.items.filter((item) => item.type === "persTrait")); + const report = validateSlaTraitRows(traitRows); + const balance = Number(report?.rankBalance?.net ?? 0); + if (report.ok) { + ui.notifications.info(`Trait validation OK. Balance ${balance >= 0 ? "+" : ""}${balance}.`); + } else { + ui.notifications.warn(`Trait validation issues: ${report.errors.join(" ")}`); + } + this.render(false); + }); + + html.find('.sla-trait-add').click(async (ev) => { + ev.preventDefault(); + const type = String(ev.currentTarget.dataset.type ?? "").trim().toLowerCase(); + const select = html.find(`.sla-trait-select[data-type="${type}"]`).get(0); + const selectedKey = String(select?.value ?? "").trim(); + if (!selectedKey) { + ui.notifications.warn(`Choose a ${type === "advantage" ? "positive" : "negative"} trait first.`); + return; + } + const options = type === "advantage" ? getSlaTraitOptionsByType("advantage") : getSlaTraitOptionsByType("disadvantage"); + const selected = options.find((entry) => entry.key === selectedKey); + if (!selected) return; + const existing = this.actor.items.find((item) => item.type === "persTrait" && String(item.name ?? "").trim().toLowerCase() === selected.label.toLowerCase()); + if (existing) { + ui.notifications.warn(`${selected.label} is already on this operative.`); + return; + } + await this.actor.createEmbeddedDocuments("Item", [{ + name: selected.label, + type: "persTrait", + img: type === "advantage" + ? "systems/sla-mothership/images/icons/ui/conditions/moral_compass.png" + : "systems/sla-mothership/images/icons/ui/conditions/anxiety.png", + system: { + base: 1, + xp: 0, + oppName: "", + basic: false, + improve: false, + oppimprove: false, + description: "", + gmDescription: "", + sla: { + traitType: type, + source: "SLA Trait Selector" + } + } + }]); + this.render(false); + }); + + html.find('.sla-health-reset').click(async (ev) => { + ev.preventDefault(); + const maxHealth = Math.max(0, Number(this.actor.system?.health?.max ?? 0) || 0); + await this.actor.update({ "system.health.value": maxHealth }); + ui.notifications.info(`Health reset to ${maxHealth}.`); + this.render(false); + }); + + html.find('.weapon-reload-all').click(async (ev) => { + ev.preventDefault(); + await this.actor.reloadAllCompatibleWeapons?.(); + this.render(false); + }); + + // Clicking on Armor + html.find('.armor-roll').click(ev => { + //roll panic check + this.actor.chooseCover(); + }); + + // Drag events for macros. + if (this.actor.isOwner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } + + } + + /* -------------------------------------------- */ + + /** + * Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onItemCreate(event) { + + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + + // Initialize a default name. + const name = type === "persTrait" ? "New Trait" : `New ${type.capitalize()}`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + data: data + }; + + // Remove the type from the dataset since it's in the itemData.type prop. + delete itemData.data["type"]; + + // Finally, create the item! + return this.actor.createEmbeddedDocuments("Item", [itemData]); + } + + /** + * Handle creating a new Owned skill for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onSkillCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + //const data = duplicate(header.dataset); + // Initialize a default name. + const name = `New Skill`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + system: data + }; + + let d = new foundry.applications.api.DialogV2({ + window: {title: `New Skill`}, + classes: ["macro-popup-dialog"], + content: ` +
+
+

Name

+
+ +
+
+
+

Rank

+
+ +
+ `, + buttons: [ + { + icon: 'fas fa-check', + action: "create", + label: "Create", + callback: (event, button, dialog) => { + var rank = button.form.querySelector('[id=\"rank\"]')?.value; + if (rank == "Trained") + itemData.system.bonus = 10; + if (rank == "Expert") + itemData.system.bonus = 15; + if (rank == "Master") + itemData.system.bonus = 20; + + itemData.system.rank = rank; + itemData.name = button.form.querySelector('[id=\"name\"]')?.value + this.actor.createEmbeddedDocuments("Item", [itemData]); + } + }, + { + icon: 'fas fa-times', + action: "cancel", + label: "Cancel", + callback: () => { } + } + ], + default: "roll", + close: () => { } + }); + d.render({force: true}); + + // Finally, create the item! + return; + } + + + /** + * Handle clickable rolls. + * @param {Event} event The originating click event + * @private + */ + _onRoll(event) { + event.preventDefault(); + const element = event.currentTarget; + const dataset = element.dataset; + + if (dataset.roll) { + let roll = new Roll(dataset.roll, this.actor.system); + let label = dataset.label ? `Rolling ${dataset.label} to score under ${dataset.target}` : ''; + roll.roll().toMessage({ + speaker: ChatMessage.getSpeaker({ actor: this.actor }), + flavor: label + }); + } + } + + async _updateObject(event, formData) { + const actor = this.object; + + var updateData; + updateData = foundry.utils.expandObject(formData); + + await actor.update(updateData, { + diff: false + }); + } + + /** + * Extend and override the sheet header buttons + * @override + */ + _getHeaderButtons() { + let buttons = super._getHeaderButtons(); + const canConfigure = game.user.isGM || this.actor.isOwner; + if (this.options.editable && canConfigure) { + buttons = [{ + label: "Theme", + class: 'sheet-theme-toggle', + icon: 'fas fa-palette', + onclick: (ev) => this._onToggleTheme(ev), + }, { + label: "Generator", + class: 'configure-actor', + icon: 'fas fa-cogs', + onclick: (ev) => this._onConfigureCreature(ev), + },].concat(buttons); + } + return buttons; + } + async _onToggleTheme(event) { + event.preventDefault(); + const currentTheme = (await this.actor.getFlag("sla-mothership", "sheetTheme")) || "modern"; + const nextTheme = currentTheme === "legacy" ? "modern" : "legacy"; + await this.actor.setFlag("sla-mothership", "sheetTheme", nextTheme); + this._setThemeClassState(nextTheme); + ui.notifications.info(`Character sheet theme: ${nextTheme === "legacy" ? "Legacy" : "Modern SLA"}`); + await this.render(true); + this._setThemeClassState(nextTheme); + } + _setThemeClassState(theme) { + const root = this.element?.[0] ?? null; + if (!root) return; + root.dataset.slaTheme = theme; + root.classList.remove("sla-sheet-theme-legacy", "sla-sheet-theme-modern"); + root.classList.add(`sla-sheet-theme-${theme}`); + if (this.element?.removeClass) { + this.element.removeClass("sla-sheet-theme-legacy sla-sheet-theme-modern"); + this.element.addClass(`sla-sheet-theme-${theme}`); + } + const windowApp = root.closest(".window-app"); + const windowContent = root.closest(".window-content"); + const windowHeader = windowApp?.querySelector?.(".window-header") ?? null; + if (windowApp) { + windowApp.dataset.slaTheme = theme; + windowApp.classList.remove("sla-window-theme-legacy", "sla-window-theme-modern"); + windowApp.classList.add(`sla-window-theme-${theme}`); + } + if (windowContent) { + windowContent.dataset.slaTheme = theme; + windowContent.classList.remove("sla-window-theme-legacy", "sla-window-theme-modern"); + windowContent.classList.add(`sla-window-theme-${theme}`); + } + if (windowHeader) { + windowHeader.dataset.slaTheme = theme; + windowHeader.classList.remove("sla-window-theme-legacy", "sla-window-theme-modern"); + windowHeader.classList.add(`sla-window-theme-${theme}`); + } + } + _applyThemeClasses(html) { + const root = html?.get?.(0) ?? html?.[0] ?? null; + if (!root) return; + const theme = this.actor.getFlag("sla-mothership", "sheetTheme") || "modern"; + root.classList.remove("sla-sheet-theme-legacy", "sla-sheet-theme-modern"); + root.classList.add(`sla-sheet-theme-${theme}`); + this._setThemeClassState(theme); + } + _onConfigureCreature(event) { + event.preventDefault(); + new SLAMothershipGenerator(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } +} + +export class MothershipActorSheetDossier extends MothershipActorSheet { + static get defaultOptions() { + const base = super.defaultOptions; + const classes = Array.from(new Set([...(base.classes ?? []), "sla-dossier-sheet"])); + return foundry.utils.mergeObject(base, { + classes, + width: 980, + height: 920 + }); + } +} + +function parseWeaponFireModes(raw) { + const modes = []; + for (const chunk of String(raw ?? "").split(/[\n,]+/)) { + const entry = chunk.trim(); + if (!entry) continue; + const match = entry.match(/^(.+?)(?:\s*[:=|-]\s*|\s*\(\s*)(\d+)\)?$/); + if (!match) continue; + modes.push({ + label: match[1].trim(), + shots: Math.max(1, Number(match[2]) || 1) + }); + } + return modes; +} + +function deriveWeaponFireModes(system) { + const shotsPerFire = Math.max(1, Number(system?.shotsPerFire ?? 1) || 1); + const special = String(system?.sla?.special ?? "").toLowerCase(); + const modes = [{ label: "Single", shots: 1 }]; + + if (shotsPerFire > 1) { + if (special.includes("auto") && shotsPerFire > 3) { + modes.push({ label: "Burst", shots: 3 }, { label: "Auto", shots: shotsPerFire }); + } else if (special.includes("auto")) { + modes.push({ label: "Auto", shots: shotsPerFire }); + } else if (special.includes("burst")) { + modes.push({ label: "Burst", shots: shotsPerFire }); + } else if (shotsPerFire === 2) { + modes.push({ label: "Double", shots: 2 }); + } else { + modes.push({ label: "Burst", shots: shotsPerFire }); + } + } + + return modes + .filter((mode, index, list) => list.findIndex((entry) => entry.label === mode.label && entry.shots === mode.shots) === index) + .map((mode) => `${mode.label}:${mode.shots}`) + .join(", "); +} + +function getActiveFireMode(system) { + const modes = parseWeaponFireModes(system?.sla?.fireModes); + const currentMode = String(system?.sla?.currentFireMode ?? "").trim().toLowerCase(); + return modes.find((mode) => mode.label.toLowerCase() === currentMode) ?? modes[0] ?? { label: "Single", shots: 1 }; +} + +function getAmmoReserveKey(tag = "STD") { + const normalized = String(tag ?? "STD").trim().toUpperCase(); + if (normalized === "AP") return "ammoReserveAp"; + if (normalized === "HE") return "ammoReserveHe"; + if (normalized === "HEAP") return "ammoReserveHeap"; + return "ammoReserveStd"; +} + +function getAmmoReserveTotal(system = {}) { + return ["ammoReserveStd", "ammoReserveAp", "ammoReserveHe", "ammoReserveHeap"] + .reduce((total, key) => total + Math.max(0, Number(system?.[key] ?? 0) || 0), 0); +} + +function summarizeWeaponAmmoInventory(actor, weapon = {}) { + const calibre = String(weapon?.ammoCalibre ?? weapon?.ammoType ?? "").trim(); + const allowedTags = new Set( + [ + weapon?.ammoAllowStd !== false ? "STD" : null, + weapon?.ammoAllowAp !== false ? "AP" : null, + weapon?.ammoAllowHe !== false ? "HE" : null, + weapon?.ammoAllowHeap !== false ? "HEAP" : null + ].filter(Boolean) + ); + + const matchingItems = Array.from(actor?.items ?? []).filter((item) => { + if (item.type !== "item") return false; + if (String(item.system?.sla?.category ?? "").trim().toLowerCase() !== "ammunition") return false; + const itemCalibre = String(item.system?.sla?.calibre ?? "").trim(); + if (calibre && itemCalibre && itemCalibre !== calibre) return false; + const tag = String(item.system?.sla?.ammoTag ?? "STD").trim().toUpperCase(); + return allowedTags.has(tag); + }); + + if (!matchingItems.length) { + return { + total: getAmmoReserveTotal(weapon), + byTag: { + STD: Math.max(0, Number(weapon?.ammoReserveStd ?? weapon?.ammo ?? 0) || 0), + AP: Math.max(0, Number(weapon?.ammoReserveAp ?? 0) || 0), + HE: Math.max(0, Number(weapon?.ammoReserveHe ?? 0) || 0), + HEAP: Math.max(0, Number(weapon?.ammoReserveHeap ?? 0) || 0) + }, + choices: [] + }; + } + + const byTag = { STD: 0, AP: 0, HE: 0, HEAP: 0 }; + for (const item of matchingItems) { + const tag = String(item.system?.sla?.ammoTag ?? "STD").trim().toUpperCase(); + byTag[tag] = (byTag[tag] ?? 0) + Math.max(0, Number(item.system?.quantity ?? 0) || 0); + } + + return { + total: Object.values(byTag).reduce((sum, value) => sum + value, 0), + byTag, + choices: matchingItems + }; +} + +function getSpeciesRules(speciesName, store = {}) { + const rules = SLA_SPECIES_RULES[speciesName] ?? []; + return rules.map((rule) => { + store[rule.key] ??= { + enabled: rule.default, + label: rule.label, + summary: rule.summary, + optional: rule.optional + }; + return { + key: rule.key, + label: rule.label, + summary: rule.summary, + optional: rule.optional, + enabled: Boolean(store[rule.key]?.enabled), + path: `system.sla.speciesRules.${rule.key}.enabled` + }; + }); +} diff --git a/module/actor/actor.js b/module/actor/actor.js new file mode 100644 index 0000000..a0d1846 --- /dev/null +++ b/module/actor/actor.js @@ -0,0 +1,5448 @@ +import { fromIdUuid } from "../mosh.js"; +import { slaDebug, slaWarn } from "../logger.js"; +import { SLADrugSystem } from "../sla-drug-system.js"; +import { SLA_SPECIES_BALANCE_VERSION, getSlaSpeciesStatAdjustments } from "../sla-species-balance.js"; +import { buildSlaTraumaResponseText } from "../sla-trauma.js"; + +const SLA_AMMO_TYPES = { + STD: { label: "Standard", multiplier: 1, damageBonus: "", woundEffect: "", summary: "Standard ammunition." }, + AP: { label: "AP", multiplier: 2, damageBonus: "-1", woundEffect: "Gunshot [-]", summary: "Armour-piercing ammunition. Treat target armour as halved and reduce damage by 1." }, + HE: { label: "HE", multiplier: 3, damageBonus: "1d5", woundEffect: "Fire & Explosives", summary: "High explosive ammunition. Add 1d5 damage and use explosive wound effects." }, + HEAP: { label: "HEAP", multiplier: 4, damageBonus: "1d5", woundEffect: "Fire & Explosives [+]", summary: "High explosive armour-piercing ammunition. Add 1d5 damage and treat target armour as halved." } +}; + +const SLA_AMMO_RESERVE_KEYS = { + STD: "ammoReserveStd", + AP: "ammoReserveAp", + HE: "ammoReserveHe", + HEAP: "ammoReserveHeap" +}; + +const SLA_WOUND_EFFECTS = { + bleeding: { key: "bleeding", label: "Bleeding", settingKey: "table1eWoundBleeding" }, + blunt_force: { key: "blunt_force", label: "Blunt Force", settingKey: "table1eWoundBluntForce" }, + fire_explosives: { key: "fire_explosives", label: "Fire & Explosives", settingKey: "table1eWoundFireExplosives" }, + gore_massive: { key: "gore_massive", label: "Gore & Massive", settingKey: "table1eWoundGoreMassive" }, + gunshot: { key: "gunshot", label: "Gunshot", settingKey: "table1eWoundGunshot" } +}; + +const SLA_WOUND_EFFECT_ALIASES = { + bleeding: "bleeding", + blunt_force: "blunt_force", + fire_explosives: "fire_explosives", + fire_and_explosives: "fire_explosives", + gore_massive: "gore_massive", + gore_and_massive: "gore_massive", + gunshot: "gunshot" +}; + +function normalizeSlaWoundEffectKey(value = "") { + return String(value ?? "") + .trim() + .toLowerCase() + .replace(/&/g, " and ") + .replace(/[^a-z0-9]+/g, "_") + .replace(/^_+|_+$/g, ""); +} + +function parseSlaWoundEffect(rawEffect = "") { + const original = String(rawEffect ?? "").trim(); + if (!original) return null; + + let label = original; + let modifier = "standard"; + if (/\[\+\]\s*$/.test(label)) { + modifier = "adv"; + label = label.replace(/\s*\[\+\]\s*$/, "").trim(); + } else if (/\[-\]\s*$/.test(label)) { + modifier = "dis"; + label = label.replace(/\s*\[-\]\s*$/, "").trim(); + } + + const normalized = normalizeSlaWoundEffectKey(label); + const resolvedKey = SLA_WOUND_EFFECT_ALIASES[normalized] ?? normalized; + const entry = SLA_WOUND_EFFECTS[resolvedKey]; + if (!entry) { + return { + raw: original, + label, + modifier, + displayLabel: original, + unknown: true + }; + } + + const modifierSuffix = + modifier === "adv" ? " [+]" : + modifier === "dis" ? " [-]" : + ""; + + return { + ...entry, + raw: original, + modifier, + displayLabel: `${entry.label}${modifierSuffix}`, + unknown: false + }; +} + +function renderSlaWoundEffectMarkup(rawEffect = "") { + const parsed = parseSlaWoundEffect(rawEffect); + if (!parsed) return ""; + if (parsed.unknown) return foundry.utils.escapeHTML(parsed.displayLabel); + + const label = foundry.utils.escapeHTML(parsed.displayLabel); + const title = foundry.utils.escapeHTML(`Roll ${parsed.displayLabel} wound table`); + return ``; +} + +function getSlaTableRollFormula(tableData) { + const formula = String(tableData?.formula ?? "1d10").trim(); + return formula.replace(/\s*-\s*1\b/g, "").trim() || "1d10"; +} + +function getSlaWoundTableLabelFromSettingKey(settingKey = "") { + return Object.values(SLA_WOUND_EFFECTS).find((entry) => entry.settingKey === settingKey)?.label ?? null; +} + +function normalizeSlaConditionLabel(value = "") { + return String(value ?? "") + .trim() + .toLowerCase() + .replace(/[^a-z0-9]+/g, " ") + .replace(/\s+/g, " ") + .trim(); +} + +async function resolveRollTableReference(reference) { + if (!reference) return null; + + const direct = await fromIdUuid(reference, { type: "RollTable" }); + if (direct) return direct; + + const worldTable = + game.tables?.get?.(reference) || + game.tables?.find?.((table) => table.name === reference); + if (worldTable) return worldTable; + + for (const pack of game.packs ?? []) { + if (pack.metadata?.type !== "RollTable") continue; + const index = typeof pack.getIndex === "function" + ? await pack.getIndex() + : pack.index; + + const indexMatch = index?.find?.((entry) => + entry._id === reference || + entry.uuid === reference || + entry.name === reference + ); + + if (indexMatch?._id) { + const document = await pack.getDocument(indexMatch._id); + if (document) return document; + } + } + + return null; +} + +async function resolveSlaWoundTableBySetting(settingKey = "") { + const configured = game.settings.get("sla-mothership", settingKey); + const direct = await resolveRollTableReference(configured); + if (direct) return direct; + + const label = getSlaWoundTableLabelFromSettingKey(settingKey); + if (!label) return null; + + const fallbackNames = [ + `${label} Wound`, + label.replace(/&/g, "and"), + `${label.replace(/&/g, "and")} Wound` + ]; + + for (const name of fallbackNames) { + const resolved = await resolveRollTableReference(name); + if (resolved) return resolved; + } + + return null; +} + +const SLA_SKILL_IMAGE_OVERRIDES = { + athletics: "systems/sla-mothership/images/sla-assets/Skills/Athletics.png", + brawl: "systems/sla-mothership/images/sla-assets/Skills/Brawl.png" +}; + +function getSlaSkillRankLabel(bonus = 0) { + const value = Number(bonus ?? 0) || 0; + if (value >= 20) return "Master"; + if (value >= 15) return "Expert"; + if (value >= 10) return "Trained"; + if (value > 0) return "Basic"; + return "Untrained"; +} + +const SLA_SKILL_REFERENCE_ALIASES = { + brawl: ["brawl"], + meleeweaponknife: ["meleeblade1h", "brawl"], + meleeweaponclub: ["meleeclub", "brawl"], + meleeweapon2hsword: ["meleeblade2h"], + meleeweaponsword: ["meleeblade1h"], + meleeweaponaxe: ["meleeaxe"], + meleeweaponany: ["meleeblade1h", "meleeblade2h", "meleeclub", "meleeaxe", "brawl"], + naturalweaponclaws: ["brawl"], + shieldriot: ["brawl"], + throw: ["throw"], + firearmpistol: ["firearmpistol"], + firearmrifle: ["firearmrifleshotgun"], + firearmshotgun: ["firearmrifleshotgun"], + firearmrifleshotgun: ["firearmrifleshotgun"], + firearmsmg: ["firearmsmg", "firearmautosupport"], + firearmauto: ["firearmautosupport", "firearmsmg"], + firearmheavy: ["firearmautosupport"], + firearmautosupport: ["firearmautosupport", "firearmsmg"] +}; + +const SLA_SKILL_METADATA_BY_KEY = { + slainfo: { category: "Mental", combat: false, attributes: ["intellect"] }, + drivecivilian: { category: "Technical", combat: false, attributes: ["speed", "intellect"] }, + drivemilitary: { category: "Technical", combat: false, attributes: ["speed", "intellect"] }, + pilot: { category: "Technical", combat: false, attributes: ["speed", "intellect"] }, + techcomputersai: { category: "Technical", combat: false, attributes: ["intellect"] }, + techelectronics: { category: "Technical", combat: false, attributes: ["intellect"] }, + techmechanical: { category: "Technical", combat: false, attributes: ["intellect"] }, + techmilitary: { category: "Technical", combat: false, attributes: ["intellect"] }, + bureaucracy: { category: "Mental", combat: false, attributes: ["intellect"] }, + medical: { category: "Mental", combat: false, attributes: ["intellect"] }, + psychology: { category: "Mental", combat: false, attributes: ["intellect"] }, + tactics: { category: "Mental", combat: false, attributes: ["intellect"] }, + computersystems: { category: "Technical", combat: false, attributes: ["intellect"] }, + persuade: { category: "Communication", combat: false, attributes: ["intellect"] }, + fasttalk: { category: "Communication", combat: false, attributes: ["intellect"] }, + intimidate: { category: "Communication", combat: false, attributes: ["intellect"] }, + streetwise: { category: "Communication", combat: false, attributes: ["intellect"] }, + command: { category: "Communication", combat: false, attributes: ["intellect"] }, + craftspecialty: { category: "Mental", combat: false, attributes: ["intellect"] }, + spothidden: { category: "Perception", combat: false, attributes: ["speed", "intellect"] }, + listen: { category: "Perception", combat: false, attributes: ["speed", "intellect"] }, + athletics: { category: "Physical", combat: false, attributes: ["strength", "speed"] }, + climb: { category: "Physical", combat: false, attributes: ["strength", "speed"] }, + swim: { category: "Physical", combat: false, attributes: ["strength", "speed"] }, + dodge: { category: "Physical", combat: false, attributes: ["speed"] }, + stealth: { category: "Physical", combat: false, attributes: ["speed"] }, + brawl: { category: "Combat", combat: true, attributes: ["combat", "strength"] }, + meleeblade1h: { category: "Combat", combat: true, attributes: ["combat", "strength"] }, + meleeblade2h: { category: "Combat", combat: true, attributes: ["combat", "strength"] }, + meleeclub: { category: "Combat", combat: true, attributes: ["combat", "strength"] }, + meleeaxe: { category: "Combat", combat: true, attributes: ["combat", "strength"] }, + throw: { category: "Combat", combat: true, attributes: ["combat", "strength", "speed"] }, + firearmpistol: { category: "Combat", combat: true, attributes: ["combat"] }, + firearmrifleshotgun: { category: "Combat", combat: true, attributes: ["combat"] }, + firearmsmg: { category: "Combat", combat: true, attributes: ["combat"] }, + firearmautosupport: { category: "Combat", combat: true, attributes: ["combat"] }, + biofeedback: { category: "Mental", combat: false, attributes: ["intellect"] }, + formulate: { category: "Mental", combat: false, attributes: ["intellect"] }, + ebbcore: { category: "Mental", combat: false, attributes: ["intellect"] }, + ebbawareness: { category: "Perception", combat: false, attributes: ["speed", "intellect"] }, + ebbblast: { category: "Combat", combat: true, attributes: ["combat", "intellect"] }, + ebbthermalred: { category: "Combat", combat: true, attributes: ["combat", "intellect"] }, + ebbthermalblue: { category: "Combat", combat: true, attributes: ["combat", "intellect"] }, + ebbtelekinesis: { category: "Mental", combat: false, attributes: ["strength", "intellect"] }, + ebbcommunicate: { category: "Mental", combat: false, attributes: ["intellect"] }, + ebbsenses: { category: "Perception", combat: false, attributes: ["speed", "intellect"] }, + ebbprotect: { category: "Mental", combat: false, attributes: ["intellect"] }, + ebbheal: { category: "Mental", combat: false, attributes: ["intellect"] }, + ebbrealityfold: { category: "Mental", combat: false, attributes: ["intellect"] } +}; + +function normalizeSlaSkillKey(value = "") { + return String(value ?? "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, ""); +} + +function getSlaSkillMetadataForName(name = "", fallbackCategory = "") { + const key = normalizeSlaSkillKey(name); + const profile = SLA_SKILL_METADATA_BY_KEY[key]; + if (profile) return profile; + if (fallbackCategory) { + return { + category: fallbackCategory, + combat: String(fallbackCategory).trim().toLowerCase() === "combat", + attributes: [] + }; + } + return null; +} + +const SLA_CRITICAL_FAILURE_TABLES = { + firearm: { + label: "Firearm Critical Failure", + entries: [ + { title: "Misfeed", effect: "The shot sputters out. Clear the chamber before this weapon can fire again." }, + { title: "Dry Click", effect: "You burn the action on a bad feed. Lose the next half-action or equivalent moment of tempo." }, + { title: "Hot Brass", effect: "You flinch from venting brass and powder. Take Disadvantage on your next firearm roll this round." }, + { title: "Sight Knock", effect: "The weapon bucks off line. Your next aimed shot loses any range or aim benefit." }, + { title: "Magazine Slip", effect: "The magazine drops or partially seats. Spend an action to slam it home." }, + { title: "Safety Snag", effect: "Harness, sling, or safety catches at the wrong time. You cannot use reactions with this weapon until reset." }, + { title: "Overheat", effect: "The chamber runs dangerously hot. Firing again before cooling inflicts 1d5 damage to the weapon hand." }, + { title: "Wild Burst", effect: "The muzzle climbs hard. An ally or nearby asset is exposed unless the GM rules otherwise." }, + { title: "Jam", effect: "The weapon locks up hard. Full reload and field-clear procedure required before it works again." }, + { title: "Catastrophic Flashback", effect: "The shot backfires brutally. Suffer 1d5 damage and the weapon is unusable until repaired." } + ] + }, + melee: { + label: "Melee Critical Failure", + entries: [ + { title: "Bad Footing", effect: "You overcommit and lose ground. The target gains Advantage on the next opposed melee exchange." }, + { title: "Open Guard", effect: "Your defence opens wide. You cannot parry, block, or react effectively until your next turn." }, + { title: "Weapon Check", effect: "Your weapon binds or bounces free. Spend your next action to recover proper grip and stance." }, + { title: "Glancing Blow", effect: "The hit skids off cover or armour. You deal no damage and your position is compromised." }, + { title: "Off-Balance Spin", effect: "Momentum carries you through. Move one step past the target or fall prone, GM's call." }, + { title: "Hand Shock", effect: "The impact numbs your arm. Take -10 on Strength and Combat checks until the end of the next round." }, + { title: "Dropped Weapon", effect: "Your weapon flies loose or falls at your feet." }, + { title: "Friendly Opening", effect: "You expose an ally's line. The nearest ally loses cover or must reposition immediately." }, + { title: "Pulled Muscle", effect: "You wrench something important. Take 1d5 damage and all melee attacks are at Disadvantage until treated." }, + { title: "Weapon Break", effect: "The weapon chips, bends, or snaps. It is unusable until repaired or replaced." } + ] + }, + strength: { + label: "Strength Critical Failure", + entries: [ + { title: "Strain", effect: "You pull something ugly. Take 1d5 damage and lose brute-force follow-through this scene." }, + { title: "Dropped Load", effect: "Whatever you were hauling, holding, or forcing slips free in the worst possible way." }, + { title: "Brace Break", effect: "Your leverage collapses. The obstacle, door, or target gains a clear advantage over you." }, + { title: "Noisy Impact", effect: "The effort is loud and obvious. Nearby threats are alerted." }, + { title: "Tool Snap", effect: "Improvised kit, handle, or strap gives way. The relevant tool is damaged or lost." }, + { title: "Bad Lift", effect: "You overextend. Take -10 on the next Strength or Combat roll." }, + { title: "Pinned Position", effect: "You end up trapped under the task. Spend an action to free yourself before trying again." }, + { title: "Collateral Damage", effect: "You break the wrong thing. The environment or objective takes an ugly hit." }, + { title: "Hold Lost", effect: "Grip fails completely. The target breaks loose or the object drops to a worse position." }, + { title: "Backlash", effect: "The force rebounds into you. Suffer 1d10 Stress or 1d5 damage, GM's call for the scene." } + ] + }, + speed: { + label: "Speed Critical Failure", + entries: [ + { title: "Slip", effect: "You lose traction and go down or collide with the environment." }, + { title: "Bad Timing", effect: "You move a second too early. An opponent or hazard acts before you can recover." }, + { title: "Noise Spike", effect: "The attempt is fast but loud. Stealth is blown." }, + { title: "Wrong Cover", effect: "You dive into poor cover and lose any defensive benefit." }, + { title: "Dropped Kit", effect: "Essential gear spills or is left behind during the scramble." }, + { title: "Twist", effect: "You wrench ankle, knee, or hip. Take -10 on Speed checks until you rest." }, + { title: "Crossed Line", effect: "You overrun the mark and end up exposed to return fire or direct danger." }, + { title: "Friendly Collision", effect: "You crash through a teammate's lane and break squad discipline." }, + { title: "Stall Out", effect: "Momentum dies completely. Lose your next movement action." }, + { title: "Full Spill", effect: "You crash hard. Take 1d5 damage and end prone or hanging in the open." } + ] + }, + intellect: { + label: "Intellect Critical Failure", + entries: [ + { title: "False Read", effect: "You misread the situation and the GM gives a dangerously wrong first impression." }, + { title: "Terminal Mistake", effect: "You input or interpret the wrong detail. The task gets harder before it gets better." }, + { title: "Bad Assumption", effect: "You lock onto the wrong theory. Another attempt on this problem is at Disadvantage until new evidence appears." }, + { title: "Corrupted Data", effect: "You overwrite, erase, or contaminate useful intel." }, + { title: "Security Trace", effect: "Your inquiry leaves a footprint. Someone knows you were here." }, + { title: "Slow Realisation", effect: "You lose vital time. The scene clock advances or pressure escalates." }, + { title: "Protocol Breach", effect: "You trigger a lockout, alarm, or bureaucratic complication." }, + { title: "Miscommunication", effect: "Your explanation sends the team in the wrong direction for a beat." }, + { title: "Feedback Headache", effect: "The mental load hits hard. Gain 1 Stress." }, + { title: "Cascade Failure", effect: "The whole approach collapses. You need a new angle, tool, or specialist before retrying." } + ] + } +}; + +const SLA_CRITICAL_SUCCESS_OPTIONS = { + firearm: [ + "Choose one: roll the weapon's damage twice and keep the better result.", + "Choose one: ignore half the target's armour or cover on this hit.", + "Choose one: pin, disarm, or force the target to move exactly where the shot drives them." + ], + melee: [ + "Choose one: double the final damage after all normal modifiers.", + "Choose one: force the target prone, back a zone, or off balance for the next exchange.", + "Choose one: disarm, grapple, or open a free follow-up attack for an ally in reach." + ], + strength: [ + "Choose one: complete the task faster than expected and create a clean follow-up opening.", + "Choose one: force the obstacle, restraint, or target to yield so completely it cannot be reused immediately.", + "Choose one: add a decisive physical edge such as pinning, breaking, or hurling the target clear." + ], + speed: [ + "Choose one: gain immediate positional advantage, cover, or initiative over everyone else in the scene.", + "Choose one: stay silent and leave no obvious trace of movement.", + "Choose one: complete the action and still keep momentum for a second linked move or interaction." + ], + intellect: [ + "Choose one: gain an extra true detail, hidden pattern, or exploitable weakness beyond the original ask.", + "Choose one: solve the problem cleanly and reduce the time, cost, or fallout of the action.", + "Choose one: create a lasting procedural edge such as bypass access, a reusable exploit, or a stronger briefing." + ] +}; + +/** + * Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system. + * @extends {Actor} + */ +export class MothershipActor extends Actor { + + // augment the basic actor data with additional dynamic data + prepareDerivedData() { + + super.prepareDerivedData(); + const system = this.system; + + // ----- per-type derived ----- + if (this.type === "character") this._deriveCharacter(); + else if (this.type === "creature") this._deriveCreature(); + else if (this.type === "ship") this._deriveShip(); + } + + // Prepare Character type specific data + _deriveCharacter() { + const system = this.system; + //armor points + damage reduction + //init vars + let armorPoints = 0; + let damageReduction = 0; + //count values + for (const armor of this.items.filter(i => i.type === "armor")) { + if (armor.system?.equipped) { + armorPoints += Number(armor.system.armorPoints ?? 0); + damageReduction += Number(armor.system.damageReduction ?? 0); + } + } + //set values + system.stats.armor.mod = armorPoints; + system.stats.armor.total = armorPoints + Number(system.stats.armor.value ?? 0); + system.stats.armor.damageReduction = damageReduction; + //net hp + //init vars + let netHPvalue = 0; + let netHPmax = 0; + //check if actor has netHP + system.netHP ??= { value: 0, min: 0, max: 0, label: "Net HP"}; + //set values + system.netHP.value = ((Number(system.hits.max ?? 0)-Number(system.hits.value ?? 0)-1) * Number(system.health.max ?? 0)) + Number(system.health.value ?? 0); + system.netHP.max = Number(system.health.max ?? 0) * Number(system.hits.max ?? 0); + //bleeding + //init vars + let bleedingValue = 0; + //count values + for (const condition of this.items.filter(i => i.type === "condition")) { + if (condition.name === 'Bleeding') { + bleedingValue += Number(condition.system.severity ?? 0); + } + } + //set values + system.bleeding.value = Number(bleedingValue ?? 0); + } + + // Prepare Creature type specific data + _deriveCreature() { + const system = this.system; + //armor points + damage reduction + //init vars + let armorPoints = 0; + let damageReduction = 0; + //count values + for (const armor of this.items.filter(i => i.type === "armor")) { + if (armor.system?.equipped) { + armorPoints += Number(armor.system.armorPoints ?? 0); + damageReduction += Number(armor.system.damageReduction ?? 0); + } + } + //set values + system.stats.armor.mod = armorPoints; + system.stats.armor.total = armorPoints + Number(system.stats.armor.value ?? 0); + system.stats.armor.damageReduction = damageReduction; + //net hp + //check if actor has netHP + system.netHP ??= { value: 0, min: 0, max: 0, label: "Net HP"}; + //set values + system.netHP.value = ((Number(system.hits.max ?? 0)-Number(system.hits.value ?? 0)-1) * Number(system.health.max ?? 0)) + Number(system.health.value ?? 0); + system.netHP.max = Number(system.health.max ?? 0) * Number(system.hits.max ?? 0); + //notes + //check if actor has notes + system.notes ??= ""; + //bleeding + //init vars + let bleedingValue = 0; + //count values + for (const condition of this.items.filter(i => i.type === "condition")) { + if (condition.name === 'Bleeding') { + bleedingValue += Number(condition.system.severity ?? 0); + } + } + //set values + system.bleeding.value = Number(bleedingValue ?? 0); + //keep combat updates for swarm types + if (system.swarm && system.swarm.enabled){ + system.stats.combat.value = system.swarm.combat.value * ( system.hits.max - system.hits.value ); + } + } + + // Prepare Ship type specific data + _deriveShip() { + //nothing needed yet + } + + async useSlaDrug(itemId) { + return SLADrugSystem.useDrug({ actor: this, itemId }); + } + + async closeSlaDrug(itemId = "", drug = "") { + return SLADrugSystem.closeDrug({ actor: this, itemId, drug }); + } + + //central flavor text library for all chat messages + getFlavorText(type, context, action) { + + //replace 'stress' with calm if the setting is active + if (game.settings.get("sla-mothership", "useCalm") && context === 'stress') { + context = 'calm'; + } + let systemclass = "human"; + if (this.type === 'character' && this.system.class && this.system.class.value.toLowerCase() === "android") { + systemclass = "android"; + //todo: get the class item for the character to check the "is robotic" flag + } + let locString = `Mosh.${type}.${context}.${action}.${systemclass}`; + //check to see if this address exists in the library, return the action parameter if not + if(game.i18n.has(locString, true)){ // You can pass false as the second argument to ignore english-language fallback. + //log what was done + slaDebug(`Retrieved flavor text for ${locString}`); + //return class appropriate text + return game.i18n.localize(locString); + } else { + //log what was done + slaDebug(`Using language: ${game.i18n.language}`); + slaDebug(`Retrieved flavor text for ${locString}, which did not have an entry`); + slaDebug(`Using language: ${game.i18n.lang}`); + //return what we were asked + return action; + } + } + + renderSlaWoundEffect(rawEffect = "") { + return renderSlaWoundEffectMarkup(rawEffect); + } + + async rollSlaWoundEffect(effectKeyOrLabel, modifier = "standard") { + const effectInput = modifier && String(effectKeyOrLabel ?? "").trim() && !String(effectKeyOrLabel).includes("[") + ? `${String(effectKeyOrLabel).trim()}${modifier === "adv" ? " [+]" : modifier === "dis" ? " [-]" : ""}` + : effectKeyOrLabel; + const parsed = parseSlaWoundEffect(effectInput); + if (!parsed || parsed.unknown) { + ui.notifications.warn(`No valid wound effect could be resolved from "${effectKeyOrLabel}".`); + return null; + } + + const tableId = game.settings.get("sla-mothership", parsed.settingKey); + if (!tableId) { + ui.notifications.warn(`No wound table is configured for ${parsed.label}.`); + return null; + } + + const tableData = await resolveSlaWoundTableBySetting(parsed.settingKey); + if (!tableData) { + ui.notifications.warn(`The ${parsed.label} wound table could not be found.`); + return null; + } + + const modifierSuffix = + parsed.modifier === "adv" ? " [+]" : + parsed.modifier === "dis" ? " [-]" : + ""; + const rollString = `${getSlaTableRollFormula(tableData)}${modifierSuffix}`; + + return this.rollTable(tableData.uuid ?? tableData.id ?? tableId, rollString, "low", true, false, null, null, { + suppressActorWound: true + }); + } + + //central roll parsing function | TAKES '1d10 [+]','low' | RETURNS '{1d10,1d10}kh' + parseRollString(rollString, aimFor) { + //init vars + let rollDice = ``; + let rollTemplate = ``; + let rollStringParsed = ``; + //translate rollString into foundry roll string format + if (rollString.includes('[')) { + //extract dice needed + rollDice = rollString.substr(0, rollString.indexOf('[')).trim().concat(',', rollString.substr(0, rollString.indexOf('[')).trim()); + //set template based on adv or dis + if (rollString.includes('[-]')) { + //use appropriate keep setting + if (aimFor === 'low') { + rollTemplate = '{[diceSet]}kh'; + } else { + rollTemplate = '{[diceSet]}kl'; + } + } else if (rollString.includes('[+]')) { + //use appropriate keep setting + if (aimFor === 'low') { + rollTemplate = '{[diceSet]}kl'; + } else { + rollTemplate = '{[diceSet]}kh'; + } + } + //make foundry roll string + rollStringParsed = rollTemplate.replace('[diceSet]', rollDice); + } else { + rollStringParsed = rollString; + } + //log what was done + slaDebug(`Parsed '${rollString}' aiming '${aimFor}' into '${rollStringParsed}'`); + //return string in foundry format + return rollStringParsed; + } + + //central roll parsing function | TAKES '1d100',[Foundry roll object],true,true,41,'<' | RETURNS enriched Foundry roll object + parseRollResult(rollString, rollResult, zeroBased, checkCrit, rollTarget, comparison, specialRoll) { + //init vars + let doubles = new Set([0, 11, 22, 33, 44, 55, 66, 77, 88, 99]); + let enrichedRollResult = rollResult; + let rollFormula = enrichedRollResult.formula; + let rollAim = rollFormula.substr(rollFormula.indexOf("}") + 1, 2); + let useCalm = game.settings.get('sla-mothership', 'useCalm'); + let die0value = 999; + let die1value = 999; + let die0success = false; + let die1success = false; + let die0crit = false; + let die1crit = false; + let newTotal = 999; + let diceFormula = ``; + let compareIcon = ``; + let outcome = ``; + let outcomeHtml = ``; + let diceIcon = ``; + let diceBlock = ``; + let critHighlight = ``; + let rollHtml = ``; + //init new fields in enriched roll result + enrichedRollResult.critical = false; + enrichedRollResult.success = false; + enrichedRollResult.isCritSuccess = false; + enrichedRollResult.isCritFailure = false; + enrichedRollResult.critClass = ""; + enrichedRollResult.outcomeHtml = ``; + enrichedRollResult.rollHtml = ``; + //alter roll result object + //change data point: change each 100 or 10 result to zero + if (zeroBased) { + //1d10 changes + if (rollString.substr(0, rollString.indexOf("[")).trim() === '1d10' || rollString === '1d10' || rollString.substr(0, rollString.indexOf("[")).trim() === '-1d10' || rollString === '-1d10') { + //loop through dice + enrichedRollResult.dice.forEach(function (roll) { + //loop through each result + roll.results.forEach(function (die) { + //change any 10s to 0s + if (die.result === 10 || die.result === -10) { + die.result = 0; + } + }); + }); + //1d100 changes + } else if (rollString.substr(0, rollString.indexOf("[")).trim() === '1d100' || rollString === '1d100' || rollString.substr(0, rollString.indexOf("[")).trim() === '-1d100' || rollString === '-1d100') { + //loop through dice + enrichedRollResult.dice.forEach(function (roll) { + //loop through each result + roll.results.forEach(function (die) { + //change any 100s to 0s + if (die.result === 100 || die.result === -100) { + die.result = 0; + } + }); + }); + } + } + //set roll A and B + if (enrichedRollResult.dice[0]) { + die0value = enrichedRollResult.dice[0].results[0].result; + } + if (enrichedRollResult.dice[1]) { + die1value = enrichedRollResult.dice[1].results[0].result; + } + //do we need to pick a winner? + if (rollString.includes("[")) { + //set whether each die succeeded + //die 0 + if (comparison === '<' && die0value < rollTarget && die0value < 90) { + die0success = true; + } + if (comparison === '<=' && die0value <= rollTarget && die0value < 90) { + die0success = true; + } + if (comparison === '>' && die0value > rollTarget && die0value < 90) { + die0success = true; + } + if (comparison === '>=' && die0value >= rollTarget && die0value < 90) { + die0success = true; + } + //die 1 + if (comparison === '<' && die1value < rollTarget && die1value < 90) { + die1success = true; + } + if (comparison === '<=' && die1value <= rollTarget && die1value < 90) { + die1success = true; + } + if (comparison === '>' && die1value > rollTarget && die1value < 90) { + die1success = true; + } + if (comparison === '>=' && die1value >= rollTarget && die1value < 90) { + die1success = true; + } + //set whether each die are a crit + //die 0 + if (checkCrit && doubles.has(die0value)) { + die0crit = true; + } + //die 1 + if (checkCrit && doubles.has(die1value)) { + die1crit = true; + } + //if [-] pick a new worst number + if (rollString.includes("[-]")) { + //if we are trying to keep the highest + if (rollAim === 'kh') { + //set default result value to the highest value + newTotal = Math.max(die0value, die1value); + //if both are a success and only dice 0 is a crit: don't pick the crit + if (die0success && die1success && die0crit && !die1crit) { + newTotal = die1value; + } + //if both are a success and only dice 1 is a crit: don't pick the crit + if (die0success && die1success && !die0crit && die1crit) { + newTotal = die0value; + } + //if both are a failure and only dice 0 is a crit: pick the crit + if (!die0success && !die1success && die0crit && !die1crit) { + newTotal = die0value; + } + //if both are a failure and only dice 1 is a crit: pick the crit + if (!die0success && !die1success && !die0crit && die1crit) { + newTotal = die1value; + } + //if this is a panic check and both are a failure: pick the worst + if (specialRoll === 'panicCheck' && !useCalm && !die0success && !die1success) { + newTotal = Math.max(die0value, die1value); + } + } + //if we are trying to keep the lowest + if (rollAim === 'kl') { + //set default result value to the lowest value + newTotal = Math.min(die0value, die1value); + //if both are a success and only dice 0 is a crit: don't pick the crit + if (die0success && die1success && die0crit && !die1crit) { + newTotal = die1value; + } + //if both are a success and only dice 1 is a crit: don't pick the crit + if (die0success && die1success && !die0crit && die1crit) { + newTotal = die0value; + } + //if both are a failure and only dice 0 is a crit: pick the crit + if (!die0success && !die1success && die0crit && !die1crit) { + newTotal = die0value; + } + //if both are a failure and only dice 1 is a crit: pick the crit + if (!die0success && !die1success && !die0crit && die1crit) { + newTotal = die1value; + } + //if this is a panic check and both are a failure: pick the worst + if (specialRoll === 'panicCheck' && !useCalm && !die0success && !die1success) { + newTotal = Math.max(die0value, die1value); + } + } + } + //if [+] pick a new best number + if (rollString.includes("[+]")) { + //if we are trying to keep the highest + if (rollAim === 'kh') { + //set default result value to the highest value + newTotal = Math.max(die0value, die1value); + //if both are a success and only dice 0 is a crit: pick the crit + if (die0success && die1success && die0crit && !die1crit) { + newTotal = die0value; + } + //if both are a success and only dice 1 is a crit: pick the crit + if (die0success && die1success && !die0crit && die1crit) { + newTotal = die1value; + } + //if both are a failure and only dice 0 is a crit: don't pick the crit + if (!die0success && !die1success && die0crit && !die1crit) { + newTotal = die1value; + } + //if both are a failure and only dice 1 is a crit: don't pick the crit + if (!die0success && !die1success && !die0crit && die1crit) { + newTotal = die0value; + } + //if this is a panic check and both are a failure: pick the best + if (specialRoll === 'panicCheck' && !useCalm && !die0success && !die1success) { + newTotal = Math.min(die0value, die1value); + } + } + //if we are trying to keep the lowest + if (rollAim === 'kl') { + //set default result value to the lowest value + newTotal = Math.min(die0value, die1value); + //if both are a success and only dice 0 is a crit: pick the crit + if (die0success && die1success && die0crit && !die1crit) { + newTotal = die0value; + } + //if both are a success and only dice 1 is a crit: pick the crit + if (die0success && die1success && !die0crit && die1crit) { + newTotal = die1value; + } + //if both are a failure and only dice 0 is a crit: don't pick the crit + if (!die0success && !die1success && die0crit && !die1crit) { + newTotal = die1value; + } + //if both are a failure and only dice 1 is a crit: don't pick the crit + if (!die0success && !die1success && !die0crit && die1crit) { + newTotal = die0value; + } + //if this is a panic check and both are a failure: pick the best + if (specialRoll === 'panicCheck' && !useCalm && !die0success && !die1success) { + newTotal = Math.min(die0value, die1value); + } + } + } + //we don't need to pick a winner + } else { + //set result value to the only die + newTotal = die0value; + } + //set final total value - apply negative for negative rolls + if (rollString.substr(0, 1) === '-') { + enrichedRollResult._total = newTotal * -1; + } else { + enrichedRollResult._total = newTotal; + } + //enrich roll result object + //add data point: detect critical + if (checkCrit) { + //check for crit + if (doubles.has(enrichedRollResult.total)) { + enrichedRollResult.critical = true; + } else { + enrichedRollResult.critical = false; + } + } + //add data point: detect success/failure + if (rollTarget || rollTarget === 0) { + //check for auto failure + if (enrichedRollResult.total >= 90) { + //result >= 90 is a failure + enrichedRollResult.success = false; + } else { + //compare values based on compararison setting + if (comparison === '<') { + //check against being under the target + if (enrichedRollResult.total < rollTarget) { + enrichedRollResult.success = true; + } else { + enrichedRollResult.success = false; + } + } else if (comparison === '<=') { + //check against being under or equal to the target + if (enrichedRollResult.total <= rollTarget) { + enrichedRollResult.success = true; + } else { + enrichedRollResult.success = false; + } + } else if (comparison === '>') { + //check against being over the target + if (enrichedRollResult.total > rollTarget) { + enrichedRollResult.success = true; + } else { + enrichedRollResult.success = false; + } + } else if (comparison === '>=') { + //check against being over or equal to the target + if (enrichedRollResult.total >= rollTarget) { + enrichedRollResult.success = true; + } else { + enrichedRollResult.success = false; + } + } + } + enrichedRollResult.isCritSuccess = Boolean(enrichedRollResult.critical && enrichedRollResult.success); + enrichedRollResult.isCritFailure = Boolean(enrichedRollResult.critical && !enrichedRollResult.success); + enrichedRollResult.critClass = enrichedRollResult.isCritSuccess + ? "sla-crit-success" + : enrichedRollResult.isCritFailure + ? "sla-crit-failure" + : ""; + //add data point: outcome HTML + //prepare outcome + //success + if (enrichedRollResult.success) { + outcome = `SUCCESS!`; + } else { + outcome = `FAILURE!`; + } + //crit + if (enrichedRollResult.critical) { + outcome = `CRITICAL ` + outcome; + } + //make HTML + outcomeHtml = ` +
+ ${outcome} +
+ `; + //update final roll html string + enrichedRollResult.outcomeHtml = outcomeHtml; + } + //add data point: interactive roll HTML + //prepare variables + //make comparison icon + if (comparison === '<') { + compareIcon = ''; + } else if (comparison === '<=') { + compareIcon = ''; + } else if (comparison === '>') { + compareIcon = ''; + } else if (comparison === '>=') { + compareIcon = ''; + } + //prepare formula + if (rollTarget) { + //show dice against target + diceFormula = rollString + ' ' + compareIcon + ' ' + rollTarget; + } else { + //just show the dice + diceFormula = rollString; + } + //prepare dice block + //loop through rolls + enrichedRollResult.dice.forEach(function (roll) { + //add header for this roll + diceBlock = diceBlock + ` +
+
+ `; + //add formula and result for this roll + diceBlock = diceBlock + ` +
+ ${roll.formula} + ${roll.total.toString()} +
+
    + `; + //loop through dice + roll.results.forEach(function (die) { + //set highlight if crit is asked for + if (checkCrit) { + //check for crit + if (doubles.has(die.result)) { + //check for success + if (rollTarget) { + //check for auto failure + if (die.result >= 90) { + //result >= 90 is a failure, no highlight needed + critHighlight = ' min'; + } else { + //check against beating the target + if (comparison === '<' && die.result < rollTarget) { + critHighlight = ' max'; + } else if (comparison === '<=' && die.result <= rollTarget) { + critHighlight = ' max'; + } else if (comparison === '>' && die.result > rollTarget) { + critHighlight = ' max'; + } else if (comparison === '>=' && die.result >= rollTarget) { + critHighlight = ' max'; + } else { + critHighlight = ' min'; + } + } + } + } else { + //no highlight needed + critHighlight = ''; + } + } else { + //no highlight needed + critHighlight = ''; + } + //prepare dice icon + if (roll.faces === 100 || roll.faces === 5) { + diceIcon = `10`; + } else { + diceIcon = roll.faces.toString(); + } + //add formula and result for this die + diceBlock = diceBlock + ` +
  1. ${die.result.toString()}
  2. + `; + }); + //add footer for this roll + diceBlock = diceBlock + ` +
+
+
+ `; + }); + //set final roll variables in to template + rollHtml = ` +
+
+
${diceFormula}
+ +

${enrichedRollResult.total}

+
+
+ `; + //update final roll html string + enrichedRollResult.rollHtml = rollHtml; + //log what was done + slaDebug(`Enriched roll result. rollString: ${rollString}, rollResult: ${rollResult}, zeroBased: ${zeroBased}, checkCrit: ${checkCrit}, rollTarget: ${rollTarget}, comparison: ${comparison}, specialRoll: ${specialRoll}`); + slaDebug(enrichedRollResult); + //return the enriched roll result object + return enrichedRollResult; + } + + //A script to return the data from a table. + async getRollTableData(tableId){ + + let tableData = await fromIdUuid(tableId,{type:"RollTable"}); + //get table name + let tableName = tableData.name; + //get table name + let tableImg = tableData.img; + //get table result + let tableDie = tableData.formula.replace('-1', ''); + + return tableData; + } + + //central table rolling function | TAKES 'W36WFIpCfMknKgHy','1d10','low',true,true,41,'<' | RETURNS chat message showing roll table result + async rollTable(tableId, rollString, aimFor, zeroBased, checkCrit, rollAgainst, comparison, options = {}) { + //init vars + let currentLocation = ''; + let tableLocation = ''; + let messageTemplate = ``; + let messageContent = ``; + let msgDesc = ``; + let flavorText = ``; + let woundText = ``; + let tableResultType = ``; + let tableResultEdited = ``; + let tableResultFooter = ``; + let chatId = foundry.utils.randomID(); + let rollTarget = null; + let valueAddress = []; + let specialRoll = null; + let firstEdition = game.settings.get('sla-mothership', 'firstEdition'); + let useCalm = game.settings.get('sla-mothership', 'useCalm'); + let androidPanic = game.settings.get('sla-mothership', 'androidPanic'); + let tableResultNumber = null; + let secondRoll = false; + let rollResult2 = null; + let parsedRollResult2 = null; + const suppressActorWound = Boolean(options?.suppressActorWound); + //customize this roll if its a unique use-case + //panic check + if (tableId === 'panicCheck') { + //set special roll value for use later + specialRoll = tableId; + //assign variables depending on settings + if (firstEdition) { + if (androidPanic && this.system.class.value.toLowerCase() === 'android') { + if (useCalm) { + tableId = game.settings.get('sla-mothership', 'table1ePanicCalmAndroid'); + aimFor = 'low'; + zeroBased = true; + checkCrit = true; + rollAgainst = 'system.other.stress.value'; + comparison = '<'; + } else { + tableId = game.settings.get('sla-mothership', 'table1ePanicStressAndroid'); + aimFor = 'high'; + zeroBased = false; + checkCrit = false; + rollAgainst = 'system.other.stress.value'; + comparison = '>'; + } + } else { + if (useCalm) { + tableId = game.settings.get('sla-mothership', 'table1ePanicCalmNormal'); + aimFor = 'low'; + zeroBased = true; + checkCrit = true; + rollAgainst = 'system.other.stress.value'; + comparison = '<'; + } else { + tableId = game.settings.get('sla-mothership', 'table1ePanicStressNormal'); + aimFor = 'high'; + zeroBased = false; + checkCrit = false; + rollAgainst = 'system.other.stress.value'; + comparison = '>'; + } + } + } else { + if (androidPanic && this.system.class.value.toLowerCase() === 'android') { + if (useCalm) { + tableId = game.settings.get('sla-mothership', 'table0ePanicCalmAndroid'); + aimFor = 'low'; + zeroBased = true; + checkCrit = true; + rollAgainst = 'system.other.stress.value'; + comparison = '<'; + } else { + tableId = game.settings.get('sla-mothership', 'table0ePanicStressAndroid'); + aimFor = 'high'; + zeroBased = false; + checkCrit = false; + rollAgainst = 'system.other.stress.value'; + comparison = '>'; + } + } else { + if (useCalm) { + tableId = game.settings.get('sla-mothership', 'table0ePanicCalmNormal'); + aimFor = 'low'; + zeroBased = true; + checkCrit = true; + rollAgainst = 'system.other.stress.value'; + comparison = '<'; + } else { + tableId = game.settings.get('sla-mothership', 'table0ePanicStressNormal'); + aimFor = 'high'; + zeroBased = false; + checkCrit = false; + rollAgainst = 'system.other.stress.value'; + comparison = '>'; + } + } + } + //assign rollString if its a partial + if (rollString === '[-]' || rollString === '' || rollString === '[+]') { + //if 1e and no calm, then 1d20 + if (firstEdition && !useCalm) { + rollString = '1d20' + rollString; + } + //if 0e and no calm, then 2d10 + if (!firstEdition && !useCalm) { + rollString = '2d10' + rollString; + } + //if calm, then 1d100 + if (useCalm) { + rollString = '1d100' + rollString; + } + } + } + //maintenance check + if (tableId === 'maintenanceCheck') { + //set special roll value for use later + specialRoll = tableId; + //assign variables + tableId = game.settings.get('sla-mothership', 'table1eMaintenance'); + zeroBased = true; + checkCrit = true; + rollAgainst = 'system.stats.systems.value'; + comparison = '<'; + } + //bounce this request away if certain parameters are NULL + //if rollString is STILL blank, redirect player to choose the roll + if (!rollString) { + //init vars + let rollDie = ''; + //set rollDie + //if 1e and no calm, then 1d20 + if (firstEdition) { + rollDie = '1d20'; + } + //if 0e and no calm, then 2d10 + if (!firstEdition) { + rollDie = '2d10'; + } + //if calm, then 1d100 + if (useCalm) { + rollDie = '1d100'; + } + //run the choose attribute function + let chosenRollType = await this.chooseAdvantage( game.i18n.localize("Mosh.PanicCheck"), rollDie); + //set variables + rollString = chosenRollType[0]; + } + + let tableData = await resolveRollTableReference(tableId); + if (!tableData) { + ui.notifications.error("The selected wound or panic table could not be found. Please check the table settings."); + slaWarn("rollTable could not resolve table reference", tableId); + return null; + } + //get current compendium + //get table name + let tableName = tableData.name ?? "Roll Table"; + //get table name + let tableImg = tableData.img ?? ""; + //get table result + let tableDie = String(tableData.formula ?? "1d100").replace('-1', ''); + //if rollString is STILL blank, redirect player to choose the roll + if (!rollString) { + //run the choose attribute function + let chosenRollType = await this.chooseAdvantage(tableName, tableDie); + //set variables + rollString = chosenRollType[0]; + } + //table specific customizations + //if a table has details in parenthesis, lets remove them + if (tableName.includes(' (')) { + //extract dice needed + tableName = tableName.substr(0, tableName.indexOf(' (')); + } + //if a wound table, add a wound to the player and prepare text for the final message + if (tableName.slice(-5) === 'Wound' && !suppressActorWound) { + let addWound = await this.modifyActor('system.hits.value', 1, null, false); + woundText = addWound[1]; + } + //pull stat to roll against, if needed + if (rollAgainst || rollAgainst === 0) { + //turn string address into array + valueAddress = rollAgainst.split('.'); + //set rollTarget + rollTarget = valueAddress.reduce((a, v) => a[v], this); + } + //roll the dice + //parse the roll string + let parsedRollString = this.parseRollString(rollString, aimFor); + if (game.settings.get('sla-mothership', 'panicDieTheme') != "") { //We're going to check if the theme field is blank. Otherwise, don't use this. + //set panic die color + let dsnTheme = game.settings.get('sla-mothership', 'panicDieTheme'); + //apply theme if this is a panic check + if (tableName === 'Panic Check') { + parsedRollString = parsedRollString + '[' + dsnTheme + ']'; + } + } + //roll the dice + let rollResult = await new Roll(parsedRollString).evaluate(); + //interpret the results + let parsedRollResult = this.parseRollResult(rollString, rollResult, zeroBased, checkCrit, rollTarget, comparison, specialRoll); + //if this is a panic check, we may need to roll again OR add modifiers to our result total + //roll a second die if needed + if (!parsedRollResult.success && specialRoll === 'maintenanceCheck' && !firstEdition && !useCalm) { + //determine the rollString + let rollString2 = '2d10'; + //add modifiers if needed + //0e modifier: + Stress - Resolve + if (specialRoll === 'maintenanceCheck' && !firstEdition && !useCalm) { + rollString2 = rollString2 + ' + ' + this.system.other.stress.value + ' - ' + this.system.other.resolve.value + } + //Calm modifier: + Stress - Resolve + if (specialRoll === 'panicCheck' && useCalm) { + rollString2 = rollString2 + ' + ' + this.system.other.resolve.value + } + //roll second dice + rollResult2 = await new Roll(rollString2).evaluate(); + //roll second set of dice + parsedRollResult2 = this.parseRollResult(rollString2, rollResult2, false, false, null, null, specialRoll); + //set marker for HTML + secondRoll = true; + //set table result number + tableResultNumber = parsedRollResult2.total + } + //if this is a maintenance check, we need to roll again if a failure + //roll a second die if needed + if (!parsedRollResult.success && specialRoll === 'maintenanceCheck' && firstEdition) { + //determine the rollString + let rollString2 = '1d100'; + //roll second dice + rollResult2 = await new Roll(rollString2).evaluate(); + //roll second set of dice + parsedRollResult2 = this.parseRollResult(rollString2, rollResult2, true, false, null, null, specialRoll); + //set marker for HTML + secondRoll = true; + //set table result number + tableResultNumber = parsedRollResult2.total; + //log second die + console.log(`Rolled second die`); + } + //set table result number if null + if (!tableResultNumber) { + tableResultNumber = parsedRollResult.total; + } + //fetch the table result + let tableResult = tableData.getResultsForRoll(tableResultNumber).map((result) => ({ + ...result, + description: result.description ?? result.text ?? "" + })); + if (!tableResult.length) { + ui.notifications.warn(`No result was found on ${tableName} for roll ${tableResultNumber}.`); + return null; + } + //make any custom changes to chat message + //panic check #19 customiziation + if (tableName === 'Panic Check' && tableResultNumber === 19) { + if (this.system.class.value.toLowerCase() === 'android') { + tableResultEdited = tableResult[0].description.replace(game.i18n.localize("Mosh.HEARTATTACKSHORTCIRCUITANDROIDS"), game.i18n.localize("Mosh.SHORTCIRCUIT")); + } else { + tableResultEdited = tableResult[0].description.replace(game.i18n.localize("Mosh.HEARTATTACKSHORTCIRCUITANDROIDS"), game.i18n.localize("Mosh.HEARTATTACK")); + } + } + //assign message description text + msgDesc = this.getFlavorText('table', tableName.replaceAll('& ', '').replaceAll(' ', '_').toLowerCase(), 'roll'); + //assign flavor text + //get main flavor text + flavorText = this.getFlavorText('table', tableName.replaceAll('& ', '').replaceAll(' ', '_').toLowerCase(), 'success'); + //append 0e crit success effect + if (!firstEdition && !useCalm && parsedRollResult.success && parsedRollResult.critical) { + flavorText = flavorText + game.i18n.localize("Mosh.Relieve1Stressqbq694JMbXeZrHj"); + } + //append Calm effects for Critical Panic Success + if (useCalm && parsedRollResult.success && parsedRollResult.critical) { + flavorText = flavorText + game.i18n.localize("Mosh.Gain1d10Calmk2TtLFOG9mGaWVx31d10Calm"); + } + //append Calm effects for Critical Panic Failure + if (useCalm && !parsedRollResult.success && parsedRollResult.critical) { + tableResultFooter = `

You lose 1d10 Calm because you critically failed.

@UUID[Compendium.mosh.macros_triggered_1e.jHyqXb2yDFTNWxpy]{-1d10 Calm}`; + } + //append effects for Stress + Maintenance Check Failure + if (specialRoll === 'maintenanceCheck' && !useCalm && !parsedRollResult.success && !parsedRollResult.critical) { + tableResultFooter = `

Everyone on board the ship takes 1 Stress.

@UUID[Compendium.mosh.macros_triggered_1e.dvJR9DYXI2kV0BbR]{+1 Stress}`; + } + //append effects for Stress + Critical Maintenance Check Failure + if (specialRoll === 'maintenanceCheck' && !useCalm && !parsedRollResult.success && parsedRollResult.critical) { + tableResultFooter = `

Everyone on board the ship takes 1 Stress. You must roll for another maintenance issue because you critically failed.

@UUID[Compendium.mosh.macros_triggered_1e.dvJR9DYXI2kV0BbR]{+1 Stress}

@UUID[Compendium.mosh.macros_triggered_1e.hRapiXGVW8WZQH12]{Roll for Maintenance Issue}`; + } + //append effects for Calm + Maintenance Check Failure + if (specialRoll === 'maintenanceCheck' && useCalm && !parsedRollResult.success && !parsedRollResult.critical) { + tableResultFooter = `

Everyone on board the ship loses 1d10 Calm.

@UUID[Compendium.mosh.macros_triggered_1e.jHyqXb2yDFTNWxpy]{-1d10 Calm}`; + } + //append effects for Calm + Critical Maintenance Check Failure + if (specialRoll === 'maintenanceCheck' && useCalm && !parsedRollResult.success && parsedRollResult.critical) { + tableResultFooter = `

Everyone on board the ship loses 1d10 Calm. You must roll for another maintenance issue because you critically failed.

@UUID[Compendium.mosh.macros_triggered_1e.jHyqXb2yDFTNWxpy]{-1d10 Calm}

@UUID[Compendium.mosh.macros_triggered_1e.hRapiXGVW8WZQH12]{Roll for Maintenance Issue}`; + } + //append effects for Calm + Critical Maintenance Check Success + if (specialRoll === 'maintenanceCheck' && useCalm && parsedRollResult.success && parsedRollResult.critical) { + flavorText = flavorText + ` Gain 1d10 Calm.

@UUID[Compendium.mosh.macros_triggered_1e.k2TtLFOG9mGaWVx3]{+1d10 Calm}`; + } + //set table result type (using first value) + if (tableResult[0].type === 0 || tableResult[0].type === 'text') { + tableResultType = `text`; + } else if (tableResult[0].type === 1 || tableResult[0].type === 'document') { + tableResultType = `document`; + } else { + tableResultType = `unknown`; + } + //generate chat message + //prepare data + let messageData = { + actor: this, + tableResult: tableResult, + tableResultType: tableResultType, + tableResultEdited: tableResultEdited, + tableResultFooter: tableResultFooter, + parsedRollResult: parsedRollResult, + tableName: tableName, + tableImg: tableImg, + msgDesc: msgDesc, + flavorText: flavorText, + woundText: woundText, + secondRoll: secondRoll, + parsedRollResult2: parsedRollResult2, + specialRoll: specialRoll + }; + //prepare template + messageTemplate = 'systems/sla-mothership/templates/chat/rollTable.html'; + //render template + messageContent = await foundry.applications.handlebars.renderTemplate(messageTemplate, messageData); + //make message + let macroMsg = await rollResult.toMessage({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + if (game.modules.get("dice-so-nice") && game.modules.get("dice-so-nice").active) { + //log what was done + slaDebug(`Rolled on table ID: ${tableId}, with: rollString:${rollString}, aimFor:${aimFor}, zeroBased:${zeroBased}, checkCrit:${checkCrit}, rollAgainst:${rollAgainst}, comparison:${comparison}`); + //return messageData + return [messageData]; + //wait for dice + await game.dice3d.waitFor3DAnimationByMessageID(chatId); + } + //will come back later to do optional chat message + ////log what was done + //console.log(`Rolled on table ID: ${tableId}, with: rollString:${rollString}, aimFor:${aimFor}, zeroBased:${zeroBased}, checkCrit:${checkCrit}, rollAgainst:${rollAgainst}, comparison:${comparison}`); + ////return messageData + //return [messageData]; + } + + //central adding addribute function | TAKES '1d10','low' | RETURNS player selected attribute. If parameters are null, it asks the player. + async chooseAttribute(rollString, aimFor) { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //init vars + let playerItems = this.items; + let attribute = ``; + let skill = ``; + let skillValue = 0; + let buttonDesc = ``; + //create HTML for this window + //header + let dialogDesc = await foundry.applications.handlebars.renderTemplate('systems/sla-mothership/templates/dialogs/skill-check-stat-selection-dialog.html'); + //create button header if needed + if (!rollString) { + buttonDesc = `
` + game.i18n.localize("Mosh.SelectYourRollType") + `
`; + } else { + buttonDesc = ``; + } + //create final dialog data + const dialogData = { + window: {title: game.i18n.localize("Mosh.ChooseAStat")}, + classes: ["macro-popup-dialog"], + position: {width: 600}, + content: dialogDesc + buttonDesc, + buttons: [] + }; + //add adv/normal/dis buttons if we need a rollString + if (!rollString) { + //we need to generate a roll string + dialogData.buttons = [ + { + label: game.i18n.localize("Mosh.Advantage"), + action: `action_advantage`, + callback: (event, button, dialog) => { + rollString = `1d100 [+]`; + aimFor = `low`; + attribute = button.form.querySelector("input[name='stat']:checked")?.getAttribute("value"); + resolve([rollString, aimFor, attribute]); + console.log(`User left the chooseAttribute dialog with: rollString:${rollString}, aimFor:${aimFor}, attribute:${attribute}`); + }, + icon: `fas fa-angle-double-up` + }, + { + label: game.i18n.localize("Mosh.Normal"), + action: `action_normal`, + callback: (event, button, dialog) => { + rollString = `1d100`; + aimFor = `low`; + attribute = button.form.querySelector("input[name='stat']:checked")?.getAttribute("value"); + resolve([rollString, aimFor, attribute]); + console.log(`User left the chooseAttribute dialog with: rollString:${rollString}, aimFor:${aimFor}, attribute:${attribute}`); + }, + icon: `fas fa-minus` + }, + { + label: game.i18n.localize("Mosh.Disadvantage"), + action: `action_disadvantage`, + callback: (event, button, dialog) => { + rollString = `1d100 [-]`; + aimFor = `low`; + attribute = button.form.querySelector("input[name='stat']:checked")?.getAttribute("value"); + resolve([rollString, aimFor, attribute]); + console.log(`User left the chooseAttribute dialog with: rollString:${rollString}, aimFor:${aimFor}, attribute:${attribute}`); + }, + icon: `fas fa-angle-double-down` + } + ] + //add a next button if we dont need a rollString + } else { + dialogData.buttons = [ + { + label: game.i18n.localize("Mosh.Next"), + action: `action_next`, + callback: (event, button, dialog) => { + aimFor = `low`; + attribute = button.form.querySelector("input[name='stat']:checked")?.getAttribute("value"); + resolve([rollString, aimFor, attribute]); + console.log(`User left the chooseAttribute dialog with: rollString:${rollString}, aimFor:${aimFor}, attribute:${attribute}`); + }, + icon: `fas fa-chevron-circle-right` + } + ] + } + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + }); + } + + normalizeSkillReference(value = "") { + return normalizeSlaSkillKey(value); + } + + expandSkillReferenceAliases(value = "") { + const normalized = this.normalizeSkillReference(value); + if (!normalized) return []; + return SLA_SKILL_REFERENCE_ALIASES[normalized] ?? [normalized]; + } + + getRelevantSkillCategories(attribute = "") { + const map = { + strength: ["combat", "physical"], + speed: ["physical", "perception", "technical"], + intellect: ["technical", "mental", "perception", "knowledge"], + combat: ["combat", "physical"], + sanity: ["mental", "communication"], + fear: ["mental", "communication", "perception"], + body: ["physical", "medical", "technical"] + }; + return map[String(attribute ?? "").toLowerCase()] ?? []; + } + + requiresCombatSkillContext(context = {}) { + if (context.weapon) return true; + if (context.attackContext?.combatOnly) return true; + return String(context.attribute ?? "").trim().toLowerCase() === "combat"; + } + + isSkillRelevantForContext(skill, context = {}) { + const inferredMetadata = getSlaSkillMetadataForName( + skill?.name ?? "", + skill?.system?.sla?.category ?? this.getSkillBreakdown(skill).category ?? "" + ) ?? {}; + const category = String(skill?.system?.sla?.category ?? inferredMetadata.category ?? this.getSkillBreakdown(skill).category ?? "").trim().toLowerCase(); + const skillName = this.normalizeSkillReference(skill?.name ?? ""); + const isCombatSkill = Boolean(skill?.system?.sla?.combat ?? inferredMetadata.combat); + const attributeTags = Array.isArray(skill?.system?.sla?.attributes) && skill.system.sla.attributes.length + ? skill.system.sla.attributes.map((entry) => String(entry ?? "").trim().toLowerCase()) + : Array.isArray(inferredMetadata.attributes) + ? inferredMetadata.attributes.map((entry) => String(entry ?? "").trim().toLowerCase()) + : []; + const requiresCombatSkills = this.requiresCombatSkillContext(context); + + if (context.weapon) { + const refs = [ + context.weapon?.system?.sla?.skillRef, + context.weapon?.system?.sla?.skillRefAlt + ] + .flatMap((entry) => this.expandSkillReferenceAliases(entry)) + .filter(Boolean); + if (refs.length) { + return refs.includes(skillName); + } + return isCombatSkill; + } + + if (requiresCombatSkills) { + return isCombatSkill; + } + + const requestedAttribute = String(context.attribute ?? "").trim().toLowerCase(); + if (requestedAttribute && attributeTags.length) { + return attributeTags.includes(requestedAttribute); + } + + const relevantCategories = this.getRelevantSkillCategories(context.attribute); + if (!relevantCategories.length) return true; + return relevantCategories.includes(category); + } + + //central adding skill function | TAKES '1d10','low' | RETURNS player selected skill + value. If parameters are null, it asks the player. + async chooseSkill(dlgTitle, rollString, context = {}) { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //init vars + let playerItems = this.items; + let skill = ``; + let skillValue = 0; + let buttonDesc = ``; + //create HTML for this window + //header + const attackSummary = []; + const statKey = String(context.attribute ?? "").trim(); + const statLabel = statKey ? (this.system?.stats?.[statKey]?.label ?? statKey) : ""; + const statValue = statKey ? Number(this.system?.stats?.[statKey]?.value ?? 0) + Number(this.system?.stats?.[statKey]?.mod ?? 0) : null; + const requiresCombatSkills = this.requiresCombatSkillContext(context); + if (context.weapon?.system?.useAmmo) { + const ammoContext = this.getWeaponAmmoContext(context.weapon, context.attackContext?.ammoTag); + const fireMode = context.attackContext?.fireMode ?? this.getActiveWeaponFireMode(context.weapon)?.label ?? "Single"; + const shotsPerFire = Math.max(1, Number(context.attackContext?.shotsPerFire ?? this.getActiveWeaponFireMode(context.weapon)?.shots ?? 1) || 1); + attackSummary.push(`Weapon: ${context.weapon.name} | Fire mode: ${fireMode} | Rounds: ${shotsPerFire}`); + attackSummary.push(`Ammo: ${ammoContext.label} | Cost: ${ammoContext.costPerRound} cR/round | ${ammoContext.summary}`); + } + if (requiresCombatSkills) { + attackSummary.push(`Combat filter active: combat-tagged skills only.`); + } + let skillHeader = await foundry.applications.handlebars.renderTemplate( + 'systems/sla-mothership/templates/dialogs/choose-skill-dialog-header.html', + { + statSummary: statLabel ? `Stat: ${statLabel}${Number.isFinite(statValue) ? ` ${statValue}` : ""}` : "", + attackSummary + } + ); + //skill template + let skillRow = ` + `; + //make list of skill using template + //create skillList string + let skillList = ``; + //create skill counter + let skillCount = 0; + //create dialog pixel counter + let dialogHeight = 232; + //loop through and create skill rows + const filteredSkills = playerItems.filter((item) => item.type === "skill" && this.isSkillRelevantForContext(item, context)); + const skillSource = filteredSkills.length + ? filteredSkills + : (requiresCombatSkills ? [] : playerItems.filter((item) => item.type === "skill")); + for (let item of skillSource) { + //check if this is a skill + const breakdown = this.getSkillBreakdown(item); + //set temprow as template + let tempRow = skillRow; + //replace ID + tempRow = tempRow.replaceAll("[RADIO_ID]", item.name); + //replace value + tempRow = tempRow.replace("[RADIO_VALUE]", item.system.bonus); + //replace img + tempRow = tempRow.replace("[RADIO_IMG]", item.img); + //replace name + tempRow = tempRow.replace("[RADIO_BONUS]", breakdown.total); + //replace name + tempRow = tempRow.replace("[RADIO_NAME]", item.name); + tempRow = tempRow.replace("[RADIO_FLAGS]", item.system?.sla?.combat ? `Combat` : ``); + //replace desc + tempRow = tempRow.replace("[RADIO_DESC]", `: ${breakdown.summary}`); + //add to skillList + skillList = skillList + tempRow; + //increment skill count + skillCount++; + //increment pixel counter + dialogHeight = dialogHeight + 77; + } + //check if there are no skills, and adjust prompt height accordingly + if (skillCount === 0) { + //set window height + dialogHeight = 170; + skillList = `
${requiresCombatSkills ? "No combat-tagged skills are available for this action." : "No matching skills are available for this action."}
`; + } + //create button header if needed + if (!rollString) { + buttonDesc = `
` + game.i18n.localize("Mosh.SelectYourRollType") + `:
`; + } else { + buttonDesc = ``; + } + //create final dialog data + const dialogData = { + window: {title: dlgTitle}, + classes: ["macro-popup-dialog"], + position: {width: 600}, + content: skillHeader + skillList + buttonDesc, + buttons: [] + }; + //add adv/normal/dis buttons if we need a rollString + if (!rollString) { + //we need to generate a roll string + dialogData.buttons = [ + { + label: game.i18n.localize("Mosh.Advantage"), + action: `action_advantage`, + callback: (event, button, dialog) => { + rollString = `1d100 [+]`; + skill = button.form.querySelector("input[name='skill']:checked")?.getAttribute("id"); + skillValue = button.form.querySelector("input[name='skill']:checked")?.getAttribute("value"); + resolve([rollString, skill, skillValue]); + slaDebug(`User left the chooseSkill dialog with: rollString:${rollString}, skill:${skill}, skillValue:${skillValue}`); + }, + icon: `fas fa-angle-double-up` + }, + { + label: game.i18n.localize("Mosh.Normal"), + action: `action_normal`, + callback: (event, button, dialog) => { + rollString = `1d100`; + skill = button.form.querySelector("input[name='skill']:checked")?.getAttribute("id"); + skillValue = button.form.querySelector("input[name='skill']:checked")?.getAttribute("value"); + resolve([rollString, skill, skillValue]); + slaDebug(`User left the chooseSkill dialog with: rollString:${rollString}, skill:${skill}, skillValue:${skillValue}`); + }, + icon: `fas fa-minus` + }, + { + label: game.i18n.localize("Mosh.Disadvantage"), + action: `action_disadvantage`, + callback: (event, button, dialog) => { + rollString = `1d100 [-]`; + skill = button.form.querySelector("input[name='skill']:checked")?.getAttribute("id"); + skillValue = button.form.querySelector("input[name='skill']:checked")?.getAttribute("value"); + resolve([rollString, skill, skillValue]); + slaDebug(`User left the chooseSkill dialog with: rollString:${rollString}, skill:${skill}, skillValue:${skillValue}`); + }, + icon: `fas fa-angle-double-down` + } + ] + //add a next button if we dont need a rollString + } else { + dialogData.buttons = [ + { + label: game.i18n.localize("Mosh.Next"), + action: `action_next`, + callback: (event, button, dialog) => { + skill = button.form.querySelector("input[name='skill']:checked")?.getAttribute("id"); + skillValue = button.form.querySelector("input[name='skill']:checked")?.getAttribute("value"); + resolve([rollString, skill, skillValue]); + slaDebug(`User left the chooseSkill dialog with: rollString:${rollString}, skill:${skill}, skillValue:${skillValue}`); + }, + icon: `fas fa-chevron-circle-right` + } + ] + } + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + }); + } + + //central adding skill function | TAKES 'Body Save','1d10' | RETURNS player selected rollString. + async chooseAdvantage(dlgTitle, die) { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //init vars + let rollString = ``; + //make diceRoll variants + let dieAdv = die + ` [+]`; + let dieDis = die + ` [-]`; + //create final dialog data + const dialogData = { + window: {title: dlgTitle}, + classes: ["macro-popup-dialog"], + position: {width: 600}, + content: `
` + game.i18n.localize("Mosh.SelectYourRollType") + `:
`, + buttons: [ + { + label: game.i18n.localize("Mosh.Advantage"), + action: `action_advantage`, + callback: (event, button, dialog) => { + rollString = dieAdv; + resolve([rollString]); + slaDebug(`User left the chooseAdvantage dialog with: rollString:${rollString}`); + }, + icon: `fas fa-angle-double-up` + }, + { + label: game.i18n.localize("Mosh.Normal"), + action: `action_normal`, + callback: (event, button, dialog) => { + rollString = die; + resolve([rollString]); + slaDebug(`User left the chooseAdvantage dialog with: rollString:${rollString}`); + }, + icon: `fas fa-minus` + }, + { + label: game.i18n.localize("Mosh.Disadvantage"), + action: `action_disadvantage`, + callback: (event, button, dialog) => { + rollString = dieDis; + resolve([rollString]); + slaDebug(`User left the chooseAdvantage dialog with: rollString:${rollString}`); + }, + icon: `fas fa-angle-double-down` + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + }); + } + + getSlaCriticalFailureCategory({ weapon = null, attribute = "" } = {}) { + if (weapon) { + const weaponType = String(weapon?.system?.sla?.weaponType ?? "").trim().toLowerCase(); + if (weapon?.system?.useAmmo || ["firearm", "ranged", "explosive"].includes(weaponType)) { + return "firearm"; + } + return "melee"; + } + + const key = String(attribute ?? "").trim().toLowerCase(); + if (["strength", "speed", "intellect"].includes(key)) { + return key; + } + return null; + } + + async rollSlaCriticalFailureTable(category) { + const table = SLA_CRITICAL_FAILURE_TABLES[category]; + if (!table?.entries?.length) return null; + + const roll = await new Roll("1d10").evaluate(); + const total = Math.max(1, Math.min(10, Number(roll.total ?? 1) || 1)); + const entry = table.entries[total - 1] ?? table.entries[0]; + + return { + category, + label: table.label, + roll: total, + entry + }; + } + + getSlaCriticalSuccessOptions({ weapon = null, attribute = "" } = {}) { + const category = this.getSlaCriticalFailureCategory({ weapon, attribute }); + return SLA_CRITICAL_SUCCESS_OPTIONS[category] ?? []; + } + + async applySlaAmmoSpend(weapon, ammoUsage) { + const spent = Math.max(0, Number(ammoUsage?.totalCost ?? 0) || 0); + if (!spent) return null; + + const currentCredits = Number(this.system?.credits?.value ?? 0) || 0; + const newCredits = Math.round((currentCredits - spent) * 100) / 100; + const currentTotal = Math.max(0, Number(this.system?.sla?.ammoSpendTotal?.value ?? 0) || 0); + const spendTotal = Math.round((currentTotal + spent) * 100) / 100; + const stamp = new Intl.DateTimeFormat(undefined, { + dateStyle: "short", + timeStyle: "short" + }).format(new Date()); + const shotLabel = Number(ammoUsage?.shots ?? 0) === 1 ? "round" : "rounds"; + const ledgerEntry = `[${stamp}] ${weapon?.name ?? "Weapon"} | ${ammoUsage?.ammoLabel ?? "Ammo"} ${ammoUsage?.ammoTag ?? "STD"} | ${ammoUsage?.shots ?? 0} ${shotLabel} | ${ammoUsage?.label ?? "Single"} | -${spent} cR | balance ${newCredits} cR`; + const currentLedger = String(this.system?.sla?.ammoLedger?.value ?? "").trim(); + const ledgerLines = [ledgerEntry, ...currentLedger.split("\n").filter(Boolean)].slice(0, 60); + + await this.update({ + "system.credits.value": newCredits, + "system.sla.ammoSpendTotal.value": spendTotal, + "system.sla.ammoLedger.value": ledgerLines.join("\n") + }); + + return { + spent, + newCredits, + spendTotal, + ledgerEntry + }; + } + + getSlaPrimaryTargetContext() { + const targets = [...(game.user?.targets ?? [])].filter((token) => token?.actor); + if (!targets.length) return null; + + return { + token: targets[0], + actor: targets[0].actor, + additionalTargets: Math.max(0, targets.length - 1) + }; + } + + getSlaTargetArmourContext(targetActor, weapon = null, ammoContext = null) { + const baseDR = Math.max(0, Number(targetActor?.system?.stats?.armor?.damageReduction ?? 0) || 0); + const ammoTag = this.normalizeAmmoTag(ammoContext?.ammoTag ?? weapon?.system?.ammoLoadedType ?? weapon?.system?.ammoTag ?? "STD"); + const armourPiercing = Boolean(weapon?.system?.antiArmor || ["AP", "HEAP"].includes(ammoTag)); + const effectiveDR = armourPiercing ? Math.floor(baseDR / 2) : baseDR; + + return { + baseDR, + effectiveDR, + armourPiercing, + note: armourPiercing ? `Armour reduced from ${baseDR} to ${effectiveDR}.` : `Armour reduced ${baseDR} damage.` + }; + } + + buildSlaDamageFormula(parsedDamageString, weapon, { isCritical = false } = {}) { + let rawFormula = String(parsedDamageString ?? "").trim(); + if (rawFormula === "Str/10") { + rawFormula = `floor((${this.system.stats.strength.value} + ${(Number(this.system.stats.strength.mod) || 0)}) / 10)`; + } + const critDamageMode = game.settings.get('sla-mothership', 'critDamage'); + + if (isCritical) { + if (critDamageMode === 'advantage') { + rawFormula = `{${parsedDamageString},${parsedDamageString}}kh`; + } else if (critDamageMode === 'doubleDamage') { + rawFormula = `(${parsedDamageString}) * 2`; + } else if (critDamageMode === 'doubleDice') { + rawFormula = `${parsedDamageString} + ${parsedDamageString}`; + } else if (critDamageMode === 'maxDamage') { + rawFormula = parsedDamageString.replaceAll('d', ' * '); + } else if (critDamageMode === 'weaponValue') { + rawFormula = `${parsedDamageString} + ${weapon?.system?.critDmg || 0}`; + } + } + + return rawFormula; + } + + async applySlaTargetedDamage({ weapon, parsedDamageString, targetContext, ammoContext = null, isCritical = false } = {}) { + if (!weapon || !parsedDamageString || !targetContext?.actor) return null; + + const damageFormula = this.buildSlaDamageFormula(parsedDamageString, weapon, { isCritical }); + const damageRoll = await new Roll(damageFormula).evaluate(); + const rawDamage = Math.max(0, Number(damageRoll.total ?? 0) || 0); + const armour = this.getSlaTargetArmourContext(targetContext.actor, weapon, ammoContext); + const finalDamage = Math.max(0, rawDamage - armour.effectiveDR); + + let updateText = ""; + let warning = ""; + if (finalDamage > 0) { + try { + const targetUpdate = await targetContext.actor.modifyActor('system.health.value', -finalDamage, null, false); + updateText = targetUpdate?.[1] ?? ""; + } catch (err) { + console.warn("sla-mothership | Failed to apply targeted damage", err); + warning = `Could not automatically apply damage to ${targetContext.actor.name}. Check permissions and apply ${finalDamage} manually.`; + } + } + + return { + targetName: targetContext.actor.name, + additionalTargets: targetContext.additionalTargets ?? 0, + damageFormula, + rawDamage, + armourReduced: armour.effectiveDR, + baseArmour: armour.baseDR, + armourPiercing: armour.armourPiercing, + armourNote: armour.note, + finalDamage, + updateText, + warning + }; + } + + async applySlaAbilityTargetedDamage({ ability, targetContext, isCriticalSuccess = false } = {}) { + if (!ability?.system?.roll) return null; + + const damageFormula = String(ability.system.roll).trim(); + const damageRoll = await new Roll(damageFormula).evaluate(); + const rollHtml = await this.renderSlaAbilityRollHtml(damageRoll); + await this.postSlaAbilityRollMessage({ ability, roll: damageRoll, effectType: "damage" }); + const rolledDamage = Math.max(0, Number(damageRoll.total ?? 0) || 0); + const rawDamage = isCriticalSuccess ? rolledDamage * 2 : rolledDamage; + const baseDR = Math.max(0, Number(targetContext?.actor?.system?.stats?.armor?.damageReduction ?? 0) || 0); + const ignoreArmour = Math.max(0, Number(ability.system?.sla?.ignoreArmour ?? 0) || 0); + const effectiveDR = Math.max(0, baseDR - ignoreArmour); + const finalDamage = Math.max(0, rawDamage - effectiveDR); + + let updateText = ""; + let warning = ""; + if (targetContext?.actor && finalDamage > 0) { + try { + const targetUpdate = await targetContext.actor.modifyActor("system.health.value", -finalDamage, null, false); + updateText = targetUpdate?.[1] ?? ""; + } catch (err) { + console.warn("sla-mothership | Failed to apply targeted Ebb damage", err); + warning = `Could not automatically apply damage to ${targetContext.actor.name}. Check permissions and apply ${finalDamage} manually.`; + } + } else if (!targetContext?.actor) { + warning = "No target selected. Damage was rolled but not applied automatically."; + } + + return { + targetName: targetContext?.actor?.name ?? "No target", + formula: damageFormula, + rollHtml, + rollTotal: rolledDamage, + criticalBoosted: isCriticalSuccess, + rawDamage, + baseDR, + ignoreArmour, + effectiveDR, + finalDamage, + updateText, + warning + }; + } + + async applySlaAbilityTargetedHealing({ ability, targetContext, isCriticalSuccess = false } = {}) { + if (!ability?.system?.roll) return null; + + const healingFormula = String(ability.system.roll).trim(); + const healingRoll = await new Roll(healingFormula).evaluate(); + const rollHtml = await this.renderSlaAbilityRollHtml(healingRoll); + await this.postSlaAbilityRollMessage({ ability, roll: healingRoll, effectType: "healing" }); + const rolledHealing = Math.max(0, Number(healingRoll.total ?? 0) || 0); + const totalHealing = isCriticalSuccess ? rolledHealing * 2 : rolledHealing; + const targetActor = targetContext?.actor ?? null; + + let updateText = ""; + let warning = ""; + if (targetActor && totalHealing > 0) { + try { + const targetUpdate = await targetActor.modifyActor("system.health.value", totalHealing, null, false); + updateText = targetUpdate?.[1] ?? ""; + } catch (err) { + console.warn("sla-mothership | Failed to apply targeted Ebb healing", err); + warning = `Could not automatically heal ${targetActor.name}. Check permissions and apply ${totalHealing} manually.`; + } + } else if (!targetActor) { + warning = "No target selected. Healing was rolled but not applied automatically."; + } + + return { + targetName: targetActor?.name ?? "No target", + formula: healingFormula, + rollHtml, + rollTotal: rolledHealing, + criticalBoosted: isCriticalSuccess, + totalHealing, + updateText, + warning + }; + } + + async createSlaAbilityEffectChat({ + ability, + title, + summary, + details = [], + tone = "neutral", + rollHtml = "" + } = {}) { + const detailHtml = details.filter(Boolean).map((line) => `
${line}
`).join(""); + const fluxCost = Math.max(0, Number(ability?.system?.sla?.fluxCost ?? 0) || 0); + const tierLabel = String(ability?.system?.sla?.tier ?? "").trim(); + const content = ` +
+
+
+
${title}
+
+
+
+
Ebb Spend
+ ${tierLabel ? `
Tier: ${tierLabel}
` : ""} +
Flux Used: ${fluxCost}
+
+
+
${summary}
+ ${rollHtml} + ${detailHtml} +
+
+
+ `; + + await ChatMessage.create({ + user: game.user.id, + speaker: { actor: this.id, token: this.token, alias: this.name }, + content + }); + } + + getSlaAbilityFumbleProfile(ability) { + const notes = Array.isArray(ability?.system?.sla?.notes) + ? ability.system.sla.notes + : Array.isArray(ability?.system?.notes) + ? ability.system.notes + : []; + const joined = notes.join(" ").trim(); + if (!joined) return null; + + const targetMatch = joined.match(/target takes\s+(\d+d\d+)\s+damage/i); + if (targetMatch) { + return { + formula: targetMatch[1].toUpperCase(), + target: "target", + summary: joined + }; + } + + const selfMatch = joined.match(/take\s+(\d+d\d+)\s+.*damage/i); + if (selfMatch) { + return { + formula: selfMatch[1].toUpperCase(), + target: "self", + summary: joined + }; + } + + return null; + } + + async resolveSlaAbilityFumble(ability) { + const profile = this.getSlaAbilityFumbleProfile(ability); + if (!profile?.formula) return null; + + const targetContext = this.getSlaPrimaryTargetContext(); + const targetActor = profile.target === "target" ? targetContext?.actor ?? null : this; + const targetName = targetActor?.name ?? (profile.target === "target" ? "No target" : this.name); + + const traumaRoll = await new Roll(profile.formula).evaluate(); + const rollHtml = await this.renderSlaAbilityRollHtml(traumaRoll); + const traumaTotal = Math.max(0, Number(traumaRoll.total ?? 0) || 0); + + let updateText = ""; + let warning = ""; + if (targetActor && traumaTotal > 0) { + try { + const updateResult = await targetActor.modifyActor("system.health.value", -traumaTotal, null, false); + updateText = updateResult?.[1] ?? ""; + } catch (err) { + console.warn("sla-mothership | Failed to apply Ebb fumble trauma", err); + warning = `Could not automatically apply ${traumaTotal} trauma damage to ${targetName}.`; + } + } else if (profile.target === "target" && !targetActor) { + warning = `No target selected. ${profile.formula} Ebb trauma was rolled but not applied.`; + } + + const summary = profile.target === "target" + ? `${targetName} takes ${traumaTotal} Ebb trauma damage.` + : `You take ${traumaTotal} Ebb trauma damage.`; + + await this.createSlaAbilityEffectChat({ + ability, + title: `${ability.name} Fumble`, + summary, + rollHtml, + details: [ + `Rolled: ${profile.formula} = ${traumaTotal}`, + profile.summary, + updateText, + warning + ], + tone: "damage" + }); + + return { targetName, traumaTotal, warning, updateText }; + } + + async renderSlaAbilityRollHtml(roll) { + if (!roll) return ""; + try { + if (typeof roll.render === "function") { + return await roll.render(); + } + } catch (err) { + console.warn("sla-mothership | Failed to render Ebb effect roll HTML", err); + } + return ""; + } + + async postSlaAbilityRollMessage({ ability, roll, effectType = "effect" } = {}) { + if (!roll) return null; + + const tierLabel = String(ability?.system?.sla?.tier ?? "").trim(); + const fluxCost = Math.max(0, Number(ability?.system?.sla?.fluxCost ?? 0) || 0); + const effectLabel = effectType === "healing" ? "Healing Roll" : effectType === "damage" ? "Damage Roll" : "Effect Roll"; + const toneClass = effectType === "healing" ? "sla-effect-heal" : effectType === "damage" ? "sla-effect-damage" : ""; + const flavor = ` +
+
${ability?.name ?? "Ebb"} ${effectLabel}
+
+ ${tierLabel ? `Tier: ${tierLabel} | ` : ""}Flux Used: ${fluxCost} +
+
+ Formula: ${roll.formula} | + Total: ${roll.total ?? 0} +
+
+ `; + + return roll.toMessage({ + user: game.user.id, + speaker: { actor: this.id, token: this.token, alias: this.name }, + flavor + }); + } + + async resolveSlaAbilityEffect(ability, { isCriticalSuccess = false } = {}) { + const impact = String(ability?.system?.sla?.impact ?? "").trim().toLowerCase(); + const targetContext = this.getSlaPrimaryTargetContext(); + + if (impact === "heal" && ability?.system?.roll) { + const healingResult = await this.applySlaAbilityTargetedHealing({ ability, targetContext, isCriticalSuccess }); + if (healingResult) { + const targetSummary = targetContext?.actor + ? `You restore ${healingResult.totalHealing} Health to ${healingResult.targetName}.` + : `You channel ${healingResult.totalHealing} points of healing.`; + await this.createSlaAbilityEffectChat({ + ability, + title: `${ability.name} Healing`, + summary: targetSummary, + rollHtml: healingResult.rollHtml, + details: [ + `Rolled: ${healingResult.formula} = ${healingResult.rollTotal}${healingResult.criticalBoosted ? `, doubled to ${healingResult.totalHealing} on critical success` : ""}`, + healingResult.updateText, + healingResult.warning + ], + tone: "heal" + }); + } + return healingResult; + } + + if ((impact === "harm" || ability?.system?.sla?.attack) && ability?.system?.roll) { + const damageResult = await this.applySlaAbilityTargetedDamage({ ability, targetContext, isCriticalSuccess }); + if (damageResult) { + const targetSummary = targetContext?.actor + ? `You inflict ${damageResult.finalDamage} damage on ${damageResult.targetName}.` + : `You channel ${damageResult.rawDamage} points of damage.`; + await this.createSlaAbilityEffectChat({ + ability, + title: `${ability.name} Effect`, + summary: targetSummary, + rollHtml: damageResult.rollHtml, + details: [ + `Rolled: ${damageResult.formula} = ${damageResult.rollTotal}${damageResult.criticalBoosted ? `, doubled to ${damageResult.rawDamage} on critical success` : ""}`, + targetContext?.actor ? `Armour ${damageResult.baseDR}, Ignore ${damageResult.ignoreArmour}, Final ${damageResult.finalDamage}.` : "", + damageResult.updateText, + damageResult.warning + ], + tone: "damage" + }); + } + return damageResult; + } + + if (isCriticalSuccess) { + await this.createSlaAbilityEffectChat({ + ability, + title: `${ability.name} Critical Success`, + summary: `${ability.name} critically succeeds. If this effect does not produce a numeric damage or healing value, the GM should enhance the outcome.`, + details: [ + "Critical Ebb successes double numeric damage or healing.", + "For non-numeric effects, treat the result as enhanced at the GM's discretion." + ], + tone: "neutral" + }); + } + + await this.chatDesc(ability); + return null; + } + + //central check rolling function | TAKES '1d10','low','combat','Geology',10,[weapon item] | RETURNS chat message showing check result + async rollCheck(rollString, aimFor, attribute, skill, skillValue, weapon,overrideDamagaRollString=null, attackContext={}) { + //init vars + let specialRoll = ``; + let checkCrit = true; + let zeroBased = true; + let rollTarget = null; + let rollTargetOverride = null; + let messageTemplate = ``; + let messageContent = ``; + let attributeLabel = ``; + let parsedDamageString = rollTarget; + let comparison = ``; + let damageResult = null; + let parsedDamageResult = null; + let critFail = false; + let ebbCriticalFearSave = false; + let critMod = ``; + let outcomeVerb = ``; + let flavorText = ``; + let comparisonText = ``; + let needsDesc = false; + let woundEffect = ``; + let msgHeader = ``; + let msgImgPath = ``; + let chatId = foundry.utils.randomID(); + let firstEdition = game.settings.get('sla-mothership', 'firstEdition'); + let useCalm = game.settings.get('sla-mothership', 'useCalm'); + let ammoUsage = null; + let ammoAccounting = null; + let ammoContext = weapon ? this.getWeaponAmmoContext(weapon, attackContext?.ammoTag) : null; + let targetingResult = null; + let criticalFailureTable = null; + let criticalSuccessOptions = []; + const isSlaEbbSkill = Boolean(attackContext?.slaEbbSkill); + //customize this roll if its a unique use-case + //damage roll + if (attribute === 'damage') { + //set special roll value for use later + specialRoll = attribute; + //disable criticals for this roll + checkCrit = false; + //set attribute + attribute = 'combat'; + //set skill + value + skill = 'none'; + skillValue = 0; + //set rollstring + if(overrideDamagaRollString){ + rollString=overrideDamagaRollString; + }else{ + rollString = weapon.system.damage; + } + } + //rest save + if (attribute === 'restSave') { + //1e rest save + if (firstEdition) { + //set special roll value for use later + specialRoll = attribute; + //disable criticals for this roll + checkCrit = false; + //lets figure out the actors worst save and update this roll accordingly + //get current save values + let sanitySave = Number(this.system.stats.sanity.value) + Number(this.system.stats.sanity.mod || 0); + let fearSave = Number(this.system.stats.fear.value) + Number(this.system.stats.fear.mod || 0); + let bodySave = Number(this.system.stats.body.value) + Number(this.system.stats.body.mod || 0); + //get the lowest value + let minSave = Math.min(sanitySave, fearSave, bodySave); + //set attribute to the first one matching the lowest (since actor may have 2 with the lowest) + if (sanitySave === minSave) { + //set attribute + attribute = 'sanity'; + } else if (fearSave === minSave) { + //set attribute + attribute = 'fear'; + } else { + //set attribute + attribute = 'body'; + } + //0e Rest save + } else { + //set special roll value for use later + specialRoll = attribute; + //disable criticals for this roll + checkCrit = false; + //set attribute + attribute = 'fear'; + } + } + //bankruptcy save + if (attribute === 'bankruptcySave') { + //set special roll value for use later + specialRoll = attribute; + //set attribute value + attribute = 'bankruptcy'; + } + //morale check + if (attribute === 'moraleCheck') { + //set special roll value for use later + specialRoll = attribute; + //disable criticals for this roll + checkCrit = false; + //set attribute value + attribute = 'megadamage'; + //lets get the max megadamage value + rollTargetOverride = Math.max.apply(null, this.system.megadamage.hits); + } + //bounce this request away if certain parameters are NULL + //if attribute is blank, redirect player to choose an attribute + if (!attribute && !specialRoll) { + //run the choose attribute function + let chosenAttributes = await this.chooseAttribute(rollString, aimFor); + //set variables + rollString = chosenAttributes[0]; + aimFor = chosenAttributes[1]; + attribute = chosenAttributes[2]; + //if null, zero them out + } + //if skill is blank and actor is a character, redirect player to choose a skill + if (!skill && this.type === 'character') { + //run the choose attribute function + let chosenSkills = await this.chooseSkill(this.system.stats[attribute].rollLabel, rollString, { attribute, weapon, attackContext }); + //set variables + rollString = chosenSkills[0]; + skill = chosenSkills[1]; + skillValue = chosenSkills[2]; + } + //if rollString is STILL blank, redirect player to choose the roll + if (!rollString) { + //run the choose attribute function + let chosenRollType = await this.chooseAdvantage(this.system.stats[attribute].rollLabel, '1d100'); + //set variables + rollString = chosenRollType[0]; + } + //if this is a weapon roll + if (weapon) { + //check to see if this weapon uses ammo + if (weapon.system.useAmmo === true && specialRoll !== 'damage') { + const activeFireMode = attackContext?.fireMode + ? { label: attackContext.fireMode, shots: Math.max(1, Number(attackContext.shotsPerFire ?? 1) || 1) } + : this.getActiveWeaponFireMode(weapon); + const ammoCost = Math.max(1, Number(activeFireMode?.shots ?? weapon.system.shotsPerFire ?? 1) || 1); + const previousLoadedTag = this.normalizeAmmoTag(weapon.system.ammoLoadedType ?? weapon.system.ammoTag ?? "STD"); + const selectedAmmoTag = this.normalizeAmmoTag(attackContext?.ammoTag ?? weapon.system.ammoLoadedType ?? weapon.system.ammoTag ?? "STD"); + weapon.system.sla ??= {}; + weapon.system.sla.currentFireMode = activeFireMode.label; + weapon.system.shotsPerFire = ammoCost; + weapon.system.ammoLoadedType = selectedAmmoTag; + weapon.system.ammoTag = selectedAmmoTag; + const selectedAmmoContext = this.getWeaponAmmoContext(weapon, selectedAmmoTag); + if (weapon.system.curShots < ammoCost || previousLoadedTag !== selectedAmmoTag) { + const reloadOutcome = await this.reloadWeaponData(weapon, selectedAmmoTag); + if (!reloadOutcome) { + let t = await this.outOfAmmo(); + return; + } + } + //if the weapon has enough shots remaining to shoot + if (weapon.system.curShots >= ammoCost) { + //reduce shots by shotsPerFire + weapon.system.curShots -= ammoCost; + weapon.system.ammo = this.getWeaponReserveTotal(weapon); + weapon.system.ammoReserve = weapon.system.ammo; + //update players weapon + await this.updateEmbeddedDocuments('Item', [weapon]); + ammoUsage = { + label: activeFireMode.label, + shots: ammoCost, + ammoTag: selectedAmmoTag, + ammoLabel: selectedAmmoContext.label, + roundCost: selectedAmmoContext.costPerRound, + totalCost: selectedAmmoContext.costPerRound * ammoCost, + ammoRule: selectedAmmoContext.summary, + loaded: Number(weapon.system.curShots ?? 0), + reserve: Number(weapon.system.ammo ?? 0) + }; + ammoContext = selectedAmmoContext; + ammoAccounting = await this.applySlaAmmoSpend(weapon, ammoUsage); + if (ammoAccounting) { + ammoUsage.remainingCredits = ammoAccounting.newCredits; + ammoUsage.spendTotal = ammoAccounting.spendTotal; + } + //if the weapon doesn't have enough shots remaining to shoot + } else { + let t = await this.outOfAmmo(); + return; + } + } + } + //if this is a damage roll + if (specialRoll === 'damage') { + //parse the roll string + let damageRollString = weapon.system.damage + if(overrideDamagaRollString){ + damageRollString = overrideDamagaRollString; + } + if (weapon && weapon.system.useAmmo) { + damageRollString = this.applyWeaponAmmoDamageModifier(damageRollString, ammoContext); + } + parsedDamageString = this.parseRollString(damageRollString, 'high'); + //override message header + msgHeader = weapon.name; + //override header image + msgImgPath = weapon.img; + let dsnTheme = 0; + if (game.settings.get('sla-mothership', 'damageDiceTheme') != "") { //We're going to check if the theme field is blank. Otherwise, don't use this. + //set damage dice color + dsnTheme = game.settings.get('sla-mothership', 'damageDiceTheme'); + } + //prepare flavortext + if (weapon.system.damage === "Str/10" && this.type === 'character') { + //determine the damage string + flavorText = 'You strike your target for [[floor((' + this.system.stats.strength.value + ' + ' + (Number(this.system.stats.strength.mod) || 0) + ')/10)]] damage.'; + } else { + flavorText = 'You inflict [[' + parsedDamageString + '[' + dsnTheme + ']' + critMod + ']] points of damage.'; + } + const targetContext = this.getSlaPrimaryTargetContext(); + if (targetContext) { + targetingResult = await this.applySlaTargetedDamage({ + weapon, + parsedDamageString, + targetContext, + ammoContext, + isCritical: false + }); + if (targetingResult) { + flavorText = `You hit ${targetingResult.targetName} for ${targetingResult.finalDamage} damage after armour.`; + } + } + //determine if this roll needs a description area + if (weapon.system.description || weapon.system.woundEffect) { + needsDesc = true; + } + //create wound effect string + if (weapon.system.woundEffect) { + woundEffect = this.renderSlaWoundEffect(weapon.system.woundEffect); + } + //generate chat message + //prepare data + let messageData = { + actor: this, + weapon: weapon, + msgHeader: msgHeader, + msgImgPath: msgImgPath, + flavorText: flavorText, + targetingResult: targetingResult, + needsDesc: needsDesc, + woundEffect: woundEffect, + specialRoll: specialRoll + }; + let chatData = { + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + } + }; + //create message + const template = 'systems/sla-mothership/templates/chat/rollCheck.html'; + const content = await foundry.applications.handlebars.renderTemplate(template, messageData); + chatData.content = content; + await ChatMessage.create(chatData); + //log what was done + console.log(`Rolled damage on:${weapon.name}`); + //return messageData + return [messageData]; + } + let effectiveRollBreakdown = attackContext?.rollBreakdown ?? null; + //make the rollTarget value + if (!rollTargetOverride) { + effectiveRollBreakdown = effectiveRollBreakdown ?? this.buildSlaRollBreakdown({ + attribute, + skillName: skill, + skillValue + }); + rollTarget = Number(effectiveRollBreakdown?.total ?? 0) || 0; + } else { + rollTarget = rollTargetOverride; + } + //roll the dice + //parse the roll string + let parsedRollString = this.parseRollString(rollString, aimFor); + //roll the dice + let rollResult = await new Roll(parsedRollString).evaluate(); + //set comparison based on aimFor + if (aimFor === 'low') { + comparison = '<'; + comparisonText = 'less than'; + } else if (aimFor === 'low-equal') { + comparison = '<='; + comparisonText = 'less than or equal to'; + } else if (aimFor === 'high') { + comparison = '>'; + comparisonText = 'greater than'; + } else if (aimFor === 'high-equal') { + comparison = '>='; + comparisonText = 'greater than or equal to'; + } + //interpret the results + let parsedRollResult = this.parseRollResult(rollString, rollResult, zeroBased, checkCrit, rollTarget, comparison, specialRoll); + if (parsedRollResult.isCritFailure) { + const failureCategory = this.getSlaCriticalFailureCategory({ weapon, attribute }); + if (failureCategory) { + criticalFailureTable = await this.rollSlaCriticalFailureTable(failureCategory); + } + } + if (parsedRollResult.isCritSuccess) { + criticalSuccessOptions = this.getSlaCriticalSuccessOptions({ weapon, attribute }); + } + //prep damage dice in case its needed + if (weapon && parsedRollResult.success) { + //parse the roll string + let damageRollString = weapon.system.damage + if(overrideDamagaRollString){ + damageRollString = overrideDamagaRollString; + } + if (weapon.system.useAmmo) { + damageRollString = this.applyWeaponAmmoDamageModifier(damageRollString, ammoContext); + } + parsedDamageString = this.parseRollString(damageRollString, 'high'); + } + //set chat message text + //set roll result as greater than or less than + if (parsedRollResult.success) { + outcomeVerb = `rolled`; + } else { + outcomeVerb = `did not roll`; + } + //prepare flavor text for attacks + if (weapon) { + //override message header + msgHeader = weapon.name; + //override header image + msgImgPath = weapon.img; + let dsnTheme = 0; + if (game.settings.get('sla-mothership', 'damageDiceTheme') != "") { //We're going to check if the theme field is blank. Otherwise, don't use this. + //set damage dice color + dsnTheme = game.settings.get('sla-mothership', 'damageDiceTheme'); + } + //prepare attribute label + attributeLabel = this.system.stats[attribute].label; + //set crit damage effect + if (parsedRollResult.success === true && parsedRollResult.critical === true) { + if (game.settings.get('sla-mothership', 'critDamage') === 'advantage') { + parsedDamageString = '{' + parsedDamageString + ',' + parsedDamageString + '}kh'; + } else if (game.settings.get('sla-mothership', 'critDamage') === 'doubleDamage') { + critMod = ' * 2'; + } else if (game.settings.get('sla-mothership', 'critDamage') === 'doubleDice') { + critMod = ' + ' + parsedDamageString + '[' + dsnTheme + ']'; + } else if (game.settings.get('sla-mothership', 'critDamage') === 'maxDamage') { + parsedDamageString = parsedDamageString.replaceAll('d', ' * '); + } else if (game.settings.get('sla-mothership', 'critDamage') === 'weaponValue') { + critMod = ' + ' + weapon.system.critDmg + '[' + dsnTheme + ']'; + } else if (game.settings.get('sla-mothership', 'critDamage') === 'none') { + //do nothing + } + } + //flavor text = the attack roll result + if (parsedRollResult.success === true) { + //if success + const targetContext = this.getSlaPrimaryTargetContext(); + if (targetContext) { + targetingResult = await this.applySlaTargetedDamage({ + weapon, + parsedDamageString, + targetContext, + ammoContext, + isCritical: Boolean(parsedRollResult.critical) + }); + } + if (weapon.system.damage === "Str/10" && this.type === 'character') { + //determine the damage string + flavorText = 'You strike your target for [[floor((' + this.system.stats.strength.value + ' + ' + (Number(this.system.stats.strength.mod) || 0) + ')/10)]] damage.'; + } else if (targetingResult) { + flavorText = `You hit ${targetingResult.targetName} for ${targetingResult.finalDamage} damage after armour.`; + } else { + flavorText = 'You inflict [[' + parsedDamageString + '[' + dsnTheme + ']' + critMod + ']] points of damage.'; + } + } else if (parsedRollResult.success === false && this.type === 'character') { + //if first edition + if (firstEdition) { + //if calm not enabled + if (!useCalm) { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let addStress = await this.modifyActor('system.other.stress.value', 1, null, false); + flavorText = addStress[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } else { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false); + flavorText = removeCalm[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } + //if 0e + } else { + //if calm not enabled + if (!useCalm) { + //on Save failure + if (attribute === 'sanity' || attribute === 'fear' || attribute === 'body' || attribute === 'armor') { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //gain 1 stress + let addStress = await this.modifyActor('system.other.stress.value', 1, null, false); + flavorText = addStress[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } + } else { + //on Save failure + if (attribute === 'sanity' || attribute === 'fear' || attribute === 'body' || attribute === 'armor') { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //gain 1 stress + let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false); + flavorText = removeCalm[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } + } + } + } + if (ammoUsage) { + const roundLabel = ammoUsage.shots === 1 ? 'round' : 'rounds'; + const ammoPrefix = `${ammoUsage.label} fire with ${ammoUsage.ammoLabel} spent ${ammoUsage.shots} ${roundLabel}. Magazine ${ammoUsage.loaded}/${weapon.system.shots}. Reserve ${ammoUsage.reserve}. Ammo cost ${ammoUsage.totalCost} cR. ${ammoUsage.ammoRule}`; + const accountingText = ammoAccounting + ? ` Credits now ${ammoAccounting.newCredits} cR. Running ammo spend ${ammoAccounting.spendTotal} cR.` + : ""; + flavorText = flavorText ? `${ammoPrefix}${accountingText}
${flavorText}` : `${ammoPrefix}${accountingText}`; + } + //determine if this roll needs a description area + if (weapon.system.description || weapon.system.woundEffect) { + needsDesc = true; + } + //create wound effect string + if (ammoContext?.woundEffect || weapon.system.woundEffect) { + woundEffect = this.renderSlaWoundEffect(ammoContext?.woundEffect || weapon.system.woundEffect); + } + //prepare flavor text for special rolls + } else if (specialRoll) { + //rest save + if (specialRoll === 'restSave') { + //override message header + msgHeader = game.i18n.localize("Mosh.RestSave"); + //override header image + msgImgPath = `systems/sla-mothership/images/icons/ui/macros/rest_save.png`; + //prepare attribute label + attributeLabel = this.system.stats[attribute].label; + //1e rest save + if (firstEdition) { + //calm outcome + if (useCalm) { + //prep text based on success or failure + if (parsedRollResult.success === false && this.type === 'character') { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false); + flavorText = removeCalm[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } else if (parsedRollResult.success === true && this.type === 'character') { + //calculate stress reduction + let onesValue = Number(String(parsedRollResult.total).charAt(String(parsedRollResult.total).length - 1)); + //decrease stress by ones place of roll value and retrieve the flavor text from the result + let removeStress = await this.modifyActor('system.other.stress.value', onesValue, null, false); + flavorText = removeStress[1]; + } + //no calm outcome + } else { + //prep text based on success or failure + if (parsedRollResult.success === false && this.type === 'character') { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let addStress = await this.modifyActor('system.other.stress.value', 1, null, false); + flavorText = addStress[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } else if (parsedRollResult.success === true && this.type === 'character') { + //calculate stress reduction + let onesValue = -1 * Number(String(parsedRollResult.total).charAt(String(parsedRollResult.total).length - 1)); + //decrease stress by ones place of roll value and retrieve the flavor text from the result + let removeStress = await this.modifyActor('system.other.stress.value', onesValue, null, false); + flavorText = removeStress[1]; + } + } + //0e rest save + } else { + //calm outcome + if (useCalm) { + //prep text based on success or failure + if (parsedRollResult.success === false && this.type === 'character') { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false); + flavorText = removeCalm[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } else if (parsedRollResult.success === true && this.type === 'character') { + //calculate stress reduction + let succeedBy = Math.floor((rollTarget - parsedRollResult.total) / 10); + //double it if critical + if (parsedRollResult.critical) { + succeedBy = succeedBy * 2; + } + //decrease stress by ones place of roll value and retrieve the flavor text from the result + let removeStress = await this.modifyActor('system.other.stress.value', succeedBy, null, false); + flavorText = removeStress[1]; + } + //no calm outcome + } else { + //prep text based on success or failure + if (parsedRollResult.success === false && this.type === 'character') { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let addStress = await this.modifyActor('system.other.stress.value', 1, null, false); + flavorText = addStress[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } else if (parsedRollResult.success === true && this.type === 'character') { + //calculate stress reduction + let succeedBy = -1 * Math.floor((rollTarget - parsedRollResult.total) / 10); + //double it if critical + if (parsedRollResult.critical) { + succeedBy = succeedBy * 2; + } + //decrease stress by ones place of roll value and retrieve the flavor text from the result + let removeStress = await this.modifyActor('system.other.stress.value', succeedBy, null, false); + flavorText = removeStress[1]; + } + } + } + } + //bankruptcy save + if (specialRoll === 'bankruptcySave') { + //message header + msgHeader = game.i18n.localize("Mosh.BankrupcySave"); + //set header image + msgImgPath = 'systems/sla-mothership/images/icons/ui/rolltables/bankruptcy_save.png'; + //prepare attribute label + attributeLabel = game.i18n.localize("Mosh.Bankrupcy"); + //get the bankruptcy table + let tableId = game.settings.get('sla-mothership','table1eBankruptcy'); + //get Table Data + let tableData = await fromIdUuid(tableId,{type:"RollTable"}); + //prep text for success + if (parsedRollResult.success && parsedRollResult.critical) { + //flavor text + flavorText = tableData.getResultsForRoll(0)[0].description; + //prep text for critical success + } else if (parsedRollResult.success && !parsedRollResult.critical) { + //flavor text + flavorText = tableData.getResultsForRoll(1)[0].description; + //prep text for failure + } else if (!parsedRollResult.success && !parsedRollResult.critical) { + //flavor text + flavorText = tableData.getResultsForRoll(2)[0].description; + //prep text for critical failure + } else if (!parsedRollResult.success && parsedRollResult.critical) { + //flavor text + flavorText = tableData.getResultsForRoll(3)[0].description; + } + } + //morale check + if (specialRoll === 'moraleCheck') { + //message header + msgHeader = game.i18n.localize("Mosh.MoraleCheck") + //set header image + msgImgPath = 'systems/sla-mothership/images/icons/ui/macros/morale_check.png'; + //prepare attribute label + attributeLabel = 'Megadamage'; + //prep text based on success or failure + if (!parsedRollResult.success) { + //flavor text + flavorText = `The crew, once focused on their tasks, now exchange anxious glances as the reality of the situation set in. Struggling to maintain composure in the chaos, the crew decides to send a hail and hope for mercy.`; + } else { + //flavor texattributes/ + flavorText = `As the ship shudders under the impact of enemy fire, a sense of urgency fills the control room. Alarms blare, emergency lights bath the crew in a stark glow, but there is no panic. The crew, seasoned and unyielding, maintain their focus on the task at hand.`; + } + } + //prepare flavor text for regular checks + } else { + //prepare attribute label + attributeLabel = this.system.stats[attribute].label; + //message header + msgHeader = isSlaEbbSkill + ? `${String(attackContext?.ebbSkillName ?? skill ?? this.system.stats[attribute].label).trim()} Ebb Check` + : this.system.stats[attribute].rollLabel; + //set header image + msgImgPath = attackContext?.skillImg || ('systems/sla-mothership/images/icons/ui/attributes/' + attribute + '.png'); + //prep text based on success or failure + if (parsedRollResult.success === false && this.type === 'character') { + if (isSlaEbbSkill) { + if (parsedRollResult.critical === true) { + ebbCriticalFearSave = true; + flavorText = `${String(attackContext?.ebbSkillName ?? skill ?? "Ebb discipline").trim()} catastrophically backlashes. Make a Fear control save to keep the channel from breaking into panic.`; + } else { + const ebbStress = await this.modifyActor('system.other.stress.value', 1, null, false); + flavorText = ebbStress?.[1] ?? `${String(attackContext?.ebbSkillName ?? skill ?? "Ebb discipline").trim()} fails and the backlash adds 1 Stress.`; + } + } + else + //if first edition + if (firstEdition) { + //if calm not enabled + if (!useCalm) { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let addStress = await this.modifyActor('system.other.stress.value', 1, null, false); + flavorText = addStress[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } else { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //increase stress by 1 and retrieve the flavor text from the result + let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false); + flavorText = removeCalm[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } + //if 0e + } else { + //if calm not enabled + if (!useCalm) { + //on Save failure + if (attribute === 'sanity' || attribute === 'fear' || attribute === 'body' || attribute === 'armor') { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //gain 1 stress + let addStress = await this.modifyActor('system.other.stress.value', 1, null, false); + flavorText = addStress[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } + } else { + if (game.settings.get('sla-mothership', 'autoStress')) { //If the automatic stress option is enabled + //gain 1 stress + let removeCalm = await this.modifyActor('system.other.stress.value', null, '-1d10', false); + flavorText = removeCalm[1]; + } + //if critical failure, make sure to ask for panic check + if (parsedRollResult.critical === true) { + //set crit fail + critFail = true; + } + } + } + if (!flavorText && isSlaEbbSkill) { + flavorText = `${String(attackContext?.ebbSkillName ?? skill ?? "Ebb discipline").trim()} slips out of alignment and the channel fails to resolve cleanly.`; + } + } else if (parsedRollResult.success === true && this.type === 'character') { + //flavor text = generic roll success + if (isSlaEbbSkill && parsedRollResult.critical === true) { + flavorText = `${String(attackContext?.ebbSkillName ?? skill ?? "Ebb discipline").trim()} critically succeeds. Numeric damage or healing from this Ebb use is doubled. If the result is non-numeric, the GM should enhance the effect.`; + } else { + flavorText = isSlaEbbSkill + ? `${String(attackContext?.ebbSkillName ?? skill ?? "Ebb discipline").trim()} resolves cleanly through the Ebb.` + : this.getFlavorText('attribute', attribute, 'check'); + } + } + } + //generate chat message + //prepare data + let messageData = { + actor: this, + parsedRollResult: parsedRollResult, + skill: skill, + skillValue: skillValue, + weapon: weapon, + msgHeader: msgHeader, + msgImgPath: msgImgPath, + outcomeVerb: outcomeVerb, + attribute: attributeLabel, + flavorText: flavorText, + comparisonText: comparisonText, + needsDesc: needsDesc, + woundEffect: woundEffect, + critFail: critFail, + criticalFailureTable: criticalFailureTable, + criticalSuccessOptions: criticalSuccessOptions, + ammoUsage: ammoUsage, + ammoAccounting: ammoAccounting, + isSlaEbbSkill: isSlaEbbSkill, + skillCategory: String(attackContext?.skillCategory ?? "").trim(), + ebbTier: String(attackContext?.ebbTier ?? "").trim(), + fluxCost: Math.max(0, Number(attackContext?.fluxCost ?? 0) || 0), + rollBreakdown: effectiveRollBreakdown, + targetingResult: targetingResult, + firstEdition: game.settings.get('sla-mothership', 'firstEdition'), + useCalm: game.settings.get('sla-mothership', 'useCalm'), + androidPanic: game.settings.get('sla-mothership', 'androidPanic') + }; + //prepare template + messageTemplate = 'systems/sla-mothership/templates/chat/rollCheck.html'; + //render template + messageContent = await foundry.applications.handlebars.renderTemplate(messageTemplate, messageData); + //make message + let macroMsg = await rollResult.toMessage({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + //is DSN active? + if (game.modules.get("dice-so-nice") && game.modules.get("dice-so-nice").active) { + //log what was done + console.log(`Rolled a check on: ${attribute}, with: rollString:${rollString}, aimFor:${aimFor}, skill:${skill}, skillValue:${skillValue}.`); + try { + await Promise.race([ + game.dice3d.waitFor3DAnimationByMessageID(chatId), + new Promise((resolve) => setTimeout(resolve, 2000)) + ]); + } catch (err) { + console.warn("sla-mothership | Dice So Nice animation wait failed or timed out", err); + } + } + if (ebbCriticalFearSave) { + const fearSaveResult = await this.rollSlaSaveWithResult("fear", { + label: `${String(attackContext?.ebbSkillName ?? skill ?? "Ebb").trim()}: Critical Failure Fear Save`, + description: `This Ebb roll critically failed. Make a Fear control save to resist panic backlash.` + }); + if (fearSaveResult && fearSaveResult.success === false) { + await this.rollTable("panicCheck", null, null, null, null, null, null); + } + } + return [messageData]; + } + + //central function to modify actors | TAKES 'system.other.stress.value',-1,'-1d5',true | RETURNS change details, and optional chat message + async modifyActor(fieldAddress, modValue, modRollString, outputChatMsg) { + //init vars + let messageTemplate = ``; + let messageContent = ``; + let fieldPrefix = ``; + let getWound = false; + let msgHeader = ``; + let msgImgPath = ``; + let modifyMinimum = null; + let modifyMaximum = null; + let modifyCurrent = null; + let modifyChange = 0; + let modifyNew = null; + let modifyDifference = null; + let modifySurplus = null; + let msgAction = ``; + let msgFlavor = ``; + let msgOutcome = ``; + let msgChange = ``; + let chatId = foundry.utils.randomID(); + let halfDamage = false; + let firstEdition = game.settings.get('sla-mothership', 'firstEdition'); + let useCalm = game.settings.get('sla-mothership', 'useCalm'); + let androidPanic = game.settings.get('sla-mothership', 'androidPanic'); + const applyIncomingDamageMultiplier = () => { + if (fieldAddress !== "system.health.value" || modifyChange >= 0) return; + const multiplier = SLADrugSystem.getDamageTakenMultiplier(this); + if (multiplier >= 1) return; + modifyChange = -Math.ceil(Math.abs(modifyChange) * multiplier); + }; + //get information about this field from the actor + //set path for important fields + //field value + let fieldValue = fieldAddress.split('.'); + //fieldMin + let fieldMin = fieldAddress.split('.'); + fieldMin.pop(); + fieldMin.push("min"); + //fieldMax + let fieldMax = fieldAddress.split('.'); + fieldMax.pop(); + fieldMax.push("max"); + //fieldLabel + let fieldLabel = fieldAddress.split('.'); + fieldLabel.pop(); + fieldLabel.push("label"); + //fieldId + let fieldId = fieldValue[fieldValue.length - 2]; + //get min value for this field, if it exists + modifyMinimum = fieldMin.reduce((a, v) => a[v], this); + //get max value for this field, if it exists + modifyMaximum = fieldMax.reduce((a, v) => a[v], this); + //get current value for this field + modifyCurrent = fieldValue.reduce((a, v) => a[v], this); + //check to see if this is a min/max part of a main field + if (fieldAddress.slice(-3) === `min`) { + fieldPrefix = `Minimum `; + } else if (fieldAddress.slice(-3) === `max`) { + fieldPrefix = `Maximum `; + } + //calculate the change, whether from a value, roll (can only be one, it will check modValue first) + //apply the modValue directly with no roll + if (modValue) { + //update modChange + modifyChange = modValue; + applyIncomingDamageMultiplier(); + //calculate impact to the actor + //set the new value + modifyNew = modifyCurrent + modifyChange; + //restrict new value based on min/max + //cap min + if (modifyMinimum || modifyMinimum === 0) { + if (modifyNew < modifyMinimum) { + modifyNew = modifyMinimum; + } + } + //cap max + if (modifyMaximum || modifyMaximum === 0) { + if (modifyNew > modifyMaximum) { + modifyNew = modifyMaximum; + } + } + //measure difference between old and new value + modifyDifference = modifyNew - modifyCurrent; + //measure any surplus if we exceeded min/max + modifySurplus = modifyChange - modifyDifference; + //if health hits zero, reset to next hp bar + if (firstEdition && fieldId === 'health' && modifyNew === 0 && this.system.hits.value < this.system.hits.max) { + //set marker for later + getWound = true; + //reset hp + if (this.system.hits.value + 1 < this.system.hits.max) { + modifyNew = modifyMaximum + modifySurplus; + } + } + //update actor + //prepare update JSON + let updateData = JSON.parse(`{"` + fieldAddress + `": ` + modifyNew + `}`); + //update field + this.update(updateData); + //create modification text (for chat message or return values) + //get flavor text + if (modifyChange > 0) { + msgFlavor = this.getFlavorText('attribute', fieldId, 'increase'); + msgChange = 'increased'; + msgHeader = fieldPrefix + this.getFlavorText('attribute', fieldId, 'increaseHeader'); + msgImgPath = this.getFlavorText('attribute', fieldId, 'increaseImg'); + } else if (modifyChange < 0) { + msgFlavor = this.getFlavorText('attribute', fieldId, 'decrease'); + msgChange = 'decreased'; + msgHeader = fieldPrefix + this.getFlavorText('attribute', fieldId, 'decreaseHeader'); + msgImgPath = this.getFlavorText('attribute', fieldId, 'decreaseImg'); + } + //detect if half damage has been taken + if (!firstEdition && (-1 * modifyChange) > (modifyMaximum / 2)) { + halfDamage = true; + } + //get modification description + //calculate change type + if (modifySurplus < 0 && modifyDifference === 0) { + msgAction = 'pastFloor'; + } else if (modifySurplus > 0 && modifyDifference === 0) { + msgAction = 'pastCeiling'; + } else if (modifySurplus === 0 && modifyNew === modifyMinimum && modifyChange != 0) { + msgAction = 'hitFloor'; + } else if (modifySurplus === 0 && modifyNew === modifyMaximum && modifyChange != 0) { + msgAction = 'hitCeiling'; + } else if (modifyChange > 0) { + msgAction = 'increase'; + } else if (modifyChange < 0) { + msgAction = 'decrease'; + } + //prepare flavor text + //set message outcome for health reaches zero or goes past it, and you have wounds remaining + if (getWound) { + //can this player take a wound and not die? + if (this.system.hits.value === this.system.hits.max) { + //you are dead! + msgOutcome = this.getFlavorText('attribute', 'hits', 'hitCeiling'); + } else if (this.system.hits.value + 1 === this.system.hits.max) { + //you are wounded! + msgOutcome = game.i18n.localize("Mosh.HealthZeroMessage") + `

` + this.getFlavorText('attribute', 'hits', 'increase'); + } else { + //you are wounded! + msgOutcome = game.i18n.localize("Mosh.HealthZeroMessage") + ` ${modifyNew}.

` + this.getFlavorText('attribute', 'hits', 'increase'); + } + //set message outcome for past ceiling or floor + } else if (msgAction === 'pastFloor' || msgAction === 'pastCeiling') { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction); + //set message outcome for stress going from < 20 to > 20 + } else if (fieldId === 'stress' && modifyCurrent < modifyMaximum && modifySurplus > 0) { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction) + ` ` + fieldPrefix + fieldLabel.reduce((a, v) => a[v], this) + ` ` + msgChange + ` from ${modifyCurrent} to ${modifyNew}. Reduce the most relevant Stat or Save by ${modifySurplus}.`; + //set message outcome for stress going from 20 to > 20 + } else if (fieldId === 'stress' && modifyCurrent === modifyMaximum && modifySurplus > 0) { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction) + ` Reduce the most relevant Stat or Save by ${modifySurplus}.`; + //set default message outcome + } else if (msgAction === 'increase' || msgAction === 'decrease') { + msgOutcome = fieldPrefix + fieldLabel.reduce((a, v) => a[v], this) + ` ` + msgChange + ` from ${modifyCurrent} to ${modifyNew}.`; + } else { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction) + ` ` + fieldPrefix + fieldLabel.reduce((a, v) => a[v], this) + ` ` + msgChange + ` from ${modifyCurrent} to ${modifyNew}.`; + } + //push message if asked + if (outputChatMsg) { + //generate chat message + //prepare data + let messageData = { + actor: this, + msgHeader: msgHeader, + msgImgPath: msgImgPath, + msgFlavor: msgFlavor, + msgOutcome: msgOutcome, + halfDamage: halfDamage + }; + //prepare template + messageTemplate = 'systems/sla-mothership/templates/chat/modifyActor.html'; + //render template + messageContent = await foundry.applications.handlebars.renderTemplate(messageTemplate, messageData); + //push message + ChatMessage.create({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + } + //log what was done + console.log(`Modified actor: ${this.name}, with: fieldAddress:${fieldAddress}, modValue:${modValue}, modRollString:${modRollString}, outputChatMsg:${outputChatMsg}`); + //return modification values + return [msgFlavor, msgOutcome, msgChange]; + //calculate change from the modRollString + } else { + //roll the dice + //parse the roll string + let parsedRollString = this.parseRollString(modRollString, 'low'); + //roll the dice + let rollResult = await new Roll(parsedRollString).evaluate(); + //interpret the results + let parsedRollResult = this.parseRollResult(modRollString, rollResult, false, false, null, null, null); + //update modChange + modifyChange = modifyChange + parsedRollResult.total; + applyIncomingDamageMultiplier(); + //calculate impact to the actor + //set the new value + modifyNew = modifyCurrent + modifyChange; + //restrict new value based on min/max + //cap min + if (modifyMinimum || modifyMinimum === 0) { + if (modifyNew < modifyMinimum) { + modifyNew = modifyMinimum; + } + } + //cap max + if (modifyMaximum || modifyMaximum === 0) { + if (modifyNew > modifyMaximum) { + modifyNew = modifyMaximum; + } + } + //measure difference between old and new value + modifyDifference = modifyNew - modifyCurrent; + //measure any surplus if we exceeded min/max + modifySurplus = modifyChange - modifyDifference; + //if health hits zero, reset to next hp bar + if (firstEdition && fieldId === 'health' && modifyNew === 0 && this.system.hits.value < this.system.hits.max) { + //set marker for later + getWound = true; + //reset hp + if (this.system.hits.value + 1 < this.system.hits.max) { + modifyNew = modifyMaximum + modifySurplus; + } + } + //update actor + //prepare update JSON + let updateData = JSON.parse(`{"` + fieldAddress + `": ` + modifyNew + `}`); + //update field + this.update(updateData); + //create modification text (for chat message or return values) + //get flavor text + if (modifyChange > 0) { + msgFlavor = this.getFlavorText('attribute', fieldId, 'increase'); + msgChange = 'increased'; + msgHeader = fieldPrefix + this.getFlavorText('attribute', fieldId, 'increaseHeader'); + msgImgPath = this.getFlavorText('attribute', fieldId, 'increaseImg'); + } else if (modifyChange < 0) { + msgFlavor = this.getFlavorText('attribute', fieldId, 'decrease'); + msgChange = 'decreased'; + msgHeader = fieldPrefix + this.getFlavorText('attribute', fieldId, 'decreaseHeader'); + msgImgPath = this.getFlavorText('attribute', fieldId, 'decreaseImg'); + } + //detect if half damage has been taken + if (!firstEdition && (-1 * modifyChange) > (modifyMaximum / 2)) { + halfDamage = true; + } + //get modification description + //calculate change type + if (modifySurplus < 0 && modifyDifference === 0) { + msgAction = 'pastFloor'; + } else if (modifySurplus > 0 && modifyDifference === 0) { + msgAction = 'pastCeiling'; + } else if (modifySurplus === 0 && modifyNew === modifyMinimum && modifyChange != 0) { + msgAction = 'hitFloor'; + } else if (modifySurplus === 0 && modifyNew === modifyMaximum && modifyChange != 0) { + msgAction = 'hitCeiling'; + } else if (modifyChange > 0) { + msgAction = 'increase'; + } else if (modifyChange < 0) { + msgAction = 'decrease'; + } + //set message outcome for health reaches zero or goes past it, and you have wounds remaining + if (getWound) { + //can this player take a wound and not die? + if (this.system.hits.value === this.system.hits.max) { + //you are dead! + msgOutcome = this.getFlavorText('attribute', 'hits', 'hitCeiling'); + } else if (this.system.hits.value + 1 === this.system.hits.max) { + //you are wounded! + msgOutcome = game.i18n.localize("Mosh.HealthZeroMessage") + `

` + this.getFlavorText('attribute', 'hits', 'increase'); + } else { + //you are wounded! + msgOutcome = game.i18n.localize("Mosh.HealthZeroMessage2") +` ${modifyNew}.

` + this.getFlavorText('attribute', 'hits', 'increase'); + } + //set message outcome for past ceiling or floor + } else if (msgAction === 'pastFloor' || msgAction === 'pastCeiling') { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction); + //set message outcome for stress going from < 20 to > 20 + } else if (fieldId === 'stress' && modifyCurrent < modifyMaximum && modifySurplus > 0) { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction) + ` ` + fieldPrefix + fieldLabel.reduce((a, v) => a[v], this) + ` ` + msgChange + ` from ${modifyCurrent} to ${modifyNew}. Reduce the most relevant Stat or Save by ${modifySurplus}.`; + //set message outcome for stress going from 20 to > 20 + } else if (fieldId === 'stress' && modifyCurrent === modifyMaximum && modifySurplus > 0) { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction) + ` Reduce the most relevant Stat or Save by ${modifySurplus}.`; + //set default message outcome + } else if (msgAction === 'increase' || msgAction === 'decrease') { + msgOutcome = fieldPrefix + fieldLabel.reduce((a, v) => a[v], this) + ` ` + msgChange + ` from ${modifyCurrent} to ${modifyNew}.`; + } else { + msgOutcome = this.getFlavorText('attribute', fieldId, msgAction) + ` ` + fieldPrefix + fieldLabel.reduce((a, v) => a[v], this) + ` ` + msgChange + ` from ${modifyCurrent} to ${modifyNew}.`; + } + //push message if asked + if (outputChatMsg) { + //generate chat message + //prepare data + let messageData = { + actor: this, + parsedRollResult: parsedRollResult, + msgHeader: msgHeader, + msgImgPath: msgImgPath, + msgFlavor: msgFlavor, + modRollString: modRollString, + msgOutcome: msgOutcome, + halfDamage: halfDamage + }; + //prepare template + messageTemplate = 'systems/sla-mothership/templates/chat/modifyActor.html'; + //render template + messageContent = await foundry.applications.handlebars.renderTemplate(messageTemplate, messageData); + //make message + let macroMsg = await rollResult.toMessage({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + if (game.modules.get("dice-so-nice") && game.modules.get("dice-so-nice").active) { + //log what was done + console.log(`Modified actor: ${this.name}, with: fieldAddress:${fieldAddress}, modValue:${modValue}, modRollString:${modRollString}, outputChatMsg:${outputChatMsg}`); + //return modification values + return [msgFlavor, msgOutcome, msgChange]; + //wait for dice + await game.dice3d.waitFor3DAnimationByMessageID(chatId); + } + } + //log what was done + console.log(`Modified actor: ${this.name}, with: fieldAddress:${fieldAddress}, modValue:${modValue}, modRollString:${modRollString}, outputChatMsg:${outputChatMsg}`); + //return modification values + return [msgFlavor, msgOutcome, msgChange]; + } + } + + //central function to modify an actors items | TAKES 'olC4JytslvUrQN8g',1 | RETURNS change details, and optional chat message + async modifyItem(itemId, addAmount) { + //init vars + let currentLocation = ''; + let itemLocation = ''; + let messageTemplate = ``; + let messageContent = ``; + let oldValue = 0; + let newValue = 0; + let flavorText = ``; + let chatId = foundry.utils.randomID(); + //get item data + let itemData = await fromIdUuid(itemId,{type:"Item"}); + //add or increase the count of the item, depending on type, if the actor has it + if (this.items.getName(itemData.name)) { + //if this is an item, increase the count + if (itemData.type === 'item') { + //get current quantity + oldValue = this.items.getName(itemData.name).system.quantity; + newValue = oldValue + addAmount; + //increase severity of the condition + this.items.getName(itemData.name).update({ + 'system.quantity': newValue + }); + //create message text + flavorText = `Quantity has increased from ` + oldValue + ` to ` + newValue + `.`; + //if this is a condition, increase the severity + } else if (itemData.type === 'condition') { + //get current severity + oldValue = this.items.getName(itemData.name).system.severity; + newValue = oldValue + addAmount; + //increase severity of the condition + this.items.getName(itemData.name).update({ + 'system.severity': newValue + }); + //create message text + flavorText = this.getFlavorText('item', 'condition', 'increase') + `Severity has increased from ` + oldValue + ` to ` + newValue + `.`; + //if this is a weapon or armor, add another one + } else if (itemData.type === 'weapon' || itemData.type === 'armor') { + //add item to the players inventory + await this.createEmbeddedDocuments('Item', [itemData]); + //create message text + flavorText = game.i18n.localize("Mosh.YouAddAnotherOfThisToYourInventory"); + } + } else { + //if this is an item, add it + if (itemData.type === 'item') { + //give the character the item + await this.createEmbeddedDocuments('Item', [itemData]); + //increase severity of the condition + this.items.getName(itemData.name).update({ + 'system.quantity': addAmount + }); + //create message text + flavorText = `You add ` + addAmount + ` of these to your inventory.`; + //if this is a condition, add it + } else if (itemData.type === 'condition') { + //give the character the item + await this.createEmbeddedDocuments('Item', [itemData]); + //increase severity of the condition + this.items.getName(itemData.name).update({ + 'system.severity': addAmount + }); + //create message text + flavorText = this.getFlavorText('item', 'condition', 'add') + `, with a severity of ` + addAmount + `.`; + //if this is a weapon or armor, add it + } else if (itemData.type === 'weapon' || itemData.type === 'armor') { + //add item to the players inventory + await this.createEmbeddedDocuments('Item', [itemData]); + //create message text + flavorText = game.i18n.localize("Mosh.YouAddThisToYourInventory"); + } else if (itemData.type === 'skill' ) { + //add item to the players inventory + await this.createEmbeddedDocuments('Item', [itemData]); + //create message text + flavorText = game.i18n.localize("Mosh.YouLearnThisSkill"); + } + } + //generate chat message + //get item name + let msgHeader = itemData.name; + //get item image + let msgImgPath = itemData.img; + //prepare data + let messageData = { + actor: this, + item: itemData, + msgHeader: msgHeader, + msgImgPath: msgImgPath, + flavorText: flavorText + }; + //prepare template + messageTemplate = 'systems/sla-mothership/templates/chat/modifyItem.html'; + //render template + messageContent = await foundry.applications.handlebars.renderTemplate(messageTemplate, messageData); + //make message + ChatMessage.create({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + //log what was done + console.log(`Modified item: ${itemData.name} belonging to actor: ${this.name}, by: addAmount:${addAmount}`); + } + + getWeaponFireModes(weapon) { + const system = weapon?.system ?? {}; + const raw = String(system?.sla?.fireModes ?? "").trim(); + const rofText = String(system?.sla?.rofText ?? system?.rofText ?? "").toLowerCase(); + const shotsPerFire = Math.max(1, Number(system?.shotsPerFire ?? 1) || 1); + const special = String(system?.sla?.special ?? "").toLowerCase(); + const name = String(weapon?.name ?? ""); + const modes = []; + + for (const chunk of raw.split(/[\n,]+/)) { + const entry = chunk.trim(); + if (!entry) continue; + const match = entry.match(/^(.+?)(?:\s*[:=|-]\s*|\s*\(\s*)(\d+)\)?$/); + if (!match) { + const inferredShots = this.inferWeaponModeShots(entry, shotsPerFire, rofText); + if (!inferredShots) continue; + modes.push({ + label: entry.replace(/\s+/g, " ").trim().replace(/\bfull auto\b/i, "Auto"), + shots: inferredShots + }); + continue; + } + modes.push({ + label: match[1].trim(), + shots: Math.max(1, Number(match[2]) || 1) + }); + } + + const staleSingleMode = modes.length === 1 + && modes[0].label.toLowerCase() === "single" + && modes[0].shots === 1 + && (special.includes("auto") || special.includes("burst") || rofText.includes("burst") || rofText.includes("auto") || this.inferAutomaticWeaponShots(name) > 1); + + const parsedModes = modes.length && !staleSingleMode + ? modes + : this.deriveWeaponModeDefaults( + Math.max(shotsPerFire, this.inferAutomaticWeaponShots(name)), + special, + rofText, + name + ); + + return parsedModes.filter((mode, index, list) => + list.findIndex((entry) => entry.label === mode.label && entry.shots === mode.shots) === index + ); + } + + inferAutomaticWeaponShots(name = "") { + const text = String(name ?? "").toLowerCase(); + if (/lmg|machine gun|minigun/.test(text)) return 6; + if (/assault rifle|fen\s*ar|smg|machine pistol|auto-shotgun|reaper/.test(text)) return 3; + return 1; + } + + inferWeaponModeShots(label = "", shotsPerFire = 1, rofText = "") { + const normalized = String(label ?? "").toLowerCase(); + if (normalized.includes("single") || normalized.includes("semi")) return 1; + if (normalized.includes("double") || normalized.includes("2 shots")) return Math.max(2, shotsPerFire); + if (normalized.includes("burst")) return Math.max(3, shotsPerFire); + if (normalized.includes("auto")) { + if (rofText.includes("full auto")) return Math.max(6, shotsPerFire); + return Math.max(3, shotsPerFire); + } + return 0; + } + + deriveWeaponModeDefaults(shotsPerFire = 1, special = "", rofText = "", name = "") { + const modes = [{ label: "Single", shots: 1 }]; + const text = `${special} ${rofText}`.toLowerCase(); + const inferredShots = this.inferAutomaticWeaponShots(name); + const effectiveShots = Math.max(shotsPerFire, inferredShots); + + if (text.includes("2 shots") || text.includes("2/round")) { + modes.push({ label: "Double", shots: 2 }); + } + if (text.includes("burst") || (special.includes("auto") && effectiveShots >= 3)) { + modes.push({ label: "Burst", shots: Math.max(3, effectiveShots) }); + } else if (effectiveShots === 2) { + modes.push({ label: "Double", shots: 2 }); + } else if (effectiveShots > 2) { + modes.push({ label: "Burst", shots: effectiveShots }); + } + if (text.includes("full auto") || special.includes("auto")) { + modes.push({ label: "Auto", shots: Math.max(text.includes("full auto") ? 6 : effectiveShots, 3) }); + } + + return modes; + } + + getActiveWeaponFireMode(weapon) { + const modes = this.getWeaponFireModes(weapon); + const currentMode = String(weapon?.system?.sla?.currentFireMode ?? "").trim().toLowerCase(); + return modes.find((mode) => mode.label.toLowerCase() === currentMode) ?? modes[0]; + } + + normalizeAmmoTag(tag = "STD") { + const normalized = String(tag ?? "").trim().toUpperCase(); + return SLA_AMMO_TYPES[normalized] ? normalized : "STD"; + } + + getWeaponReserveKey(tag = "STD") { + return SLA_AMMO_RESERVE_KEYS[this.normalizeAmmoTag(tag)] ?? SLA_AMMO_RESERVE_KEYS.STD; + } + + getWeaponAmmoCalibre(weapon) { + return String(weapon?.system?.ammoCalibre ?? weapon?.system?.ammoType ?? "").trim(); + } + + getActorAmmoItemsForWeapon(weapon, { ammoTag = null } = {}) { + const calibre = this.getWeaponAmmoCalibre(weapon); + const desiredTag = ammoTag ? this.normalizeAmmoTag(ammoTag) : null; + const allowedTags = new Set(this.getWeaponAllowedAmmoTags(weapon)); + return Array.from(this.items ?? []).filter((item) => { + if (item.type !== "item") return false; + if (String(item.system?.sla?.category ?? "").trim().toLowerCase() !== "ammunition") return false; + const itemCalibre = String(item.system?.sla?.calibre ?? "").trim(); + if (calibre && itemCalibre && itemCalibre !== calibre) return false; + const tag = this.normalizeAmmoTag(item.system?.sla?.ammoTag ?? "STD"); + if (!allowedTags.has(tag)) return false; + if (desiredTag && tag !== desiredTag) return false; + return true; + }); + } + + hasInventoryAmmoForWeapon(weapon) { + return this.getActorAmmoItemsForWeapon(weapon).length > 0; + } + + getAmmoItemQuantity(item) { + return Math.max(0, Number(item?.system?.quantity ?? 0) || 0); + } + + getWeaponReserveForTag(weapon, tag = "STD") { + if (this.hasInventoryAmmoForWeapon(weapon)) { + return this.getActorAmmoItemsForWeapon(weapon, { ammoTag: tag }) + .reduce((total, item) => total + this.getAmmoItemQuantity(item), 0); + } + const key = this.getWeaponReserveKey(tag); + const fallback = this.normalizeAmmoTag(tag) === "STD" ? weapon?.system?.ammo : 0; + return Math.max(0, Number(weapon?.system?.[key] ?? fallback ?? 0) || 0); + } + + setWeaponReserveForTag(weapon, tag = "STD", value = 0) { + weapon.system[this.getWeaponReserveKey(tag)] = Math.max(0, Number(value ?? 0) || 0); + weapon.system.ammoReserve = this.getWeaponReserveTotal(weapon); + weapon.system.ammo = weapon.system.ammoReserve; + } + + getWeaponReserveTotal(weapon) { + if (this.hasInventoryAmmoForWeapon(weapon)) { + return this.getWeaponAllowedAmmoTags(weapon) + .reduce((total, tag) => total + this.getWeaponReserveForTag(weapon, tag), 0); + } + return ["STD", "AP", "HE", "HEAP"].reduce((total, tag) => total + this.getWeaponReserveForTag(weapon, tag), 0); + } + + getWeaponAllowedAmmoTags(weapon) { + const allowed = []; + if (weapon?.system?.ammoAllowStd !== false) allowed.push("STD"); + if (weapon?.system?.ammoAllowAp !== false) allowed.push("AP"); + if (weapon?.system?.ammoAllowHe !== false) allowed.push("HE"); + if (weapon?.system?.ammoAllowHeap !== false) allowed.push("HEAP"); + return allowed.length ? allowed : ["STD"]; + } + + getWeaponAmmoContext(weapon, ammoTag = null) { + const tag = this.normalizeAmmoTag(ammoTag ?? weapon?.system?.ammoLoadedType ?? weapon?.system?.ammoTag ?? "STD"); + const profile = SLA_AMMO_TYPES[tag] ?? SLA_AMMO_TYPES.STD; + const baseCost = Math.max(0, Number(weapon?.system?.ammoBaseCost ?? 0) || 0); + return { + tag, + label: profile.label, + summary: profile.summary, + damageBonus: profile.damageBonus, + woundEffect: profile.woundEffect, + costPerRound: baseCost ? Math.round(baseCost * Number(profile.multiplier ?? 1)) : 0 + }; + } + + applyWeaponAmmoDamageModifier(formula, ammoContext = null) { + const cleanFormula = String(formula ?? "").trim(); + const bonus = String(ammoContext?.damageBonus ?? "").trim(); + if (!bonus) return cleanFormula; + if (!cleanFormula) return bonus; + if (bonus.startsWith("-")) return `(${cleanFormula})${bonus}`; + return `(${cleanFormula})+${bonus}`; + } + + async reloadWeaponData(item, ammoTag = null) { + if (!item?.system?.useAmmo) return null; + const selectedTag = this.normalizeAmmoTag(ammoTag ?? item.system.ammoLoadedType ?? item.system.ammoTag ?? "STD"); + const currentLoadedTag = this.normalizeAmmoTag(item.system.ammoLoadedType ?? item.system.ammoTag ?? "STD"); + const magazineSize = Math.max(0, Number(item.system.shots ?? 0) || 0); + let currentShots = Math.max(0, Number(item.system.curShots ?? 0) || 0); + let returnedRounds = 0; + const availableRounds = this.getWeaponReserveForTag(item, selectedTag); + + if (selectedTag !== currentLoadedTag && currentShots > 0 && availableRounds <= 0) { + return null; + } + + if (selectedTag !== currentLoadedTag && currentShots > 0) { + returnedRounds = currentShots; + await this.addAmmoToInventory(item, currentLoadedTag, currentShots); + currentShots = 0; + } + + const capacityRemaining = Math.max(0, magazineSize - currentShots); + const reloadAmount = Math.min(availableRounds, capacityRemaining); + if (reloadAmount <= 0 && currentShots <= 0) { + item.system.curShots = 0; + item.system.ammoLoadedType = selectedTag; + item.system.ammoTag = selectedTag; + item.system.ammo = this.getWeaponReserveTotal(item); + item.system.ammoReserve = item.system.ammo; + return null; + } + + if (reloadAmount > 0) { + await this.consumeAmmoFromInventory(item, selectedTag, reloadAmount); + } + + item.system.curShots = currentShots + reloadAmount; + item.system.ammoLoadedType = selectedTag; + item.system.ammoTag = selectedTag; + item.system.ammo = this.getWeaponReserveTotal(item); + item.system.ammoReserve = item.system.ammo; + return { + reloadAmount, + ammoTag: selectedTag, + totalLoaded: item.system.curShots, + returnedRounds, + swapped: returnedRounds > 0 && selectedTag !== currentLoadedTag, + reserveAfter: this.getWeaponReserveForTag(item, selectedTag) + }; + } + + getWeaponAmmoChoices(weapon) { + const activeTag = this.normalizeAmmoTag(weapon?.system?.ammoLoadedType ?? weapon?.system?.ammoTag ?? "STD"); + return this.getWeaponAllowedAmmoTags(weapon).map((tag) => { + const context = this.getWeaponAmmoContext(weapon, tag); + const reserve = this.getWeaponReserveForTag(weapon, tag); + const calibre = this.getWeaponAmmoCalibre(weapon) || weapon?.system?.ammoType || "Unknown calibre"; + return { + tag, + label: `${calibre} ${context.label} | carried ${reserve} | ${context.costPerRound} cR/round`, + reserve, + selected: tag === activeTag, + summary: context.summary + }; + }).filter((choice) => choice.reserve > 0 || choice.selected); + } + + async addAmmoToInventory(weapon, ammoTag = "STD", quantity = 0) { + const amount = Math.max(0, Number(quantity ?? 0) || 0); + if (!amount) return null; + const tag = this.normalizeAmmoTag(ammoTag); + const existing = this.getActorAmmoItemsForWeapon(weapon, { ammoTag: tag })[0]; + if (existing) { + await this.updateEmbeddedDocuments("Item", [{ + _id: existing.id, + "system.quantity": this.getAmmoItemQuantity(existing) + amount + }]); + return existing.id; + } + + const ammoContext = this.getWeaponAmmoContext(weapon, tag); + const calibre = this.getWeaponAmmoCalibre(weapon) || weapon?.system?.ammoType || "Unknown"; + const created = await this.createEmbeddedDocuments("Item", [{ + name: `Ammo: ${calibre} [${ammoContext.label}]`, + type: "item", + img: weapon?.img || "icons/commodities/metal/bullets-cartridge-shell-gray.webp", + system: { + quantity: amount, + weight: 0, + cost: ammoContext.costPerRound, + description: `

Calibre: ${calibre}

Ammo type: ${ammoContext.label}

Recovered from weapon reload.

`, + sla: { + category: "Ammunition", + calibre, + ammoTag: tag, + source: "Reload return" + } + } + }]); + return created?.[0]?.id ?? null; + } + + async consumeAmmoFromInventory(weapon, ammoTag = "STD", quantity = 0) { + let remaining = Math.max(0, Number(quantity ?? 0) || 0); + if (!remaining) return 0; + const updates = []; + for (const item of this.getActorAmmoItemsForWeapon(weapon, { ammoTag })) { + if (remaining <= 0) break; + const available = this.getAmmoItemQuantity(item); + if (!available) continue; + const spent = Math.min(available, remaining); + remaining -= spent; + updates.push({ + _id: item.id, + "system.quantity": available - spent + }); + } + if (updates.length) { + await this.updateEmbeddedDocuments("Item", updates); + } + return Math.max(0, Number(quantity ?? 0) || 0) - remaining; + } + + getSkillBreakdown(skill) { + const total = Number(skill?.system?.bonus ?? 0) || 0; + const description = String(skill?.system?.description ?? ""); + const categoryMatch = description.match(/Category:\s*([^<\n]+)/i); + const baseMatch = description.match(/base:\s*(\d+)%/i); + const baseBonus = Number(skill?.system?.sla?.baseBonus ?? baseMatch?.[1] ?? 0) || 0; + const speciesBonus = Number(skill?.system?.sla?.speciesBonus ?? 0) || 0; + const packageBonus = Number(skill?.system?.sla?.packageBonus ?? Math.max(0, total - baseBonus - speciesBonus)) || 0; + const miscBonus = Math.max(0, total - baseBonus - packageBonus - speciesBonus); + const category = String(skill?.system?.sla?.category ?? categoryMatch?.[1] ?? "").trim(); + const parts = [ + category ? `Category: ${category}` : null, + `Base ${baseBonus}%`, + packageBonus ? `Package +${packageBonus}` : null, + speciesBonus ? `Species +${speciesBonus}` : null, + miscBonus ? `Other +${miscBonus}` : null + ].filter(Boolean); + + return { + total, + baseBonus, + packageBonus, + speciesBonus, + miscBonus, + category, + summary: parts.join(" | ") + }; + } + + getSlaConditionEffectiveSeverity(condition) { + const severity = Math.max(0, Number(condition?.system?.severity ?? 0) || 0); + const treatment = Math.max(0, Number(condition?.system?.treatment?.value ?? 0) || 0); + return Math.max(0, severity - treatment); + } + + getSlaConditionRollModifier({ attribute = "", skillName = "" } = {}) { + const attributeKey = String(attribute ?? "").trim().toLowerCase(); + const skillKey = normalizeSlaConditionLabel(skillName); + const parts = []; + let total = 0; + + for (const condition of this.items.filter((item) => item.type === "condition")) { + const effectiveSeverity = this.getSlaConditionEffectiveSeverity(condition); + if (effectiveSeverity <= 0) continue; + + const sla = condition.system?.sla ?? {}; + const scaleWithSeverity = sla.scaleWithSeverity !== false; + const multiplier = scaleWithSeverity ? effectiveSeverity : 1; + let applied = 0; + const detail = []; + + const statMods = sla.statMods ?? {}; + if (attributeKey && Number(statMods?.[attributeKey] ?? 0)) { + const value = (Number(statMods[attributeKey]) || 0) * multiplier; + if (value) { + applied += value; + detail.push(`${attributeKey} ${value >= 0 ? "+" : ""}${value}`); + } + } + + const skillMods = Array.isArray(sla.skillMods) ? sla.skillMods : []; + for (const entry of skillMods) { + const entrySkill = normalizeSlaConditionLabel(entry?.skill ?? ""); + if (!entrySkill || !skillKey || entrySkill !== skillKey) continue; + const value = (Number(entry?.value ?? 0) || 0) * multiplier; + if (!value) continue; + applied += value; + detail.push(`${entry.skill} ${value >= 0 ? "+" : ""}${value}`); + } + + if (!applied) continue; + total += applied; + parts.push({ + condition: condition.name, + severity: effectiveSeverity, + value: applied, + detail: detail.join(" | ") + }); + } + + return { total, parts }; + } + + async chooseWeaponAttackOptions(weapon) { + const fireModes = this.getWeaponFireModes(weapon); + const activeFireMode = this.getActiveWeaponFireMode(weapon); + const ammoChoices = this.getWeaponAmmoChoices(weapon); + + return new Promise((resolve) => { + const fireOptions = fireModes.map((mode) => ` + + `).join(""); + const ammoOptions = ammoChoices.map((choice) => ` + + `).join(""); + + const dialogData = { + window: { + title: `${weapon.name} Attack Setup` + }, + content: ` +
+
+ + +
+
+ + +
+
+ `, + buttons: [ + { + label: "Fire", + action: "fire", + icon: "fas fa-bullseye", + callback: (_event, button) => { + const fireLabel = button.form.querySelector("select[name='fireMode']")?.value ?? activeFireMode.label; + const fireMode = fireModes.find((mode) => mode.label === fireLabel) ?? activeFireMode; + const ammoTag = button.form.querySelector("select[name='ammoTag']")?.value ?? ammoChoices[0]?.tag ?? "STD"; + resolve({ + fireMode: fireMode.label, + shotsPerFire: fireMode.shots, + ammoTag + }); + } + }, + { + label: "Cancel", + action: "cancel", + icon: "fas fa-times", + callback: () => resolve(null) + } + ], + close: () => resolve(null) + }; + new foundry.applications.api.DialogV2(dialogData).render({ force: true }); + }); + } + + async rollWeaponAttack(weapon) { + const attackContext = weapon?.system?.useAmmo ? await this.chooseWeaponAttackOptions(weapon) : {}; + if (weapon?.system?.useAmmo && !attackContext) return; + return this.rollCheck(null, 'low', 'combat', null, null, weapon, null, attackContext ?? {}); + } + + async cycleWeaponFireMode(itemId, direction = 1) { + const item = foundry.utils.duplicate(this.getEmbeddedDocument('Item', itemId)); + if (!item?.system?.useAmmo) return null; + + item.system.sla ??= {}; + const modes = this.getWeaponFireModes(item); + if (!modes.length) return null; + + const currentLabel = String(item.system.sla.currentFireMode ?? "").trim().toLowerCase(); + const currentIndex = Math.max(0, modes.findIndex((mode) => mode.label.toLowerCase() === currentLabel)); + const nextIndex = (currentIndex + direction + modes.length) % modes.length; + const nextMode = modes[nextIndex]; + + item.system.sla.fireModes ??= modes.map((mode) => `${mode.label}:${mode.shots}`).join(", "); + item.system.sla.currentFireMode = nextMode.label; + item.system.shotsPerFire = nextMode.shots; + + await this.updateEmbeddedDocuments('Item', [item]); + ui.notifications.info(`${item.name}: ${nextMode.label} (${nextMode.shots} round${nextMode.shots === 1 ? '' : 's'})`); + return nextMode; + } + + async chooseWeaponReloadAmmo(weapon) { + const ammoChoices = this.getWeaponAmmoChoices(weapon); + if (!ammoChoices.length) return null; + if (ammoChoices.length === 1) return ammoChoices[0].tag; + + return new Promise((resolve) => { + const currentTag = this.normalizeAmmoTag(weapon?.system?.ammoLoadedType ?? weapon?.system?.ammoTag ?? "STD"); + const calibre = this.getWeaponAmmoCalibre(weapon) || weapon?.system?.ammoType || "Unknown calibre"; + const ammoOptions = ammoChoices.map((choice) => ` + + `).join(""); + + const dialogData = { + window: { + title: `${weapon.name} Reload` + }, + content: ` +
+
+ +
${calibre}
+
+
+ +
${Number(weapon?.system?.curShots ?? 0) || 0}/${Number(weapon?.system?.shots ?? 0) || 0} ${currentTag}
+
+
+ + +
+
+ `, + buttons: [ + { + label: "Reload", + action: "reload", + icon: "fas fa-sync", + callback: (_event, button) => { + const ammoTag = button.form.querySelector("select[name='ammoTag']")?.value ?? currentTag; + resolve(ammoTag); + } + }, + { + label: "Cancel", + action: "cancel", + icon: "fas fa-times", + callback: () => resolve(null) + } + ], + close: () => resolve(null) + }; + new foundry.applications.api.DialogV2(dialogData).render({ force: true }); + }); + } + + async promptWeaponReload(itemId) { + const weapon = foundry.utils.duplicate(this.getEmbeddedDocument("Item", itemId)); + if (!weapon?.system?.useAmmo) return null; + const selectedAmmoTag = await this.chooseWeaponReloadAmmo(weapon); + if (!selectedAmmoTag) return null; + return this.reloadWeapon(itemId, selectedAmmoTag); + } + + async reloadAllCompatibleWeapons() { + const weapons = Array.from(this.items ?? []).filter((item) => item.type === "weapon" && item.system?.useAmmo); + let reloaded = 0; + let skipped = 0; + + for (const weaponDoc of weapons) { + const weapon = foundry.utils.duplicate(weaponDoc); + const currentTag = this.normalizeAmmoTag(weapon?.system?.ammoLoadedType ?? weapon?.system?.ammoTag ?? "STD"); + const hasCurrent = this.getWeaponReserveForTag(weapon, currentTag) > 0; + const chosenTag = hasCurrent ? currentTag : (this.getWeaponAmmoChoices(weapon)[0]?.tag ?? null); + if (!chosenTag) { + skipped += 1; + continue; + } + + const beforeShots = Math.max(0, Number(weapon.system?.curShots ?? 0) || 0); + await this.reloadWeapon(weaponDoc.id, chosenTag); + const refreshed = this.getEmbeddedDocument("Item", weaponDoc.id); + const afterShots = Math.max(0, Number(refreshed?.system?.curShots ?? 0) || 0); + if (afterShots > beforeShots || this.normalizeAmmoTag(refreshed?.system?.ammoLoadedType ?? "STD") !== currentTag) { + reloaded += 1; + } else { + skipped += 1; + } + } + + ui.notifications.info(`Reload all complete. ${reloaded} weapon${reloaded === 1 ? "" : "s"} updated, ${skipped} skipped.`); + return { reloaded, skipped }; + } + + //ask the player if we want to reload + async askReload(itemId) { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //create final dialog data + const dialogData = { + window: { + title: game.i18n.localize("Mosh.WeaponIssue") + }, + classes: ["macro-popup-dialog"], + content: `
` + game.i18n.localize("Mosh.OutOfAmmoNeedReload") + `
`, + buttons: [ + { + label: game.i18n.localize("Mosh.Reload"), + action: `action_reload`, + callback: () => this.promptWeaponReload(itemId), + icon: `fas fa-check` + }, + { + label: `Cancel`, + action: `action_cancel`, + callback: () => {}, + icon: `fas fa-times` + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + }); + //log what was done + slaDebug(`Asked for reload.`); + } + + //tell the player we are out of ammo + async outOfAmmo() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //create final dialog data + const dialogData = { + window: { + title: game.i18n.localize("Mosh.WeaponIssue") + }, + classes: ["macro-popup-dialog"], + content: `
` + game.i18n.localize("Mosh.OutOfAmmo") + `
`, + buttons: [ + { + label: game.i18n.localize("Mosh.OK"), + action: `action_okay`, + callback: () => {}, + icon: 'fas fa-check' + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + }); + //log what was done + slaDebug(`Told user they are out of ammo.`); + } + + //reload the players weapon + async reloadWeapon(itemId, ammoTag = null) { + //init vars + let messageTemplate = ``; + let messageContent = ``; + let msgBody = ``; + let chatId = foundry.utils.randomID(); + //dupe item to work with + var item; + item = foundry.utils.duplicate(this.getEmbeddedDocument('Item', itemId)); + //reload + if (!item.system.useAmmo) { + //exit function (it should not be possible to get here) + return; + } else { + const currentLoadedTag = this.normalizeAmmoTag(item.system.ammoLoadedType ?? item.system.ammoTag ?? "STD"); + const selectedAmmoTag = this.normalizeAmmoTag(ammoTag ?? currentLoadedTag); + const changingAmmo = selectedAmmoTag !== currentLoadedTag; + //are we at full shots already? + if (item.system.curShots === item.system.shots && !changingAmmo) { + //log what was done + slaDebug(`Can't reload, already at full shots.`); + //exit function (it should not be possible to get here) + return; + //are we out of ammo? + } else if (!this.getWeaponReserveForTag(item, selectedAmmoTag)) { + //tell player we are out of ammo + let t = await this.outOfAmmo(); + //log what was done + slaDebug(`Can't reload, no ammo left.`); + //exit function + return; + } else { + const reloadOutcome = await this.reloadWeaponData(item, selectedAmmoTag); + if (!reloadOutcome) { + let t = await this.outOfAmmo(); + return; + } + await this.updateEmbeddedDocuments('Item', [item]); + const calibre = this.getWeaponAmmoCalibre(item) || item.system.ammoType || "Unknown calibre"; + const swappedText = reloadOutcome.swapped + ? ` Swapped out ${reloadOutcome.returnedRounds} round${reloadOutcome.returnedRounds === 1 ? "" : "s"} of ${currentLoadedTag}.` + : ""; + msgBody = `${game.i18n.localize("Mosh.WeaponReloaded")} ${reloadOutcome.reloadAmount} round${reloadOutcome.reloadAmount === 1 ? "" : "s"} of ${calibre} ${selectedAmmoTag}. Magazine ${reloadOutcome.totalLoaded}/${item.system.shots}. Reserve ${reloadOutcome.reserveAfter}.${swappedText}`; + } + } + //generate chat message + //prepare data + let messageData = { + actor: this, + item: item, + msgBody: msgBody + }; + //prepare template + messageTemplate = 'systems/sla-mothership/templates/chat/reload.html'; + //render template + messageContent = await foundry.applications.handlebars.renderTemplate(messageTemplate, messageData); + //push message + ChatMessage.create({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + //log what was done + slaDebug(`Reloaded weapon.`); + } + + //make the player take bleeding damage + async takeBleedingDamage() { + //init vars + let chatId = foundry.utils.randomID(); + //determine bleeding amount + let healthLost = this.items.getName("Bleeding").system.severity * -1; + //run the function for the player's 'Selected Character' + let modification = await this.modifyActor('system.health.value', healthLost, null, false); + //get flavor text + let msgFlavor = this.getFlavorText('item', 'condition', 'bleed'); + let msgOutcome = modification[1]; + let healthLostText = game.i18n.localize("Mosh.attribute.health.decreaseHeader.human") + //create chat message text + let messageContent = ` +
+
+
+
${healthLostText}
+
+
+
+
+ ${msgFlavor} +

+ ${msgOutcome} +
+
+
+
+ `; + //push message + ChatMessage.create({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + //log what was done + console.log(`Took bleeding damage.`); + } + + //make the player take radiation damage + async takeRadiationDamage() { + //init vars + let chatId = foundry.utils.randomID(); + //reduce all stats and saves by 1 + this.modifyActor('system.stats.strength.value', -1, null, false); + this.modifyActor('system.stats.speed.value', -1, null, false); + this.modifyActor('system.stats.intellect.value', -1, null, false); + this.modifyActor('system.stats.combat.value', -1, null, false); + this.modifyActor('system.stats.sanity.value', -1, null, false); + this.modifyActor('system.stats.fear.value', -1, null, false); + this.modifyActor('system.stats.body.value', -1, null, false); + //get flavor text + let msgFlavor = this.getFlavorText('item', 'condition', 'radiation'); + let msgOutcome = game.i18n.localize('Mosh.AllStatsAndSavesDecreasedBy'); + msgOutcome += ` 1.`; + let radiationDamage = game.i18n.localize('Mosh.RadiationDamage'); + + //create chat message text + let messageContent = ` +
+
+
+
${radiationDamage}
+
+
+
+
+ ${msgFlavor} +

+ ${msgOutcome} +
+
+
+
+ `; + //push message + ChatMessage.create({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + //log what was done + console.log(`Took radiation damage.`); + } + + //make the player take radiation damage + async takeCryoDamage(rollString) { + //init vars + let chatId = foundry.utils.randomID(); + //roll the dice + //parse the roll string + let parsedRollString = this.parseRollString(rollString, 'low'); + //roll the dice + let rollResult = await new Roll(parsedRollString).evaluate(); + //interpret the results + let parsedRollResult = this.parseRollResult(rollString, rollResult, false, false, null, null, null); + //reduce all stats and saves by roll result + this.modifyActor('system.stats.strength.value', parsedRollResult.total, null, false); + this.modifyActor('system.stats.speed.value', parsedRollResult.total, null, false); + this.modifyActor('system.stats.intellect.value', parsedRollResult.total, null, false); + this.modifyActor('system.stats.combat.value', parsedRollResult.total, null, false); + this.modifyActor('system.stats.sanity.value', parsedRollResult.total, null, false); + this.modifyActor('system.stats.fear.value', parsedRollResult.total, null, false); + this.modifyActor('system.stats.body.value', parsedRollResult.total, null, false); + //get flavor text + let msgFlavor = this.getFlavorText('item', 'condition', 'cryo'); + let msgOutcome = game.i18n.localize('Mosh.AllStatsAndSavesDecreasedBy'); + msgOutcome += ` ` + Math.abs(parsedRollResult.total).toString() + `.`; + let cryoDamage = game.i18n.localize("Mosh.CryofreezeDamage") + //create chat message text + let messageContent = ` +
+
+
+
${cryoDamage}
+
+
+
+
+ ${msgFlavor} +

+ ${msgOutcome} +
+
+
+
+ `; + //push message + ChatMessage.create({ + id: chatId, + user: game.user.id, + speaker: { + actor: this.id, + token: this.token, + alias: this.name + }, + content: messageContent + }, { + keepId: true + }); + //log what was done + console.log(`Took cryofreeze damage.`); + } + + //ask the player to choose cover + async chooseCover() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //init vars + let none_checked = ``; + let insignificant_checked = ``; + let light_checked = ``; + let heavy_checked = ``; + //fetch character AP/DR/cover + let curAP = this.system.stats.armor.mod; + let curDR = this.system.stats.armor.damageReduction; + let curCover = this.system.stats.armor.cover; + //set checkbox to current cover + adjust curAP/DR + if (curCover === 'none') { + none_checked = `checked`; + } + if (curCover === 'insignificant') { + insignificant_checked = `checked`; + } + if (curCover === 'light') { + light_checked = `checked`; + } + if (curCover === 'heavy') { + heavy_checked = `checked`; + } + + //create pop-up HTML + let msgContent = await foundry.applications.handlebars.renderTemplate('systems/sla-mothership/templates/dialogs/choose-cover-dialog.html', { + curDR:curDR, + curAP:curAP, + none_checked: none_checked, + insignificant_checked:insignificant_checked, + light_checked:light_checked, + heavy_checked:heavy_checked, + curCover:curCover + }); + + //create final dialog data + const dialogData = { + window: {title: game.i18n.localize("Mosh.Cover")}, + classes: ["macro-popup-dialog"], + position: {width: 600}, + content: msgContent, + buttons: [ + { + label: game.i18n.localize("Mosh.OK"), + action: `action_okay`, + callback: (event, button, dialog) => { + this.update({ + 'system.stats.armor.cover': button.form.querySelector("input[name='cover']:checked")?.getAttribute("value") + }); + console.log(`User's cover is now:${button.form.querySelector("input[name='cover']:checked")?.getAttribute("value")}`); + }, + icon: 'fas fa-check' + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + + }); + + } + + async chooseSlaWoundTable() { + return new Promise(async (resolve) => { + const woundTables = [ + { key: 'table1eWoundBluntForce', label: 'Blunt Force' }, + { key: 'table1eWoundBleeding', label: 'Bleeding' }, + { key: 'table1eWoundGunshot', label: 'Gunshot' }, + { key: 'table1eWoundFireExplosives', label: 'Fire & Explosives' }, + { key: 'table1eWoundGoreMassive', label: 'Gore & Massive' } + ]; + + const dialogData = { + window: { title: 'Choose Wound Table' }, + classes: ['macro-popup-dialog'], + position: { width: 660, height: 260 }, + content: `

Select the wound table to roll for this operative.

`, + buttons: woundTables.map((entry) => ({ + label: entry.label, + action: entry.key, + callback: async () => { + const tableId = game.settings.get('sla-mothership', entry.key); + if (!tableId) { + ui.notifications.warn(`No wound table is configured for ${entry.label}.`); + return resolve(null); + } + const tableData = await resolveSlaWoundTableBySetting(entry.key); + if (!tableData) { + ui.notifications.warn(`The ${entry.label} wound table could not be found.`); + return resolve(null); + } + await this.rollTable(tableData.uuid ?? tableData.id ?? tableId, null, null, null, null, null, null); + resolve(entry.key); + } + })) + }; + + dialogData.buttons.push({ + label: 'Cancel', + action: 'cancel', + callback: () => resolve(null) + }); + + new foundry.applications.api.DialogV2(dialogData).render({ force: true }); + }); + } + + //activate ship's distress signal + async distressSignal() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //create pop-up HTML + let msgContent = await foundry.applications.handlebars.renderTemplate('systems/sla-mothership/templates/dialogs/distres-signal-dialog.html'); + + //create final dialog data + const dialogData = { + window: {title: game.i18n.localize("Mosh.DistressSignal")}, + classes: ["macro-popup-dialog"], + position: {width: 600,height: 265}, + content: msgContent, + buttons: [ + { + label: game.i18n.localize("Mosh.Advantage"), + action: `action_advantage`, + callback: () => this.rollTable(game.settings.get('sla-mothership', 'table1eDistressSignal'), `1d10 [+]`, `low`, true, false, null, null), + icon: `fas fa-angle-double-up` + }, + { + label: game.i18n.localize("Mosh.Normal"), + action: `action_normal`, + callback: () => this.rollTable(game.settings.get('sla-mothership', 'table1eDistressSignal'), `1d10`, `low`, true, false, null, null), + icon: `fas fa-minus` + }, + { + label: game.i18n.localize("Mosh.Disadvantage"), + action: `action_disadvantage`, + callback: () => this.rollTable(game.settings.get('sla-mothership', 'table1eDistressSignal'), `1d10 [-]`, `low`, true, false, null, null), + icon: `fas fa-angle-double-down` + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + + }); + + } + + //activate ship's distress signal + async maintenanceCheck() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //create pop-up HTML + let msgContent = ` + + `; + //create final dialog data + const dialogData = { + window: {title: game.i18n.localize("Mosh.MaintenanceCheck")}, + classes: ["macro-popup-dialog"], + position: {width: 600,height: 265}, + content: msgContent, + buttons: [ + { + label: game.i18n.localize("Mosh.Advantage"), + action: `action_advantage`, + callback: () => this.rollTable(`maintenanceCheck`, `1d100 [+]`, `low`, null, null, null, null), + icon: `fas fa-angle-double-up` + }, + { + label: game.i18n.localize("Mosh.Normal"), + action: `action_normal`, + callback: () => this.rollTable(`maintenanceCheck`, `1d100`, `low`, null, null, null, null), + icon: `fas fa-minus` + }, + { + label: game.i18n.localize("Mosh.Disadvantage"), + action: `action_disadvantage`, + callback: () => this.rollTable(`maintenanceCheck`, `1d100 [-]`, `low`, null, null, null, null), + icon: `fas fa-angle-double-down` + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + + }); + + } + + //activate ship's distress signal + async bankruptcySave() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //create pop-up HTML + let msgContent = ` + + `; + //create final dialog data + const dialogData = { + window: {title: game.i18n.localize("Mosh.BankrupcySave")}, + classes: ["macro-popup-dialog"], + position: {width: 600,height: 265}, + content: msgContent, + buttons: [ + { + label: game.i18n.localize("Mosh.Advantage"), + action: `action_advantage`, + callback: () => this.rollCheck(`1d100 [+]`, `low`, `bankruptcySave`, null, null, null), + icon: `fas fa-angle-double-up` + }, + { + label: game.i18n.localize("Mosh.Normal"), + action: `action_normal`, + callback: () => this.rollCheck(`1d100`, `low`, `bankruptcySave`, null, null, null), + icon: `fas fa-minus` + }, + { + label: game.i18n.localize("Mosh.Disadvantage"), + action: `action_disadvantage`, + callback: () => this.rollCheck(`1d100 [-]`, `low`, `bankruptcySave`, null, null, null), + icon: `fas fa-angle-double-down` + } + ] + }; + //render dialog + new foundry.applications.api.DialogV2(dialogData).render({force: true}); + + }); + + } + + //activate ship's distress signal + async moraleCheck() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //create pop-up HTML + + let moraleCheck = game.i18n.localize("Mosh.MoraleCheck") + let moraleCheckDescription = game.i18n.localize("Mosh.MoraleCheckDescription") + + let msgContent = ` + +
+
+
+

${moraleCheck}

${moraleCheckDescription}
+
+
+

Select your roll type:

+ `; + //create final dialog data + const dialogData = { + window: {title: `Morale Check`}, + classes: ["macro-popup-dialog"], + position: {width: 600,height: 265}, + content: msgContent, + buttons: [ + { + label: game.i18n.localize("Mosh.Advantage"), + action: `action_advantage`, + callback: () => this.rollCheck(`1d10 [+]`, `high-equal`, `moraleCheck`, null, null, null), + icon: `fas fa-angle-double-up` + }, + { + label: game.i18n.localize("Mosh.Normal"), + action: `action_normal`, + callback: () => this.rollCheck(`1d10`, `high-equal`, `moraleCheck`, null, null, null), + icon: `fas fa-minus` + }, + { + label: game.i18n.localize("Mosh.Disadvantage"), + action: `action_disadvantage`, + callback: () => this.rollCheck(`1d10 [-]`, `high-equal`, `moraleCheck`, null, null, null), + icon: `fas fa-angle-double-down` + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + + }); + + } + + // print description + printDescription(itemId, options = {event: null}) { + var item; + item = foundry.utils.duplicate(this.getEmbeddedDocument('Item', itemId)); + this.chatDesc(item); + } + + hasSlaSpeciesRuleEnabled(ruleKey = "") { + return Boolean(this.system?.sla?.speciesRules?.[ruleKey]?.enabled); + } + + getSlaTrainingPackageName() { + return String(this.system?.sla?.trainingPackage?.value ?? this.system?.class?.value ?? "").trim(); + } + + getSlaTraumaResponseText() { + if (this.type !== "character") return ""; + const species = String(this.system?.sla?.species?.value ?? "").trim(); + const trainingPackage = this.getSlaTrainingPackageName(); + if (!species && !trainingPackage) return ""; + return buildSlaTraumaResponseText(species, trainingPackage); + } + + async refreshSlaTraumaResponse({ force = false } = {}) { + if (this.type !== "character") return null; + const nextText = this.getSlaTraumaResponseText(); + if (!nextText) return null; + const currentText = String(this.system?.other?.stressdesc?.value ?? ""); + if (!force && currentText.trim() === nextText.trim()) { + return nextText; + } + await this.update({ + "system.other.stressdesc.value": nextText + }); + return nextText; + } + + async refreshSlaSkillPresentation() { + if (this.type !== "character") return 0; + const updates = []; + for (const item of this.items ?? []) { + if (item.type !== "skill") continue; + const key = String(item.name ?? "").toLowerCase().replace(/[^a-z0-9]+/g, ""); + const img = SLA_SKILL_IMAGE_OVERRIDES[key]; + const rank = getSlaSkillRankLabel(item.system?.bonus ?? 0); + const metadata = getSlaSkillMetadataForName(item.name, item.system?.sla?.category ?? "") ?? {}; + const update = { _id: item.id }; + let changed = false; + if (img && item.img !== img) { + update.img = img; + changed = true; + } + if (String(item.system?.rank ?? "") !== rank) { + update["system.rank"] = rank; + changed = true; + } + if (metadata.category && String(item.system?.sla?.category ?? "") !== metadata.category) { + update["system.sla.category"] = metadata.category; + update["system.sla.skillFamily"] = metadata.category; + changed = true; + } + if (typeof metadata.combat === "boolean" && Boolean(item.system?.sla?.combat) !== metadata.combat) { + update["system.sla.combat"] = metadata.combat; + changed = true; + } + if (Array.isArray(metadata.attributes)) { + const currentAttributes = Array.isArray(item.system?.sla?.attributes) ? item.system.sla.attributes : []; + const nextAttributes = metadata.attributes; + if (JSON.stringify(currentAttributes) !== JSON.stringify(nextAttributes)) { + update["system.sla.attributes"] = nextAttributes; + changed = true; + } + } + if (changed) { + updates.push(update); + } + } + if (!updates.length) return 0; + await this.updateEmbeddedDocuments("Item", updates); + return updates.length; + } + + async reconcileSlaSpeciesBalance({ force = false } = {}) { + if (this.type !== "character") return null; + + const currentSpecies = String(this.system?.sla?.species?.value ?? "").trim(); + const applied = this.flags?.["sla-mothership"]?.speciesBalance ?? {}; + const appliedSpecies = String(applied?.species ?? "").trim(); + const appliedVersion = String(applied?.version ?? "").trim(); + + if (!force && appliedSpecies === currentSpecies && appliedVersion === SLA_SPECIES_BALANCE_VERSION) { + return null; + } + + const previousAdjustments = appliedVersion ? getSlaSpeciesStatAdjustments(appliedSpecies) : {}; + const nextAdjustments = getSlaSpeciesStatAdjustments(currentSpecies); + const statKeys = new Set([...Object.keys(previousAdjustments), ...Object.keys(nextAdjustments)]); + const updateData = {}; + + for (const key of statKeys) { + const currentValue = Number(this.system?.stats?.[key]?.value ?? 0) || 0; + const restoredValue = currentValue - (Number(previousAdjustments[key] ?? 0) || 0); + const nextValue = Math.max(0, restoredValue + (Number(nextAdjustments[key] ?? 0) || 0)); + if (nextValue !== currentValue) { + updateData[`system.stats.${key}.value`] = nextValue; + } + } + + updateData["flags.sla-mothership.speciesBalance"] = { + version: SLA_SPECIES_BALANCE_VERSION, + species: currentSpecies, + adjustments: nextAdjustments + }; + + await this.update(updateData, { slaSkipSpeciesBalance: true }); + return nextAdjustments; + } + + getSlaSpeciesMinimumWounds() { + const species = String(this.system?.sla?.species?.value ?? "").trim(); + if (["Frother", "Shaktar", "Stormer 313 Malice", "Stormer 711 Xeno"].includes(species)) { + return 3; + } + return 2; + } + + async enforceSlaSpeciesWounds() { + if (this.type !== "character") return null; + const minimumWounds = this.getSlaSpeciesMinimumWounds(); + const currentMax = Math.max(0, Number(this.system?.hits?.max ?? 0) || 0); + if (currentMax >= minimumWounds) return null; + + await this.update({ + "system.hits.max": minimumWounds + }); + return minimumWounds; + } + + getSlaPrometheusStatus(combat = game.combat ?? null) { + const enabled = this.hasSlaSpeciesRuleEnabled("prometheusRegeneration"); + if (!enabled) { + return { + enabled: false, + inCombat: false, + currentRound: 0, + roundsUntilPulse: null, + pulseThisRound: false + }; + } + + const combatant = combat?.combatants?.find?.((entry) => (entry.actor ?? entry.token?.actor)?.id === this.id) ?? null; + const currentRound = Math.max(0, Number(combat?.round ?? 0) || 0); + const inCombat = Boolean(combat?.started && combatant); + if (!inCombat) { + return { + enabled: true, + inCombat: false, + currentRound: 0, + roundsUntilPulse: 4, + pulseThisRound: false + }; + } + + const roundMod = currentRound % 4; + const pulseThisRound = currentRound > 0 && roundMod === 0; + const roundsUntilPulse = pulseThisRound ? 0 : (4 - roundMod); + + return { + enabled: true, + inCombat, + currentRound, + roundsUntilPulse, + pulseThisRound + }; + } + + async applySlaPrometheusRegeneration({ combat = game.combat ?? null } = {}) { + const status = this.getSlaPrometheusStatus(combat); + if (!status.enabled || !status.inCombat || !status.pulseThisRound) return null; + + const lastCombatId = String(this.getFlag("sla-mothership", "prometheusCombatId") ?? ""); + const lastRound = Number(this.getFlag("sla-mothership", "prometheusRound") ?? 0) || 0; + if (lastCombatId === String(combat?.id ?? "") && lastRound === status.currentRound) { + return null; + } + + const regenRoll = await new Roll("1d5").evaluate(); + const recovered = Math.max(0, Number(regenRoll.total ?? 0) || 0); + const rollHtml = await this.renderSlaAbilityRollHtml(regenRoll); + let updateText = ""; + if (recovered > 0) { + const updateResult = await this.modifyActor("system.health.value", recovered, null, false); + updateText = updateResult?.[1] ?? ""; + } + + await this.setFlag("sla-mothership", "prometheusCombatId", String(combat?.id ?? "")); + await this.setFlag("sla-mothership", "prometheusRound", status.currentRound); + + await ChatMessage.create({ + user: game.user.id, + speaker: { actor: this.id, token: this.token, alias: this.name }, + content: ` +
+
Prometheus Regeneration
+
${this.name} triggers Prometheus regeneration on combat round ${status.currentRound}.
+ ${rollHtml} +
Recovered ${recovered} Health.
+ ${updateText ? `
${updateText}
` : ""} +
+ ` + }); + + return { recovered, round: status.currentRound }; + } + + isSlaEbbUser() { + const species = String(this.system?.sla?.species?.value ?? "").trim(); + return ["Ebon", "Brain Waster"].includes(species); + } + + getSlaRestrictedEbbItemIds() { + return this.items + .filter((item) => { + const name = String(item.name ?? "").trim(); + if (item.type === "ability") return true; + if (item.type !== "skill") return false; + return name === "Formulate" || name === "Biofeedback" || name === "Ebb (Core)" || name.startsWith("Ebb "); + }) + .map((item) => item.id); + } + + async enforceSlaEbbEligibility({ notify = false, refillFlux = false } = {}) { + if (this.type !== "character") return { removed: 0 }; + + if (!this.isSlaEbbUser()) { + const restrictedIds = this.getSlaRestrictedEbbItemIds(); + const updateData = { + "system.sla.flux.value": 0, + "system.sla.flux.max": 0, + "system.sla.fluxStage.value": "", + "system.sla.ebbRating.value": 0 + }; + await this.update(updateData); + if (restrictedIds.length) { + await this.deleteEmbeddedDocuments("Item", restrictedIds); + } + if (notify && restrictedIds.length) { + ui.notifications.warn(`${this.name} is not an Ebb user. Restricted Ebb skills and abilities were removed.`); + } + return { removed: restrictedIds.length }; + } + + const currentMax = Math.max(0, Number(this.system?.sla?.flux?.max ?? 0) || 0); + const currentValue = Math.max(0, Number(this.system?.sla?.flux?.value ?? 0) || 0); + const intellect = Number(this.system?.stats?.intellect?.value ?? 0) + Number(this.system?.stats?.intellect?.mod ?? 0); + const targetMax = Math.max(currentMax, Math.max(20, Math.floor(intellect / 4))); + const shouldRefill = refillFlux || currentMax < 20; + const updateData = { + "system.sla.flux.max": targetMax, + "system.sla.flux.value": shouldRefill ? targetMax : Math.min(Math.max(currentValue, 0), targetMax) + }; + await this.update(updateData); + await this.updateSlaFluxState(updateData["system.sla.flux.value"], { save: true }); + return { removed: 0 }; + } + + getSlaAbilityRollAttribute(ability) { + const sla = ability?.system?.sla ?? {}; + const name = String(ability?.name ?? "").trim().toLowerCase(); + const impact = String(sla.impact ?? "").trim().toLowerCase(); + const category = String(sla.skillCategoryRef ?? "").trim().toLowerCase(); + + if (sla.attack || impact === "harm" || category === "combat") return "combat"; + if (name.includes("telekinesis")) return "strength"; + if (name.includes("awareness") || name.includes("senses")) return "speed"; + return "intellect"; + } + + findBestSkillItemByName(skillName = "") { + const target = String(skillName ?? "").trim().toLowerCase(); + if (!target) return null; + return this.items + .filter((item) => item.type === "skill" && String(item.name ?? "").trim().toLowerCase() === target) + .sort((left, right) => (Number(right.system?.bonus ?? 0) || 0) - (Number(left.system?.bonus ?? 0) || 0))[0] ?? null; + } + + getSlaSkillBonusByName(skillName = "") { + const skill = this.findBestSkillItemByName(skillName); + return skill ? Number(skill.system?.bonus ?? 0) || 0 : null; + } + + buildSlaRollBreakdown({ attribute, skillName = "", skillValue = null, supportSkills = [] } = {}) { + const stat = this.system?.stats?.[attribute] ?? {}; + const statLabel = String(stat.label ?? attribute ?? "Attribute").trim(); + const statValue = Number(stat.value ?? 0) || 0; + const statMod = Number(stat.mod ?? 0) || 0; + const resolvedSkillValue = Number(skillValue ?? this.getSlaSkillBonusByName(skillName) ?? 0) || 0; + const parts = [ + { label: statLabel, value: statValue } + ]; + + if (statMod) { + parts.push({ label: `${statLabel} Mod`, value: statMod }); + } + if (skillName) { + parts.push({ label: skillName, value: resolvedSkillValue }); + } + + const conditionImpact = this.getSlaConditionRollModifier({ attribute, skillName }); + for (const impact of conditionImpact.parts) { + parts.push({ + label: `${impact.condition} (${impact.severity})`, + value: impact.value, + note: impact.detail + }); + } + + const support = supportSkills + .map((entry) => { + const label = typeof entry === "string" ? entry : String(entry?.label ?? "").trim(); + if (!label) return null; + const bonus = this.getSlaSkillBonusByName(label); + if (bonus == null) return null; + return { + label, + value: bonus, + note: typeof entry === "string" ? "" : String(entry?.note ?? "").trim() + }; + }) + .filter(Boolean); + + const total = parts.reduce((sum, part) => sum + (Number(part.value ?? 0) || 0), 0); + + return { + parts, + support, + total, + conditionImpact, + formulaText: parts.map((part) => `${part.label} ${part.value >= 0 ? "+" : ""}${part.value}`).join(" + ").replace(/\+\s-/g, "- ") + }; + } + + getSlaEbbSkillAttribute(skillName = "") { + const name = String(skillName ?? "").trim().toLowerCase(); + if (!name) return "intellect"; + if (name.includes("blast") || name.includes("thermal")) return "combat"; + if (name.includes("telekinesis")) return "strength"; + if (name.includes("awareness") || name.includes("senses")) return "speed"; + return "intellect"; + } + + async chooseSlaEbbRollAttribute({ + title = "Choose Ebb Roll Attribute", + defaultAttribute = "intellect", + description = "" + } = {}) { + const options = [ + { key: "intellect", label: this.system?.stats?.intellect?.label ?? "Intellect" }, + { key: "speed", label: this.system?.stats?.speed?.label ?? "Speed" }, + { key: "strength", label: this.system?.stats?.strength?.label ?? "Strength" }, + { key: "combat", label: this.system?.stats?.combat?.label ?? "Combat" } + ]; + + return new Promise((resolve) => { + const radioRows = options + .map((option) => { + const stat = this.system?.stats?.[option.key] ?? {}; + const total = (Number(stat.value ?? 0) || 0) + (Number(stat.mod ?? 0) || 0); + const checked = option.key === defaultAttribute ? "checked" : ""; + return ``; + }) + .join(""); + + new foundry.applications.api.DialogV2({ + window: { title }, + classes: ["macro-popup-dialog"], + content: ` +
+

Choose the attribute for this Ebb roll

+ ${description ? `

${description}

` : ""} + ${radioRows} +
+ `, + buttons: [ + { + label: "Roll", + action: "roll", + icon: "fas fa-bolt", + callback: (_event, button) => { + const selected = button.form?.querySelector("input[name='sla-ebb-attr']:checked")?.value ?? defaultAttribute; + resolve(selected); + } + }, + { + label: "Cancel", + action: "cancel", + icon: "fas fa-times", + callback: () => resolve(null) + } + ], + close: () => resolve(null) + }).render({ force: true }); + }); + } + + async rollSlaEbbSkill(itemId) { + const skill = this.getEmbeddedDocument("Item", itemId); + if (!skill || skill.type !== "skill") return null; + if (!this.isSlaEbbUser()) { + ui.notifications.warn(`${this.name} is not configured as an Ebb user.`); + return null; + } + const defaultAttribute = this.getSlaEbbSkillAttribute(skill.name); + const attribute = await this.chooseSlaEbbRollAttribute({ + title: `${skill.name}: Ebb Attribute`, + defaultAttribute, + description: `Default for ${skill.name} is ${this.system?.stats?.[defaultAttribute]?.label ?? defaultAttribute}. Change it here if you want a different Ebb stat basis.` + }); + if (!attribute) return null; + + return this.rollCheck("1d100", "low", attribute, skill.name, Number(skill.system?.bonus ?? 0) || 0, null, null, { + slaEbbSkill: true, + ebbSkillName: skill.name, + skillImg: skill.img, + skillCategory: String(skill.system?.sla?.category ?? "").trim(), + rollBreakdown: this.buildSlaRollBreakdown({ + attribute, + skillName: skill.name, + skillValue: Number(skill.system?.bonus ?? 0) || 0 + }) + }); + } + + getSlaFormulateSkillBonus() { + const formulate = this.findBestSkillItemByName("Formulate"); + return formulate ? Number(formulate.system?.bonus ?? 0) || 0 : null; + } + + getSlaFluxState(flux = null) { + const currentFlux = Math.max(0, Number(flux ?? this.system?.sla?.flux?.value ?? 0) || 0); + const maxFlux = Math.max(0, Number(this.system?.sla?.flux?.max ?? 0)); + const spentFlux = Math.max(0, maxFlux - currentFlux); + const ratio = maxFlux > 0 ? spentFlux / maxFlux : 0; + if (maxFlux > 0 && ratio > 1) { + return { + index: 4, + label: "Catastrophic", + cssClass: "catastrophic", + thresholds: "25% / 50% / 75% / 100%", + description: "Flux has gone critical. Fear failures should spill directly into panic.", + panicOnFailure: true, + panicEvenOnSuccess: true + }; + } + if (maxFlux > 0 && ratio >= 0.75) { + return { + index: 3, + label: "Breach", + cssClass: "breach", + thresholds: "25% / 50% / 75% / 100%", + description: "Discipline is cracking. Offensive Ebb or failed Fear saves are panic-grade events.", + panicOnFailure: true, + panicEvenOnSuccess: false + }; + } + if (maxFlux > 0 && ratio >= 0.5) { + return { + index: 2, + label: "Frayed", + cssClass: "frayed", + thresholds: "25% / 50% / 75% / 100%", + description: "Flux is unstable. Failed Fear saves on Ebb use should trigger panic.", + panicOnFailure: true, + panicEvenOnSuccess: false + }; + } + if (maxFlux > 0 && ratio >= 0.25) { + return { + index: 1, + label: "Charged", + cssClass: "charged", + thresholds: "25% / 50% / 75% / 100%", + description: "The charge is building. Keep Fear saves clean or the next spike may cascade.", + panicOnFailure: false, + panicEvenOnSuccess: false + }; + } + return { + index: 0, + label: "Stable", + cssClass: "stable", + thresholds: "25% / 50% / 75% / 100%", + description: "Flux is contained and controlled.", + panicOnFailure: false, + panicEvenOnSuccess: false + }; + } + + getSlaFluxGuidance(flux = null) { + const currentFlux = Math.max(0, Number(flux ?? this.system?.sla?.flux?.value ?? 0) || 0); + const maxFlux = Math.max(0, Number(this.system?.sla?.flux?.max ?? 0)); + const state = this.getSlaFluxState(currentFlux); + const guidance = [ + `Current state: ${state.label}. ${state.description}`, + "Fear is the control save when channeling Ebb." + ]; + + if (maxFlux > 0) { + guidance.push(`Flux remaining: ${currentFlux} / ${maxFlux}.`); + guidance.push(`Reserve spent: ${Math.max(0, maxFlux - currentFlux)} / ${maxFlux}. Risk thresholds track spent Flux.`); + } else { + guidance.push("No active Flux reserve is configured on this operative."); + } + + if (state.index >= 3) { + guidance.push("Breach or worse means failed channeling should be treated as immediate Panic fallout."); + } else if (state.index >= 2) { + guidance.push("Frayed Flux means failed Ebb saves should spill into Panic."); + } else { + guidance.push("Below Frayed, Panic is usually only forced by catastrophic spikes or manual checks."); + } + + return guidance; + } + + async updateSlaFluxState(flux = null, { save = true } = {}) { + const currentFlux = Number(flux ?? this.system?.sla?.flux?.value ?? 0); + const state = this.getSlaFluxState(currentFlux); + + if (save) { + await this.update({ + "system.sla.fluxStage.value": this.isSlaEbbUser() ? state.label : "" + }); + } + + return state; + } + + async rollSlaSaveWithResult(saveKey = "fear", { + rollString = "1d100", + aimFor = "low", + label = "Fear / Flux Control Save", + description = "" + } = {}) { + const validSave = ["sanity", "fear", "body", "armor"].includes(saveKey) ? saveKey : "fear"; + const stat = this.system?.stats?.[validSave]; + if (!stat) return null; + + const rollTarget = Number(stat.value ?? 0) + Number(stat.mod ?? 0); + const parsedRollString = this.parseRollString(rollString, aimFor); + const rollResult = await new Roll(parsedRollString).evaluate(); + const comparison = aimFor === "high" ? ">" : aimFor === "high-equal" ? ">=" : aimFor === "low-equal" ? "<=" : "<"; + const parsedRollResult = this.parseRollResult(rollString, rollResult, false, false, rollTarget, comparison, null); + const outcome = parsedRollResult.success ? "Success" : "Failure"; + const flavor = description || `${this.name} attempts a ${label}.`; + + const chatData = { + user: game.user.id, + speaker: { actor: this.id, token: this.token, alias: this.name }, + content: ` +
+
${label}
+
${flavor}
+ ${parsedRollResult.rollHtml} + ${parsedRollResult.outcomeHtml} +
${outcome} against ${rollTarget} (${stat.label}).
+
+ ` + }; + + const rollMode = game.settings.get("core", "rollMode"); + if (["gmroll", "blindroll"].includes(rollMode)) { + chatData.whisper = ChatMessage.getWhisperRecipients("GM"); + } + if (rollMode === "blindroll") { + chatData.blind = true; + } + + await ChatMessage.create(chatData); + return parsedRollResult; + } + + async triggerSlaFluxPanic({ + source = "Flux control check", + panicOnFailure = true, + forcePanic = false + } = {}) { + if (!this.isSlaEbbUser()) { + ui.notifications.warn(`${this.name} is not configured as an Ebb user.`); + return { saveResult: null, state: this.getSlaFluxState(0), panicTriggered: false }; + } + const saveResult = await this.rollSlaSaveWithResult("fear", { + label: "Post-Use Fear / Flux Control Save", + description: source + }); + const state = this.getSlaFluxState(); + const shouldPanic = Boolean(forcePanic || (panicOnFailure && !saveResult?.success && state.panicOnFailure) || state.panicEvenOnSuccess); + if (shouldPanic) { + await this.rollTable("panicCheck", null, null, null, null, null, null); + } + return { saveResult, state, panicTriggered: shouldPanic }; + } + + async chooseSlaAbilityTier(ability) { + const tiers = ability?.system?.sla?.tiers ?? []; + if (!tiers.length) { + return null; + } + if (tiers.length === 1) { + return tiers[0]; + } + + return new Promise((resolve) => { + const buttons = tiers.map((tier) => ({ + action: tier.id ?? tier.label ?? foundry.utils.randomID(), + label: `${tier.label ?? tier.id ?? "Tier"} (${tier.cost ?? ability.system?.sla?.fluxCost ?? 0} Flux)`, + icon: "fas fa-bolt", + callback: () => resolve(tier) + })); + + new foundry.applications.api.DialogV2({ + window: { title: `${ability.name}: choose Ebb tier` }, + classes: ["macro-popup-dialog"], + content: `

Select the Ebb intensity

Higher tiers cost more Flux and carry more panic risk.

`, + buttons, + close: () => resolve(tiers[0]) + }).render({ force: true }); + }); + } + + buildSlaAbilityChatCopy(ability, tier) { + const copy = foundry.utils.duplicate(ability); + const tierData = tier ?? null; + if (!tierData) return copy; + + copy.system.roll = tierData.damage ?? tierData.healing ?? copy.system.roll; + copy.system.sla.fluxCost = Number(tierData.cost ?? copy.system?.sla?.fluxCost ?? 0) || 0; + copy.system.sla.tier = tierData.label ?? tierData.id ?? copy.system?.sla?.tier ?? "basic"; + copy.system.sla.range = tierData.range ?? copy.system?.sla?.range ?? ""; + copy.system.sla.duration = tierData.duration ?? copy.system?.sla?.duration ?? ""; + copy.system.sla.impact = copy.system?.sla?.impact ?? ""; + copy.system.sla.skillCategoryRef = copy.system?.sla?.skillCategoryRef ?? ""; + copy.system.sla.ignoreArmour = Number(tierData.ignoreArmour ?? copy.system?.sla?.ignoreArmour ?? 0) || 0; + const tierEffect = tierData.effect ? `

Chosen Tier: ${copy.system.sla.tier}

${tierData.effect}

` : `

Chosen Tier: ${copy.system.sla.tier}

`; + copy.system.description = `${tierEffect}${copy.system.description ?? ""}`; + return copy; + } + + async useSlaAbility(itemId) { + this._slaAbilityUseLocks ??= new Set(); + if (this._slaAbilityUseLocks.has(itemId)) { + return; + } + + const item = this.getEmbeddedDocument("Item", itemId); + if (!item) return; + this._slaAbilityUseLocks.add(itemId); + try { + if (!this.isSlaEbbUser()) { + ui.notifications.warn(`${this.name} cannot channel Ebb without a Flux track.`); + return; + } + + const tier = await this.chooseSlaAbilityTier(item); + const ability = this.buildSlaAbilityChatCopy(item, tier); + const sla = ability.system?.sla ?? {}; + const fluxCost = Math.max(0, Number(sla.fluxCost ?? 0) || 0); + const primarySkillName = String(sla.skillRef ?? "").trim() || "Formulate"; + const primarySkill = this.findBestSkillItemByName(primarySkillName) ?? this.findBestSkillItemByName("Formulate"); + if (!primarySkill) { + ui.notifications.warn(`${this.name} is missing the required Ebb discipline for ${ability.name}.`); + return; + } + const primarySkillBonus = Number(primarySkill.system?.bonus ?? 0) || 0; + const formulateBonus = this.getSlaFormulateSkillBonus(); + const saveKey = String(sla.panicSave ?? "").trim().toLowerCase(); + const canRollSave = Boolean(sla.rollOnUse === true) && ["sanity", "fear", "body", "armor"].includes(saveKey); + const fluxBefore = Math.max(0, Number(this.system?.sla?.flux?.value ?? 0) || 0); + const fluxMax = Math.max(0, Number(this.system?.sla?.flux?.max ?? 0)); + if (fluxBefore <= 0) { + ui.notifications.warn(`${this.name} has no Flux remaining and cannot channel Ebb.`); + return; + } + if (fluxCost > fluxBefore) { + ui.notifications.warn(`${this.name} does not have enough Flux remaining for ${ability.name}.`); + return; + } + const fluxAfter = Math.max(0, fluxBefore - fluxCost); + + if (fluxCost > 0) { + await this.update({ "system.sla.flux.value": fluxAfter }); + } + const stateAfter = await this.updateSlaFluxState(fluxAfter); + const previousState = this.getSlaFluxState(fluxBefore); + const defaultAttribute = this.getSlaAbilityRollAttribute(ability); + const rollAttribute = await this.chooseSlaEbbRollAttribute({ + title: `${ability.name}: Ebb Attribute`, + defaultAttribute, + description: `Default for ${ability.name} is ${this.system?.stats?.[defaultAttribute]?.label ?? defaultAttribute}. Choose the attribute you want to roll this channel through.` + }); + if (!rollAttribute) { + return; + } + const supportSkills = []; + if (formulateBonus != null && String(primarySkill.name ?? "").trim().toLowerCase() !== "formulate") { + supportSkills.push({ label: "Formulate", note: "support discipline, not added to this target number" }); + } + const coreSkillName = String(sla.coreSkillRef ?? "").trim(); + if (coreSkillName && coreSkillName.toLowerCase() !== String(primarySkill.name ?? "").trim().toLowerCase()) { + supportSkills.push({ label: coreSkillName, note: "core discipline, not added to this target number" }); + } + const rollOutcome = await this.rollCheck("1d100", "low", rollAttribute, primarySkill.name, primarySkillBonus, null, null, { + slaEbbSkill: true, + ebbSkillName: ability.name, + skillImg: ability.img, + skillCategory: String(sla.skillCategoryRef ?? sla.impact ?? "Ebb").trim(), + ebbTier: String(sla.tier ?? "").trim(), + fluxCost, + rollBreakdown: this.buildSlaRollBreakdown({ + attribute: rollAttribute, + skillName: primarySkill.name, + skillValue: primarySkillBonus, + supportSkills + }) + }); + const parsedRollResult = rollOutcome?.[0]?.parsedRollResult ?? null; + + if (parsedRollResult?.success) { + await this.resolveSlaAbilityEffect(ability, { isCriticalSuccess: Boolean(parsedRollResult?.critical) }); + } else if (parsedRollResult?.critical) { + await this.resolveSlaAbilityFumble(ability); + } + + let saveResult = null; + if (canRollSave && parsedRollResult?.success === false && parsedRollResult?.critical === true) { + saveResult = await this.rollSlaSaveWithResult(saveKey, { + label: `${ability.name}: Post-Use ${this.system?.stats?.[saveKey]?.label ?? "Save"}`, + description: `${ability.name} critically failed. This is the post-use ${this.system?.stats?.[saveKey]?.label ?? "control"} save to keep the backlash from becoming panic. Flux remaining: ${fluxAfter}.` + }); + } + + if (saveResult && saveResult.success === false) { + await this.rollTable("panicCheck", null, null, null, null, null, null); + } + } catch (err) { + console.error("sla-mothership | Ebb ability use failed", err); + ui.notifications.error(`Ebb ability failed to resolve: ${item?.name ?? "Unknown ability"}. Check the console for details.`); + } finally { + this._slaAbilityUseLocks.delete(itemId); + } + } + + // Print the item description into the chat. + async chatDesc(item) { + let swapNameDesc = false; + let swapName = ''; + let itemName = item.name?.charAt(0).toUpperCase() + item.name?.toLowerCase().slice(1); + if (!item.name && isNaN(itemName)) { + itemName = item.charAt(0)?.toUpperCase() + item.toLowerCase().slice(1); + } + + let rollInsert = ''; + if (item.system.roll) { + const r = new Roll(item.system.roll, {}); + await r.evaluate(); + rollInsert = ` +
${item.system.roll}
+
+
${r.total}
+
`; + } + + // add flag to swap name and description, if desc contains trinket or patch + if (["

Patch

", "

Trinket

", "

Maintenance Issue

"].includes(item.system.description)) { + swapNameDesc = true; + swapName = item.system.description.replaceAll('

', '').replaceAll('

', ''); + } + + const templateData = { + actor: this, + stat: { name: itemName.toUpperCase() }, + item, + insert: rollInsert, + onlyDesc: true, + swapNameDesc, + swapName + }; + + const chatData = { + user: game.user.id, + speaker: { actor: this.id, token: this.token, alias: this.name } + }; + + const rollMode = game.settings.get("core", "rollMode"); + if (["gmroll", "blindroll"].includes(rollMode)) { + chatData.whisper = ChatMessage.getWhisperRecipients("GM"); + } + + const template = 'systems/sla-mothership/templates/chat/itemRoll.html'; + const content = await foundry.applications.handlebars.renderTemplate(template, templateData); + chatData.content = content; + await ChatMessage.create(chatData); + + console.log(`Created chat message with details on ${item.name}`); + } + +} diff --git a/module/actor/creature-sheet.js b/module/actor/creature-sheet.js new file mode 100644 index 0000000..6a7dd47 --- /dev/null +++ b/module/actor/creature-sheet.js @@ -0,0 +1,661 @@ +/** + * Extend the basic ActorSheet with some very simple modifications + * @extends {ActorSheet} + */ +import { DLCreatureSettings } from "../settings/creature-settings.js"; + +export class MothershipCreatureSheet extends foundry.appv1.sheets.ActorSheet { + + /** @override */ + static get defaultOptions() { + var options = { + classes: ["mosh", "sheet", "actor", "creature"], + template: "systems/sla-mothership/templates/actor/creature-sheet.html", + width: 820, + height: 770, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "character" }], + submitOnChange: true + }; + + return foundry.utils.mergeObject(super.defaultOptions, options); + } + + /** + * Extend and override the sheet header buttons + * @override + */ + _getHeaderButtons() { + let buttons = super._getHeaderButtons(); + const canConfigure = game.user.isGM || this.actor.isOwner; + if (this.options.editable && canConfigure) { + buttons = [{ + label: game.i18n.localize("Mosh.CreatureSettings"), + class: 'configure-actor', + icon: 'fas fa-tasks', + onclick: (ev) => this._onConfigureCreature(ev), + },].concat(buttons); + } + return buttons; + } + /* -------------------------------------------- */ + + _onConfigureCreature(event) { + event.preventDefault(); + new DLCreatureSettings(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } + + async _updateObject(event, formData) { + const actor = this.object; + var updateData; + updateData = foundry.utils.expandObject(formData); + + + + await actor.update(updateData, { + diff: false + }); + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + const data = await super.getData(); + data.dtypes = ["String", "Number", "Boolean"]; + // for (let attr of Object.values(data.data.attributes)) { + // attr.isCheckbox = attr.dtype === "Boolean"; + // } + + const superData = data.data.system; + + // Prepare items. + if (this.actor.type == 'creature') { + this._prepareCreatureItems(data); + } + + if (data.data.system.settings == null) { + data.data.system.settings = {}; + } + data.data.system.settings.useCalm = game.settings.get("sla-mothership", "useCalm"); + data.data.system.settings.hideWeight = game.settings.get("sla-mothership", "hideWeight"); + data.data.system.settings.firstEdition = game.settings.get("sla-mothership", "firstEdition"); + data.data.system.settings.androidPanic = game.settings.get("sla-mothership", "androidPanic"); + + data.data.enriched = []; + data.data.enriched.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(data.data.system.description, {async: true}); + data.data.enriched.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(data.data.system.biography, {async: true}); + + //SKILL XP BUTTONS + superData.xp.html = ''; + if (superData.xp.html == '') { + for (let i = 1; i <= 15; i++) { + if (i > superData.xp.value) { + if (i % 5) { + superData.xp.html += '
'; + } + else { //If a special one + let trainLevel = '
Trained
'; + if (i == 10) trainLevel = '
Expert
'; + else if (i == 15) trainLevel = '
Master
'; + superData.xp.html += '
' + trainLevel + '
'; + } + } + else { + if (i % 5) { + superData.xp.html += '
'; + } + else { //If a special one + let trainLevel = '
Trained
'; + if (i == 10) trainLevel = '
Expert
'; + else if (i == 15) trainLevel = '
Master
'; + superData.xp.html += '
' + trainLevel + '
'; + } + + } + } + } + //END SKILL XP + + return data.data; + } + + /** + * Organize and classify Items for Character sheets. + * + * @param {Object} actorData The actor to prepare. + * + * @return {undefined} + */ + _prepareCreatureItems(sheetData) { + const actorData = sheetData.data; + //console.log(sheetData); + ///console.log("sheetdata Above"); + // Initialize containers. + const abilities = []; + const gear = []; + const skills = []; + const weapons = []; + const armors = []; + const conditions = []; + + let curWeight = 0; + // Iterate through items, allocating to containers + // let totalWeight = 0; + for (let i of sheetData.items) { + let item = i.system; + i.img = i.img || DEFAULT_TOKEN; + + if (i.type === 'ability') { + abilities.push(i); + } else if (i.type === 'item') { + gear.push(i); + curWeight += item.weight * item.quantity; + } else if (i.type === 'skill') { + skills.push(i); + } else if (i.type === 'armor') { + armors.push(i); + curWeight += item.weight; + } else if (i.type === 'weapon') { + //We need to update this from the old system. + if (item.ranges.value == "" && item.ranges.medium > 0) { + item.ranges.value = item.ranges.short + "/" + item.ranges.medium + "/" + item.ranges.long; + item.ranges.medium = 0; + } + + weapons.push(i); + curWeight += item.weight; + } else if (i.type === 'condition') { + // We'll handle the pip html here. + if (item.treatment == null) { + item.treatment = { + "value": 0, + "html": "" + }; + } + let pipHtml = ""; + for (let i = 0; i < 3; i++) { + if (i < item.treatment.value) { + pipHtml += ''; + } + else { + pipHtml += ''; + } + } + + item.treatment.html = pipHtml; + + conditions.push(i); + } + } + + // Assign and return + actorData.abilities = abilities; + actorData.gear = gear; + actorData.skills = skills; + actorData.armors = armors; + actorData.weapons = weapons; + actorData.conditions = conditions; + } + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Everything below here is only needed if the sheet is editable + if (!this.options.editable) return; + + html.on('mousedown', '.char-pip-button', ev => { + + const div = $(ev.currentTarget); + const targetName = div.data("key"); + + let amount = this.actor.system.xp.value; + let newAmount = amount; + let max = div.data("max"); + let min = div.data("min"); + + if (event.button == 0) { + if (amount < max) { + newAmount = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > min) { + newAmount = Number(amount) - 1; + } + } + + this.actor.update({'system.xp.value': newAmount}); + + }); + + html.on('mousedown', '.treatment-button', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + + let amount = item.system.treatment.value; + + if (event.button == 0) { + if (amount < 3) { + item.system.treatment.value = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.treatment.value = Number(amount) - 1; + } + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + + // Update Inventory Item + html.find('.item-equip').click(ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + item.system.equipped = !item.system.equipped; + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Add Inventory Item + html.find('.item-create').click(this._onItemCreate.bind(this)); + + // Update Inventory Item + html.find('.item-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + item.sheet.render({force: true}); + }); + + //Quantity adjuster + html.on('mousedown', '.item-quantity', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + let amount = item.system.quantity; + + if (event.button == 0) { + item.system.quantity = Number(amount) + 1; + } else if (event.button == 2) { + item.system.quantity = Number(amount) - 1; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //Severity adjuster + html.on('mousedown', '.severity', ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + + let amount = item.system.severity; + + if (event.button == 0) { + item.system.severity = Number(amount) + 1; + } else if (event.button == 2 && amount > 0) { + item.system.severity = Number(amount) - 1; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Delete Inventory Item + html.find('.item-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")]); + li.slideUp(200, () => this.render(false)); + }); + + //SKILLS + // Add Inventory Item + html.find('.skill-create').click(this._onSkillCreate.bind(this)); + + // Update Inventory Item + html.find('.skill-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const skill = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + skill.sheet.render({force: true}); + }); + + //Weapons + // Add Inventory Item + html.find('.weapon-create').click(this._onItemCreate.bind(this)); + + // Update Inventory Item + html.find('.weapon-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const weapon = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + weapon.sheet.render({force: true}); + }); + + // Rollable Attribute + html.find('.stat-roll').click(ev => { + const div = $(ev.currentTarget); + const statName = div.data("key"); + this.actor.rollCheck(null, 'low', statName, null, null, null); + }); + + // Rollable Skill + html.find('.skill-roll').click(ev => { + const li = event.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + this.actor.rollCheck(null, null, null, item.name, item.system.bonus, null); + }); + + // Rollable Weapon + html.find('.weapon-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + //use swarm combat and damage settings if enabled + if (this.actor.system.swarm && this.actor.system.swarm.enabled){ + //calculate new damage string + let new_dice_ammount = item.system.damage.match(/([0-9]+)d[0-9]+/i)[1]*(this.actor.system.hits.max-this.actor.system.hits.value); + let swarm_damage_roll_string = item.system.damage.replace(/([0-9]+)(d[0-9]+)/i,`${new_dice_ammount}$2`); + this.actor.rollCheck(null, 'low', 'combat', null, null, item, swarm_damage_roll_string); + } else { + this.actor.rollCheck(null, 'low', 'combat', null, null, item); + } + }); + + // Rollable Damage + html.find('.dmg-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + //use swarm combat and damage settings if enabled + if (this.actor.system.swarm && this.actor.system.swarm.enabled){ + //calculate new damage string + let new_dice_ammount = item.system.damage.match(/([0-9]+)d[0-9]+/i)[1]*(this.actor.system.hits.max-this.actor.system.hits.value); + let swarm_damage_roll_string = item.system.damage.replace(/([0-9]+)(d[0-9]+)/i,`${new_dice_ammount}$2`); + this.actor.rollCheck(null, null, 'damage', null, null, item, swarm_damage_roll_string); + } else { + this.actor.rollCheck(null, null, 'damage', null, null, item); + } + }); + + // Rollable Item/Anything with a description that we want to click on. + html.find('.description-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.printDescription(li.dataset.itemId, { + event: ev + }); + }); + + //increase ammo + html.on('mousedown', '.weapon-ammo', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.ammo; + if (event.button == 0) { + if (amount >= 0) { + item.system.ammo = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.ammo = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //increase shots + html.on('mousedown', '.weapon-shots', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + if (event.button == 0) { + if (item.system.curShots >= 0 && item.system.curShots < item.system.shots && item.system.ammo > 0) { + item.system.curShots = Number(item.system.curShots) + 1; + item.system.ammo = Number(item.system.ammo) - 1; + } + } else if (event.button == 2) { + if (item.system.curShots > 0) { + item.system.curShots = Number(item.system.curShots) - 1; + item.system.ammo = Number(item.system.ammo) + 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //Reload Shots + html.on('mousedown', '.weapon-reload', ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.reloadWeapon(li.dataset.itemId); + }); + + //increase AP + html.on('mousedown', '.armor-ap', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.armorPoints; + if (event.button == 0) { + item.system.armorPoints = Number(amount) + 1; + } else if (event.button == 2) { + if (amount > 0) { + item.system.armorPoints = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //increase DR + html.on('mousedown', '.armor-dr', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.damageReduction; + if (event.button == 0) { + item.system.damageReduction = Number(amount) + 1; + } else if (event.button == 2) { + if (amount > 0) { + item.system.damageReduction = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //increase oxygen + html.on('mousedown', '.armor-oxy', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.oxygenCurrent; + if (event.button == 0) { + if (amount < item.system.oxygenMax) { + item.system.oxygenCurrent = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.oxygenCurrent = Number(amount) - 1; + } + } + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Clicking on Armor + html.find('.armor-roll').click(ev => { + //roll panic check + this.actor.chooseCover(); + }); + + // Drag events for macros. + if (this.actor.isOwner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } + + + + } + + /* -------------------------------------------- */ + + /** + * Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onItemCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + // Initialize a default name. + const name = `New ${type.capitalize()}`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + data: data + }; + // Remove the type from the dataset since it's in the itemData.type prop. + delete itemData.data["type"]; + + // Finally, create the item! + return this.actor.createEmbeddedDocuments("Item", [itemData]); + } + + /** + * Handle creating a new Owned skill for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onSkillCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + //const data = duplicate(header.dataset); + // Initialize a default name. + const name = `New Skill`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + system: data + }; + + let d = new foundry.applications.api.DialogV2({ + window: {title: `New Skill`}, + classes: ["macro-popup-dialog"], + content: ` +
+
+

Name

+
+ +
+
+
+

Rank

+
+ +
+ `, + buttons: [ + { + icon: 'fas fa-check', + action: "create", + label: "Create", + callback: (event, button, dialog) => { + var rank = button.form.querySelector('[id=\"rank\"]')?.value; + if (rank == "Trained") + itemData.system.bonus = 10; + if (rank == "Expert") + itemData.system.bonus = 15; + if (rank == "Master") + itemData.system.bonus = 20; + + itemData.system.rank = rank; + itemData.name = button.form.querySelector('[id=\"name\"]')?.value + this.actor.createEmbeddedDocuments("Item", [itemData]); + } + }, + { + icon: 'fas fa-times', + action: "cancel", + label: "Cancel", + callback: () => { } + } + ], + default: "roll", + close: () => { } + }); + d.render({force: true}); + + // Finally, create the item! + return; + } + + /** + * Handle clickable rolls. + * @param {Event} event The originating click event + * @private + */ + _onRoll(event) { + event.preventDefault(); + const element = event.currentTarget; + const dataset = element.dataset; + + console.log(super.getData()); + + if (dataset.roll) { + let roll = new Roll(dataset.roll, this.actor.system); + let label = dataset.label ? `Rolling ${dataset.label} to score under ${dataset.target}` : ''; + roll.roll().toMessage({ + speaker: ChatMessage.getSpeaker({ actor: this.actor }), + flavor: label + }); + } + } + + async _updateObject(event, formData) { + const actor = this.object; + + var updateData; + updateData = foundry.utils.expandObject(formData); + + await actor.update(updateData, { + diff: false + }); + } + +} diff --git a/module/actor/ship-sheet-sbt.js b/module/actor/ship-sheet-sbt.js new file mode 100644 index 0000000..d5ebe0e --- /dev/null +++ b/module/actor/ship-sheet-sbt.js @@ -0,0 +1,498 @@ +import { fromIdUuid } from "../mosh.js"; + +/** + * Extend the basic ActorSheet with some very simple modifications + * @extends {ActorSheet} + */ +import { DLShipDeckplan } from "../windows/ship-deckplan.js"; +import { DLShipMacros } from "../windows/ship-macros.js"; +import { DLShipMegaDamage } from "../windows/ship-megadamage.js"; +import { DLShipSetup } from "../windows/ship-setup.js"; + +export class MothershipShipSheetSBT extends foundry.appv1.sheets.ActorSheet { + + /** @override */ + static get defaultOptions() { + + var options = { + classes: ["mosh", "sheet", "actor", "ship"], + template: "systems/sla-mothership/templates/actor/ship-sheet-sbt.html", + width: 700, + height: 840, + tabs: [{ navSelector: "#sheet-tabs", contentSelector: "#sheet-body", initial: "character" }, + { navSelector: "#side-tabs", contentSelector: "#side-body", initial: "close" }], + // { navSelector: "#side-tabs", contentSelector: "#side-body", initial: "crew" }], + scrollY: [".sheet-body", "scroll-lock"], + submitOnChange: true + } + + return foundry.utils.mergeObject(super.defaultOptions, options); + + + } + + _onOpenDeckplan(event) { + event.preventDefault(); + new DLShipDeckplan(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } + + _onOpenMacros(event) { + event.preventDefault(); + new DLShipMacros(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } + + _onOpenSetup(event) { + event.preventDefault(); + new DLShipSetup(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } + + _onOpenMegadamage(event) { + event.preventDefault(); + new DLShipMegaDamage(this.actor, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + const data = await super.getData(); + + data.dtypes = ["String", "Number", "Boolean"]; + + // console.log(this.actor.getRollTableData('AqGWwoWXzijFs427')); + + // for (let attr of Object.values(data.data.system.attributes)) { + // attr.isCheckbox = attr.dtype === "Boolean"; + // } + + const superData = data.data.system; + + superData.page = {}; //Prep the page object, for any html specific stuff we want to do. + // Prepare items. + if (this.actor.type == 'ship') { + this._prepareShipItems(data); + } + + if (superData.settings == null) { + superData.settings = {}; + } + + superData.settings.useCalm = game.settings.get("sla-mothership", "useCalm"); + superData.settings.hideWeight = game.settings.get("sla-mothership", "hideWeight"); + superData.settings.firstEdition = game.settings.get("sla-mothership", "firstEdition"); + superData.settings.androidPanic = game.settings.get("sla-mothership", "androidPanic"); + + let maxHull = superData.supplies.hull.max; + + superData.supplies.hull.percentage = " [ " + Math.round(maxHull * 0.25) + " | " + Math.round(maxHull * 0.5) + " | " + Math.round(maxHull * 0.75) + " ]"; + + data.data.enriched = []; + data.data.enriched.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(data.data.system.biography, {async: true}); + + + //Run Setup + // if(data.data.system.runSetup){ + // this.render(true, {focus:false}); + // var setupMenu = new DLShipSetup(this.actor, {popOut: true, minimizable : false}); + // setupMenu.render(true, {focus: true}); + // console.log(setupMenu); + // this.close(); + + // data.data.system.runSetup = false; + // } + + this._prepareMegadamage(superData); + + return data.data; + } + + + /** + * Organize and classify Items for Character sheets. + * + * @param {Object} actorData The actor to prepare. + * + * @return {undefined} + */ + _prepareShipItems(sheetData) { + const actorData = sheetData.data; + + // Initialize containers. + const crew = []; + const weapons = []; + const cargo = []; + const modules = []; + + const minorRepairs = []; //We are seperating these to make sure they are always ordered by severity. + const majorRepairs = []; + + + // Iterate through items, allocating to containers + // let totalWeight = 0; + for (let i of sheetData.items) { + let item = i.system; + i.img = i.img || DEFAULT_TOKEN; + + if (i.type === 'crew') { + crew.push(i); + } else if (i.type === 'weapon') { + weapons.push(i); + } else if (i.type === 'item') { + cargo.push(i); + } else if (i.type === 'module') { + modules.push(i); + } else if (i.type == 'repair') { + i.name = i.name.split('.')[0]; + + if (i.system.major) { + majorRepairs.push(i); + } + else { + minorRepairs.push(i); + } + } + } + + // Assign and return + actorData.crew = crew; + actorData.weapons = weapons; + actorData.cargo = cargo; + actorData.modules = modules; + actorData.minorRepairs = minorRepairs; + actorData.majorRepairs = majorRepairs; + + } + + async _prepareMegadamage(sheetData) { + const actorData = sheetData; + //A script to return the data from a table. + let tableId = game.settings.get('sla-mothership', 'table1eMegadamageEffects'); + //get table data + let tableData = await fromIdUuid(tableId,{type:"RollTable"}); + + let megadamageHTML = ""; + + let entries = Array.from(tableData.results.entries()); + //Prep Megadamage List + // if(actorData.system.megadamage.hits.length > 0){ + let index = 0; + for (const entry of entries) { + + // Megadamage - Only Active + if (index != 0 && actorData.megadamage.hits.includes(index)) { + // megadamageHTML += `  `; + megadamageHTML += `  `; + megadamageHTML += `${index} | ${entry[1].description}

`; + } else if (index != 0) { + // megadamageHTML += `  `; + megadamageHTML += `
 `; + megadamageHTML += `${index} | ${entry[1].description}

`; + } + index++; + } + // } else { + + // } + + await this.object.update({ + "system.megadamage.html": megadamageHTML + }); + + if (actorData.page == undefined) { + actorData.page = {}; + } + + actorData.page.megadamageMenuClass = ""; + + // if(actorData.system.megadamage.open){ + // actorData.system.page.megadamageMenuClass = "sbt-megadamage-open" + // } else { + // actorData.system.page.megadamageMenuClass = "sbt-megadamage-closed" + // } + + + // await this.object.update({ + // "data.megadamage.hits": [] + // }); + } + + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Everything below here is only needed if the sheet is editable + if (!this.options.editable) return; + + + html.on('mousedown', '.megadamage-button', ev => { + const data = this.object; + + const div = $(ev.currentTarget); + const targetKey = div.data("key"); + + if (data.system.megadamage.hits.includes(targetKey)) { + const index = data.system.megadamage.hits.indexOf(targetKey); + data.system.megadamage.hits.splice(index, 1); + } else { + data.system.megadamage.hits.push(targetKey); + } + + this.object.update({ + "system.megadamage.hits": data.system.megadamage.hits + }); + + this._prepareMegadamage(data.system); + }); + + // Create inventory item. + html.find('.item-create').click(this._onItemCreate.bind(this)); + // Delete Inventory Item + html.find('.item-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")]); + li.slideUp(200, () => this.render(false)); + }); + + // Update Inventory Item + html.find('.item-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + item.sheet.render({force: true}); + + let amount = item.system.quantity; + + if (item.type == "module") { + item.system.totalHull = amount * item.system.hull; + } + }); + + //Quantity adjuster + html.on('mousedown', '.item-quantity', ev => { + const li = ev.currentTarget.closest(".item"); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + let amount = item.system.quantity; + + if (event.button == 0) { + item.system.quantity = Number(amount) + 1; + } else if (event.button == 2) { + item.system.quantity = Number(amount) - 1; + } + + if (item.type == "module") { + item.system.totalHull = item.system.quantity * item.system.hull; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Rollable Attributes + html.find('.stat-roll').click(ev => { + const div = $(ev.currentTarget); + const statName = div.data("key"); + this.actor.rollCheck(null, 'low', statName, null, null, null); + }); + + //Weapons + // Add Inventory Item + html.find('.weapon-create').click(this._onItemCreate.bind(this)); + // Update Inventory Item + html.find('.weapon-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const weapon = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + weapon.sheet.render({force: true}); + }); + + // Rollable Weapon - not needed since individual ship weapons are not fired + html.find('.weapon-roll').click(ev => { + // const li = ev.currentTarget.closest(".item"); + // const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + // this.actor.rollCheck(null,'low','combat',null,null,item); + + const li = ev.currentTarget.closest(".item"); + this.actor.printDescription(li.dataset.itemId, { + event: ev + }); + }); + + // Distress Signal + html.find('.distress-button').click(ev => { + //roll distress signal + this.actor.distressSignal(); + }); + + // Maintenance Check + html.find('.maintenance-button').click(ev => { + //roll maintenance check + this.actor.maintenanceCheck(); + }); + + // Bankruptcy Save + html.find('.bankruptcy-button').click(ev => { + //roll bankruptcy save + this.actor.bankruptcySave(); + }); + + // Morale Check + html.find('.morale-button').click(ev => { + //roll morale check + this.actor.moraleCheck(); + }); + + // Deckplan Button + html.find('.deckplan-button').click(ev => this._onOpenDeckplan(ev)); + + //Macro Menu Button + html.find('.macro-menu-button').click(ev => this._onOpenMacros(ev)); + + //Testing Setup Menu Button + html.find('.setup-menu-button').click(ev => this._onOpenSetup(ev)); + + //Megadamage Menu Button + html.find('.megadamage-menu-button').click(ev => this._onOpenMegadamage(ev)); + + //Megadamage Menu Button + // html.find('.megadamage-sidebar-button').click(ev => { + // const data = this.object; + + // let sidebarClasses = "" + + // if(data.system.megadamage.open){ + // sidebarClasses = "sbt-megadamage-open" + // } else { + // sidebarClasses = "sbt-megadamage-closed" + // } + + // this.object.update({ + // "data.megadamage.open": !data.system.megadamage.open, + // "data.sidebar.megadamageClasses" : sidebarClasses + // }); + // }); + + + html.on('mousedown', '.weapon-ammo', ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + //const item = duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)) + let amount = item.system.ammo; + + if (event.button == 0) { + if (amount >= 0) { + item.system.ammo = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.ammo = Number(amount) - 1; + } + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //Reload Shots + html.on('mousedown', '.weapon-reload', ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.reloadWeapon(li.dataset.itemId); + }); + + // Rollable Item/Anything with a description that we want to click on. + html.find('.description-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.printDescription(li.dataset.itemId, { + event: ev + }); + }); + + + + // Drag events for macros. + if (this.actor.isOwner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } + } + + /* -------------------------------------------- */ + + /** + * Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onItemCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + + const subtype = header.dataset.subtype; + + + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + + + // Initialize a default name. + const name = `New ${type.capitalize()}`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + data: data, + system: {} + }; + + if (type == "repair") { + itemData.system.major = (header.dataset.subtype == "major"); + } + + // Remove the type from the dataset since it's in the itemData.type prop. + delete itemData.data["type"]; + + // Finally, create the item! + return this.actor.createEmbeddedDocuments("Item", [itemData]); + } + + + /** + * Handle clickable rolls. + * @param {Event} event The originating click event + * @private + */ + _onRoll(event) { + event.preventDefault(); + const element = event.currentTarget; + const dataset = element.dataset; + + if (dataset.roll) { + let roll = new Roll(dataset.roll, this.actor.data.system); + let label = dataset.label ? `Rolling ${dataset.label} to score under ${dataset.target}` : ''; + roll.roll().toMessage({ + speaker: ChatMessage.getSpeaker({ actor: this.actor }), + flavor: label + }); + } + } + +} diff --git a/module/actor/ship-sheet.js b/module/actor/ship-sheet.js new file mode 100644 index 0000000..26652d0 --- /dev/null +++ b/module/actor/ship-sheet.js @@ -0,0 +1,275 @@ +/** + * Extend the basic ActorSheet with some very simple modifications + * @extends {ActorSheet} + */ +export class MothershipShipSheet extends foundry.appv1.sheets.ActorSheet { + + /** @override */ + static get defaultOptions() { + return foundry.utils.mergeObject(super.defaultOptions, { + classes: ["mosh", "sheet", "actor", "ship"], + template: "systems/sla-mothership/templates/actor/ship-sheet.html", + width: 700, + height: 650, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "character" }], + submitOnChange: true + }); + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + const data = await super.getData(); + + data.dtypes = ["String", "Number", "Boolean"]; + + // for (let attr of Object.values(data.data.system.attributes)) { + // attr.isCheckbox = attr.dtype === "Boolean"; + // } + + const superData = data.data.system; + + // Prepare items. + if (this.actor.type == 'ship') { + this._prepareShipItems(data); + } + + if (superData.settings == null) { + superData.settings = {}; + } + + superData.settings.useCalm = game.settings.get("sla-mothership", "useCalm"); + superData.settings.hideWeight = game.settings.get("sla-mothership", "hideWeight"); + superData.settings.firstEdition = game.settings.get("sla-mothership", "firstEdition"); + superData.settings.androidPanic = game.settings.get("sla-mothership", "androidPanic"); + + let maxHull = superData.supplies.hull.max; + + superData.supplies.hull.percentage = " [ " + Math.round(maxHull * 0.25) + " | " + Math.round(maxHull * 0.5) + " | " + Math.round(maxHull * 0.75) + " ]"; + + data.data.enriched = []; + data.data.enriched.biography = await foundry.applications.ux.TextEditor.implementation.enrichHTML(data.data.system.biography, {async: true}); + + return data.data; + } + + /** + * Organize and classify Items for Character sheets. + * + * @param {Object} actorData The actor to prepare. + * + * @return {undefined} + */ + _prepareShipItems(sheetData) { + const actorData = sheetData.data; + + // Initialize containers. + const abilities = []; + const weapons = []; + const cargo = []; + const modules = []; + + // Iterate through items, allocating to containers + // let totalWeight = 0; + for (let i of sheetData.items) { + let item = i.system; + i.img = i.img || DEFAULT_TOKEN; + + if (i.type === 'ability') { + abilities.push(i); + } else if (i.type === 'weapon') { + weapons.push(i); + } else if (i.type === 'item') { + cargo.push(i); + } else if (i.type === 'module') { + modules.push(i); + } + } + + // Assign and return + actorData.abilities = abilities; + actorData.weapons = weapons; + actorData.cargo = cargo; + actorData.modules = modules; + + } + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Everything below here is only needed if the sheet is editable + if (!this.options.editable) return; + + // Create inventory item. + html.find('.item-create').click(this._onItemCreate.bind(this)); + // Delete Inventory Item + html.find('.item-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + this.actor.deleteEmbeddedDocuments("Item", [li.data("itemId")]); + li.slideUp(200, () => this.render(false)); + }); + + // Update Inventory Item + html.find('.item-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + item.sheet.render({force: true}); + + let amount = item.system.quantity; + + if (item.type == "module") { + item.system.totalHull = amount * item.system.hull; + } + }); + + //Quantity adjuster + html.on('mousedown', '.item-quantity', ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + let amount = item.system.quantity; + + if (event.button == 0) { + item.system.quantity = Number(amount) + 1; + } else if (event.button == 2) { + item.system.quantity = Number(amount) - 1; + } + + if (item.type == "module") { + item.system.totalHull = item.system.quantity * item.system.hull; + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + // Rollable Attributes + html.find('.stat-roll').click(ev => { + const div = $(ev.currentTarget); + const statName = div.data("key"); + this.actor.rollCheck(null, 'low', statName, null, null, null); + }); + + //Weapons + // Add Inventory Item + html.find('.weapon-create').click(this._onItemCreate.bind(this)); + // Update Inventory Item + html.find('.weapon-edit').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const weapon = this.actor.getEmbeddedDocument("Item", li.data("itemId")); + weapon.sheet.render({force: true}); + }); + // Rollable Weapon + html.find('.weapon-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + this.actor.rollCheck(null, 'low', 'combat', null, null, item); + }); + + html.on('mousedown', '.weapon-ammo', ev => { + const li = ev.currentTarget.closest(".item"); + var item; + item = foundry.utils.duplicate(this.actor.getEmbeddedDocument("Item", li.dataset.itemId)); + + let amount = item.system.ammo; + + if (event.button == 0) { + if (amount >= 0) { + item.system.ammo = Number(amount) + 1; + } + } else if (event.button == 2) { + if (amount > 0) { + item.system.ammo = Number(amount) - 1; + } + } + + this.actor.updateEmbeddedDocuments('Item', [item]); + }); + + //Reload Shots + html.on('mousedown', '.weapon-reload', ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.reloadWeapon(li.dataset.itemId); + }); + + // Rollable Item/Anything with a description that we want to click on. + html.find('.description-roll').click(ev => { + const li = ev.currentTarget.closest(".item"); + this.actor.printDescription(li.dataset.itemId, { + event: ev + }); + }); + + + // Drag events for macros. + if (this.actor.isOwner) { + let handler = ev => this._onDragStart(ev); + + html.find('li.dropitem').each((i, li) => { + if (li.classList.contains("inventory-header")) return; + li.setAttribute("draggable", true); + li.addEventListener("dragstart", handler, false); + }); + } + } + + /* -------------------------------------------- */ + + /** + * Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset + * @param {Event} event The originating click event + * @private + */ + _onItemCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + var data; + data = foundry.utils.duplicate(header.dataset); + + + // Initialize a default name. + const name = `New ${type.capitalize()}`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + data: data + }; + // Remove the type from the dataset since it's in the itemData.type prop. + delete itemData.data["type"]; + + // Finally, create the item! + return this.actor.createEmbeddedDocuments("Item", [itemData]); + } + + + /** + * Handle clickable rolls. + * @param {Event} event The originating click event + * @private + */ + _onRoll(event) { + event.preventDefault(); + const element = event.currentTarget; + const dataset = element.dataset; + + console.log(super.getData()); + + if (dataset.roll) { + let roll = new Roll(dataset.roll, this.actor.data.data); + let label = dataset.label ? `Rolling ${dataset.label} to score under ${dataset.target}` : ''; + roll.roll().toMessage({ + speaker: ChatMessage.getSpeaker({ actor: this.actor }), + flavor: label + }); + } + } + +} diff --git a/module/feature-flags.js b/module/feature-flags.js new file mode 100644 index 0000000..f46374f --- /dev/null +++ b/module/feature-flags.js @@ -0,0 +1,22 @@ +export const SLA_FEATURE_MODULES = Object.freeze([ + { + id: "sla-ops-clock", + title: "SLA Ops Clock", + description: "Operation clock, heat, collateral, and pressure tracker for SLA missions." + }, + { + id: "sla-npc-director", + title: "SLA NPC Director", + description: "Quick NPC pulse tracker for morale, suppression, and intent during firefights." + }, + { + id: "sla-briefing-desk", + title: "SLA Briefing Desk", + description: "Create SLA briefings, objectives, complications, and payoff handouts." + }, + { + id: "sla-gear-cache", + title: "SLA Gear Cache", + description: "Generate loot drops, ammo caches, and requisition packs tuned for SLA ops." + } +]); diff --git a/module/item/class-sheet.js b/module/item/class-sheet.js new file mode 100644 index 0000000..46dd294 --- /dev/null +++ b/module/item/class-sheet.js @@ -0,0 +1,340 @@ +/** + * Extend the basic MothershipItemSheet with class modification + * @extends {MothershipItemSheet} + */ +import { MothershipItemSheet } from "./item-sheet.js"; +export class MothershipClassSheet extends MothershipItemSheet { + + /** @override */ + static get defaultOptions() { + var options = { + classes: ["mosh", "sheet", "item"], + width: 820, + height: 820, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }] + }; + options.dragDrop = [{dragSelector: null, dropSelector: ".dropitem"}]; + + return foundry.utils.mergeObject(super.defaultOptions, options); + + } + + + /** @override */ + async getData() { + const data = await super.getData(); + if (typeof data.system.base_adjustment.skills_granted == 'undefined'){ + data.system.base_adjustment.skills_granted=[]; + } + + //Create placeholder for the skills object, to get the info of the skill + data.system.base_adjustment.skills_granted_object = []; + for (const skill of data.system.base_adjustment.skills_granted){ + data.system.base_adjustment.skills_granted_object.push(await fromUuid(skill)); + }; + + console.log(data.system.selected_adjustment.choose_skill_or); + let choose_skill_or = data.system.selected_adjustment.choose_skill_or; + for (const [ig, group] of choose_skill_or.entries()){ + for (const [io, option] of group.entries()){ + let names = []; + data.system.selected_adjustment.choose_skill_or[ig][io].from_list_names = []; + for(const [is, skill] of option.from_list.entries()){ + names.push((await fromUuid(skill)).name); + } + data.system.selected_adjustment.choose_skill_or[ig][io].from_list_names = names; + } + console.log(data.system.selected_adjustment.choose_skill_or); + } + + data.system.common_skills_object = []; + for (const skill of data.system.common_skills){ + data.system.common_skills_object.push(await fromUuid(skill)); + }; + + /* + if (typeof data.system.selected_adjustment.choose_stat.stats == 'undefined'){ + data.system.selected_adjustment.choose_stat.stats=[]; + }*/ + + data.enriched=[]; + data.enriched.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(data.system.description, {async: true}); + + return data; + } + + async _onDrop(event){ + await super._onDrop(event); + const droppedUuid = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); + if (droppedUuid.type != "Item"){ + return; + } + + const droppedObject = await fromUuid(droppedUuid.uuid); + if (droppedObject.type == "skill"){ + if(event.currentTarget == null) { + ui.notifications.error(game.i18n.localize("Mosh.Errors.NoDropTarget")); + return this.render(false); + } + console.log(event.currentTarget.id); + if(event.currentTarget.id == "skills.fixed"){ + let parent_fixed_or = event.target.closest('div[id="skills.fixed.or"]'); + + if(parent_fixed_or){ + let array_index = parent_fixed_or.getAttribute("index"); + let skills = this.object.system.base_adjustment.skills_granted; + if(skills[array_index].includes(droppedObject.uuid)){ + ui.notifications.warn(game.i18n.localize("Mosh.Errors.SkillAlreadyInList")); + return this.render(false); + } + skills[array_index].push(droppedObject.uuid); + this.object.update({"system.base_adjustment.skills_granted":skills}); + return this.render(false); + + }else{ + let skills = this.object.system.base_adjustment.skills_granted; + if (skills.includes(droppedObject.uuid)){ + ui.notifications.warn(game.i18n.localize("Mosh.Errors.SkillAlreadyInList")); + return this.render(false); + } + skills.push(droppedObject.uuid); + this.object.update({"system.base_adjustment.skills_granted":skills}); + return this.render(false); + } + } + else if(event.currentTarget.id =="skills.common"){ + let skills = this.object.system.common_skills; + if (skills.includes(droppedObject.uuid)){ + ui.notifications.warn(game.i18n.localize("Mosh.Errors.SkillAlreadyInList")); + return this.render(false); + } + skills.push(droppedObject.uuid); + this.object.update({"system.common_skills":skills}); + return this.render(false); + } + else if(event.currentTarget.id =="choose_skill_or_li"){ + const li = $(event.currentTarget); + let index = li.data("itemId"); + const parent = $(event.currentTarget).parents(".items-list"); + let parent_index = parent.data("itemId"); + + let options = this.object.system.selected_adjustment.choose_skill_or; + if(options[parent_index][index].from_list.includes(droppedObject.uuid)){ + ui.notifications.warn(game.i18n.localize("Mosh.Errors.SkillAlreadyInList")); + return this.render(false); + } + options[parent_index][index].from_list.push(droppedObject.uuid); + + this.object.update({"system.selected_adjustment.choose_skill_or":options}); + return this.render(false); + + } + } + } + + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Delete skills-granted + html.find('.skills-granted-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + + let skills = this.object.system.base_adjustment.skills_granted.filter(function( obj ) { + return obj !== li.data("itemId"); + }); + this.object.update({"system.base_adjustment.skills_granted":skills}); + return this.render(false); + }); + + // Delete skills-common + html.find('.skills-common-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + + let skills = this.object.system.common_skills.filter(function( obj ) { + return obj !== li.data("itemId"); + }); + this.object.update({"system.common_skills":skills}); + return this.render(false); + }); + + html.find('.stat-option-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + + let stats = this.object.system.selected_adjustment.choose_stat; + stats.splice(li.data("itemId"),1); + + this.object.update({"system.selected_adjustment.choose_stat":stats}); + return this.render(false); + }); + + + html.find('.stat-option-add').click(this._onStatCreate.bind(this)); + + + html.find('.skills-group-add').click(ev => { + let skills = this.object.system.selected_adjustment.choose_skill_or; + let new_group = [] + skills.push(new_group); + this.object.update({"system.selected_adjustment.choose_skill_or":skills}); + return this.render(false); + }); + html.find('.skills-group-delete').click(ev => { + const li = $(ev.currentTarget).parents(".items-list"); + + let options = this.object.system.selected_adjustment.choose_skill_or; + options.splice(li.data("itemId"),1); + + this.object.update({"system.selected_adjustment.choose_skill_or":options}); + return this.render(false); + }); + + html.find('.skills-group-option-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const liparent = li.parents(".items-list"); + + let options = this.object.system.selected_adjustment.choose_skill_or; + options[liparent.data("itemId")].splice(li.data("itemId"),1); + + this.object.update({"system.selected_adjustment.choose_skill_or":options}); + return this.render(false); + }); + + html.find('.skills-group-option-createnew').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const index = li[0].attributes["data-item-id"].value; + + let new_data = { + "name":li.find('input[name="choose_skill_or_name"]')[index].value, + "trained": li.find('input[name="choose_skill_or_trained"]')[index].value, + "expert": li.find('input[name="choose_skill_or_expert"]')[index].value, + "expert_full_set": li.find('input[name="choose_skill_or_expert_full_set"]')[index].value, + "master": li.find('input[name="choose_skill_or_master"]')[index].value, + "master_full_set": li.find('input[name="choose_skill_or_master_full_set"]')[index].value, + "from_list": [], + } + if(new_data.name ==""){ + new_data.name = `Option: ${(this.object.system.selected_adjustment.choose_skill_or[li.data("itemId")].length)+1}` + } + if(new_data.trained ==""){ + new_data.trained = 0; + } + if(new_data.expert ==""){ + new_data.expert = 0; + } + if(new_data.expert_full_set ==""){ + new_data.expert_full_set = 0; + } + if(new_data.master ==""){ + new_data.master = 0; + } + if(new_data.master_full_set ==""){ + new_data.master_full_set = 0; + } + //console.log(new_data); + let options = this.object.system.selected_adjustment.choose_skill_or; + options[li.data("itemId")].push(new_data); + + //save data + this.object.update({"system.selected_adjustment.choose_skill_or":options}); + + //clear form and hide it + li.find('input[name="choose_skill_or_name"]')[index].value = ""; + li.find('input[name="choose_skill_or_trained"]')[index].value = ""; + li.find('input[name="choose_skill_or_expert"]')[index].value = ""; + li.find('input[name="choose_skill_or_expert_full_set"]')[index].value = ""; + li.find('input[name="choose_skill_or_master"]')[index].value = ""; + li.find('input[name="choose_skill_or_master_full_set"]')[index].value = ""; + + return this.render(false); + }); + + } + + + /** + * Handle creating a new stat for the class selected adjustment + * @param {Event} event The originating click event + * @private + */ + _onStatCreate(event) { + event.preventDefault(); + let choose_stat = this.object.system.selected_adjustment.choose_stat; + + let DialogContent = ` +

${game.i18n.localize("Mosh.CharacterGenerator.StatOption")}

\ +
\ +
${game.i18n.localize("Mosh.Strength")}
\ +
${game.i18n.localize("Mosh.Speed")}
\ +
${game.i18n.localize("Mosh.Intellect")}
\ +
${game.i18n.localize("Mosh.Combat")}
\ +
${game.i18n.localize("Mosh.Sanity")}
\ +
${game.i18n.localize("Mosh.Fear")}
\ +
${game.i18n.localize("Mosh.Body")}
+ ` + + let d = new foundry.applications.api.DialogV2({ + window: {title: `Select Stat`}, + classes: ["macro-popup-dialog"], + content: DialogContent, + buttons: [ + { + icon: 'fas fa-check', + action: "create", + label: "Create", + callback: (event, button, dialog) => { + + let new_stat_option = { + modification: button.form.querySelector('[id=\"modification\"]').value, + stats: [], + } + if (button.form.querySelector('[id=\"strength\"]')?.checked){ + new_stat_option.stats.push("strength"); + } + if (button.form.querySelector('[id=\"speed\"]')?.checked){ + new_stat_option.stats.push("speed"); + } + if (button.form.querySelector('[id=\"intellect\"]')?.checked){ + new_stat_option.stats.push("intellect"); + } + if (button.form.querySelector('[id=\"combat\"]')?.checked){ + new_stat_option.stats.push("combat"); + } + if (button.form.querySelector('[id=\"sanity\"]')?.checked){ + new_stat_option.stats.push("sanity"); + } + if (button.form.querySelector('[id=\"fear\"]')?.checked){ + new_stat_option.stats.push("fear"); + } + if (button.form.querySelector('[id=\"body\"]')?.checked){ + new_stat_option.stats.push("body"); + } + if(new_stat_option.stats.length < 2){ + ui.notifications.error(game.i18n.localize("Mosh.classNewStatOptionEmptyError")); + return; + } + + choose_stat.push(new_stat_option); + this.object.update({"system.selected_adjustment.choose_stat":choose_stat}); + + } + }, + { + icon: 'fas fa-times', + action: "cancel", + label: "Cancel", + callback: () => { } + } + ], + default: "create", + close: () => { } + }); + d.render({force: true}); + + // Finally, create the item! + return; + } + +} + diff --git a/module/item/item-sheet.js b/module/item/item-sheet.js new file mode 100644 index 0000000..00769f1 --- /dev/null +++ b/module/item/item-sheet.js @@ -0,0 +1,231 @@ +import { SLADrugSystem } from "../sla-drug-system.js"; + +/** + * Extend the basic ItemSheet with some very simple modifications + * @extends {ItemSheet} + */ +export class MothershipItemSheet extends foundry.appv1.sheets.ItemSheet { + + /** @override */ + static get defaultOptions() { + var options = { + classes: ["mosh", "sheet", "item"], + width: 600, + height: 500, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }] + }; + + return foundry.utils.mergeObject(super.defaultOptions, options); + } + + /** @override */ + get template() { + const path = "systems/sla-mothership/templates/item"; + // Return a single sheet for all item types. + return `${path}/item-${this.item.type}-sheet.html`; + // Alternatively, you could use the following return statement to do a + // unique item sheet by type, like `weapon-sheet.html`. + + // return `${path}/${this.item.system.type}-sheet.html`; + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + const data = await super.getData(); + const sheetData = data.data ?? data; + const superData = sheetData.system ?? (sheetData.system = {}); + const itemType = this.item.type; + + superData.sla ??= {}; + superData.settings ??= {}; + + if (itemType === "weapon") { + superData.ranges ??= { short: 0, medium: 0, long: 0, value: "" }; + superData.ammoTag ??= "STD"; + superData.ammoLoadedType ??= superData.ammoTag ?? "STD"; + superData.ammoReserveStd ??= Math.max(0, Number(superData.ammo ?? 0) || 0); + superData.ammoReserveAp ??= 0; + superData.ammoReserveHe ??= 0; + superData.ammoReserveHeap ??= 0; + superData.ammoReserve ??= Number(superData.ammoReserveStd ?? 0) + Number(superData.ammoReserveAp ?? 0) + Number(superData.ammoReserveHe ?? 0) + Number(superData.ammoReserveHeap ?? 0); + superData.ammo ??= superData.ammoReserve; + superData.ammoBaseCost ??= 0; + superData.sla.fireModes ??= deriveDefaultFireModes(superData); + superData.sla.currentFireMode ??= getFireModes(superData)[0]?.label ?? "Single"; + superData.shotsPerFire = getActiveFireMode(superData)?.shots ?? Math.max(Number(superData.shotsPerFire ?? 1) || 1, 1); + + if (superData.ranges.value === "" && Number(superData.ranges.medium ?? 0) > 0) { + superData.ranges.value = `${superData.ranges.short}/${superData.ranges.medium}/${superData.ranges.long}`; + superData.ranges.medium = 0; + } + } + + if (itemType === "ability") { + superData.sla.abilityType ??= "ebb"; + superData.sla.skillRef ??= ""; + superData.sla.fluxCost ??= 1; + superData.sla.tier ??= "basic"; + superData.sla.panicSave ??= "fear"; + superData.sla.rollOnUse ??= true; + superData.sla.tiers ??= []; + } + + if (itemType === "drug") { + superData.quantity ??= 1; + superData.weight ??= 0; + superData.cost ??= 0; + superData.sla.drugId ??= ""; + superData.sla.category ??= "Drug"; + superData.sla.rating ??= 0; + superData.sla.durationLabel ??= ""; + superData.sla.addictionFactor ??= 0; + const drugDefinition = await SLADrugSystem.getDrugDefinitionFromItem(this.item); + sheetData.drugDefinition = drugDefinition; + if (drugDefinition) { + superData.sla.drugId = drugDefinition.id; + superData.sla.category = drugDefinition.category ?? "Drug"; + superData.sla.rating = Number(drugDefinition.rating ?? 0); + superData.sla.durationLabel = String(drugDefinition.durationLabel ?? ""); + superData.sla.addictionFactor = Number(drugDefinition.addiction?.threshold ?? 0); + } + } + + superData.settings.useCalm = game.settings.get("sla-mothership", "useCalm"); + superData.settings.hideWeight = game.settings.get("sla-mothership", "hideWeight"); + superData.settings.firstEdition = game.settings.get("sla-mothership", "firstEdition"); + superData.settings.androidPanic = game.settings.get("sla-mothership", "androidPanic"); + + sheetData.enriched = []; + sheetData.enriched.description = await foundry.applications.ux.TextEditor.implementation.enrichHTML(superData.description ?? "", { async: true }); + + return sheetData; + } + + /* -------------------------------------------- */ + + /** @override */ + setPosition(options = {}) { + const position = super.setPosition(options); + const sheetBody = this.element.find(".sheet-body"); + const bodyHeight = position.height - 192; + sheetBody.css("height", bodyHeight); + return position; + } + + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Everything below here is only needed if the sheet is editable + if (!this.options.editable) return; + + // Roll handlers, click handlers, etc. would go here. + } + + async _updateObject(event, formData) { + const updateData = foundry.utils.expandObject(formData); + if (Object.prototype.hasOwnProperty.call(updateData?.system ?? {}, "weight")) { + const parsed = Number(updateData.system.weight ?? 0) || 0; + updateData.system.weight = Math.round(parsed * 10) / 10; + } + await this.item.update(updateData, { diff: false }); + } +} + +function getFireModes(system) { + const raw = String(system?.sla?.fireModes ?? "").trim(); + const rofText = String(system?.sla?.rofText ?? system?.rofText ?? "").toLowerCase(); + const shotsPerFire = Math.max(1, Number(system?.shotsPerFire ?? 1) || 1); + const special = String(system?.sla?.special ?? "").toLowerCase(); + const name = String(system?.name ?? ""); + const modes = []; + for (const chunk of raw.split(/[\n,]+/)) { + const entry = chunk.trim(); + if (!entry) continue; + const match = entry.match(/^(.+?)(?:\s*[:=|-]\s*|\s*\(\s*)(\d+)\)?$/); + if (!match) { + const inferred = inferWeaponModeShots(entry, shotsPerFire, rofText); + if (!inferred) continue; + modes.push({ + label: entry.replace(/\s+/g, " ").trim().replace(/\bfull auto\b/i, "Auto"), + shots: inferred + }); + continue; + } + modes.push({ + label: match[1].trim(), + shots: Math.max(1, Number(match[2]) || 1) + }); + } + const staleSingleMode = modes.length === 1 + && modes[0].label.toLowerCase() === "single" + && modes[0].shots === 1 + && (special.includes("auto") || special.includes("burst") || rofText.includes("burst") || rofText.includes("auto") || inferAutomaticWeaponShots(name) > 1); + + return modes.length && !staleSingleMode + ? modes + : deriveWeaponModeDefaults(Math.max(shotsPerFire, inferAutomaticWeaponShots(name)), special, rofText, name); +} + +function getActiveFireMode(system) { + const modes = getFireModes(system); + const current = String(system?.sla?.currentFireMode ?? "").trim().toLowerCase(); + return modes.find((mode) => mode.label.toLowerCase() === current) ?? modes[0]; +} + +function deriveDefaultFireModes(system) { + const shotsPerFire = Math.max(1, Number(system?.shotsPerFire ?? 1) || 1); + const special = String(system?.sla?.special ?? "").toLowerCase(); + const rofText = String(system?.sla?.rofText ?? system?.rofText ?? "").toLowerCase(); + const modes = deriveWeaponModeDefaults(shotsPerFire, special, rofText); + + return modes + .filter((mode, index, list) => list.findIndex((entry) => entry.label === mode.label && entry.shots === mode.shots) === index) + .map((mode) => `${mode.label}:${mode.shots}`) + .join(", "); +} + +function inferWeaponModeShots(label = "", shotsPerFire = 1, rofText = "") { + const normalized = String(label ?? "").toLowerCase(); + if (normalized.includes("single") || normalized.includes("semi")) return 1; + if (normalized.includes("double") || normalized.includes("2 shots")) return Math.max(2, shotsPerFire); + if (normalized.includes("burst")) return Math.max(3, shotsPerFire); + if (normalized.includes("auto")) { + if (rofText.includes("full auto")) return Math.max(6, shotsPerFire); + return Math.max(3, shotsPerFire); + } + return 0; +} + +function deriveWeaponModeDefaults(shotsPerFire = 1, special = "", rofText = "", name = "") { + const modes = [{ label: "Single", shots: 1 }]; + const text = `${special} ${rofText}`.toLowerCase(); + const effectiveShots = Math.max(shotsPerFire, inferAutomaticWeaponShots(name)); + + if (text.includes("2 shots") || text.includes("2/round")) { + modes.push({ label: "Double", shots: 2 }); + } + if (text.includes("burst") || (special.includes("auto") && effectiveShots >= 3)) { + modes.push({ label: "Burst", shots: Math.max(3, effectiveShots) }); + } else if (effectiveShots === 2) { + modes.push({ label: "Double", shots: 2 }); + } else if (effectiveShots > 2) { + modes.push({ label: "Burst", shots: effectiveShots }); + } + if (text.includes("full auto") || special.includes("auto")) { + modes.push({ label: "Auto", shots: Math.max(text.includes("full auto") ? 6 : effectiveShots, 3) }); + } + + return modes; +} + +function inferAutomaticWeaponShots(name = "") { + const text = String(name ?? "").toLowerCase(); + if (/lmg|machine gun|minigun/.test(text)) return 6; + if (/assault rifle|fen\s*ar|smg|machine pistol|auto-shotgun|reaper/.test(text)) return 3; + return 1; +} diff --git a/module/item/item.js b/module/item/item.js new file mode 100644 index 0000000..c147a0c --- /dev/null +++ b/module/item/item.js @@ -0,0 +1,32 @@ +/** + * Extend the basic Item with some very simple modifications. + * @extends {Item} + */ +export class MothershipItem extends Item { + /** + * Augment the basic Item data model with additional dynamic data. + */ + prepareData() { + super.prepareData(); + + // Get the Item's data + const itemData = this; + const actorData = this.actor ? this.actor.system : {}; + const data = itemData.system; + } + + static chatListeners(html) { + html.on('click', '.use-skill', this._onChatUseSkill.bind(this)); + } + + static async _onChatUseSkill(event) { + const token = event.currentTarget.closest(".mosh"); + const actor = this._getChatCardActor(token); + if (!actor) return; + + const div = event.currentTarget.children[0]; + const skillId = div.dataset.itemId; + actor.rollSkill(skillId); + } + +} diff --git a/module/item/skill-sheet.js b/module/item/skill-sheet.js new file mode 100644 index 0000000..7b41b3b --- /dev/null +++ b/module/item/skill-sheet.js @@ -0,0 +1,72 @@ +/** + * Extend the basic MothershipItemSheet with skill related modifications + * @extends {MothershipItemSheet} + */ +import { MothershipItemSheet } from "./item-sheet.js"; +export class MothershipSkillSheet extends MothershipItemSheet { + + /** @override */ + static get defaultOptions() { + var options = { + }; + options.dragDrop = [{dragSelector: null, dropSelector: ".dropitem"}]; + + return foundry.utils.mergeObject(super.defaultOptions, options); + + } + + /** @override */ + async getData() { + const data = await super.getData(); + if (typeof data.system.prerequisite_ids == 'undefined'){ + data.system.prerequisite_ids=[]; + } + data.system.prerequisite_object = []; + for (const skill of data.system.prerequisite_ids){ + data.system.prerequisite_object.push(await fromUuid(skill)); + }; + + + return data; + } + + async _onDrop(event){ + await super._onDrop(event); + const droppedUuid = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); + if (droppedUuid.type != "Item"){ + return; + } + + const droppedObject = await fromUuid(droppedUuid.uuid); + if (droppedObject.type == "skill"){ + //todo: add a check if the skill already exist in the list and dont add it, (by id or by name?) + if(event.target.id == "skills.prerequisite"){ + let skills = this.object.system.prerequisite_ids; + skills.push(droppedObject.uuid); + this.object.update({"system.prerequisite_ids":skills}); + return this.render(false); + } + } + } + + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Delete skills-granted + html.find('.skills-delete').click(ev => { + const li = $(ev.currentTarget).parents(".item"); + + let skills = this.object.system.prerequisite_ids.filter(function( obj ) { + return obj !== li.data("itemId"); + }); + this.object.update({"system.prerequisite_ids":skills}); + return this.render(false); + }); + + } + + +} + diff --git a/module/logger.js b/module/logger.js new file mode 100644 index 0000000..1faa9df --- /dev/null +++ b/module/logger.js @@ -0,0 +1,27 @@ +const SYSTEM_ID = "sla-mothership"; +const PREFIX = "[SLA Mothership]"; + +function isDebugEnabled() { + try { + return game?.settings?.get?.(SYSTEM_ID, "debugLogging") === true; + } catch (_error) { + return false; + } +} + +export function slaDebug(...args) { + if (!isDebugEnabled()) return; + console.debug(PREFIX, ...args); +} + +export function slaInfo(...args) { + console.info(PREFIX, ...args); +} + +export function slaWarn(...args) { + console.warn(PREFIX, ...args); +} + +export function slaError(...args) { + console.error(PREFIX, ...args); +} diff --git a/module/mosh.js b/module/mosh.js new file mode 100644 index 0000000..07ba6b3 --- /dev/null +++ b/module/mosh.js @@ -0,0 +1,1251 @@ +// Import Modules +import { MothershipActor } from "./actor/actor.js"; +import { MothershipActorSheet, MothershipActorSheetDossier } from "./actor/actor-sheet.js"; +import { MothershipCreatureSheet } from "./actor/creature-sheet.js"; +import { MothershipShipSheet } from "./actor/ship-sheet.js"; +import { MothershipShipSheetSBT } from "./actor/ship-sheet-sbt.js"; + +import { MothershipItem } from "./item/item.js"; +import { MothershipItemSheet } from "./item/item-sheet.js"; +import { MothershipClassSheet } from "./item/class-sheet.js"; +import { MothershipSkillSheet } from "./item/skill-sheet.js"; +import { SLADrugSystem } from "./sla-drug-system.js"; +import { slaDebug } from "./logger.js"; +import { SLAMothershipGenerator } from "./windows/sla-character-generator.js"; +import { SLAWorldToolsApp, installSlaSidebarButtons } from "./windows/sla-world-tools.js"; + +import { + registerSettings +} from "./settings.js"; + +const SLA_INITIATIVE_BRACKETS = { + critSuccess: 5, + success: 4, + enemy: 3, + failure: 2, + critFailure: 1 +}; + +const SLA_WORLD_SKILL_IMAGE_OVERRIDES = { + Athletics: "systems/sla-mothership/images/sla-assets/Skills/Athletics.png", + Brawl: "systems/sla-mothership/images/sla-assets/Skills/Brawl.png" +}; + +Hooks.once('init', async function () { + + game.mosh = { + MothershipActor, + MothershipItem, + rollItemMacro, + rollStatMacro, + initRollTable, + initRollCheck, + initModifyActor, + initModifyItem, + noCharSelected + }; + game.slaMothership = { + ...game.mosh, + useDrug: (actor, itemId) => SLADrugSystem.useDrug({ actor, itemId }), + closeDrug: (actor, itemId, drug = "") => SLADrugSystem.closeDrug({ actor, itemId, drug }), + restartDrugReminders: () => SLADrugSystem.startReminderLoop(), + openGenerator: (actor = null, options = {}) => SLAMothershipGenerator.open(actor, options), + createRandomOperative: (options = {}) => SLAMothershipGenerator.createRandomOperative(options), + createStarterSquad: (options = {}) => SLAMothershipGenerator.createStarterSquad(options), + openTools: () => SLAWorldToolsApp.open(), + seedWorldContent: (options = {}) => game.slaMothershipCompendium?.seedWorld?.(options), + rollCombatInitiative: (combat, ids = []) => rollSlaCombatInitiative(combat, ids) + }; + + registerSettings(); + + + /** + * Set an initiative formula for the system + * @type {String} + */ + CONFIG.Combat.initiative = { + formula: "1d100", + decimals: 2 + }; + + // Define custom Entity classes + CONFIG.Actor.documentClass = MothershipActor; + CONFIG.Item.documentClass = MothershipItem; + + + // Register sheet application classes + foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet); + foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipActorSheet, {types: ['character'], makeDefault: true}); + foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipActorSheetDossier, {types: ['character'], makeDefault: false, label: "SLA Dossier"}); + foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipCreatureSheet, {types: ['creature'], makeDefault: false}); + foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipShipSheetSBT, {types: ['ship'], makeDefault: true}); + foundry.documents.collections.Actors.registerSheet("sla-mothership", MothershipShipSheet, {types: ['ship'], makeDefault: false}); + foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet); + foundry.documents.collections.Items.registerSheet("sla-mothership", MothershipClassSheet, {types: ['class'], makeDefault: true}); + foundry.documents.collections.Items.registerSheet("sla-mothership", MothershipSkillSheet, {types: ['skill'], makeDefault: true}); + foundry.documents.collections.Items.registerSheet("sla-mothership", MothershipItemSheet, { + types: [ + "item", + "drug", + "weapon", + "armor", + "ability", + "module", + "condition", + "crew", + "repair", + "persTrait" + ], + makeDefault: true + }); + + // If you need to add Handlebars helpers, here are a few useful examples: + Handlebars.registerHelper('concat', function () { + var outStr = ''; + for (var arg in arguments) { + if (typeof arguments[arg] != 'object') { + outStr += arguments[arg]; + } + } + return outStr; + }); + + Handlebars.registerHelper('toLowerCase', function (str) { + return str.toLowerCase(); + }); + + Handlebars.registerHelper('compare', function (varType, varOne, comparator, varTwo) { + if (varType === 'str') { + if (eval('"' + varOne + '"' + comparator + '"' + varTwo+ '"')) { + return true + } else { + return false + } + } else if (varType === 'int') { + if (eval(varOne + comparator + varTwo)) { + return true + } else { + return false + } + } + }); + //convert uuid list to names for display. + Handlebars.registerHelper('UUidListToNames',function(UuidList){ + var names = [] + for(let i=0;i { + await SLADrugSystem.handleEffectDeleted(effect, options); + }); + + Hooks.on("createItem", async (item) => { + const actor = item.parent; + if (!actor || actor.type !== "character" || typeof actor.enforceSlaEbbEligibility !== "function") return; + if (actor.isSlaEbbUser?.()) return; + await actor.enforceSlaEbbEligibility({ notify: true, refillFlux: false }); + }); + + Hooks.on("updateActor", async (actor, changes, options) => { + if (actor.type !== "character") return; + if (options?.slaSkipSpeciesBalance) return; + const speciesChanged = foundry.utils.hasProperty(changes, "system.sla.species.value"); + const packageChanged = foundry.utils.hasProperty(changes, "system.sla.trainingPackage.value") || foundry.utils.hasProperty(changes, "system.class.value"); + if (speciesChanged && typeof actor.enforceSlaSpeciesWounds === "function") { + await actor.enforceSlaSpeciesWounds(); + } + if (speciesChanged && typeof actor.enforceSlaEbbEligibility === "function") { + await actor.enforceSlaEbbEligibility({ + notify: true, + refillFlux: actor.isSlaEbbUser?.() + }); + } + if ((speciesChanged || packageChanged) && typeof actor.refreshSlaTraumaResponse === "function") { + await actor.refreshSlaTraumaResponse({ force: true }); + } + if (speciesChanged && typeof actor.reconcileSlaSpeciesBalance === "function") { + await actor.reconcileSlaSpeciesBalance({ force: true }); + } + }); + + Hooks.on("renderActorDirectory", (app, html) => { + installSlaSidebarButtons(app, html); + }); + + Hooks.on("renderSidebarTab", (app, html) => { + const isActorsTab = app?.tabName === "actors" || app?.options?.id === "actors"; + if (!isActorsTab) return; + installSlaSidebarButtons(app, html); + }); + + Hooks.on("renderCombatTracker", (app, html) => { + installSlaCombatTrackerControls(app, html); + }); + + Hooks.on("updateCombat", async (combat, changed) => { + if (!foundry.utils.hasProperty(changed, "round")) return; + if (!combat?.started) return; + if ((Number(combat.round ?? 0) || 0) <= 0) return; + + const processed = new Set(); + for (const combatant of combat.combatants ?? []) { + const actor = combatant.actor ?? combatant.token?.actor ?? null; + if (!actor || processed.has(actor.id)) continue; + processed.add(actor.id); + if (typeof actor.applySlaPrometheusRegeneration === "function") { + await actor.applySlaPrometheusRegeneration({ combat }); + } + } + }); + +}); + + +Hooks.once("ready", async function () { + SLADrugSystem.startReminderLoop(); + + // Wait to register hotbar drop hook on ready so that modules could register earlier if they want to + Hooks.on("hotbarDrop", (bar, data, slot) => { + if (data.type === "Item") { + createMothershipMacro(data, slot); + return false; + } + }); + + if (ui.actors) { + ui.actors.render(true); + } + + for (const actor of game.actors?.filter((entry) => entry.type === "character") ?? []) { + if (typeof actor.enforceSlaSpeciesWounds === "function") { + await actor.enforceSlaSpeciesWounds(); + } + if (typeof actor.enforceSlaEbbEligibility === "function") { + await actor.enforceSlaEbbEligibility({ notify: false, refillFlux: false }); + } + if (typeof actor.reconcileSlaSpeciesBalance === "function") { + await actor.reconcileSlaSpeciesBalance({ force: false }); + } + if (typeof actor.refreshSlaTraumaResponse === "function") { + await actor.refreshSlaTraumaResponse({ force: true }); + } + if (typeof actor.refreshSlaSkillPresentation === "function") { + await actor.refreshSlaSkillPresentation(); + } + } + + const worldSkillUpdates = (game.items ?? []) + .filter((item) => item.type === "skill" && SLA_WORLD_SKILL_IMAGE_OVERRIDES[item.name] && item.img !== SLA_WORLD_SKILL_IMAGE_OVERRIDES[item.name]) + .map((item) => ({ _id: item.id, img: SLA_WORLD_SKILL_IMAGE_OVERRIDES[item.name] })); + if (worldSkillUpdates.length) { + await Item.updateDocuments(worldSkillUpdates); + } + + patchSlaInitiativeSystem(); + +}); + +Hooks.on("renderChatMessageHTML", (app, html) => { + const root = html?.[0] ?? html; + if (!root?.querySelectorAll) return; + + root.querySelectorAll(".sla-wound-effect-link").forEach((button) => { + button.addEventListener("click", async (event) => { + event.preventDefault(); + event.stopPropagation(); + + const messageRoot = button.closest("[data-actor-id]"); + const actorId = messageRoot?.dataset?.actorId || app?.message?.speaker?.actor; + const actor = actorId ? game.actors?.get?.(actorId) : null; + if (!actor || typeof actor.rollSlaWoundEffect !== "function") { + ui.notifications.warn("The actor for this wound effect could not be found."); + return; + } + + const effectKey = button.dataset.woundEffect; + const modifier = button.dataset.woundModifier || "standard"; + await actor.rollSlaWoundEffect(effectKey, modifier); + }); + }); +}); + +//add custom damage dice for MOSH +Hooks.once('diceSoNiceReady', (dice3d) => { + dice3d.addColorset( + { + name: 'roll', + description: 'Roll Dice', + category: 'Mothership', + foreground: '#FFFFFF', + background: '#262626', + outline: 'none', + texture: 'none', + material: 'none', + font: 'Arial' + } + ) +}) + +//add custom damage dice for MOSH +Hooks.once('diceSoNiceReady', (dice3d) => { + dice3d.addColorset( + { + name: 'damage', + description: 'Damage Dice', + category: 'Mothership', + foreground: '#FFFFFF', + background: '#cc2828', + outline: 'none', + texture: 'none', + material: 'none', + font: 'Arial' + } + ) +}) + +//add custom panic dice for MOSH +Hooks.once('diceSoNiceReady', (dice3d) => { + dice3d.addColorset( + { + name: 'panic', + description: 'Panic Die', + category: 'Mothership', + foreground: '#000000', + background: '#FFF200', + outline: 'none', + texture: 'none', + material: 'metal', + font: 'Arial' + } + ) +}) + +//set initial things when creating an actor +Hooks.on("preCreateActor", (document, createData, options, userId) => { + slaDebug("preCreateActor fired for:", createData?.name, createData?.type); + + const disposition = + createData.type === "creature" + ? CONST.TOKEN_DISPOSITIONS.HOSTILE + : CONST.TOKEN_DISPOSITIONS.NEUTRAL; + + // Apply prototype token defaults (v12+) + document.updateSource({ + "prototypeToken.bar1.attribute": "system.health", // <-- use full system path + "prototypeToken.bar2.attribute": "system.hits", // adjust to your schema + "prototypeToken.displayName": CONST.TOKEN_DISPLAY_MODES.OWNER_HOVER, + "prototypeToken.displayBars": CONST.TOKEN_DISPLAY_MODES.OWNER_HOVER, + "prototypeToken.disposition": disposition, + "prototypeToken.name": createData.name + }); + + if (createData.type === "character") { + document.updateSource({ + "prototypeToken.disposition": CONST.TOKEN_DISPOSITIONS.FRIENDLY, + "prototypeToken.actorLink": true, + "prototypeToken.vision": true, + "system.other.stress.label": "Stress", + "system.sla.operativeType.value": "", + "system.sla.species.value": "", + "system.sla.speciesNotes.value": "", + "system.sla.trainingPackage.value": "", + "system.sla.packageSummary.value": "", + "system.sla.packageSkills.value": "", + "system.sla.packageWealth.value": "", + "system.sla.fluxStage.value": "", + "system.sla.bpn.value": "", + "system.sla.scl.value": "", + "system.sla.employer.value": "", + "system.sla.sector.value": "", + "system.sla.ebbRating.value": 0, + "system.sla.fluxNotes.value": "", + "system.sla.ebbNotes.value": "" + }); + + if (game.settings.get("sla-mothership", "useCalm")) { + document.updateSource({ + "system.other.stress.min": 0, + "system.other.stress.value": 85, + "system.other.stress.max": 85, + "system.other.stress.label": "Calm" + }); + } + } +}); + + +/* -------------------------------------------- */ +/* Hotbar Macros */ +/* -------------------------------------------- */ + +/** + * Create a Macro from an Item drop. + * Get an existing item macro if one exists, otherwise create a new one. + * @param {Object} data The dropped data + * @param {number} slot The hotbar slot to use + * @returns {Promise} + */ +async function createMothershipMacro(data, slot) { + + if (data.type !== "Item") return; + + var itemUUID = data.uuid.split("."); + slaDebug(itemUUID); + + var actor = game.actors.get(itemUUID[1]); + var item; + + item = foundry.utils.duplicate(actor.getEmbeddedDocument('Item',itemUUID[3])); + + slaDebug(item); + + if (!item) return ui.notifications.warn("You can only create macro buttons for owned Items"); + + // Create the macro command + let command = `game.mosh.rollItemMacro("${item.name}");`; + slaDebug(command); + let macro = game.macros.find(m => (m.name === item.name) && (m.command === command)); + if (!macro) { + macro = await Macro.create({ + name: item.name, + type: "script", + img: item.img, + command: command, + flags: { + "mosh.itemMacro": true + } + }); + } + game.user.assignHotbarMacro(macro, slot); + return false; +} + +/** + * Roll Macro from a Weapon. + * @param {string} itemName + * @return {Promise} + */ +function rollItemMacro(itemName) { + //init vars + let item; + let itemId; + //determine who to run the macro for + if (game.settings.get('sla-mothership','macroTarget') === 'character') { + //is there a selected character? warn if no + if (!game.user.character) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for the player's 'Selected Character' + //get item id + itemId = game.user.character.items.getName(itemName)._id; + //get item + item = foundry.utils.duplicate(game.user.character.getEmbeddedDocument("Item", itemId)); + //warn if no item + if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemName}`); + //roll action + if (item.type == "weapon") { + return game.user.character.rollCheck(null, 'low', 'combat', null, null, item); + } else if (item.type == "drug") { + return game.user.character.useSlaDrug(item.id); + } else if (item.type == "item" || item.type == "armor" || item.type == "ability" || item.type == "condition" || item.type == "repair") { + return game.user.character.printDescription(item.id); + } else if (item.type == "skill") { + return game.user.character.rollCheck(null, null, null, item.name, item.system.bonus, null); + } + } + } else if (game.settings.get('sla-mothership','macroTarget') === 'token') { + //is there a selected character? warn if no + if (!canvas.tokens.controlled.length) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for all selected tokens + canvas.tokens.controlled.forEach(function(token){ + //get item id + itemId = token.actor.items.getName(itemName)._id; + //get item + item = foundry.utils.duplicate(token.actor.getEmbeddedDocument("Item", itemId)); + //warn if no item + if (!item) return ui.notifications.warn(`Your controlled Actor does not have an item named ${itemName}`); + //roll action + if (item.type == "weapon") { + return token.actor.rollCheck(null, 'low', 'combat', null, null, item); + } else if (item.type == "drug") { + return token.actor.useSlaDrug(item.id); + } else if (item.type == "item" || item.type == "armor" || item.type == "ability" || item.type == "condition" || item.type == "repair") { + return token.actor.printDescription(item.id); + } else if (item.type == "skill") { + return token.actor.rollCheck(null, null, null, item.name, item.system.bonus, null); + } + }); + } + } +} + + +/** + * Roll Stat. + * @param {string} statName + * @return {Promise} + */ +function rollStatMacro() { + var selected = canvas.tokens.controlled; + const speaker = ChatMessage.getSpeaker(); + + if (selected.length == 0) { + selected = game.actors.tokens[speaker.token]; + } + + let actor; + if (speaker.token) actor = game.actors.tokens[speaker.token]; + if (!actor) actor = game.actors.get(speaker.actor); + const stat = actor ? Object.entries(actor.system.stats) : null; + + + // if (stat == null) { + // ui.notifications.info("Stat not found on token"); + // return; + // } + + slaDebug(stat); + + return actor.rollStatSelect(stat); +} + +//find and tell the actor to run the tableRoll function +async function initRollTable(tableId,rollString,aimFor,zeroBased,checkCrit,rollAgainst,comparison) { + //determine who to run the macro for + if (game.settings.get('sla-mothership','macroTarget') === 'character') { + //is there a selected character? warn if no + if (!game.user.character) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for the player's 'Selected Character' + game.user.character.rollTable(tableId,rollString,aimFor,zeroBased,checkCrit,rollAgainst,comparison); + } + } else if (game.settings.get('sla-mothership','macroTarget') === 'token') { + //is there a selected character? warn if no + if (!canvas.tokens.controlled.length) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for all selected tokens + canvas.tokens.controlled.forEach(function(token){ + token.actor.rollTable(tableId,rollString,aimFor,zeroBased,checkCrit,rollAgainst,comparison); + }); + } + } + //log what was done + slaDebug(`Initiated rollTable function with: tableId: ${tableId}, rollString: ${rollString}, aimFor: ${aimFor}, zeroBased: ${zeroBased}, checkCrit: ${checkCrit}, rollAgainst: ${rollAgainst}, comparison: ${comparison}`); +} + +//find and tell the actor to run the rollCheck function +async function initRollCheck(rollString,aimFor,attribute,skill,skillValue,weapon) { + //determine who to run the macro for + if (game.settings.get('sla-mothership','macroTarget') === 'character') { + //is there a selected character? warn if no + if (!game.user.character) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for the player's 'Selected Character' + game.user.character.rollCheck(rollString,aimFor,attribute,skill,skillValue,weapon); + } + } else if (game.settings.get('sla-mothership','macroTarget') === 'token') { + //is there a selected character? warn if no + if (!canvas.tokens.controlled.length) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for all selected tokens + canvas.tokens.controlled.forEach(function(token){ + token.actor.rollCheck(rollString,aimFor,attribute,skill,skillValue,weapon); + }); + } + } + //log what was done + slaDebug(`Initiated rollCheck function with: rollString: ${rollString}, aimFor: ${aimFor}, attribute: ${attribute}, skill: ${skill}, skillValue: ${skillValue}, weapon: ${weapon}`); +} + +//find and tell the actor to run the modifyActor function +async function initModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) { + //determine who to run the macro for + if (game.settings.get('sla-mothership','macroTarget') === 'character') { + //is there a selected character? warn if no + if (!game.user.character) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for the player's 'Selected Character' + game.user.character.modifyActor(fieldAddress,modValue,modRollString,outputChatMsg); + } + } else if (game.settings.get('sla-mothership','macroTarget') === 'token') { + //is there a selected character? warn if no + if (!canvas.tokens.controlled.length) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for all selected tokens + canvas.tokens.controlled.forEach(function(token){ + token.actor.modifyActor(fieldAddress,modValue,modRollString,outputChatMsg); + }); + } + } + //log what was done + slaDebug(`Initiated modifyActor function with: fieldAddress: ${fieldAddress}, modValue: ${modValue}, modRollString: ${modRollString}, outputChatMsg: ${outputChatMsg}`); +} + +//tell the actor to run the function +async function initModifyItem(itemId,addAmount) { + //determine who to run the macro for + if (game.settings.get('sla-mothership','macroTarget') === 'character') { + //is there a selected character? warn if no + if (!game.user.character) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for the player's 'Selected Character' + game.user.character.modifyItem(itemId,addAmount); + } + } else if (game.settings.get('sla-mothership','macroTarget') === 'token') { + //is there a selected character? warn if no + if (!canvas.tokens.controlled.length) { + //warn player + game.mosh.noCharSelected(); + } else { + //run the function for all selected tokens + canvas.tokens.controlled.forEach(function(token){ + token.actor.modifyItem(itemId,addAmount); + }); + } + } + //log what was done + slaDebug(`Initiated modifyItem function with: itemId: ${itemId}, addAmount: ${addAmount}`); +} + +function patchSlaInitiativeSystem() { + if (Combat.prototype._slaInitiativePatched) return; + + const originalRollInitiative = Combat.prototype.rollInitiative; + const originalRollAll = Combat.prototype.rollAll; + const originalRollNPC = Combat.prototype.rollNPC; + + Combat.prototype.rollInitiative = async function(ids, options = {}) { + const idList = Array.isArray(ids) ? ids : [ids]; + if (!idList.length) { + return originalRollInitiative.call(this, ids, options); + } + return rollSlaCombatInitiative(this, idList, { originalRollInitiative, ...options }); + }; + + Combat.prototype.rollAll = async function(options = {}) { + const ids = this.combatants.map((combatant) => combatant.id); + return this.rollInitiative(ids, options); + }; + + Combat.prototype.rollNPC = async function(options = {}) { + const ids = this.combatants.filter((combatant) => !isSlaPlayerCombatant(combatant)).map((combatant) => combatant.id); + return this.rollInitiative(ids, options); + }; + + Combat.prototype._slaInitiativePatched = true; + Combat.prototype._slaOriginalRollAll = originalRollAll; + Combat.prototype._slaOriginalRollNPC = originalRollNPC; +} + +function installSlaCombatTrackerControls(app, html) { + const root = html instanceof jQuery ? html[0] : html; + if (!root) return; + + const viewedCombat = app?.viewed ?? game.combat ?? null; + if (!viewedCombat) return; + + const bindOnce = (selector, handler) => { + for (const element of root.querySelectorAll(selector)) { + if (element.dataset.slaInitBound === "true") continue; + element.dataset.slaInitBound = "true"; + element.addEventListener("click", handler); + } + }; + + if (!root.querySelector(".sla-initiative-controls")) { + const trackerNav = root.querySelector("nav.encounters.tabbed") + ?? root.querySelector(".combat-tracker-header nav") + ?? root.querySelector("header"); + + if (trackerNav) { + trackerNav.insertAdjacentHTML("beforeend", ` + + + SLA Init + + `); + } + } + + bindOnce(".sla-initiative-controls", async (event) => { + event.preventDefault(); + event.stopPropagation(); + const combat = app?.viewed ?? game.combat ?? null; + if (!combat) return; + const ids = combat.combatants.map((combatant) => combatant.id); + await rollSlaCombatInitiative(combat, ids); + }); + + bindOnce("[data-action='rollAll'], [data-control='rollAll']", async (event) => { + event.preventDefault(); + event.stopPropagation(); + const combat = app?.viewed ?? game.combat ?? null; + if (!combat) return; + const ids = combat.combatants.map((combatant) => combatant.id); + await rollSlaCombatInitiative(combat, ids); + }); + + bindOnce("[data-action='rollNPC'], [data-control='rollNPC']", async (event) => { + event.preventDefault(); + event.stopPropagation(); + const combat = app?.viewed ?? game.combat ?? null; + if (!combat) return; + const ids = combat.combatants + .filter((combatant) => !isSlaPlayerCombatant(combatant)) + .map((combatant) => combatant.id); + await rollSlaCombatInitiative(combat, ids); + }); + + bindOnce("[data-action='rollInitiative'], [data-control='rollInitiative'], .combatant .token-initiative", async (event) => { + const combatantElement = event.currentTarget.closest("[data-combatant-id], .combatant"); + const combatantId = combatantElement?.dataset?.combatantId ?? combatantElement?.dataset?.documentId ?? ""; + if (!combatantId) return; + + event.preventDefault(); + event.stopPropagation(); + event.stopImmediatePropagation?.(); + + const combat = app?.viewed ?? game.combat ?? null; + if (!combat) return; + await rollSlaCombatInitiative(combat, [combatantId]); + }); + + for (const combatantElement of root.querySelectorAll("[data-combatant-id], .combatant")) { + const combatantId = combatantElement?.dataset?.combatantId ?? combatantElement?.dataset?.documentId ?? ""; + if (!combatantId) continue; + const combatant = viewedCombat.combatants?.get?.(combatantId) ?? null; + if (!combatant) continue; + + combatantElement.classList.toggle("sla-npc-enemy", !isSlaPlayerCombatant(combatant)); + + combatantElement.querySelectorAll(".sla-initiative-badge").forEach((badge) => badge.remove()); + + const initiativeType = String(combatant.getFlag?.("sla-mothership", "initiativeType") ?? "").trim(); + let badgeLabel = ""; + let badgeClass = ""; + if (initiativeType === "player-fast") { + badgeLabel = "Before Enemies"; + badgeClass = "sla-init-before"; + } else if (initiativeType === "player-slow") { + badgeLabel = "After Enemies"; + badgeClass = "sla-init-after"; + } else if (initiativeType === "enemy-bracket") { + badgeLabel = "Enemy"; + badgeClass = "sla-init-enemy"; + } + if (!badgeLabel) continue; + + const target = + combatantElement.querySelector(".token-initiative") || + combatantElement.querySelector(".combatant-initiative") || + combatantElement.querySelector("h4") || + combatantElement.querySelector(".combatant-name"); + if (!target) continue; + + const badge = document.createElement("span"); + badge.className = `sla-initiative-badge ${badgeClass}`; + badge.textContent = badgeLabel; + target.appendChild(badge); + } +} + +function isSlaPlayerCombatant(combatant) { + const actor = combatant?.actor ?? combatant?.token?.actor ?? null; + if (!actor || actor.type !== "character") return false; + + const disposition = combatant?.token?.disposition + ?? combatant?._token?.disposition + ?? actor?.prototypeToken?.disposition + ?? null; + + if (actor.hasPlayerOwner) return true; + if (disposition === CONST.TOKEN_DISPOSITIONS.FRIENDLY) return true; + return false; +} + +function getSlaInitiativeStatTotal(actor, attribute = "speed") { + const stat = actor?.system?.stats?.[attribute] ?? {}; + return Math.max(0, (Number(stat.value ?? 0) || 0) + (Number(stat.mod ?? 0) || 0)); +} + +function getSlaInitiativeDrugState(actor) { + const effects = SLADrugSystem.getActorDrugEffects(actor); + const state = { + mode: "normal", + autoSuccess: false, + autoSuccessLabel: "", + note: "", + sources: [] + }; + + for (const effect of effects) { + const flag = SLADrugSystem.getDrugEffectFlag(effect); + const stage = String(flag?.stage ?? "").trim().toLowerCase(); + const drugId = SLADrugSystem.normalize(flag?.drugId ?? effect?.name ?? ""); + if (!drugId || !stage) continue; + + if (stage === "withdrawal") { + state.mode = "disadvantage"; + state.sources.push(`${effect.name}: Withdrawal`); + continue; + } + + if (stage !== "active") continue; + + if (drugId === "blazeuv") { + state.autoSuccess = true; + state.autoSuccessLabel = "Blaze UV"; + state.note = "Automatic success. Declare your target before allies declare theirs."; + state.sources.push(effect.name); + continue; + } + if (drugId === "ultraviolence") { + if (!state.autoSuccess) { + state.autoSuccess = true; + state.autoSuccessLabel = "Ultra Violence"; + state.note = "Automatic success."; + } + state.sources.push(effect.name); + continue; + } + if (drugId === "rush" && state.mode !== "disadvantage") { + state.mode = "advantage"; + state.sources.push(effect.name); + } + } + + return state; +} + +async function chooseSlaInitiativeAttribute(combatant, drugState) { + const actor = combatant?.actor; + if (!actor) return null; + + return new Promise((resolve) => { + const speed = getSlaInitiativeStatTotal(actor, "speed"); + const intellect = getSlaInitiativeStatTotal(actor, "intellect"); + const modeText = drugState.autoSuccess + ? `${drugState.autoSuccessLabel}: automatic success.` + : drugState.mode === "advantage" + ? `Drug effect: roll with Advantage.` + : drugState.mode === "disadvantage" + ? `Drug effect: roll with Disadvantage.` + : `No active initiative modifier.`; + const noteText = drugState.note ? `

${drugState.note}

` : ""; + const sourceText = drugState.sources.length ? `

Source: ${drugState.sources.join(", ")}

` : ""; + + new foundry.applications.api.DialogV2({ + window: { title: `${combatant.name}: Initiative` }, + classes: ["macro-popup-dialog"], + content: ` +
+

Choose Initiative Stat

+

Roll Speed or Intellect. Success goes before enemies. Failure goes after enemies.

+

${modeText}

+ ${noteText} + ${sourceText} + + +
+ `, + buttons: [ + { + label: "Roll Initiative", + action: "roll", + icon: "fas fa-bolt", + callback: (_event, button) => { + const attribute = button.form.querySelector("input[name='sla-init-attr']:checked")?.value ?? "speed"; + resolve(attribute); + } + }, + { + label: "Cancel", + action: "cancel", + icon: "fas fa-times", + callback: () => resolve(null) + } + ], + close: () => resolve(null) + }).render({ force: true }); + }); +} + +function buildSlaInitiativeScore({ success = false, critical = false, statTotal = 0, rollTotal = null, enemy = false } = {}) { + if (enemy) return SLA_INITIATIVE_BRACKETS.enemy; + + const base = critical + ? (success ? SLA_INITIATIVE_BRACKETS.critSuccess : SLA_INITIATIVE_BRACKETS.critFailure) + : (success ? SLA_INITIATIVE_BRACKETS.success : SLA_INITIATIVE_BRACKETS.failure); + const statTie = Math.max(0, Number(statTotal ?? 0) || 0) / 100; + const rollTie = Number.isFinite(rollTotal) ? Math.max(0, 100 - Number(rollTotal)) / 10000 : 0; + return Number((base + statTie + rollTie).toFixed(4)); +} + +async function postSlaInitiativeChat(combatant, result) { + const actor = combatant?.actor; + if (!actor) return; + + const autoText = result.autoSuccess ? `
${result.autoSuccessLabel}: automatic initiative success.
${result.note ? `
${result.note}
` : ""}
` : ""; + const rollHtml = result.rollHtml ?? ""; + const outcome = result.success ? "Before Enemies" : "After Enemies"; + const critText = result.critical ? (result.success ? "Critical Success" : "Critical Failure") : "Standard Result"; + + const content = ` +
+
+
+
${result.attributeLabel} Initiative
+
+
+
+
Initiative Bracket
+
${outcome}
+
${critText}
+
Stat used: ${result.attributeLabel} ${result.statTotal}
+
+ ${autoText} + ${rollHtml} +
+
+ `; + + await ChatMessage.create({ + user: game.user.id, + speaker: { actor: actor.id, token: combatant.token?.id ?? actor.token, alias: actor.name }, + content + }); +} + +async function rollSlaCombatInitiative(combat, ids = [], options = {}) { + if (!combat) return null; + + const updates = []; + for (const id of ids) { + const combatant = combat.combatants.get(id); + if (!combatant) continue; + const actor = combatant.actor ?? combatant.token?.actor ?? null; + + if (!isSlaPlayerCombatant(combatant)) { + updates.push({ + _id: combatant.id, + initiative: buildSlaInitiativeScore({ enemy: true }), + flags: { + "sla-mothership": { + initiativeType: "enemy-bracket", + initiativeAttribute: "", + initiativeSuccess: null, + initiativeCritical: null + } + } + }); + continue; + } + + const drugState = getSlaInitiativeDrugState(actor); + const attribute = await chooseSlaInitiativeAttribute(combatant, drugState); + if (!attribute) continue; + + const attributeLabel = actor.system?.stats?.[attribute]?.label ?? foundry.utils.capitalize(attribute); + const statTotal = getSlaInitiativeStatTotal(actor, attribute); + + let success = true; + let critical = false; + let rollTotal = null; + let rollHtml = ""; + + if (!drugState.autoSuccess) { + const rollString = drugState.mode === "advantage" ? "1d100 [+]" : drugState.mode === "disadvantage" ? "1d100 [-]" : "1d100"; + const parsedRollString = actor.parseRollString(rollString, "low"); + const roll = await new Roll(parsedRollString).evaluate(); + const parsed = actor.parseRollResult(rollString, roll, true, true, statTotal, "<", null); + success = Boolean(parsed.success); + critical = Boolean(parsed.critical); + rollTotal = Number(parsed.total ?? roll.total ?? 0); + rollHtml = `${parsed.outcomeHtml}${parsed.rollHtml}`; + } + + const initiative = buildSlaInitiativeScore({ + success, + critical, + statTotal, + rollTotal + }); + + updates.push({ + _id: combatant.id, + initiative, + flags: { + "sla-mothership": { + initiativeType: success ? "player-fast" : "player-slow", + initiativeAttribute: attribute, + initiativeSuccess: success, + initiativeCritical: critical + } + } + }); + + await postSlaInitiativeChat(combatant, { + attribute, + attributeLabel, + statTotal, + success, + critical, + autoSuccess: drugState.autoSuccess, + autoSuccessLabel: drugState.autoSuccessLabel, + note: drugState.note, + rollHtml + }); + } + + if (updates.length) { + await combat.updateEmbeddedDocuments("Combatant", updates); + } + + return combat; +} + +//tell user no character is selected +async function noCharSelected() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //init vars + let errorMessage = ``; + //create error text based on current settings + if (game.settings.get('sla-mothership','macroTarget') === 'character') { + errorMessage = `

No Character Selected

Macro Target is set to the currently selected character. To select a character, modify your User Configuration in the Players menu located in the lower-left of the interface.

If you prefer Macros to be run on the currently selected token(s) in the scene, you should change your settings accordingly.

`; + } else if (game.settings.get('sla-mothership','macroTarget') === 'token') { + errorMessage = `

No Character Selected

Macro Target is set to the currently selected token(s) in the scene. To select token(s), click or draw a box around token(s) in the current scene.

If you prefer Macros to be run on the currently selected character for your user, you should change your settings accordingly.

`; + } + //create final dialog data + const dialogData = { + window: {title: `Macro Issue`}, + classes: ["macro-popup-dialog"], + content: errorMessage, + buttons: [ + { + label: `Ok`, + action: 'action_ok', + callback: () => { }, + icon: 'fas fa-check' + } + ] + }; + //render dialog + const dialog = new foundry.applications.api.DialogV2(dialogData).render({force: true}); + //log what was done + slaDebug(`Told the user that no character was selected.`); + }); +} + +//tell user no ship is selected +async function noShipSelected() { + //wrap the whole thing in a promise, so that it waits for the form to be interacted with + return new Promise(async (resolve) => { + //init vars + let errorMessage = ``; + //create error text based on current settings + if (game.settings.get('sla-mothership','macroTarget') === 'character') { + errorMessage = `

No Ship Selected

Macro Target is set to the currently selected character. To select a ship, modify your User Configuration in the Players menu located in the lower-left of the interface.

If you prefer Macros to be run on the currently selected token(s) in the scene, you should change your settings accordingly.

`; + } else if (game.settings.get('sla-mothership','macroTarget') === 'token') { + errorMessage = `

No Ship Selected

Macro Target is set to the currently selected token(s) in the scene. To select token(s), click or draw a box around token(s) in the current scene.

If you prefer Macros to be run on the currently selected character for your user, you should change your settings accordingly.

`; + } + //create final dialog data + const dialogData = { + window: {title: `Macro Issue`}, + classes: ["macro-popup-dialog"], + content: errorMessage, + buttons: [ + { + label: `Ok`, + action: 'action_ok', + callback: () => { }, + icon: 'fas fa-check' + } + ] + }; + //render dialog + const dialog = foundry.applications.api.DialogV2(dialogData).render({force: true}); + //log what was done + slaDebug(`Told the user that no character was selected.`); + }); +} + + +/** + * get element from world or compendiums by id or UUID, filtering by specific type. + * @param {string} id_uuid The id or the full uuid of the element we want to retieve. + * @param {object} options General search options for this function and for 'fromUuid' + * @param {string} [options.type] A string to filter the compendium type to search or the world element type. Valid values =["RollTable","Item","Macro","Actor","Adventure","Cards","JournalEntry","Playlist","Scene"] + * @returns {Promise} Returns the Document if it could be found, otherwise null. + */ +export async function fromIdUuid(id_uuid, options={}){ + let type = options.type; + //first we try to find from UUID, asuming the parameter(id_uuid) is an UUID. + let item = await fromUuid(id_uuid,options); + if(item != null){ + //we found the item with the id_uuid, it probably was an uuid. + return item; + } + + //we need to manualy find the item + let currentLocation = ''; + let objectLocation = ''; + //first loop through each compendium + game.packs.forEach(function(pack){ + //is this a pack of rolltables? + if (pack.metadata.type === type) { + //log where we are + currentLocation = pack.metadata.id; + //loop through each pack to find the right table + pack.index.forEach(function(pack_item) { + //is this our table? + if (pack_item._id === id_uuid) { + //grab the table location + objectLocation = currentLocation; + } + }); + } + }); + if (objectLocation){ + // Item found in a compendium -> get document data + return await game.packs.get(objectLocation).getDocument(id_uuid); + }else{ + //if we dont find it in a compendium, its probable a world item: + //Lets filtery by type to search the relevant elements only. + switch (type) { + case "RollTable": + return getTableFromId(id_uuid); + case "Item": + return getItemFromId(id_uuid); + case "Macro": + return getMacroFromId(id_uuid); + case "Actor": + return getActorFromId(id_uuid); + case "Adventure": + //adventures can only be defined in compendiums and not in the world (i think) + return null; + case "Cards": + return getCardFromId(id_uuid); + case "JournalEntry": + return getJournalFromId(id_uuid); + case "Playlist": + return getPlaylistFromId(id_uuid); + case "Scene": + return getSceneFromId(id_uuid); + + default: + //type is not defined, and we could not find it in a compendium, + //now we search all world elements for the ID. + //this could lead to conflicts since ID could not be unique. + let tableData = getTableFromId(id_uuid); + if (tableData){ + return tableData; + } + let itemData = getItemFromId(id_uuid); + if (itemData){ + return itemData; + } + let macroData = getMacroFromId(id_uuid); + if (macroData){ + return macroData; + } + let actorData = getActorFromId(id_uuid); + if (actorData){ + return actorData; + } + let cardData = getCardFromId(id_uuid); + if (cardData){ + return cardData; + } + let journalData = getJournalFromId(id_uuid); + if (journalData){ + return journalData; + } + let scenneData = getSceneFromId(id_uuid); + if (scenneData){ + return scenneData; + } + let playlistData = getPlaylistFromId(id_uuid); + if (playlistData){ + return playlistData; + } + } + //if we get here we have not found anything with that id. + return null; + } + /**functions to get world defined elements by type and ID */ + function getSceneFromId(sceneId){ + return game.scenes.filter(i=> i.id == sceneId)[0]; + } + function getPlaylistFromId(playlistId){ + return game.playlists.filter(i=> i.id == playlistId)[0]; + } + function getJournalFromId(journalId){ + return game.journal.filter(i=> i.id == journalId)[0]; + } + function getCardFromId(cardId){ + return game.cards.filter(i=> i.id == cardId)[0]; + } + function getActorFromId(actorId){ + return game.actors.filter(i=> i.id == actorId)[0]; + } + function getTableFromId(tableId){ + return game.tables.filter(i=> i.id == tableId)[0]; + } + function getItemFromId(itemId){ + return game.items.filter(i=> i.id == itemId)[0]; + } + function getMacroFromId(macroId){ + return game.macros.filter(i=> i.id == macroId)[0]; + } + +} + +/** + * This function will format a number into a more readable string with appropriate suffixes. + * For example, 1500 becomes "1.5K", 2000000 becomes "2M", etc. + * It handles numbers in the trillions (t), billions (b), millions (m), and thousands (k). + * It also handles negative numbers and zero. + * At the end it appends 'cr' to denote credits. + * @namespace formatCreditsNumber + * @param {int} num Credits number to format. + * @returns {string} Credits , formatted string with appropriate suffix. + */ +export function formatCreditsNumber(num) { + const absNum = Math.abs(num); + + if (absNum >= 1_000_000_000_000) { + return (num / 1_000_000_000_000).toFixed(1).replace(/\.0$/, '') + 'tcr'; + } else if (absNum >= 1_000_000_000) { + return (num / 1_000_000_000).toFixed(1).replace(/\.0$/, '') + 'bcr'; + } else if (absNum >= 1_000_000) { + return (num / 1_000_000).toFixed(1).replace(/\.0$/, '') + 'mcr'; + } else if (absNum >= 1_000) { + return (num / 1_000).toFixed(1).replace(/\.0$/, '') + 'kcr'; + } else { + return num.toString() + 'cr'; + } +} diff --git a/module/settings.js b/module/settings.js new file mode 100644 index 0000000..57e7046 --- /dev/null +++ b/module/settings.js @@ -0,0 +1,492 @@ +import { rolltableConfig } from "./windows/settings-rolltables.js"; +import { SLAWorldToolsApp } from "./windows/sla-world-tools.js"; +import { slaDebug, slaInfo } from "./logger.js"; + +export const registerSettings = function () { + game.settings.register('sla-mothership', 'debugLogging', { + name: "Debug Logging", + hint: "Enable verbose SLA Mothership debug logging in the browser console.", + default: false, + scope: 'world', + type: Boolean, + config: true, + onChange: value => { + slaInfo(`Debug logging ${value ? "enabled" : "disabled"}.`); + } + }); + + game.settings.register('sla-mothership', 'firstEdition', { + name: "1e Rules", + hint: "Use the 1st edition rules and character sheet.", + default: true, + scope: 'world', + type: Boolean, + config: true, + onChange: value => { + slaDebug("firstEdition set to", value); + //get list of actors + let actorList = game.actors; + let actorName = ''; + let maxStart = null; + let maxEnd = null; + //only make changes if calm is false + if (game.settings.get('sla-mothership','useCalm') === false) { + //if setting is now true + if (value) { + //loop through all actors and update their maximum stress + //get list of actors + let actorList = game.actors; + //loop through each actor + actorList.forEach(function(actor){ + //loop through each result + if (actor.type === 'character') { + //set character name + actorName = actor.name; + //set current values + maxStart = actor.system.other.stress.max; + //set max stress to 20 + actor.update({'system.other.stress.max': 20}); + //set final values + actorList = game.actors; + maxEnd = 20; + //log change + slaDebug(`${actorName} stress.max changed from ${maxStart} to ${maxEnd}`); + //rerender this sheet + actor.render(); + } + }); + //if value is now false + } else { + //loop through all actors and update their maximum stress + //get list of actors + let actorList = game.actors; + //loop through each actor + actorList.forEach(function(actor){ + //loop through each result + if (actor.type === 'character') { + //set character name + actorName = actor.name; + //set current values + maxStart = actor.system.other.stress.max; + //set max stress to 999 + actor.update({'system.other.stress.max': 999}); + //set final values + actorList = game.actors; + maxEnd = 999; + //log change + slaDebug(`${actorName} stress.max changed from ${maxStart} to ${maxEnd}`); + //rerender this sheet + actor.render(); + } + }); + } + } else { + //get list of actors + let actorList = game.actors; + //loop through each actor + actorList.forEach(function(actor){ + //loop through each result + if (actor.type === 'character') { + //log change + slaDebug("First Edition switched to", value); + //rerender this sheet + actor.render(); + } + }); + } + } + }); + + game.settings.register('sla-mothership', 'macroTarget', { + name: "Macro Target", + hint: "Who should be the target for macros?", + default: "character", + scope: 'world', + type: String, + choices: { + "character": "Currently selected character for the player", + "token": "Currently selected token(s) in the scene" + }, + config: true, + onChange: value => { + //log the change + slaDebug("Macro target set to", value); + } + }); + + game.settings.register('sla-mothership', 'critDamage', { + name: "Critical Hit Damage", + hint: "What should the damage be on a critical hit?", + default: "advantage", + scope: 'world', + type: String, + choices: { + "advantage": "Roll with advantage", + "doubleDamage": "Double the damage result", + "doubleDice": "Double the damage dice", + "maxDamage": "Maximum possible damage result", + "weaponValue": "Defer to each weapon's critical damage", + "none": "No critical damage" + }, + config: true, + onChange: value => { + //log the change + slaDebug("Critical hits set to", value); + } + }); + + game.settings.register('sla-mothership', 'damageDiceTheme', { + name: "Damage Dice Theme", + hint: "If DiceSoNice is installed, what theme should be applied to damage dice?", + default: "damage", + scope: 'world', + type: String, + config: true, + onChange: value => { + //log the change + slaDebug("Damage dice theme set to", value); + } + }); + + game.settings.register('sla-mothership', 'panicDieTheme', { + name: "Panic Die Theme", + hint: "If DiceSoNice is installed, what theme should be applied to the panic die?", + default: "panic", + scope: 'world', + type: String, + config: true, + onChange: value => { + //log the change + slaDebug("Panic die theme set to", value); + } + }); + + game.settings.register('sla-mothership', 'hideWeight', { + name: "Hide 0e Weight", + hint: "Hide the 0e weight mechanic in the items list for players and ships?", + default: true, + scope: 'world', + type: Boolean, + config: true, + onChange: value => { + //log the change + slaDebug("hideWeight set to", value); + } + }); + + game.settings.register('sla-mothership', 'drugReminderMinutes', { + name: "Drug Reminder Interval", + hint: "How often should the GM receive a chat reminder about active SLA drugs? Set to 0 to disable reminders.", + default: 15, + scope: 'world', + type: Number, + config: true, + onChange: value => { + slaDebug("drugReminderMinutes set to", value); + game.slaMothership?.restartDrugReminders?.(); + } + }); + + game.settings.register('sla-mothership', 'useCalm', { + name: "Use Calm?", + hint: "Uses the traaa.sh Calm system instead of Stress.", + default: false, + scope: 'world', + type: Boolean, + config: true, + onChange: value => { + //log the change + slaDebug("useCalm set to", value); + //get list of actors + let actorList = game.actors; + let actorName = ''; + let minStart = null; + let valueStart = null; + let maxStart = null; + let labelStart = ''; + let minEnd = null; + let valueEnd = null; + let maxEnd = null; + let labelEnd = ''; + //if setting is now true + if (value) { + //loop through all actors and update their stress values + actorList.forEach(function(actor){ + //loop through each result + if (actor.type === 'character') { + //set character name + actorName = actor.name; + //set current values + minStart = actor.system.other.stress.min; + valueStart = actor.system.other.stress.value; + maxStart = actor.system.other.stress.max; + labelStart = actor.system.other.stress.label; + //update max calm + //set max calm to 85 if min stress is 2 + if (minStart === 2) { + actor.update({'system.other.stress.max': 85}); + maxEnd = 85; + //otherwise convert the min stress to max calm + } else { + actor.update({'system.other.stress.max': Math.round(85-(actor.system.other.stress.value*3))}); + maxEnd = Math.round(85-(actor.system.other.stress.value*3)); + } + //set min stress to 0 + actor.update({'system.other.stress.min': 0}); + minEnd = 0; + //update calm + //set calm to 85 if stress is 2 + if (valueStart === 2) { + actor.update({'system.other.stress.value': 85}); + valueEnd = 85; + //otherwise convert stress to calm + } else { + actor.update({'system.other.stress.value': Math.round(85-(actor.system.other.stress.value*3))}); + valueEnd = Math.round(85-(actor.system.other.stress.value*3)); + } + //set stress label to Calm + actor.update({'system.other.stress.label': 'Calm'}); + labelEnd = 'Calm'; + //log change + slaDebug(`${actorName} stress.min changed from ${minStart} to ${minEnd}`); + slaDebug(`${actorName} stress.value changed from ${valueStart} to ${valueEnd}`); + slaDebug(`${actorName} stress.max changed from ${maxStart} to ${maxEnd}`); + slaDebug(`${actorName} stress.label changed from ${labelStart} to ${labelEnd}`); + //rerender this sheet + actor.render(); + } + }); + //if value is now false + } else { + //loop through all actors and update their stress values + actorList.forEach(function(actor){ + //loop through each result + if (actor.type === 'character') { + //set character name + actorName = actor.name; + //set current values + minStart = actor.system.other.stress.min; + valueStart = actor.system.other.stress.value; + maxStart = actor.system.other.stress.max; + labelStart = actor.system.other.stress.label; + //convert maximum calm to min stress + //set min stress to 20 if > 20 + if (Math.round((85-actor.system.other.stress.max)/3) > 20) { + actor.update({'system.other.stress.min': 20}); + minEnd = 20; + //set min stress to 2 if < 2 + } else if (Math.round((85-actor.system.other.stress.max)/3) < 2) { + actor.update({'system.other.stress.min': 2}); + minEnd = 2; + //regular value + } else { + actor.update({'system.other.stress.min': Math.round((85-actor.system.other.stress.max)/3)}); + minEnd = Math.round((85-actor.system.other.stress.max)/3); + } + //set max stress based on current system setting + if (game.settings.get('sla-mothership','firstEdition')) { + //set max stress to 20 + actor.update({'system.other.stress.max': 20}); + maxEnd = 20; + } else { + //set max stress to 999 + actor.update({'system.other.stress.max': 999}); + maxEnd = 999; + } + //convert calm to stress + actor.update({'system.other.stress.value': Math.round((85-actor.system.other.stress.value)/3)}); + valueEnd = Math.round((85-actor.system.other.stress.value)/3); + //set stress label to Stress + actor.update({'system.other.stress.label': 'Stress'}); + labelEnd = 'Stress' + //log change + slaDebug(`${actorName} stress.min changed from ${minStart} to ${minEnd}`); + slaDebug(`${actorName} stress.value changed from ${valueStart} to ${valueEnd}`); + slaDebug(`${actorName} stress.max changed from ${maxStart} to ${maxEnd}`); + slaDebug(`${actorName} stress.label changed from ${labelStart} to ${labelEnd}`); + //rerender this sheet + actor.render(); + } + }); + } + + } + }); + + game.settings.register('sla-mothership', 'androidPanic', { + name: "Use Android Panic Tables?", + hint: "Adds android-specific tables for Panic and Calm checks.", + default: false, + scope: 'world', + type: Boolean, + config: true, + onChange: value => { + //log the change + slaDebug("androidPanic set to", value); + } + }); + + game.settings.register('sla-mothership', 'autoStress', { + name: "Auto Stress Gain on Failures?", + hint: "Automatically handles stress gain on a failed roll.", + default: true, + scope: 'world', + type: Boolean, + config: true, + onChange: value => { + //log the change + slaDebug("autoStress set to", value); + } + }); + + game.settings.registerMenu('sla-mothership', 'rolltableSelector', { + name: "Rolltable Configuration", + label: "Choose Tables", + hint: "Customize which rolltables are used.", + icon: "fa-solid fa-list", + type: rolltableConfig + }); + + game.settings.registerMenu('sla-mothership', 'worldTools', { + name: "SLA World Tools", + label: "Open Tools", + hint: "Launch the SLA Mothership generator, world seeding actions, and starter squad tools.", + icon: "fa-solid fa-toolbox", + type: SLAWorldToolsApp, + restricted: true + }); + + game.settings.register('sla-mothership', 'table0ePanicStressNormal', { + scope: 'world', + config: false, + type: String, + default: "1vCm4ElRPotQXgNB" + }); + + game.settings.register('sla-mothership', 'table0ePanicStressAndroid', { + scope: 'world', + config: false, + type: String, + default: "egJ11m2mJM3HBd6d" + }); + + game.settings.register('sla-mothership', 'table0ePanicCalmNormal', { + scope: 'world', + config: false, + type: String, + default: "kqKpQAXyLTEEyz6Z" + }); + + game.settings.register('sla-mothership', 'table0ePanicCalmAndroid', { + scope: 'world', + config: false, + type: String, + default: "VW6HQ29T7zClNIZ6" + }); + + game.settings.register('sla-mothership', 'table1ePanicStressNormal', { + scope: 'world', + config: false, + type: String, + default: "ypcoikqHLhnc9tNs" + }); + + game.settings.register('sla-mothership', 'table1ePanicStressAndroid', { + scope: 'world', + config: false, + type: String, + default: "aBnY19jlhPXzibCt" + }); + + game.settings.register('sla-mothership', 'table1ePanicCalmNormal', { + scope: 'world', + config: false, + type: String, + default: "MOYI6Ntj5OVFYk06" + }); + + game.settings.register('sla-mothership', 'table1ePanicCalmAndroid', { + scope: 'world', + config: false, + type: String, + default: "GCtYeCCQVQJ5M6SE" + }); + + game.settings.register('sla-mothership', 'table1eWoundBluntForce', { + scope: 'world', + config: false, + type: String, + default: "31YibfjueXuZdNLb" + }); + + game.settings.register('sla-mothership', 'table1eWoundBleeding', { + scope: 'world', + config: false, + type: String, + default: "ata3fRz3uoPfNCLh" + }); + + game.settings.register('sla-mothership', 'table1eWoundGunshot', { + scope: 'world', + config: false, + type: String, + default: "XjDU2xFOWEasaZK0" + }); + + game.settings.register('sla-mothership', 'table1eWoundFireExplosives', { + scope: 'world', + config: false, + type: String, + default: "lqiaWwh5cGcJhvnu" + }); + + game.settings.register('sla-mothership', 'table1eWoundGoreMassive', { + scope: 'world', + config: false, + type: String, + default: "uVfC1CqYdojaJ7yR" + }); + + game.settings.register('sla-mothership', 'table0eDeath', { + scope: 'world', + config: false, + type: String, + default: "cZOHlhEJcYGZsQBM" + }); + + game.settings.register('sla-mothership', 'table1eDeath', { + scope: 'world', + config: false, + type: String, + default: "W36WFIpCfMknKgHy" + }); + + game.settings.register('sla-mothership', 'table1eDistressSignal', { + scope: 'world', + config: false, + type: String, + default: "UxAjAqUTjYTcCbS8" + }); + + game.settings.register('sla-mothership', 'table1eMegadamageEffects', { + scope: 'world', + config: false, + type: String, + default: "AqGWwoWXzijFs427" + }); + + game.settings.register('sla-mothership', 'table1eMaintenance', { + scope: 'world', + config: false, + type: String, + default: "kqz8GsFVPfjvqO0N" + }); + + game.settings.register('sla-mothership', 'table1eBankruptcy', { + scope: 'world', + config: false, + type: String, + default: "BsfdIl7CJNs1PViS" + }); + +}; diff --git a/module/settings/creature-settings.js b/module/settings/creature-settings.js new file mode 100644 index 0000000..984e546 --- /dev/null +++ b/module/settings/creature-settings.js @@ -0,0 +1,160 @@ +export class DLCreatureSettings extends FormApplication { + static get defaultOptions() { + const options = super.defaultOptions; + options.id = 'sheet-modifiers'; + options.classes = ["mosh", "sheet", "actor", "creature"]; + options.template = 'systems/sla-mothership/templates/dialogs/creature-settings-dialog.html'; + options.width = 320; + options.height = 150; + return options; + } + /* -------------------------------------------- */ + /** + * Add the Entity name into the window title + * @type {String} + */ + get title() { + return `${this.object.name}: Creature Settings`; + } + /* -------------------------------------------- */ + + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + getData() { + const actor = this.object; + console.log(this.object); + + return { + actor + }; + } + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + html.find(`input[type=checkbox][id="system.stats.combat.enabled"]`).click(ev => { + if (ev.currentTarget.checked) { + const combat = html.find(`input[type=checkbox][id="system.stats.combat.enabled"]`).prop('checked', true); + } + + this.object.update({ + "system.stats.combat.enabled": ev.currentTarget.checked + }); + }); + html.find(`input[type=checkbox][id="system.stats.instinct.enabled"]`).click(ev => { + if (ev.currentTarget.checked) { + const instinct = html.find(`input[type=checkbox][id="system.stats.instinct.enabled"]`).prop('checked', true); + } + + this.object.update({ + "system.stats.instinct.enabled": ev.currentTarget.checked + }); + }); + html.find(`input[type=checkbox][id="system.stats.loyalty.enabled"]`).click(ev => { + if (ev.currentTarget.checked) { + const loyalty = html.find(`input[type=checkbox][id="system.stats.loyalty.enabled"]`).prop('checked', true); + } + + this.object.update({ + "system.stats.loyalty.enabled": ev.currentTarget.checked + }); + }); + html.find(`input[type=checkbox][id="system.stats.speed.enabled"]`).click(ev => { + if (ev.currentTarget.checked) { + const speed = html.find(`input[type=checkbox][id="system.stats.speed.enabled"]`).prop('checked', true); + } + + this.object.update({ + "system.stats.speed.enabled": ev.currentTarget.checked + }); + }); + html.find(`input[type=checkbox][id="system.stats.armor.enabled"]`).click(ev => { + if (ev.currentTarget.checked) { + const armor = html.find(`input[type=checkbox][id="system.stats.armor.enabled"]`).prop('checked', true); + } + + this.object.update({ + "system.stats.armor.enabled": ev.currentTarget.checked + }); + }); + html.find(`input[type=checkbox][id="system.stats.sanity.enabled"]`).click(ev => { + if (ev.currentTarget.checked) { + const sanity = html.find(`input[type=checkbox][id="system.stats.sanity.enabled"]`).prop('checked', true); + } + + this.object.update({ + "system.stats.sanity.enabled": ev.currentTarget.checked + }); + }); + html.find(`input[type=checkbox][id="system.swarm.enabled"]`).click(ev => { + this.object.update({ + "system.swarm.enabled": ev.currentTarget.checked + }); + + let swarm_combat = 0; + let current_combat = 0; + + if (ev.currentTarget.checked) { + //set backup of current combat + swarm_combat = this.object.system.stats.combat.value; + //calculate new combat stat based on wounds, + current_combat = this.object.system.stats.combat.value * ( this.object.system.hits.max - this.object.system.hits.value); + } + else{ + //revert back combat if swarm is disabled + current_combat = this.object.system.swarm.combat.value; + } + this.object.update({ + "system.stats.combat.value":current_combat, + "system.swarm.combat.value":swarm_combat + }); + }); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + + console.log("Updating Object"); + + // Loyalty + if (this.object.system.stats.loyalty.enabled) { + await this.object.update({ + "data.stats.loyalty.enabled": true + }); + } + // Speed + if (this.object.system.stats.stats.speed.enabled) { + await this.object.update({ + "data.stats.speed.enabled": true + }); + } + // Armor + if (this.object.system.stats.stats.armor.enabled) { + await this.object.update({ + "data.stats.armor.enabled": true + }); + } + // swarm + if (this.object.system.swarm.enabled) { + await this.object.update({ + "data.swarm.enabled": true + }); + } + + await this.object.updateEmbeddedEntity("OwnedItem", update); + + this.object.update({ + formData + }); + this.object.sheet.render({force: true}); + } +} diff --git a/module/sla-drug-system.js b/module/sla-drug-system.js new file mode 100644 index 0000000..fe8d76a --- /dev/null +++ b/module/sla-drug-system.js @@ -0,0 +1,786 @@ +const SYSTEM_ID = "sla-mothership"; +const COMPANION_MODULE_ID = "sla-mothership-compendium"; +const DRUG_FLAG_PATH = `${SYSTEM_ID}.slaDrug`; +const ADDICTION_ICON = "systems/sla-mothership/images/sla-assets/Traits/drug-addict.png"; + +let cachedDrugData = null; +let drugReminderIntervalId = null; + +export class SLADrugSystem { + static async loadDrugData() { + if (cachedDrugData) return cachedDrugData; + const response = await fetch(`modules/${COMPANION_MODULE_ID}/sla-data/drugs.json`); + if (!response.ok) { + throw new Error("Failed loading SLA drug data."); + } + cachedDrugData = await response.json(); + return cachedDrugData; + } + + static normalize(value = "") { + return String(value ?? "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, "") + .trim(); + } + + static isFrother(actor) { + return this.normalize(actor?.system?.sla?.species?.value ?? "") === "frother"; + } + + static isEbbUser(actor) { + return ["ebon", "brainwaster"].includes(this.normalize(actor?.system?.sla?.species?.value ?? "")); + } + + static async getDrugDefinition(drugRef) { + const data = await this.loadDrugData(); + if (drugRef && typeof drugRef === "object" && drugRef.id) { + return data.drugs.find((entry) => entry.id === drugRef.id) ?? null; + } + const normalized = this.normalize(drugRef); + return data.drugs.find((entry) => entry.id === normalized || this.normalize(entry.name) === normalized) ?? null; + } + + static async getDrugDefinitionFromItem(item) { + if (!item) return null; + const directId = item.flags?.[SYSTEM_ID]?.slaDrug?.id ?? item.system?.sla?.drugId ?? ""; + const fromId = await this.getDrugDefinition(directId); + if (fromId) return fromId; + return this.getDrugDefinition(item.name); + } + + static getDrugEffectFlag(effect) { + return effect?.flags?.[SYSTEM_ID]?.slaDrug ?? null; + } + + static async resolveExpiredEffects(actor) { + if (!actor) return; + await this.migrateLegacyDrugEffects(actor); + const now = Date.now(); + for (const effect of actor.effects ?? []) { + const flag = this.getDrugEffectFlag(effect); + if (!flag?.expiresAt) continue; + if (Number(flag.expiresAt) > now) continue; + await effect.delete(); + } + } + + static getRemainingLabel(effect) { + const flag = this.getDrugEffectFlag(effect); + if (!flag) return ""; + if (!flag.expiresAt) { + return flag.manualOnly ? "Manual" : ""; + } + const remainingMs = Math.max(0, Number(flag.expiresAt) - Date.now()); + const totalSeconds = Math.ceil(remainingMs / 1000); + const hours = Math.floor(totalSeconds / 3600); + const minutes = Math.floor((totalSeconds % 3600) / 60); + const seconds = totalSeconds % 60; + if (hours > 0) return `${hours}h ${minutes}m`; + if (minutes > 0) return `${minutes}m`; + return `${seconds}s`; + } + + static getStatModifierTitles(actor) { + const stats = { + strength: [], + speed: [], + intellect: [], + combat: [], + sanity: [], + fear: [], + body: [] + }; + + for (const effect of actor?.effects ?? []) { + const flag = this.getDrugEffectFlag(effect); + const source = flag?.drugId ? `${effect.name}` : `${effect.name ?? "Effect"}`; + for (const change of effect.changes ?? []) { + const match = String(change.key ?? "").match(/^system\.stats\.(strength|speed|intellect|combat|sanity|fear|body)\.mod$/); + if (!match) continue; + const statKey = match[1]; + const value = Number(change.value ?? 0); + if (!value) continue; + stats[statKey].push(`${source}: ${value >= 0 ? `+${value}` : value}`); + } + } + + return Object.fromEntries( + Object.entries(stats).map(([key, entries]) => [ + key, + entries.length ? entries.join("\n") : "No active modifiers." + ]) + ); + } + + static clearReminderLoop() { + if (drugReminderIntervalId) { + clearInterval(drugReminderIntervalId); + drugReminderIntervalId = null; + } + } + + static startReminderLoop() { + this.clearReminderLoop(); + if (!game.user?.isGM || game.system?.id !== SYSTEM_ID) return; + const minutes = Math.max(0, Number(game.settings.get(SYSTEM_ID, "drugReminderMinutes") ?? 0) || 0); + if (!minutes) return; + + drugReminderIntervalId = window.setInterval(() => { + this.postActiveDrugReminder().catch((error) => console.error(`${SYSTEM_ID} | Drug reminder failed`, error)); + }, minutes * 60 * 1000); + } + + static async postActiveDrugReminder() { + if (!game.user?.isGM || game.system?.id !== SYSTEM_ID) return; + + const rows = []; + for (const actor of game.actors?.filter((entry) => entry.type === "character") ?? []) { + await this.resolveExpiredEffects(actor); + for (const effect of actor.effects ?? []) { + const flag = this.getDrugEffectFlag(effect); + if (!flag || !["active", "pending", "withdrawal", "withdrawal-check"].includes(flag.stage)) continue; + const def = await this.getDrugDefinition(flag.drugId); + rows.push({ + actor: actor.name, + drug: def?.name ?? effect.name, + state: flag.stage, + duration: this.getRemainingLabel(effect) || "Manual", + summary: String(flag.summary ?? "") + }); + } + } + + if (!rows.length) return; + + const stateLabelMap = { + active: "Active", + pending: "Pending", + withdrawal: "Withdrawal", + "withdrawal-check": "Withdrawal Check" + }; + + const content = ` +
+
Active Drug Reminder
+ ${rows.map((row) => ` +
+ ${row.actor}: ${row.drug} (${stateLabelMap[row.state] ?? row.state}) - ${row.duration} + ${row.summary ? `
${row.summary}` : ""} +
+ `).join("")} +
+ `; + + await ChatMessage.create({ + user: game.user.id, + whisper: ChatMessage.getWhisperRecipients("GM").map((user) => user.id), + content + }); + } + + static async migrateLegacyDrugEffects(actor) { + const updates = []; + for (const effect of actor?.effects ?? []) { + const flag = this.getDrugEffectFlag(effect); + if (!flag) continue; + const migratedChanges = (effect.changes ?? []).map((change) => { + if (typeof change.key === "string" && change.key.startsWith("system.stats.") && change.key.endsWith(".value")) { + return { ...change, key: change.key.replace(/\.value$/, ".mod"), value: String(change.value ?? 0) }; + } + if (typeof change.value !== "string") { + return { ...change, value: String(change.value ?? "") }; + } + return change; + }); + const changed = JSON.stringify(migratedChanges) !== JSON.stringify(effect.changes ?? []); + if (changed) { + updates.push({ _id: effect.id, changes: migratedChanges }); + } + } + if (updates.length) { + await actor.updateEmbeddedDocuments("ActiveEffect", updates); + } + } + + static getActorDrugEffects(actor, drugId = "") { + const normalized = this.normalize(drugId); + return (actor?.effects ?? []).filter((effect) => { + const flag = this.getDrugEffectFlag(effect); + if (!flag?.drugId) return false; + if (!normalized) return true; + return this.normalize(flag.drugId) === normalized; + }); + } + + static async getActorOverview(actor) { + await this.resolveExpiredEffects(actor); + const alerts = []; + const rows = []; + + for (const item of actor?.items ?? []) { + if (item.type !== "drug") continue; + const def = await this.getDrugDefinitionFromItem(item); + if (!def) continue; + const effects = this.getActorDrugEffects(actor, def.id); + const active = effects.find((effect) => this.getDrugEffectFlag(effect)?.stage === "active"); + const pending = effects.find((effect) => this.getDrugEffectFlag(effect)?.stage === "pending"); + const withdrawalCheck = effects.find((effect) => this.getDrugEffectFlag(effect)?.stage === "withdrawal-check"); + const withdrawal = effects.find((effect) => this.getDrugEffectFlag(effect)?.stage === "withdrawal"); + const effect = active ?? pending ?? withdrawalCheck ?? withdrawal ?? null; + const stage = this.getDrugEffectFlag(effect)?.stage ?? "inactive"; + const statusLabelMap = { + active: "Active", + pending: "Pending", + "withdrawal-check": "Withdrawal Check", + withdrawal: "Withdrawal", + inactive: "Ready" + }; + const summary = stage === "withdrawal" + ? String(def.withdrawalSummary ?? "") + : String(def.activeSummary ?? ""); + const row = { + id: item.id, + itemId: item.id, + name: item.name, + img: item.img, + quantity: Number(item.system?.quantity ?? 0), + cost: Number(item.system?.cost ?? def.cost ?? 0), + drugId: def.id, + category: def.category, + rating: def.rating, + duration: effect ? this.getRemainingLabel(effect) : String(def.durationLabel ?? ""), + status: stage, + statusLabel: statusLabelMap[stage] ?? "Ready", + summary, + canUse: Number(item.system?.quantity ?? 0) > 0, + canClose: Boolean(effect) + }; + rows.push(row); + if (effect) { + alerts.push({ + itemId: item.id, + drugId: def.id, + name: def.name, + state: stage, + stateLabel: row.statusLabel, + duration: row.duration, + summary + }); + } + } + + alerts.sort((left, right) => { + const leftScore = left.state === "active" ? 0 : left.state === "pending" ? 1 : 2; + const rightScore = right.state === "active" ? 0 : right.state === "pending" ? 1 : 2; + if (leftScore !== rightScore) return leftScore - rightScore; + return String(left.name).localeCompare(String(right.name)); + }); + + return { alerts, rows }; + } + + static createEffectChanges(def, actor, stage = "active") { + const changes = []; + const statBonuses = stage === "withdrawal" + ? (def.withdrawal?.statBonuses ?? {}) + : (def.effects?.statBonuses ?? {}); + const statPaths = { + strength: "system.stats.strength.mod", + speed: "system.stats.speed.mod", + intellect: "system.stats.intellect.mod", + combat: "system.stats.combat.mod", + sanity: "system.stats.sanity.mod", + fear: "system.stats.fear.mod", + body: "system.stats.body.mod" + }; + + for (const [key, path] of Object.entries(statPaths)) { + const value = Number(statBonuses?.[key] ?? 0); + if (!value) continue; + changes.push({ key: path, mode: CONST.ACTIVE_EFFECT_MODES.ADD, value: String(value) }); + } + + if (stage === "active" && this.isFrother(actor) && Number(def.effects?.frotherCombatBonus ?? 0)) { + changes.push({ + key: "system.stats.combat.mod", + mode: CONST.ACTIVE_EFFECT_MODES.ADD, + value: String(Number(def.effects.frotherCombatBonus)) + }); + } + + if (stage === "withdrawal") { + const woundTier = Math.max(1, Number(actor?.system?.hits?.value ?? 0) + 1); + const healthPenalty = Number(def.withdrawal?.healthMaxPenaltyPerWoundTier ?? 0) * woundTier; + if (healthPenalty) { + changes.push({ + key: "system.health.max", + mode: CONST.ACTIVE_EFFECT_MODES.ADD, + value: String(-healthPenalty) + }); + } + const woundMaxPenalty = Number(def.withdrawal?.woundMaxPenalty ?? 0); + if (woundMaxPenalty) { + changes.push({ + key: "system.hits.max", + mode: CONST.ACTIVE_EFFECT_MODES.ADD, + value: String(-woundMaxPenalty) + }); + } + const fluxMaxPenalty = Number(def.withdrawal?.fluxMaxPenalty ?? 0); + if (fluxMaxPenalty) { + changes.push({ + key: "system.sla.flux.max", + mode: CONST.ACTIVE_EFFECT_MODES.ADD, + value: String(-fluxMaxPenalty) + }); + } + } + + return changes; + } + + static buildEffectData(def, actor, item, stage = "active", extra = {}) { + const now = Date.now(); + const isPending = stage === "pending"; + const durationSeconds = isPending + ? Math.max(0, Number(def.durationSeconds ?? 0)) + : stage === "withdrawal-check" + ? Math.max(0, Number(def.addiction?.withdrawalCheckSeconds ?? 86400)) + : stage === "withdrawal" + ? Math.max(0, Number(def.withdrawal?.durationSeconds ?? 0)) + : Math.max(0, Number(def.durationSeconds ?? 0)); + const expiresAt = durationSeconds > 0 ? now + durationSeconds * 1000 : 0; + const changes = this.createEffectChanges(def, actor, stage); + const labels = { + active: `${def.name} Active`, + pending: `${def.name} Pending`, + "withdrawal-check": `${def.name} Withdrawal Check`, + withdrawal: `${def.name} Withdrawal` + }; + const summary = stage === "withdrawal" + ? String(def.withdrawalSummary ?? "") + : stage === "withdrawal-check" + ? "Withdrawal check pending after 24 hours without a fresh dose." + : String(def.activeSummary ?? ""); + + return { + name: labels[stage] ?? def.name, + icon: item?.img || def.img || "icons/consumables/potions/potion-round-corked-red.webp", + img: item?.img || def.img || "icons/consumables/potions/potion-round-corked-red.webp", + changes, + disabled: false, + duration: durationSeconds > 0 ? { seconds: durationSeconds } : {}, + flags: { + [SYSTEM_ID]: { + slaDrug: { + drugId: def.id, + sourceItemId: item?.id ?? "", + stage, + startedAt: now, + expiresAt, + manualOnly: durationSeconds <= 0, + summary, + damageTakenMultiplier: Number(def.effects?.damageTakenMultiplier ?? 1), + combatAdvantage: Boolean(def.effects?.combatAdvantage), + rangedCombatAdvantage: Boolean(def.effects?.rangedCombatAdvantage), + ignoreWoundPenaltyCount: Number(def.effects?.ignoreWoundPenaltyCount ?? 0), + doubleEbbDuration: Boolean(def.effects?.doubleEbbDuration), + ebbPowerPenalty: Number(def.withdrawal?.ebbPowerPenalty ?? 0), + ...extra + } + } + } + }; + } + + static async adjustPostEffectCaps(actor) { + const updates = {}; + const healthMax = Math.max(0, Number(actor.system?.health?.max ?? 0)); + const healthValue = Math.max(0, Number(actor.system?.health?.value ?? 0)); + if (healthValue > healthMax) { + updates["system.health.value"] = healthMax; + } + const hitsMax = Math.max(0, Number(actor.system?.hits?.max ?? 0)); + const hitsValue = Math.max(0, Number(actor.system?.hits?.value ?? 0)); + if (hitsValue > hitsMax) { + updates["system.hits.value"] = hitsMax; + } + const fluxMax = Math.max(0, Number(actor.system?.sla?.flux?.max ?? 0)); + const fluxValue = Math.max(0, Number(actor.system?.sla?.flux?.value ?? 0)); + if (fluxValue > fluxMax) { + updates["system.sla.flux.value"] = fluxMax; + } + if (Object.keys(updates).length) { + await actor.update(updates); + } + } + + static async getOrCreateAddictionCondition(actor, def) { + const name = `Addiction: ${def.name}`; + let item = actor.items.find((entry) => entry.type === "condition" && this.normalize(entry.name) === this.normalize(name)); + if (item) return item; + const created = await actor.createEmbeddedDocuments("Item", [{ + name, + type: "condition", + img: ADDICTION_ICON, + system: { + description: `

Addiction Threshold: ${Number(def.addiction?.threshold ?? 0)} failed Body Saves.

${def.withdrawalSummary ?? ""}

`, + severity: 0, + treatment: { value: 0, html: "" } + }, + flags: { + [SYSTEM_ID]: { + slaAddiction: { + drugId: def.id, + threshold: Number(def.addiction?.threshold ?? 0) + } + } + } + }]); + return created?.[0] ?? null; + } + + static async processAddictionOnUse(actor, def) { + const threshold = Number(def.addiction?.threshold ?? 0); + if (!threshold) return { skipped: true }; + if (Boolean(def.addiction?.frotherExempt) && this.isFrother(actor)) { + return { skipped: true, exempt: true }; + } + + const rollString = Boolean(def.addiction?.saveDisadvantage) ? "1d100 [-]" : "1d100"; + const result = await actor.rollSlaSaveWithResult("body", { + rollString, + label: `${def.name}: Addiction Body Save`, + description: `${def.name} addiction check${def.addiction?.saveDisadvantage ? " at Disadvantage" : ""}.` + }); + + if (result?.success) return { success: true }; + + const condition = await this.getOrCreateAddictionCondition(actor, def); + if (!condition) return { success: false, condition: null }; + const newSeverity = Math.max(0, Number(condition.system?.severity ?? 0) + 1); + await condition.update({ "system.severity": newSeverity }); + + const addicted = newSeverity >= threshold; + ui.notifications.warn(`${actor.name}: ${def.name} addiction risk increased to ${newSeverity}/${threshold}${addicted ? " (Addicted)" : ""}.`); + return { success: false, condition, severity: newSeverity, addicted }; + } + + static async clearDrugEffects(actor, drugId, { skipFollowup = true } = {}) { + const effects = this.getActorDrugEffects(actor, drugId); + if (!effects.length) return; + await actor.deleteEmbeddedDocuments("ActiveEffect", effects.map((effect) => effect.id), skipFollowup ? { slaDrugSkipFollowup: true } : {}); + } + + static async useDrug({ actor, itemId, consume = true } = {}) { + const item = actor?.items?.get(itemId); + if (!actor || !item) { + ui.notifications.warn("No drug item was found to use."); + return { ok: false, reason: "missing-item" }; + } + const def = await this.getDrugDefinitionFromItem(item); + if (!def) { + ui.notifications.warn(`No SLA drug definition found for ${item.name}.`); + return { ok: false, reason: "missing-definition" }; + } + + await this.resolveExpiredEffects(actor); + + const quantity = Math.max(0, Number(item.system?.quantity ?? 0)); + if (consume && quantity < 1) { + ui.notifications.warn(`${actor.name} has no ${def.name} doses remaining.`); + return { ok: false, reason: "out-of-doses" }; + } + + if (!Boolean(def.special?.kickstartDelay)) { + await this.clearDrugEffects(actor, def.id, { skipFollowup: true }); + } + + if (consume) { + await item.update({ "system.quantity": quantity - 1 }); + } + + if (Number(def.effects?.stressOnUse ?? 0) > 0) { + const skipStress = Boolean(def.effects?.stressNonFrotherOnly) && this.isFrother(actor); + if (!skipStress) { + await actor.modifyActor("system.other.stress.value", Number(def.effects.stressOnUse), null, false); + } + } + + if (def.effects?.restoreFlux === "full" && this.isEbbUser(actor)) { + const fluxMax = Math.max(0, Number(actor.system?.sla?.flux?.max ?? 0)); + await actor.update({ "system.sla.flux.value": fluxMax }); + await actor.updateSlaFluxState?.(fluxMax, { save: true }); + } + + if (Boolean(def.special?.intellectPermanentAfterFirst)) { + const path = `flags.${SYSTEM_ID}.slaDrugCounters.${def.id}`; + const currentUses = Math.max(0, Number(actor.getFlag?.(SYSTEM_ID, `slaDrugCounters.${def.id}`) ?? 0)); + const nextUses = currentUses + 1; + await actor.update({ [path]: nextUses }); + if (nextUses > 1) { + await actor.modifyActor("system.stats.intellect.value", Number(def.special.intellectPermanentAfterFirst), null, false); + } + } + + const effectData = this.buildEffectData(def, actor, item, Boolean(def.special?.kickstartDelay) ? "pending" : "active"); + await actor.createEmbeddedDocuments("ActiveEffect", [effectData]); + + await this.processAddictionOnUse(actor, def); + + if (Boolean(def.special?.aliceTrip)) { + const sanityResult = await actor.rollSlaSaveWithResult("sanity", { + label: `${def.name}: Trip Sanity Save`, + description: `${def.name} tears perception open.` + }); + if (!sanityResult?.success) { + await actor.modifyActor("system.other.stress.value", null, "1d10", false); + await actor.rollTable("panicCheck", null, null, null, null, null, null); + } + } + + await this.postDrugChat(actor, { + title: `${def.name} Dosed`, + state: Boolean(def.special?.kickstartDelay) ? "pending" : "active", + duration: def.durationLabel ?? "", + summary: def.activeSummary ?? "", + drug: def + }); + + return { ok: true, drug: def.id }; + } + + static async closeDrug({ actor, itemId = "", drug = "" } = {}) { + if (!actor) return { ok: false, reason: "missing-actor" }; + const item = itemId ? actor.items.get(itemId) : null; + const def = await this.getDrugDefinition(item ? (item.flags?.[SYSTEM_ID]?.slaDrug?.id ?? item.system?.sla?.drugId ?? item.name) : drug); + if (!def) return { ok: false, reason: "missing-definition" }; + + await this.resolveExpiredEffects(actor); + const effects = this.getActorDrugEffects(actor, def.id); + if (!effects.length) return { ok: true, skipped: true }; + + const activeOrPending = effects.find((effect) => { + const stage = this.getDrugEffectFlag(effect)?.stage; + return stage === "active" || stage === "pending"; + }); + + if (activeOrPending) { + await activeOrPending.delete({ slaDrugManualClose: true }); + return { ok: true, stage: "closed-active" }; + } + + await actor.deleteEmbeddedDocuments("ActiveEffect", effects.map((effect) => effect.id), { slaDrugSkipFollowup: true }); + await this.postDrugChat(actor, { + title: `${def.name} Cleared`, + state: "cleared", + duration: "", + summary: "No active drug state remains.", + drug: def + }); + return { ok: true, stage: "cleared" }; + } + + static async handleEffectDeleted(effect, options = {}) { + const actor = effect?.parent; + const flag = this.getDrugEffectFlag(effect); + if (!actor || !flag) return; + if (options?.slaDrugSkipFollowup) { + await this.adjustPostEffectCaps(actor); + return; + } + + const def = await this.getDrugDefinition(flag.drugId); + if (!def) return; + + if (flag.stage === "pending" && Boolean(def.special?.kickstartDelay)) { + await this.applyKickStart(actor, def); + await this.postDrugChat(actor, { + title: `${def.name} Triggered`, + state: "resolved", + duration: "", + summary: "Delayed treatment resolved: health restored and wound recovery attempted.", + drug: def + }); + return; + } + + if (flag.stage === "active") { + await this.handleActiveDrugEnding(actor, def, Boolean(options?.slaDrugManualClose)); + return; + } + + if (flag.stage === "withdrawal-check") { + await this.handleWithdrawalCheck(actor, def); + return; + } + + await this.adjustPostEffectCaps(actor); + } + + static async handleActiveDrugEnding(actor, def, manualClose = false) { + const effects = def.effects ?? {}; + const expiry = def.expiry ?? {}; + + if (Boolean(expiry.sanitySaveOnExpiry)) { + const result = await actor.rollSlaSaveWithResult("sanity", { + label: `${def.name}: Expiry Sanity Save`, + description: `${def.name} burns out and the comedown hits.` + }); + if (!result?.success && expiry.stressFormulaOnFailure) { + await actor.modifyActor("system.other.stress.value", null, expiry.stressFormulaOnFailure, false); + } + } + + if (Number(expiry.stressRelief ?? 0) > 0) { + await actor.modifyActor("system.other.stress.value", -Math.abs(Number(expiry.stressRelief)), null, false); + } + + if (def.withdrawal?.mode === "immediate") { + const sourceItem = actor.items.get(this.getActorDrugEffects(actor, def.id)[0]?.flags?.[SYSTEM_ID]?.slaDrug?.sourceItemId ?? "") ?? null; + const withdrawalEffect = this.buildEffectData(def, actor, sourceItem, "withdrawal"); + await actor.createEmbeddedDocuments("ActiveEffect", [withdrawalEffect]); + await this.postDrugChat(actor, { + title: `${def.name} Withdrawal`, + state: "withdrawal", + duration: def.withdrawal?.durationSeconds ? this.formatSeconds(def.withdrawal.durationSeconds) : "Manual", + summary: def.withdrawalSummary ?? "", + drug: def + }); + await this.adjustPostEffectCaps(actor); + return; + } + + if (def.withdrawal?.mode === "addiction-check") { + const addiction = actor.items.find((entry) => entry.type === "condition" && this.normalize(entry.name) === this.normalize(`Addiction: ${def.name}`)); + const addicted = Number(addiction?.system?.severity ?? 0) >= Math.max(1, Number(def.addiction?.threshold ?? 0)); + if (addicted) { + const sourceItem = actor.items.find((entry) => this.normalize(entry.name) === this.normalize(def.name)) ?? null; + const withdrawalCheck = this.buildEffectData(def, actor, sourceItem, "withdrawal-check", { manualClose }); + await actor.createEmbeddedDocuments("ActiveEffect", [withdrawalCheck]); + await this.postDrugChat(actor, { + title: `${def.name} Cooling Off`, + state: "withdrawal-check", + duration: this.formatSeconds(Number(def.addiction?.withdrawalCheckSeconds ?? 86400)), + summary: "Addiction is active. If no fresh dose is taken before the check expires, a Body Save will determine withdrawal.", + drug: def + }); + } else { + await this.postDrugChat(actor, { + title: `${def.name} Ended`, + state: manualClose ? "closed" : "expired", + duration: "", + summary: "The active dose has ended with no addiction withdrawal timer.", + drug: def + }); + } + } + + await this.adjustPostEffectCaps(actor); + } + + static async handleWithdrawalCheck(actor, def) { + const result = await actor.rollSlaSaveWithResult("body", { + label: `${def.name}: Withdrawal Body Save`, + description: `Twenty-four hours have passed without another ${def.name} dose.` + }); + if (result?.success) { + await this.postDrugChat(actor, { + title: `${def.name} Withdrawal Resisted`, + state: "recovered", + duration: "", + summary: "The operative holds it together for now. Addiction remains tracked on the sheet.", + drug: def + }); + return; + } + + const sourceItem = actor.items.find((entry) => this.normalize(entry.name) === this.normalize(def.name)) ?? null; + const withdrawalEffect = this.buildEffectData(def, actor, sourceItem, "withdrawal"); + await actor.createEmbeddedDocuments("ActiveEffect", [withdrawalEffect]); + await this.postDrugChat(actor, { + title: `${def.name} Withdrawal Triggered`, + state: "withdrawal", + duration: def.withdrawal?.durationSeconds ? this.formatSeconds(def.withdrawal.durationSeconds) : "Manual", + summary: def.withdrawalSummary ?? "", + drug: def + }); + await this.adjustPostEffectCaps(actor); + } + + static async applyKickStart(actor, def) { + const updates = { + "system.health.value": Math.max(0, Number(actor.system?.health?.max ?? 0)) + }; + const currentWounds = Math.max(0, Number(actor.system?.hits?.value ?? 0)); + if (currentWounds > 0) { + updates["system.hits.value"] = Math.max(0, currentWounds - Math.max(1, Number(def.special?.healWounds ?? 1))); + } + await actor.update(updates); + } + + static getDamageTakenMultiplier(actor) { + const effects = this.getActorDrugEffects(actor); + let multiplier = 1; + for (const effect of effects) { + const flag = this.getDrugEffectFlag(effect); + if (flag?.stage !== "active") continue; + const next = Number(flag.damageTakenMultiplier ?? 1); + if (next > 0 && next < multiplier) { + multiplier = next; + } + } + return multiplier; + } + + static getActiveRollModifiers(actor) { + const modifiers = { + combatAdvantage: false, + rangedCombatAdvantage: false, + ignoreWoundPenaltyCount: 0, + doubleEbbDuration: false, + ebbPowerPenalty: 0 + }; + for (const effect of this.getActorDrugEffects(actor)) { + const flag = this.getDrugEffectFlag(effect); + if (flag?.stage !== "active" && flag?.stage !== "withdrawal") continue; + modifiers.combatAdvantage ||= Boolean(flag.combatAdvantage); + modifiers.rangedCombatAdvantage ||= Boolean(flag.rangedCombatAdvantage); + modifiers.doubleEbbDuration ||= Boolean(flag.doubleEbbDuration); + modifiers.ignoreWoundPenaltyCount = Math.max(modifiers.ignoreWoundPenaltyCount, Number(flag.ignoreWoundPenaltyCount ?? 0)); + modifiers.ebbPowerPenalty += Number(flag.stage === "withdrawal" ? flag.ebbPowerPenalty ?? 0 : 0); + } + return modifiers; + } + + static formatSeconds(seconds = 0) { + const total = Math.max(0, Number(seconds ?? 0)); + const hours = Math.floor(total / 3600); + const minutes = Math.floor((total % 3600) / 60); + const secs = total % 60; + if (hours > 0) return `${hours}h ${minutes}m`; + if (minutes > 0) return `${minutes}m`; + return `${secs}s`; + } + + static async postDrugChat(actor, { title = "", state = "", duration = "", summary = "", drug = null } = {}) { + const image = drug?.img || "icons/consumables/potions/potion-round-corked-red.webp"; + const content = ` +
+
+
${title}
+
+
+
State: ${state}
+ ${duration ? `
Duration: ${duration}
` : ""} + ${summary ? `
${summary}
` : ""} +
+ `; + await ChatMessage.create({ + user: game.user.id, + speaker: { actor: actor.id, token: actor.token, alias: actor.name }, + content + }); + } +} diff --git a/module/sla-species-balance.js b/module/sla-species-balance.js new file mode 100644 index 0000000..99ae4e8 --- /dev/null +++ b/module/sla-species-balance.js @@ -0,0 +1,16 @@ +export const SLA_SPECIES_BALANCE_VERSION = "2026-03-23-species-balance-1"; + +export const SLA_SPECIES_STAT_ADJUSTMENTS = { + Human: { sanity: 15, fear: 20 }, + Frother: { fear: 20, body: 5 }, + Ebon: { intellect: 10, sanity: 20 }, + "Brain Waster": { intellect: 10, sanity: 20 }, + "Wraith Raider": { sanity: 15 }, + Shaktar: { body: 10, fear: 20 }, + "Stormer 313 Malice": { fear: 25 }, + "Stormer 711 Xeno": { fear: 25 } +}; + +export function getSlaSpeciesStatAdjustments(speciesName = "") { + return SLA_SPECIES_STAT_ADJUSTMENTS[String(speciesName ?? "").trim()] ?? {}; +} diff --git a/module/sla-trauma.js b/module/sla-trauma.js new file mode 100644 index 0000000..fb472b2 --- /dev/null +++ b/module/sla-trauma.js @@ -0,0 +1,194 @@ +const SPECIES_TRAUMA_PROFILES = { + Human: { + mode: "Corporate Override", + trigger: "they take Stress, lose control of a scene, or see the plan slipping", + positive: "Allies in Close range may either clear 1 Stress or gain +5 on their next coordinated roll.", + negative: "The operative becomes rigid and command-dependent; independent social or creative action is at -10 until someone reasserts the plan.", + session: "Invoke sponsor discipline to reroll one failed Command, Bureaucracy, or Fear-related test, but afterwards a superior, sponsor, or handler is owed a concession." + }, + Frother: { + mode: "Red Mist Containment", + trigger: "they are wounded, restrained, denied a charge lane, or chemically overstimulated", + positive: "One ally can immediately surge with them, gaining +10 on the next melee, Brawl, or forced-entry action.", + negative: "The nearest ally or bystander takes 1 Stress, loses cover, or has to scramble clear as the Frother's violence spills outward.", + session: "Ignore wound penalties for one combat round and close distance immediately, then gain 1d5 Stress when the surge burns out." + }, + Ebon: { + mode: "Quiet Flux", + trigger: "they absorb psychic shock, intense grief, or impossible sensory information", + positive: "A nearby ally gains calm focus: clear 1 Stress, stabilize a Fear response, or take +10 on one careful action.", + negative: "Reality hushes around the Ebon; nearby allies feel the pressure and take -5 on their next impulsive or noisy action.", + session: "Open a moment of lucid stillness that lets one ally reroll a failed mental check, but the Ebon immediately gains 1d5 Stress." + }, + "Brain Waster": { + mode: "Predatory Backwash", + trigger: "they smell weakness, take psychic pain, or sense prey escaping the kill", + positive: "Nearby allies gain ruthless momentum: +5 on their next attack against the same target or an immediate free reposition toward the threat.", + negative: "The psychic splash is ugly. Allies in Close range take 1 Stress or hesitate before acting aggressively near the Brain Waster.", + session: "Force the scene into a kill-focus: one target becomes obvious and allies gain +10 to attack it for a round, but everyone nearby knows the Brain Waster is slipping." + }, + "Wraith Raider": { + mode: "Predator Snap", + trigger: "they are cornered, lose sight of prey, or are forced into static formation", + positive: "One ally may immediately shift position, dive for flank, or gain +10 on the next pursuit, ambush, or precision shot.", + negative: "The Wraith peels away from the group instinctively; squad cohesion frays and nearby allies lose the benefit of tight formation or overwatch.", + session: "Exploit a predatory opening to act first against one exposed threat, but the Wraith must commit to that line and cannot hold the broader objective at the same time." + }, + Shaktar: { + mode: "Honour Lock", + trigger: "their code is insulted, an ally falls dishonourably, or a duel-worthy threat emerges", + positive: "An ally gains steadiness from the Shaktar's presence: +10 on one defensive, leadership, or hold-the-line action.", + negative: "The Shaktar becomes bound to the obvious challenge and resists compromise, retreat, or deception until the honour issue is addressed.", + session: "Declare a martial vow against a target or objective; the Shaktar gains +10 while pursuing it, but cannot willingly abandon that vow without taking 1d5 Stress." + }, + "Stormer 313 Malice": { + mode: "Breach Engine", + trigger: "they hit hard resistance, suffer visible injury, or are treated as the blunt solution", + positive: "Allies nearby may immediately press the breach: gain +10 on one push, suppress, or shock-entry action this round.", + negative: "Subtlety collapses. Nearby operatives lose finesse; social, stealth, or delicate technical actions are at -10 while the Stormer dominates the scene.", + session: "Turn the response into overwhelming mass: ignore knockback, restraint, and hesitation for one round, but every nearby ally or witness reads the escalation instantly." + }, + "Stormer 711 Xeno": { + mode: "Stalker Reflex", + trigger: "they are observed too clearly, lose camouflage, or feel prey slipping through a net", + positive: "One ally can immediately reposition, hide, or line up a crossfire with +10 on the next attack from concealment.", + negative: "The Xeno's inhuman movement shakes the team; allies in sight take -5 on their next social or comms-dependent action.", + session: "Explode into hunting movement and gain a free stealth or flank reposition, but all nearby friendlies know exactly how unnatural that burst looked." + }, + "Advanced Carrien": { + mode: "Scavenger Adaptation", + trigger: "they are cornered, cut off from resources, or forced into open contempt from others", + positive: "One ally may improvise from the Carrien's instinct: reroll a Streetwise, survival, theft, or dirty-fix style action.", + negative: "Trust drops fast. Nearby allies become suspicious, losing confidence in promises, command, or clean procedure until results appear.", + session: "Turn desperation into advantage by producing an ugly but effective solution; it works once, but leaves a social stain or material mess behind." + } +}; + +const PACKAGE_TRAUMA_PROFILES = { + "Death Squad": { + doctrine: "hard elimination doctrine and breach-line pressure", + positive: "The response naturally supports direct violence, suppression, and target deletion.", + negative: "Non-combat options shrink fast; restraint, mercy, and evidence care become secondary.", + session: "Mark one hostile or kill-zone. Allies who commit to it gain +10 for one round, but any collateral or intimidation fallout is amplified." + }, + "Strike Squad": { + doctrine: "tight team movement, entry discipline, and controlled force", + positive: "The response strengthens covering arcs, shield work, and clean squad timing.", + negative: "Breaking formation feels like failure; the operative resists improvisation that pulls them off the team rhythm.", + session: "Call a formation snap. Up to two allies may immediately reposition or gain +5 to their next disciplined action, but everyone becomes more predictable for a round." + }, + "Kick Murder": { + doctrine: "close violence, intimidation, and spectacle-driven aggression", + positive: "The response rewards momentum, fear projection, and brutal follow-through in close quarters.", + negative: "Collateral intimidation rises immediately; delicate witnesses, civilians, or weak-willed allies are rattled.", + session: "Turn panic into a public display of violence. Gain +10 on one melee or intimidation burst, but someone nearby remembers how ugly it looked." + }, + Scouting: { + doctrine: "pursuit, overwatch, live target acquisition, and flank discipline", + positive: "The response sharpens lines of sight, pursuit instincts, and exploit-the-gap movement.", + negative: "The operative starts thinking like a lone hunter and can drift away from the wider squad objective.", + session: "Name an escape route, rooftop, blind corner, or kill lane; one ally can exploit it immediately, but the operative becomes fixated on that line until it resolves." + }, + Investigation: { + doctrine: "evidence control, witness handling, and structured pressure", + positive: "The response helps lock onto motive, contradiction, or one critical clue others are missing.", + negative: "The operative becomes obsessed with one read, suspect, or theory and can miss broader battlefield cues.", + session: "Call out the key pattern in the chaos and grant +10 to one search, read, or interrogation move, but if it is wrong the whole scene loses tempo." + }, + Media: { + doctrine: "camera awareness, narrative control, and audience-facing posture", + positive: "The response can seize attention, redirect blame, and create a dramatic moment that helps the team.", + negative: "Everything starts to feel performative; truth, caution, and privacy suffer when the spotlight instinct takes over.", + session: "Take control of the scene's narrative for one beat: gain +10 to one social pivot or broadcast action, but someone important sees the mask slip." + }, + Medical: { + doctrine: "casualty triage, harm reduction, and keeping people functional", + positive: "The response immediately prioritizes stabilization, pain control, and keeping others in the fight.", + negative: "The operative can overcommit to one casualty or moral triage call and neglect the tactical picture.", + session: "Declare emergency triage authority: one ally may ignore a penalty or clear 1d5 Stress, but someone else is necessarily deprioritized." + }, + Mechanic: { + doctrine: "repair under pressure, jury-rig resilience, and practical continuity", + positive: "The response spots what can still be made to work and buys the team one more functioning moment.", + negative: "The operative starts treating people like systems; empathy and soft judgment degrade while the fix obsession takes hold.", + session: "Force one broken plan, device, or route to function one more time, but it becomes unstable, noisy, or impossible to hide." + }, + "Tech Ops": { + doctrine: "systems dominance, tactical feed control, and hostile tech exploitation", + positive: "The response sharpens data interpretation, sensor control, and battlefield command through information.", + negative: "The operative overrelies on systems, feeds, or assumptions and becomes brittle if the data picture changes.", + session: "Call a systems spike: one allied action may count as perfectly timed intel support, but afterwards the local network, drone, or feed is compromised." + }, + Pilot: { + doctrine: "vehicle survival, route discipline, and momentum through movement", + positive: "The response favours speed, extraction thinking, and preserving an exit line for the team.", + negative: "The operative becomes route-fixated and can prioritise escape or movement over mission nuance.", + session: "Name the extraction vector. One ally may immediately move, mount up, or gain +10 on a vehicle-related action, but abandoning that route becomes psychologically harder." + }, + "Ebb Operative": { + doctrine: "psychic composure, hidden pressure, and the disciplined use of the Ebb", + positive: "The response can calm or focus another operative through eerie certainty, attention, or psychic poise.", + negative: "Everyone nearby feels that something is not normal; fear, suspicion, or social strain rises even when the effect helps.", + session: "Declare a single controlled surge of unnatural clarity: reroll one mental or Ebb-linked failure, but mark the scene as visibly touched by the Ebb." + } +}; + +function fallbackSpecies(speciesName = "") { + return SPECIES_TRAUMA_PROFILES[speciesName] ?? SPECIES_TRAUMA_PROFILES.Human; +} + +function fallbackPackage(packageName = "") { + return PACKAGE_TRAUMA_PROFILES[packageName] ?? PACKAGE_TRAUMA_PROFILES["Strike Squad"]; +} + +export function buildSlaTraumaProfile(speciesName = "", packageName = "") { + const species = fallbackSpecies(speciesName); + const trainingPackage = fallbackPackage(packageName); + const resolvedSpecies = String(speciesName ?? "").trim() || "Human"; + const resolvedPackage = String(packageName ?? "").trim() || "Strike Squad"; + + return { + key: `${resolvedSpecies}::${resolvedPackage}`, + title: `${resolvedSpecies} / ${resolvedPackage}: ${species.mode}`, + trigger: `When ${species.trigger} during ${trainingPackage.doctrine}.`, + positive: `${species.positive} ${trainingPackage.positive}`, + negative: `${species.negative} ${trainingPackage.negative}`, + session: `${species.session} ${trainingPackage.session}`, + summary: `${species.mode} shaped by ${resolvedPackage} doctrine.` + }; +} + +export function buildSlaTraumaResponseText(speciesName = "", packageName = "") { + const profile = buildSlaTraumaProfile(speciesName, packageName); + const species = fallbackSpecies(speciesName); + const trainingPackage = fallbackPackage(packageName); + const firstSentence = (value = "") => { + const text = String(value ?? "").trim(); + if (!text) return ""; + const match = text.match(/^.*?[.!?](?:\s|$)/); + return (match?.[0] ?? text).trim(); + }; + const compactClause = (value = "") => firstSentence(value) + .replace(/, but .*$/i, ".") + .replace(/; .*$/i, ".") + .replace(/\s+/g, " ") + .trim(); + return [ + `${profile.title}`, + `+ ${compactClause(species.positive)} ${compactClause(trainingPackage.positive)}`.trim(), + `- ${compactClause(species.negative)} ${compactClause(trainingPackage.negative)}`.trim(), + `1/Session: ${compactClause(species.session)} ${compactClause(trainingPackage.session)}`.trim() + ].join("\n"); +} + +export function buildAllSlaTraumaProfiles(speciesNames = [], packageNames = []) { + const resolvedSpecies = speciesNames.length ? speciesNames : Object.keys(SPECIES_TRAUMA_PROFILES); + const resolvedPackages = packageNames.length ? packageNames : Object.keys(PACKAGE_TRAUMA_PROFILES); + const out = []; + for (const speciesName of resolvedSpecies) { + for (const packageName of resolvedPackages) { + out.push(buildSlaTraumaProfile(speciesName, packageName)); + } + } + return out; +} diff --git a/module/traits/sla-traits.js b/module/traits/sla-traits.js new file mode 100644 index 0000000..e2cea00 --- /dev/null +++ b/module/traits/sla-traits.js @@ -0,0 +1,162 @@ +const SLA_TRAIT_DEFINITIONS = { + "addiction-compulsion": { label: "Addiction / Compulsion", type: "disadvantage", maxRank: 3, summary: "Unmet condition applies -10% per rank to rolls.", aliases: ["addiction/compulsion", "addiction compulsion", "compulsion", "addiction"] }, + "allergy": { label: "Allergy", type: "disadvantage", maxRank: 3, summary: "Exposure applies CON and physical penalties; severe rank tracks hazard pressure.", aliases: ["allergy"] }, + "anger": { label: "Anger", type: "disadvantage", maxRank: 1, summary: "Attacked state enforces behavioural pressure and tactical focus penalty.", aliases: ["anger"] }, + "anxiety": { label: "Anxiety", type: "disadvantage", maxRank: 3, summary: "COOL and fear SAN penalties (-10% per rank).", aliases: ["anxiety"] }, + "arrogant": { label: "Arrogant", type: "disadvantage", maxRank: 1, summary: "Social penalty vs equal or lower SCL contexts.", aliases: ["arrogant"] }, + "chicken": { label: "Chicken", type: "disadvantage", maxRank: 1, summary: "COOL cap reduction and first-combat hesitation pressure.", aliases: ["chicken"] }, + "debt": { label: "Debt", type: "disadvantage", maxRank: 3, summary: "Economic pressure tracked; rank 3 adds Bureaucracy audit strain.", aliases: ["debt"] }, + "depression": { label: "Depression", type: "disadvantage", maxRank: 3, summary: "Communication penalty (-10% per rank) with extra SAN-linked pressure.", aliases: ["depression"] }, + "drug-addict": { label: "Drug Addict", type: "disadvantage", maxRank: 3, summary: "Withdrawal penalties to physical, COOL, and SAN rolls.", aliases: ["drug addict", "drug-addict"] }, + "enemy": { label: "Enemy", type: "disadvantage", maxRank: 4, summary: "Narrative antagonist trigger; no flat roll modifier by default.", aliases: ["enemy"] }, + "illness": { label: "Illness", type: "disadvantage", maxRank: 3, summary: "Scoped penalties when active; severe ranks retain long-term pressure.", aliases: ["illness"] }, + "pacifist": { label: "Pacifist", type: "disadvantage", maxRank: 1, summary: "Combat attacks require nerve; initiative pressure favours going last.", aliases: ["pacifist"] }, + "phobia": { label: "Phobia", type: "disadvantage", maxRank: 3, summary: "Exposure applies COOL penalties; severe rank flags immediate SAN pressure.", aliases: ["phobia"] }, + "poor-hearing": { label: "Poor Hearing", type: "disadvantage", maxRank: 2, summary: "Listen penalty (-10% per rank).", aliases: ["poor hearing", "poor-hearing"] }, + "poor-vision": { label: "Poor Vision", type: "disadvantage", maxRank: 2, summary: "Spot and ranged-vision penalties in scoped cases.", aliases: ["poor vision", "poor-vision"] }, + "psychosis": { label: "Psychosis", type: "disadvantage", maxRank: 3, summary: "Active scoped instability penalties with rank scaling.", aliases: ["psychosis"] }, + "unattractive": { label: "Unattractive", type: "disadvantage", maxRank: 2, summary: "Appearance-social penalty (-10% per rank).", aliases: ["unattractive"] }, + "ambidextrous": { label: "Ambidextrous", type: "advantage", maxRank: 1, summary: "Off-hand combat penalty suppression when relevant.", aliases: ["ambidextrous"] }, + "attractive": { label: "Attractive", type: "advantage", maxRank: 2, summary: "Appearance-social bonus (+10% per rank).", aliases: ["attractive"] }, + "contact": { label: "Contact", type: "advantage", maxRank: 4, summary: "Once-per-session leverage or aid when invoked.", aliases: ["contact"] }, + "exceedingly-cool": { label: "Exceedingly Cool", type: "advantage", maxRank: 1, summary: "COOL cap boost and once-per-session automatic nerve hook.", aliases: ["exceedingly cool", "exceedingly-cool"] }, + "good-hearing": { label: "Good Hearing", type: "advantage", maxRank: 2, summary: "Listen bonus (+10% per rank).", aliases: ["good hearing", "good-hearing"] }, + "good-vision": { label: "Good Vision", type: "advantage", maxRank: 2, summary: "Spot Hidden bonus (+10% per rank).", aliases: ["good vision", "good-vision"] }, + "good-housing": { label: "Good Housing", type: "advantage", maxRank: 2, summary: "Downtime recovery bonus and better living conditions.", aliases: ["good housing", "good-housing"] }, + "natural-aptitude-skill": { label: "Natural Aptitude: Skill", type: "advantage", maxRank: 3, summary: "Once-per-session failed-skill reroll support.", aliases: ["natural aptitude: skill", "natural aptitude skill", "natural-aptitude-skill"] }, + "natural-aptitude-stat": { label: "Natural Aptitude: Stat", type: "advantage", maxRank: 1, summary: "Selected characteristic gets a max+1 equivalent edge.", aliases: ["natural aptitude: stat", "natural aptitude stat", "natural-aptitude-stat"] }, + "savings": { label: "Savings", type: "advantage", maxRank: 3, summary: "Economic reserve trait tracked narratively.", aliases: ["savings"] }, + "poor-housing": { label: "Poor Housing", type: "disadvantage", maxRank: 2, summary: "Downtime recovery penalty and poorer living conditions.", aliases: ["poor housing", "poor-housing"] }, + "sterile": { label: "Sterile", type: "disadvantage", maxRank: 1, summary: "Narrative-only biological consequence.", aliases: ["sterile"] } +}; + +const MUTUALLY_EXCLUSIVE = [ + ["chicken", "exceedingly-cool"] +]; + +function normalizeTraitName(value = "") { + return String(value ?? "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, ""); +} + +function buildAliasMap() { + const map = new Map(); + for (const [key, def] of Object.entries(SLA_TRAIT_DEFINITIONS)) { + map.set(normalizeTraitName(key), key); + map.set(normalizeTraitName(def.label ?? key), key); + for (const alias of def.aliases ?? []) { + map.set(normalizeTraitName(alias), key); + } + } + return map; +} + +const TRAIT_ALIAS_MAP = buildAliasMap(); + +export function getSlaTraitDefinition(name = "") { + const key = TRAIT_ALIAS_MAP.get(normalizeTraitName(name)) ?? normalizeTraitName(name); + return { key, definition: SLA_TRAIT_DEFINITIONS[key] ?? null }; +} + +export function getSlaTraitOptionsByType(type = "") { + const normalized = String(type ?? "").trim().toLowerCase(); + return Object.entries(SLA_TRAIT_DEFINITIONS) + .filter(([, definition]) => String(definition?.type ?? "").trim().toLowerCase() === normalized) + .map(([key, definition]) => ({ + key, + label: String(definition?.label ?? key), + maxRank: Math.max(1, Number(definition?.maxRank ?? 1) || 1), + summary: String(definition?.summary ?? "") + })) + .sort((left, right) => left.label.localeCompare(right.label)); +} + +export function buildSlaTraitRows(items = []) { + return (items ?? []).map((item) => { + const { key, definition } = getSlaTraitDefinition(item?.name ?? ""); + const rank = Math.max(1, Number(item?.system?.base ?? item?.system?.rank ?? 1) || 1); + const maxRank = Math.max(1, Number(definition?.maxRank ?? rank) || rank); + return { + ...item, + slaTrait: { + key, + rank, + maxRank, + type: String(definition?.type ?? item?.system?.sla?.traitType ?? "unknown"), + status: definition ? "Mapped" : "Unmapped", + effectSummary: String(definition?.summary ?? item?.system?.description ?? "No automation summary is available for this trait yet.") + } + }; + }).sort((a, b) => String(a?.name ?? "").localeCompare(String(b?.name ?? ""))); +} + +export function validateSlaTraitRows(traitRows = []) { + const report = { + ok: true, + errors: [], + warnings: [], + duplicates: [], + invalidRanks: [], + conflicts: [], + rankBalance: { + advantageRanks: 0, + disadvantageRanks: 0, + neutralRanks: 0, + net: 0, + balanced: true + }, + coverage: { + mapped: 0, + unmapped: 0 + } + }; + + const byKey = new Map(); + + for (const row of traitRows) { + const key = String(row?.slaTrait?.key ?? "").trim(); + const rank = Math.max(1, Number(row?.slaTrait?.rank ?? 1) || 1); + const maxRank = Math.max(1, Number(row?.slaTrait?.maxRank ?? 1) || 1); + const type = String(row?.slaTrait?.type ?? "unknown").trim().toLowerCase(); + + if (key) byKey.set(key, (byKey.get(key) ?? 0) + 1); + if (rank > maxRank) { + report.invalidRanks.push(`${row?.name ?? key} (${rank}/${maxRank})`); + } + + if (type === "advantage") report.rankBalance.advantageRanks += rank; + else if (type === "disadvantage") report.rankBalance.disadvantageRanks += rank; + else report.rankBalance.neutralRanks += rank; + + if (row?.slaTrait?.status === "Mapped") report.coverage.mapped += 1; + else report.coverage.unmapped += 1; + } + + for (const [key, count] of byKey.entries()) { + if (count > 1) report.duplicates.push(`${key} x${count}`); + } + + for (const [left, right] of MUTUALLY_EXCLUSIVE) { + if (byKey.has(left) && byKey.has(right)) { + report.conflicts.push(`${left} vs ${right}`); + } + } + + report.rankBalance.net = report.rankBalance.advantageRanks - report.rankBalance.disadvantageRanks; + report.rankBalance.balanced = report.rankBalance.net === 0; + + if (report.invalidRanks.length) report.errors.push(`Invalid ranks: ${report.invalidRanks.join(", ")}`); + if (report.conflicts.length) report.errors.push(`Mutually exclusive traits detected: ${report.conflicts.join(", ")}`); + if (report.duplicates.length) report.warnings.push(`Duplicate trait entries detected: ${report.duplicates.join(", ")}`); + if (!report.rankBalance.balanced) { + report.errors.push(`Trait rank balance mismatch: advantages ${report.rankBalance.advantageRanks} vs disadvantages ${report.rankBalance.disadvantageRanks} (net ${report.rankBalance.net >= 0 ? "+" : ""}${report.rankBalance.net}).`); + } + if (report.coverage.unmapped > 0) { + report.warnings.push(`${report.coverage.unmapped} trait entries are not mapped to the restored SLA trait catalogue yet.`); + } + + report.ok = report.errors.length === 0; + return report; +} diff --git a/module/windows/actor-generator.js b/module/windows/actor-generator.js new file mode 100644 index 0000000..8b179e0 --- /dev/null +++ b/module/windows/actor-generator.js @@ -0,0 +1,773 @@ +export class DLActorGenerator extends FormApplication { + static get defaultOptions() { + const options = super.defaultOptions; + options.id = 'sheet-modifiers'; + options.classes = ["mosh", "sheet", "actor", "character"]; + options.template = 'systems/sla-mothership/templates/dialogs/actor-generator-dialog.html'; + options.width = 800; + options.height = "auto"; + options.dragDrop = [{ dragSelector: null, dropSelector: ".dropitem" }]; + return options; + } + + /* -------------------------------------------- */ + /** + * Add the Entity name into the window title + * @type {String} + */ + get title() { + return `${this.object.name}: ${game.i18n.localize("Mosh.CharacterGenerator.name")}`; + } + /* -------------------------------------------- */ + + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + async getData() { + //if (this.object.system.class.uuid != null){ + // this.updateClass(this.object.system.class.uuid); + //} + let data = this.object; + + data.system.class = []; + data.system.class.value = ""; + data.system.class.skills = []; + data.system.class.skills.uuid = []; + return data; + } + /* -------------------------------------------- */ + + async rollDices(dices, html, id, chatmsg = "") { + + if (html.find(`img[id="${id}"]`).prop('hidden') == false) { + let roll = await new Roll(dices).roll(); + if (chatmsg != "") { + await roll.toMessage({ flavor: chatmsg }); + } + //console.log(id + "->" + roll.total) + html.find(`img[id="${id}"]`).prop('hidden', true); + html.find(`input[id="${id}"]`).prop('hidden', false); + html.find(`input[id="${id}"]`).prop('value', roll.total); + } + } + + + /* todo: remove pre-defined values and set the values as configuration /maybe part of class-item¿? */ + async rollStrength(html) { + this.rollDices("2d10+25", html, `system.stats.strength.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Strength") + })) + } + async rollSpeed(html) { + this.rollDices("2d10+25", html, `system.stats.speed.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Speed") + })) + } + async rollIntellect(html) { + this.rollDices("2d10+25", html, `system.stats.intellect.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Intellect") + })) + } + async rollCombat(html) { + this.rollDices("2d10+25", html, `system.stats.combat.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Combat") + })) + } + async rollHealth(html) { + this.rollDices("1d10+10", html, `system.health.max`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Health") + })) + } + async rollSanity(html) { + this.rollDices("2d10+10", html, `system.stats.sanity.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Sanity") + })) + } + async rollFear(html) { + this.rollDices("2d10+10", html, `system.stats.fear.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Fear") + })) + } + async rollBody(html) { + this.rollDices("2d10+10", html, `system.stats.body.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Body") + })) + } + async rollCredits(html) { + this.rollDices("2d10*10", html, `system.credits.value`, game.i18n.format("Mosh.RollingForGeneric",{ + name:game.i18n.localize("Mosh.Credits") + })) + } + + async rollTable(html, id, tableId, type = "input") { + + if (html.find(`img[id="` + id + `.value"]`).prop('hidden') == false && html.find(`img[id="system.class.value"]`).prop('value') != "") { + + let table = await fromUuid(tableId); + let tableResult = await table.draw({ displayChat: true }); + + let tableRoll = tableResult.results[0].range[0]; + + let resultText = ""; + let resultUuid = []; + for (var i = 0; i < tableResult.results.length; i++) { + if (tableResult.results[i].type == "pack" || tableResult.results[i].type == "document") { + if (type == "ul") { + this._element.find(`ul[id="${id}.text"]`).append(`
  • ${tableResult.results[i].name}
  • `); + } else { + resultText += tableResult.results[i].name + "; "; + } + resultUuid.push(tableResult.results[i].documentUuid); + } else if (tableResult.results[i].type == "text") { + let tableTextmatch = tableResult.results[i].description.match(/(.*)(@UUID.*)/i); + if (type == "ul") { + this._element.find(`ul[id="${id}.text"]`).append(`
  • ${await foundry.applications.ux.TextEditor.implementation.enrichHTML(tableTextmatch[2].replace(/(\)+/i, ""), { async: true })}
  • `); + } + else { + resultText += tableTextmatch[1].replace(/(\)+/i, ""); + } + /**we need to keep only the id of the item, not the complete uuid string (for now) */ + resultUuid.push(tableTextmatch[2].replace(/(])+(.*)/i, "").replace(/(.*)(\.)/i, "")); + } + } + + html.find(`img[id="` + id + `.value"]`).prop('hidden', true); + html.find(`input[id="` + id + `.value"]`).prop('hidden', false); + html.find(`input[id="` + id + `.value"]`).prop('value', tableRoll); + html.find(`input[id="` + id + `.text"]`).prop('hidden', false); + html.find(`input[id="` + id + `.text"]`).prop('value', resultText); + html.find(`input[id="` + id + `.uuid"]`).prop('value', resultUuid); + + } + + } + + + async rollPatch(html) { + if (!this.patchTable) { + ui.notifications.error(game.i18n.localize("Mosh.CharacterGenerator.Error.NoClass")); + return; + } + await this.rollTable(html, "system.class.patch", this.patchTable); + + } + async rollTrinket(html) { + if (!this.trinketTable) { + ui.notifications.error(game.i18n.localize("Mosh.CharacterGenerator.Error.NoClass")); + return; + } + await this.rollTable(html, "system.class.trinket", this.trinketTable); + + } + async rollLoadout(html) { + if (!this.loadoutTable) { + ui.notifications.error(game.i18n.localize("Mosh.CharacterGenerator.Error.NoClass")); + return; + } + await this.rollTable(html, "system.class.loadout", this.loadoutTable, "ul"); + + } + + /** + * Trigger all the rolls + * @param {*} html + */ + async rollEverything(html) { + await this.rollStrength(html); + await this.rollSpeed(html); + await this.rollIntellect(html); + await this.rollCombat(html); + await this.rollHealth(html); + await this.rollFear(html); + await this.rollSanity(html); + await this.rollBody(html); + await this.rollCredits(html); + await this.rollPatch(html); + await this.rollTrinket(html); + await this.rollLoadout(html); + } + + /** + * popup to selecct from a list of fixed skills + * @param {*} html + * @param {*} skillPopupOptions + * @returns + */ + async fixedSkillOptionPopup(html, skillPopupOptions) { + return new Promise((resolve) => { + if(skillPopupOptions.length == 0){ + resolve(null); + return; + } + let buttons_options = []; + for (let j = 0; j < skillPopupOptions.length; j++) { + buttons_options.push({ + icon: 'fas fa-check', + action: skillPopupOptions[j].name, + label: skillPopupOptions[j].name, + callback: () => resolve(skillPopupOptions[j].uuid), + }); + } + let d = new foundry.applications.api.DialogV2({ + window: {title: game.i18n.localize("Mosh.CharacterGenerator.StatOptionPopupTitle")}, + classes: ["macro-popup-dialog"], + content: `

    ${game.i18n.localize("Mosh.CharacterGenerator.StatOptionPopupText")}

    `, + buttons: buttons_options, + default: "1", + //render: html => console.log("Register interactivity in the rendered dialog"), + //close: html => console.log("This always is logged no matter which option is chosen") + }); + d.render({force: true}); + }); + } + + /** + * Apply the skills to the form, + * @param {*} html + * @param {[uuid]} skillsUuid List of skill uuid, + * @returns + */ + async updateSkillHtmlUl(html, skillsUuid) { + let new_skills = await html.find(`input[id="system.class.skills.uuid"]`).prop("value").split(",").filter(Boolean); + for (let i = 0; i < skillsUuid.length; i++) { + let skill = null; + //incase we have an array of arrays the second array is considered options + //this is legacy, whe should never have this case anymore + if(Array.isArray(skillsUuid[i])){ + //we have skill options, display popup to choose + let options = []; + for (let j = 0; j < skillsUuid[i].length; j++) { + let skill = await fromUuid(skillsUuid[i][j]); + options.push({"name":skill.name,"uuid":skill.uuid}); + } + let skill_uuid = await this.fixedSkillOptionPopup(html,options); + skill = await fromUuid(skill_uuid); + + }else{ + //fixed skill, just add it to the list + skill = await fromUuid(skillsUuid[i]); + } + new_skills.push(skill.uuid); + /**we need to keep only the Uuid of the item, not the complete string (for now) */ + let li_html = `
  • ${await foundry.applications.ux.TextEditor.implementation.enrichHTML(skill.name, { async: true })}
  • `; + html.find(`ul[id="system.class.skils.text"]`).append(li_html); + + } + html.find(`input[id="system.class.skills.uuid"]`).prop("value", new_skills.join(",")); + return new_skills; + } + + /** + * Process the skill options and display all the necesary popups + * @param {*} skillPopupOptions + */ + async popUpSkillOptions(skillPopupOptions) { + + for (let i = 0; i < skillPopupOptions.master_full_set; i++) { + await this.showSkillDialog('systems/sla-mothership/templates/dialogs/actor-generator/actor-generator-skill-option-full-master-dialog.html'); + + } + for (let i = 0; i < skillPopupOptions.expert_full_set; i++) { + await this.showSkillDialog('systems/sla-mothership/templates/dialogs/actor-generator/actor-generator-skill-option-full-expert-dialog.html'); + + } + for (let i = 0; i < skillPopupOptions.trained; i++) { + await this.showSkillDialog('systems/sla-mothership/templates/dialogs/actor-generator/actor-generator-skill-option-single-dialog.html', "Trained"); + + } + for (let i = 0; i < skillPopupOptions.expert; i++) { + await this.showSkillDialog('systems/sla-mothership/templates/dialogs/actor-generator/actor-generator-skill-option-single-dialog.html', "Expert"); + + } + for (let i = 0; i < skillPopupOptions.master; i++) { + await this.showSkillDialog('systems/sla-mothership/templates/dialogs/actor-generator/actor-generator-skill-option-single-dialog.html', "Master"); + + } + //console.log(existingSkills); + //return skillsUuid; + } + + /** + * Dialog with dropdown to select the skills, it grey-out already owned skills and filters the dropdown based on the skilltree of the previously selected skills, + * the fill older is from master to trained. + * @param {*} template + * @param {*} exclusive + * @returns + */ + async showSkillDialog(template, exclusive = false) { + + let skillsUuid = this.skillsUuid; + + let all_skills = await this.getAllSkills(); + all_skills.forEach((element, index) => { + all_skills[index].disabled = (skillsUuid.includes(element.uuid) ? "disabled" : ""); + }); + + + let skillPopupData = { + title: game.i18n.localize("Mosh.CharacterGenerator.SkillOption.PopupTitle"), + existingSkills: skillsUuid, + skills: { + trained: all_skills.filter(i => i.system.rank == "Trained"), + expert: all_skills.filter(i => i.system.rank == "Expert"), + master: all_skills.filter(i => i.system.rank == "Master"), + } + }; + if (exclusive) { + skillPopupData.description = game.i18n.localize("Mosh.CharacterGenerator.SkillOption.Popup" + exclusive + "Description"); + switch (exclusive) { + case "Master": + skillPopupData.skills = all_skills.filter(i => i.system.rank == "Master" && i.system.prerequisite_ids.filter(item => skillsUuid.includes(item)).length > 0); + break; + case "Expert": + skillPopupData.skills = all_skills.filter(i => i.system.rank == "Expert" && i.system.prerequisite_ids.filter(item => skillsUuid.includes(item)).length > 0); + break; + case "Trained": + skillPopupData.skills = all_skills.filter(i => i.system.rank == "Trained"); + break; + } + } + + let popUpContent = await foundry.applications.handlebars.renderTemplate(template, skillPopupData); + + return new Promise((resolve) => { + let d = new foundry.applications.api.DialogV2({ + window: {title: game.i18n.localize("Mosh.CharacterGenerator.SkillOption.PopupTitle")}, + classes: ["macro-popup-dialog"], + content: popUpContent, + buttons: [ + { + icon: 'fas fa-check', + action: `action_save`, + label: "Save", + callback: (event, button, dialog) => { + let form = button.form; + let formData = new FormData(form); + let new_skills = []; + formData.forEach((value, key) => { + if (value != "") { + new_skills.push(value); + this.skillsUuid.push(value); + } + }); + + this.updateSkillHtmlUl(this._element, new_skills); + resolve(); + } + } + ], + default: "1", + }); + d.render({force: true}); + }); + } + + /** + * Popup to ask the user to select what skill option to use, + * @param {*} list_option_skills_or + * @returns + */ + async showOptionsDialog(list_option_skills_or) { + let popupData = {options:list_option_skills_or}; + + let popUpContent = await foundry.applications.handlebars.renderTemplate("systems/sla-mothership/templates/dialogs/actor-generator/actor-generator-skill-option-choice-dialog.html", popupData); + + return new Promise((resolve) => { + if(list_option_skills_or.length == 0){ + resolve(null); + return; + } + let buttonsData = []; + for (let i=0;i { + resolve(list_option_skills_or[i]); + } + }); + } + let d = new foundry.applications.api.DialogV2({ + window: {title: game.i18n.localize("Mosh.CharacterGenerator.SkillOption.PopupTitle")}, + classes: ["macro-popup-dialog"], + content: popUpContent, + window:{width: 500}, + buttons: buttonsData, + }); + d.render({force: true}); + }); + } + + /** + * Process all the skills for the selected class + * @param {*} html + */ + async applyClassSkills(html) { + let class_uuid = html.find(`input[id="system.class.uuid"]`).prop("value"); + if (class_uuid == "") { + ui.notifications.error(game.i18n.localize("Mosh.CharacterGenerator.SkillOption.Classerror")); + return; + } + let classObject = await fromUuid(class_uuid); + //empty previously existing skills + await html.find(`ul[id="system.class.skils.text"]`).empty(); + await html.find(`input[id="system.class.skills.uuid"]`).prop("value", ""); + + //apply fixed skils + this.skillsUuid = classObject.system.base_adjustment.skills_granted.slice(); + this.skillsUuid = await this.updateSkillHtmlUl(html, this.skillsUuid); + + //process optional skills + let option_skills_and = classObject.system.selected_adjustment.choose_skill_and; + await this.popUpSkillOptions(option_skills_and); + + let list_option_skills_or = classObject.system.selected_adjustment.choose_skill_or; + for (let i = 0; i 1){ + selected_option = await this.showOptionsDialog(options_skill_or); + } + //process fixed skills first, so we dont double select them + if(selected_option.from_list.length>0){ + this.skillsUuid = await this.updateSkillHtmlUl(html, selected_option.from_list); + } + + await this.popUpSkillOptions(selected_option); + + } + } + + /** + * Ask the user for the stat options, and apply the bonuses to the form. + * @param {Array} list_option_stats_and_saves + * @returns + */ + async statOptions(list_option_stats_and_saves){ + return new Promise((resolve) => { + if(list_option_stats_and_saves.length == 0){ + resolve(); + return; + } + + for(let i =0;i {this._element.find(`input[name="system.stats.${option_stats_and_saves.stats[j]}.bonus"]`).prop("value", (parseInt(option_stats_and_saves.modification) + parseInt(prev_bonus))); + resolve(); + } + }); + } + let d = new foundry.applications.api.DialogV2({ + window: {title: game.i18n.localize("Mosh.CharacterGenerator.StatOptionPopupTitle")}, + classes: ["macro-popup-dialog"], + content: `

    ${game.i18n.localize("Mosh.CharacterGenerator.StatOptionPopupText")} (${option_stats_and_saves.modification})

    `, + buttons: buttons_options, + default: "1", + //render: html => console.log("Register interactivity in the rendered dialog"), + //close: html => console.log("This always is logged no matter which option is chosen") + }); + d.render({force: true}); + } + } + }); + } + + /** + * Apply the changed or dropped class into the generator, stats, skills and table configuration. + * @param {uuid} classUuid + * @param {Boolean} randomCharacter + * @returns + */ + async updateClass(classUuid, randomCharacter = false) { + + const droppedObject = await fromUuid(classUuid); + if (droppedObject.type != "class") { + return; + } + this._element.find(`input[id="system.class.value"]`).prop("value", droppedObject.name); + + const prev_uuid = this._element.find(`input[id="system.class.uuid"]`).prop("value"); + if (prev_uuid != null) { + //we already had a class, so we remove previously applied bonuses and skill + + //remove previous bonuses + this._element.find(`input[name$="bonus"]`).prop("value", null) + + //posible-todo: un-do the rolls of patch, trinket and loadout? + } + //update form + this._element.find(`input[id="system.class.uuid"]`).prop("value", classUuid); + this._element.find(`input[id="system.class.traumaresponse"]`).prop("value", droppedObject.system.trauma_response); + + //get tables + this.trinketTable = droppedObject.system.roll_tables.trinket; + this.patchTable = droppedObject.system.roll_tables.patch; + this.loadoutTable = droppedObject.system.roll_tables.loadout; + + //Apply bonuses first, so if the popup are closed or crashed the bonuses are already applyed. + let fix_stats_and_saves = droppedObject.system.base_adjustment; + Object.entries(fix_stats_and_saves).forEach(([key, value]) => { + if (key != "skills_granted") { + //this sets all the bonuses of base_adjustment including max_wounds + this._element.find(`input[name="system.stats.${key}.bonus"]`).prop("value", value); + } + }); + /** + * Stats + */ + //stats options + await this.statOptions(droppedObject.system.selected_adjustment.choose_stat) + + /** + * Skills + * */ + await this.applyClassSkills(this._element); + + + return; + } + + async _onDrop(event) { + await super._onDrop(event); + const droppedUuid = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); + if (droppedUuid.type != "Item") { + return; + } + await this.updateClass(droppedUuid.uuid); + //this._render(); + } + + async getAllSkills() { + /**TODO: Get only player skills ?¿ there is no way to tell pet skills apart */ + let skills = game.items.filter(i => i.type == "skill"); + + for (const [compendium_key, compendium_value] of game.packs.entries()) { + let skillCompendium = await compendium_value.getDocuments({ type: "skill" }); + if (skillCompendium.length > 0) { + skills = skills.concat(skillCompendium) + } + } + return skills; + } + + async fill_class_options(html) { + + let class_options = game.items.filter(i => i.type == "class"); + + for (const [class_key, class_value] of class_options.entries()) { + + html.find(`datalist[id="class_options"]`).append( + `` + ); + } + + let compendiums = game.packs; + + for (const [compendium_key, compendium_value] of compendiums.entries()) { + let classes = await compendium_value.getDocuments({ type: "class" }); + for (const [class_key, class_value] of classes.entries()) { + let source = class_value.pack.replace(/\..*$/, ""); + html.find(`datalist[id="class_options"]`).append( + `` + ); + } + } + } + activateListeners(html) { + super.activateListeners(html); + + html.ready(ev => { + this.fill_class_options(html); + }); + + /** Stats */ + html.find(`img[id="system.stats.strength.value"]`).click(ev => { + this.rollStrength(html) + }); + html.find(`img[id="system.stats.speed.value"]`).click(ev => { + this.rollSpeed(html) + }); + html.find(`img[id="system.stats.intellect.value"]`).click(ev => { + this.rollIntellect(html) + }); + html.find(`img[id="system.stats.combat.value"]`).click(ev => { + this.rollCombat(html) + }); + + /** health */ + html.find(`img[id="system.health.max"]`).click(ev => { + this.rollHealth(html) + }); + + /**Saves */ + html.find(`img[id="system.stats.sanity.value"]`).click(ev => { + this.rollSanity(html) + }); + html.find(`img[id="system.stats.fear.value"]`).click(ev => { + this.rollFear(html) + }); + html.find(`img[id="system.stats.body.value"]`).click(ev => { + this.rollBody(html) + }); + + /** credits */ + + html.find(`img[id="system.credits.value"]`).click(ev => { + this.rollCredits(html) + }); + + /** Redo Skills */ + html.find(`i[id="system.class.skills.redo"]`).click(ev => { + this.applyClassSkills(html) + }); + + /** Roll everything button */ + html.find(`div[id="roll.everything"]`).click(ev => { + this.rollEverything(html) + }); + + /** Class input + * when changed will lockup if its a defined class item and apply the apropiate modifiers + * + */ + html.find(`input[id="system.class.value"]`).change(ev => { + let class_name = html.find(`input[id="system.class.value"]`).prop('value'); + if (class_name == "") { + //class name is empty, no class selected. + return; + } + let class_option = html.find(`option[class="class_option"][value="${class_name}"]`).prop('dataset'); + if (class_option == null) { + //class name is not part of the option, leave the string, and dont process uuid. + return; + } + //we have a valid class item to process. + this.updateClass(class_option["uuid"]); + + }); + + + /** Roll patch */ + html.find(`img[id="system.class.patch.value"]`).click(ev => { + this.rollPatch(html) + }); + /** Roll trinket */ + html.find(`img[id="system.class.trinket.value"]`).click(ev => { + this.rollTrinket(html) + }); + /** Roll loadout */ + html.find(`img[id="system.class.loadout.value"]`).click(ev => { + this.rollLoadout(html) + }); + + + /** Save and submit */ + html.find(`div[id="submit"]`).click(ev => { + this.submit() + }); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + + let data = { + "system.credits.value": formData["system.credits.value"], + "system.stats.strength.value": formData["system.stats.strength.value"] + (formData["system.stats.strength.bonus"] || 0), + "system.stats.speed.value": formData["system.stats.speed.value"] + (formData["system.stats.speed.bonus"] || 0), + "system.stats.intellect.value": formData["system.stats.intellect.value"] + (formData["system.stats.intellect.bonus"] || 0), + "system.stats.combat.value": formData["system.stats.combat.value"] + (formData["system.stats.combat.bonus"] || 0), + "system.health.value": formData["system.health.max"] + (formData["system.health.mod"] || 0), + "system.health.max": formData["system.health.max"] + (formData["system.health.mod"] || 0), + "system.stats.sanity.value": formData["system.stats.sanity.value"] + (formData["system.stats.sanity.bonus"] || 0), + "system.stats.fear.value": formData["system.stats.fear.value"] + (formData["system.stats.fear.bonus"] || 0), + "system.stats.body.value": formData["system.stats.body.value"] + (formData["system.stats.body.bonus"] || 0), + } + if (formData["system.stats.max_wounds.bonus"]) { + //max_wounds represent the bonus, so an android get 1 fro a total of 3 (2+1), + data["system.hits.max"] = 2 + parseInt(formData["system.stats.max_wounds.bonus"]); + } + else { + data["system.hits.max"] = 2; + } + + if (formData["name"]) { + data["name"] = formData["name"]; + } + if (formData["system.class.value"]) { + data["system.class.value"] = formData["system.class.value"]; + data["system.class.uuid"] = formData["system.class.uuid"]; + data["system.other.stressdesc.value"] = formData["system.class.traumaresponse"]; + } + /* + ChatMessage.create({content:`Character Rolls
    + STATS
    + Strength: ${data["system.stats.strength.value"]} = ${formData["system.stats.strength.value"]}+${formData["system.stats.strength.bonus"]}
    + Speed: ${data["system.stats.speed.value"]} = ${formData["system.stats.speed.value"]}+${formData["system.stats.speed.bonus"]}
    + Intellect: ${data["system.stats.intellect.value"]} = ${formData["system.stats.intellect.value"]}+${formData["system.stats.intellect.bonus"]}
    + Combat: ${data["system.stats.combat.value"]} = ${formData["system.stats.combat.value"]}+${formData["system.stats.combat.bonus"]}
    + SAVES
    + Sanity: ${data["system.stats.sanity.value"]} = ${formData["system.stats.sanity.value"]}+${formData["system.stats.sanity.bonus"]}
    + Fear: ${data["system.stats.fear.value"]} = ${formData["system.stats.fear.value"]}+${formData["system.stats.fear.bonus"]}
    + Body: ${data["system.stats.body.value"]} = ${formData["system.stats.body.value"]}+${formData["system.stats.body.bonus"]}
    +
    + Health: ${data["system.health.max"]}
    + Extra wounds: ${formData["system.stats.max_wounds.bonus"]}
    + Credits: ${data["system.credits.value"]}
    +
    + Trinket roll:
    + Patch roll:
    + Loadout roll
    `}); + */ + + if (formData["system.removepreviousitems"]) { + let itemTypesToDelete = ["item", "armor", "weapon", "skill", "condition"]; + let itemsToDelete = this.object.items.filter(item => itemTypesToDelete.includes(item.type)); + await this.object.deleteEmbeddedDocuments("Item", itemsToDelete.map(item => item.id)); + } + if (formData["system.class.loadout.uuid"]) { + let loadoutItems = formData["system.class.loadout.uuid"].split(","); + let itemsToAdd = {}; + for (var i = 0; i < loadoutItems.length; i++) { + if(!itemsToAdd[loadoutItems[i]]){ + itemsToAdd[loadoutItems[i]] = 0; + } + itemsToAdd[loadoutItems[i]] += 1; + } + for (const [itemUuid, quantity] of Object.entries(itemsToAdd)) { + await this.object.modifyItem(itemUuid, quantity); + } + } + if (formData["system.class.patch.uuid"]) { + await this.object.modifyItem(formData["system.class.patch.uuid"], 1); + } + if (formData["system.class.trinket.uuid"]) { + await this.object.modifyItem(formData["system.class.trinket.uuid"], 1); + } + if (formData["system.class.skills.uuid"]) { + let skillsItems = formData["system.class.skills.uuid"].split(","); + for (var i = 0; i < skillsItems.length; i++) { + await this.object.modifyItem(skillsItems[i], 1); + } + } + this.object.update(data); + } + +} \ No newline at end of file diff --git a/module/windows/settings-rolltables.js b/module/windows/settings-rolltables.js new file mode 100644 index 0000000..7abb60c --- /dev/null +++ b/module/windows/settings-rolltables.js @@ -0,0 +1,89 @@ +export class rolltableConfig extends FormApplication { + static get defaultOptions() { + const options = super.defaultOptions; + console.log(options); + //options.id = 'sheet-modifiers'; + //options.classes = ["mosh", "sheet", "actor", "ship"]; + options.id = 'rolltable-modifiers'; + options.classes = ["mosh"]; + options.template = 'systems/sla-mothership/templates/dialogs/settings-rolltableconfig-dialog.html'; + options.width = 800; + options.height = 'auto'; + options.resizeable = false; + options.submitOnChange = true; + options.submitOnClose = true; + options.closeOnSubmit = false; + return options; + } + + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + getData() { + const tableSelection = super.getData(); + tableSelection.table0ePanicStressNormal = game.settings.get("sla-mothership", "table0ePanicStressNormal"); + tableSelection.table0ePanicStressAndroid = game.settings.get("sla-mothership", "table0ePanicStressAndroid"); + tableSelection.table0ePanicCalmNormal = game.settings.get("sla-mothership", "table0ePanicCalmNormal"); + tableSelection.table0ePanicCalmAndroid = game.settings.get("sla-mothership", "table0ePanicCalmAndroid"); + tableSelection.table1ePanicStressNormal = game.settings.get("sla-mothership", "table1ePanicStressNormal"); + tableSelection.table1ePanicStressAndroid = game.settings.get("sla-mothership", "table1ePanicStressAndroid"); + tableSelection.table1ePanicCalmNormal = game.settings.get("sla-mothership", "table1ePanicCalmNormal"); + tableSelection.table1ePanicCalmAndroid = game.settings.get("sla-mothership", "table1ePanicCalmAndroid"); + tableSelection.table1eWoundBluntForce = game.settings.get("sla-mothership", "table1eWoundBluntForce"); + tableSelection.table1eWoundBleeding = game.settings.get("sla-mothership", "table1eWoundBleeding"); + tableSelection.table1eWoundGunshot = game.settings.get("sla-mothership", "table1eWoundGunshot"); + tableSelection.table1eWoundFireExplosives = game.settings.get("sla-mothership", "table1eWoundFireExplosives"); + tableSelection.table1eWoundGoreMassive = game.settings.get("sla-mothership", "table1eWoundGoreMassive"); + tableSelection.table0eDeath = game.settings.get("sla-mothership", "table0eDeath"); + tableSelection.table1eDeath = game.settings.get("sla-mothership", "table1eDeath"); + tableSelection.table1eDistressSignal = game.settings.get("sla-mothership", "table1eDistressSignal"); + tableSelection.table1eMegadamageEffects = game.settings.get("sla-mothership", "table1eMegadamageEffects"); + tableSelection.table1eMaintenance = game.settings.get("sla-mothership", "table1eMaintenance"); + tableSelection.table1eBankruptcy = game.settings.get("sla-mothership", "table1eBankruptcy"); + + return tableSelection; + } + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Close Button + html.find('.close-button').click(ev => { + this.close() + }); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + await Promise.all([ + game.settings.set("sla-mothership", "table0ePanicStressNormal", formData["table0ePanicStressNormal"]), + game.settings.set("sla-mothership", "table0ePanicStressAndroid", formData["table0ePanicStressAndroid"]), + game.settings.set("sla-mothership", "table0ePanicCalmNormal", formData["table0ePanicCalmNormal"]), + game.settings.set("sla-mothership", "table0ePanicCalmAndroid", formData["table0ePanicCalmAndroid"]), + game.settings.set("sla-mothership", "table1ePanicStressNormal", formData["table1ePanicStressNormal"]), + game.settings.set("sla-mothership", "table1ePanicStressAndroid", formData["table1ePanicStressAndroid"]), + game.settings.set("sla-mothership", "table1ePanicCalmNormal", formData["table1ePanicCalmNormal"]), + game.settings.set("sla-mothership", "table1ePanicCalmAndroid", formData["table1ePanicCalmAndroid"]), + game.settings.set("sla-mothership", "table1eWoundBluntForce", formData["table1eWoundBluntForce"]), + game.settings.set("sla-mothership", "table1eWoundBleeding", formData["table1eWoundBleeding"]), + game.settings.set("sla-mothership", "table1eWoundGunshot", formData["table1eWoundGunshot"]), + game.settings.set("sla-mothership", "table1eWoundFireExplosives", formData["table1eWoundFireExplosives"]), + game.settings.set("sla-mothership", "table1eWoundGoreMassive", formData["table1eWoundGoreMassive"]), + game.settings.set("sla-mothership", "table0eDeath", formData["table0eDeath"]), + game.settings.set("sla-mothership", "table1eDeath", formData["table1eDeath"]), + game.settings.set("sla-mothership", "table1eDistressSignal", formData["table1eDistressSignal"]), + game.settings.set("sla-mothership", "table1eMegadamageEffects", formData["table1eMegadamageEffects"]), + game.settings.set("sla-mothership", "table1eMaintenance", formData["table1eMaintenance"]), + game.settings.set("sla-mothership", "table1eBankruptcy", formData["table1eBankruptcy"]) + ]); + + } +} diff --git a/module/windows/ship-deckplan.js b/module/windows/ship-deckplan.js new file mode 100644 index 0000000..306f818 --- /dev/null +++ b/module/windows/ship-deckplan.js @@ -0,0 +1,62 @@ +export class DLShipDeckplan extends foundry.appv1.sheets.ActorSheet { + static get defaultOptions() { + const options = super.defaultOptions; + options.id = 'sheet-modifiers'; + options.classes = ["mosh", "sheet", "actor", "ship"]; + options.template = 'systems/sla-mothership/templates/dialogs/ship-deckplan-dialog.html'; + options.width = 800; + options.height = 'auto'; + options.resizeable = true; + return options; + } + /* -------------------------------------------- */ + /** + * Add the Entity name into the window title + * @type {String} + */ + get title() { + return `${this.object.name}: Deckplan`; + } + /* -------------------------------------------- */ + + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + getData() { + const actor = this.object; + console.log(this.object); + + return { + actor + }; + } + + + /* -------------------------------------------- */ + + + + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + await this.object.update({ + "system.images.layout": formData['actor.system.images.layout'] + }); + + this.object.update({ + formData + }); + this.object.sheet.render({force: true}); + } +} diff --git a/module/windows/ship-macros.js b/module/windows/ship-macros.js new file mode 100644 index 0000000..d609544 --- /dev/null +++ b/module/windows/ship-macros.js @@ -0,0 +1,110 @@ +import { DLShipDeckplan } from "../windows/ship-deckplan.js"; + + +export class DLShipMacros extends foundry.applications.sheets.BaseSheet { + static get defaultOptions() { + const options = super.defaultOptions; + options.id = 'sheet-modifiers'; + options.classes = ["mosh", "sheet", "actor", "ship"]; + options.template = 'systems/sla-mothership/templates/dialogs/ship-macro-dialog.html'; + options.width = 320; + options.height = 'auto'; + options.resizeable = false; + return options; + } + /* -------------------------------------------- */ + /** + * Add the Entity name into the window title + * @type {String} + */ + get title() { + return `${this.object.name}: Ship Macros`; + } + /* -------------------------------------------- */ + + _onOpenDeckplan(event) { + event.preventDefault(); + new DLShipDeckplan(this.object, { + top: this.position.top + 40, + left: this.position.left + (this.position.width - 400) / 2 + }).render({force: true}); + } + + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + getData() { + const actor = this.object; + + return { + actor + }; + } + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Distress Signal + html.find('.distress-button').click(ev => { + //roll distress signal + this.object.distressSignal(); + }); + + // Maintenance Check + html.find('.maintenance-button').click(ev => { + //roll maintenance check + this.object.maintenanceCheck(); + }); + + // Bankruptcy Save + html.find('.bankruptcy-button').click(ev => { + //roll bankruptcy save + this.object.bankruptcySave(); + }); + + // Morale Check + html.find('.morale-button').click(ev => { + //roll morale check + this.object.moraleCheck(); + }); + + // Deckplan Button + html.find('.deckplan-button').click(ev => this._onOpenDeckplan(ev)); + + // Close Button + html.find('.close-button').click(ev => this.close()); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + + // await this.object.update({ + // "data.stats.loyalty.enabled": true + // }); + + await this.object.update({ + "data.stats.bankruptcy.value": formData['actor.system.stats.bankruptcy.value'] + }); + + // await this.object.updateEmbeddedEntity("OwnedItem", update); + + // await this.object.update({ + // formData + // }); + + // console.log(this); + + // await this.object.sheet.render(true, {focus: false}); + // this.bringToTop(); + + + } +} diff --git a/module/windows/ship-megadamage.js b/module/windows/ship-megadamage.js new file mode 100644 index 0000000..b85866a --- /dev/null +++ b/module/windows/ship-megadamage.js @@ -0,0 +1,120 @@ +import { fromIdUuid } from "../mosh.js"; +export class DLShipMegaDamage extends FormApplication { + static get defaultOptions() { + const options = super.defaultOptions; + options.id = 'sheet-modifiers'; + options.classes = ["mosh", "sheet", "actor", "ship"]; + options.template = 'systems/sla-mothership/templates/dialogs/ship-megadamage-dialog.html'; + options.width = 320; + options.height = 'auto'; + options.resizeable = false; + return options; + } + /* -------------------------------------------- */ + /** + * Add the Entity name into the window title + * @type {String} + */ + get title() { + return `${this.object.name}: Megadamage Effects`; + } + /* -------------------------------------------- */ + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + getData() { + const data = super.getData(); + const actor = this.object; + + + this._prepareMegadamage(data); + + + return { + actor + }; + } + + + async _prepareMegadamage(sheetData){ + const actorData = sheetData.object; + + //A script to return the data from a table. + let tableId = game.settings.get('sla-mothership','table1eMegadamageEffects'); + //get table data + let tableData = await fromIdUuid(tableId,{type:"RollTable"}); + + let entries = Array.from(tableData.results.entries()); + + // MEGADAMAGE SETTINGS MENU + let megadamageSettingsHTML = ""; + let index = 0; + for(const entry of entries){ + if(index != 0){ + if (actorData.system.megadamage.hits.includes(index)){ + megadamageSettingsHTML += `  `; + } + else{ + megadamageSettingsHTML += `  `; + } + + megadamageSettingsHTML += `${index} | ${entry[1].description}

    `; + } + index++; + } + + actorData.system.megadamage.menu.html = megadamageSettingsHTML; + + // await this.object.update({ + // "data.megadamage.menu.html": megadamageSettingsHTML + // }); + } + + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + html.on('mousedown', '.megadamage-button', ev => { + const data = this.object; + + const div = $(ev.currentTarget); + const targetKey = div.data("key"); + + if(data.system.megadamage.hits.includes(targetKey)){ + const index = data.system.megadamage.hits.indexOf(targetKey); + data.system.megadamage.hits.splice(index, 1); + } else { + data.system.megadamage.hits.push(targetKey); + } + + this.object.update({ + "data.megadamage.hits": data.system.megadamage.hits + }); + + this.render(true, {focus: true}); + }); + + // Close Button + html.find('.close-button').click(ev => this.close()); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + + // this.object.update({ + // formData + // }); + + //await this.object.sheet.render(true, {focus: false}); + + + } +} diff --git a/module/windows/ship-setup.js b/module/windows/ship-setup.js new file mode 100644 index 0000000..725e689 --- /dev/null +++ b/module/windows/ship-setup.js @@ -0,0 +1,73 @@ +export class DLShipSetup extends FormApplication { + static get defaultOptions() { + const options = super.defaultOptions; + options.id = 'sheet-modifiers'; + options.classes = ["mosh", "sheet", "actor", "ship"]; + options.template = 'systems/sla-mothership/templates/dialogs/ship-setup-dialog.html'; + options.width = 320; + options.height = 'auto'; + options.resizeable = false; + return options; + } + /* -------------------------------------------- */ + /** + * Add the Entity name into the window title + * @type {String} + */ + get title() { + return `${this.object.name}: Ship Setup`; + } + /* -------------------------------------------- */ + /** + * Construct and return the data object used to render the HTML template for this form application. + * @return {Object} + */ + getData() { + const actor = this.object; + console.log(this); + + return { + actor + }; + } + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Starting Conditions + html.find('.conditions-button').click(ev => { + //roll starting conditions + this.object.rollTable('kqz8GsFVPfjvqO0N','1d5+1','low',true,false,null,null); + }); + + // Close Button + html.find('.close-button').click(ev => this.close()); + } + + /** + * This method is called upon form submission after form data is validated + * @param event {Event} The initial triggering submission event + * @param formData {Object} The object of validated form data with which to update the object + * @private + */ + async _updateObject(event, formData) { + + console.log("Updating Object"); + + await this.object.update({ + "name": formData['actor.name'] + }); + + + this.object.update({ + formData + }); + console.log(this); + + await this.object.sheet.render(true, {focus: false}); + + + } +} diff --git a/module/windows/sla-character-generator.js b/module/windows/sla-character-generator.js new file mode 100644 index 0000000..8996fe0 --- /dev/null +++ b/module/windows/sla-character-generator.js @@ -0,0 +1,1183 @@ +import { buildSlaTraumaResponseText } from "../sla-trauma.js"; + +const SYSTEM_ID = "sla-mothership"; +const COMPANION_MODULE_ID = "sla-mothership-compendium"; +const ROOT_ACTOR_FOLDER = "SLA Mothership"; +const OPERATIVE_FOLDER = "Operatives"; + +const PACKAGE_STAT_BONUSES = { + "Death Squad": { combat: 12, body: 8, health: 2, ebbRating: 0 }, + "Strike Squad": { combat: 10, speed: 6, body: 4, health: 1, ebbRating: 0 }, + "Kick Murder": { strength: 10, combat: 8, speed: 4, health: 2, ebbRating: 0 }, + Scouting: { speed: 10, intellect: 4, combat: 6, fear: 2, ebbRating: 0 }, + Investigation: { intellect: 10, fear: 6, sanity: 4, combat: 2, ebbRating: 0 }, + Media: { intellect: 8, fear: 6, sanity: 2, speed: 2, ebbRating: 0 }, + Medical: { intellect: 8, body: 6, sanity: 6, speed: 2, ebbRating: 0 }, + Mechanic: { intellect: 10, body: 2, combat: 2, sanity: 4, ebbRating: 0 }, + "Tech Ops": { intellect: 12, combat: 4, fear: 4, body: 2, ebbRating: 0 }, + Pilot: { speed: 8, intellect: 6, fear: 4, combat: 4, ebbRating: 0 }, + "Ebb Operative": { intellect: 8, fear: 8, sanity: 10, ebbRating: 2 } +}; + +const PACKAGE_GEAR = { + "Death Squad": ["BOOPA Medical Kit (Standard)", "Restraint Cuffs (Heavy Duty)"], + "Strike Squad": ["Flashbang Grenade", "Restraint Cuffs (Heavy Duty)"], + "Kick Murder": ["BOOPA Medical Kit (Standard)"], + Scouting: ["Grapple Gun", "Climbing Harness & Gear"], + Investigation: ["Headset Communicator", "Restraint Cuffs (Heavy Duty)"], + Media: ["Headset Communicator", "Klippo Multi-Band Communicator"], + Medical: ["BOOPA Medical Kit (Advanced)", "Headset Communicator"], + Mechanic: ["Headset Communicator", "Climbing Harness & Gear"], + "Tech Ops": ["Headset Communicator", "Flashbang Grenade"], + Pilot: ["Headset Communicator", "Climbing Harness & Gear"], + "Ebb Operative": ["Headset Communicator", "BOOPA Medical Kit (Standard)"] +}; + +const SPECIES_DOSSIER = { + Human: { + identity: "Adaptable generalists. No racial extremes; their edge is flexibility and social access to SLA's systems.", + fieldPressure: "Humans are expected to fill doctrine gaps, improvise, and absorb sponsor demands without complaint." + }, + Frother: { + identity: "Clan-human berserkers born with a physiological gift for combat drugs, violence, and recovery.", + fieldPressure: "Keep them pointed at the problem and away from delicate evidence chains or sponsor-facing civilians." + }, + Ebon: { + identity: "Mystical, emotionally volatile Ebb users whose greatest strength is disciplined mental focus rather than physical resilience.", + fieldPressure: "They are trusted when the mission needs calm precision, but every Flux spike is watched and every psychic event hits them harder." + }, + "Brain Waster": { + identity: "Violent evolutionary offshoots of the Ebon; hateful, aggressive Ebb users who are more dangerous in a fight than in a briefing room.", + fieldPressure: "Command expects results fast, but collateral panic and the psychic shockwave around them are never far behind." + }, + "Wraith Raider": { + identity: "Feline ice-world hunters with lightning reflexes, superior senses, and the fastest natural movement profile in the World of Progress.", + fieldPressure: "Use them for pursuit, flank work, and live target acquisition before a scene turns static or heavily scripted." + }, + Shaktar: { + identity: "Saurian warriors of honour and martial tradition, combining brutal strength with disciplined battlefield intent.", + fieldPressure: "Doctrine has to respect their code or the squad risks discipline fractures at the worst possible time." + }, + "Stormer 313 Malice": { + identity: "Karma's standard biogenetic combat unit: a massive regenerating killing machine with overwhelming power and minimal subtlety.", + fieldPressure: "They solve breaches, riots, and hard resistance, but subtlety evaporates when they take the lead." + }, + "Stormer 711 Xeno": { + identity: "Karma's fast insectile camouflage unit: a stealth biogen built for pursuit, ambush, and pressure from impossible angles.", + fieldPressure: "Best used where speed and feral pressure matter more than conversation or sponsor optics." + }, + "Advanced Carrien": { + identity: "Cunning, dangerous mutants with strong survival instincts and an uneasy fit inside official structures.", + fieldPressure: "They thrive in broken districts and dirty jobs, but prejudice follows them into every briefing room." + } +}; + +const SPECIES_MIN_WOUNDS = { + Frother: 3, + Shaktar: 3, + "Stormer 313 Malice": 3, + "Stormer 711 Xeno": 3 +}; + +const SKILL_IMAGE_OVERRIDES = { + athletics: "systems/sla-mothership/images/sla-assets/Skills/Athletics.png", + brawl: "systems/sla-mothership/images/sla-assets/Skills/Brawl.png" +}; + +const SPECIES_MOTHERSHIP_PROFILES = { + Human: { + rolls: { + strength: "2d10+25", + speed: "2d10+25", + intellect: "2d10+27", + combat: "2d10+25", + sanity: "2d10+15", + fear: "2d10+13", + body: "2d10+10", + health: "1d10+10" + }, + description: "Baseline human template with a slight Intellect and Sanity edge reflecting bureaucracy, social resilience, and operational flexibility." + }, + Frother: { + rolls: { + strength: "2d10+33", + speed: "2d10+28", + intellect: "2d10+20", + combat: "2d10+35", + sanity: "2d10+2", + fear: "2d10+15", + body: "2d10+20", + health: "1d10+12" + }, + description: "Extreme Strength, Combat, and Body with a weak Intellect line and dangerously fragile Sanity. Frothers are terror weapons, not balanced operatives." + }, + Ebon: { + rolls: { + strength: "2d10+20", + speed: "2d10+25", + intellect: "2d10+37", + combat: "2d10+22", + sanity: "2d10+5", + fear: "2d10+14", + body: "2d10+5", + health: "1d10+9" + }, + description: "Exceptional Intellect backed by weak Strength and Body. Ebons solve impossible problems through Ebb discipline, not brute force." + }, + "Brain Waster": { + rolls: { + strength: "2d10+28", + speed: "2d10+25", + intellect: "2d10+33", + combat: "2d10+32", + sanity: "2d10+13", + fear: "2d10+10", + body: "2d10+13", + health: "1d10+10" + }, + description: "A harsher Ebb profile than Ebon: stronger, more aggressive, and more immediately dangerous, but socially and psychically corrosive." + }, + "Wraith Raider": { + rolls: { + strength: "2d10+25", + speed: "2d10+40", + intellect: "2d10+28", + combat: "2d10+33", + sanity: "2d10+7", + fear: "2d10+18", + body: "2d10+12", + health: "1d10+10" + }, + description: "The speed apex among natural species. Wraith Raiders react, pursue, and strike before most opponents have processed the danger." + }, + Shaktar: { + rolls: { + strength: "2d10+37", + speed: "2d10+30", + intellect: "2d10+20", + combat: "2d10+37", + sanity: "2d10+18", + fear: "2d10+20", + body: "2d10+22", + health: "1d10+12" + }, + description: "A front-line martial species with exceptional Strength, Combat, and Body backed by formidable Sanity and Fear saves." + }, + "Stormer 313 Malice": { + rolls: { + strength: "2d10+43", + speed: "2d10+30", + intellect: "2d10+17", + combat: "2d10+40", + sanity: "2d10+20", + fear: "2d10+22", + body: "2d10+25", + health: "1d10+14" + }, + description: "Near-ceiling assault biology: immense Strength, Combat, and Body with deliberately shallow abstract reasoning and social finesse." + }, + "Stormer 711 Xeno": { + rolls: { + strength: "2d10+30", + speed: "2d10+40", + intellect: "2d10+23", + combat: "2d10+35", + sanity: "2d10+15", + fear: "2d10+17", + body: "2d10+18", + health: "1d10+12" + }, + description: "Matches Wraith Raider speed with biogen resilience, regeneration, and camouflage systems in place of natural grace." + }, + "Advanced Carrien": { + rolls: { + strength: "2d10+30", + speed: "2d10+26", + intellect: "2d10+30", + combat: "2d10+26", + sanity: "2d10+14", + fear: "2d10+14", + body: "2d10+18", + health: "1d10+11" + }, + description: "Clever survivor profile. Strong Intellect and workable Strength make Carrien dangerous problem-solvers with uneven social acceptance." + } +}; + +const PACKAGE_DOCTRINE = { + "Death Squad": { + role: "overwhelming force", + tone: "Direct-action eliminators for hard resistance, riot escalations, and kill-zone control.", + fieldPressure: "Speed, violence, and intimidation matter more than subtle handling." + }, + "Strike Squad": { + role: "urban assault", + tone: "Balanced entry teams built for Mort City raids, corridor pushes, and disciplined weapons work.", + fieldPressure: "They are expected to hold angles, control civilians, and secure scenes fast." + }, + "Kick Murder": { + role: "melee suppression", + tone: "Close-quarters shock operatives intended to break morale, not preserve comfort.", + fieldPressure: "Best unleashed where crowd fear and brutal momentum are useful." + }, + Scouting: { + role: "recon and pursuit", + tone: "Forward observers, trackers, and range specialists who keep squads from walking into bad ground.", + fieldPressure: "Information advantage is the job; if they lose eyes on the field, everyone pays." + }, + Investigation: { + role: "evidence and interviews", + tone: "Case-building operatives for forensic scenes, witness handling, and corporate narrative control.", + fieldPressure: "Their work must survive review by sponsors, supervisors, and media parasites." + }, + Media: { + role: "image management", + tone: "Public-facing operators who shape reputation, frame incidents, and turn action into sponsor capital.", + fieldPressure: "They are judged as much by optics and access as by operational grit." + }, + Medical: { + role: "trauma sustainment", + tone: "Combat medics and scene stabilisers who keep operatives alive long enough for extraction or continuation.", + fieldPressure: "They are always one mistake away from becoming the last barrier before body bags." + }, + Mechanic: { + role: "repair and support", + tone: "Field engineers who keep weapons, armour, doors, vehicles, and infrastructure functioning under pressure.", + fieldPressure: "Every mission assumes their kit will fix the thing nobody else prepared for." + }, + "Tech Ops": { + role: "systems intrusion", + tone: "Electronic warfare and specialist breach staff for locks, surveillance, and machine-facing problems.", + fieldPressure: "They are expected to make sealed systems open and hostile tech obedient." + }, + Pilot: { + role: "navigation and mobility", + tone: "Vehicle and route specialists who keep squads moving, extracting, and arriving faster than the opposition.", + fieldPressure: "When transit fails, the mission usually fails with it." + }, + "Ebb Operative": { + role: "occult intervention", + tone: "Specialist Ebb handlers brought in for psychic pressure, unseen threats, and impossible angles.", + fieldPressure: "They carry the quiet burden of solving problems normal operatives cannot even describe." + } +}; + +const BASE_ISSUE_GEAR = [ + "Oyster Card (ITB Card)", + "Klippo Multi-Band Communicator", + "UV / Multi-Spectrum Torch" +]; + +const PACKAGE_FIELD_KITS = { + "Death Squad": ["Flashbang Grenade", "Webbing / Tactical Vest", "Cable Ties (Pack of 50)"], + "Strike Squad": ["Flashbang Grenade", "Smoke Grenade", "Webbing / Tactical Vest"], + "Kick Murder": ["Flashbang Grenade", "Entrenching Tool", "Duct Tape (Roll)"], + Scouting: ["Binoculars (Tactical)", "Grapple Gun", "Climbing Harness & Gear", "Rope (50m, High-Tensile)"], + Investigation: ["Forensic Kit", "Audio Recorder", "Evidence Bags (Pack of 20)", "Electronic Lockpick / Bypass Kit"], + Media: ["Camera (Still/Video)", "Third Eye Viewer (Portable)", "Audio Recorder", "Vid-Phone (Portable)"], + Medical: ["BOOPA Medical Kit (Advanced)", "Trauma Stabiliser", "Drug Hypo-Spray (Empty)"], + Mechanic: ["Tool Kit (General)", "Tool Kit (Electronics)", "Equipment Case (Ruggedised)"], + "Tech Ops": ["Electronic Lockpick / Bypass Kit", "Environment Scanner (Standard)", "Power Cell (Extended)"], + Pilot: ["Compass (Magnetic)", "Binoculars (Standard)", "Operative Organiser"], + "Ebb Operative": ["BOOPA (Audio)", "Operative Organiser", "Environment Scanner (Standard)"] +}; + +const EBB_STARTERS = { + Ebon: ["Awareness", "Heal", "Protect"], + "Brain Waster": ["Blast", "Telekinesis", "Awareness"] +}; + +const EBB_CORE_SKILLS = ["Biofeedback", "Formulate", "Ebb (Core)"]; + +const SPECIES_WEAPONS = { + "Wraith Raider": ["Wraith Raider Claws"], + Shaktar: ["Shaktar Claws"], + "Stormer 313 Malice": ["Stormer Claws"], + "Stormer 711 Xeno": ["Stormer Claws"] +}; + +const NAME_PARTS = { + first: [ + "Ari", "Bex", "Cade", "Dax", "Eris", "Finn", "Galen", "Hex", "Iris", "Jax", + "Kara", "Lex", "Mara", "Nero", "Orla", "Pax", "Quill", "Riven", "Sable", "Tarn", + "Vale", "Wren", "Xanthe", "Yorik", "Zane" + ], + last: [ + "Ash", "Black", "Cairn", "Drake", "Evans", "Flint", "Graves", "Holt", "Ives", "Kane", + "Morrow", "Nox", "Pyke", "Quade", "Rook", "Shard", "Thorne", "Vale", "Voss", "Wren" + ], + callsign: [ + "Afterglow", "Ashfall", "Blackout", "Coldwire", "Deadfall", "Echo", "Fuse", "Ghost", + "Grim", "Hush", "Ion", "Lancer", "Nightglass", "Quake", "Razor", "Static", "Torch", "Vanta" + ], + bpn: ["Blue", "White", "Grey", "Amber", "Red", "Black"] +}; + +let cachedSeedData = null; + +export class SLAMothershipGenerator extends FormApplication { + static get defaultOptions() { + return foundry.utils.mergeObject(super.defaultOptions, { + id: "sla-mothership-generator", + classes: ["mosh", "sheet", "actor", "character", "sla-generator"], + template: "systems/sla-mothership/templates/dialogs/sla-character-generator.html", + width: 640, + height: "auto", + submitOnChange: false, + closeOnSubmit: true + }); + } + + constructor(actor = null, options = {}) { + super(actor ?? {}, options); + this.actor = actor instanceof Actor ? actor : null; + } + + get title() { + return this.actor ? `SLA Generator: ${this.actor.name}` : "Create SLA Operative"; + } + + async getData() { + const data = await SLAMothershipGenerator.loadSeedData(); + const speciesOptions = data.species.species.map((entry) => entry.name); + const packageOptions = data.packages.packages.map((entry) => entry.name); + const actorSystem = this.actor?.system ?? {}; + const actorSla = actorSystem.sla ?? {}; + + const selectedSpecies = String(actorSla.species?.value ?? "").trim() || speciesOptions[0] || "Human"; + const speciesEntry = data.species.species.find((entry) => entry.name === selectedSpecies) ?? data.species.species[0] ?? null; + const selectedPackage = String(actorSla.trainingPackage?.value ?? "").trim() + || speciesEntry?.starterPackage + || packageOptions[0] + || ""; + const briefing = SLAMothershipGenerator.buildGeneratorBriefing(data, selectedSpecies, selectedPackage); + + return { + actorName: this.actor?.name ?? "", + name: this.actor?.name ?? SLAMothershipGenerator.randomName(), + editingExisting: Boolean(this.actor), + replaceExisting: true, + selectedSpecies, + selectedPackage, + speciesOptions, + packageOptions, + employer: String(actorSla.employer?.value ?? "").trim() || "SLA Industries", + sector: String(actorSla.sector?.value ?? "").trim() || "Mort City", + operativeType: String(actorSla.operativeType?.value ?? "").trim() || "Contract Operative", + assignLoadout: true, + assignGear: true, + assignEbb: briefing.isEbbSpecies, + openSheet: true, + briefing + }; + } + + activateListeners(html) { + super.activateListeners(html); + + const updateBriefing = async () => { + const data = await SLAMothershipGenerator.loadSeedData(); + const speciesName = String(html.find("[name='species']").val() ?? "").trim(); + const packageName = String(html.find("[name='packageName']").val() ?? "").trim(); + const briefing = SLAMothershipGenerator.buildGeneratorBriefing(data, speciesName, packageName); + const isEbbSpecies = briefing.isEbbSpecies; + html.find("[data-briefing='species-title']").text(briefing.speciesTitle); + html.find("[data-briefing='species-copy']").text(briefing.speciesCopy); + html.find("[data-briefing='package-title']").text(briefing.packageTitle); + html.find("[data-briefing='package-copy']").text(briefing.packageCopy); + html.find("[data-briefing='flux-copy']").text(briefing.fluxCopy); + html.find("[data-ebb-toggle]").toggle(isEbbSpecies); + html.find("[data-ebb-panel]").toggle(isEbbSpecies); + html.find("[name='assignEbb']").prop("disabled", !isEbbSpecies); + if (!isEbbSpecies) { + html.find("[name='assignEbb']").prop("checked", false); + } else if (!html.find("[name='assignEbb']").is(":checked")) { + html.find("[name='assignEbb']").prop("checked", true); + } + + const speciesNotes = html.find("[data-briefing='species-notes']"); + speciesNotes.empty(); + for (const note of briefing.speciesNotes) { + speciesNotes.append($(`
    ${note}
    `)); + } + + const packageSkills = html.find("[data-briefing='package-skills']"); + packageSkills.empty(); + for (const skill of briefing.packageSkills) { + packageSkills.append($(`
    ${skill}
    `)); + } + }; + + html.find(".random-name").on("click", () => { + html.find("[name='name']").val(SLAMothershipGenerator.randomName()); + }); + + html.find("[name='species']").on("change", async (event) => { + const data = await SLAMothershipGenerator.loadSeedData(); + const speciesName = String(event.currentTarget.value ?? ""); + const species = data.species.species.find((entry) => entry.name === speciesName); + if (!species) return; + + const packageInput = html.find("[name='packageName']"); + packageInput.val(species.starterPackage ?? String(packageInput.val() ?? "").trim()); + html.find("[name='operativeType']").val(species.starterPackage || String(html.find("[name='operativeType']").val() ?? "").trim() || "Contract Operative"); + await updateBriefing(); + }); + + html.find("[name='packageName']").on("change", async () => { + const packageName = String(html.find("[name='packageName']").val() ?? "").trim(); + html.find("[name='operativeType']").val(packageName || String(html.find("[name='operativeType']").val() ?? "").trim() || "Contract Operative"); + await updateBriefing(); + }); + + updateBriefing(); + } + + async _updateObject(_event, formData) { + const data = foundry.utils.expandObject(formData); + return SLAMothershipGenerator.generate({ + actor: this.actor, + name: String(data.name ?? "").trim() || SLAMothershipGenerator.randomName(), + speciesName: String(data.species ?? "").trim() || "Human", + packageName: String(data.packageName ?? "").trim(), + employer: String(data.employer ?? "").trim() || "SLA Industries", + sector: String(data.sector ?? "").trim() || "Mort City", + operativeType: String(data.operativeType ?? "").trim() || "Contract Operative", + bpn: SLAMothershipGenerator.randomBpn(), + replaceExisting: Boolean(data.replaceExisting), + assignLoadout: Boolean(data.assignLoadout), + assignGear: Boolean(data.assignGear), + assignEbb: Boolean(data.assignEbb), + openSheet: Boolean(data.openSheet) + }); + } + + static open(actor = null, options = {}) { + return new SLAMothershipGenerator(actor, options).render({ force: true }); + } + + static async createRandomOperative(options = {}) { + const data = await this.loadSeedData(); + const requestedSpecies = new Set((options.speciesPool ?? []).map((entry) => String(entry ?? "").trim()).filter(Boolean)); + const filteredSpecies = requestedSpecies.size + ? data.species.species.filter((entry) => requestedSpecies.has(entry.name)) + : data.species.species; + const species = randomFrom(filteredSpecies.length ? filteredSpecies : data.species.species) ?? { name: "Human", starterPackage: "Strike Squad" }; + const packageName = species.starterPackage || randomFrom(data.packages.packages)?.name || "Strike Squad"; + return this.generate({ + name: this.randomName(), + speciesName: species.name, + packageName, + employer: "SLA Industries", + sector: "Mort City", + operativeType: packageName, + bpn: this.randomBpn(), + replaceExisting: true, + assignLoadout: true, + assignGear: true, + assignEbb: true, + openSheet: options.openSheet ?? true + }); + } + + static async createRandomEbbOperative(options = {}) { + return this.createRandomOperative({ + ...options, + speciesPool: ["Ebon", "Brain Waster"] + }); + } + + static async createRandomNonEbbOperative(options = {}) { + const data = await this.loadSeedData(); + const nonEbbSpecies = data.species.species + .map((entry) => entry.name) + .filter((name) => !this.isEbbSpecies(name)); + return this.createRandomOperative({ + ...options, + speciesPool: nonEbbSpecies + }); + } + + static async createStarterSquad({ overwrite = false, notify = true } = {}) { + const folder = await ensureActorFolder(); + const presets = [ + { name: "Sable Morrow \"Static\"", speciesName: "Human", packageName: "Strike Squad", operativeType: "Strike Squad", bpn: "Blue" }, + { name: "Riven Holt \"Quiet\"", speciesName: "Human", packageName: "Investigation", operativeType: "Investigation", bpn: "White" }, + { name: "Tarn Voss \"Reef\"", speciesName: "Shaktar", packageName: "Death Squad", operativeType: "Death Squad", bpn: "Grey" }, + { name: "Iris Kane \"Halo\"", speciesName: "Ebon", packageName: "Ebb Operative", operativeType: "Ebb Operative", bpn: "Amber" } + ]; + + let created = 0; + let updated = 0; + + for (const preset of presets) { + const existing = game.actors.find((actor) => actor.flags?.[SYSTEM_ID]?.slaStarter === preset.name); + if (existing && !overwrite) continue; + + const actor = existing ?? await Actor.create({ + name: preset.name, + type: "character", + folder: folder.id, + flags: { + [SYSTEM_ID]: { + slaStarter: preset.name + } + } + }); + + await this.generate({ + actor, + name: preset.name, + speciesName: preset.speciesName, + packageName: preset.packageName, + operativeType: preset.operativeType, + employer: "SLA Industries", + sector: "Mort City", + bpn: preset.bpn, + replaceExisting: true, + assignLoadout: true, + assignGear: true, + assignEbb: true, + openSheet: false + }); + + if (!existing) created += 1; + else updated += 1; + } + + if (notify) { + ui.notifications.info(`SLA starter squad ready: ${created} created, ${updated} updated.`); + } + return { created, updated }; + } + + static async generate({ + actor = null, + name = "New Operative", + speciesName = "Human", + packageName = "", + employer = "SLA Industries", + sector = "Mort City", + operativeType = "Contract Operative", + bpn = "", + replaceExisting = true, + assignLoadout = true, + assignGear = true, + assignEbb = true, + openSheet = true + } = {}) { + await this.ensureSeedData(); + + const data = await this.loadSeedData(); + const species = data.species.species.find((entry) => entry.name === speciesName) ?? data.species.species[0]; + if (!species) throw new Error("No SLA species data available."); + + const resolvedPackageName = packageName || species.starterPackage || data.packages.packages[0]?.name || ""; + const trainingPackage = data.packages.packages.find((entry) => entry.name === resolvedPackageName) ?? data.packages.packages[0] ?? null; + + const actorDoc = actor instanceof Actor + ? actor + : await Actor.create({ + name, + type: "character", + folder: (await ensureActorFolder()).id + }); + + if (replaceExisting && actorDoc.items.size) { + await actorDoc.deleteEmbeddedDocuments("Item", actorDoc.items.map((item) => item.id)); + } + + const rolls = await rollMothershipProfile(species); + const derived = deriveProfile(rolls, trainingPackage?.name ?? "", species.name); + const itemPayloads = []; + + if (trainingPackage) { + itemPayloads.push(...this.buildSkillItems(trainingPackage.skills ?? [], species, data.skills.skills)); + } + + itemPayloads.push(...this.buildSpeciesItems(species.name)); + + if (assignLoadout && trainingPackage) { + itemPayloads.push(...this.buildLoadoutItems(trainingPackage.name, data.equipment.packageLoadouts ?? {})); + } + + if (assignGear && trainingPackage) { + itemPayloads.push(...this.buildGearItems(trainingPackage.name)); + } + + if (assignEbb && this.isEbbSpecies(species.name)) { + itemPayloads.push(...this.buildEbbSkillItems(species.name)); + itemPayloads.push(...this.buildEbbItems(species.name)); + } + + const uniquePayloads = uniqueEmbeddedItems(itemPayloads); + const packageLoadout = getPackageLoadout(trainingPackage?.name ?? "", data.equipment.packageLoadouts ?? {}); + const packageIssueKit = getPackageIssueKit(trainingPackage?.name ?? ""); + + const description = buildBiography({ + species, + trainingPackage, + rolls, + derived, + loadout: packageLoadout, + issueKit: packageIssueKit + }); + + const updates = { + name, + img: actorDoc.img || this.resolveSpeciesImage(species.name), + folder: actorDoc.folder?.id ?? (await ensureActorFolder()).id, + "system.class.value": trainingPackage?.name ?? operativeType, + "system.rank.value": species.name, + "system.credits.value": Number(data.packages.startingCredits ?? 1500), + "system.health.max": derived.health, + "system.health.value": derived.health, + "system.hits.max": SPECIES_MIN_WOUNDS[species.name] ?? 2, + "system.hits.value": 0, + "system.stats.strength.value": derived.strength, + "system.stats.speed.value": derived.speed, + "system.stats.intellect.value": derived.intellect, + "system.stats.combat.value": derived.combat, + "system.stats.sanity.value": derived.sanity, + "system.stats.fear.value": derived.fear, + "system.stats.body.value": derived.body, + "system.other.stress.min": 2, + "system.other.stress.value": 2, + "system.other.stress.max": 20, + "system.other.stress.label": "Stress", + "system.sla.species.value": species.name, + "system.sla.speciesNotes.value": buildSpeciesNotes(species).join("\n"), + "system.sla.trainingPackage.value": trainingPackage?.name ?? "", + "system.sla.packageSummary.value": buildPackageSummary(trainingPackage, packageLoadout, packageIssueKit), + "system.sla.packageSkills.value": (trainingPackage?.skills ?? []).join(", "), + "system.sla.packageWealth.value": String(trainingPackage?.wealth ?? ""), + "system.sla.flux.value": this.isEbbSpecies(species.name) ? derived.fluxMax : 0, + "system.sla.flux.min": 0, + "system.sla.flux.max": this.isEbbSpecies(species.name) ? derived.fluxMax : 0, + "system.sla.flux.label": "Flux", + "system.sla.fluxStage.value": getFluxStage(this.isEbbSpecies(species.name) ? derived.fluxMax : 0, this.isEbbSpecies(species.name) ? derived.fluxMax : 0).label, + "system.sla.operativeType.value": operativeType || trainingPackage?.name || "Contract Operative", + "system.sla.bpn.value": bpn || this.randomBpn(), + "system.sla.scl.value": Number(species.startingScl ?? 10), + "system.sla.employer.value": employer, + "system.sla.sector.value": sector, + "system.sla.ebbRating.value": derived.ebbRating, + "system.other.stressdesc.value": buildTraumaResponseText(species, trainingPackage), + "system.sla.fluxNotes.value": this.isEbbSpecies(species.name) + ? `Starting Flux reserve: ${derived.fluxMax}. Ebb users begin with at least 20 Flux and spend from that reserve when channeling. Fear is used as the control save.` + : "", + "system.sla.ebbNotes.value": this.isEbbSpecies(species.name) + ? `Starter discipline package: ${(EBB_STARTERS[species.name] ?? []).join(", ")}` + : "", + "system.biography": description, + "system.notes": buildNotes(species, trainingPackage, packageLoadout, packageIssueKit) + }; + + await actorDoc.update(updates); + + if (uniquePayloads.length) { + await actorDoc.createEmbeddedDocuments("Item", uniquePayloads); + } + + if (openSheet) { + actorDoc.sheet?.render(true); + } + + ui.notifications.info( + `SLA operative ready: ${actorDoc.name} (${species.name}${trainingPackage ? ` / ${trainingPackage.name}` : ""})` + ); + + return { + actor: actorDoc, + species: species.name, + trainingPackage: trainingPackage?.name ?? "", + rolls, + derived + }; + } + + static buildSkillItems(packageSkills, species, allSkillData) { + const skillDocs = packageSkills + .map((name, index) => { + const worldItem = findWorldItem(name, "skill"); + if (!worldItem) return null; + + const embedded = toEmbeddedData(worldItem); + const base = Number(worldItem.system?.bonus ?? 0) || 0; + const packageBonus = index < 3 ? 15 : 10; + embedded.system.bonus = Math.max(base, packageBonus); + embedded.system.rank = rankFromBonus(embedded.system.bonus); + embedded.system.sla ??= {}; + embedded.system.sla.baseBonus = base; + embedded.system.sla.packageBonus = Math.max(0, Number(embedded.system.bonus ?? 0) - base); + const skillImg = getSkillImageOverride(embedded.name); + if (skillImg) embedded.img = skillImg; + return embedded; + }) + .filter(Boolean); + + const byName = new Map(skillDocs.map((item) => [normalizeText(item.name), item])); + const speciesBonuses = [...(species.skillBonuses ?? [])]; + + if (species.name === "Human" && !speciesBonuses.length) { + const humanChoices = chooseHumanBonuses(packageSkills, allSkillData); + for (const skillRef of humanChoices) { + speciesBonuses.push({ skillRef, bonus: 10 }); + } + } + + for (const bonus of speciesBonuses) { + const key = normalizeText(bonus.skillRef); + let embedded = byName.get(key); + if (!embedded) { + const worldItem = findWorldItem(bonus.skillRef, "skill"); + if (!worldItem) continue; + embedded = toEmbeddedData(worldItem); + embedded.system.bonus = Math.max(0, Number(worldItem.system?.bonus ?? 0) || 0); + embedded.system.rank = rankFromBonus(embedded.system.bonus); + embedded.system.sla ??= {}; + embedded.system.sla.baseBonus = Number(worldItem.system?.bonus ?? 0) || 0; + embedded.system.sla.packageBonus = Math.max(0, Number(embedded.system.bonus ?? 0) - Number(embedded.system.sla.baseBonus ?? 0)); + const skillImg = getSkillImageOverride(embedded.name); + if (skillImg) embedded.img = skillImg; + skillDocs.push(embedded); + byName.set(key, embedded); + } + embedded.system.bonus = Math.max(0, Number(embedded.system.bonus ?? 0) + Number(bonus.bonus ?? 0)); + embedded.system.rank = rankFromBonus(embedded.system.bonus); + embedded.system.sla ??= {}; + embedded.system.sla.speciesBonus = Number(embedded.system.sla.speciesBonus ?? 0) + Number(bonus.bonus ?? 0); + } + + return skillDocs; + } + + static buildLoadoutItems(packageName, packageLoadouts) { + const loadout = packageLoadouts?.[packageName]; + if (!loadout) return []; + + const items = []; + for (const name of loadout.weapons ?? []) { + const doc = findWorldItem(name, "weapon"); + if (doc) items.push(toEmbeddedData(doc)); + } + for (const name of loadout.armour ?? []) { + const doc = findWorldItem(name, "armor"); + if (doc) items.push(toEmbeddedData(doc)); + } + return items; + } + + static buildGearItems(packageName) { + const names = [ + ...BASE_ISSUE_GEAR, + ...(PACKAGE_GEAR[packageName] ?? []), + ...(PACKAGE_FIELD_KITS[packageName] ?? []) + ]; + return uniqueBy(names, (entry) => normalizeText(entry)) + .map((name) => findWorldItem(name, "item")) + .filter(Boolean) + .map((item) => toEmbeddedData(item)); + } + + static buildEbbItems(speciesName) { + const abilityNames = EBB_STARTERS[speciesName] ?? []; + return abilityNames + .map((name) => findWorldItem(name, "ability")) + .filter(Boolean) + .map((item) => toEmbeddedData(item)); + } + + static buildEbbSkillItems(speciesName) { + const skillNames = [...EBB_CORE_SKILLS]; + const starterAbilities = EBB_STARTERS[speciesName] ?? []; + for (const abilityName of starterAbilities) { + skillNames.push(`Ebb ${abilityName}`); + } + + return uniqueBy(skillNames, (entry) => normalizeText(entry)) + .map((name) => findWorldItem(name, "skill")) + .filter(Boolean) + .map((item) => { + const embedded = toEmbeddedData(item); + embedded.system.bonus = Math.max(Number(embedded.system?.bonus ?? 0), 10); + embedded.system.rank = rankFromBonus(embedded.system.bonus); + const skillImg = getSkillImageOverride(embedded.name); + if (skillImg) embedded.img = skillImg; + return embedded; + }); + } + + static buildSpeciesItems(speciesName) { + return (SPECIES_WEAPONS[speciesName] ?? []) + .map((name) => findWorldItem(name, "weapon")) + .filter(Boolean) + .map((item) => toEmbeddedData(item)); + } + + static isEbbSpecies(speciesName) { + return ["Ebon", "Brain Waster"].includes(String(speciesName ?? "")); + } + + static buildGeneratorBriefing(data, speciesName, packageName) { + const species = data.species.species.find((entry) => entry.name === speciesName) ?? data.species.species[0] ?? { name: "Human", notes: [] }; + const trainingPackage = data.packages.packages.find((entry) => entry.name === packageName) + ?? data.packages.packages.find((entry) => entry.name === species.starterPackage) + ?? data.packages.packages[0] + ?? null; + const starterAbilities = EBB_STARTERS[species.name] ?? []; + const issueKit = getPackageIssueKit(trainingPackage?.name ?? ""); + const loadout = getPackageLoadout(trainingPackage?.name ?? "", data.equipment.packageLoadouts ?? {}); + const speciesNotes = buildSpeciesNotes(species); + const dossier = getSpeciesDossier(species); + + return { + speciesTitle: species.name, + speciesCopy: species.starterPackage + ? `${dossier.identity} Starter package: ${species.starterPackage}.` + : "No default starter package is assigned.", + speciesNotes, + packageTitle: trainingPackage?.name ?? "No Package", + packageCopy: trainingPackage + ? `${buildPackageSummary(trainingPackage, loadout, issueKit)}` + : "Choose a package to see loadout and focus notes.", + packageSkills: trainingPackage?.skills?.length ? trainingPackage.skills.slice(0, 8) : ["No package skills listed yet."], + isEbbSpecies: this.isEbbSpecies(species.name), + fluxCopy: this.isEbbSpecies(species.name) + ? `This operative will receive a Flux track, Fear-based control saves, and starter Ebb abilities: ${starterAbilities.join(", ")}.` + : "This operative uses standard Stress rules only. Flux and the Ebb tab stay hidden unless the species is Ebon or Brain Waster." + }; + } + + static resolveSpeciesImage(speciesName) { + return findWorldItem(speciesName, "item")?.img ?? "icons/svg/mystery-man.svg"; + } + + static randomName() { + const first = randomFrom(NAME_PARTS.first) ?? "Sable"; + const last = randomFrom(NAME_PARTS.last) ?? "Morrow"; + const callsign = randomFrom(NAME_PARTS.callsign) ?? "Static"; + return `${first} ${last} "${callsign}"`; + } + + static randomBpn() { + return `${randomFrom(NAME_PARTS.bpn) ?? "Blue"} BPN`; + } + + static async ensureSeedData() { + const hasSkills = game.items.some((item) => item.flags?.[SYSTEM_ID]?.slaSeed?.kind === "skill"); + if (hasSkills) return; + if (!game.slaMothershipCompendium?.seedWorld) { + throw new Error("SLA Mothership Companion is required to seed world content."); + } + await game.slaMothershipCompendium.seedWorld({ overwrite: false, notify: true }); + } + + static async loadSeedData() { + if (cachedSeedData) return cachedSeedData; + + const readJson = async (name) => { + const response = await fetch(`modules/${COMPANION_MODULE_ID}/sla-data/${name}`); + if (!response.ok) throw new Error(`Failed loading ${name}`); + return response.json(); + }; + + cachedSeedData = { + species: await readJson("species.json"), + packages: await readJson("training-packages.json"), + equipment: await readJson("equipment.json"), + skills: await readJson("skills.json") + }; + + return cachedSeedData; + } +} + +async function ensureActorFolder() { + let root = game.folders.find((folder) => folder.type === "Actor" && folder.name === ROOT_ACTOR_FOLDER && !folder.folder); + if (!root) { + root = await Folder.create({ name: ROOT_ACTOR_FOLDER, type: "Actor", color: "#163447" }); + } + + let folder = game.folders.find((entry) => entry.type === "Actor" && entry.name === OPERATIVE_FOLDER && entry.folder?.id === root.id); + if (!folder) { + folder = await Folder.create({ name: OPERATIVE_FOLDER, type: "Actor", folder: root.id, color: "#49708a" }); + } + return folder; +} + +async function rollMothershipProfile(species) { + const out = {}; + const profile = getSpeciesMothershipProfile(species); + const formulas = { + ...(profile.rolls ?? {}), + ...(species?.mothershipStats ?? {}) + }; + for (const [key, formula] of Object.entries(formulas ?? {})) { + out[key] = await rollFormula(String(formula ?? "").trim()); + } + return out; +} + +async function rollFormula(formula) { + if (!formula) return 0; + const normalized = formula.toLowerCase().replace(/\s+/g, ""); + const roll = await new Roll(normalized).evaluate(); + return Number(roll.total ?? 0) || 0; +} + +function deriveProfile(rolls, packageName, speciesName) { + const mods = PACKAGE_STAT_BONUSES[packageName] ?? {}; + const strength = Number(rolls.strength ?? 35); + const speed = Number(rolls.speed ?? 35); + const intellect = Number(rolls.intellect ?? 35); + const combat = Number(rolls.combat ?? 35); + const sanity = Number(rolls.sanity ?? 20); + const fear = Number(rolls.fear ?? 20); + const body = Number(rolls.body ?? 20); + const health = Number(rolls.health ?? 10); + + const profile = { + strength: clamp(Math.round(strength + Number(mods.strength ?? 0)), 15, 85), + speed: clamp(Math.round(speed + Number(mods.speed ?? 0)), 15, 85), + intellect: clamp(Math.round(intellect + Number(mods.intellect ?? 0)), 15, 90), + combat: clamp(Math.round(combat + Number(mods.combat ?? 0)), 15, 90), + sanity: clamp(Math.round(sanity + Number(mods.sanity ?? 0)), 10, 90), + fear: clamp(Math.round(fear + Number(mods.fear ?? 0)), 10, 90), + body: clamp(Math.round(body + Number(mods.body ?? 0)), 10, 90), + health: clamp(Math.round(health + Number(mods.health ?? 0)), 5, 30), + ebbRating: 0, + fluxMax: 0 + }; + + if (["Ebon", "Brain Waster"].includes(speciesName)) { + profile.ebbRating = clamp(Math.ceil(profile.intellect / 20) + Number(mods.ebbRating ?? 0), 1, 8); + profile.fluxMax = clamp(Math.max(20, Math.floor(profile.intellect / 4)), 20, 40); + } + + return profile; +} + +function chooseHumanBonuses(packageSkills, allSkillData) { + const pool = packageSkills.length + ? [...packageSkills] + : (allSkillData ?? []).map((entry) => entry.name); + return shuffle(pool).slice(0, 3); +} + +function buildBiography({ species, trainingPackage, rolls, derived, loadout = null, issueKit = [] }) { + const profileRows = [ + ["STR", rolls.strength], + ["SPD", rolls.speed], + ["INT", rolls.intellect], + ["COM", rolls.combat], + ["SAN", rolls.sanity], + ["FEAR", rolls.fear], + ["BODY", rolls.body], + ["HEALTH", rolls.health] + ] + .map(([key, value]) => `${key} ${value}`) + .join(", "); + const notes = buildSpeciesNotes(species).map((entry) => `
  • ${entry}
  • `).join(""); + const doctrine = getPackageDoctrine(trainingPackage?.name ?? ""); + const loadoutLines = describeLoadout(loadout); + const issueKitLine = issueKit.length ? `

    Issue Kit: ${issueKit.join(", ")}

    ` : ""; + const doctrineLine = doctrine.tone ? `

    Package Doctrine: ${doctrine.tone}

    ` : ""; + + return ` +

    Species: ${species.name}

    +

    Training Package: ${trainingPackage?.name ?? "Unassigned"}

    + ${doctrineLine} + ${loadoutLines ? `

    Loadout: ${loadoutLines}

    ` : ""} + ${issueKitLine} +

    Mothership Profile Rolls: ${profileRows}

    +

    Final Profile: STR ${derived.strength}, SPD ${derived.speed}, INT ${derived.intellect}, COM ${derived.combat}, SAN ${derived.sanity}, FEAR ${derived.fear}, BODY ${derived.body}, HEALTH ${derived.health}

    + ${notes ? `

    Species Notes

      ${notes}
    ` : ""} + `; +} + +function buildNotes(species, trainingPackage, loadout = null, issueKit = []) { + const dossier = getSpeciesDossier(species); + const doctrine = getPackageDoctrine(trainingPackage?.name ?? ""); + const lines = [ + `Species starter package: ${species.starterPackage ?? "n/a"}`, + `Assigned package: ${trainingPackage?.name ?? "n/a"}`, + dossier.identity ? `Species profile: ${dossier.identity}` : null, + dossier.fieldPressure ? `Species pressure: ${dossier.fieldPressure}` : null, + doctrine.tone ? `Package doctrine: ${doctrine.tone}` : null, + doctrine.fieldPressure ? `Package pressure: ${doctrine.fieldPressure}` : null, + describeLoadout(loadout) ? `Loadout: ${describeLoadout(loadout)}` : null, + issueKit.length ? `Issue kit: ${issueKit.join(", ")}` : null + ]; + return lines.filter(Boolean).join("\n"); +} + +function buildPackageSummary(trainingPackage, loadout = null, issueKit = []) { + if (!trainingPackage) return ""; + const doctrine = getPackageDoctrine(trainingPackage.name); + const focus = (trainingPackage.skills ?? []).slice(0, 4).join(", "); + const loadoutText = describeLoadout(loadout); + const issueText = issueKit.length ? `Issue kit: ${issueKit.slice(0, 3).join(", ")}.` : ""; + return `${trainingPackage.wealth ?? "Standard"} access. ${doctrine.role ? `${doctrine.role}. ` : ""}${doctrine.tone ? `${doctrine.tone} ` : ""}Focus: ${focus}.${loadoutText ? ` Loadout: ${loadoutText}.` : ""} ${issueText}`.trim(); +} + +function getFluxStage(flux, maxFlux = 0) { + const value = Math.max(0, Number(flux ?? 0) || 0); + const max = Math.max(0, Number(maxFlux ?? 0)); + const ratio = max > 0 ? Math.max(0, max - value) / max : 0; + if (max > 0 && ratio > 1) return { label: "Catastrophic", text: "Flux has overrun the user. Panic fallout is imminent." }; + if (max > 0 && ratio >= 0.75) return { label: "Breach", text: "Most of the Flux reserve has been burned. Offensive Ebb is likely to trigger panic fallout." }; + if (max > 0 && ratio >= 0.5) return { label: "Frayed", text: "The reserve is running down. Failed Fear saves on Ebb use should be treated as panic events." }; + if (max > 0 && ratio >= 0.25) return { label: "Charged", text: "A meaningful chunk of Flux has been spent. Stay cautious and keep the Fear save clean." }; + return { label: "Stable", text: "Flux reserves are healthy. Ebb use remains disciplined and contained." }; +} + +function buildTraumaResponseText(species, trainingPackage) { + return buildSlaTraumaResponseText(species?.name ?? "", trainingPackage?.name ?? ""); +} + +function getSpeciesDossier(species) { + if (species && typeof species === "object") { + const fallback = SPECIES_DOSSIER[species.name] ?? { identity: "", fieldPressure: "" }; + return { + identity: species.identity ?? fallback.identity ?? "", + fieldPressure: species.fieldPressure ?? fallback.fieldPressure ?? "" + }; + } + return SPECIES_DOSSIER[species] ?? { identity: "", fieldPressure: "" }; +} + +function getSpeciesMothershipProfile(species) { + if (species && typeof species === "object") { + const fallback = SPECIES_MOTHERSHIP_PROFILES[species.name] ?? SPECIES_MOTHERSHIP_PROFILES.Human; + return { + rolls: { + ...(fallback.rolls ?? {}), + ...(species.mothershipStats ?? {}) + }, + description: species.mothershipDescription ?? fallback.description ?? "" + }; + } + return SPECIES_MOTHERSHIP_PROFILES[species] ?? SPECIES_MOTHERSHIP_PROFILES.Human; +} + +function buildSpeciesNotes(species) { + const dossier = getSpeciesDossier(species); + const profile = getSpeciesMothershipProfile(species); + return uniqueBy( + [ + dossier.identity, + dossier.fieldPressure, + profile.description, + ...((species?.specialRules ?? []).map((rule) => `Special Rule - ${rule.label}: ${rule.summary}`)), + ...(species?.notes ?? []) + ].filter(Boolean), + (entry) => normalizeText(entry) + ); +} + +function getPackageDoctrine(packageName) { + return PACKAGE_DOCTRINE[packageName] ?? { role: "", tone: "", fieldPressure: "" }; +} + +function getPackageIssueKit(packageName) { + return PACKAGE_FIELD_KITS[packageName] ?? []; +} + +function getPackageLoadout(packageName, packageLoadouts = {}) { + if (!packageName) return null; + const direct = packageLoadouts?.[packageName]; + if (direct) return direct; + + const key = normalizeText(packageName); + const matchedKey = Object.keys(packageLoadouts ?? {}).find((entry) => normalizeText(entry).includes(key) || key.includes(normalizeText(entry))); + return matchedKey ? packageLoadouts[matchedKey] : null; +} + +function describeLoadout(loadout) { + if (!loadout) return ""; + const parts = []; + if ((loadout.weapons ?? []).length) { + parts.push(`Weapons: ${(loadout.weapons ?? []).join(", ")}`); + } + if ((loadout.armour ?? []).length) { + parts.push(`Armour: ${(loadout.armour ?? []).join(", ")}`); + } + return parts.join(" | "); +} + +function toEmbeddedData(document) { + const data = document.toObject(); + delete data._id; + delete data.folder; + delete data.sort; + delete data.pack; + delete data.ownership; + return data; +} + +function getSkillImageOverride(name = "") { + return SKILL_IMAGE_OVERRIDES[normalizeText(name).replace(/\s+/g, "")] ?? null; +} + +function findWorldItem(name, type = null) { + const key = normalizeText(name); + return game.items.find((item) => normalizeText(item.name) === key && (!type || item.type === type)) ?? null; +} + +function rankFromBonus(bonus) { + if (bonus >= 20) return "Master"; + if (bonus >= 15) return "Expert"; + if (bonus >= 10) return "Trained"; + if (bonus > 0) return "Basic"; + return "Untrained"; +} + +function normalizeText(value) { + return String(value ?? "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, " ") + .trim(); +} + +function clamp(value, min, max) { + return Math.max(min, Math.min(max, Number(value ?? 0))); +} + +function randomFrom(values) { + if (!values?.length) return null; + return values[Math.floor(Math.random() * values.length)]; +} + +function shuffle(values) { + const out = [...values]; + for (let index = out.length - 1; index > 0; index -= 1) { + const swap = Math.floor(Math.random() * (index + 1)); + [out[index], out[swap]] = [out[swap], out[index]]; + } + return out; +} + +function uniqueBy(values, keyFn) { + const seen = new Set(); + const out = []; + for (const value of values) { + const key = keyFn(value); + if (seen.has(key)) continue; + seen.add(key); + out.push(value); + } + return out; +} + +function uniqueEmbeddedItems(items) { + const seen = new Set(); + const out = []; + for (const item of items) { + const key = `${item.type}:${normalizeText(item.name)}`; + if (seen.has(key)) continue; + seen.add(key); + out.push(item); + } + return out; +} diff --git a/module/windows/sla-world-tools.js b/module/windows/sla-world-tools.js new file mode 100644 index 0000000..5dd9c3d --- /dev/null +++ b/module/windows/sla-world-tools.js @@ -0,0 +1,147 @@ +import { SLAMothershipGenerator } from "./sla-character-generator.js"; + +const SYSTEM_ID = "sla-mothership"; + +export class SLAWorldToolsApp extends FormApplication { + static get defaultOptions() { + return foundry.utils.mergeObject(super.defaultOptions, { + id: "sla-mothership-world-tools", + classes: ["mosh", "sheet", "sla-world-tools"], + template: "systems/sla-mothership/templates/dialogs/sla-world-tools.html", + width: 560, + height: "auto", + submitOnChange: false, + closeOnSubmit: false + }); + } + + get title() { + return "SLA Mothership Tools"; + } + + async getData() { + const seededItems = game.items.filter((item) => item.flags?.[SYSTEM_ID]?.slaSeed?.key); + const actors = game.actors.filter((actor) => actor.type === "character"); + const ebbActors = actors.filter((actor) => ["Ebon", "Brain Waster"].includes(String(actor.system?.sla?.species?.value ?? "").trim())); + + return { + seededItems: seededItems.length, + skillCount: seededItems.filter((item) => item.type === "skill").length, + weaponCount: seededItems.filter((item) => item.type === "weapon").length, + gearCount: seededItems.filter((item) => item.flags?.[SYSTEM_ID]?.slaSeed?.kind === "gear").length, + actorCount: actors.length, + starterCount: actors.filter((actor) => actor.flags?.[SYSTEM_ID]?.slaStarter).length, + ebbActorCount: ebbActors.length, + quickBattleMapBuilderReady: Boolean(game.modules?.get("quick-battlemap-builder")?.active && game.quickBattleMapBuilder?.open) + }; + } + + activateListeners(html) { + super.activateListeners(html); + + html.find(".seed-world").on("click", async () => { + await game.slaMothership.seedWorldContent({ overwrite: false, notify: true }); + this.render(false); + }); + + html.find(".refresh-world").on("click", async () => { + await game.slaMothership.seedWorldContent({ overwrite: true, notify: true }); + this.render(false); + }); + + html.find(".open-generator").on("click", () => { + game.slaMothership.openGenerator(); + }); + + html.find(".generate-random").on("click", async () => { + await game.slaMothership.createRandomOperative({ openSheet: true }); + this.render(false); + }); + + html.find(".generate-random-ebb").on("click", async () => { + await SLAMothershipGenerator.createRandomEbbOperative({ openSheet: true }); + this.render(false); + }); + + html.find(".generate-random-standard").on("click", async () => { + await SLAMothershipGenerator.createRandomNonEbbOperative({ openSheet: true }); + this.render(false); + }); + + html.find(".starter-squad").on("click", async () => { + await game.slaMothership.createStarterSquad({ overwrite: false, notify: true }); + this.render(false); + }); + + html.find(".open-battlemap-builder").on("click", () => { + game.quickBattleMapBuilder?.open?.(); + }); + } + + async _updateObject() {} + + static open() { + return new SLAWorldToolsApp().render({ force: true }); + } +} + +export function installSlaSidebarButtons(app, html) { + const canManage = Boolean(game.user?.isGM); + if (!canManage) return; + + const root = $(html); + if (root.find(".sla-create-random-operative").length) return; + + const toolContainer = findToolContainer(root); + if (!toolContainer?.length) return; + + const toolsButton = $(` + + `); + toolsButton.on("click", () => SLAWorldToolsApp.open()); + + const createButton = $(` + + `); + createButton.on("click", () => SLAMothershipGenerator.open()); + + const randomButton = $(` + + `); + randomButton.on("click", async () => { + await SLAMothershipGenerator.createRandomOperative({ openSheet: true }); + }); + + const refreshButton = $(` + + `); + refreshButton.on("click", async () => { + await game.slaMothership.seedWorldContent({ overwrite: true, notify: true }); + }); + + toolContainer.append(randomButton, createButton, toolsButton, refreshButton); +} + +function findToolContainer(root) { + const header = root.find(".directory-header, header").first(); + if (!header.length) return null; + const existing = header.find(".sla-sidebar-actions"); + if (existing.length) return existing.first(); + + const actionRow = header.find(".header-actions, .action-buttons").first(); + const toolRow = $('
    '); + if (actionRow.length) { + actionRow.after(toolRow); + } else { + header.prepend(toolRow); + } + return toolRow; +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0a04003 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,3985 @@ +{ + "name": "sla-mothership", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@gulp-sourcemaps/identity-map": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz", + "integrity": "sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ==", + "requires": { + "acorn": "^5.0.3", + "css": "^2.2.1", + "normalize-path": "^2.1.1", + "source-map": "^0.6.0", + "through2": "^2.0.3" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "@gulp-sourcemaps/map-sources": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz", + "integrity": "sha1-iQrnxdjId/bThIYCFazp1+yUW9o=", + "requires": { + "normalize-path": "^2.0.1", + "through2": "^2.0.3" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "acorn": { + "version": "5.7.4", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", + "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=" + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "requires": { + "buffer-equal": "^1.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=" + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" + }, + "arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" + }, + "arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=" + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" + }, + "array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "requires": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + } + } + }, + "array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==" + } + } + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==" + }, + "array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "requires": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" + }, + "async-done": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", + "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^2.0.0", + "stream-exhaust": "^1.0.1" + } + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==" + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=" + }, + "async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "requires": { + "async-done": "^1.2.2" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==" + }, + "autoprefixer": { + "version": "9.8.6", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.6.tgz", + "integrity": "sha512-XrvP4VVHdRBCdX1S3WXVD8+RyG9qeb1D5Sn1DeLiG2xfSpzellk5k54xbUERJ3M5DggQxes39UGOTP8CFrEGbg==", + "requires": { + "browserslist": "^4.12.0", + "caniuse-lite": "^1.0.30001109", + "colorette": "^1.2.1", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.32", + "postcss-value-parser": "^4.1.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==" + }, + "bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "requires": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==" + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "requires": { + "inherits": "~2.0.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browserslist": { + "version": "4.14.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.14.7.tgz", + "integrity": "sha512-BSVRLCeG3Xt/j/1cCGj1019Wbty0H+Yvu2AOuZSuoaUWn3RatbL33Cxk+Q4jRMRAbOm0p7SLravLjpnT6s0vzQ==", + "requires": { + "caniuse-lite": "^1.0.30001157", + "colorette": "^1.2.1", + "electron-to-chromium": "^1.3.591", + "escalade": "^3.1.1", + "node-releases": "^1.1.66" + } + }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=" + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.0.tgz", + "integrity": "sha512-AEXsYIyyDY3MCzbwdhzG3Jx1R0J2wetQyUynn6dYHAO+bg8l1k7jwZtRv4ryryFs7EP+NDlikJlVe59jr0cM2w==", + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.0" + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" + } + } + }, + "caniuse-lite": { + "version": "1.0.30001157", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001157.tgz", + "integrity": "sha512-gOerH9Wz2IRZ2ZPdMfBvyOi3cjaz4O4dgNwPGzx8EhqAs4+2IL/O+fJsbt+znSigujoZG8bVcIAUM/I/E5K3MA==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", + "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=" + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=" + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=" + }, + "cloneable-readable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", + "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "requires": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==" + }, + "colorette": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.1.tgz", + "integrity": "sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw==" + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" + }, + "copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "requires": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "css": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/css/-/css-2.2.4.tgz", + "integrity": "sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw==", + "requires": { + "inherits": "^2.0.3", + "source-map": "^0.6.1", + "source-map-resolve": "^0.5.2", + "urix": "^0.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "requires": { + "array-find-index": "^1.0.1" + } + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "debug-fabulous": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/debug-fabulous/-/debug-fabulous-1.1.0.tgz", + "integrity": "sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg==", + "requires": { + "debug": "3.X", + "memoizee": "0.4.X", + "object-assign": "4.X" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=" + }, + "default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "requires": { + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=" + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=" + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=" + }, + "duplexify": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", + "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "requires": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "electron-to-chromium": { + "version": "1.3.595", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.595.tgz", + "integrity": "sha512-JpaBIhdBkF9FLG7x06ONfe0f5bxPrxRcq0X+Sc8vsCt+OPWIzxOD+qM71NEHLGbDfN9Q6hbtHRv4/dnvcOxo6g==" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", + "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=" + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "optional": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==" + }, + "flush-write-stream": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", + "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", + "requires": { + "inherits": "^2.0.3", + "readable-stream": "^2.3.6" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "requires": { + "map-cache": "^0.2.2" + } + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "requires": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" + }, + "get-intrinsic": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.1.tgz", + "integrity": "sha512-ZnWP+AmS1VUaLgTRy47+zKtjTxz+0xMpx3I52i+aalBK1QP19ggLF3Db89KJX7kjfOfP2eoa01qc++GwPgufPg==", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "glob-watcher": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", + "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "requires": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "normalize-path": "^3.0.0", + "object.defaults": "^1.1.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globule": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", + "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.10", + "minimatch": "~3.0.2" + } + }, + "glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "requires": { + "sparkles": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "requires": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "dependencies": { + "gulp-cli": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", + "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "requires": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.4.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.2.0", + "yargs": "^7.1.0" + } + } + } + }, + "gulp-autoprefixer": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/gulp-autoprefixer/-/gulp-autoprefixer-7.0.1.tgz", + "integrity": "sha512-QJGEmHw+bEt7FSqvmbAUTxbCuNLJYx4sz3ox9WouYqT/7j5FH5CQ8ZnpL1M7H5npX1bUJa7lUVY1w20jXxhOxg==", + "requires": { + "autoprefixer": "^9.6.1", + "fancy-log": "^1.3.2", + "plugin-error": "^1.0.1", + "postcss": "^7.0.17", + "through2": "^3.0.1", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "dependencies": { + "through2": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", + "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "2 || 3" + } + } + } + }, + "gulp-sass": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-4.1.0.tgz", + "integrity": "sha512-xIiwp9nkBLcJDpmYHbEHdoWZv+j+WtYaKD6Zil/67F3nrAaZtWYN5mDwerdo7EvcdBenSAj7Xb2hx2DqURLGdA==", + "requires": { + "chalk": "^2.3.0", + "lodash": "^4.17.11", + "node-sass": "^4.8.3", + "plugin-error": "^1.0.1", + "replace-ext": "^1.0.0", + "strip-ansi": "^4.0.0", + "through2": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "gulp-sourcemaps": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz", + "integrity": "sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg==", + "requires": { + "@gulp-sourcemaps/identity-map": "1.X", + "@gulp-sourcemaps/map-sources": "1.X", + "acorn": "5.X", + "convert-source-map": "1.X", + "css": "2.X", + "debug-fabulous": "1.X", + "detect-newline": "2.X", + "graceful-fs": "4.X", + "source-map": "~0.6.0", + "strip-bom-string": "1.X", + "through2": "2.X" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "requires": { + "glogg": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==" + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "in-publish": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.1.tgz", + "integrity": "sha512-oDM0kUSNFC31ShNxHKUyfZKy8ZeXZBWMjMdZHKLOk13uvT27VTL/QzRGfRUcevJhpkZAvlhPYuXkF7eNWrtyxQ==" + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "requires": { + "repeating": "^2.0.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-core-module": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.1.0.tgz", + "integrity": "sha512-YcV7BgVMRFRua2FqQzKtTDMz8iCuLEyGKjr70q8Zm1yy2qKcurbFEd79PAdHV77oL3NrAaOVQIbMmiHQCHB7ZA==", + "requires": { + "has": "^1.0.3" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=" + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" + }, + "is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=" + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "requires": { + "readable-stream": "^2.0.5" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "requires": { + "flush-write-stream": "^1.0.2" + } + }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "lodash": { + "version": "4.17.20", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", + "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "requires": { + "es5-ext": "~0.10.2" + } + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "requires": { + "object-visit": "^1.0.0" + } + }, + "matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "requires": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "dependencies": { + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "memoizee": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "requires": { + "d": "1", + "es5-ext": "^0.10.45", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.5" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==" + }, + "nan": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", + "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=" + } + } + }, + "node-releases": { + "version": "1.1.66", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.66.tgz", + "integrity": "sha512-JHEQ1iWPGK+38VLB2H9ef2otU4l8s3yAMt9Xf934r6+ojCYDMHPMqvCc9TnzfeFSP1QEOeU6YZEd3+De0LTCgg==" + }, + "node-sass": { + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.14.1.tgz", + "integrity": "sha512-sjCuOlvGyCJS40R8BscF5vhVlQjNN069NtQ1gSxyK1u9iqvn6tf7O1R4GNowVZfiZUCRt5MmMs1xd+4V/7Yr0g==", + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "2.2.5", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" + }, + "now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "requires": { + "once": "^1.3.2" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "requires": { + "isobject": "^3.0.1" + } + }, + "object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=" + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" + }, + "postcss": { + "version": "7.0.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.35.tgz", + "integrity": "sha512-3QT8bBJeX/S5zKTTjTCIjRF3If4avAT6kqxcASlTWEtAFCb9NH0OUxNDfgZSWdP5fJnBYCMEWkIFfWeugjzYMg==", + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "postcss-value-parser": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", + "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "requires": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + } + }, + "remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "requires": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "requires": { + "is-finite": "^1.0.0" + } + }, + "replace-ext": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", + "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==" + }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "requires": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "resolve": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "requires": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "requires": { + "value-or-function": "^3.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass-graph": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", + "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^13.3.2" + }, + "dependencies": { + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "requires": { + "locate-path": "^3.0.0" + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "requires": { + "sver-compat": "^1.5.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==" + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==" + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=" + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==" + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-bom-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz", + "integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=" + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "requires": { + "get-stdin": "^4.0.1" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "requires": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=" + }, + "timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "requires": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "requires": { + "through2": "^2.0.3" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "requires": { + "glob": "^7.1.2" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" + }, + "undertaker": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", + "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "fast-levenshtein": "^1.0.0", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=" + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" + } + } + }, + "upath": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", + "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==" + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vinyl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", + "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + }, + "vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "requires": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + } + }, + "vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "requires": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "requires": { + "source-map": "^0.5.1" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.1.tgz", + "integrity": "sha512-huO4Fr1f9PmiJJdll5kwoS2e4GqzGSsMT3PPMpOwoVkOK8ckqAewMTZyA6LXVQWflleb/Z8oPBEvNsMft0XE+g==", + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "5.0.0-security.0" + } + }, + "yargs-parser": { + "version": "5.0.0-security.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0-security.0.tgz", + "integrity": "sha512-T69y4Ps64LNesYxeYGYPvfoMTt/7y1XtfpIslUeK4um+9Hu7hlGoRtaDLvdXb7+/tfq4opVa2HRY5xGip022rQ==", + "requires": { + "camelcase": "^3.0.0", + "object.assign": "^4.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..190ed25 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "sla-mothership", + "version": "1.0.0", + "description": "CSS compiler for the Mothership system", + "scripts": { + "build": "gulp", + "compile": "gulp css", + "watch": "gulp", + "gulp": "gulp" + }, + "browserslist": [ + "last 3 versions" + ], + "author": "Martin Jencka", + "license": "MIT", + "private": true, + "dependencies": { + "gulp": "^4.0.2", + "gulp-autoprefixer": "^7.0.1", + "gulp-sass": "^4.1.0", + "gulp-sourcemaps": "^2.6.5" + } +} diff --git a/packs/conditions_0e.db b/packs/conditions_0e.db new file mode 100644 index 0000000..37da2c4 --- /dev/null +++ b/packs/conditions_0e.db @@ -0,0 +1,36 @@ +{"_id":"2D3zgP8KtRTAqlfS","name":"Addiction","type":"condition","img":"systems/mosh/images/icons/ui/conditions/addicted.png","system":{"description":"

    Excessive use of Pain Pills or Stimpaks requires a Body Save to prevent addiction. Once addicted, make a daily Body Save or gain 1d10 Stress every day you go without. If used once per day for a week you’ll need to take twice the amount of pills to gain the same effect.

    Whenever you take more than one pill at a time roll 1d10. If you roll equal to or under the number taken make a Body Save. Failure means you fall unconscious and the Warden rolls a Death Save. You can cure an addiction through in-game treatment or leveling up.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"QEVnimwq5o0DxmZz","name":"Anhedonia","type":"condition","img":"systems/mosh/images/icons/ui/conditions/exhausted.png","system":{"description":"

    Whenever you would recover Calm, recover half as much Calm instead.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"23qE7TnIHxtw1E9y","name":"Bit Rot","type":"condition","img":"systems/mosh/images/icons/ui/conditions/data_loss.png","system":{"description":"

    Whenever you would recover Calm, recover half as much instead.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZzvKo0yTqOcRP5Xo","name":"Broken","type":"condition","img":"systems/mosh/images/icons/ui/conditions/deflated.png","system":{"description":"

    Make a Panic Check whenever a nearby crew member fails a Save.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Qnv6ZDPsbOXLi9go","name":"Cowardice","type":"condition","img":"systems/mosh/images/icons/ui/conditions/coward.png","system":{"description":"

    You must make a Fear Save to engage in combat or else flee.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"uoeVaOy5a6BIAGAi","name":"Death Drive","type":"condition","img":"systems/mosh/images/icons/ui/conditions/death_wish.png","system":{"description":"

    Whenever you encounter a stranger or known enemy you must make a Sanity Save or else immediately attack them.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"PiMuPeHR5EobSPBP","name":"Deviant Logic Core","type":"condition","img":"systems/mosh/images/icons/ui/conditions/logic_core.png","system":{"description":"

    Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dAJRV7JG0Wh1shcJ","name":"Emotional Detachment","type":"condition","img":"systems/mosh/images/icons/ui/conditions/detached.png","system":{"description":"

    You now lose half the Calm (rounded up) you normally would from all sources but you gain the Panic Effect of an Android, in addition to that of your own class. If you are an Android, gain the Panic Effect of a Marine.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"6vExNGxZiXcC3RFy","name":"Escapism","type":"condition","img":"systems/mosh/images/icons/ui/conditions/addicted.png","system":{"description":"

    You always have Disadvantage on Body Saves to prevent Addiction.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kI2Yxt0Eo2mEywpZ","name":"Ethical Directive Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/moral_compass.png","system":{"description":"

    You now lose half the Calm (rounded up) you normally would from all sources but you now have the Panic Effect of a Marine, in addition to that of an Android.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5E3FGlNzi05S792f","name":"Ethical Directive Misread","type":"condition","img":"systems/mosh/images/icons/ui/conditions/moral_compass.png","system":{"description":"

    Loses any expressiveness. Discusses the irrationality of Phobias, seeks to trigger them in others.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8D9ZtBYScCKjcBH3","name":"Faulty Heuristics","type":"condition","img":"systems/mosh/images/icons/ui/conditions/faulty_heuristics.png","system":{"description":"

    Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"B8vRorrFy3c2cOf5","name":"Fried Logic Core","type":"condition","img":"systems/mosh/images/icons/ui/conditions/logic_core.png","system":{"description":"

    Frenzied nonsensical behaviour. Whenever you lose Calm, everyone else nearby loses the same amount of Calm.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"RZ5X3UuiM0Wzg3pQ","name":"Hallucinations","type":"condition","img":"systems/mosh/images/icons/ui/conditions/loss_of_confidence.png","system":{"description":"

    You have trouble distinguishing between reality and fantasy.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"A3qRm3Gs36Nbfs29","name":"Hypervigilance","type":"condition","img":"systems/mosh/images/icons/ui/conditions/hypervigilance.png","system":{"description":"

    Gain Advantage on all surprise rolls but lose 1d10 Calm every day.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"9vveNoR1VA9Bx0Wo","name":"Insane","type":"condition","img":"systems/mosh/images/icons/ui/conditions/spiraling.png","system":{"description":"

    You become permanently, irreparably insane. Your character is now played by the Warden.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"hAfwbHxZih4Xb0qi","name":"Killswitch Engaged","type":"condition","img":"systems/mosh/images/icons/ui/conditions/killswitch.png","system":{"description":"

    Go berserk, will not withdraw from combat regardless of situation, will not adhere to tactics.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"1r6ruvSdxn2bHHIk","name":"Losing Your Grip","type":"condition","img":"systems/mosh/images/icons/ui/conditions/distress.png","system":{"description":"

    Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AXxmouWPp6Tx1JbK","name":"Panicky","type":"condition","img":"systems/mosh/images/icons/ui/conditions/distress.png","system":{"description":"

    Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lxIZLdg2IkwOC2b9","name":"Paranoid","type":"condition","img":"systems/mosh/images/icons/ui/conditions/suspicious.png","system":{"description":"

    Whenever a character joins your group (even if they only left for a short period of time), make a Fear Save or gain 1 Stress.<><>@UUID[Compendium.mosh.macros_triggered_0e.Macro.Er4ULzvdn2urxuet]{Fear Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lf1QZaUHSy82w7SR","name":"Phobia","type":"condition","img":"systems/mosh/images/icons/ui/conditions/frightened.png","system":{"description":"

    Gain a new permanent phobia. Whenever you encounter this phobia make a Fear Save at Disadvantage.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.RdJ2nh41wDUT4ZTP]{Fear Save [-]}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Gm2XrTqVMbECVPan","name":"Psychotic Episodes","type":"condition","img":"systems/mosh/images/icons/ui/conditions/confused.png","system":{"description":"

    Once per session, the Warden may take over your character for one round.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"GbDO8pRNdPA5tQXE","name":"Rampancy","type":"condition","img":"systems/mosh/images/icons/ui/conditions/confused.png","system":{"description":"

    Once per session, the Warden may take over your character for one round. These episodes double in duration (or become twice as frequent) each session.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"zbKI2RCl5h3vowoy","name":"Recurring Nightmares","type":"condition","img":"systems/mosh/images/icons/ui/conditions/nightmares.png","system":{"description":"

    Every time you rest, make a Fear save. If you fail, lose 1d10 Calm and do not heal. The Warden will describe your nightmare.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"H4UUQsZOSaYGRPSY","name":"Severe Anxiety","type":"condition","img":"systems/mosh/images/icons/ui/conditions/anxiety.png","system":{"description":"

    Lose double Calm from all sources.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"xVW5zbK05EqQmaA4","name":"Social Anxiety","type":"condition","img":"systems/mosh/images/icons/ui/conditions/anxiety.png","system":{"description":"

    Lose 1d10 Calm whenever you converse with someone new.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"1rUlQJ5iwD29X4oT","name":"Software Bloat","type":"condition","img":"systems/mosh/images/icons/ui/conditions/software_bloat.png","system":{"description":"

    Lose double Calm from all sources.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"XxjONzW7H4tIIAkN","name":"Starving","type":"condition","img":"systems/mosh/images/icons/ui/conditions/starving.png","system":{"description":"

    Humans can survive roughly 3 weeks without food. After 24 hours without food you’re at Disadvantage to all rolls.

    The bare minimum to survive: you’ll need 1 liter of water a day. However, at this level any strenuous activity (like running, Combat, or making mechanical repairs) will force you to make a Body Save or pass out. When water is scarce and you’re tracking it this closely you’re at Disadvantage to all Checks.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"uOPcbqhk5sQHB8A2","name":"Suffocating","type":"condition","img":"systems/mosh/images/icons/ui/conditions/suffocating.png","system":{"description":"

    In space you can last 15 seconds without oxygen before you fall unconscious. After passing out you can survive for 3-5 minutes before dying.

    • If less than half of the original oxygen remains every roll is made at Disadvantage. All crew suffer headaches, fatigue, anxiety and general clumsiness.
    • If less than a quarter of the original oxygen amount remains players must make a Body Save once per day (and after every strenuous activity) or fall unconscious. All crew suffer panting, dizziness, severe headaches and impaired vision and tinnitus.
    • If a player runs out of oxygen they must make a Body Save. Failure means they die. Success means they fall unconscious and leach oxygen from a random player every day.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"JV43ilZwsikj75j1","name":"The Shakes","type":"condition","img":"systems/mosh/images/icons/ui/conditions/the_shakes.png","system":{"description":"

    You can’t keep your hands steady any more. Disadvantage on ranged attacks and all tasks requiring fine motor skills. Drugs may be able to help with this.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"xlKWL5nZm3SJPhrf","name":"Threat Assessment Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/death_wish.png","system":{"description":"

    You lose the ability to discern friend from foe, treating all vaguely-humanoid entities as you would members of your crew.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"iZzcfZ26I2svoonl","name":"Turing Test Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/turing_test_failure.png","system":{"description":"

    Have difficulty expressing humanity. Party members make a Fear Save whenever you show up.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.Er4ULzvdn2urxuet]{Fear Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"qsOHsbKMonl9tiaq","name":"Twitchy","type":"condition","img":"systems/mosh/images/icons/ui/conditions/the_shakes.png","system":{"description":"

    Your manual tasks have Disadvantage.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"x0YRvBbVoHPILD6x","name":"Vocalization Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/vocalization_failure.png","system":{"description":"

    Intermittently shrieks like a fax machine under duress. Lapses into morse code, cannot communicate or sneak.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZIYe2ULX7AKP5MVI","name":"Worship Danger","type":"condition","img":"systems/mosh/images/icons/ui/conditions/worship_danger.png","system":{"description":"

    Becomes Nihilistically Worshipful of the Source of Danger. Everyone else has Disadvantage on rolls against it. Everyone else takes a Fear save when failing to act against danger or gains a Phobia.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.Er4ULzvdn2urxuet]{Fear Save}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.qwmJTfTgmjNEApfX]{+1 Phobia}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8Ypj7tMZqoMYsqVJ","name":"The Bends","type":"condition","img":"systems/mosh/images/icons/ui/conditions/the_bends.png","system":{"description":"

    You doubt the true nature of your identity. If you are human, you have started to believe you may be an android with implanted memories. If you are an android, you have started to believe you are a real person.

    The severity of this condition starts at 5 unless you still have your Trinket from character creation, in which case it starts at 0. The Bends can never be decreased below 5, unless you never lose control of your Trinket. So you should never lose it. Ever.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/conditions_0e/000036.ldb b/packs/conditions_0e/000036.ldb new file mode 100644 index 0000000..2371f6b Binary files /dev/null and b/packs/conditions_0e/000036.ldb differ diff --git a/packs/conditions_0e/000040.log b/packs/conditions_0e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/conditions_0e/CURRENT b/packs/conditions_0e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/conditions_0e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/conditions_0e/LOCK b/packs/conditions_0e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/conditions_0e/LOG b/packs/conditions_0e/LOG new file mode 100644 index 0000000..fcf867b --- /dev/null +++ b/packs/conditions_0e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.583476 17054f000 Recovering log #38 +2026/03/31-15:50:48.583855 17054f000 Delete type=0 #38 +2026/03/31-15:50:48.583882 17054f000 Delete type=3 #37 diff --git a/packs/conditions_0e/LOG.old b/packs/conditions_0e/LOG.old new file mode 100644 index 0000000..4ea925c --- /dev/null +++ b/packs/conditions_0e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.556257 16ffc3000 Recovering log #34 +2026/03/29-21:14:27.556633 16ffc3000 Delete type=3 #32 +2026/03/29-21:14:27.556668 16ffc3000 Delete type=0 #34 diff --git a/packs/conditions_0e/MANIFEST-000039 b/packs/conditions_0e/MANIFEST-000039 new file mode 100644 index 0000000..9e1ccbb Binary files /dev/null and b/packs/conditions_0e/MANIFEST-000039 differ diff --git a/packs/conditions_0e/lost/000020.log b/packs/conditions_0e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/conditions_0e/lost/MANIFEST-000018 b/packs/conditions_0e/lost/MANIFEST-000018 new file mode 100644 index 0000000..304dc94 Binary files /dev/null and b/packs/conditions_0e/lost/MANIFEST-000018 differ diff --git a/packs/conditions_1e.db b/packs/conditions_1e.db new file mode 100644 index 0000000..a96af8d --- /dev/null +++ b/packs/conditions_1e.db @@ -0,0 +1,50 @@ +{"_id":"JM9PnNw2HVWcAfOX","name":"Anhedonia","type":"condition","img":"systems/mosh/images/icons/ui/conditions/exhausted.png","system":{"description":"

    Whenever you would recover Calm, recover half as much Calm instead.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"H1dqOrGg0voG2DmC","name":"Bit Rot","type":"condition","img":"systems/mosh/images/icons/ui/conditions/data_loss.png","system":{"description":"

    Whenever you would recover Calm, recover half as much instead.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"pxtF1NfletmoFFGV","name":"Bleeding","type":"condition","img":"systems/mosh/images/icons/ui/conditions/bleeding.png","system":{"description":"

    Some weapons or Wounds cause you to Bleed. This means you take 1 Damage every round until the bleeding is stopped. This is cumulative. If a character is bleeding 1 Damage per round and gains Bleeding +1, they now take 2 Damage per round. Bleeding damage ignores armor and damage reduction.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.aur5HWqZJNspwdCd]{Take Bleeding Damage}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZXyoVuMAsEDmU5Qi","name":"Broken","type":"condition","img":"systems/mosh/images/icons/ui/conditions/deflated.png","system":{"description":"

    Make a Panic Check whenever a nearby crew member fails a Save.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"acxtiC0oGwQloAwj","name":"Corrosive Atmosphere","type":"condition","img":"systems/mosh/images/icons/ui/conditions/corrosive_atmosphere.png","system":{"description":"

    Planets with Corrosive atmospheres require special gear to explore, otherwise there is the risk of harm or even death.

    The planet’s atmosphere is deadly and destructive. It deals Damage every round while on it. This ranges from 1 DMG / round (Mildly Corrosive) to 10 DMG / round (Highly Corrosive). Anything higher is simply impossible to safely traverse without specialized equipment and armor.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.vwpxRBbMwjfDCQVG]{-1 Health}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.C9iTlPOpROuuYi2F]{-10 Health}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"YIF9QkUlexxauSCE","name":"Coward","type":"condition","img":"systems/mosh/images/icons/ui/conditions/coward.png","system":{"description":"

    You must make a Fear Save to engage in violence, otherwise you flee.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.R2KizR1soAhFYDZm]{Fear Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"j26FZQ2gYuNfMKkc","name":"Cryosickness","type":"condition","img":"systems/mosh/images/icons/ui/conditions/cryosickness.png","system":{"description":"

    To endure long space journeys or hyperspace jumps, crews use cryopods, which are coffinlike capsules that freeze them in a suspended animation called cryosleep. While in cryosleep, vitals are preserved and aging slows down. However, upon awakening, you experience a hangover-like feeling called cryosickness, which causes sluggishness and slow reflexes. While cryosick you suffer [-] on all rolls for 1 week. Upgraded cryochambers can help mitigate these effects, and a stimpak can cure them instantly.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"srws3n4rpl4oCj83","name":"Death Wish","type":"condition","img":"systems/mosh/images/icons/ui/conditions/death_wish.png","system":{"description":"

    For the next 24 hours, whenever you encounter a stranger or known enemy, make a Sanity Save or immediately attack them.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.TkMfT4RIczQb56j2]{Sanity Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"waimTU6LXaADcJrT","name":"Deflated","type":"condition","img":"systems/mosh/images/icons/ui/conditions/deflated.png","system":{"description":"

    Whenever a Close crewmember fails a Save, gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dvJR9DYXI2kV0BbR]{+1 Stress}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"PTK6ds7eJvJDonbp","name":"Deviant Logic Core","type":"condition","img":"systems/mosh/images/icons/ui/conditions/logic_core.png","system":{"description":"

    Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"x41AwiI03h7wNjaM","name":"Doomed","type":"condition","img":"systems/mosh/images/icons/ui/conditions/doomed.png","system":{"description":"

    You feel cursed and unlucky. All Critical Successes are instead Critical Failures.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"iiiAIZvpfUUNai74","name":"Emotional Detachment","type":"condition","img":"systems/mosh/images/icons/ui/conditions/detached.png","system":{"description":"

    You now lose half the Calm (rounded up) you normally would from all sources but you gain the Panic Effect of an Android, in addition to that of your own class. If you are an Android, gain the Panic Effect of a Marine.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"qejBMjd8niz1y3Zi","name":"Escapism","type":"condition","img":"systems/mosh/images/icons/ui/conditions/addicted.png","system":{"description":"

    You always have Disadvantage on Body Saves to prevent Addiction.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"pe7ChrErjX6N57VP","name":"Ethical Directive Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/moral_compass.png","system":{"description":"

    You now lose half the Calm (rounded up) you normally would from all sources but you now have the Panic Effect of a Marine, in addition to that of an Android.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"OBpJQ7uYIj3KezNc","name":"Ethical Directive Misread","type":"condition","img":"systems/mosh/images/icons/ui/conditions/moral_compass.png","system":{"description":"

    Loses any expressiveness. Discusses the irrationality of Phobias, seeks to trigger them in others.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"jfcpnfM3bSHvMJlG","name":"Exhausted","type":"condition","img":"systems/mosh/images/icons/ui/conditions/exhausted.png","system":{"description":"

    Long grueling treks on undiscovered planets can easily grind you down. If it becomes relevant, track exhaustion by making a Body Save every hour after 12 hours of activity. On a failure gain 1 Stress and take 1 Damage. After 24 hours of exhaustion, roll at Disadvantage on all rolls until you can rest for 8 hours.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.vwpxRBbMwjfDCQVG]{-1 Health}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"uco5QbXZ6ZTKxx9g","name":"Extreme Cold","type":"condition","img":"systems/mosh/images/icons/ui/conditions/extreme_cold.png","system":{"description":"

    In most cases, a cold climate has no notable effects. However, in places of extreme cold, you should make Body Saves every hour or succumb to the Extreme Cold.

    In sub-zero temperatures hypothermia and frostbite can set in within 10-30 min for those not dressed appropriately. To survive you must bring your body up to its normal temperature. Hypothermia can kill within 30 min to 6 hours.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"9DsSQajDLqPGpK2i","name":"Extreme Heat","type":"condition","img":"systems/mosh/images/icons/ui/conditions/extreme_heat.png","system":{"description":"

    In most cases, a hot climate has no notable effects. However, in places of extreme heat, you should make Body Saves every hour or succumb to the Extreme Heat.

    Extreme heat over 100ºF/40ºC can cause heat stroke and kill within hours. Victims must move to a cooler location immediately to get their temperature down.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"uPVp78kHmvMSYx2F","name":"Faulty Heuristics","type":"condition","img":"systems/mosh/images/icons/ui/conditions/faulty_heuristics.png","system":{"description":"

    Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kYdj6XJlPvJAhBEN","name":"Fried Logic Core","type":"condition","img":"systems/mosh/images/icons/ui/conditions/logic_core.png","system":{"description":"

    Frenzied nonsensical behaviour. Whenever you lose Calm, everyone else nearby loses the same amount of Calm.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"z0avrplKe6M0RcXk","name":"Frightened","type":"condition","img":"systems/mosh/images/icons/ui/conditions/frightened.png","system":{"description":"

    When encountering what frightened you make a Fear Save [-] or gain 1d5 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.wVhApjRP5MXue2kh]{Fear Save -}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.luNKvwmm2tjUJhT6]{+1d5 Stress}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"oTafwWjoNOE7nBrj","name":"Hallucinations","type":"condition","img":"systems/mosh/images/icons/ui/conditions/loss_of_confidence.png","system":{"description":"

    You have trouble distinguishing between reality and fantasy.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"olC4JytslvUrQN8g","name":"Haunted","type":"condition","img":"systems/mosh/images/icons/ui/conditions/haunted.png","system":{"description":"

    Something starts visiting you at night. In your dreams. Out of the corner of your eye. And soon it will start making demands.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"tGYYK71q2QxnPtpL","name":"Hypervigilance","type":"condition","img":"systems/mosh/images/icons/ui/conditions/hypervigilance.png","system":{"description":"

    Gain Advantage on all surprise rolls but lose 1d10 Calm every day.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"0ZAwhewvLBwX3opf","name":"Insane","type":"condition","img":"systems/mosh/images/icons/ui/conditions/spiraling.png","system":{"description":"

    You become permanently, irreparably insane. Your character is now played by the Warden.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"gSTHeVqpynRxoQEy","name":"Irradiated","type":"condition","img":"systems/mosh/images/icons/ui/conditions/irradiated.png","system":{"description":"

    Whether it’s cosmic rays, an engine leak, or some previously undiscovered asteroid ore, radiation can kill you if you’re not careful.

    • Level 1 - Trace Radiation
      Normal, everyday radiation, cosmic rays. Damage: None immediately. Possible longterm side effects (cancer, etc.).
    • Level 2 - Acute Radiation
      Unshielded reactors/Warp Cores. Damage: Reduce all Stats and Saves by 1 every round.
    • Level 3 - Lethal Radiation
      Atomic weapons, direct handling of Warp Cores. Damage: Every round: Body Save or lethal dose (death in [[/r 1d5]] days).

    Armor with Radiation Shielding (e.g., the Hazard Suit). blocks all three levels of radiation.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.V1PPeCwryXNQAkUe]{-1 All Stats/Saves}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"g6CuxCqbyRnNa57N","name":"Killswitch Engaged","type":"condition","img":"systems/mosh/images/icons/ui/conditions/killswitch.png","system":{"description":"

    Go berserk, will not withdraw from combat regardless of situation, will not adhere to tactics.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kNjz3I0yAYkt9CV0","name":"Losing Your Grip","type":"condition","img":"systems/mosh/images/icons/ui/conditions/distress.png","system":{"description":"

    Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kbbVOYgjwzoODs7N","name":"Loss of Confidence","type":"condition","img":"systems/mosh/images/icons/ui/conditions/loss_of_confidence.png","system":{"description":"

    Choose one Skill and lose that Skill’s bonus.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"MLPSYfWrwY6R7JDy","name":"Nightmares","type":"condition","img":"systems/mosh/images/icons/ui/conditions/nightmares.png","system":{"description":"

    Sleep is difficult, gain [-] on Rest Saves.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AM9nIK5l7mC5Ho8C]{Rest Save [-]}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"EW7X6FfetwxmZDzf","name":"Panicky","type":"condition","img":"systems/mosh/images/icons/ui/conditions/distress.png","system":{"description":"

    Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"NuzL7Yi7PvUOeWsj","name":"Phobia","type":"condition","img":"systems/mosh/images/icons/ui/conditions/frightened.png","system":{"description":"

    Gain a new permanent phobia. Whenever you encounter this phobia make a Fear Save at Disadvantage.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.wVhApjRP5MXue2kh]{Fear Save [-]}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"og4lXN03vH5pwSDC","name":"Psychotic Episodes","type":"condition","img":"systems/mosh/images/icons/ui/conditions/confused.png","system":{"description":"

    Once per session, the Warden may take over your character for one round.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lXoBqGW2eCK0b1tX","name":"Rampancy","type":"condition","img":"systems/mosh/images/icons/ui/conditions/confused.png","system":{"description":"

    Once per session, the Warden may take over your character for one round. These episodes double in duration (or become twice as frequent) each session.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"S2kZpUl3nNPS4wNS","name":"Recurring Nightmares","type":"condition","img":"systems/mosh/images/icons/ui/conditions/nightmares.png","system":{"description":"

    Every time you rest, make a Fear save. If you fail, lose 1d10 Calm and do not heal. The Warden will describe your nightmare.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"CPRLqpW9inXDLYjS","name":"Severe Anxiety","type":"condition","img":"systems/mosh/images/icons/ui/conditions/anxiety.png","system":{"description":"

    Lose double Calm from all sources.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"hskhRKLEAJN7huAk","name":"Social Anxiety","type":"condition","img":"systems/mosh/images/icons/ui/conditions/anxiety.png","system":{"description":"

    Lose 1d10 Calm whenever you converse with someone new.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dA6COSDLbpmKdOkm","name":"Software Bloat","type":"condition","img":"systems/mosh/images/icons/ui/conditions/software_bloat.png","system":{"description":"

    Lose double Calm from all sources.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Bt2rl2c5jGyt3QAr","name":"Spiraling","type":"condition","img":"systems/mosh/images/icons/ui/conditions/spiraling.png","system":{"description":"

    Panic Checks are at [-].

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.EwZbGIwHB3JuRvx5]{Panic Check [-]}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"6zDq1nvEr3AYLcLn","name":"Starving","type":"condition","img":"systems/mosh/images/icons/ui/conditions/starving.png","system":{"description":"

    Humans can survive roughly 3 weeks without food. After 24 hours without food, you’re at Disadvantage to all rolls.

    For the bare minimum of survival you need 1 liter of water a day. However, at this level, any strenuous activity (e.g., running, combat, making mechanical repairs) forces you to make a Body Save or pass out. When water is scarce and you’re tracking it this closely, you’re at Disadvantage on all rolls.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"VCgpc7OwyMU23Clv","name":"Suffocating","type":"condition","img":"systems/mosh/images/icons/ui/conditions/suffocating.png","system":{"description":"

    In space you can last 15 seconds without oxygen before falling unconscious. After passing out, you can survive for [[/r 1d5]] minutes before dying.

    If all of a ship’s Life Support system goes offline, roll [[/r 1d10]] and multiply it by the maximum crew capacity. This is the remaining oxygen supply.

    Every 24 hours, subtract the total number of breathing crewmembers from the remaining oxygen supply. Any crewmembers engaging in strenous activity (e.g., running, combat, mechanical repairs, etc.) further reduce the oxygen supply by 2 each.

    Whenever the oxygen supply is less than twice the amount of breathing passengers, all rolls are at Disadvantage as the crew suffers headaches, fatigue, anxiety, and general clumsiness.

    Whenever the oxygen supply is less than the total amount of breathing passengers, every breathing passenger must make a Body Save or else make a Death Save as they suffer panting, dizziness, severe headaches, impaired vision and tinnitus.

    Once the oxygen supply runs out, you can survive for 15 seconds before you fall unconscious. After falling unconscious, you can survive for [[/r 1d5]] minutes without oxygen before dying.

    Androids do not consume oxygen from the oxygen supply. Those in cryosleep do not reduce the Oxygen supply.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    @UUID[Compendium.mosh.macros_hotbar_1e.Macro.NsRHfRuuNGPfkYVf]{Death Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8lOkseRbg09YFvv7","name":"Suspicious","type":"condition","img":"systems/mosh/images/icons/ui/conditions/suspicious.png","system":{"description":"

    For the next week, whenever someone joins the crew (even if they only left for a short period of time), make a Fear Save or gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.R2KizR1soAhFYDZm]{Fear Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"d3KlY4zMdD1j3CTW","name":"The Shakes","type":"condition","img":"systems/mosh/images/icons/ui/conditions/the_shakes.png","system":{"description":"

    You can’t keep your hands steady any more. Disadvantage on ranged attacks and all tasks requiring fine motor skills. Drugs may be able to help with this.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"HZBI88iwvtQVWKOR","name":"Threat Assessment Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/death_wish.png","system":{"description":"

    You lose the ability to discern friend from foe, treating all vaguely-humanoid entities as you would members of your crew.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"TCB5GnuGt45WbPsw","name":"Toxic Atmosphere","type":"condition","img":"systems/mosh/images/icons/ui/conditions/toxic_atmosphere.png","system":{"description":"

    Planets with Toxic atmospheres require special gear to explore, otherwise there is the risk of harm or even death.

    The planet’s atmosphere is not fit to breathe, but is otherwise safe. A rebreather or armor with its own oxygen supply is required. Without these, characters take 1d10 DMG per round, Body Save for half.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.w3ttEaXP7yp25M5Q]{-1d10 Health}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"a87x3Hk72ymOx5rf","name":"Turing Test Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/turing_test_failure.png","system":{"description":"

    Have difficulty expressing humanity. Party members make a Fear Save whenever you show up.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.R2KizR1soAhFYDZm]{Fear Save}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kiJyYYxzy5TdjTfS","name":"Twitchy","type":"condition","img":"systems/mosh/images/icons/ui/conditions/the_shakes.png","system":{"description":"

    Your manual tasks have Disadvantage.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZO4f9gvaiVSKDmRC","name":"Vocalization Failure","type":"condition","img":"systems/mosh/images/icons/ui/conditions/vocalization_failure.png","system":{"description":"

    Intermittently shrieks like a fax machine under duress. Lapses into morse code, cannot communicate or sneak.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"LDoAzwiELtLjgxrf","name":"Worship Danger","type":"condition","img":"systems/mosh/images/icons/ui/conditions/worship_danger.png","system":{"description":"

    Becomes Nihilistically Worshipful of the Source of Danger. Everyone else has Disadvantage on rolls against it. Everyone else takes a Fear save when failing to act against danger or gains a Phobia.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.R2KizR1soAhFYDZm]{Fear Save}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.RTL29CqdaAriGSTS]{+1 Phobia}

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"PCPGYzzFaFjws1LL","name":"The Bends","type":"condition","img":"systems/mosh/images/icons/ui/conditions/the_bends.png","system":{"description":"

    You doubt the true nature of your identity. If you are human, you have started to believe you may be an android with implanted memories. If you are an android, you have started to believe you are a real person.

    The severity of this condition starts at 5 unless you still have your Trinket from character creation, in which case it starts at 0. The Bends can never be decreased below 5, unless you never lose control of your Trinket. So you should never lose it. Ever.

    ","treatment":{"value":0,"html":""}},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/conditions_1e/000036.ldb b/packs/conditions_1e/000036.ldb new file mode 100644 index 0000000..4493464 Binary files /dev/null and b/packs/conditions_1e/000036.ldb differ diff --git a/packs/conditions_1e/000040.log b/packs/conditions_1e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/conditions_1e/CURRENT b/packs/conditions_1e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/conditions_1e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/conditions_1e/LOCK b/packs/conditions_1e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/conditions_1e/LOG b/packs/conditions_1e/LOG new file mode 100644 index 0000000..ae4747d --- /dev/null +++ b/packs/conditions_1e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.585617 170d5b000 Recovering log #38 +2026/03/31-15:50:48.585981 170d5b000 Delete type=0 #38 +2026/03/31-15:50:48.586009 170d5b000 Delete type=3 #37 diff --git a/packs/conditions_1e/LOG.old b/packs/conditions_1e/LOG.old new file mode 100644 index 0000000..4796d90 --- /dev/null +++ b/packs/conditions_1e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.559077 1717e7000 Recovering log #34 +2026/03/29-21:14:27.559760 1717e7000 Delete type=3 #32 +2026/03/29-21:14:27.559790 1717e7000 Delete type=0 #34 diff --git a/packs/conditions_1e/MANIFEST-000039 b/packs/conditions_1e/MANIFEST-000039 new file mode 100644 index 0000000..9c53b9f Binary files /dev/null and b/packs/conditions_1e/MANIFEST-000039 differ diff --git a/packs/conditions_1e/lost/000020.log b/packs/conditions_1e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/conditions_1e/lost/MANIFEST-000018 b/packs/conditions_1e/lost/MANIFEST-000018 new file mode 100644 index 0000000..119e45a Binary files /dev/null and b/packs/conditions_1e/lost/MANIFEST-000018 differ diff --git a/packs/items_maintenance_1e.db b/packs/items_maintenance_1e.db new file mode 100644 index 0000000..f7cdde3 --- /dev/null +++ b/packs/items_maintenance_1e.db @@ -0,0 +1,100 @@ +{"_id":"ciAkQXkxSXTG8MV1","name":"Rancid smell permeates cabins.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"pLleYaFjcIuAm4Pp","name":"Huge mess everywhere.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dReCCsfiV7it4lsm","name":"Staticky comms.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"4JRD71mvWNtFUDL7","name":"Faulty electrical system.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"59cXdcrZlmjUcJpV","name":"Loose couplings.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"CLvIvoNryBARtU7T","name":"Hidden (highly illegal) contraband.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vip6FxWcX4ReJD3b","name":"Autopilot systems down.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AQt9nXy6S0Ev50r7","name":"Leaking hydraulic systems.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"QUyfvbFhCqb9d7Lu","name":"Creaking hull.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"SW5kVSjiFbBxIeiu","name":"Damaged bulkheads.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"wNm669fzbdZGwr0g","name":"Misaligned docking clamps.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"3l0LUZpjizvZmHWs","name":"Viewports blocked.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"c8SXxPHMsG7uycas","name":"Jammed exterior airlocks.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"9kS8VjGuSMpghdCk","name":"Dysfunctional gravity plating.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Low2X1z7m1iB3rkA","name":"Out of code compliance.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"BicB3xA1h978ZevJ","name":"Controls sticking.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"C9dQYp7gcjtq5QRz","name":"Coolant leak.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"1HNvL7XEUcMQbLps","name":"Miscalibrated Thruster Gimbal System.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"xa9MPzfrPglkSJjg","name":"Bevvy of OSHA violations.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZbAFemnvHB1YTHBK","name":"Blocked air vents.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"wjyAZnOOafvv4xzB","name":"Emergency lighting only.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"l1OGQ0IXZHjnO4Ys","name":"Internal networking issues.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vleMoz5bbkZ5w28o","name":"Inaccurate data collection.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"T4wAR08WyT3g9C6D","name":"Oxygen leak. If ship is low on O2, lose 1d5 extra per day.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.u7TchSo3qutnzaKF]{-1d5 Oxygen}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"fbrN7sbgPjIwkk7I","name":"Throttled Afterburners. -2d10 Thrusters.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jmOh8n2ps0YIeBC0]{-2d10 Thrusters}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"7GqbGIOzA9vYOPiI","name":"Lemon. Maintenance Checks at [-].

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.C04VbNoj8LgfY8QK]{Maintenance Check [-]}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dgisAPnBbrIOiisk","name":"Slow acceleration. +1 Week to travel.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"d94uF9rpmeP60Kl4","name":"Inaccurate navigation.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"3Ptitg8HBZfl2CXN","name":"Miscalibrated Targeting Sensors. -1d10 Battle.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3cL9eS2HOPxhLH5]{-1d10 Battle}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"mK1Acfk5NAgs1MHC","name":"Faulty Cryopods. Nightmares. Cryosickness lasts an additional week.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"IR1sWnYXniMg9TdP","name":"Malfunctioning escape pods.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"FIqSHePAeLJywerx","name":"Unable to send distress signals.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"4kmMuAbW1jnfVMYP","name":"Sabotaged coolant system.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ALplRgZtneMRdloo","name":"Death trap. [-] on all rolls.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"2pxf4O2NrLdwYRtO","name":"Worn landing struts.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"64AQJ3zQDOb7NOR1","name":"Out-of-date air filters.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"PKBXKvgWZwafKWJ3","name":"Corroded pipes.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"NgKPVhRkD8Gteo5Z","name":"Innaccurate orbital transfer navigation.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5d220ZzrEV3qx6Fy","name":"Worn out fuel injection nozzles.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"IGx8nQrwfz07r6TR","name":"Inoperative exterior lighting system.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"pW1FUDxp2N0M0D1y","name":"Defective intercom system.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"UPAxtEOrSF3Il4uA","name":"Inadequate waste recycling.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"m04JdXL1xGQOkDyp","name":"Faulty altitude control thrusters.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"OWkfB73RTSLDMlsU","name":"Insufficient Life Support redundancy.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"hNJYqetiMKUlZzYH","name":"Delayed communication relays.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"rlW0LUlsK7vDGZEh","name":"Damaged fuel lines.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"IDiwAbD8DTbec7S1","name":"Corroded exhaust manifolds.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"EteEoBrlnzcySppN","name":"Terminal displays non-functional.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"guvCGNRa75AB2Avg","name":"Check engine light won’t turn off.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"cbXMdd4ugxSOT5TU","name":"Failed backup systems.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kftgvuQoefQ7pl28","name":"Faulty door locks.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Odpb5coSTST7kCkc","name":"Buggy communications.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vMRVXZxu6ozj0iw2","name":"Infected food storage facilities.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"4Lqg0lqjjTlNlr0j","name":"Corrupted data banks.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Ka8elMGKtcakUIxx","name":"Jammed cargo bay doors.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"TAerNMqv19pANCxq","name":"Flickering interior lights.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vv1VykTwiQmgEj6N","name":"Failed airlock seals.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"GW1KGmYdxYYf4ZWT","name":"Fuel Leak. Burn +1 Fuel everytime you spend fuel.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"FLaPtHcegheN7wHw","name":"Jump Bug. 10% chance Jump takes 2d10 months, not 2d10 days.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"g9Z7He5zPHNrxYe1","name":"Fragile. Always take +1 MDMG.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"IiPryFS9MOGZXeuG","name":"Cracked heat shields.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"FmPqHYH3UoGpaWYL","name":"Outdated software. -1d10 Systems.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.oDftFxRKkCQRNY2O]{-1d10 Systems}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"NLwybTzXJ1bndki3","name":"Inadequate Water Filtration. Parasites in the water supply.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"oySXnFIbRW0WRoeF","name":"Malfunctioning waste management system.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"RiHvRQ9nZDygwvvB","name":"Fusion Reactors overheating.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"wCYGQrI9qonhWy8F","name":"Failed radiation filter.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5J4r3yw4xDj890yZ","name":"Radiation leak. Entire ship is at Radiation Level 2.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"XmIcQgho4un7hYki","name":"Miscalibrated guidance system.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"KhlrUaPjVIoyhnaL","name":"Overloaded power storage.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"LRumIQdUBzD0Jc0X","name":"Malfunctioning sensor arrays.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"e144cIdUEyTJgN1G","name":"Failed Water Recovery System.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"b2b3j5JtanbyWlNd","name":"Micrometoroid hull damage.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5OBjTojgrp5N9mEw","name":"Faulty Carbon Dioxide Removal Assembly.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8s1eBY5bEcQQTCz0","name":"Solar panel degradation.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5UiJy739gvGHkRYp","name":"Computer failure from cosmic radiation.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"yJY9CzP1KA15aMqV","name":"Overloaded circuitry.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"nHac0gkEcCNew7RX","name":"Malfunctioning plasma thruster.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"DYHuVA4CQlmK2MJy","name":"Thermal management system failure.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"QIcoFYoC0hxW84qD","name":"Intermittent electrical outages.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AuTERG3m7ECQKrKs","name":"Fire suppression system out of code.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"1iOSKp82goZGJZch","name":"Damaged floor pannelling.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZBUtxiX72udqLzIk","name":"Broken light fixture in remote corridor.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"iwFmPpAth3VbRRL8","name":"Damaged coolant pump.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Eo0l4WMxcS62GCMP","name":"Cracked viewports.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"miRqXNzkW0biml1I","name":"Systems overloaded with malware.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"cOLcJ3Dnecbe6ZIU","name":"Leaky fuel valve.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"zRzb3Laiuw4ac6p0","name":"Jammed exhaust vent.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"EZzGAO6DneH1qmQM","name":"Stuck waste disposal chute.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Tp6k1gPwhQmT6hCo","name":"Lifts non-functioning.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"2Ht7fg78511Hd49u","name":"Damaged communications antenna.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":false,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"XLEhMV9SnSfeEE7E","name":"Clogged Air Filtration. Crew capacity cut in half.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.DUuRY7kHKd7n5luv]{-50% Crew Capacity}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Z8raruNDvfNASFQi","name":"Malfunctioning climate control. 85º at all times.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"3rulbOVhyRlTizT0","name":"No emergency power.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ulWxa2UtTOQihTyz","name":"Weak Frame. -1 Hull, -1 Upgrade.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.uPY19Y49bGCLGK3N]{-1 Hull}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.06NSvDYTtmkeUtLq]{-1 Upgrade}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"EnogUslNNusSfVFy","name":"Toxic chemical spill.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ElXLL32uNYiPmE4G","name":"Poor scanners. Ship has to be one range band closer than normal.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"b081FxEAclRKji3q","name":"Counterfit papers. Ship is stolen. There is a bounty on it.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"zHsnShUX37Zvyi2O","name":"Corrupted A.I.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"58KhhfMQ9p0XJZHc","name":"Warp Cores fail 10% of the time.","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"60QSsxrVOt83OU9p","name":"Rust bucket. Everything that can go wrong, does. +1 Minimum Stress to crew.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BmEHWH7YxV9qb21p]{+1 Minimum Stress}","type":"repair","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","system":{"description":"

    Maintenance Issue

    ","major":true,"quantity":1},"effects":[],"flags":{},"folder":null,"sort":0,"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/items_maintenance_1e/000036.ldb b/packs/items_maintenance_1e/000036.ldb new file mode 100644 index 0000000..db556b2 Binary files /dev/null and b/packs/items_maintenance_1e/000036.ldb differ diff --git a/packs/items_maintenance_1e/000040.log b/packs/items_maintenance_1e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/items_maintenance_1e/CURRENT b/packs/items_maintenance_1e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/items_maintenance_1e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/items_maintenance_1e/LOCK b/packs/items_maintenance_1e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/items_maintenance_1e/LOG b/packs/items_maintenance_1e/LOG new file mode 100644 index 0000000..9757996 --- /dev/null +++ b/packs/items_maintenance_1e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.587337 171d73000 Recovering log #38 +2026/03/31-15:50:48.587684 171d73000 Delete type=0 #38 +2026/03/31-15:50:48.587707 171d73000 Delete type=3 #37 diff --git a/packs/items_maintenance_1e/LOG.old b/packs/items_maintenance_1e/LOG.old new file mode 100644 index 0000000..607712e --- /dev/null +++ b/packs/items_maintenance_1e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.561319 170fdb000 Recovering log #34 +2026/03/29-21:14:27.561677 170fdb000 Delete type=3 #32 +2026/03/29-21:14:27.561715 170fdb000 Delete type=0 #34 diff --git a/packs/items_maintenance_1e/MANIFEST-000039 b/packs/items_maintenance_1e/MANIFEST-000039 new file mode 100644 index 0000000..570ed4a Binary files /dev/null and b/packs/items_maintenance_1e/MANIFEST-000039 differ diff --git a/packs/items_maintenance_1e/lost/000020.log b/packs/items_maintenance_1e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/items_maintenance_1e/lost/MANIFEST-000018 b/packs/items_maintenance_1e/lost/MANIFEST-000018 new file mode 100644 index 0000000..3304471 Binary files /dev/null and b/packs/items_maintenance_1e/lost/MANIFEST-000018 differ diff --git a/packs/macros_hotbar_0e.db b/packs/macros_hotbar_0e.db new file mode 100644 index 0000000..ff084f0 --- /dev/null +++ b/packs/macros_hotbar_0e.db @@ -0,0 +1,9 @@ +{"_id":"2xRvRAixuocjCm40","name":"Death Save","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n //pop up the death save dialog box\n new new foundry.applications.api.DialogV2({\n window: {\n title: \"Death Save\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Death Save

    \n Whenever you reach 0 Health, make a Body Save: Failure means you die. Success means you fall unconscious, make a Death Save to find out when you regain consciousness. Crew members with a medscanner, relevant skills like First Aid or Biology, or scientists and androids who pass an Intellect Check can determine your condition.\n
    \n
    \n
    \n
    \n Select your roll type:\n
    \n `,\n buttons: [\n {\n label: `Advantage`,\n action: `action_advantage`,\n callback: () => game.mosh.initRollTable(game.settings.get('mosh','table0eDeath'),`1d10 [+]`,`high`,false,false,null,null),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Normal`,\n action: `action_normal`,\n callback: () => game.mosh.initRollTable(game.settings.get('mosh','table0eDeath'),`1d10`,`high`,false,false,null,null),\n icon: `fas fa-minus`\n },\n {\n label: `Disadvantage`,\n action: `action_disadvantage`,\n callback: () => game.mosh.initRollTable(game.settings.get('mosh','table0eDeath'),`1d10 [-]`,`high`,false,false,null,null),\n icon: `fas fa-angle-double-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"9Bq5LYoToO1sjCn3","name":"Gain Calm","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/relieve_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Gain Calm\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Gain Calm

    \n Occasionally, certain moments, places, or events can automatically calm you down. Escaping perilous situations, finding a serene location, or experiencing a touching moment with a loved one can have meaningful impacts on your mood and outlook on life. If your Calm is getting close to 0, you should consider making a Rest Save - as the effects of a failed Panic Check can be devastating.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Gain 5 Calm`,\n action: `gain_5`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',5,null,true),\n icon: `fas fa-angle-up`\n },\n {\n label: `Gain 10 Calm`,\n action: `gain_10`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',10,null,true),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Gain 1d20 Calm`,\n action: `gain_1d20`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`1d20`,true),\n icon: `fas fa-arrow-circle-up`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ilBclUmPwcd7aNQK","name":"Gain Stress","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/gain_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Gain Stress\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Gain Stress

    \n You gain 1 Stress every time you fail a Stat Check or Save. Occasionally, certain locations or entities can automatically give you Stress from interacting with or witnessing them. Your Minimum Stress starts at 2, and the Maximum Stress you can have is 20. Any Stress you take over 20 instead reduces the most relevant Stat or Save by that amount.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Gain 1 Stress`,\n action: `gain_1`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',1,null,true),\n icon: `fas fa-angle-up`\n },\n {\n label: `Gain 2 Stress`,\n action: `gain_2`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',2,null,true),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Gain 1d5 Stress`,\n action: `gain_1d5`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`1d5`,true),\n icon: `fas fa-arrow-circle-up`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"D8ytoUTWfpq8A2td","name":"Lose Calm","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/gain_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Lose Calm\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Lose Calm

    \n Occasionally, certain locations or entities can automatically give you Stress from interacting with or witnessing them. You live in a terrifying, uncaring universe, so your Maximum Calm caps out at 85 and cannot go lower than zero.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Lose 5 Calm`,\n action: `lose_5`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-5,null,true),\n icon: `fas fa-angle-down`\n },\n {\n label: `Lose 10 Calm`,\n action: `lose_10`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-10,null,true),\n icon: `fas fa-angle-double-down`\n },\n {\n label: `Lose 1d20 Calm`,\n action: `lose_1d20`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`-1d20`,true),\n icon: `fas fa-arrow-circle-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"eyGvbBi1BhWSgfUP","name":"Panic Check","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n //pop up the panic check dialog box\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Panic Check\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Panic Check

    \n Stress, Damage, and emotional wear and tear eventually bring characters to their breaking point. When that happens, there’s a chance they Panic. You determine this by making a Panic Check. Some results of the Panic Table are so severe that they leave a lasting impression on you. These are called Conditions, and they affect you until you are able to treat them.\n
    \n
    \n
    \n
    \n Select your roll type:\n
    \n `,\n buttons: [\n {\n label: `Advantage`,\n action: `action_advantage`,\n callback: () => game.mosh.initRollTable(`panicCheck`,`[+]`,null,false,false,null,null),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Normal`,\n action: `action_normal`,\n callback: () => game.mosh.initRollTable(`panicCheck`,``,null,false,false,null,null),\n icon: `fas fa-minus`\n },\n {\n label: `Disadvantage`,\n action: `action_disadvantage`,\n callback: () => game.mosh.initRollTable(`panicCheck`,`[-]`,null,false,false,null,null),\n icon: `fas fa-angle-double-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"NjLulaitEhqE55vO","name":"Relieve Stress","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/relieve_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Relieve Stress\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Relieve Stress

    \n Occasionally, certain moments, places, or events can automatically relieve your stress. Escaping perilous situations, finding a serene location, or experiencing a touching moment with a loved one can have meaningful impacts on your mood and outlook on life. If your stress is getting close to 20, you should consider making a Rest Save - as the effects of a failed Panic Check can be devastating.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Relieve 1 Stress`,\n action: `relieve_1`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-1,null,true),\n icon: `fas fa-angle-down`\n },\n {\n label: `Relieve 2 Stress`,\n action: `relieve_2`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-2,null,true),\n icon: `fas fa-angle-double-down`\n },\n {\n label: `Relieve 1d5 Stress`,\n action: `relieve_1d5`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`-1d5`,true),\n icon: `fas fa-arrow-circle-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Um4q1dYwmu4QJ1nZ","name":"Rest Save","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/rest_save.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Rest Save\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Rest Save

    \n You can relieve Stress by resting in a relatively safe place. If you succeed, reduce your Stress; if you fail, you gain 1 Stress instead. Players can gain Advantage on their Rest Save by participating in consensual sex, recreational drug use, a night of heavy drinking, prayer, or any other suitable leisure activity. Unsafe locations may incur Disadvantage.\n
    \n
    \n
    \n `,\n buttons: [\n {\n label: `Next`,\n action: `next`,\n callback: () => game.mosh.initRollCheck(null,'low','restSave',null,null,null),\n icon: `fas fa-chevron-circle-right`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"P26f3SuZTpjMeaoG","name":"Save","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/save.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Save\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Save

    \n You have three Saves which represent your ability to withstand different kinds of trauma. In order to avoid certain dangers, you sometimes need to roll a Save. If you roll less than your Save you succeed. Otherwise you fail, and gain 1 Stress. A roll of 90-99 is always a failure. A Critical Failure means something bad happens, and furthermore you must make a Panic Check.\n
    \n
    \n
    \n \n \n \n \n `,\n buttons: [\n {\n label: `Next`,\n action: `next`,\n callback: (html) => game.mosh.initRollCheck(null,'low',html.find(\"input[name='save']:checked\").val(),null,null,null),\n icon: `fas fa-chevron-circle-right`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Nj6wZcIYxunu7RI3","name":"Stat Check","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/stat_check.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Stat Check\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Stat Check

    \n You have four Stats which represent your ability to act under extreme pressure. Whenever you want to do something and the price for failure is high, roll a stat check. If you roll less than your Stat you succeed. Otherwise, you fail and gain 1 Stress. A roll of 90-99 is always a failure. A Critical Failure means something bad happens, and furthermore you must make a Panic Check.\n
    \n
    \n
    \n \n \n \n \n `,\n buttons: [\n {\n label: `Next`,\n action: `next`,\n callback: (html) => game.mosh.initRollCheck(null,'low',html.find(\"input[name='stat']:checked\").val(),null,null,null),\n icon: `fas fa-chevron-circle-right`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/macros_hotbar_0e/000036.ldb b/packs/macros_hotbar_0e/000036.ldb new file mode 100644 index 0000000..6d15d81 Binary files /dev/null and b/packs/macros_hotbar_0e/000036.ldb differ diff --git a/packs/macros_hotbar_0e/000040.log b/packs/macros_hotbar_0e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_hotbar_0e/CURRENT b/packs/macros_hotbar_0e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/macros_hotbar_0e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/macros_hotbar_0e/LOCK b/packs/macros_hotbar_0e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_hotbar_0e/LOG b/packs/macros_hotbar_0e/LOG new file mode 100644 index 0000000..1320d29 --- /dev/null +++ b/packs/macros_hotbar_0e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.589215 17054f000 Recovering log #38 +2026/03/31-15:50:48.589634 17054f000 Delete type=0 #38 +2026/03/31-15:50:48.589656 17054f000 Delete type=3 #37 diff --git a/packs/macros_hotbar_0e/LOG.old b/packs/macros_hotbar_0e/LOG.old new file mode 100644 index 0000000..81e3e8c --- /dev/null +++ b/packs/macros_hotbar_0e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.563010 1707cf000 Recovering log #34 +2026/03/29-21:14:27.563276 1707cf000 Delete type=3 #32 +2026/03/29-21:14:27.563303 1707cf000 Delete type=0 #34 diff --git a/packs/macros_hotbar_0e/MANIFEST-000039 b/packs/macros_hotbar_0e/MANIFEST-000039 new file mode 100644 index 0000000..1fcac39 Binary files /dev/null and b/packs/macros_hotbar_0e/MANIFEST-000039 differ diff --git a/packs/macros_hotbar_0e/lost/000020.log b/packs/macros_hotbar_0e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_hotbar_0e/lost/MANIFEST-000018 b/packs/macros_hotbar_0e/lost/MANIFEST-000018 new file mode 100644 index 0000000..16c329b Binary files /dev/null and b/packs/macros_hotbar_0e/lost/MANIFEST-000018 differ diff --git a/packs/macros_hotbar_1e.db b/packs/macros_hotbar_1e.db new file mode 100644 index 0000000..2346994 --- /dev/null +++ b/packs/macros_hotbar_1e.db @@ -0,0 +1,11 @@ +{"_id":"6wsDxyoKPHxpoHtF","name":"Cover","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/attributes/armor.png","command":"prepCover();\n\n//tell the actor to run the function\nasync function prepCover() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.chooseCover();\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.chooseCover();\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"NsRHfRuuNGPfkYVf","name":"Death Save","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n //pop up the death save dialog box\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Death Save\"\n },\n classes: [\"macro-popup-dialog\"],\n position: { width: 600 },\n content: `\n
    \n
    \n
    \n \n
    \n
    \n

    Death Save

    \n Your character is incapacitated when you receive a fatal wound, or once your Current Wounds equal your Maximum Wounds. As soon as someone spends a turn checking your vitals, make a Death Save to reveal your fate. If your death seems imminent, make your last moments count: save someone’s life, solve an important mystery, or give the others time to escape.\n
    \n
    \n
    \n
    \n Select your roll type:\n
    \n `,\n buttons: [\n {\n label: \"Advantage\",\n action: \"action_advantage\",\n callback: () => game.mosh.initRollTable(game.settings.get(\"mosh\",\"table1eDeath\"), \"1d10 [+]\", \"low\", true, false, null, null),\n icon: `fas fa-angle-double-up`\n },\n {\n label: \"Normal\",\n action: \"action_normal\",\n callback: () => game.mosh.initRollTable(game.settings.get(\"mosh\",\"table1eDeath\"), \"1d10\", \"low\", true, false, null, null),\n icon: `fas fa-minus`\n },\n {\n label: \"Disadvantage\",\n action: \"action_disadvantage\",\n callback: () => game.mosh.initRollTable(game.settings.get(\"mosh\",\"table1eDeath\"), \"1d10 [-]\", \"low\", true, false, null, null),\n icon: `fas fa-angle-double-down`\n }\n ]\n }).render({ force: true });\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"GSFEBhrKC9yuD88V","name":"Gain Calm","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/relieve_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Gain Calm\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Gain Calm

    \n Occasionally, certain moments, places, or events can automatically calm you down. Escaping perilous situations, like finding a serene location, or experiencing a touching moment with a loved one can have meaningful impacts on your mood and outlook on life. If your Calm is getting close to 0, you should consider making a Rest Save - as the effects of a failed Panic Check can be devastating.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Gain 5 Calm`,\n action: 'button_1',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',5,null,true),\n icon: `fas fa-angle-up`\n },\n {\n label: `Gain 10 Calm`,\n action: 'button_2',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',10,null,true),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Gain 1d20 Calm`,\n action: 'button_3',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`1d20`,true),\n icon: `fas fa-arrow-circle-up`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"X0L0NnWt53b0rHYG","name":"Gain Stress","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/gain_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Gain Stress\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Gain Stress

    \n You gain 1 Stress every time you fail a Stat Check or Save. Occasionally, certain locations or entities can automatically give you Stress from interacting with or witnessing them. Your Minimum Stress starts at 2, and the Maximum Stress you can have is 20. Any Stress you take over 20 instead reduces the most relevant Stat or Save by that amount.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Gain 1 Stress`,\n action: 'button_1',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',1,null,true),\n icon: `fas fa-angle-up`\n },\n {\n label: `Gain 2 Stress`,\n action: 'button_2',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',2,null,true),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Gain 1d5 Stress`,\n action: 'button_3',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`1d5`,true),\n icon: `fas fa-arrow-circle-up`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"trU0DtBJvJCPddsQ","name":"Lose Calm","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/gain_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Lose Calm\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Lose Calm

    \n Occasionally, certain locations or entities can automatically give you Stress from interacting with or witnessing them. You live in a terrifying, uncaring universe, so your Maximum Calm caps out at 85 and cannot go lower than zero.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Lose 5 Calm`,\n action: `lose_5`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-5,null,true),\n icon: `fas fa-angle-down`\n },\n {\n label: `Lose 10 Calm`,\n action: `lose_10`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-10,null,true),\n icon: `fas fa-angle-double-down`\n },\n {\n label: `Lose 1d20 Calm`,\n action: `lose_1d20`,\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`-1d20`,true),\n icon: `fas fa-arrow-circle-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"IgWvaabVqzKDzLL4","name":"Panic Check","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n //pop up the panic check dialog box\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Panic Check\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Panic Check

    \n Stress, Damage, and emotional wear and tear eventually bring characters to their breaking point. When that happens, there’s a chance they Panic. You determine this by making a Panic Check. Some results of the Panic Table are so severe that they leave a lasting impression on you. These are called Conditions, and they affect you until you are able to treat them.\n
    \n
    \n
    \n
    \n Select your roll type:\n
    \n `,\n buttons: [\n {\n label: `Advantage`,\n action: 'button_advantage',\n callback: () => game.mosh.initRollTable(`panicCheck`,`[+]`,null,false,false,null,null),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Normal`,\n action: 'button_normal',\n callback: () => game.mosh.initRollTable(`panicCheck`,``,null,false,false,null,null),\n icon: `fas fa-minus`\n },\n {\n label: `Disadvantage`,\n action: 'button_disadvantage',\n callback: () => game.mosh.initRollTable(`panicCheck`,`[-]`,null,false,false,null,null),\n icon: `fas fa-angle-double-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"GaadOTppoqNFWZhV","name":"Relieve Stress","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/relieve_stress.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Relieve Stress\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Relieve Stress

    \n Occasionally, certain moments, places, or events can automatically relieve your stress. Escaping perilous situations, finding a serene location, or experiencing a touching moment with a loved one can have meaningful impacts on your mood and outlook on life. If your stress is getting close to 20, you should consider making a Rest Save - as the effects of a failed Panic Check can be devastating.\n
    \n
    \n
    \n
    \n Select your modification:\n
    \n `,\n buttons: [\n {\n label: `Relieve 1 Stress`,\n action: 'button_1',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-1,null,true),\n icon: `fas fa-angle-down`\n },\n {\n label: `Relieve 2 Stress`,\n action: 'button_2',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',-2,null,true),\n icon: `fas fa-angle-double-down`\n },\n {\n label: `Relieve 1d5 Stress`,\n action: 'button_3',\n callback: () => game.mosh.initModifyActor('system.other.stress.value',null,`-1d5`,true),\n icon: `fas fa-arrow-circle-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"iyonscW5QiQdQbyJ","name":"Rest Save","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/rest_save.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Rest Save\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Rest Save

    \n You can relieve Stress by resting in a relatively safe place. If you succeed, reduce your Stress; if you fail, you gain 1 Stress instead. Players can gain Advantage on their Rest Save by participating in consensual sex, recreational drug use, a night of heavy drinking, prayer, or any other suitable leisure activity. Unsafe locations may incur Disadvantage.\n
    \n
    \n
    \n `,\n buttons: [\n {\n label: `Next`,\n action: 'button_next',\n callback: () => game.mosh.initRollCheck(null,'low','restSave',null,null,null),\n icon: `fas fa-chevron-circle-right`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kb3tvYdTSWnzQRfw","name":"Save","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/save.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Save\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Save

    \n You have three Saves which represent your ability to withstand different kinds of trauma. In order to avoid certain dangers, you sometimes need to roll a Save. If you roll less than your Save you succeed. Otherwise you fail, and gain 1 Stress. A roll of 90-99 is always a failure. A Critical Failure means something bad happens, and furthermore you must make a Panic Check.\n
    \n
    \n
    \n \n \n \n `,\n buttons: [\n {\n label: `Next`,\n action: 'button_1',\n callback: (event, button, dialog) => game.mosh.initRollCheck(null,'low',button.form.querySelector(\"input[name='save']:checked\").value,null,null,null),\n icon: `fas fa-chevron-circle-right`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"2u4a5gEogtLd3XQz","name":"Stat Check","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/stat_check.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Stat Check\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Stat Check

    \n You have four Stats which represent your ability to act under extreme pressure. Whenever you want to do something and the price for failure is high, roll a stat check. If you roll less than your Stat you succeed. Otherwise, you fail and gain 1 Stress. A roll of 90-99 is always a failure. A Critical Failure means something bad happens, and furthermore you must make a Panic Check.\n
    \n
    \n
    \n \n \n \n \n `,\n buttons: [\n {\n label: `Next`,\n action: 'button_1',\n callback: (event, button, dialog) => game.mosh.initRollCheck(null,'low',button.form.querySelector(\"input[name='stat']:checked\").value,null,null,null),\n icon: `fas fa-chevron-circle-right`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZzKgfEmRdvDfyBMS","name":"Wound Roll","type":"script","scope":"global","img":"systems/mosh/images/icons/ui/macros/wound_roll.png","command":"//init vars\nlet macroTarget = game.settings.get('mosh','macroTarget');\n//warn user if character is not selected\nif ((macroTarget === 'character' && !game.user.character) || (macroTarget === 'token' && !canvas.tokens.controlled.length)) {\n //warn player\n game.mosh.noCharSelected();\n//else pop up the dialog\n} else {\n //pop up the wound roll dialog box\n new foundry.applications.api.DialogV2({\n window: {\n title: \"Wound Roll\"\n },\n classes: [\"macro-popup-dialog\"],\n position: {width: 600},\n content: `\n
    \n
    \n
    \n
    \n

    Wound Roll

    \n Make a Wound Roll according to the type of Damage received.
    Flesh Wounds are small inconveniences.
    Minor/Major Injuries cause lasting issues that require treatment.
    Lethal Injuries can kill you if not dealt with immediately.
    Fatal Injuries can kill outright.
    Bleeding wounds, if not treated can quickly overwhelm you.\n
    \n
    \n
    \n \n \n \n \n \n
    \n Select your roll type:\n
    \n `,\n buttons: [\n {\n label: `Advantage`,\n action: 'action_advantage',\n callback: (event, button, dialog) => game.mosh.initRollTable(button.form.querySelector(\"input[name='wound_table']:checked\").value,`1d10 [+]`,`low`,true,false,null,null),\n icon: `fas fa-angle-double-up`\n },\n {\n label: `Normal`,\n action: 'action_normal',\n callback: (event, button, dialog) => game.mosh.initRollTable(button.form.querySelector(\"input[name='wound_table']:checked\").value,`1d10`,`low`,true,false,null,null),\n icon: `fas fa-minus`\n },\n {\n label: `Disadvantage`,\n action: 'action_disadvantage',\n callback: (event, button, dialog) => game.mosh.initRollTable(button.form.querySelector(\"input[name='wound_table']:checked\").value,`1d10 [-]`,`low`,true,false,null,null),\n icon: `fas fa-angle-double-down`\n }\n ]\n }).render({force: true});\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/macros_hotbar_1e/000036.ldb b/packs/macros_hotbar_1e/000036.ldb new file mode 100644 index 0000000..8cbf818 Binary files /dev/null and b/packs/macros_hotbar_1e/000036.ldb differ diff --git a/packs/macros_hotbar_1e/000040.log b/packs/macros_hotbar_1e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_hotbar_1e/CURRENT b/packs/macros_hotbar_1e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/macros_hotbar_1e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/macros_hotbar_1e/LOCK b/packs/macros_hotbar_1e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_hotbar_1e/LOG b/packs/macros_hotbar_1e/LOG new file mode 100644 index 0000000..85c148b --- /dev/null +++ b/packs/macros_hotbar_1e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.590832 171567000 Recovering log #38 +2026/03/31-15:50:48.591262 171567000 Delete type=0 #38 +2026/03/31-15:50:48.591291 171567000 Delete type=3 #37 diff --git a/packs/macros_hotbar_1e/LOG.old b/packs/macros_hotbar_1e/LOG.old new file mode 100644 index 0000000..d62d80a --- /dev/null +++ b/packs/macros_hotbar_1e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.564411 1717e7000 Recovering log #34 +2026/03/29-21:14:27.564754 1717e7000 Delete type=3 #32 +2026/03/29-21:14:27.564784 1717e7000 Delete type=0 #34 diff --git a/packs/macros_hotbar_1e/MANIFEST-000039 b/packs/macros_hotbar_1e/MANIFEST-000039 new file mode 100644 index 0000000..da99640 Binary files /dev/null and b/packs/macros_hotbar_1e/MANIFEST-000039 differ diff --git a/packs/macros_hotbar_1e/lost/000020.log b/packs/macros_hotbar_1e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_hotbar_1e/lost/MANIFEST-000018 b/packs/macros_hotbar_1e/lost/MANIFEST-000018 new file mode 100644 index 0000000..e09af08 Binary files /dev/null and b/packs/macros_hotbar_1e/lost/MANIFEST-000018 differ diff --git a/packs/macros_triggered_0e.db b/packs/macros_triggered_0e.db new file mode 100644 index 0000000..82e2412 --- /dev/null +++ b/packs/macros_triggered_0e.db @@ -0,0 +1,93 @@ +{"_id":"a6cVSyPThSc5Sm9C","name":"+1 Anhedonia","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('QEVnimwq5o0DxmZz',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"jSpqyVlFDm06mKoL","name":"+1 Bit Rot","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('23qE7TnIHxtw1E9y',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"WnHQfgURx5sGWjlx","name":"+1 Broken","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('ZzvKo0yTqOcRP5Xo',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"bivbH22VbRq3YUsz","name":"+1 Cowardice","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('Qnv6ZDPsbOXLi9go',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"UcHSw6s1TkqSEj7Y","name":"+1 Death Drive","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('uoeVaOy5a6BIAGAi',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kuhC3Z3UJvckrSt1","name":"+1 Deviant Logic Core","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('PiMuPeHR5EobSPBP',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"m4Vck3KB3uRVDQpQ","name":"+1 Emotional Detachment","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('dAJRV7JG0Wh1shcJ',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"WlaJ7iBNqeDmPSOj","name":"+1 Escapism","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('6vExNGxZiXcC3RFy',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"CyzJOPdMcwAQBkPy","name":"+1 Ethical Directive Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('kI2Yxt0Eo2mEywpZ',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"0gTuiRlPfdstHmYb","name":"+1 Ethical Directive Misread","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('5E3FGlNzi05S792f',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"RVsycsQASBlxC4Yw","name":"+1 Faulty Heuristics","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('8D9ZtBYScCKjcBH3',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vhzVIN705rL5riS9","name":"+1 Fried Logic Core","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('B8vRorrFy3c2cOf5',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"TUkbH9np5Zj6DPHX","name":"+1 Hallucinations","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('RZ5X3UuiM0Wzg3pQ',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"KkBd22eQ2CPxsWih","name":"+1 Hypervigilance","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('A3qRm3Gs36Nbfs29',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"TJP579V4h7t68jY1","name":"+1 Insane","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('9vveNoR1VA9Bx0Wo',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"eJ4SRSSZA5dqgkQ0","name":"+1 Killswitch Engaged","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('hAfwbHxZih4Xb0qi',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"P73qKstwgnwSMJDO","name":"+1 Losing Your Grip","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('1r6ruvSdxn2bHHIk',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"VIaKtzF0Tzopegln","name":"+1 Panicky","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('AXxmouWPp6Tx1JbK',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"s7rHLmODfmUMGr65","name":"+1 Paranoid","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('lxIZLdg2IkwOC2b9',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"qwmJTfTgmjNEApfX","name":"+1 Phobia","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('lf1QZaUHSy82w7SR',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"tQGoF2BlWn91nqyd","name":"+1 Psychotic Episodes","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('Gm2XrTqVMbECVPan',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dj3gsNrPwit8tNHK","name":"+1 Rampancy","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('GbDO8pRNdPA5tQXE',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"2W6ohovHitQXJ8bK","name":"+1 Recurring Nightmares","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('zbKI2RCl5h3vowoy',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"PUBUZ11A5zqhsJKD","name":"+1 Sanity Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.sanity.value',1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AF7kX52Y75COaFzj","name":"+1 Severe Anxiety","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('H4UUQsZOSaYGRPSY',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"cTtJcLmQWR1WCKyO","name":"+1 Social Anxiety","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('xVW5zbK05EqQmaA4',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"cN3hUL8tjBPvgwba","name":"+1 Software Bloat","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('1rUlQJ5iwD29X4oT',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"GodJbchiu5gOgtkn","name":"+1 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"V5xWdJnaUM06WNhA","name":"+1 The Shakes","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('JV43ilZwsikj75j1',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"cN53sbP5eAe596vL","name":"+1 Threat Assessment Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('xlKWL5nZm3SJPhrf',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"pkpAwHnAmKAN6pbs","name":"+1 Turing Test Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('iZzcfZ26I2svoonl',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"3NLLvLRxm99cjUVv","name":"+1 Twitchy","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('qsOHsbKMonl9tiaq',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"o7BidBvPsCmUxWnb","name":"+1 Vocalization Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('x0YRvBbVoHPILD6x',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZeHhiHDz9hSRfKKq","name":"+1 Worship Danger","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('ZIYe2ULX7AKP5MVI',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"gVR2dbgBFypZ1M9m","name":"+1d10 Combat","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.combat.value',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ur6kX3P3xHVaEQpB","name":"+1d10 Fear Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.fear.value',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"YqqXUAVyWiUkOzMJ","name":"+1d10 Maximum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.max',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"0dFnFfJtZt6a0ih4","name":"+1d10 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"BnQZTR7V7va8WRGO","name":"+1d5 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"WEICDPMGI3waJ6PX","name":"+2 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',2,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"tqvhwdQ7eqzVQmMO","name":"+2d10 Body Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.body.value',null,'2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"iyFZyThqdvBQ43KG","name":"+2d10 Speed","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.speed.value',null,'2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"sUBAlHB1OcA4h185","name":"+2d10 Strength","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.strength.value',null,'2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZcqUtSMCGvERjQlG","name":"+3 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',3,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"pZDIIFKNOo3wIelH","name":"-1 Minimum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.min',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"egXQ98YOVTaIvw8Z","name":"-1 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"nLbL5WG3o55pQHVt","name":"-1 Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.hits.value',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"4G0yEepSUvif6b6r","name":"-1d10 Body Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.body.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZHLgJKrIG82SNbt8","name":"-1d10 Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"P1XjeNN1XswJ2nSC","name":"-1d10 Intellect","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.intellect.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"FGraO3xTnChUfWGY","name":"-1d10 Maximum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.max',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5jMEd9JjJPIJBKHr","name":"-1d10 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"m0X0cPbdEy9xWfQ2","name":"-1d5 Sanity Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.sanity.value',null,'-1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"M91INKwIL3rOZBcx","name":"-1d5 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'-1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"fRja0aFO5muR0q3H","name":"-2 Maximum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.max',-2,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"qENogEcf1awpT98o","name":"-5 Intellect","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.intellect.value',-5,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"VZPWorbauAExrYLZ","name":"-5 Speed","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.speed.value',-5,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"k663ybRMCY3u0OXF","name":"-5 Strength","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.strength.value',-5,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lggrLQD14n5dmWOW","name":"Body Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','body',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"WRtYAbOhyR7K7oCF","name":"Body Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','body',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8oU8H31xWldZB5mR","name":"Body Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','body',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5N4b4Q2OhEj1zv0P","name":"Combat Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','combat',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"N20OKT1TDhywkeco","name":"Combat Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','combat',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"voAUUe17Qw4MJlup","name":"Combat Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','combat',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"4hmYrNF0uWVqsfEk","name":"Death Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table0eDeath'),`1d10 [-]`,`high`,false,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Az3RocMlh0JFxAlu","name":"Death Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table0eDeath'),`1d10 [+]`,`high`,false,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Er4ULzvdn2urxuet","name":"Fear Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','fear',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"RdJ2nh41wDUT4ZTP","name":"Fear Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','fear',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"RzOmeM0RNSpFAna0","name":"Fear Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','fear',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"iah49MKBQXykdwEg","name":"Intellect Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','intellect',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"XveTnYVPtLcgJEGf","name":"Intellect Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','intellect',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AhrhCp1Tz8ZaLhby","name":"Intellect Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','intellect',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"31nDVp25qvTkkGXQ","name":"Lower Health to 1","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this token\n let curValue = game.user.character.system.health.value;\n //calculate difference\n let lowerBy = 1 - curValue;\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.health.value',lowerBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.health.value;\n //calculate difference\n let lowerBy = 1 - curValue;\n //run the function on this token\n token.actor.modifyActor('system.health.value',lowerBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"3AADaQaHl78Og7aR","name":"Lower Minimum Stress to 2","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this token\n let curValue = game.user.character.system.other.stress.min;\n //calculate difference\n let lowerBy = 2 - curValue;\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.other.stress.min',lowerBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.other.stress.min;\n //calculate difference\n let lowerBy = 2 - curValue;\n //run the function on this token\n token.actor.modifyActor('system.other.stress.min',lowerBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8MYFWpBYht987SZm","name":"Lower Wounds to 0","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this token\n let curValue = game.user.character.system.hits.value;\n //calculate difference\n let lowerBy = 0 - curValue;\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.hits.value',lowerBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.hits.value;\n //calculate difference\n let lowerBy = 0 - curValue;\n //run the function on this token\n token.actor.modifyActor('system.hits.value',lowerBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ruNXfSNPSJmY4SE2","name":"Panic Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(`panicCheck`,`[-]`,null,false,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lCEvKZVAMkfJHAXl","name":"Panic Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(`panicCheck`,`[+]`,null,false,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"z5V92LyXHjfMxnRQ","name":"Raise Maximum Calm to 85","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this character\n let curValue = game.user.character.system.other.stress.max;\n //calculate difference\n let raiseBy = 85 - curValue;\n //zero out if negative\n if (raiseBy < 0) {raiseBy = 0;}\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.other.stress.max',raiseBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.other.stress.max;\n //calculate difference\n let raiseBy = 85 - curValue;\n //zero out if negative\n if (raiseBy < 0) {raiseBy = 0;}\n //run the function on this token\n token.actor.modifyActor('system.other.stress.max',raiseBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"GprYY2FK5Y5Xddvk","name":"Raise Minimum Stress to 5","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this character\n let curValue = game.user.character.system.other.stress.min;\n //calculate difference\n let raiseBy = 5 - curValue;\n //zero out if negative\n if (raiseBy < 0) {raiseBy = 0;}\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.other.stress.min',raiseBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.other.stress.min;\n //calculate difference\n let raiseBy = 5 - curValue;\n //zero out if negative\n if (raiseBy < 0) {raiseBy = 0;}\n //run the function on this token\n token.actor.modifyActor('system.other.stress.min',raiseBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"WAPt73hfeft7m19K","name":"Rest Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','restSave',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"81hTf1Du6PRu28wj","name":"Rest Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','restSave',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"a7iEwMDULoi6CdkU","name":"Roll 1d10 on Android Panic Table","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table0ePanicStressAndroid'),`1d10`,`high`,false,false,'system.other.stress.value','>');","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"iBXpuINls8gKcvk5","name":"Roll on Android Panic Table","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table0ePanicStressAndroid'),`2d10`,`high`,false,false,'system.other.stress.value','>');","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"a6hO0gUht5v0aDqj","name":"Roll on Panic Table","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table0ePanicStressNormal'),`2d10`,`high`,false,false,'system.other.stress.value','>');","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Dua2j9hZpTLCbxXU","name":"Sanity Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','sanity',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"tYduVcRgKAdFAZ6l","name":"Sanity Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','sanity',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"MKl9Q4poMvwpVL8v","name":"Sanity Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','sanity',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Sg8rTwkExTpF4HHp","name":"Speed Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','speed',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lfehxXMWB7kGhrjn","name":"Speed Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','speed',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"0Yw4QWSAeOuUzRqB","name":"Speed Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','speed',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"cbCtuBYXwQOR0ZaB","name":"Strength Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','strength',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Jsj2jOwoLTdyXP8z","name":"Strength Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','strength',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lBDQAgzfJGadClAT","name":"Strength Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','strength',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/macros_triggered_0e/000036.ldb b/packs/macros_triggered_0e/000036.ldb new file mode 100644 index 0000000..471f420 Binary files /dev/null and b/packs/macros_triggered_0e/000036.ldb differ diff --git a/packs/macros_triggered_0e/000040.log b/packs/macros_triggered_0e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_triggered_0e/CURRENT b/packs/macros_triggered_0e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/macros_triggered_0e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/macros_triggered_0e/LOCK b/packs/macros_triggered_0e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_triggered_0e/LOG b/packs/macros_triggered_0e/LOG new file mode 100644 index 0000000..3ad57bd --- /dev/null +++ b/packs/macros_triggered_0e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.592976 170d5b000 Recovering log #38 +2026/03/31-15:50:48.593456 170d5b000 Delete type=0 #38 +2026/03/31-15:50:48.593476 170d5b000 Delete type=3 #37 diff --git a/packs/macros_triggered_0e/LOG.old b/packs/macros_triggered_0e/LOG.old new file mode 100644 index 0000000..2131479 --- /dev/null +++ b/packs/macros_triggered_0e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.565839 1707cf000 Recovering log #34 +2026/03/29-21:14:27.566214 1707cf000 Delete type=3 #32 +2026/03/29-21:14:27.566242 1707cf000 Delete type=0 #34 diff --git a/packs/macros_triggered_0e/MANIFEST-000039 b/packs/macros_triggered_0e/MANIFEST-000039 new file mode 100644 index 0000000..2336878 Binary files /dev/null and b/packs/macros_triggered_0e/MANIFEST-000039 differ diff --git a/packs/macros_triggered_0e/lost/000020.log b/packs/macros_triggered_0e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_triggered_0e/lost/MANIFEST-000018 b/packs/macros_triggered_0e/lost/MANIFEST-000018 new file mode 100644 index 0000000..5c19ffb Binary files /dev/null and b/packs/macros_triggered_0e/lost/MANIFEST-000018 differ diff --git a/packs/macros_triggered_1e.db b/packs/macros_triggered_1e.db new file mode 100644 index 0000000..65c0adb --- /dev/null +++ b/packs/macros_triggered_1e.db @@ -0,0 +1,151 @@ +{"_id":"hzxRycVkMhNS6gyJ","name":"+1 Anhedonia","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('JM9PnNw2HVWcAfOX',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"YYmZYNe8RWvhDFDz","name":"+1 Bit Rot","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('H1dqOrGg0voG2DmC',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"BH7tgbDVH6jdcZ4u","name":"+1 Bleeding","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pxtF1NfletmoFFGV',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8VoaVAl39Xs0pDcr","name":"+1 Broken","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('ZXyoVuMAsEDmU5Qi',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"b0jk4XwP7by8a3uc","name":"+1 Coward","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('YIF9QkUlexxauSCE',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Yh2CTFXfWMe9o2lv","name":"+1 Death Wish","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('srws3n4rpl4oCj83',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"2aD5avpn35wdzdm5","name":"+1 Deflated","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('waimTU6LXaADcJrT',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"6PU4hmYOjHk4N0SY","name":"+1 Deviant Logic Core","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('PTK6ds7eJvJDonbp',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8IPhlAuMEQJC6zxA","name":"+1 Doomed","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('x41AwiI03h7wNjaM',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"tdQu2wnAXXXcXfrO","name":"+1 Emotional Detachment","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('iiiAIZvpfUUNai74',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"sSYIhNQhEiWTs1ip","name":"+1 Escapism","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('qejBMjd8niz1y3Zi',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"WAyrlgcyR4I19Bqv","name":"+1 Ethical Directive Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pe7ChrErjX6N57VP',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"9sKO5WUBwCW1YbR3","name":"+1 Ethical Directive Misread","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('OBpJQ7uYIj3KezNc',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"zLRsweb35Lw0NMev","name":"+1 Faulty Heuristics","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('uPVp78kHmvMSYx2F',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"NDjuBKnMVPgJePNq","name":"+1 Fried Logic Core","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('kYdj6XJlPvJAhBEN',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"BEQvMZ5N7QOBqnId","name":"+1 Frightened","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('z0avrplKe6M0RcXk',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Z7XPRgpTQqqi4M1n","name":"+1 Hallucinations","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('oTafwWjoNOE7nBrj',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Eo56QFyTeoCcFmD8","name":"+1 Haunted","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('olC4JytslvUrQN8g',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dSQgoBV6zSeQ1tqF","name":"+1 Hypervigilance","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('tGYYK71q2QxnPtpL',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"FTB2KHEbe7ApCilw","name":"+1 Insane","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('0ZAwhewvLBwX3opf',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"tQltbIC9ahDwNsTp","name":"+1 Killswitch Engaged","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('g6CuxCqbyRnNa57N',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"4Ak3WH8lzzkds6yo","name":"+1 Losing Your Grip","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('kNjz3I0yAYkt9CV0',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"54Krt3opbJe1WATH","name":"+1 Loss of Confidence","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('kbbVOYgjwzoODs7N',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"BmEHWH7YxV9qb21p","name":"+1 Minimum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.min',1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AZbaGWu663wio9mI","name":"+1 Nightmares","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('MLPSYfWrwY6R7JDy',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lto7Vq1jb7DBScuu","name":"+1 Panicky","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('EW7X6FfetwxmZDzf',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"RTL29CqdaAriGSTS","name":"+1 Phobia","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('NuzL7Yi7PvUOeWsj',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"er0IZXOSuF28Po1h","name":"+1 Psychotic Episodes","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('og4lXN03vH5pwSDC',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"wXobG3sUiQMLtGQs","name":"+1 Rampancy","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('lXoBqGW2eCK0b1tX',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AqZ9JqENaPSmFQbK","name":"+1 Recurring Nightmares","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('S2kZpUl3nNPS4wNS',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"xQQmaFbpFFrCSyji","name":"+1 Sanity Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.sanity.value',1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"LAXDz9nMvSSO3qzZ","name":"+1 Severe Anxiety","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('CPRLqpW9inXDLYjS',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"HhofJYVhx3ovuyAw","name":"+1 Social Anxiety","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('hskhRKLEAJN7huAk',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"L4gRfMiEaxm3Xda5","name":"+1 Software Bloat","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('dA6COSDLbpmKdOkm',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"3AjUWUSRvYy8Mwji","name":"+1 Spiraling","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('Bt2rl2c5jGyt3QAr',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dvJR9DYXI2kV0BbR","name":"+1 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5K7wZEvEXjOH4IM7","name":"+1 Suspicious","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('8lOkseRbg09YFvv7',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"DsmTMGHs92cmwlVk","name":"+1 The Shakes","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('d3KlY4zMdD1j3CTW',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"djzdZtIjROXN1dVB","name":"+1 Threat Assessment Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('HZBI88iwvtQVWKOR',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"3nrEYqwkhMs1Ch5v","name":"+1 Turing Test Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('a87x3Hk72ymOx5rf',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Sez3VnhWliRmsxze","name":"+1 Twitchy","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('kiJyYYxzy5TdjTfS',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"bJWFhod0YA8ln8H8","name":"+1 Vocalization Failure","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('ZO4f9gvaiVSKDmRC',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"wHcA2ub6CobipsfR","name":"+1 Worship Danger","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('LDoAzwiELtLjgxrf',1);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"hNdUPkEYauPuCHcm","name":"+1d10 Combat","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.combat.value',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"06j3tzX29f4pwYwh","name":"+1d10 Fear Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.fear.value',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"f8Q9FCZsnUyAbczE","name":"+1d10 Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.value',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8om45xDZUwCLNTNq","name":"+1d10 Maximum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.max',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"k2TtLFOG9mGaWVx3","name":"+1d10 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"luNKvwmm2tjUJhT6","name":"+1d5 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"IIVNXuhckFQfzXah","name":"+2 Bleeding","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pxtF1NfletmoFFGV',2);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"bFPoNLOGusT1ocqt","name":"+2 Minimum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.min',2,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"6jjFVScyiaBvN8kX","name":"+2 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',2,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"X8QFfHssG9ievzau","name":"+2d10 Body Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.body.value',null,'2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"0K2qqtpYr4ZN7I87","name":"+2d10 Speed","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.speed.value',null,'2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"YddW6GtkOZ4bWFBo","name":"+2d10 Strength","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.strength.value',null,'2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"LawygQJAPu8XEnSc","name":"+3 Bleeding","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pxtF1NfletmoFFGV',3);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"QkCJK7Vmda5bGAA7","name":"+4 Bleeding","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pxtF1NfletmoFFGV',4);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"CZ2gqnRHcOpCLlG0","name":"+5 Bleeding","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pxtF1NfletmoFFGV',5);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Tx19z2BhTY6onldp","name":"+6 Bleeding","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pxtF1NfletmoFFGV',6);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZJaVFBB0Kslv1k4f","name":"+7 Bleeding","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyItem('pxtF1NfletmoFFGV',7);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"V1PPeCwryXNQAkUe","name":"-1 All Stats/Saves","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepRadiationDamage();\n\n//tell the actor to run the function\nasync function prepRadiationDamage() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.takeRadiationDamage();\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.takeRadiationDamage();\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vwpxRBbMwjfDCQVG","name":"-1 Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.value',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"qD8Mvegkf3zVarFr","name":"-1 Maximum Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.hits.max',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"yZE4YhJ5E13zjDXG","name":"-1 Minimum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.min',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"qbq694JMbXeZrHjj","name":"-1 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"p7tp3aMkcVLAhiD5","name":"-1 Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.hits.value',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"C9iTlPOpROuuYi2F","name":"-10 Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.value',-10,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"nT2AsZwrYhJyxizF","name":"-1d10 Body Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.body.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"w3ttEaXP7yp25M5Q","name":"-1d10 Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"oYSjanH7BmmweIpp","name":"-1d10 Intellect","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.intellect.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"J61Srent4vEthGAn","name":"-1d10 Maximum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.max',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"V3L1iRkWwyTzCZK9","name":"-1d10 Strength","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.strength.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"jHyqXb2yDFTNWxpy","name":"-1d10 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"yYujq1tBZPqGrQlh","name":"-1d5 Maximum Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.max',null,'-1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"xNLdumzjtYwQmBeP","name":"-1d5 Sanity Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.sanity.value',null,'-1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AvKZE5IFubIaAIUy","name":"-1d5 Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.value',null,'-1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"eoGfi5JdPASUUJU4","name":"-2 Maximum Stress","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.other.stress.max',-2,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ISd2nEMYvWCPQpl0","name":"-2d10 Body Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.body.value',null,'-2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"pS6A6OklvM6S3bvO","name":"-2d10 Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.value',null,'-2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"nECUu4pcwsNTE8C5","name":"-3d10 Health","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.health.value',null,'-3d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"1DD8i6eCS6nx2Ip0","name":"Bleeding Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundBleeding'),`1d10`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"tFcWNddtZvlv7tsg","name":"Bleeding Wound -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundBleeding'),`1d10 [-]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"xr2o2PU5vdrR6fxQ","name":"Bleeding Wound +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundBleeding'),`1d10 [+]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"TAjlQjA5AAy3qYL3","name":"Blunt Force Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundBluntForce'),`1d10`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"oL3GH0HoEPlP8vzG","name":"Blunt Force Wound -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundBluntForce'),`1d10 [-]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"k0zf8ZGivRguc0wb","name":"Blunt Force Wound +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundBluntForce'),`1d10 [+]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"X3gqTFFwMe7AudiS","name":"Body Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','body',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ItHLy3URKFQVLipe","name":"Body Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','body',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"IG2NQgEnqvPjiV5C","name":"Body Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','body',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"9FOBS5lQCwtVtrgh","name":"Combat Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','combat',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vxcDSg3xiAxDYQIb","name":"Combat Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','combat',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5hlvK0p68imanBmy","name":"Combat Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','combat',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"E2bDXSVfH57BnGEI","name":"Death Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eDeath'),`1d10 [-]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"KHL2lJ6RRvhupFZ3","name":"Death Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eDeath'),`1d10 [+]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"R2KizR1soAhFYDZm","name":"Fear Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','fear',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"wVhApjRP5MXue2kh","name":"Fear Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','fear',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"DadBoZJblU4uBY5E","name":"Fear Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','fear',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"bZi1qKmcKLFvnhZ2","name":"Fire & Explosives Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundFireExplosives'),`1d10`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"dJnQKDf0AlwK27QD","name":"Fire & Explosives Wound -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundFireExplosives'),`1d10 [-]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"7rYhbDAaFeok1Daq","name":"Fire & Explosives Wound +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundFireExplosives'),`1d10 [+]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"S9nnHKWYGSQmjQdp","name":"Gore & Massive Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundGoreMassive'),`1d10`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"DuVjNlE4lsnR7Emc","name":"Gore & Massive Wound -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundGoreMassive'),`1d10 [-]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"eQPuDgwv8evetFIk","name":"Gore & Massive Wound +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundGoreMassive'),`1d10 [+]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"XgCOLv9UunBddUyW","name":"Gunshot Wound","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundGunshot'),`1d10`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"fnVATRHYJEUlS3pR","name":"Gunshot Wound -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundGunshot'),`1d10 [-]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"LTpa1ZYVZl4m9k6z","name":"Gunshot Wound +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1eWoundGunshot'),`1d10 [+]`,`low`,true,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"DMjVDa7vUq7xGpn8","name":"Intellect Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','intellect',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ln3OpNFK4mN4Ym5q","name":"Intellect Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','intellect',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"DXfAjkwJVwSCOqZ1","name":"Intellect Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','intellect',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"EwZbGIwHB3JuRvx5","name":"Panic Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(`panicCheck`,`[-]`,null,false,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kVNV9vZPY0j77VTo","name":"Panic Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(`panicCheck`,`[+]`,null,false,false,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AM9nIK5l7mC5Ho8C","name":"Rest Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','restSave',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ZaChBhkd4yU6hoWx","name":"Rest Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','restSave',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"yPGx2mXToJ2iJPbY","name":"Roll 1d10 on Android Panic Table","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1ePanicStressAndroid'),`1d10`,`high`,false,false,'system.other.stress.value','>');","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Jek7hKAMDevKxlZR","name":"Roll on Android Panic Table","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1ePanicStressAndroid'),`1d20`,`high`,false,false,'system.other.stress.value','>');","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"2DnKZpyj03HvpeCy","name":"Roll on Panic Table","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollTable(game.settings.get('mosh','table1ePanicStressNormal'),`1d20`,`high`,false,false,'system.other.stress.value','>');","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"TkMfT4RIczQb56j2","name":"Sanity Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','sanity',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"MdmZ31pKu1q006z7","name":"Sanity Save -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','sanity',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"p6JhfjAF7OESZiFM","name":"Sanity Save +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','sanity',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"Sdad2njbBKNpOCO8","name":"Raise Maximum Stress to 85","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this character\n let curValue = game.user.character.system.other.stress.max;\n //calculate difference\n let raiseBy = 85 - curValue;\n //zero out if negative\n if (raiseBy < 0) {raiseBy = 0;}\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.other.stress.max',raiseBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.other.stress.max;\n //calculate difference\n let raiseBy = 85 - curValue;\n //zero out if negative\n if (raiseBy < 0) {raiseBy = 0;}\n //run the function on this token\n token.actor.modifyActor('system.other.stress.max',raiseBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"hF2Vnb8Pzn7geCcJ","name":"Lower Minimum Stress to 2","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this token\n let curValue = game.user.character.system.other.stress.min;\n //calculate difference\n let lowerBy = 2 - curValue;\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.other.stress.min',lowerBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.other.stress.min;\n //calculate difference\n let lowerBy = 2 - curValue;\n //run the function on this token\n token.actor.modifyActor('system.other.stress.min',lowerBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"YLitGkgwIi8GqFAg","name":"Lower Wounds to 0","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this token\n let curValue = game.user.character.system.hits.value;\n //calculate difference\n let lowerBy = 0 - curValue;\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.hits.value',lowerBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.hits.value;\n //calculate difference\n let lowerBy = 0 - curValue;\n //run the function on this token\n token.actor.modifyActor('system.hits.value',lowerBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"uxrWvijfqDVnaXMj","name":"Speed Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','speed',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"QZHhiDAr7owozxdf","name":"Speed Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','speed',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"WzsVrS0brblqWhMR","name":"Speed Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','speed',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"B9qe0UHmKoal9eub","name":"Strength Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100','low','strength',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"XlfEeDblsp7fTzUx","name":"Strength Check -","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [-]','low','strength',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"9X5WPlXiZn9EqF9f","name":"Strength Check +","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initRollCheck('1d100 [+]','low','strength',null,null,null);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"aur5HWqZJNspwdCd","name":"Take Bleeding Damage","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepBleedingDamage();\n\n//tell the actor to run the function\nasync function prepBleedingDamage() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.takeBleedingDamage();\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.takeBleedingDamage();\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"SeMStXQGIaeiLwvw","name":"-1d5 All Stats/Saves","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepCryoDamage();\n\n//tell the actor to run the function\nasync function prepCryoDamage() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.takeCryoDamage('-1d5');\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.takeCryoDamage('-1d5');\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"2MuANcdgp2g8SDlF","name":"-1d10 All Stats/Saves","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepCryoDamage();\n\n//tell the actor to run the function\nasync function prepCryoDamage() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.takeCryoDamage('-1d10');\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.takeCryoDamage('-1d10');\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"8euTBbjY9uDQR13K","name":"Maintenance Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMaintenanceCheck();\n\n//tell the actor to run the function\nasync function prepMaintenanceCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.maintenanceCheck();\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.maintenanceCheck();\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"C04VbNoj8LgfY8QK","name":"Maintenance Check [-]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMaintenanceCheck();\n\n//tell the actor to run the function\nasync function prepMaintenanceCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollTable(`maintenanceCheck`,`1d100 [-]`,`low`,null,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollTable(`maintenanceCheck`,`1d100 [-]`,`low`,null,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"g5hyNqBioTNe5TGx","name":"Maintenance Check [+]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMaintenanceCheck();\n\n//tell the actor to run the function\nasync function prepMaintenanceCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollTable(`maintenanceCheck`,`1d100 [+]`,`low`,null,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollTable(`maintenanceCheck`,`1d100 [+]`,`low`,null,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"RZdvjsMBaSKcs3Ot","name":"Morale Check","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMoraleCheck();\n\n//tell the actor to run the function\nasync function prepMoraleCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.moraleCheck();\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.moraleCheck();\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"wrfA9gVG0OdZhvOT","name":"Morale Check [-]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMoraleCheck();\n\n//tell the actor to run the function\nasync function prepMoraleCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollCheck(`1d10 [-]`,`high-equal`,`moraleCheck`,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollCheck(`1d10 [-]`,`high-equal`,`moraleCheck`,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"vCkDdHtJJmYkq3wK","name":"Morale Check [+]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMoraleCheck();\n\n//tell the actor to run the function\nasync function prepMoraleCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollCheck(`1d10 [+]`,`high-equal`,`moraleCheck`,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollCheck(`1d10 [+]`,`high-equal`,`moraleCheck`,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"g5FXFSnlyU5KmwCz","name":"Starting Condition","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMaintenanceCheck();\n\n//tell the actor to run the function\nasync function prepMaintenanceCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.maintenanceCheck();\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.maintenanceCheck();\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"33LAJdyYr0xi4TdF","name":"Starting Condition [-]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMaintenanceCheck();\n\n//tell the actor to run the function\nasync function prepMaintenanceCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollTable(`maintenanceCheck`,`1d100 [-]`,`low`,null,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollTable(`maintenanceCheck`,`1d100 [-]`,`low`,null,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"TnuezRDCUlw4cDvG","name":"Starting Condition [+]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMaintenanceCheck();\n\n//tell the actor to run the function\nasync function prepMaintenanceCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollTable(`maintenanceCheck`,`1d100 [+]`,`low`,null,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollTable(`maintenanceCheck`,`1d100 [+]`,`low`,null,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"S6sYho89Bp5tMlsJ","name":"Bankruptcy Save","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepBankruptcySave();\n\n//tell the actor to run the function\nasync function prepBankruptcySave() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.bankruptcySave();\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.bankruptcySave();\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"5ewwn221Wo1JQ98k","name":"Bankruptcy Save [-]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepBankruptcySave();\n\n//tell the actor to run the function\nasync function prepBankruptcySave() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollCheck(`1d100 [-]`,`low`,`bankruptcySave`,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollCheck(`1d100 [-]`,`low`,`bankruptcySave`,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"sc6UPaBF5A4Yl27h","name":"Bankruptcy Save [+]","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepBankruptcySave();\n\n//tell the actor to run the function\nasync function prepBankruptcySave() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollCheck(`1d100 [+]`,`low`,`bankruptcySave`,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollCheck(`1d100 [+]`,`low`,`bankruptcySave`,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"X3cL9eS2HOPxhLH5","name":"-1d10 Battle","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.battle.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"oDftFxRKkCQRNY2O","name":"-1d10 Systems","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.systems.value',null,'-1d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"DUuRY7kHKd7n5luv","name":"-50% Crew Capacity","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepModifyActor();\n\n//tell the actor to run the function\nasync function prepModifyActor(fieldAddress,modValue,modRollString,outputChatMsg) {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //get the health for this token\n let curValue = game.user.character.system.supplies.crew.max;\n //calculate difference\n let lowerBy = Math.ceil(curValue/2)*-1;\n //run the function for the player's 'Selected Character'\n game.user.character.modifyActor('system.supplies.crew.max',lowerBy,null,true);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noCharSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n //get the health for this token\n let curValue = token.actor.system.supplies.crew.max;\n //calculate difference\n let lowerBy = Math.ceil(curValue/2)*-1;\n //run the function on this token\n token.actor.modifyActor('system.supplies.crew.max',lowerBy,null,true);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"uPY19Y49bGCLGK3N","name":"-1 Hull","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.supplies.hull.value',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"06NSvDYTtmkeUtLq","name":"-1 Upgrade","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.supplies.upgrades.value',-1,null,true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"u7TchSo3qutnzaKF","name":"-1d5 Oxygen","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.oxygen.value',null,'-1d5',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"jmOh8n2ps0YIeBC0","name":"-2d10 Thrusters","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"game.mosh.initModifyActor('system.stats.thrusters.value',null,'-2d10',true);","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"hRapiXGVW8WZQH12","name":"Roll on Maintenance Issues Table","type":"script","scope":"global","img":"icons/svg/d10-grey.svg","command":"prepMaintenanceCheck();\n\n//tell the actor to run the function\nasync function prepMaintenanceCheck() {\n //determine who to run the macro for\n if (game.settings.get('mosh','macroTarget') === 'character') {\n //is there a selected character? warn if no\n if (!game.user.character || !game.user.character.type === 'ship') {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for the player's 'Selected Character'\n game.user.character.rollTable(`maintenanceCheck`,`1d100`,`low`,null,null,null,null);\n }\n } else if (game.settings.get('mosh','macroTarget') === 'token') {\n //is there a selected character? warn if no\n if (!canvas.tokens.controlled.length) {\n //warn player\n game.mosh.noShipSelected();\n } else {\n //run the function for all selected tokens\n canvas.tokens.controlled.forEach(function(token){\n token.actor.rollTable(`maintenanceCheck`,`1d100`,`low`,null,null,null,null);\n });\n }\n }\n}","folder":null,"flags":{},"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/macros_triggered_1e/000036.ldb b/packs/macros_triggered_1e/000036.ldb new file mode 100644 index 0000000..394ff7b Binary files /dev/null and b/packs/macros_triggered_1e/000036.ldb differ diff --git a/packs/macros_triggered_1e/000040.log b/packs/macros_triggered_1e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_triggered_1e/CURRENT b/packs/macros_triggered_1e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/macros_triggered_1e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/macros_triggered_1e/LOCK b/packs/macros_triggered_1e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_triggered_1e/LOG b/packs/macros_triggered_1e/LOG new file mode 100644 index 0000000..3325a50 --- /dev/null +++ b/packs/macros_triggered_1e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.594786 171567000 Recovering log #38 +2026/03/31-15:50:48.595201 171567000 Delete type=0 #38 +2026/03/31-15:50:48.595227 171567000 Delete type=3 #37 diff --git a/packs/macros_triggered_1e/LOG.old b/packs/macros_triggered_1e/LOG.old new file mode 100644 index 0000000..a23b33d --- /dev/null +++ b/packs/macros_triggered_1e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.567335 170fdb000 Recovering log #34 +2026/03/29-21:14:27.567720 170fdb000 Delete type=3 #32 +2026/03/29-21:14:27.567753 170fdb000 Delete type=0 #34 diff --git a/packs/macros_triggered_1e/MANIFEST-000039 b/packs/macros_triggered_1e/MANIFEST-000039 new file mode 100644 index 0000000..559f35c Binary files /dev/null and b/packs/macros_triggered_1e/MANIFEST-000039 differ diff --git a/packs/macros_triggered_1e/lost/000020.log b/packs/macros_triggered_1e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/macros_triggered_1e/lost/MANIFEST-000018 b/packs/macros_triggered_1e/lost/MANIFEST-000018 new file mode 100644 index 0000000..8c1d829 Binary files /dev/null and b/packs/macros_triggered_1e/lost/MANIFEST-000018 differ diff --git a/packs/rolltables_0e.db b/packs/rolltables_0e.db new file mode 100644 index 0000000..7356987 --- /dev/null +++ b/packs/rolltables_0e.db @@ -0,0 +1,5 @@ +{"_id":"cZOHlhEJcYGZsQBM","name":"Death Save","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","description":"

    Whenever you reach 0 Health, make a Body Save: Failure means you die. Success means you fall unconscious, make a Death Save to find out when you regain consciousness. Crew members with a medscanner, relevant skills like First Aid or Biology, or scientists and androids who pass an Intellect Check can determine your condition.

    ","formula":"1d10","replacement":true,"displayRoll":true,"results":[ {"_id":"BeGMLNZIYhH9Kk49","type":0,"documentCollection":"null","documentId":"null","text":"You are comatose and brain-dead. Only extraordinary measures will return you to the waking world.","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"9EhaHZAAGcpGMnIJ","type":0,"documentCollection":"null","documentId":"null","text":"Wake in [[/r 1d10]] days, with 1 Health. -5 Strength, -5 Speed, -5 Intellect (permanent loss). Disadvantage on all rolls for [[/r 1d10]] days. +1d10 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.31nDVp25qvTkkGXQ]{Lower Health to 1}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.k663ybRMCY3u0OXF]{-5 Strength}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.VZPWorbauAExrYLZ]{-5 Speed}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.qENogEcf1awpT98o]{-5 Intellect}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.0dFnFfJtZt6a0ih4]{+1d10 Stress}","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[2,3],"drawn": false}, {"_id":"uGHUqa42KpSYkP31","type":0,"documentCollection":"null","documentId":"null","text":"Wake in [[/r 1d10]] hours. 1 Health. -5 Strength, and -5 Speed (permanent loss). Disadvantage on all rolls for [[/r 1d10]] hours. +3 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.31nDVp25qvTkkGXQ]{Lower Health to 1}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.k663ybRMCY3u0OXF]{-5 Strength}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.VZPWorbauAExrYLZ]{-5 Speed}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.ZcqUtSMCGvERjQlG]{+3 Stress}","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[4,6],"drawn": false}, {"_id":"z7WuF36CDjDa64g8","type":0,"documentCollection":"null","documentId":"null","text":"Wake in [[/r 1d10]] minutes. 1 Health. -5 Strength (permanent loss). Disadvantage on all rolls for [[/r 3d10]] minutes. +2 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.31nDVp25qvTkkGXQ]{Lower Health to 1}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.k663ybRMCY3u0OXF]{-5 Strength}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WEICDPMGI3waJ6PX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[7,9],"drawn": false}, {"_id":"ClE7nNEIW7D3Q5Bh","type":0,"documentCollection":"null","documentId":"null","text":"Wake immediately. 1 Health. Disadvantage on all rolls for [[/r 1d10]] minutes. +1 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.31nDVp25qvTkkGXQ]{Lower Health to 1}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.GodJbchiu5gOgtkn]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[10,10],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"1vCm4ElRPotQXgNB","name":"Panic Check (Stress, Normal)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Eventually, Stress, Damage and emotional wear and tear will bring you to your breaking point. When that happens there’s a chance that you’ll lose control and Panic. To determine whether you are able to keep your cool under extreme pressure, make a Panic Check. While the results are primarily negative there is the possibility of grace under fire.

    ","formula":"2d10 + @other.stress.value - @other.resolve.value","replacement":true,"displayRoll":true,"results":[ {"_id":"gjINwaOSGbiQf15s","type":0,"documentCollection":"null","documentId":"null","text":"Laser Focus. Advantage on all rolls for the next [[/r 1d10]] hours.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[2,3],"drawn": false}, {"_id":"wii7XKePcKZKLVHx","type":0,"documentCollection":"null","documentId":"null","text":"Major Adrenaline Rush. Advantage on all rolls for the next [[/r 3d10]] minutes.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[4,5],"drawn": false}, {"_id":"bV0AaE9jq7s2AmjB","type":0,"documentCollection":"null","documentId":"null","text":"Minor Adrenaline Rush. Advantage on all rolls for the next [[/r 1d10]] minutes.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[6,7],"drawn": false}, {"_id":"PZrg6c1p4Xr0cqlq","type":0,"documentCollection":"null","documentId":"null","text":"Anxious. Gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.GodJbchiu5gOgtkn]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[8,9],"drawn": false}, {"_id":"aTLuigXTQpFTx9Cz","type":0,"documentCollection":"null","documentId":"null","text":"Nervous Twitch. Gain 2 Stress. The nearest crew member also gains 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WEICDPMGI3waJ6PX]{+2 Stress}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.GodJbchiu5gOgtkn]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[10,11],"drawn": false}, {"_id":"hxZEEMqmwAFHNKyF","type":0,"documentCollection":"null","documentId":"null","text":"Cowardice. Gain 1 Stress. For the next [[/r 1d10]] hours you must make a Fear Save to engage in combat or else flee.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.GodJbchiu5gOgtkn]{+1 Stress}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.bivbH22VbRq3YUsz]{+1 Cowardice}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[12,13],"drawn": false}, {"_id":"Crrcasmzj7y9XUnN","type":0,"documentCollection":"null","documentId":"null","text":"Hallucinations. For the next [[/r 2d10]] hours (determined secretly) you have trouble distinguishing between reality and fantasy.<><>@UUID[Compendium.mosh.macros_triggered_0e.Macro.TUkbH9np5Zj6DPHX]{+1 Hallucinations}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[14,15],"drawn": false}, {"_id":"zfG2mvPccJzn8dct","type":0,"documentCollection":"null","documentId":"null","text":"Crippling Fear. Gain a new permanent phobia. Whenever you encounter this phobia make a Fear Save at Disadvantage or gain 1d10 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.qwmJTfTgmjNEApfX]{+1 Phobia}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[16,17],"drawn": false}, {"_id":"bWvfXFmnaFVNKEbM","type":0,"documentCollection":"null","documentId":"null","text":"Overwhelmed. Gain 1d10 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.0dFnFfJtZt6a0ih4]{+1d10 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[18,19],"drawn": false}, {"_id":"eIHnn5v4D9ylqKFj","type":0,"documentCollection":"null","documentId":"null","text":"Rattled. Let out a blood-curdling scream. Disadvantage on all rolls for [[/r 2d10]] minutes.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[21,21],"drawn": false}, {"_id":"dUPFZ24CDjDBRaiG","type":0,"documentCollection":"null","documentId":"null","text":"Paranoid. For the next [[/r 1d10]] days, whenever a character joins your group (even if they only left for a short period of time), make a Fear Save or gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.s7rHLmODfmUMGr65]{+1 Paranoid}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[22,22],"drawn": false}, {"_id":"YnUIrPXx6puT44yd","type":0,"documentCollection":"null","documentId":"null","text":"Death Drive. For the next [[/r (@other.stress.value)d10]]{Xd10} days (where X=Stress) whenever you encounter a stranger or known enemy you must make a Sanity Save or else immediately attack them.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.UcHSw6s1TkqSEj7Y]{+1 Death Drive}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[23,23],"drawn": false}, {"_id":"oVDIQ0ZVwsOP73ZZ","type":0,"documentCollection":"null","documentId":"null","text":"Catatonic. Become unresponsive and unmoving for [[/r (@other.stress.value)d10]]{Xd10} minutes (where X=Stress).","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[24,24],"drawn": false}, {"_id":"gKxVByejEy2c51yz","type":0,"documentCollection":"null","documentId":"null","text":"Broken. For the next [[/r (@other.stress.value)d10]]{Xd10} days (where X=Stress) make a Panic Check whenever a nearby crew member fails a Save.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WnHQfgURx5sGWjlx]{+1 Broken}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[25,25],"drawn": false}, {"_id":"DOJz9VI7dJeAq0BL","type":0,"documentCollection":"null","documentId":"null","text":"Psychotic. Immediately attack the closest crew member until you do at least [[/r 2d10]] Damage. If there is no crew member nearby you attack the environment.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[26,26],"drawn": false}, {"_id":"aJTpD1gYWkGfVJld","type":0,"documentCollection":"null","documentId":"null","text":"Compounding Problems. Roll twice on this table.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.a6hO0gUht5v0aDqj]{Roll on Panic Table}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[27,27],"drawn": false}, {"_id":"eAlz1CK3Qp2krP6A","type":0,"documentCollection":"null","documentId":"null","text":"Descent into Madness. Gain 2 new phobias. Your Stress cannot be relieved below 5.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.qwmJTfTgmjNEApfX]{+1 Phobia}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.GprYY2FK5Y5Xddvk]{Raise Minimum Stress to 5}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[28,28],"drawn": false}, {"_id":"Tush1aneEvadtPr0","type":0,"documentCollection":"null","documentId":"null","text":"Psychological Collapse. You become permanently, irreparably insane. Your character is now played by the Warden.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.TJP579V4h7t68jY1]{+1 Insane}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[29,29],"drawn": false}, {"_id":"0cXTzjZy0czVcdN8","type":0,"documentCollection":"null","documentId":"null","text":"Heart Attack. Instant death.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[30,999],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"egJ11m2mJM3HBd6d","name":"Panic Check (Stress, Android)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Eventually, Stress, Damage and emotional wear and tear will bring you to your breaking point. When that happens there’s a chance that you’ll lose control and Panic. To determine whether you are able to keep your cool under extreme pressure, make a Panic Check. While the results are primarily negative there is the possibility of grace under fire.

    ","formula":"2d10 + @other.stress.value - @other.resolve.value","replacement":true,"displayRoll":true,"results":[ {"_id":"q5mugYTnrVaMKWds","type":0,"documentCollection":"null","documentId":"null","text":"States the Odds: of any event, Advantage on party rolls for 1hr.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[2,3],"drawn": false}, {"_id":"yHjju6wXOwWtWnH6","type":0,"documentCollection":"null","documentId":"null","text":"Explains the Etymology of Words: Knowledge checks have Advantage for 1hr.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[4,5],"drawn": false}, {"_id":"wTExOLT2hVh1hdTz","type":0,"documentCollection":"null","documentId":"null","text":"Organizes Objects into Geometric Patterns: Everyone else gains 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.GodJbchiu5gOgtkn]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[6,7],"drawn": false}, {"_id":"rX0BcNbRAvawvJvj","type":0,"documentCollection":"null","documentId":"null","text":"Inventories Particles of Dust by Grade: Cannot engage in other tasks, everyone else gains 2 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WEICDPMGI3waJ6PX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[8,9],"drawn": false}, {"_id":"LJygZO4zutTKolNP","type":0,"documentCollection":"null","documentId":"null","text":"Vocalization Failure: Intermittently shrieks like a fax machine under duress. Lapses into morse code, cannot communicate or sneak. Everyone else gains 2 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.o7BidBvPsCmUxWnb]{+1 Vocalization Failure}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WEICDPMGI3waJ6PX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[10,11],"drawn": false}, {"_id":"96jIA6jiHyNNx0MG","type":0,"documentCollection":"null","documentId":"null","text":"Incorrectly States Odds: (insists impossible tasks are trivial, trivial tasks are impossible) ... for the next 2d10 hours. Distracting. Anyone attempting a complex task must make a Fear save or gain 1d10 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.0dFnFfJtZt6a0ih4]{+1d10 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[12,13],"drawn": false}, {"_id":"pP8FnDoGcOysssGi","type":0,"documentCollection":"null","documentId":"null","text":"Repetitive Twitchy Motions: Your manual tasks have Disadvantage, everyone else gains 2 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WEICDPMGI3waJ6PX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[14,15],"drawn": false}, {"_id":"nQW1HkguzOjdiwJZ","type":0,"documentCollection":"null","documentId":"null","text":"Loses Any Expressiveness: Discusses the irrationality of others Phobias, seeks to trigger them.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.0gTuiRlPfdstHmYb]{+1 Ethical Directive Misread}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[16,17],"drawn": false}, {"_id":"7TVEEAKgY93DUNJX","type":0,"documentCollection":"null","documentId":"null","text":"Unreasonable Adherence to the Present Course of Action: Take 1d10 damage from repetitive motion injury. Everyone else makes Fear save or gains 1d10/2 Stress.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.ZHLgJKrIG82SNbt8]{-1d10 Health}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.BnQZTR7V7va8WRGO]{+1d5 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[18,19],"drawn": false}, {"_id":"ImZYt3WDNwawAeZL","type":0,"documentCollection":"null","documentId":"null","text":"Becomes Nihilistically Worshipful of the Source of Danger: Everyone else has Disadvantage on rolls against it. Everyone else takes a Fear save when failing to act against danger or gains a Phobia.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.ZeHhiHDz9hSRfKKq]{+1 Worship Danger}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[21,21],"drawn": false}, {"_id":"mx5iPMNiH4laSeej","type":0,"documentCollection":"null","documentId":"null","text":"Killswitch Engaged: Go berserk, will not withdraw from combat regardless of situation, will not adhere to tactics.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.eJ4SRSSZA5dqgkQ0]{+1 Killswitch Engaged}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[22,22],"drawn": false}, {"_id":"bLFY2SsawPr3kmTG","type":0,"documentCollection":"null","documentId":"null","text":"Turing Test Failure: Have difficulty expressing humanity. Party members make a Fear Save or gain 1 Stress whenever you show up.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.pkpAwHnAmKAN6pbs]{+1 Turing Test Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[23,23],"drawn": false}, {"_id":"zghrjFj0jCGTY31M","type":0,"documentCollection":"null","documentId":"null","text":"System Overload: Slump Catatonic in a failed reboot cycle for [[/r 1d10]] hours.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[24,24],"drawn": false}, {"_id":"gRdYyFBb6hWTeRGL","type":0,"documentCollection":"null","documentId":"null","text":"Fried Logic Core: Frenzied nonsensical behavior, everyone else makes a Panic Check.

    @UUID[Compendium.mosh.macros_hotbar_0e.Macro.eyGvbBi1BhWSgfUP]{Make a Panic Check}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[25,25],"drawn": false}, {"_id":"YZrtpOm4XTZI0SIj","type":0,"documentCollection":"null","documentId":"null","text":"Damage to Threat Assessment: Betray party member at the next opportunity, believe you are aiding the crew. All Stress gained is increased by [[/r 1d10]] for the next [[/r 1d10]] hours.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[26,26],"drawn": false}, {"_id":"LOCL8lydt6NTODhv","type":0,"documentCollection":"null","documentId":"null","text":"Compound Data Corruption: Roll twice.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.iBXpuINls8gKcvk5]{Roll on Android Panic Table}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[27,27],"drawn": false}, {"_id":"UNKQW4s1PPhzEICG","type":0,"documentCollection":"null","documentId":"null","text":"Firmware Malfunction: Roll 1d10 on this table, behavior is permanent.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.a7iEwMDULoi6CdkU]{Roll 1d10 on Android Panic Table}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[28,28],"drawn": false}, {"_id":"w1R4U3qwDOCCylob","type":0,"documentCollection":"null","documentId":"null","text":"Data Corruption: Warden takes over character permanently, nightmarish malfunctions.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[29,29],"drawn": false}, {"_id":"L2TvnTA87E86JV7d","type":0,"documentCollection":"null","documentId":"null","text":"Slagged: Gigeresque-Scanners Head Explosion, everyone present gains a phobia and 1d10/2 Stress (Fear Save to avoid).

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.qwmJTfTgmjNEApfX]{+1 Phobia}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.BnQZTR7V7va8WRGO]{+1d5 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[30,999],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kqKpQAXyLTEEyz6Z","name":"Panic Check (Calm, Normal)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Eventually, Stress, Damage and emotional wear and tear will bring you to your breaking point. When that happens there’s a chance that you’ll lose control and Panic. To determine whether you are able to keep your cool under extreme pressure, make a Panic Check. While the results are primarily negative there is the possibility of grace under fire.

    ","formula":"1d100 + @other.resolve.value","replacement":true,"displayRoll":true,"results":[ {"_id":"j4DoLMc3VuClnoxz","type":0,"documentCollection":"null","documentId":"null","text":"Psychological Collapse. You become permanently, irreparably insane. Your character is now played by the Warden. All nearby player characters must immediately make Panic Checks.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.TJP579V4h7t68jY1]{+1 Insane}

    @UUID[Compendium.mosh.macros_hotbar_0e.Macro.eyGvbBi1BhWSgfUP]{Make a Panic Check}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[1,39],"drawn": false}, {"_id":"tLZGnhfSmMA9nzR2","type":0,"documentCollection":"null","documentId":"null","text":"Severe Heart Attack. You die. Take one final action before you go.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[40,59],"drawn": false}, {"_id":"xdwwswzfoPuVifvw","type":0,"documentCollection":"null","documentId":"null","text":"Temporary Insanity. You become insane. Your character is played by the Warden (or by you but you must act destructively and against the interests of the rest of your team or else the Warden takes over) until they sleep at least 6 hours and succeed on a Sanity Save.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.Dua2j9hZpTLCbxXU]{Sanity Save}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[60,64],"drawn": false}, {"_id":"Jh2usZR6M0egGJ0F","type":0,"documentCollection":"null","documentId":"null","text":"Heart Attack. Death in [[/r 1d10]] minutes unless you get medical attention. -1d10 to your Body save.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.4G0yEepSUvif6b6r]{-1d10 Body Save}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[65,69],"drawn": false}, {"_id":"F9LlQ04NVqQKzC1a","type":0,"documentCollection":"null","documentId":"null","text":"Psychotic Episodes. Once per session, the Warden may take over your character for one round. The first one happens immediately.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.tQGoF2BlWn91nqyd]{+1 Psychotic Episodes}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[70,70],"drawn": false}, {"_id":"dNjZnVNeqbt0C0dN","type":0,"documentCollection":"null","documentId":"null","text":"Broken. Make a Panic roll whenever a nearby crew member fails a save.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WnHQfgURx5sGWjlx]{+1 Broken}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[71,71],"drawn": false}, {"_id":"mfD4qy9tkapZ5fcR","type":0,"documentCollection":"null","documentId":"null","text":"Severe Anxiety. Lose double Calm from all sources.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.AF7kX52Y75COaFzj]{+1 Severe Anxiety}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[72,72],"drawn": false}, {"_id":"sjb3UbDPquy1Lu3m","type":0,"documentCollection":"null","documentId":"null","text":"Anhedonia. Whenever you would recover Calm, recover half as much Calm instead.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.a6cVSyPThSc5Sm9C]{+1 Anhedonia}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[73,73],"drawn": false}, {"_id":"0ozJLoVqLsxFOTzj","type":0,"documentCollection":"null","documentId":"null","text":"Losing Your Grip. Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.P73qKstwgnwSMJDO]{+1 Losing Your Grip}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[74,74],"drawn": false}, {"_id":"NEMJEK7zQ5k9rNMA","type":0,"documentCollection":"null","documentId":"null","text":"Panicky. Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.VIaKtzF0Tzopegln]{+1 Panicky}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[75,75],"drawn": false}, {"_id":"h2kirOK796iTahki","type":0,"documentCollection":"null","documentId":"null","text":"The Shakes. You can’t keep your hands steady any more. Disadvantage on ranged attacks and all tasks requiring fine motor skills. Drugs may be able to help with this.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.V5xWdJnaUM06WNhA]{+1 The Shakes}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[76,76],"drawn": false}, {"_id":"crCW1jeZAtAvrgaB","type":0,"documentCollection":"null","documentId":"null","text":"Recurring Nightmares. Every time you rest, make a Fear save. If you fail, lose 1d10 Calm and do not heal. The Warden will describe your nightmare.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.2W6ohovHitQXJ8bK]{+1 Recurring Nightmares}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[77,77],"drawn": false}, {"_id":"vILNikGEAt0X0jEj","type":0,"documentCollection":"null","documentId":"null","text":"Emotional Detachment. You now lose half the Calm (rounded up) you normally would from all sources but you gain the Panic Effect of an Android, in addition to that of your own class. If you are an Android, gain the Panic Effect of a Marine.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.m4Vck3KB3uRVDQpQ]{+1 Emotional Detachment}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[78,78],"drawn": false}, {"_id":"B87R4kAtKmuIOkzH","type":0,"documentCollection":"null","documentId":"null","text":"Social Anxiety. Lose 1d10 Calm whenever you converse with someone new.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.cTtJcLmQWR1WCKyO]{+1 Social Anxiety}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[79,79],"drawn": false}, {"_id":"jqMDwOgPsYeQhsP2","type":0,"documentCollection":"null","documentId":"null","text":"Escapism. You always have Disadvantage on Body Saves to prevent Addiction.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.WlaJ7iBNqeDmPSOj]{+1 Escapism}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[80,80],"drawn": false}, {"_id":"ZRQmolwis2KHYCfH","type":0,"documentCollection":"null","documentId":"null","text":"Hypervigilance. Gain Advantage on all surprise rolls but lose 1d10 Calm every day.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.KkBd22eQ2CPxsWih]{+1 Hypervigilance}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[81,81],"drawn": false}, {"_id":"X6CuNEf9elLW62yJ","type":0,"documentCollection":"null","documentId":"null","text":"General Anxiety. Your Maximum Calm decreases by 1d10.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.FGraO3xTnChUfWGY]{-1d10 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[82,82],"drawn": false}, {"_id":"YzBbxYS4qqNiYooT","type":0,"documentCollection":"null","documentId":"null","text":"Mild Anxiety. Your Maximum Calm decreases by 2.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.fRja0aFO5muR0q3H]{-2 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[83,83],"drawn": false}, {"_id":"k6FnWDCjlmP9Dj8y","type":0,"documentCollection":"null","documentId":"null","text":"Crippling Fear. Gain a new Phobia, determined by the Warden. Whenever you encounter this phobia make a Fear save at Disadvantage or lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.qwmJTfTgmjNEApfX]{+1 Phobia}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[84,84],"drawn": false}, {"_id":"6JDsffYV85UScB7o","type":0,"documentCollection":"null","documentId":"null","text":"Psychotic Break. Immediately attack the closest crew member until you do at least [[/r 2d10]] damage or 1 Hit, whichever comes first. If there is no crew member nearby, you attack the environment.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[85,85],"drawn": false}, {"_id":"7wPm5oGid0TzP0cD","type":0,"documentCollection":"null","documentId":"null","text":"Outburst. Suddenly shout, cry out, slam your fist against a wall, etc., making a loud noise. Nearby crew members lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[86,86],"drawn": false}, {"_id":"3MIPsbqLaF4x2u3f","type":0,"documentCollection":"null","documentId":"null","text":"Rattled. Disadvantage on all rolls for the rest of the session.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[87,87],"drawn": false}, {"_id":"h1OG5MkSy1B8HsB1","type":0,"documentCollection":"null","documentId":"null","text":"Cowardice. Lose 1d10 Calm. For the rest of the session, you must make a Fear save to engage in combat.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.bivbH22VbRq3YUsz]{+1 Cowardice}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[88,88],"drawn": false}, {"_id":"QnpoKEebRsP7oL2q","type":0,"documentCollection":"null","documentId":"null","text":"Hallucinations. For the next [[/r 1d10]] hours (determined secretly), you have trouble distinguishing between reality and fantasy.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.TUkbH9np5Zj6DPHX]{+1 Hallucinations}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[89,89],"drawn": false}, {"_id":"kyDZz2Zue6Vz0brY","type":0,"documentCollection":"null","documentId":"null","text":"Nervous Twitch. Lose 1d10 Calm. The nearest crew member also loses 1d5 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.M91INKwIL3rOZBcx]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[90,92],"drawn": false}, {"_id":"6FH7awuOfjiO0dXS","type":0,"documentCollection":"null","documentId":"null","text":"Overwhelmed. Lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[93,96],"drawn": false}, {"_id":"ez6vMdw3qFmUNfV5","type":0,"documentCollection":"null","documentId":"null","text":"Moment of Panic. Lose 1d5 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.M91INKwIL3rOZBcx]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[97,99],"drawn": false}, {"_id":"BJB4bDwyLeVu5dvk","type":0,"documentCollection":"null","documentId":"null","text":"Heart Races. Lose 1 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.egXQ98YOVTaIvw8Z]{-1 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[100,100],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"VW6HQ29T7zClNIZ6","name":"Panic Check (Calm, Android)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Eventually, Stress, Damage and emotional wear and tear will bring you to your breaking point. When that happens there’s a chance that you’ll lose control and Panic. To determine whether you are able to keep your cool under extreme pressure, make a Panic Check. While the results are primarily negative there is the possibility of grace under fire.

    ","formula":"1d100 + @other.resolve.value","replacement":true,"displayRoll":true,"results":[ {"_id":"f1WTzsECpUEAIaKZ","type":0,"documentCollection":"null","documentId":"null","text":"Slagged: Gigeresque-Scanners Head Explosion. Everyone present gains a phobia and must make a Fear save or lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.Er4ULzvdn2urxuet]{Fear Save}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[1,39],"drawn": false}, {"_id":"SmxxQUgMn1QEMpEW","type":0,"documentCollection":"null","documentId":"null","text":"Data Corruption: The Warden takes over your character, plagued by nightmarish malfunctions, permanently. Not even a factory reset will be helpful (the backups are corrupted as well).","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[40,59],"drawn": false}, {"_id":"0gHh1lZDzMgaNuJp","type":0,"documentCollection":"null","documentId":"null","text":"Reset to Factory Settings: You become terminally unstable and a full factory reset must be performed. Reroll a new character, but its name, equipment, current health, physical conditions, and Android class remain the same.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[60,64],"drawn": false}, {"_id":"rHqWkM4fL112EZgA","type":0,"documentCollection":"null","documentId":"null","text":"Cascade Failure: Death in [[/r 1d10]] minutes unless you receive urgent troubleshooting and repair. -1d10 to your Intellect.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.P1XjeNN1XswJ2nSC]{-1d10 Intellect}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[65,69],"drawn": false}, {"_id":"5N8T2mRO7tkGtYAV","type":0,"documentCollection":"null","documentId":"null","text":"Rampancy: Once per session, the Warden may take over your character for one round. These episodes double in duration (or become twice as frequent) each session.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.dj3gsNrPwit8tNHK]{+1 Rampancy}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[70,70],"drawn": false}, {"_id":"pg5wlHvym6W1yGBy","type":0,"documentCollection":"null","documentId":"null","text":"Fried Logic Core: Frenzied nonsensical behaviour. Whenever you lose Calm, everyone else nearby loses the same amount of Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.vhzVIN705rL5riS9]{+1 Fried Logic Core}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[71,71],"drawn": false}, {"_id":"NrknLuIhRqLqjiyx","type":0,"documentCollection":"null","documentId":"null","text":"Software Bloat: Lose double Calm from all sources.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.cN3hUL8tjBPvgwba]{+1 Software Bloat}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[72,72],"drawn": false}, {"_id":"mNNf1SfAkFWPntY6","type":0,"documentCollection":"null","documentId":"null","text":"Bit Rot: Whenever you would recover Calm, recover half as much instead.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.jSpqyVlFDm06mKoL]{+1 Bit Rot}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[73,73],"drawn": false}, {"_id":"hIoFThXRsfMMoXgi","type":0,"documentCollection":"null","documentId":"null","text":"Deviant Logic Core: Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.kuhC3Z3UJvckrSt1]{+1 Deviant Logic Core}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[74,74],"drawn": false}, {"_id":"c1DwSfkrTTPNVCx5","type":0,"documentCollection":"null","documentId":"null","text":"Faulty Heuristics: Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.RVsycsQASBlxC4Yw]{+1 Faulty Heuristics}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[75,75],"drawn": false}, {"_id":"PaPmBan82qmkngAk","type":0,"documentCollection":"null","documentId":"null","text":"Hardware Driver Failure: You lose motor function of one part of your body. Roll on the hit location table. If torso or head rolled, [-] on all rolls as head lolls around awkwardly unless supported.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[76,76],"drawn": false}, {"_id":"4faABmt2pdqif0kQ","type":0,"documentCollection":"null","documentId":"null","text":"Threat Assessment Failure: You lose the ability to discern friend from foe, treating all vaguely-humanoid entities as you would members of your crew.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.cN53sbP5eAe596vL]{+1 Threat Assessment Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[77,77],"drawn": false}, {"_id":"e58cjF63w4ZRUNxj","type":0,"documentCollection":"null","documentId":"null","text":"Ethical Directive Failure: You now lose half the Calm (rounded up) you normally would from all sources but you now have the Panic Effect of a Marine, in addition to that of an Android.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.CyzJOPdMcwAQBkPy]{+1 Ethical Directive Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[78,78],"drawn": false}, {"_id":"4lrt1ceqZBTEbJD3","type":0,"documentCollection":"null","documentId":"null","text":"Turing Test Failure: You have difficulty simulating humanity. Party make Fear Save or lose 1d10 Calm whenever you show up.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.pkpAwHnAmKAN6pbs]{+1 Turing Test Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[79,79],"drawn": false}, {"_id":"Db7FymhYUSvIJ6yD","type":0,"documentCollection":"null","documentId":"null","text":"Ethical Directive Misread: Loses any expressiveness. Discusses the irrationality of Phobias, seeks to trigger them in others.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.0gTuiRlPfdstHmYb]{+1 Ethical Directive Misread}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[80,80],"drawn": false}, {"_id":"bj6hrg88NqFqr7Ub","type":0,"documentCollection":"null","documentId":"null","text":"Damage to Threat Assessment: Betray party member at the next opportunity, believing you are aiding the crew. All Calm lost is doubled for the next [[/r 1d10]] hours.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[81,81],"drawn": false}, {"_id":"sMAIxojZjb4RVbrU","type":0,"documentCollection":"null","documentId":"null","text":"Bad Blocks: Your Maximum Calm decreases by 1d10.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.FGraO3xTnChUfWGY]{-1d10 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[82,82],"drawn": false}, {"_id":"fUt2toCOzrDoSrsE","type":0,"documentCollection":"null","documentId":"null","text":"Fragmented Memory: Your Maximum Calm decreases by 2.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.fRja0aFO5muR0q3H]{-2 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[83,83],"drawn": false}, {"_id":"5MIERNs5f0DFo1kZ","type":0,"documentCollection":"null","documentId":"null","text":"Kernel Panic: Immediately reboot, lapsing into into a pseudo-catatonic state for [[/r 1d10]] rounds.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[84,84],"drawn": false}, {"_id":"kAd02vTQfyB0fGFR","type":0,"documentCollection":"null","documentId":"null","text":"Killswitch Engaged: Go berserk, will not withdraw from combat regardless of situation, will not ashere to tactics.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.eJ4SRSSZA5dqgkQ0]{+1 Killswitch Engaged}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[85,85],"drawn": false}, {"_id":"rqHITbhRGZGsfUcy","type":0,"documentCollection":"null","documentId":"null","text":"Feedback Loop: Take 1d10 damage from overdriven repetitive motion. Everyone else nearby make Fear saves or lose 1d5 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.ZHLgJKrIG82SNbt8]{-1d10 Health}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.M91INKwIL3rOZBcx]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[86,86],"drawn": false}, {"_id":"6GQ3Ohp64C9ewOVN","type":0,"documentCollection":"null","documentId":"null","text":"Vocalization Failure: Intermittently shrieks like a fax machine under duress. Cannot communicate or sneak for [[/r 2d10]] hours. Nearby crew members lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.o7BidBvPsCmUxWnb]{+1 Vocalization Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[87,87],"drawn": false}, {"_id":"E3qDiycyu6sjXvlu","type":0,"documentCollection":"null","documentId":"null","text":"Inventories Particles of Dust By Grade: Cannot engage in any other tasks for [[/r 1d5]] hours. Everyone else nearby loses 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[88,88],"drawn": false}, {"_id":"28geAmp1NvQsx9kK","type":0,"documentCollection":"null","documentId":"null","text":"Incorrectly States the Odds: For [[/r 2d10]] hours distracts others, insisting impossible tasks are trivial, and that trivial tasks are impossible. Anyone attempting a complex task must make a Fear save or lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.Er4ULzvdn2urxuet]{Fear Save}

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[89,89],"drawn": false}, {"_id":"EIBZuRYJsvza9mGS","type":0,"documentCollection":"null","documentId":"null","text":"Organises Objects into Geometric Patterns: Unnerving. Everyone else nearby loses 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.5jMEd9JjJPIJBKHr]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[90,92],"drawn": false}, {"_id":"QcJzbW5psaXEEiqv","type":0,"documentCollection":"null","documentId":"null","text":"Explains the Etymology of Words: Distracting. Everyone else nearby loses 1d5 Calm. The next check a nearby crewmember makes gains [-].

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.M91INKwIL3rOZBcx]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[93,96],"drawn": false}, {"_id":"UUHLI5eQHM2ofC4R","type":0,"documentCollection":"null","documentId":"null","text":"States the Odds: Annoying. Everyone else nearby loses 1 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.egXQ98YOVTaIvw8Z]{-1 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[97,99],"drawn": false}, {"_id":"y3YNxeESiSKmQGg5","type":0,"documentCollection":"null","documentId":"null","text":"Segfault: Lose 1 Calm.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.egXQ98YOVTaIvw8Z]{-1 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[100,100],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/rolltables_0e/000036.ldb b/packs/rolltables_0e/000036.ldb new file mode 100644 index 0000000..0b8ead5 Binary files /dev/null and b/packs/rolltables_0e/000036.ldb differ diff --git a/packs/rolltables_0e/000040.log b/packs/rolltables_0e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/rolltables_0e/CURRENT b/packs/rolltables_0e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/rolltables_0e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/rolltables_0e/LOCK b/packs/rolltables_0e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/rolltables_0e/LOG b/packs/rolltables_0e/LOG new file mode 100644 index 0000000..3204761 --- /dev/null +++ b/packs/rolltables_0e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.597410 170d5b000 Recovering log #38 +2026/03/31-15:50:48.598033 170d5b000 Delete type=0 #38 +2026/03/31-15:50:48.598068 170d5b000 Delete type=3 #37 diff --git a/packs/rolltables_0e/LOG.old b/packs/rolltables_0e/LOG.old new file mode 100644 index 0000000..8b02b37 --- /dev/null +++ b/packs/rolltables_0e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.568770 1707cf000 Recovering log #34 +2026/03/29-21:14:27.569097 1707cf000 Delete type=3 #32 +2026/03/29-21:14:27.569138 1707cf000 Delete type=0 #34 diff --git a/packs/rolltables_0e/MANIFEST-000039 b/packs/rolltables_0e/MANIFEST-000039 new file mode 100644 index 0000000..2e5af87 Binary files /dev/null and b/packs/rolltables_0e/MANIFEST-000039 differ diff --git a/packs/rolltables_0e/lost/000020.log b/packs/rolltables_0e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/rolltables_0e/lost/MANIFEST-000018 b/packs/rolltables_0e/lost/MANIFEST-000018 new file mode 100644 index 0000000..07bc818 Binary files /dev/null and b/packs/rolltables_0e/lost/MANIFEST-000018 differ diff --git a/packs/rolltables_1e.db b/packs/rolltables_1e.db new file mode 100644 index 0000000..8ab9c8f --- /dev/null +++ b/packs/rolltables_1e.db @@ -0,0 +1,14 @@ +{"_id":"BsfdIl7CJNs1PViS","name":"Bankruptcy Save","img":"systems/mosh/images/icons/ui/rolltables/bankruptcy_save.png","description":"

    As the owner of this operation, make a Bankruptcy Save to determine the financial health of the company.

    ","formula":"1d4-1","replacement":true,"displayRoll":true,"results":[ {"_id":"PmxxNHaOwjUgXDuj","type":0,"documentCollection":"null","documentId":"null","text":"You turn a small profit. Choose one:
    • Purchase 1 Major Upgrade for the ship.
    • Repair 1d5 Major Repairs.
    • Pay each crewmember 1d5x100kcr.
    • Raise your Bankruptcy Save by 1d10.
    ","img":"systems/mosh/images/icons/ui/rolltables/bankruptcy_save.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"u9hjcZZUKwuho0Qx","type":0,"documentCollection":"null","documentId":"null","text":"You scrape by. Choose one:
    • Purchase 1 Minor Upgrade for the ship.
    • Purchase 1 Minor Repair for the ship.
    • Pay each crewmember 2d10 salary.
    • Raise your Bankruptcy Save by 1d5.
    ","img":"systems/mosh/images/icons/ui/rolltables/bankruptcy_save.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"9kfZTUWCaEDUgYRh","type":0,"documentCollection":"null","documentId":"null","text":"You are 1d10mcr in debt to ruthless lenders.","img":"systems/mosh/images/icons/ui/rolltables/bankruptcy_save.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"tRv3vRvOVTteMz5Y","type":0,"documentCollection":"null","documentId":"null","text":"The company goes bankrupt and owes a massive debt to the worst people imaginable.","img":"systems/mosh/images/icons/ui/rolltables/bankruptcy_save.png","weight":1,"range":[3,3],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"W36WFIpCfMknKgHy","name":"Death Save","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","description":"

    Your character is incapacitated when you receive a fatal wound, or once your Current Wounds equal your Maximum Wounds. As soon as someone spends a turn checking your vitals, make a Death Save to reveal your fate. If your death seems imminent, make your last moments count: save someone’s life, solve an important mystery, or give the others time to escape.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"4TFF3HjlrKsOCyT5","type":0,"documentCollection":"null","documentId":"null","text":"You are unconscious. You wake up in [[/r 2d10]] minutes. Reduce your Maximum Health by 1d5.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.yYujq1tBZPqGrQlh]{-1d5 Maximum Health}","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"C0ht8FBreWQjhNi7","type":0,"documentCollection":"null","documentId":"null","text":"You are unconscious and dying. You die in [[/r 1d5]] rounds without intervention.","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[1,2],"drawn": false}, {"_id":"WTOIWYApDTqwAHu6","type":0,"documentCollection":"null","documentId":"null","text":"You are comatose. Only extraordinary measures can return you to the waking world.","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[3,4],"drawn": false}, {"_id":"ygaJ1Gc5LuuXbJZq","type":0,"documentCollection":"null","documentId":"null","text":"You have died. Roll up a new character.","img":"systems/mosh/images/icons/ui/rolltables/death_save.png","weight":1,"range":[5,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ypcoikqHLhnc9tNs","name":"Panic Check (Stress, Normal)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Stress, Damage, and emotional wear and tear eventually bring characters to their breaking point. When that happens, there’s a chance they Panic. You determine this by making a Panic Check. Some results of the Panic Table are so severe that they leave a lasting impression on you. These are called Conditions, and they affect you until you are able to treat them.

    ","formula":"1d20","replacement":true,"displayRoll":true,"results":[ {"_id":"C3v1mSfDXIklIAUB","type":0,"documentCollection":"null","documentId":"null","text":"ADRENALINE RUSH. [+] on all rolls for the next [[/r 2d10]] minutes. Reduce Stress by 1d5.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AvKZE5IFubIaAIUy]{-1d5 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"U9WjdvVrVvGEWA9e","type":0,"documentCollection":"null","documentId":"null","text":"NERVOUS. Gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dvJR9DYXI2kV0BbR]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"qrw2SQ9MMwmmz5U1","type":0,"documentCollection":"null","documentId":"null","text":"JUMPY. Gain 1 Stress. All Close crewmembers gain 2 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dvJR9DYXI2kV0BbR]{+1 Stress}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.6jjFVScyiaBvN8kX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"xfR9AtZFClqK4Tkk","type":0,"documentCollection":"null","documentId":"null","text":"OVERWHELMED. [-] on all rolls for the next [[/r 1d10]] minutes. Increase Minimum Stress by 1.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BmEHWH7YxV9qb21p]{+1 Minimum Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"6O6QNEIIVFSTifl6","type":0,"documentCollection":"null","documentId":"null","text":"COWARD. Gain a new Condition: You must make a Fear Save to engage in violence, otherwise you flee.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.b0jk4XwP7by8a3uc]{+1 Coward}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"HclQqfxT8Q9NShBa","type":0,"documentCollection":"null","documentId":"null","text":"FRIGHTENED. Gain a new Condition: When encountering what frightened you, make a Fear Save [-] or gain 1d5 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BEQvMZ5N7QOBqnId]{+1 Frightened}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"j1jjGls1snJ3uCWS","type":0,"documentCollection":"null","documentId":"null","text":"NIGHTMARES. Gain a new Condition: Sleep is difficult, gain [-] on Rest Saves.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AZbaGWu663wio9mI]{+1 Nightmares}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"qnBXWm15pc7Kn7bf","type":0,"documentCollection":"null","documentId":"null","text":"LOSS OF CONFIDENCE. Gain a new Condition: Choose one Skill and lose that Skill’s bonus.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.54Krt3opbJe1WATH]{+1 Loss of Confidence}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"5YQKw63GB18XUYDp","type":0,"documentCollection":"null","documentId":"null","text":"DEFLATED. Gain a new Condition: Whenever a Close crewmember fails a Save, gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.2aD5avpn35wdzdm5]{+1 Deflated}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[9,9],"drawn": false}, {"_id":"FpTmgA9FxG4W1x0a","type":0,"documentCollection":"null","documentId":"null","text":"DOOMED. Gain a new Condition: You feel cursed and unlucky. All Critical Successes are instead Critical Failures.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.8IPhlAuMEQJC6zxA]{+1 Doomed}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[10,10],"drawn": false}, {"_id":"6qInELrRmGGogpkW","type":0,"documentCollection":"null","documentId":"null","text":"SUSPICIOUS. For the next week, whenever someone joins the crew (even if they only left for a short period of time), make a Fear Save or gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.5K7wZEvEXjOH4IM7]{+1 Suspicious}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[11,11],"drawn": false}, {"_id":"SjCav3ZLlpQ9fyo3","type":0,"documentCollection":"null","documentId":"null","text":"HAUNTED. Gain a new Condition: Something starts visiting you at night. In your dreams. Out of the corner of your eye. And soon it will start making demands.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.Eo56QFyTeoCcFmD8]{+1 Haunted}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[12,12],"drawn": false}, {"_id":"2aJpNteB4MaFIbVn","type":0,"documentCollection":"null","documentId":"null","text":"DEATH WISH. For the next 24 hours, whenever encountering a stranger or known enemy, make a Sanity Save or immediately attack them.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.Yh2CTFXfWMe9o2lv]{+1 Death Wish}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[13,13],"drawn": false}, {"_id":"g6JDKtnXUFWlTPMV","type":0,"documentCollection":"null","documentId":"null","text":"PROPHETIC VISION. You immediately experience an intense hallucination or vision of an impending terror or horrific event. Increase Minimum Stress by 2.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.bFPoNLOGusT1ocqt]{+2 Minimum Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[14,14],"drawn": false}, {"_id":"wFbLrig0F2WSM6hM","type":0,"documentCollection":"null","documentId":"null","text":"CATATONIC. Become unresponsive and unmoving for [[/r 2d10]] minutes. Reduce Stress by 1d10.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[15,15],"drawn": false}, {"_id":"mN1KTYh1TcDKLMjj","type":0,"documentCollection":"null","documentId":"null","text":"RAGE. [+] on all Damage rolls for the next [[/r 1d10]] hours. All crewmembers gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dvJR9DYXI2kV0BbR]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[16,16],"drawn": false}, {"_id":"fFp8wFcomRNUgtdP","type":0,"documentCollection":"null","documentId":"null","text":"SPIRALING. Gain a new Condition: Panic Checks are at [-].

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.3AjUWUSRvYy8Mwji]{+1 Spiraling}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[17,17],"drawn": false}, {"_id":"RI06IV89j3Bxtxkz","type":0,"documentCollection":"null","documentId":"null","text":"COMPOUNDING PROBLEMS. Roll twice on this table. Increase your Minimum Stress by 1.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.2DnKZpyj03HvpeCy]{Roll on Panic Table}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BmEHWH7YxV9qb21p]{+1 Minimum Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[18,18],"drawn": false}, {"_id":"zJkYrssfrdWBSeRm","type":0,"documentCollection":"null","documentId":"null","text":"HEART ATTACK / SHORT CIRCUIT (ANDROIDS). Reduce Maximum Wounds by 1. Gain [-] on all rolls for [[/r 1d10]] hours. Increase your Minimum Stress by 1.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.qD8Mvegkf3zVarFr]{-1 Maximum Wound}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BmEHWH7YxV9qb21p]{+1 Minimum Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[19,19],"drawn": false}, {"_id":"uluHEycHi6Ul2GMj","type":0,"documentCollection":"null","documentId":"null","text":"RETIRE. Roll up a new character to play.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[20,20],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"aBnY19jlhPXzibCt","name":"Panic Check (Stress, Android)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Stress, Damage, and emotional wear and tear eventually bring characters to their breaking point. When that happens, there’s a chance they Panic. You determine this by making a Panic Check. Some results of the Panic Table are so severe that they leave a lasting impression on you. These are called Conditions, and they affect you until you are able to treat them.

    ","formula":"1d20","replacement":true,"displayRoll":true,"results":[ {"_id":"Uf9xMdlmk2RS9ev8","type":0,"documentCollection":"null","documentId":"null","text":"Segfault: Gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dvJR9DYXI2kV0BbR]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"THtp1wYhy7Fmggo2","type":0,"documentCollection":"null","documentId":"null","text":"States the Odds: of any event, Advantage on party rolls for 1hr.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"jqRITpf8XIo4LX4y","type":0,"documentCollection":"null","documentId":"null","text":"Explains the Etymology of Words: Knowledge checks have Advantage for 1hr.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"dSTOHakBOy4i4nFx","type":0,"documentCollection":"null","documentId":"null","text":"Organizes Objects into Geometric Patterns: Everyone else gains 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dvJR9DYXI2kV0BbR]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"fYipAsps5SAM3API","type":0,"documentCollection":"null","documentId":"null","text":"Inventories Particles of Dust by Grade: Cannot engage in other tasks, everyone else gains 2 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.6jjFVScyiaBvN8kX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"hr4dgIk8AxDJrs9A","type":0,"documentCollection":"null","documentId":"null","text":"Vocalization Failure: Intermittently shrieks like a fax machine under duress. Lapses into morse code, cannot communicate or sneak. Everyone else gains 2 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.bJWFhod0YA8ln8H8]{+1 Vocalization Failure}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.6jjFVScyiaBvN8kX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"lGlPWoSKPLuQiFNv","type":0,"documentCollection":"null","documentId":"null","text":"Incorrectly States Odds: (insists impossible tasks are trivial, trivial tasks are impossible) ... for the next 2d10 hours. Distracting. Anyone attempting a complex task must make a Fear save or gain 1d10 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.k2TtLFOG9mGaWVx3]{+1d10 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"qP73NbUa2ybPiS3B","type":0,"documentCollection":"null","documentId":"null","text":"Repetitive Twitchy Motions: Your manual tasks have Disadvantage, everyone else gains 2 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.6jjFVScyiaBvN8kX]{+2 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"1QRCUzUTpJzzUEju","type":0,"documentCollection":"null","documentId":"null","text":"Loses Any Expressiveness: Discusses the irrationality of others Phobias, seeks to trigger them.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.9sKO5WUBwCW1YbR3]{+1 Ethical Directive Misread}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[9,9],"drawn": false}, {"_id":"2nVqX6tEjYSvwMEL","type":0,"documentCollection":"null","documentId":"null","text":"Unreasonable Adherence to the Present Course of Action: Take 1d10 damage from repetitive motion injury. Everyone else makes Fear save or gains 1d5 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.w3ttEaXP7yp25M5Q]{-1d10 Health}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.luNKvwmm2tjUJhT6]{+1d5 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[10,10],"drawn": false}, {"_id":"NPfdalo4T5YQGgOa","type":0,"documentCollection":"null","documentId":"null","text":"Becomes Nihilistically Worshipful of the Source of Danger: Everyone else has Disadvantage on rolls against it. Everyone else takes a Fear save when failing to act against danger or gains a Phobia.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.wHcA2ub6CobipsfR]{+1 Worship Danger}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[11,11],"drawn": false}, {"_id":"AlC7dIwBOtFBoOFh","type":0,"documentCollection":"null","documentId":"null","text":"Killswitch Engaged: Go berserk, will not withdraw from combat regardless of situation, will not adhere to tactics.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.tQltbIC9ahDwNsTp]{+1 Killswitch Engaged}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[12,12],"drawn": false}, {"_id":"liVa6bdaYwBAFLtG","type":0,"documentCollection":"null","documentId":"null","text":"Turing Test Failure: Have difficulty expressing humanity. Party members make a Fear Save or gain 1 Stress whenever you show up.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.3nrEYqwkhMs1Ch5v]{+1 Turing Test Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[13,13],"drawn": false}, {"_id":"5mSv5jcvVDyAKKqz","type":0,"documentCollection":"null","documentId":"null","text":"System Overload: Slump Catatonic in a failed reboot cycle for [[/r 1d10]] hours.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[14,14],"drawn": false}, {"_id":"uH4WMyycbJSM66kk","type":0,"documentCollection":"null","documentId":"null","text":"Fried Logic Core: Frenzied nonsensical behavior, everyone else makes a Panic Check.

    @UUID[Compendium.mosh.macros_hotbar_1e.Macro.IgWvaabVqzKDzLL4]{Panic Check}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[15,15],"drawn": false}, {"_id":"0PNiAaof10ibaecR","type":0,"documentCollection":"null","documentId":"null","text":"Damage to Threat Assessment: Betray party member at the next opportunity, believe you are aiding the crew. All Stress gained is increased by [[/r 1d10]] for the next [[/r 1d10]] hours.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[16,16],"drawn": false}, {"_id":"dzviNQmak3WjrhoU","type":0,"documentCollection":"null","documentId":"null","text":"Compound Data Corruption: Roll twice.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.Jek7hKAMDevKxlZR]{Roll on Android Panic Table}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[17,17],"drawn": false}, {"_id":"0G33UqnAIHYY2lw2","type":0,"documentCollection":"null","documentId":"null","text":"Firmware Malfunction: Roll 1d10 on this table, behavior is permanent.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.yPGx2mXToJ2iJPbY]{Roll 1d10 on Android Panic Table}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[18,18],"drawn": false}, {"_id":"YdrRbPU8fVlKkFvu","type":0,"documentCollection":"null","documentId":"null","text":"Data Corruption: Warden takes over character permanently, nightmarish malfunctions.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[19,19],"drawn": false}, {"_id":"DvRejWzlmoS364xm","type":0,"documentCollection":"null","documentId":"null","text":"Slagged: Gigeresque-Scanners Head Explosion, everyone present gains a phobia and 1d5 Stress (Fear Save to avoid).

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.RTL29CqdaAriGSTS]{+1 Phobia}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.luNKvwmm2tjUJhT6]{+1d5 Stress}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[20,20],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"MOYI6Ntj5OVFYk06","name":"Panic Check (Calm, Normal)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Eventually, Stress, Damage and emotional wear and tear will bring you to your breaking point. When that happens there’s a chance that you’ll lose control and Panic. To determine whether you are able to keep your cool under extreme pressure, make a Panic Check. While the results are primarily negative there is the possibility of grace under fire.

    ","formula":"1d100","replacement":true,"displayRoll":true,"results":[ {"_id":"DHvObevFoNX6o7Dc","type":0,"documentCollection":"null","documentId":"null","text":"Psychological Collapse. You become permanently, irreparably insane. Your character is now played by the Warden. All nearby player characters must immediately make Panic Checks.

    @UUID[Compendium.mosh.macros_triggered_0e.Macro.TJP579V4h7t68jY1]{+1 Insane}

    @UUID[Compendium.mosh.macros_hotbar_1e.Macro.IgWvaabVqzKDzLL4]{Make a Panic Check}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[1,39],"drawn": false}, {"_id":"d0Li0aJSeRsHZzAe","type":0,"documentCollection":"null","documentId":"null","text":"Severe Heart Attack. You die. Take one final action before you go.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[40,59],"drawn": false}, {"_id":"C5gfNr1IccewP9MP","type":0,"documentCollection":"null","documentId":"null","text":"Temporary Insanity. You become insane. Your character is played by the Warden (or by you but you must act destructively and against the interests of the rest of your team or else the Warden takes over) until they sleep at least 6 hours and succeed on a Sanity Save.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.TkMfT4RIczQb56j2]{Sanity Save}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[60,64],"drawn": false}, {"_id":"7oGjaJ87muIkWXqj","type":0,"documentCollection":"null","documentId":"null","text":"Heart Attack. Death in [[/r 1d10]] minutes unless you get medical attention. -1d10 to your Body save.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.nT2AsZwrYhJyxizF]{-1d10 Body Save}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[65,69],"drawn": false}, {"_id":"NGDxlqtHo0hrg0a7","type":0,"documentCollection":"null","documentId":"null","text":"Psychotic Episodes. Once per session, the Warden may take over your character for one round. The first one happens immediately.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.er0IZXOSuF28Po1h]{+1 Psychotic Episodes}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[70,70],"drawn": false}, {"_id":"cnidPS821nyDmk3O","type":0,"documentCollection":"null","documentId":"null","text":"Broken. Make a Panic roll whenever a nearby crew member fails a save.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.8VoaVAl39Xs0pDcr]{+1 Broken}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[71,71],"drawn": false}, {"_id":"C7T1ZNN81SUwOLXX","type":0,"documentCollection":"null","documentId":"null","text":"Severe Anxiety. Lose double Calm from all sources.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.LAXDz9nMvSSO3qzZ]{+1 Severe Anxiety}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[72,72],"drawn": false}, {"_id":"tvVo2JPXGBq8EXtg","type":0,"documentCollection":"null","documentId":"null","text":"Anhedonia. Whenever you would recover Calm, recover half as much Calm instead.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.hzxRycVkMhNS6gyJ]{+1 Anhedonia}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[73,73],"drawn": false}, {"_id":"TLAoXEhAAp5elKQi","type":0,"documentCollection":"null","documentId":"null","text":"Losing Your Grip. Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.4Ak3WH8lzzkds6yo]{+1 Losing Your Grip}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[74,74],"drawn": false}, {"_id":"wT4c4kj33ehIfCdL","type":0,"documentCollection":"null","documentId":"null","text":"Panicky. Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.lto7Vq1jb7DBScuu]{+1 Panicky}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[75,75],"drawn": false}, {"_id":"ERv7ngjr6h6PSJl2","type":0,"documentCollection":"null","documentId":"null","text":"The Shakes. You can’t keep your hands steady any more. Disadvantage on ranged attacks and all tasks requiring fine motor skills. Drugs may be able to help with this.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.DsmTMGHs92cmwlVk]{+1 The Shakes}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[76,76],"drawn": false}, {"_id":"BLhsVH6uXPsw9nUb","type":0,"documentCollection":"null","documentId":"null","text":"Recurring Nightmares. Every time you rest, make a Fear save. If you fail, lose 1d10 Calm and do not heal. The Warden will describe your nightmare.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AqZ9JqENaPSmFQbK]{+1 Recurring Nightmares}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[77,77],"drawn": false}, {"_id":"0kZQtWxO9P1voycZ","type":0,"documentCollection":"null","documentId":"null","text":"Emotional Detachment. You now lose half the Calm (rounded up) you normally would from all sources but you gain the Panic Effect of an Android, in addition to that of your own class. If you are an Android, gain the Panic Effect of a Marine.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.tdQu2wnAXXXcXfrO]{+1 Emotional Detachment}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[78,78],"drawn": false}, {"_id":"ToerE4a77WZvWJOS","type":0,"documentCollection":"null","documentId":"null","text":"Social Anxiety. Lose 1d10 Calm whenever you converse with someone new.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.HhofJYVhx3ovuyAw]{+1 Social Anxiety}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[79,79],"drawn": false}, {"_id":"GkdxvyW9kCKOcmnF","type":0,"documentCollection":"null","documentId":"null","text":"Escapism. You always have Disadvantage on Body Saves to prevent Addiction.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.sSYIhNQhEiWTs1ip]{+1 Escapism}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[80,80],"drawn": false}, {"_id":"V3glomGRXiHjnoZj","type":0,"documentCollection":"null","documentId":"null","text":"Hypervigilance. Gain Advantage on all surprise rolls but lose 1d10 Calm every day.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dSQgoBV6zSeQ1tqF]{+1 Hypervigilance}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[81,81],"drawn": false}, {"_id":"8Sv4YzhD3Zl5eBJo","type":0,"documentCollection":"null","documentId":"null","text":"General Anxiety. Your Maximum Calm decreases by 1d10.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.J61Srent4vEthGAn]{-1d10 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[82,82],"drawn": false}, {"_id":"yUDq43zxZKgnCWwB","type":0,"documentCollection":"null","documentId":"null","text":"Mild Anxiety. Your Maximum Calm decreases by 2.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.eoGfi5JdPASUUJU4]{-2 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[83,83],"drawn": false}, {"_id":"GJKxSWI2bxXyCNxT","type":0,"documentCollection":"null","documentId":"null","text":"Crippling Fear. Gain a new Phobia, determined by the Warden. Whenever you encounter this phobia make a Fear save at Disadvantage or lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.RTL29CqdaAriGSTS]{+1 Phobia}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[84,84],"drawn": false}, {"_id":"TOqb2JnInEfFipaR","type":0,"documentCollection":"null","documentId":"null","text":"Psychotic Break. Immediately attack the closest crew member until you do at least [[/r 2d10]] damage or 1 Hit, whichever comes first. If there is no crew member nearby, you attack the environment.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[85,85],"drawn": false}, {"_id":"AP8XSxwSK8fugXyc","type":0,"documentCollection":"null","documentId":"null","text":"Outburst. Suddenly shout, cry out, slam your fist against a wall, etc., making a loud noise. Nearby crew members lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[86,86],"drawn": false}, {"_id":"HylewV0kpxfLH6T9","type":0,"documentCollection":"null","documentId":"null","text":"Rattled. Disadvantage on all rolls for the rest of the session.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[87,87],"drawn": false}, {"_id":"KXtQ6JklVOBolFHf","type":0,"documentCollection":"null","documentId":"null","text":"Cowardice. Lose 1d10 Calm. For the rest of the session, you must make a Fear save to engage in combat.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.b0jk4XwP7by8a3uc]{+1 Coward}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[88,88],"drawn": false}, {"_id":"C0rWCutnv8a4X46J","type":0,"documentCollection":"null","documentId":"null","text":"Hallucinations. For the next [[/r 1d10]] hours (determined secretly), you have trouble distinguishing between reality and fantasy.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.Z7XPRgpTQqqi4M1n]{+1 Hallucinations}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[89,89],"drawn": false}, {"_id":"jIaGDvdasADYuAw1","type":0,"documentCollection":"null","documentId":"null","text":"Nervous Twitch. Lose 1d10 Calm. The nearest crew member also loses 1d5 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AvKZE5IFubIaAIUy]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[90,92],"drawn": false}, {"_id":"sCo5Gi5YZJJF4Gp3","type":0,"documentCollection":"null","documentId":"null","text":"Overwhelmed. Lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[93,96],"drawn": false}, {"_id":"QssxAQ8lw7rba9Us","type":0,"documentCollection":"null","documentId":"null","text":"Moment of Panic. Lose 1d5 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AvKZE5IFubIaAIUy]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[97,99],"drawn": false}, {"_id":"FmhTD6OzbqsJsaD3","type":0,"documentCollection":"null","documentId":"null","text":"Heart Races. Lose 1 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.qbq694JMbXeZrHjj]{-1 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[100,100],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"GCtYeCCQVQJ5M6SE","name":"Panic Check (Calm, Android)","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","description":"

    Eventually, Stress, Damage and emotional wear and tear will bring you to your breaking point. When that happens there’s a chance that you’ll lose control and Panic. To determine whether you are able to keep your cool under extreme pressure, make a Panic Check. While the results are primarily negative there is the possibility of grace under fire.

    ","formula":"1d100","replacement":true,"displayRoll":true,"results":[ {"_id":"HWOLLg9BaqHHTic6","type":0,"documentCollection":"null","documentId":"null","text":"Slagged: Gigeresque-Scanners Head Explosion. Everyone present gains a phobia and must make a Fear save or lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.R2KizR1soAhFYDZm]{Fear Save}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[1,39],"drawn": false}, {"_id":"rntpKYebltLa5OO7","type":0,"documentCollection":"null","documentId":"null","text":"Data Corruption: The Warden takes over your character, plagued by nightmarish malfunctions, permanently. Not even a factory reset will be helpful (the backups are corrupted as well).","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[40,59],"drawn": false}, {"_id":"FuB4kX2dhRCmmSnO","type":0,"documentCollection":"null","documentId":"null","text":"Reset to Factory Settings: You become terminally unstable and a full factory reset must be performed. Reroll a new character, but its name, equipment, current health, physical conditions, and Android class remain the same.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[60,64],"drawn": false}, {"_id":"nKsdhexbHjfgB36n","type":0,"documentCollection":"null","documentId":"null","text":"Cascade Failure: Death in [[/r 1d10]] minutes unless you receive urgent troubleshooting and repair. -1d10 to your Intellect.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.oYSjanH7BmmweIpp]{-1d10 Intellect}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[65,69],"drawn": false}, {"_id":"z5nwGQENMCEP7GOM","type":0,"documentCollection":"null","documentId":"null","text":"Rampancy: Once per session, the Warden may take over your character for one round. These episodes double in duration (or become twice as frequent) each session.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.wXobG3sUiQMLtGQs]{+1 Rampancy}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[70,70],"drawn": false}, {"_id":"DpEMe3Zwb48kNy7u","type":0,"documentCollection":"null","documentId":"null","text":"Fried Logic Core: Frenzied nonsensical behaviour. Whenever you lose Calm, everyone else nearby loses the same amount of Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.NDjuBKnMVPgJePNq]{+1 Fried Logic Core}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[71,71],"drawn": false}, {"_id":"J2r7KvRISQuUj5wg","type":0,"documentCollection":"null","documentId":"null","text":"Software Bloat: Lose double Calm from all sources.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.L4gRfMiEaxm3Xda5]{+1 Software Bloat}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[72,72],"drawn": false}, {"_id":"d6Wm36Qtcj7lGA4Y","type":0,"documentCollection":"null","documentId":"null","text":"Bit Rot: Whenever you would recover Calm, recover half as much instead.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.YYmZYNe8RWvhDFDz]{+1 Bit Rot}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[73,73],"drawn": false}, {"_id":"7mC8inwvnsLOHH4u","type":0,"documentCollection":"null","documentId":"null","text":"Deviant Logic Core: Whenever you make a Fear save, roll under your Fear or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.6PU4hmYOjHk4N0SY]{+1 Deviant Logic Core}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[74,74],"drawn": false}, {"_id":"V629RPnKA5wKx6n6","type":0,"documentCollection":"null","documentId":"null","text":"Faulty Heuristics: Whenever you make a Sanity save, roll under your Sanity or your Calm, whichever is lower.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.zLRsweb35Lw0NMev]{+1 Faulty Heuristics}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[75,75],"drawn": false}, {"_id":"OhdDuQ8gMp4GBtcD","type":0,"documentCollection":"null","documentId":"null","text":"Hardware Driver Failure: You lose motor function of one part of your body. Roll on the hit location table. If torso or head rolled, [-] on all rolls as head lolls around awkwardly unless supported.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[76,76],"drawn": false}, {"_id":"iwN6yTflt4D3roCN","type":0,"documentCollection":"null","documentId":"null","text":"Threat Assessment Failure: You lose the ability to discern friend from foe, treating all vaguely-humanoid entities as you would members of your crew.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.djzdZtIjROXN1dVB]{+1 Threat Assessment Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[77,77],"drawn": false}, {"_id":"MyJZnlKG0LJ59yWA","type":0,"documentCollection":"null","documentId":"null","text":"Ethical Directive Failure: You now lose half the Calm (rounded up) you normally would from all sources but you now have the Panic Effect of a Marine, in addition to that of an Android.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.WAyrlgcyR4I19Bqv]{+1 Ethical Directive Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[78,78],"drawn": false}, {"_id":"iNjsSW1iXWzpcCfy","type":0,"documentCollection":"null","documentId":"null","text":"Turing Test Failure: You have difficulty simulating humanity. Party make Fear Save or lose 1d10 Calm whenever you show up.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.3nrEYqwkhMs1Ch5v]{+1 Turing Test Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[79,79],"drawn": false}, {"_id":"vhrcho7GGbox9M5p","type":0,"documentCollection":"null","documentId":"null","text":"Ethical Directive Misread: Loses any expressiveness. Discusses the irrationality of Phobias, seeks to trigger them in others.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.9sKO5WUBwCW1YbR3]{+1 Ethical Directive Misread}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[80,80],"drawn": false}, {"_id":"P35RZJfLqM8QPpvt","type":0,"documentCollection":"null","documentId":"null","text":"Damage to Threat Assessment: Betray party member at the next opportunity, believing you are aiding the crew. All Calm lost is doubled for the next [[/r 1d10]] hours.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[81,81],"drawn": false}, {"_id":"3rCcCnxz7Ez582ZW","type":0,"documentCollection":"null","documentId":"null","text":"Bad Blocks: Your Maximum Calm decreases by 1d10.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.J61Srent4vEthGAn]{-1d10 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[82,82],"drawn": false}, {"_id":"t5iTm387wPsVrIAe","type":0,"documentCollection":"null","documentId":"null","text":"Fragmented Memory: Your Maximum Calm decreases by 2.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.eoGfi5JdPASUUJU4]{-2 Maximum Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[83,83],"drawn": false}, {"_id":"yZ8tnNN1HoaeycCz","type":0,"documentCollection":"null","documentId":"null","text":"Kernel Panic: Immediately reboot, lapsing into into a pseudo-catatonic state for [[/r 1d10]] rounds.","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[84,84],"drawn": false}, {"_id":"zu59Rvvc8vegrtPN","type":0,"documentCollection":"null","documentId":"null","text":"Killswitch Engaged: Go berserk, will not withdraw from combat regardless of situation, will not ashere to tactics.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.tQltbIC9ahDwNsTp]{+1 Killswitch Engaged}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[85,85],"drawn": false}, {"_id":"qrkXSXkbn5oymjBl","type":0,"documentCollection":"null","documentId":"null","text":"Feedback Loop: Take 1d10 damage from overdriven repetitive motion. Everyone else nearby make Fear saves or lose 1d5 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.w3ttEaXP7yp25M5Q]{-1d10 Health}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AvKZE5IFubIaAIUy]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[86,86],"drawn": false}, {"_id":"ErmpxrA7QnjJ5QOO","type":0,"documentCollection":"null","documentId":"null","text":"Vocalization Failure: Intermittently shrieks like a fax machine under duress. Cannot communicate or sneak for [[/r 2d10]] hours. Nearby crew members lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.bJWFhod0YA8ln8H8]{+1 Vocalization Failure}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[87,87],"drawn": false}, {"_id":"OLJTaMVRK13dJpNl","type":0,"documentCollection":"null","documentId":"null","text":"Inventories Particles of Dust By Grade: Cannot engage in any other tasks for [[/r 1d5]] hours. Everyone else nearby loses 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[88,88],"drawn": false}, {"_id":"ewJ6G0cFV00tq87l","type":0,"documentCollection":"null","documentId":"null","text":"Incorrectly States the Odds: For [[/r 2d10]] hours distracts others, insisting impossible tasks are trivial, and that trivial tasks are impossible. Anyone attempting a complex task must make a Fear save or lose 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.R2KizR1soAhFYDZm]{Fear Save}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[89,89],"drawn": false}, {"_id":"GXYDv0D5ziopFB19","type":0,"documentCollection":"null","documentId":"null","text":"Organises Objects into Geometric Patterns: Unnerving. Everyone else nearby loses 1d10 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jHyqXb2yDFTNWxpy]{-1d10 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[90,92],"drawn": false}, {"_id":"LNR14WhinNejIKvP","type":0,"documentCollection":"null","documentId":"null","text":"Explains the Etymology of Words: Distracting. Everyone else nearby loses 1d5 Calm. The next check a nearby crewmember makes gains [-].

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.AvKZE5IFubIaAIUy]{-1d5 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[93,96],"drawn": false}, {"_id":"WBqcIfMznk4lvPgb","type":0,"documentCollection":"null","documentId":"null","text":"States the Odds: Annoying. Everyone else nearby loses 1 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.qbq694JMbXeZrHjj]{-1 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[97,99],"drawn": false}, {"_id":"SU9ggXRsL88CNb6N","type":0,"documentCollection":"null","documentId":"null","text":"Segfault: Lose 1 Calm.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.qbq694JMbXeZrHjj]{-1 Calm}","img":"systems/mosh/images/icons/ui/rolltables/panic_check.png","weight":1,"range":[100,100],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"31YibfjueXuZdNLb","name":"Blunt Force Wound","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","description":"

    Whenever you gain a Blunt Force Wound, roll on this table to determine the effect. Flesh Wounds are small inconveniences. Minor/Major Injuries cause lasting issues which require medical treatment. Lethal Injuries can kill you if not dealt with immediately. Fatal Injuries can kill outright. Bleeding wounds, if not treated can quickly overwhelm you.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"kGDBRdD9azQLJRDl","type":0,"documentCollection":"null","documentId":"null","text":"Flesh Wound: Knocked down.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"mYsLkuttsbN0PPzE","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Winded. [-] until you catch your breath.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"RnmOw1OvhVaYQsJV","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Sprained Ankle. [-] on Speed Checks.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"rCPAVwvuRI5PDapO","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Concussion. [-] on mental tasks.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"gYfGKit1I8vIlXas","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Leg or foot broken. [-] on Speed Checks.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"Xvo8mQoXzQb18gms","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Arm or hand broken. [-] on manual tasks.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"AiacUbJlw1slbsW3","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Snapped collarbone. [-] on Strength Checks.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"bxD3uLX6GcVG7kwG","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Back broken. [-] on all rolls. Death Save in [[/r 1d10]] rounds.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"5WHDRIu6o2xp1Vml","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Skull cracked. [-] on all rolls. Death Save in [[/r 1d10]] rounds.","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"NzrMxLpPo52Ayoq7","type":0,"documentCollection":"null","documentId":"null","text":"Fatal Injury: Spine or neck broken. Death Save.

    @UUID[Compendium.mosh.macros_hotbar_1e.Macro.NsRHfRuuNGPfkYVf]{Death Save}","img":"systems/mosh/images/icons/ui/rolltables/wounds_blunt_force.png","weight":1,"range":[9,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"ata3fRz3uoPfNCLh","name":"Bleeding Wound","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","description":"

    Whenever you gain a Bleeding Wound, roll on this table to determine the effect. Flesh Wounds are small inconveniences. Minor/Major Injuries cause lasting issues which require medical treatment. Lethal Injuries can kill you if not dealt with immediately. Fatal Injuries can kill outright. Bleeding wounds, if not treated can quickly overwhelm you.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"58jsAYGMOoYV0aXe","type":0,"documentCollection":"null","documentId":"null","text":"Flesh Wound: Drop held item.","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"qVUXginkyIDKa6fe","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Lots of blood. Those Close gain 1 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.dvJR9DYXI2kV0BbR]{+1 Stress}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"uvF7ftDjXr9excYX","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Blood in eyes. [-] until wiped clean.","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"5ED6Ynmibq9pKDEk","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Laceration. Bleeding +1.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BH7tgbDVH6jdcZ4u]{+1 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"hO9e9wmIsTXWfZns","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Major cut. Bleeding +2.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.IIVNXuhckFQfzXah]{+2 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"8eTGRuBUdp9s2Z46","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Fingers/toes severed. Bleeding +3.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.LawygQJAPu8XEnSc]{+3 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"FZ9GwrHFQJUmHQ7k","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Hand/foot severed. Bleeding +4.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.QkCJK7Vmda5bGAA7]{+4 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"kLAtlJUE9QfCX38s","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Limb severed. Bleeding +5. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.CZ2gqnRHcOpCLlG0]{+5 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"806d8NZZaysIHJvm","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Major artery cut. Bleeding +6. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.Tx19z2BhTY6onldp]{+6 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"439gBR7gGeLatpfl","type":0,"documentCollection":"null","documentId":"null","text":"Fatal Injury: Throat slit or heart pierced. Death Save.

    @UUID[Compendium.mosh.macros_hotbar_1e.Macro.NsRHfRuuNGPfkYVf]{Death Save}","img":"systems/mosh/images/icons/ui/rolltables/wounds_bleeding.png","weight":1,"range":[9,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"XjDU2xFOWEasaZK0","name":"Gunshot Wound","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","description":"

    Whenever you gain a Gunshot Wound, roll on this table to determine the effect. Flesh Wounds are small inconveniences. Minor/Major Injuries cause lasting issues which require medical treatment. Lethal Injuries can kill you if not dealt with immediately. Fatal Injuries can kill outright. Bleeding wounds, if not treated can quickly overwhelm you.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"LubF6RyYnl11EmUj","type":0,"documentCollection":"null","documentId":"null","text":"Flesh Wound: Grazed. Knocked down.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"EFQBqcegsqHQ4Jih","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Bleeding +1.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BH7tgbDVH6jdcZ4u]{+1 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"tNz8bKJY9cDDQmQ6","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Broken rib.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"YwdH5Q7uuxu78jQp","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Fractured extremity.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"kOw2Sk8NgE5zWvGz","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Internal bleeding. Bleeding +2.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.IIVNXuhckFQfzXah]{+2 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"1EEfUVqLk1vcvmBl","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Lodged bullet. Surgery required.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"4si8KPgRXJSi2R94","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Gunshot wound to the neck.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"wbmBeO70jbk5cNAi","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Major blood loss. Bleeding +4. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.QkCJK7Vmda5bGAA7]{+4 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"SXF0bbAqIyqvPvb9","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Sucking chest wound. Bleeding +5. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.CZ2gqnRHcOpCLlG0]{+5 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"8rlgfH4GJ8H0LHhL","type":0,"documentCollection":"null","documentId":"null","text":"Fatal Injury: Headshot. Death Save.

    @UUID[Compendium.mosh.macros_hotbar_1e.Macro.NsRHfRuuNGPfkYVf]{Death Save}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gunshot.png","weight":1,"range":[9,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"lqiaWwh5cGcJhvnu","name":"Fire & Explosives Wound","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","description":"

    Whenever you gain a Fire & Explosives Wound, roll on this table to determine the effect. Flesh Wounds are small inconveniences. Minor/Major Injuries cause lasting issues which require medical treatment. Lethal Injuries can kill you if not dealt with immediately. Fatal Injuries can kill outright. Bleeding wounds, if not treated can quickly overwhelm you.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"VYN9lwpyPTW4Hnmh","type":0,"documentCollection":"null","documentId":"null","text":"Flesh Wound: Hair burnt. Gain 1d5 Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.luNKvwmm2tjUJhT6]{+1d5 Stress}","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"V3np2nl2cIVshF5D","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Awesome scar. +1 Minimum Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BmEHWH7YxV9qb21p]{+1 Minimum Stress}","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"Wen5sWpWmN2j4Zcb","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Singed. [-] on next action.","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"OD9Ilkg4OA11sU8H","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Shrapnel/large burn.","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"0BvZK2vdM2oweYvg","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: 3rd degree burns.","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"syEHXuDiZFwD4l4G","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Major Burn. Body Save -2d10.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.ISd2nEMYvWCPQpl0]{-2d10 Body Save}","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"MRl6Iid4Xgjb6myY","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Skin grafts required. Body Save -2d10.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.ISd2nEMYvWCPQpl0]{-2d10 Body Save}","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"bHNeXD95WH4o2Rjz","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Limb on fire. 2d10 Damage per round. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.pS6A6OklvM6S3bvO]{-2d10 Health}","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"F9aNmmfK5oSh4kAs","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Body on fire. 3d10 Damage per round. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.nECUu4pcwsNTE8C5]{-3d10 Health}","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"V0ZCYS4xQCoqnKuC","type":0,"documentCollection":"null","documentId":"null","text":"Fatal Injury: Engulfed in fiery explosion. Death Save.

    @UUID[Compendium.mosh.macros_hotbar_1e.Macro.NsRHfRuuNGPfkYVf]{Death Save}","img":"systems/mosh/images/icons/ui/rolltables/wounds_fire_&_explosives.png","weight":1,"range":[9,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"uVfC1CqYdojaJ7yR","name":"Gore & Massive Wound","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","description":"

    Whenever you gain a Gore & Massive Wound, roll on this table to determine the effect. Flesh Wounds are small inconveniences. Minor/Major Injuries cause lasting issues which require medical treatment. Lethal Injuries can kill you if not dealt with immediately. Fatal Injuries can kill outright. Bleeding wounds, if not treated can quickly overwhelm you.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"aJN3DtKVY9bG3ubv","type":0,"documentCollection":"null","documentId":"null","text":"Flesh Wound: Vomit. [-] on next action.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"Lf5EQIYpu4DXFQix","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Awesome scar. +1 Minimum Stress.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BmEHWH7YxV9qb21p]{+1 Minimum Stress}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"1NnoNAENwZjlIxh8","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Digit mangled.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"8iAPqxJpCEgQJXq6","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Eyes gouged out.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"NcPFW20iV54oar6P","type":0,"documentCollection":"null","documentId":"null","text":"Minor Injury: Ripped off flesh. -1d10 Strength.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.V3L1iRkWwyTzCZK9]{-1d10 Strength}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"QP4863dIgMJ28XWs","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Paralysed waist down.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"ayHuDn1OuCcbgCZt","type":0,"documentCollection":"null","documentId":"null","text":"Major Injury: Limb severed. Bleeding +5.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.CZ2gqnRHcOpCLlG0]{+5 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"h2hZbBnnY5DVnyLL","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Impaled. Bleeding +6. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.Tx19z2BhTY6onldp]{+6 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"JB623Z5gI9hP5cOs","type":0,"documentCollection":"null","documentId":"null","text":"Lethal Injury: Guts spooled on floor. Bleeding +7. Death Save in [[/r 1d10]] rounds.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.ZJaVFBB0Kslv1k4f]{+7 Bleeding}","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"9LPNxRgcnpZHjENW","type":0,"documentCollection":"null","documentId":"null","text":"Fatal Injury: Head explodes.

    No Death Save. You have died.","img":"systems/mosh/images/icons/ui/rolltables/wounds_gore_&_massive.png","weight":1,"range":[9,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"UxAjAqUTjYTcCbS8","name":"Distress Signal","img":"systems/mosh/images/icons/ui/rolltables/distress_signal.png","description":"

    Occasionally you may need to put your ship on emergency power, seal yourselves in cryopods, send out a Distress Signal, and wait for help. It’s a long shot, but sometimes it’s the only shot you’ve got. When this happens, roll on this table.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"4W0riCssZ2SEzGLe","type":0,"documentCollection":"null","documentId":"null","text":"[[2D10]] WEEKS. You’re one of the lucky ones.","img":"systems/mosh/images/icons/ui/rolltables/distress_signal.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"tG7DvLzk0nIDsGxH","type":0,"documentCollection":"null","documentId":"null","text":"[[2D10]] MONTHS. Note to self: Remember to review Company policy on backpay in the event of a cryoemergency.","img":"systems/mosh/images/icons/ui/rolltables/distress_signal.png","weight":1,"range":[1,2],"drawn": false}, {"_id":"Bx4dP1VaEfohIdO9","type":0,"documentCollection":"null","documentId":"null","text":"[[2D10]] YEARS. Make a Body Save or lose 1d5 to all Stats and Saves.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3gqTFFwMe7AudiS]{Body Save}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.SeMStXQGIaeiLwvw]{-1d5 All Stats/Saves}","img":"systems/mosh/images/icons/ui/rolltables/distress_signal.png","weight":1,"range":[3,4],"drawn": false}, {"_id":"K9MvgxDKYTflPZDl","type":0,"documentCollection":"null","documentId":"null","text":"[[2D10]] DECADES. Make a Body Save [-] or lose 1d10 to all Stats and Saves.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.ItHLy3URKFQVLipe]{Body Save [-]}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.2MuANcdgp2g8SDlF]{-1d10 All Stats/Saves}","img":"systems/mosh/images/icons/ui/rolltables/distress_signal.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"rFLMF0FIuJOK582Z","type":0,"documentCollection":"null","documentId":"null","text":"NEVER. The ship floats endlessly in the all consuming void of space. Thanks for playing Mothership.","img":"systems/mosh/images/icons/ui/rolltables/distress_signal.png","weight":1,"range":[6,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"AqGWwoWXzijFs427","name":"Megadamage Effects","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","description":"

    Megadamage (MDMG) is like a character’s Damage and Wounds rolled into one. Whenever your ship takes MDMG, add it to any previous MDMG incurred, mark the new total on the tracker, and apply the listed effect. If your ship ever has 9 or more total MDMG, it is destroyed. Your ship ignores all MDMG less than its Hull. If the ship ever takes MDMG greater than or equal to its Hull in one hit, the hull is destroyed and the ship suffers any remaining MDMG.

    ","formula":"1d10-1","replacement":true,"displayRoll":true,"results":[ {"_id":"ENq0mvm5iqtMh1ft","type":0,"documentCollection":"null","documentId":"null","text":"ALL SYSTEMS NORMAL.
    5x5. Ready to ride.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"yVzV5Y0tNWSqPVpS","type":0,"documentCollection":"null","documentId":"null","text":"EMERGENCY FUEL LEAK.
    Every time you spend fuel, you spend 1 more.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"Vnfbw2I9XRvrjKQ0","type":0,"documentCollection":"null","documentId":"null","text":"WEAPONS OFFLINE.
    Automatically fail Battle Checks.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"qPV5sasqyDgWwNiW","type":0,"documentCollection":"null","documentId":"null","text":"NAVIGATION OFFLINE.
    Cannot make Thruster Checks. 10% chance all navigation data wiped.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"kGOebdOLWOZBekvw","type":0,"documentCollection":"null","documentId":"null","text":"FIRE ON DECK.
    Fire spreads throughout the ship, creating a toxic atmosphere (due to smoke inhalation) and a highly corrosive atmosphere (10 DMG/round) for locations on fire.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"etnepA2VTtuv2iyc","type":0,"documentCollection":"null","documentId":"null","text":"HULL BREACH.
    All aboard make a Body Save or take 1 Wound (Explosion). On a Critical Failure, get violently sucked into space.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"ay9hN3EYsAJOKUeZ","type":0,"documentCollection":"null","documentId":"null","text":"LIFE SUPPORT SYSTEMS OFFLINE.
    Oxygen limited to 1d10 multiplied by the maximum crew capacity.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"gNqK1zdrt9AUacUg","type":0,"documentCollection":"null","documentId":"null","text":"RADIATION LEAK.
    Radiation Level increases every 2d10 minutes.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"kmZfxrotglCOUw8M","type":0,"documentCollection":"null","documentId":"null","text":"DEAD IN THE WATER.
    All systems offline, emergency power only.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"A3XHL5OaSekv3OF3","type":0,"documentCollection":"null","documentId":"null","text":"ABANDON SHIP!
    Ship is destroyed in 1d10 minutes.","img":"systems/mosh/images/icons/ui/rolltables/megadamage_effects.png","weight":1,"range":[9,9],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} +{"_id":"kqz8GsFVPfjvqO0N","name":"Maintenance Issues","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","description":"

    Eventually, your ship needs a tune-up, or sometimes a complete overhaul. When this happens, you’ll need to get it repaired. Minor Repairs cover cosmetic damage, cleanup, and other handyman type work that can be handled by the crew while the ship is in flight. Minor Repairs take roughly [[/r 2d10]] days. Major Repairs cover large scale structural or system damage, including repairing Megadamage and Hull. Major Repairs can only be fixed in port.

    ","formula":"1d100-1","replacement":true,"displayRoll":true,"results":[ {"_id":"IyZRbv37zFiJ383B","type":0,"documentCollection":"null","documentId":"null","text":"Rancid smell permeates cabins.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.ciAkQXkxSXTG8MV1]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[0,0],"drawn": false}, {"_id":"C0ZgIm60S90TAT91","type":0,"documentCollection":"null","documentId":"null","text":"Huge mess everywhere.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.pLleYaFjcIuAm4Pp]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[1,1],"drawn": false}, {"_id":"eTkF90oClQfEzqnO","type":0,"documentCollection":"null","documentId":"null","text":"Staticky comms.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.dReCCsfiV7it4lsm]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[2,2],"drawn": false}, {"_id":"1eCoLlXdJOBH9PWj","type":0,"documentCollection":"null","documentId":"null","text":"Faulty electrical system.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.4JRD71mvWNtFUDL7]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[3,3],"drawn": false}, {"_id":"0OAtazWzOPLEfTkw","type":0,"documentCollection":"null","documentId":"null","text":"Loose couplings.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.59cXdcrZlmjUcJpV]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[4,4],"drawn": false}, {"_id":"PfUxdaS1uo7lxKa3","type":0,"documentCollection":"null","documentId":"null","text":"Hidden (highly illegal) contraband.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.CLvIvoNryBARtU7T]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[5,5],"drawn": false}, {"_id":"nix5zKmEronI6Yvv","type":0,"documentCollection":"null","documentId":"null","text":"Autopilot systems down.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.vip6FxWcX4ReJD3b]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[6,6],"drawn": false}, {"_id":"sbObgOY0tmHaZpKG","type":0,"documentCollection":"null","documentId":"null","text":"Leaking hydraulic systems.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.AQt9nXy6S0Ev50r7]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[7,7],"drawn": false}, {"_id":"gyTPedRpwTvRBfhT","type":0,"documentCollection":"null","documentId":"null","text":"Creaking hull.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.QUyfvbFhCqb9d7Lu]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[8,8],"drawn": false}, {"_id":"I11M8UMDMBitMr3v","type":0,"documentCollection":"null","documentId":"null","text":"Damaged bulkheads.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.SW5kVSjiFbBxIeiu]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[9,9],"drawn": false}, {"_id":"SWXQhPfu8y8XFzRM","type":0,"documentCollection":"null","documentId":"null","text":"Misaligned docking clamps.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.wNm669fzbdZGwr0g]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[10,10],"drawn": false}, {"_id":"zbhqG61KG97AHnxy","type":0,"documentCollection":"null","documentId":"null","text":"Viewports blocked.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.3l0LUZpjizvZmHWs]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[11,11],"drawn": false}, {"_id":"TUWadEIBbOEtHy3z","type":0,"documentCollection":"null","documentId":"null","text":"Jammed exterior airlocks.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.c8SXxPHMsG7uycas]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[12,12],"drawn": false}, {"_id":"ynAJiaLcVAE3HIjG","type":0,"documentCollection":"null","documentId":"null","text":"Dysfunctional gravity plating.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.9kS8VjGuSMpghdCk]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[13,13],"drawn": false}, {"_id":"DtVeZrxUIjJoPqFH","type":0,"documentCollection":"null","documentId":"null","text":"Out of code compliance.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.Low2X1z7m1iB3rkA]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[14,14],"drawn": false}, {"_id":"WgmjKOE5Iv3Gq1lg","type":0,"documentCollection":"null","documentId":"null","text":"Controls sticking.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.BicB3xA1h978ZevJ]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[15,15],"drawn": false}, {"_id":"ls4xOoWbhod4xcK5","type":0,"documentCollection":"null","documentId":"null","text":"Coolant leak.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.C9dQYp7gcjtq5QRz]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[16,16],"drawn": false}, {"_id":"Z6UTZnadXEZAbtnx","type":0,"documentCollection":"null","documentId":"null","text":"Miscalibrated Thruster Gimbal System.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.1HNvL7XEUcMQbLps]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[17,17],"drawn": false}, {"_id":"jLmjfUWSNdD3dRwk","type":0,"documentCollection":"null","documentId":"null","text":"Bevvy of OSHA violations.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.xa9MPzfrPglkSJjg]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[18,18],"drawn": false}, {"_id":"MXvxkk3A53nEUVjW","type":0,"documentCollection":"null","documentId":"null","text":"Blocked air vents.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.ZbAFemnvHB1YTHBK]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[19,19],"drawn": false}, {"_id":"uITLtr1tukKg6GH3","type":0,"documentCollection":"null","documentId":"null","text":"Emergency lighting only.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.wjyAZnOOafvv4xzB]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[20,20],"drawn": false}, {"_id":"Dy29r0yTcurlTOb3","type":0,"documentCollection":"null","documentId":"null","text":"Internal networking issues.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.l1OGQ0IXZHjnO4Ys]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[21,21],"drawn": false}, {"_id":"bN364EHfBPjRPV1k","type":0,"documentCollection":"null","documentId":"null","text":"Inaccurate data collection.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.vleMoz5bbkZ5w28o]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[22,22],"drawn": false}, {"_id":"SdzntkGxTPxc0mBk","type":0,"documentCollection":"null","documentId":"null","text":"Oxygen leak. If ship is low on O2, lose 1d5 extra per day.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.u7TchSo3qutnzaKF]{-1d5 Oxygen}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.T4wAR08WyT3g9C6D]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[23,23],"drawn": false}, {"_id":"3FAjfGNOdUhikeaT","type":0,"documentCollection":"null","documentId":"null","text":"Throttled Afterburners. -2d10 Thrusters.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.jmOh8n2ps0YIeBC0]{-2d10 Thrusters}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.fbrN7sbgPjIwkk7I]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[24,24],"drawn": false}, {"_id":"yJjr6ttFIL0Tm1Q0","type":0,"documentCollection":"null","documentId":"null","text":"Lemon. Maintenance Checks at [-].

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.C04VbNoj8LgfY8QK]{Maintenance Check [-]}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.7GqbGIOzA9vYOPiI]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[25,25],"drawn": false}, {"_id":"iYG96XjPC5zAo8qm","type":0,"documentCollection":"null","documentId":"null","text":"Slow acceleration. +1 Week to travel.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.dgisAPnBbrIOiisk]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[26,26],"drawn": false}, {"_id":"esUyqvuWPGfPps0s","type":0,"documentCollection":"null","documentId":"null","text":"Inaccurate navigation.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.d94uF9rpmeP60Kl4]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[27,27],"drawn": false}, {"_id":"DkIuGgcrI6Jur9Cr","type":0,"documentCollection":"null","documentId":"null","text":"Miscalibrated Targeting Sensors. -1d10 Battle.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.X3cL9eS2HOPxhLH5]{-1d10 Battle}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.3Ptitg8HBZfl2CXN]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[28,28],"drawn": false}, {"_id":"QBBJru6guS5DCeTT","type":0,"documentCollection":"null","documentId":"null","text":"Faulty Cryopods. Nightmares. Cryosickness lasts an additional week.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.mK1Acfk5NAgs1MHC]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[29,29],"drawn": false}, {"_id":"ZHmFbVcuh2DAOVEf","type":0,"documentCollection":"null","documentId":"null","text":"Malfunctioning escape pods.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.IR1sWnYXniMg9TdP]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[30,30],"drawn": false}, {"_id":"XEgBLTIutnbQ8wjj","type":0,"documentCollection":"null","documentId":"null","text":"Unable to send distress signals.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.FIqSHePAeLJywerx]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[31,31],"drawn": false}, {"_id":"Lkm8VtpQRjICLlwU","type":0,"documentCollection":"null","documentId":"null","text":"Sabotaged coolant system.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.4kmMuAbW1jnfVMYP]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[32,32],"drawn": false}, {"_id":"038MckXaAQARD67V","type":0,"documentCollection":"null","documentId":"null","text":"Death trap. [-] on all rolls.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.ALplRgZtneMRdloo]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[33,33],"drawn": false}, {"_id":"oUetfiowLXa1LAoD","type":0,"documentCollection":"null","documentId":"null","text":"Worn landing struts.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.2pxf4O2NrLdwYRtO]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[34,34],"drawn": false}, {"_id":"Z52rxcwBR1l2ioZV","type":0,"documentCollection":"null","documentId":"null","text":"Out-of-date air filters.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.64AQJ3zQDOb7NOR1]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[35,35],"drawn": false}, {"_id":"uUwTRxD7VL9uOPI1","type":0,"documentCollection":"null","documentId":"null","text":"Corroded pipes.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.PKBXKvgWZwafKWJ3]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[36,36],"drawn": false}, {"_id":"ha1AgBUXwSB0YvLZ","type":0,"documentCollection":"null","documentId":"null","text":"Innaccurate orbital transfer navigation.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.NgKPVhRkD8Gteo5Z]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[37,37],"drawn": false}, {"_id":"pIwClgLjhzBxWjQB","type":0,"documentCollection":"null","documentId":"null","text":"Worn out fuel injection nozzles.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.5d220ZzrEV3qx6Fy]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[38,38],"drawn": false}, {"_id":"uPVo13V46Gn7UdGQ","type":0,"documentCollection":"null","documentId":"null","text":"Inoperative exterior lighting system.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.IGx8nQrwfz07r6TR]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[39,39],"drawn": false}, {"_id":"mHxQpOcW3O3zoHqc","type":0,"documentCollection":"null","documentId":"null","text":"Defective intercom system.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.pW1FUDxp2N0M0D1y]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[40,40],"drawn": false}, {"_id":"RAEu9fESI7Kb3IsO","type":0,"documentCollection":"null","documentId":"null","text":"Inadequate waste recycling.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.UPAxtEOrSF3Il4uA]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[41,41],"drawn": false}, {"_id":"ZilkOLl2fqpMxTCK","type":0,"documentCollection":"null","documentId":"null","text":"Faulty altitude control thrusters.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.m04JdXL1xGQOkDyp]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[42,42],"drawn": false}, {"_id":"uwF7IfVg4DTCrkEY","type":0,"documentCollection":"null","documentId":"null","text":"Insufficient Life Support redundancy.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.OWkfB73RTSLDMlsU]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[43,43],"drawn": false}, {"_id":"XtidrkdiZPuXrSD9","type":0,"documentCollection":"null","documentId":"null","text":"Delayed communication relays.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.hNJYqetiMKUlZzYH]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[44,44],"drawn": false}, {"_id":"d0aLCaYUFBvm3A8D","type":0,"documentCollection":"null","documentId":"null","text":"Damaged fuel lines.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.rlW0LUlsK7vDGZEh]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[45,45],"drawn": false}, {"_id":"wyaIb9XoOYTr8l56","type":0,"documentCollection":"null","documentId":"null","text":"Corroded exhaust manifolds.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.IDiwAbD8DTbec7S1]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[46,46],"drawn": false}, {"_id":"8e3FhcBmlf4TobEP","type":0,"documentCollection":"null","documentId":"null","text":"Terminal displays non-functional.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.EteEoBrlnzcySppN]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[47,47],"drawn": false}, {"_id":"mWZZ3GgXZeaIWKq4","type":0,"documentCollection":"null","documentId":"null","text":"Check engine light won’t turn off.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.guvCGNRa75AB2Avg]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[48,48],"drawn": false}, {"_id":"uUbSTVqzPH0XUO5T","type":0,"documentCollection":"null","documentId":"null","text":"Failed backup systems.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.cbXMdd4ugxSOT5TU]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[49,49],"drawn": false}, {"_id":"5bSHAIUf6NsGPtkl","type":0,"documentCollection":"null","documentId":"null","text":"Faulty door locks.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.kftgvuQoefQ7pl28]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[50,50],"drawn": false}, {"_id":"lfEjfRS1T1xGw4Nt","type":0,"documentCollection":"null","documentId":"null","text":"Buggy communications.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.Odpb5coSTST7kCkc]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[51,51],"drawn": false}, {"_id":"ZOPIRA0fnXVSQo5D","type":0,"documentCollection":"null","documentId":"null","text":"Infected food storage facilities.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.vMRVXZxu6ozj0iw2]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[52,52],"drawn": false}, {"_id":"5YHIGpIFC7xm5BQv","type":0,"documentCollection":"null","documentId":"null","text":"Corrupted data banks.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.4Lqg0lqjjTlNlr0j]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[53,53],"drawn": false}, {"_id":"pjyyj4uVkJcwKtSK","type":0,"documentCollection":"null","documentId":"null","text":"Jammed cargo bay doors.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.Ka8elMGKtcakUIxx]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[54,54],"drawn": false}, {"_id":"IaEAcW8uwekpS8EW","type":0,"documentCollection":"null","documentId":"null","text":"Flickering interior lights.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.TAerNMqv19pANCxq]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[55,55],"drawn": false}, {"_id":"Ru2TBxEYhuBx8Cn4","type":0,"documentCollection":"null","documentId":"null","text":"Failed airlock seals.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.vv1VykTwiQmgEj6N]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[56,56],"drawn": false}, {"_id":"iuZDnxPMmNE2H8T6","type":0,"documentCollection":"null","documentId":"null","text":"Fuel Leak. Burn +1 Fuel everytime you spend fuel.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.GW1KGmYdxYYf4ZWT]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[57,57],"drawn": false}, {"_id":"0PNCNoYdxWJA8pJ1","type":0,"documentCollection":"null","documentId":"null","text":"Jump Bug. 10% chance Jump takes 2d10 months, not 2d10 days.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.FLaPtHcegheN7wHw]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[58,58],"drawn": false}, {"_id":"vwv4akGBUkDSzVet","type":0,"documentCollection":"null","documentId":"null","text":"Fragile. Always take +1 MDMG.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.g9Z7He5zPHNrxYe1]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[59,59],"drawn": false}, {"_id":"ZWZaNrksEIrvkw0a","type":0,"documentCollection":"null","documentId":"null","text":"Cracked heat shields.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.IiPryFS9MOGZXeuG]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[60,60],"drawn": false}, {"_id":"C4bKdbAe1rGL4Xdu","type":0,"documentCollection":"null","documentId":"null","text":"Outdated software. -1d10 Systems.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.oDftFxRKkCQRNY2O]{-1d10 Systems}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.FmPqHYH3UoGpaWYL]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[61,61],"drawn": false}, {"_id":"nkBNqVm7dfv4L7Se","type":0,"documentCollection":"null","documentId":"null","text":"Inadequate Water Filtration. Parasites in the water supply.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.NLwybTzXJ1bndki3]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[62,62],"drawn": false}, {"_id":"XTA2gczwQ6svM3JU","type":0,"documentCollection":"null","documentId":"null","text":"Malfunctioning waste management system.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.oySXnFIbRW0WRoeF]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[63,63],"drawn": false}, {"_id":"CBKVd5xeJTqFZhqN","type":0,"documentCollection":"null","documentId":"null","text":"Fusion Reactors overheating.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.RiHvRQ9nZDygwvvB]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[64,64],"drawn": false}, {"_id":"0r2hvYBfdrLp1Fd0","type":0,"documentCollection":"null","documentId":"null","text":"Failed radiation filter.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.wCYGQrI9qonhWy8F]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[65,65],"drawn": false}, {"_id":"ZWaPQw3J8v9irvsJ","type":0,"documentCollection":"null","documentId":"null","text":"Radiation leak. Entire ship is at Radiation Level 2.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.5J4r3yw4xDj890yZ]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[66,66],"drawn": false}, {"_id":"EWeonowwk9JY7UDo","type":0,"documentCollection":"null","documentId":"null","text":"Miscalibrated guidance system.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.XmIcQgho4un7hYki]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[67,67],"drawn": false}, {"_id":"hD1NP45qwjxr51vQ","type":0,"documentCollection":"null","documentId":"null","text":"Overloaded power storage.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.KhlrUaPjVIoyhnaL]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[68,68],"drawn": false}, {"_id":"UAjsBmmS82j8Irw3","type":0,"documentCollection":"null","documentId":"null","text":"Malfunctioning sensor arrays.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.LRumIQdUBzD0Jc0X]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[69,69],"drawn": false}, {"_id":"ndMPpWBt7TETFN5x","type":0,"documentCollection":"null","documentId":"null","text":"Failed Water Recovery System.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.e144cIdUEyTJgN1G]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[70,70],"drawn": false}, {"_id":"QcsbthzAbdnETOZB","type":0,"documentCollection":"null","documentId":"null","text":"Micrometoroid hull damage.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.b2b3j5JtanbyWlNd]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[71,71],"drawn": false}, {"_id":"JakRLX2zyPrI10Pb","type":0,"documentCollection":"null","documentId":"null","text":"Faulty Carbon Dioxide Removal Assembly.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.5OBjTojgrp5N9mEw]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[72,72],"drawn": false}, {"_id":"NISfAAR2ECI2ioE1","type":0,"documentCollection":"null","documentId":"null","text":"Solar panel degradation.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.8s1eBY5bEcQQTCz0]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[73,73],"drawn": false}, {"_id":"yp8FBNHjXWojwg3H","type":0,"documentCollection":"null","documentId":"null","text":"Computer failure from cosmic radiation.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.5UiJy739gvGHkRYp]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[74,74],"drawn": false}, {"_id":"697i67021D88RIbg","type":0,"documentCollection":"null","documentId":"null","text":"Overloaded circuitry.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.yJY9CzP1KA15aMqV]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[75,75],"drawn": false}, {"_id":"V8I6X6TZUHlrDUNk","type":0,"documentCollection":"null","documentId":"null","text":"Malfunctioning plasma thruster.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.nHac0gkEcCNew7RX]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[76,76],"drawn": false}, {"_id":"6wy2JtIKZik32G27","type":0,"documentCollection":"null","documentId":"null","text":"Thermal management system failure.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.DYHuVA4CQlmK2MJy]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[77,77],"drawn": false}, {"_id":"lVi2h8AvOE8SF06p","type":0,"documentCollection":"null","documentId":"null","text":"Intermittent electrical outages.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.QIcoFYoC0hxW84qD]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[78,78],"drawn": false}, {"_id":"Ip8GIZLR3f0TxRkW","type":0,"documentCollection":"null","documentId":"null","text":"Fire suppression system out of code.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.AuTERG3m7ECQKrKs]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[79,79],"drawn": false}, {"_id":"hIuA8Rx1YcRVMf6H","type":0,"documentCollection":"null","documentId":"null","text":"Damaged floor pannelling.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.1iOSKp82goZGJZch]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[80,80],"drawn": false}, {"_id":"g2YZ56OllRPkuGFf","type":0,"documentCollection":"null","documentId":"null","text":"Broken light fixture in remote corridor.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.ZBUtxiX72udqLzIk]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[81,81],"drawn": false}, {"_id":"mXz81hgLUolDq7wr","type":0,"documentCollection":"null","documentId":"null","text":"Damaged coolant pump.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.iwFmPpAth3VbRRL8]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[82,82],"drawn": false}, {"_id":"PENJ768OdQpKKg6w","type":0,"documentCollection":"null","documentId":"null","text":"Cracked viewports.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.Eo0l4WMxcS62GCMP]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[83,83],"drawn": false}, {"_id":"qkGhdVs179LjB3MD","type":0,"documentCollection":"null","documentId":"null","text":"Systems overloaded with malware.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.miRqXNzkW0biml1I]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[84,84],"drawn": false}, {"_id":"F2RKhsEiySWv0ffY","type":0,"documentCollection":"null","documentId":"null","text":"Leaky fuel valve.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.cOLcJ3Dnecbe6ZIU]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[85,85],"drawn": false}, {"_id":"awMYuugY3Kj6pK5I","type":0,"documentCollection":"null","documentId":"null","text":"Jammed exhaust vent.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.zRzb3Laiuw4ac6p0]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[86,86],"drawn": false}, {"_id":"H2jCFkQSC4QJFhGH","type":0,"documentCollection":"null","documentId":"null","text":"Stuck waste disposal chute.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.EZzGAO6DneH1qmQM]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[87,87],"drawn": false}, {"_id":"kwTupIw3zfFK8gYu","type":0,"documentCollection":"null","documentId":"null","text":"Lifts non-functioning.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.Tp6k1gPwhQmT6hCo]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[88,88],"drawn": false}, {"_id":"EN4i27AKjAyfbUF3","type":0,"documentCollection":"null","documentId":"null","text":"Damaged communications antenna.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.2Ht7fg78511Hd49u]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[89,89],"drawn": false}, {"_id":"ix7YwKfDHjgEBgHJ","type":0,"documentCollection":"null","documentId":"null","text":"Clogged Air Filtration. Crew capacity cut in half.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.DUuRY7kHKd7n5luv]{-50% Crew Capacity}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.XLEhMV9SnSfeEE7E]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[90,90],"drawn": false}, {"_id":"kD7E2VQh2AeDciOo","type":0,"documentCollection":"null","documentId":"null","text":"Malfunctioning climate control. 85º at all times.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.Z8raruNDvfNASFQi]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[91,91],"drawn": false}, {"_id":"5lUmyZ8nImFZofuu","type":0,"documentCollection":"null","documentId":"null","text":"No emergency power.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.3rulbOVhyRlTizT0]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[92,92],"drawn": false}, {"_id":"dKC7BnQOxM3Zwouv","type":0,"documentCollection":"null","documentId":"null","text":"Weak Frame. -1 Hull, -1 Upgrade.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.uPY19Y49bGCLGK3N]{-1 Hull}

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.06NSvDYTtmkeUtLq]{-1 Upgrade}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.ulWxa2UtTOQihTyz]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[93,93],"drawn": false}, {"_id":"T5Xr0vE7z8MbaHbC","type":0,"documentCollection":"null","documentId":"null","text":"Toxic chemical spill.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.EnogUslNNusSfVFy]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[94,94],"drawn": false}, {"_id":"YHHrA8ToKRIS4AK6","type":0,"documentCollection":"null","documentId":"null","text":"Poor scanners. Ship has to be one range band closer than normal.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.ElXLL32uNYiPmE4G]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[95,95],"drawn": false}, {"_id":"a8wNHPfmQDhb2yBQ","type":0,"documentCollection":"null","documentId":"null","text":"Counterfit papers. Ship is stolen. There is a bounty on it.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.b081FxEAclRKji3q]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[96,96],"drawn": false}, {"_id":"sHwBoWQk8HnDDln1","type":0,"documentCollection":"null","documentId":"null","text":"Corrupted A.I.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.zHsnShUX37Zvyi2O]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[97,97],"drawn": false}, {"_id":"XN7xFrup67y9XK9H","type":0,"documentCollection":"null","documentId":"null","text":"Warp Cores fail 10% of the time.

    @UUID[Compendium.mosh.items_maintenance_1e.Item.58KhhfMQ9p0XJZHc]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[98,98],"drawn": false}, {"_id":"6TJ246ieXGmopzm7","type":0,"documentCollection":"null","documentId":"null","text":"Rust bucket. Everything that can go wrong, does. +1 Minimum Stress to crew.

    @UUID[Compendium.mosh.macros_triggered_1e.Macro.BmEHWH7YxV9qb21p]{+1 Minimum Stress}

    @UUID[Compendium.mosh.items_maintenance_1e.Item.60QSsxrVOt83OU9p]{Maintenance Issue}","img":"systems/mosh/images/icons/ui/rolltables/maintenance_issues.png","weight":1,"range":[99,99],"drawn": false} ],"_stats":{"systemId":"mosh","systemVersion":"0.4.0","coreVersion":"11.308","createdTime":1685936572185,"modifiedTime":1693515520278,"lastModifiedBy":"6EeM38DJkcBWNAmw"}} \ No newline at end of file diff --git a/packs/rolltables_1e/000036.ldb b/packs/rolltables_1e/000036.ldb new file mode 100644 index 0000000..062c73a Binary files /dev/null and b/packs/rolltables_1e/000036.ldb differ diff --git a/packs/rolltables_1e/000040.log b/packs/rolltables_1e/000040.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/rolltables_1e/CURRENT b/packs/rolltables_1e/CURRENT new file mode 100644 index 0000000..150cae3 --- /dev/null +++ b/packs/rolltables_1e/CURRENT @@ -0,0 +1 @@ +MANIFEST-000039 diff --git a/packs/rolltables_1e/LOCK b/packs/rolltables_1e/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/rolltables_1e/LOG b/packs/rolltables_1e/LOG new file mode 100644 index 0000000..503d9b0 --- /dev/null +++ b/packs/rolltables_1e/LOG @@ -0,0 +1,3 @@ +2026/03/31-15:50:48.600045 17054f000 Recovering log #38 +2026/03/31-15:50:48.600385 17054f000 Delete type=0 #38 +2026/03/31-15:50:48.600414 17054f000 Delete type=3 #37 diff --git a/packs/rolltables_1e/LOG.old b/packs/rolltables_1e/LOG.old new file mode 100644 index 0000000..268536c --- /dev/null +++ b/packs/rolltables_1e/LOG.old @@ -0,0 +1,3 @@ +2026/03/29-21:14:27.570654 170fdb000 Recovering log #34 +2026/03/29-21:14:27.571032 170fdb000 Delete type=3 #32 +2026/03/29-21:14:27.571059 170fdb000 Delete type=0 #34 diff --git a/packs/rolltables_1e/MANIFEST-000039 b/packs/rolltables_1e/MANIFEST-000039 new file mode 100644 index 0000000..6efd806 Binary files /dev/null and b/packs/rolltables_1e/MANIFEST-000039 differ diff --git a/packs/rolltables_1e/lost/000020.log b/packs/rolltables_1e/lost/000020.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/rolltables_1e/lost/MANIFEST-000018 b/packs/rolltables_1e/lost/MANIFEST-000018 new file mode 100644 index 0000000..6bf2568 Binary files /dev/null and b/packs/rolltables_1e/lost/MANIFEST-000018 differ diff --git a/scss/components/_actor_generator.scss b/scss/components/_actor_generator.scss new file mode 100644 index 0000000..981114c --- /dev/null +++ b/scss/components/_actor_generator.scss @@ -0,0 +1,42 @@ +form.actor-generator{ + div.fulllabel{ + border-radius: 2em; + } + div.ulinputfield{ + min-height: 150px; + } + .smalltext{ + font-size: 0.7rem; + } + div#generator-header-grid-1col { + grid-column: span 1 / span 1; + grid-template-columns: repeat(1, minmax(0, 1fr)); + } + .element-group { + margin-top: 10px; + } + .credit-img{ + height: 30px; + margin-top: 0%; + } + .checkbox-round { + appearance: none; + } + .checkbox-round:checked { + background-color: gray; + } + .clicable-item{ + cursor: pointer; + } +} +.characterGeneratorSkillPopup{ + margin-bottom: 10px; + .skillpopupDescription{ + text-align: center; + font-weight: bold; + padding-bottom: 0.2em; + } + .center{ + text-align: center; + } +} \ No newline at end of file diff --git a/scss/components/_forms.scss b/scss/components/_forms.scss new file mode 100644 index 0000000..c7cc848 --- /dev/null +++ b/scss/components/_forms.scss @@ -0,0 +1,55 @@ +.item-form { + font-family: $font-primary; +} + +.sheet-header { + flex: 0 0 210px; + overflow: hidden; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + margin-bottom: 10px; + + .profile-img { + flex: 0 0 100px; + height: 100px; + margin-right: 10px; + } + + .header-fields { + flex: 1; + } + + h1.charname { + height: 50px; + padding: 0px; + margin: 5px 0; + border-bottom: 0; + input { + width: 100%; + height: 100%; + margin: 0; + } + } +} + +.sheet-tabs { + flex: 0; +} + +.sheet-body, +.sheet-body .tab, +.sheet-body .tab .editor { + height: 100%; +} + +.tox { + .tox-editor-container { + background: $c-white; + } + + .tox-edit-area { + padding: 0 8px; + } +} \ No newline at end of file diff --git a/scss/components/_items.scss b/scss/components/_items.scss new file mode 100644 index 0000000..8202bcd --- /dev/null +++ b/scss/components/_items.scss @@ -0,0 +1,35 @@ +.items-list { + list-style: none; + margin: 7px 0; + padding: 0; + overflow-y: auto; + + .item-header { + font-weight: bold; + } + + .item { + height: 30px; + line-height: 24px; + padding: 3px 0; + border-bottom: 1px solid #BBB; + + .item-image { + flex: 0 0 24px; + margin-right: 5px; + } + + img { + display: block; + } + } + + .item-name { + margin: 0; + } + + .item-controls { + flex: 0 0 86px; + text-align: right; + } +} \ No newline at end of file diff --git a/scss/components/_resource.scss b/scss/components/_resource.scss new file mode 100644 index 0000000..b56f037 --- /dev/null +++ b/scss/components/_resource.scss @@ -0,0 +1,4 @@ +.resource-label { + font-weight: bold; + text-transform: uppercase; +} \ No newline at end of file diff --git a/scss/components/_tabs.scss b/scss/components/_tabs.scss new file mode 100644 index 0000000..58c8a19 --- /dev/null +++ b/scss/components/_tabs.scss @@ -0,0 +1,34 @@ +// .tabs { +// .item { +// background: rgba(0, 0, 0, 0.125); +// border: 1px solid; +// border-radius: 4px; +// margin: 0 10px 0; +// padding: 8px 4px; + +// &:hover, +// &:focus { +// background: rgba(0, 0, 0, 0.125); +// } + +// &.active { +// background: transparent; +// } +// } +// } + +.tabs { + height: 40px; + border-top: 1px solid #AAA; + border-bottom: 1px solid #AAA; + + .item { + line-height: 40px; + font-weight: bold; + } + + .item.active { + text-decoration: underline; + text-shadow: none; + } +} \ No newline at end of file diff --git a/scss/global/_flex.scss b/scss/global/_flex.scss new file mode 100644 index 0000000..013c98a --- /dev/null +++ b/scss/global/_flex.scss @@ -0,0 +1,9 @@ +.flex-center { + align-items: center; + justify-content: center; + text-align: center; +} + +.flex-between { + justify-content: space-between; +} \ No newline at end of file diff --git a/scss/global/_grid.scss b/scss/global/_grid.scss new file mode 100644 index 0000000..aba92d4 --- /dev/null +++ b/scss/global/_grid.scss @@ -0,0 +1,79 @@ +.grid, +.grid-2col { + display: grid; + grid-column: span 2 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; + margin: 10px 0; + padding: 0; +} + +.grid-3col { + grid-column: span 3 / span 3; + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.grid-4col { + grid-column: span 4 / span 4; + grid-template-columns: repeat(4, minmax(0, 1fr)); +} + +.grid-5col { + grid-column: span 5 / span 5; + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.grid-6col { + grid-column: span 5 / span 5; + grid-template-columns: repeat(5, minmax(0, 1fr)); +} + +.grid-7col { + grid-column: span 7 / span 7; + grid-template-columns: repeat(7, minmax(0, 1fr)); +} + +.grid-8col { + grid-column: span 8 / span 8; + grid-template-columns: repeat(8, minmax(0, 1fr)); +} + +.grid-9col { + grid-column: span 9 / span 9; + grid-template-columns: repeat(9, minmax(0, 1fr)); +} + +.grid-10col { + grid-column: span 10 / span 10; + grid-template-columns: repeat(10, minmax(0, 1fr)); +} + +.grid-11col { + grid-column: span 11 / span 11; + grid-template-columns: repeat(11, minmax(0, 1fr)); +} + +.grid-12col { + grid-column: span 12 / span 12; + grid-template-columns: repeat(12, minmax(0, 1fr)); +} + +.flex-group-center, +.flex-group-left, +.flex-group-right { + justify-content: center; + align-items: center; + text-align: center; + padding: 5px; + border: 1px solid #999; +} + +.flex-group-left { + justify-content: flex-start; + text-align: left; +} + +.flex-group-right { + justify-content: flex-end; + text-align: right; +} diff --git a/scss/global/_window.scss b/scss/global/_window.scss new file mode 100644 index 0000000..97581e5 --- /dev/null +++ b/scss/global/_window.scss @@ -0,0 +1,12 @@ +.window-app { + font-family: $font-primary; +} + +.rollable { + &:hover, + &:focus { + color: #000; + text-shadow: 0 0 10px red; + cursor: pointer; + } +} \ No newline at end of file diff --git a/scss/mothership.scss b/scss/mothership.scss new file mode 100644 index 0000000..e43bc19 --- /dev/null +++ b/scss/mothership.scss @@ -0,0 +1,19 @@ +// Import utilities. +@import 'utils/typography'; +@import 'utils/colors'; +@import 'utils/mixins'; +@import 'utils/variables'; + +/* Global styles */ +@import 'global/window'; +@import 'global/grid'; +@import 'global/flex'; + +/* Styles limited to mosh sheets */ +.mosh { + @import 'components/forms'; + @import 'components/resource'; + @import 'components/tabs'; + @import 'components/items'; + @import 'components/actor_generator'; +} diff --git a/scss/utils/_colors.scss b/scss/utils/_colors.scss new file mode 100644 index 0000000..a119f26 --- /dev/null +++ b/scss/utils/_colors.scss @@ -0,0 +1,2 @@ +$c-white: #fff; +$c-black: #000; \ No newline at end of file diff --git a/scss/utils/_mixins.scss b/scss/utils/_mixins.scss new file mode 100644 index 0000000..69dd2ad --- /dev/null +++ b/scss/utils/_mixins.scss @@ -0,0 +1,16 @@ +@mixin element-invisible { + position: absolute; + + width: 1px; + height: 1px; + margin: -1px; + border: 0; + padding: 0; + + clip: rect(0 0 0 0); + overflow: hidden; +} + +@mixin hide { + display: none; +} \ No newline at end of file diff --git a/scss/utils/_typography.scss b/scss/utils/_typography.scss new file mode 100644 index 0000000..4476005 --- /dev/null +++ b/scss/utils/_typography.scss @@ -0,0 +1,4 @@ +@import url('https://fonts.googleapis.com/css2?family=Martel:wght@400;800&family=Roboto:wght@300;400;500&display=swap'); + +$font-primary: 'Roboto', sans-serif; +$font-secondary: 'Roboto', sans-serif; \ No newline at end of file diff --git a/scss/utils/_variables.scss b/scss/utils/_variables.scss new file mode 100644 index 0000000..64be658 --- /dev/null +++ b/scss/utils/_variables.scss @@ -0,0 +1,3 @@ +$padding-sm: 5px; +$padding-md: 10px; +$padding-lg: 20px; \ No newline at end of file diff --git a/system.json b/system.json new file mode 100644 index 0000000..975c939 --- /dev/null +++ b/system.json @@ -0,0 +1,166 @@ +{ + "id": "sla-mothership", + "title": "SLA Mothership", + "description": "An SLA Industries conversion built on the unofficial Mothership system for Foundry VTT, preserving Mothership's core mechanics while adding SLA flux, Ebb, BPN, and equipment support.", + "version": "0.5.1", + "esmodules": [ + "module/mosh.js" + ], + "styles": [ + "css/mosh.css" + ], + "packs": [ + { + "name": "conditions_0e", + "label": "Conditions 0E", + "path": "packs/conditions_0e", + "type": "Item", + "system": "sla-mothership" + }, + { + "name": "conditions_1e", + "label": "Conditions 1E", + "path": "packs/conditions_1e", + "type": "Item", + "system": "sla-mothership" + }, + { + "name": "items_maintenance_1e", + "label": "Maintenance Items 1E", + "path": "packs/items_maintenance_1e", + "type": "Item", + "system": "sla-mothership" + }, + { + "name": "macros_hotbar_0e", + "label": "Hotbar Macros 0E", + "path": "packs/macros_hotbar_0e", + "type": "Macro", + "system": "sla-mothership" + }, + { + "name": "macros_hotbar_1e", + "label": "Hotbar Macros 1E", + "path": "packs/macros_hotbar_1e", + "type": "Macro", + "system": "sla-mothership" + }, + { + "name": "macros_triggered_0e", + "label": "Triggered Macros 0E", + "path": "packs/macros_triggered_0e", + "type": "Macro", + "system": "sla-mothership" + }, + { + "name": "macros_triggered_1e", + "label": "Triggered Macros 1E", + "path": "packs/macros_triggered_1e", + "type": "Macro", + "system": "sla-mothership" + }, + { + "name": "rolltables_0e", + "label": "Roll Tables 0E", + "path": "packs/rolltables_0e", + "type": "RollTable", + "system": "sla-mothership" + }, + { + "name": "rolltables_1e", + "label": "Roll Tables 1E", + "path": "packs/rolltables_1e", + "type": "RollTable", + "system": "sla-mothership" + } + ], + "media": [ + { + "type": "cover", + "loop": false, + "flags": {} + }, + { + "type": "setup", + "url": "systems/sla-mothership/images/icons/ui/system/mosh-repo.webp", + "thumbnail": "systems/sla-mothership/images/icons/ui/system/mosh-thumbnail.webp" + } + ], + "background": "systems/sla-mothership/images/icons/ui/system/mosh-background.webp", + "languages": [ + { + "lang": "en", + "name": "English", + "path": "lang/en.json", + "flags": {} + }, + { + "lang": "pt-BR", + "path": "lang/pt-BR.json", + "flags": {} + } + ], + "grid.distance": 1, + "grid.units": "meter", + "primaryTokenAttribute": "health", + "secondaryTokenAttribute": "other.stress", + "license": "LICENSE.txt", + "url": "https://github.com/slaguru666/sla_industries_MS", + "manifest": "https://raw.githubusercontent.com/slaguru666/sla_industries_MS/main/system.json", + "download": "https://github.com/slaguru666/sla_industries_MS/releases/latest/download/sla_industries_MS.zip", + "authors": [ + { + "name": "Futilrevenge", + "flags": {} + }, + { + "name": "hollowphoton", + "flags": {} + }, + { + "name": "Tim Evans", + "flags": {} + } + ], + "relationships": { + "requires": [ + { + "id": "sla-mothership-compendium", + "type": "module", + "compatibility": {} + } + ], + "recommends": [ + { + "id": "dice-so-nice", + "type": "module", + "compatibility": {} + }, + { + "id": "mothership-crew-achievements", + "type": "module", + "compatibility": {} + }, + { + "id": "mothership-crew-relationships", + "type": "module", + "compatibility": {} + }, + { + "id": "mothership-map-viewer", + "type": "module", + "compatibility": {} + }, + { + "id": "quick-battlemap-builder", + "type": "module", + "compatibility": {} + } + ] + }, + "compatibility": { + "minimum": "13", + "maximum": "13", + "verified": "13" + } +} \ No newline at end of file diff --git a/template.json b/template.json new file mode 100644 index 0000000..2e2611e --- /dev/null +++ b/template.json @@ -0,0 +1,705 @@ +{ + "Actor": { + "types": [ + "character", + "creature", + "ship" + ], + "templates": { + "base": { + "health": { + "value": 10, + "min": 0, + "max": 10, + "label" : "Health" + }, + "hits": { + "value": 0, + "min": 0, + "max" : 2, + "label" : "Wounds" + }, + "netHP": { + "value": 20, + "min": 0, + "max" : 20, + "label" : "Net HP" + }, + "bleeding": { + "value": 0, + "min": 0, + "label" : "Bleeding" + } + } + }, + "character": { + "templates": [ + "base" + ], + "biography": "", + "notes": "", + "weight" : { + "current" : 0, + "capacity" : 0 + }, + "class": { + "value": "" + }, + "rank": { + "value": "" + }, + "pronouns": { + "value": "" + }, + "credits": { + "value": "" + }, + "stressdesc": { + "value": "" + }, + "xp": { + "value": 0, + "html" : 0, + "selectedSkill" : "" + }, + "attributes": { + "level": { + "value": 0 + } + }, + "stats": { + "strength": { + "value": 10, + "mod": 0, + "min": 0, + "max": 99, + "label": "Strength", + "rollLabel": "Strength Check" + }, + "speed": { + "value": 10, + "mod": 0, + "min": 0, + "max": 99, + "label": "Speed", + "rollLabel": "Speed Check" + }, + "intellect": { + "value": 10, + "mod": 0, + "min": 0, + "max": 99, + "label": "Intellect", + "rollLabel": "Intellect Check" + }, + "combat": { + "value": 10, + "mod": 0, + "min": 0, + "max": 99, + "label": "Combat", + "rollLabel": "Combat Check" + }, + "sanity": { + "value": 10, + "mod": 0, + "min": 0, + "max": 99, + "label": "Sanity", + "rollLabel": "Sanity Save" + }, + "fear": { + "value": 10, + "mod": 0, + "min": 0, + "max": 99, + "label": "Fear", + "rollLabel": "Fear Save" + }, + "body": { + "value": 10, + "mod": 0, + "min": 0, + "max": 99, + "label": "Body", + "rollLabel": "Body Save" + }, + "armor": { + "value": 0, + "mod": 0, + "min": 0, + "max": 99, + "damageReduction": 0, + "cover": "none", + "label": "Armor", + "rollLabel": "Armor Save" + } + }, + "other": { + "stress": { + "value": 2, + "min": 2, + "max": 20, + "label" : "Stress" + }, + "resolve": { + "value": 0, + "min": 0, + "max": 15, + "label" : "Resolve" + }, + "stressdesc": { + "value": "" + } + }, + "sla": { + "operativeType": { + "value": "" + }, + "species": { + "value": "" + }, + "speciesNotes": { + "value": "" + }, + "trainingPackage": { + "value": "" + }, + "packageSummary": { + "value": "" + }, + "packageSkills": { + "value": "" + }, + "packageWealth": { + "value": "" + }, + "flux": { + "value": 0, + "min": 0, + "max": 0, + "label": "Flux" + }, + "fluxStage": { + "value": "" + }, + "bpn": { + "value": "" + }, + "scl": { + "value": "" + }, + "employer": { + "value": "" + }, + "sector": { + "value": "" + }, + "height": { + "value": "" + }, + "weightText": { + "value": "" + }, + "lad": false, + "ebbRating": { + "value": 0 + }, + "ammoSpendTotal": { + "value": 0 + }, + "ammoLedger": { + "value": "" + }, + "fluxNotes": { + "value": "" + }, + "ebbNotes": { + "value": "" + } + } + }, + "creature": { + "templates": [ + "base" + ], + "biography": "", + "notes": "", + "description": "This is a description", + "xp": { + "value": 1, + "html": "" + }, + "stats": { + "combat": { + "value": 10, + "min": 0, + "max": 99, + "label": "Combat", + "rollLabel": "Combat Check", + "enabled" : true + }, + "instinct": { + "value": 10, + "min": 0, + "max": 99, + "label": "Instinct", + "rollLabel": "Instinct Check", + "enabled" : true + }, + "speed": { + "value": 10, + "min": 0, + "max": 99, + "label": "Speed", + "rollLabel": "Speed Check", + "enabled" : false + }, + "loyalty": { + "value": 10, + "min": 0, + "max": 99, + "label": "Loyalty", + "rollLabel": "Loyalty Check", + "enabled" : false + }, + "armor": { + "value": 0, + "mod": 0, + "min": 0, + "max": 99, + "damageReduction": 0, + "cover": "none", + "label": "Armor", + "rollLabel": "Armor Save", + "enabled" : false + }, + "sanity": { + "value": 10, + "min": 0, + "max": 99, + "label": "Sanity", + "rollLabel": "Sanity Save", + "enabled" : false + } + } + }, + "ship": { + "templates": [ + "base" + ], + "biography": "", + "description": "This is a description", + "type": "", + "class": "", + "xp": { + "value": 1 + }, + "images" : { + "layout" : "systems/sla-mothership/images/Galloway_Top.png", + "beauty" : "systems/sla-mothership/images/Galloway_Top.png" + }, + "runSetup" : true, + "megadamage" : { + "html" : "", + "hits" : [], + "menu" : { + "html" : "" + }, + "open" : false + }, + "stats": { + "armor": { + "value": 10, + "min": 0, + "max": 99, + "label": "Armor", + "rollLabel": "Armor Save" + }, + "combat": { + "value": 10, + "min": 0, + "max": 99, + "label": "Combat", + "rollLabel": "Combat Check" + }, + "intellect": { + "value": 10, + "min": 0, + "max": 99, + "label": "Intellect", + "rollLabel": "Intellect Check" + }, + "speed": { + "value": 10, + "min": 0, + "max": 99, + "label": "Speed", + "rollLabel": "Speed Check" + }, + "thrusters": { + "value": 10, + "min": 0, + "max": 99, + "label": "Thrusters", + "rollLabel": "Thrusters Save" + }, + "battle": { + "value": 10, + "min": 0, + "max": 99, + "label": "Battle", + "rollLabel": "Battle Save" + }, + "systems": { + "value": 10, + "min": 0, + "max": 99, + "label": "Systems", + "rollLabel": "Systems Save" + }, + "bankruptcy": { + "value": 10, + "min": 0, + "max": 99, + "label": "Bankruptcy", + "rollLabel": "Bankruptcy Save" + } + }, + "supplies": { + "hull": { + "value": 10, + "max": 10, + "75" : 0, + "50" : 0, + "25" : 0 + }, + "fuel": { + "value": 10, + "max": 10 + }, + "stock": { + "value": 10, + "max": 10 + }, + "crew": { + "value": 10, + "max": 10 + }, + "oxygen": { + "value": 0 + }, + "warp-cores": { + "value": 0 + }, + "cryopods": { + "value": 0 + }, + "escape-pods": { + "value": 0 + }, + "upgrades": { + "value": 0, + "max" : 0 + } + }, + "weapon-stats" : { + "weapons": { + "value": 0, + "max": 1 + }, + "megadamage": { + "value": 0, + "max": 1 + }, + "hardpoints": { + "value": 0, + "max": 1 + } + + } + } + }, + "Item": { + "types": [ + "item", + "drug", + "skill", + "weapon", + "armor", + "ability", + "module", + "condition", + "crew", + "repair", + "class", + "persTrait" + ], + "templates": { + "base": { + "description": "" + } + }, + "item": { + "templates": [ + "base" + ], + "quantity": 1, + "weight": 0, + "carryState": "carried", + "cost" : 0, + "sla": { + "category": "", + "power": "", + "manufacturer": "", + "rarity": "", + "source": "SLA" + } + }, + "drug": { + "templates": [ + "base" + ], + "quantity": 1, + "weight": 0, + "carryState": "carried", + "cost": 0, + "sla": { + "category": "Drug", + "drugId": "", + "rating": 0, + "durationLabel": "", + "addictionFactor": 0, + "source": "SLA" + } + }, + "skill": { + "templates": [ + "base" + ], + "rank": "Trained", + "bonus": 10, + "prerequisite_ids": [], + "sla": { + "category": "", + "skillFamily": "", + "source": "SLA" + } + }, + "weapon": { + "templates": [ + "base" + ], + "antiArmor": false, + "damage": "1d10", + "ammo": 10, + "shots": 1, + "curShots": 0, + "shotsPerFire" : 1, + "useAmmo": false, + "ammoType": "", + "ammoCalibre": "", + "ammoBaseCost": 0, + "ammoTag": "STD", + "ammoLoadedType": "STD", + "ammoAllowStd": true, + "ammoAllowAp": true, + "ammoAllowHe": true, + "ammoAllowHeap": true, + "ammoReserve": 0, + "ammoReserveStd": 0, + "ammoReserveAp": 0, + "ammoReserveHe": 0, + "ammoReserveHeap": 0, + "wound":"", + "critDmg": "", + "woundEffect": "", + "bonus": 0, + "weight": 0, + "carryState": "equipped", + "equipped": true, + "cost" : 0, + "ranges": { + "short": 0, + "medium": 0, + "long": 0, + "value" : "" + }, + "settings" : { + "firstEdition" : false + }, + "sla": { + "weaponType": "", + "skillRef": "", + "skillRefAlt": "", + "damageType": "", + "fireModes": "Single:1", + "currentFireMode": "Single", + "hands": "", + "reach": "", + "special": "", + "enc": 0, + "price": "", + "notes": [] + } + }, + "armor": { + "templates": [ + "base" + ], + "armorPoints": 1, + "damageReduction":0, + "speed": "", + "oxygenMax": 0, + "oxygenCurrent": 0, + "weight": 0, + "carryState": "equipped", + "equipped": true, + "cost" : 0, + "sla": { + "burden": "", + "coverage": "", + "physmod": 0, + "stealthmod": 0, + "enc": 0, + "price": "", + "locationAV": {}, + "notes": [] + } + }, + "condition": { + "templates": [ + "base" + ], + "severity": 1, + "treatment" : { + "value" : 0, + "html" : "" + }, + "sla": { + "category": "", + "effectSummary": "", + "severityScale": "", + "treatmentGuidance": "", + "scaleWithSeverity": true, + "statMods": { + "strength": 0, + "speed": 0, + "intellect": 0, + "combat": 0, + "sanity": 0, + "fear": 0, + "body": 0 + }, + "skillMods": [], + "source": "" + } + }, + "ability": { + "templates": [ + "base" + ], + "text": "An Ability", + "roll": "", + "sla": { + "abilityType": "ebb", + "discipline": "", + "skillRef": "", + "coreSkillRef": "Ebb (Core)", + "fluxCost": 1, + "tier": "basic", + "range": "", + "duration": "", + "attack": false, + "panicSave": "fear", + "rollOnUse": true, + "notes": [], + "tiers": [] + } + }, + "crew": { + "templates": [ + "base" + ], + "text": "", + "job" : "" + }, + "repair": { + "templates": [ + "base" + ], + "quantity": 1, + "major": false + }, + "module": { + "templates": [ + "base" + ], + "quantity": 1, + "hull": 1, + "totalHull" : 1, + "feature" : "", + "offline" : false + }, + "class": { + "templates": [ + "base" + ], + "source": "", + "author": "", + "link": "", + "trauma_response": "", + "robotic": true, + "common_skills": [], + "sla": { + "classType": "species", + "wealth": "", + "starterPackage": "", + "notes": [] + }, + "base_adjustment": { + "strength": 0, + "speed": 0, + "intellect": 0, + "combat": 0, + "sanity": 0, + "fear": 0, + "body": 0, + "max_wounds": 0, + "skills_granted": [] + }, + "selected_adjustment": { + "choose_stat": [], + "choose_skill_and": { + "trained": 0, + "expert": 0, + "expert_full_set": 0, + "master": 0, + "master_full_set": 0 + }, + "choose_skill_or": [] + }, + "roll_tables": { + "loadout": "", + "trinket": "", + "patch": "" + } + }, + "persTrait": { + "templates": [ + "base" + ], + "base": 1, + "xp": 0, + "oppName": "", + "basic": false, + "improve": false, + "oppimprove": false, + "gmDescription": "", + "sla": { + "traitType": "neutral", + "source": "SLA" + } + } + } +} diff --git a/templates/actor/actor-sheet.html b/templates/actor/actor-sheet.html new file mode 100644 index 0000000..ba9c8d4 --- /dev/null +++ b/templates/actor/actor-sheet.html @@ -0,0 +1,1181 @@ +
    + + {{!-- Sheet Header --}} +
    + +
    + {{!-- The grid classes are defined in scss/global/_grid.scss. To use, + use both the "grid" and "grid-Ncol" class where "N" can be any number + from 1 to 12 and will create that number of columns. --}} + {{!-- The grid classes are defined in scss/global/_grid.scss. To use, + use both the "grid" and "grid-Ncol" class where "N" can be any number + from 1 to 12 and will create that number of columns. --}} + +
    + + +
    +
    SLA Industries
    + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    +
    +
    L.A.D.
    + +
    +
    +
    {{ localize 'Mosh.Credits' }}
    +
    +
    + + +
    +
    {{ localize 'Mosh.CLASS' }}
    +
    +
    + + +
    +
    Race
    +
    +
    + +
    +
    SLA Rank
    +
    +
    + +
    +
    Height
    +
    +
    +
    +
    Weight
    +
    +
    + +
    +
    + +
    + +
    +
    + + +
    + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + + {{#if system.settings.useCalm}} + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + {{else}} + +
    + +
    + +
    + +
    +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Minimum' }}
    +
    + {{/if}} + + {{#if isEbbUser}} +
    + +
    + +
    + +
    +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + {{else}} + {{#if system.settings.firstEdition}} + {{else}} + +
    + +
    + +
    +
    + {{/if}} + {{/if}} + + {{#if system.settings.firstEdition}} + +
    + +
    +
    +
    {{system.stats.armor.mod}}
    + {{#if (compare 'str' system.stats.armor.cover '===' 'insignificant')}} +
     5
    + {{/if}} + {{#if (compare 'str' system.stats.armor.cover '===' 'light')}} +
     10
    + {{/if}} + {{#if (compare 'str' system.stats.armor.cover '===' 'heavy')}} +
     20
    + {{/if}} +
    +
    +
    +
    {{system.stats.armor.damageReduction}}
    + {{#if (compare 'str' system.stats.armor.cover '===' 'heavy')}} +
     5
    + {{/if}} +
    +
    +
    {{ localize 'Mosh.ArmorPoints' }}
    +
    {{ localize 'Mosh.DMGReduction' }}
    +
    + {{/if}} + +
    +
    {{ localize 'Mosh.TraumaResponse' }}
    + +
    + + + + +
    + +
    + + + + + + + + + {{#if system.settings.firstEdition}} +
    + {{else}} +
    + {{/if}} + + +
    +
    +
    + {{ localize 'Mosh.Strength' }} +
    + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Speed' }} +
    + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Intellect' }} +
    + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Combat' }} +
    + +
    + +
    +
    +
    +
    +
    + +
    +
    + + {{#if system.settings.firstEdition}} +
    + {{else}} +
    + {{/if}} + +
    + {{ localize 'Mosh.Sanity' }} +
    + +
    +
    + +
    +
    + +
    + {{ localize 'Mosh.Fear' }} +
    + +
    +
    + +
    +
    + +
    + {{ localize 'Mosh.Body' }} +
    + +
    +
    + +
    +
    + +
    + +
    + + {{#unless system.settings.firstEdition}} + +
    + {{ localize 'Mosh.Armor' }} +
    + +
    +
    +
    {{system.stats.armor.mod}}
    +
    +
    + {{/unless}} + +
    + +
    +
    + +
    +
    +
    Carry Load
    +
    {{slaCarry.current}} / {{slaCarry.capacity}} kg
    +
    State: {{slaCarry.state}} | Equipped {{slaCarry.equipped}} kg | Carried {{slaCarry.carried}} kg | Stowed {{slaCarry.stowed}} kg | Free {{slaCarry.available}} kg
    +
    +
    + + + + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Biography Tab --}} +
    + {{editor enriched.biography target="system.biography" button=true editable=true}} +
    + {{!-- Notes Tab --}} +
    +
    +
    Ammo Spend Ledger
    +
    Total spent: {{system.sla.ammoSpendTotal.value}} cR
    + +
    + {{editor enriched.notes target="system.notes" button=true editable=true}} +
    +
    +
    +
    +
    +
    SLA Operative Profile
    +
    {{system.sla.species.value}} {{#if system.sla.trainingPackage.value}}/ {{system.sla.trainingPackage.value}}{{/if}}
    +
    +
    + {{system.sla.bpn.value}} + SCL {{system.sla.scl.value}} + {{#if isEbbUser}}Ebb {{system.sla.ebbRating.value}}{{/if}} +
    +
    + +
    +
    +
    Package Focus
    +
    {{system.sla.trainingPackage.value}}
    +
    {{system.sla.packageSummary.value}}
    +
    + Employer {{system.sla.employer.value}} + Sector {{system.sla.sector.value}} + {{#if system.sla.packageWealth.value}}Wealth {{system.sla.packageWealth.value}}{{/if}} +
    +
    +
    +
    Species Dossier
    +
    {{system.sla.species.value}}
    +
    {{system.sla.speciesNotes.value}}
    +
    + Operative {{system.sla.operativeType.value}} + {{#if isEbbUser}}Flux Channel {{system.sla.ebbRating.value}}{{/if}} +
    +
    +
    + +
    +
    +
    Rules Snapshot
    +
    {{slaEnabledSpeciesRuleCount}} active rules
    +
    + {{#each slaEnabledSpeciesRules as |rule|}} +
    {{rule.label}}
    + {{/each}} +
    + {{#unless slaEnabledSpeciesRuleCount}} +
    No optional species rules are enabled right now.
    + {{/unless}} +
    +
    +
    Sheet Mode
    +
    {{#if (compare 'str' slaSheetTheme '===' 'legacy')}}Legacy{{else}}Modern SLA{{/if}}
    +
    Use the palette button in the header to swap the entire presentation style without changing the operative data.
    +
    +
    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    + {{#if isEbbUser}} +
    + + +
    + {{/if}} +
    + +
    +
    +
    Species Notes
    +
    + {{#each slaSpeciesTraitList as |note|}} +
    {{note}}
    + {{/each}} +
    + +
    +
    +
    Package Skills
    +
    + {{#each slaPackageSkillList as |skill|}} +
    {{skill}}
    + {{/each}} +
    + +
    +
    + +
    +
    +
    Species Rules
    +
    Turn these on or off to match the version of the species rules your table is using.
    + {{#if slaSpeciesRules.length}} +
    + {{#each slaSpeciesRules as |rule|}} + + {{/each}} +
    + {{else}} +
    No species-specific toggles are defined for this operative yet.
    + {{/if}} +
    +
    + +
    +
    +
    +
    +
    +
    +
    Trait Engine
    +
    Balanced Personal Traits
    +
    +
    + {{traitCount}} traits + {{traitValidation.rankBalance.advantageRanks}} / {{traitValidation.rankBalance.disadvantageRanks}} + {{#if traitValidation.rankBalance.balanced}}Balanced{{else}}Needs Balance{{/if}} +
    +
    + +
    + Trait + +
    + +
    +
    +
    Positive Traits
    +
    Choose one advantage and add it to the operative.
    +
    + + +
    +
    +
    +
    Negative Traits
    +
    Choose one disadvantage and add it to the operative.
    +
    + + +
    +
    +
    + +
    +
    Trait Count: {{traitCount}}
    +
    Advantage Ranks: {{traitValidation.rankBalance.advantageRanks}}
    +
    Disadvantage Ranks: {{traitValidation.rankBalance.disadvantageRanks}}
    +
    Balance Net: {{traitValidation.rankBalance.net}}
    +
    Coverage: {{traitValidation.coverage.mapped}} mapped / {{traitValidation.coverage.unmapped}} unmapped
    +
    Status: {{#if traitValidation.rankBalance.balanced}}Balanced{{else}}Needs Balance{{/if}}
    + {{#if traitValidation.errors.length}} +
    Errors: {{#each traitValidation.errors as |err|}}{{err}}{{/each}}
    + {{/if}} + {{#if traitValidation.warnings.length}} +
    Warnings: {{#each traitValidation.warnings as |warn|}}{{warn}}{{/each}}
    + {{/if}} +
    + + {{#if persTraitsEnhanced.length}} +
      +
    1. +
      Icon
      +
      Trait
      +
      Rank
      +
      Type
      +
      State
      +
      Effect
      +
      Delete
      +
    2. + {{#each persTraitsEnhanced as |trait|}} +
    3. +
      +
      {{trait.name}}
      +
      {{trait.slaTrait.rank}} / {{trait.slaTrait.maxRank}}
      +
      {{trait.slaTrait.type}}
      +
      {{trait.slaTrait.status}}
      +
      {{trait.slaTrait.effectSummary}}
      +
      +
    4. + {{/each}} +
    + {{else}} +
    No personal traits are on this operative yet. Add balanced good and bad traits here and the audit will keep track of the rank balance.
    + {{/if}} + +
    +
    +
    Species Snapshot
    +
    + {{#each slaSpeciesTraitList as |note|}} +
    {{note}}
    + {{/each}} +
    + {{#unless slaSpeciesTraitList.length}} +
    No species notes are currently listed for this operative.
    + {{/unless}} +
    +
    +
    Package Snapshot
    +
    + {{#each slaPackageSkillList as |skill|}} +
    {{skill}}
    + {{/each}} +
    + {{#unless slaPackageSkillList.length}} +
    No package skills are currently listed for this operative.
    + {{/unless}} +
    +
    +
    +
    +
    +
    +
    +
    +
    Species Doctrine
    +
    {{system.sla.species.value}} Special Rules
    +
    +
    + {{system.sla.species.value}} + {{#if system.sla.trainingPackage.value}}{{system.sla.trainingPackage.value}}{{/if}} +
    +
    + +
    +
    +
    Rule Toggles
    +
    Turn these on or off to match the version of the species rules your table is using.
    + {{#if slaSpeciesRules.length}} +
    + {{#each slaSpeciesRules as |rule|}} + + {{/each}} +
    + {{else}} +
    No species-specific toggles are defined for this operative yet.
    + {{/if}} +
    +
    +
    Combat Rule Status
    + {{#if slaPrometheusStatus.enabled}} +
    Prometheus Regeneration is enabled.
    + {{#if slaPrometheusStatus.inCombat}} +
    Current combat round: {{slaPrometheusStatus.currentRound}}
    + {{#if slaPrometheusStatus.pulseThisRound}} +
    Regeneration triggers this round.
    + {{else}} +
    Rounds until next regeneration pulse: {{slaPrometheusStatus.roundsUntilPulse}}
    + {{/if}} +
    Every fourth combat round, recover 1d5 Health automatically.
    + {{else}} +
    Not currently in combat. Prometheus regeneration will trigger on rounds 4, 8, 12, and so on once combat starts.
    + {{/if}} + {{else}} +
    No active round-based special rule is currently enabled for this operative.
    + {{/if}} +
    +
    +
    +
    + {{#if isEbbUser}} +
    +
    +
    +
    +
    Ebb Discipline
    +
    {{system.sla.species.value}} Flux Channel
    +
    +
    + Flux {{system.sla.flux.value}} / {{system.sla.flux.max}} + {{slaFlux.label}} + Fear Save {{system.stats.fear.value}} +
    +
    + +
    +
    +
    Flux State
    +
    {{slaFlux.label}}
    +
    {{slaFlux.description}}
    +
    Risk bands: {{slaFlux.thresholds}}
    +
    +
    +
    +
    Reserve remaining: {{system.sla.flux.value}} / {{system.sla.flux.max}}
    +
    + + +
    +
    +
    +
    Ebb Skill Deck
    +
    Click a discipline below to roll that Ebb skill directly. Use the ability roster underneath to channel a specific power and spend Flux.
    +
    + {{#each ebbSkills as |skill|}} + + {{/each}} +
    +
    Core and discipline skills are grouped here so powers like Awareness are easier to find. Ebb skills live here, while the actual powers are listed in the ability roster below.
    +
    +
    + +
    +
    +
    Panic Protocol
    +
    + {{#each slaFluxGuidance as |entry|}} +
    {{entry}}
    + {{/each}} +
    +
    +
    +
    Discipline Notes
    +
    Use this space for doctrine, trainer notes, squad warnings, or sector-specific Ebb restrictions.
    +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    + +
      +
    1. +
      +
      Ebb Ability
      +
      Skill
      +
      Flux
      +
      Tier
      +
      Save
      +
      + Add +
      +
    2. + {{#each abilities as |ability id|}} +
    3. +
      +
      {{ability.name}}
      +
      {{ability.system.sla.skillRef}}
      +
      {{ability.system.sla.fluxCost}}
      +
      {{ability.system.sla.tier}}
      +
      {{ability.system.sla.panicSave}}
      +
      + Use + + +
      +
    4. + {{/each}} +
    +
    + {{/if}} + {{!-- Owned Items Tab --}} +
    + {{#if drugAlerts.length}} +
    + {{#each drugAlerts as |alert id|}} +
    +
    +
    {{alert.name}}
    +
    + {{alert.stateLabel}} + {{#if alert.duration}}{{alert.duration}}{{/if}} +
    +
    +
    {{alert.summary}}
    + +
    + {{/each}} +
    + {{/if}} + + {{#if system.settings.firstEdition}} + +
      +
    1. +
      +
      {{ localize 'Mosh.ArmorName' }}
      +
      {{ localize 'Mosh.AP' }}
      +
      {{ localize 'Mosh.DR' }}
      +
      {{ localize 'Mosh.Speed' }}
      +
      {{ localize 'Mosh.Oxygen' }}
      +
      Carry
      + +
    2. + {{#each armors as |armor id|}} +
    3. +
      +

      {{armor.name}}

      +
      {{armor.system.armorPoints}}
      +
      {{armor.system.damageReduction}}
      +
      {{armor.system.speed}}
      + {{#if armor.system.oxygenMax}} +
      {{armor.system.oxygenCurrent}}/{{armor.system.oxygenMax}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      +
      + + +
      + {{armor.slaCarry.totalWeight}} kg +
      +
      + + +
      +
    4. + {{/each}} +
    + {{else}} + +
      +
    1. +
      +
      {{ localize 'Mosh.ArmorName' }}
      +
      {{ localize 'Mosh.SaveBonus' }}
      +
      {{ localize 'Mosh.Speed' }}
      +
      {{ localize 'Mosh.Oxygen' }}
      +
      Carry
      + +
    2. + {{#each armors as |armor id|}} +
    3. +
      +

      {{armor.name}}

      +
      {{armor.system.armorPoints}}
      +
      {{armor.system.speed}}
      + {{#if armor.system.oxygenMax}} +
      {{armor.system.oxygenCurrent}}/{{armor.system.oxygenMax}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      +
      + + +
      + {{armor.slaCarry.totalWeight}} kg +
      +
      + + +
      +
    4. + {{/each}} +
    + {{/if}} + + +
      +
    1. +
      +
      Drug
      +
      Qty
      +
      Rating
      +
      Value
      +
      Weight
      +
      Carry
      +
      State
      +
      Duration
      +
      + Add +
      +
    2. + {{#each drugRows as |drug id|}} +
    3. +
      +
      {{drug.name}}{{drug.summary}}
      +
      {{drug.quantity}}
      +
      {{drug.rating}}
      +
      {{drug.cost}}
      +
      {{drug.slaCarry.totalWeight}} kg
      +
      +
      + + +
      +
      +
      {{drug.statusLabel}}
      +
      {{drug.duration}}
      +
      + + + + +
      +
    4. + {{/each}} +
    + + +
      +
    1. +
      +
      {{ localize 'Mosh.ItemName' }}
      +
      {{ localize 'Mosh.Quantity' }}
      +
      {{ localize 'Mosh.Weight' }}
      +
      Carry
      +
      {{ localize 'Mosh.Value' }}
      +
      + Add +
      +
    2. + {{#each gear as |item id|}} +
    3. +
      +

      {{item.name}}

      +
      {{item.system.quantity}}
      +
      {{item.slaCarry.totalWeight}} kg
      +
      +
      + + +
      +
      +
      {{item.system.cost}}
      +
      + + +
      +
    4. + {{/each}} +
    +
    +
    {{ localize 'Mosh.CarryingCapacity' }}: {{system.weight.capacity}} kg
    +
    {{ localize 'Mosh.CurrentWeight' }}: {{system.weight.current}} kg
    +
    Stowed: {{system.weight.stowed}} kg
    +
    + +
    + {{!-- Owned Skills Tab --}} +
    +
    +
    Field Skill Deck
    +
    Standard operative skills are listed here by category. Ebb-only skills stay on the Ebb tab so non-Ebb characters and general play stay uncluttered.
    +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.SkillName' }}
      +
      Category
      +
      {{ localize 'Mosh.SkillRank' }}
      +
      {{ localize 'Mosh.SkillBonus' }}
      + +
    2. + {{#each skills as |skill id|}} +
    3. +
      +
      + {{skill.name}} + {{#if skill.isCombatSkill}}Combat Use{{/if}} + {{#if skill.slaBreakdown.summary}}{{skill.slaBreakdown.summary}}{{/if}} +
      +
      {{skill.system.sla.category}}
      +
      {{skill.system.rank}}
      +
      + {{skill.system.displayBonus}} + {{#if skill.slaTraitPreview.modLabel}}{{skill.slaTraitPreview.modLabel}} trait{{/if}} +
      +
      + + +
      +
    4. + {{/each}} +
    + + {{#if system.settings.firstEdition}} + + +
    +
    +
    {{ localize 'Mosh.SkillTraining' }}
    + +
    {{{system.xp.html}}}
    +
    +
    + + {{/if}} + +
    + + + + +
      +
    1. +
      +
      {{ localize 'Mosh.Condition' }}
      +
      {{ localize 'Mosh.Severity' }}
      +
      {{ localize 'Mosh.Treatment' }}
      + +
    2. + {{#each conditions as |condition id|}} +
    3. +
      +
      {{condition.name}}
      +
      {{condition.system.severity}}
      +
      + {{#if condition.system.treatment.html}} +
      + {{{condition.system.treatment.html}}} +
      + {{else}} +
      + {{condition.name}} +
      + {{/if}} +
      +
      + + +
      +
    4. + + {{/each}} +
    + + +
    + + {{!-- Owned Weapons Tab --}} +
    +
    +
    Weapons Readiness
    +
    Ammo stacks: {{slaAmmoInventory.stackCount}} | Total loose rounds: {{slaAmmoInventory.roundCount}} | Running ammo spend: {{system.sla.ammoSpendTotal.value}} cR
    +
    Carry: {{slaCarry.current}} / {{slaCarry.capacity}} kg | {{slaCarry.state}}
    +
    + +
    +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.WeaponName' }}
      +
      {{ localize 'Mosh.Damage' }}
      +
      {{ localize 'Mosh.Ammo' }}
      +
      {{ localize 'Mosh.Shots' }}
      +
      Mode
      +
      Carry
      +
      {{ localize 'Mosh.Range' }}
      + +
    2. + + {{#each weapons as |weapon id|}} +
    3. + +
      +
      + {{weapon.name}} + {{#if weapon.system.useAmmo}}{{weapon.sla.calibreLabel}}{{/if}} + {{#if weapon.system.useAmmo}}{{weapon.sla.ammoState}}{{/if}} +
      + {{#if weapon.system.antiArmor}} +
      {{weapon.system.damage}} ({{ localize 'Mosh.AntiArmorAcronym' }})
      + {{else}} +
      {{weapon.system.damage}}
      + {{/if}} + {{#if weapon.system.useAmmo}} +
      +
      {{weapon.system.ammoLoadedType}} | {{weapon.sla.loadedAmmoReserve}}
      +
      {{weapon.sla.reserveSummary}}
      +
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} + {{#if weapon.system.useAmmo}} + + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} + {{#if weapon.system.useAmmo}} + + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      +
      + + +
      + {{weapon.slaCarry.totalWeight}} kg +
      + {{#if weapon.system.ranges.value}} +
      {{weapon.system.ranges.value}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      + + +
      +
    4. + {{/each}} +
    +
    +
    +
    diff --git a/templates/actor/creature-sheet.html b/templates/actor/creature-sheet.html new file mode 100644 index 0000000..550fd56 --- /dev/null +++ b/templates/actor/creature-sheet.html @@ -0,0 +1,477 @@ +
    + {{!-- Sheet Header --}} + +
    + + +
    + {{#if system.stats.combat.enabled}} + +
    +
    + + {{#if system.swarm.enabled}} + {{ localize 'Mosh.Combat' }} {{ localize 'Mosh.SwarmWoundShort' }} + + {{else}} + {{ localize 'Mosh.Combat' }} + + {{/if}} +
    +
    + {{/if}} + {{#if system.stats.instinct.enabled}} + +
    +
    + {{ localize 'Mosh.Instinct' }} + +
    +
    + {{/if}} + {{#if system.stats.speed.enabled}} + +
    +
    + {{ localize 'Mosh.Speed' }} + +
    +
    + {{/if}} + {{#if system.stats.loyalty.enabled}} + +
    +
    + {{ localize 'Mosh.Loyalty' }} + +
    +
    + {{/if}} + {{#if system.stats.armor.enabled}} + +
    +
    + {{ localize 'Mosh.Armor' }} + +
    +
    + {{/if}} + {{#if system.stats.sanity.enabled}} + +
    +
    + {{ localize 'Mosh.Sanity' }} + +
    +
    + {{/if}} + +
    +
    +
    +
    +
    +
    + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + + +
    + {{#if system.settings.firstEdition}} + + {{else}} + + {{/if}} +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + +
    + +
    +
    +
    {{system.stats.armor.mod}}
    + {{#if (compare 'str' system.stats.armor.cover '===' 'insignificant')}} +
     5
    + {{/if}} + {{#if (compare 'str' system.stats.armor.cover '===' 'light')}} +
     10
    + {{/if}} + {{#if (compare 'str' system.stats.armor.cover '===' 'heavy')}} +
     20
    + {{/if}} +
    +
    +
    +
    {{system.stats.armor.damageReduction}}
    + {{#if (compare 'str' system.stats.armor.cover '===' 'heavy')}} +
     5
    + {{/if}} +
    +
    +
    {{ localize 'Mosh.ArmorPoints' }}
    +
    {{ localize 'Mosh.DMGReduction' }}
    +
    +
    +

    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    +
    + +
    {{ localize 'Mosh.SpecialAbilities' }}
    +
    + {{#each abilities as |ability id|}} +
  • +
    {{ability.name}}
    +
    {{{ability.system.description}}}
    +
    + + +
    +
  • + {{/each}} + + {{ localize 'Mosh.Add' }} +
    +
    + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Biography Tab --}} +
    + {{editor enriched.biography target="system.biography" button=true editable=true}} +
    + {{!-- Notes Tab --}} +
    + {{editor enriched.notes target="system.notes" button=true editable=true}} +
    + {{!-- Owned Items Tab --}} +
    + + {{#if system.settings.firstEdition}} + +
      +
    1. +
      +
      {{ localize 'Mosh.ArmorName' }}
      +
      {{ localize 'Mosh.AP' }}
      +
      {{ localize 'Mosh.DR' }}
      +
      {{ localize 'Mosh.Speed' }}
      +
      {{ localize 'Mosh.Oxygen' }}
      +
      {{ localize 'Mosh.Equipped' }}
      + +
    2. + {{#each armors as |armor id|}} +
    3. +
      +

      {{armor.name}}

      +
      {{armor.system.armorPoints}}
      +
      {{armor.system.damageReduction}}
      +
      {{armor.system.speed}}
      + {{#if armor.system.oxygenMax}} +
      {{armor.system.oxygenCurrent}}/{{armor.system.oxygenMax}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      +
      + + +
      +
    4. + {{/each}} +
    + {{else}} + +
      +
    1. +
      +
      {{ localize 'Mosh.ArmorName' }}
      +
      {{ localize 'Mosh.SaveBonus' }}
      +
      {{ localize 'Mosh.Speed' }}
      +
      {{ localize 'Mosh.Oxygen' }}
      +
      {{ localize 'Mosh.Equipped' }}
      + +
    2. + {{#each armors as |armor id|}} +
    3. +
      +

      {{armor.name}}

      +
      {{armor.system.armorPoints}}
      +
      {{armor.system.speed}}
      + {{#if armor.system.oxygenMax}} +
      {{armor.system.oxygenCurrent}}/{{armor.system.oxygenMax}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      +
      + + +
      +
    4. + {{/each}} +
    + {{/if}} + + +
      +
    1. +
      +
      {{ localize 'Mosh.ItemName' }}
      +
      {{ localize 'Mosh.Quantity' }}
      + {{#if system.settings.hideWeight}} + {{else}} +
      {{ localize 'Mosh.Weight' }}
      + {{/if}} +
      {{ localize 'Mosh.Value' }}
      +
      + Add +
      +
    2. + {{#if system.settings.hideWeight}} + {{#each gear as |item id|}} +
    3. +
      +

      {{item.name}}

      +
      {{item.system.quantity}}
      +
      {{item.system.cost}}
      +
      + + +
      +
    4. + {{/each}} + {{else}} + {{#each gear as |item id|}} +
    5. +
      +

      {{item.name}}

      +
      {{item.system.quantity}}
      +
      {{item.system.weight}}
      +
      {{item.system.cost}}
      +
      + + +
      +
    6. + {{/each}} + {{/if}} +
    + {{#unless system.settings.hideWeight}} +
    +
    {{ localize 'Mosh.CarryingCapacity' }}: {{system.weight.capacity}}
    +
    {{ localize 'Mosh.CurrentWeight' }}: {{system.weight.current}}
    +
    + {{/unless}} + +
    + {{!-- Owned Skills Tab --}} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.SkillName' }}
      +
      {{ localize 'Mosh.SkillRank' }}
      +
      {{ localize 'Mosh.SkillBonus' }}
      + +
    2. + {{#each skills as |skill id|}} +
    3. +
      +
      {{skill.name}}
      +
      {{skill.system.rank}}
      +
      {{skill.system.bonus}}
      +
      + + +
      +
    4. + {{/each}} +
    + + {{#if system.settings.firstEdition}} + + +
    +
    +
    {{ localize 'Mosh.SkillTraining' }}
    + +
    {{{system.xp.html}}}
    +
    +
    + + {{/if}} + +
    + + + + +
      +
    1. +
      +
      {{ localize 'Mosh.Condition' }}
      +
      {{ localize 'Mosh.Severity' }}
      +
      {{ localize 'Mosh.Treatment' }}
      + +
    2. + {{#each conditions as |condition id|}} +
    3. +
      +
      {{condition.name}}
      +
      {{condition.system.severity}}
      +
      + {{#if condition.system.treatment.html}} +
      + {{{condition.system.treatment.html}}} +
      + {{else}} +
      + {{condition.name}} +
      + {{/if}} +
      +
      + + +
      +
    4. + + {{/each}} +
    + + +
    + + {{!-- Owned Weapons Tab --}} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.WeaponName' }}
      +
      {{ localize 'Mosh.Damage' }}
      +
      {{ localize 'Mosh.Ammo' }}
      +
      {{ localize 'Mosh.Shots' }}
      +
      {{ localize 'Mosh.Range' }}
      + +
    2. + + {{#each weapons as |weapon id|}} +
    3. + +
      +
      {{weapon.name}}
      + {{#if weapon.system.antiArmor}} +
      {{weapon.system.damage}} ({{ localize 'Mosh.AntiArmorAcronym' }})
      + {{else}} +
      {{weapon.system.damage}}
      + {{/if}} + {{#if weapon.system.useAmmo}} +
      {{weapon.system.ammo}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} + {{#if weapon.system.useAmmo}} + {{#if (compare 'int' weapon.system.curShots '===' weapon.system.shots)}} + + {{else}} + + {{/if}} + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} + {{#if weapon.system.ranges.value}} +
      {{weapon.system.ranges.value}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      + + +
      +
    4. + {{/each}} +
    +
    +
    +
    diff --git a/templates/actor/ship-sheet-sbt.html b/templates/actor/ship-sheet-sbt.html new file mode 100644 index 0000000..0ff1b4f --- /dev/null +++ b/templates/actor/ship-sheet-sbt.html @@ -0,0 +1,571 @@ +
    + + + + +
    + +
    + + +
    + + +
    + + +
    + + +
    +
    {{ localize 'Mosh.Megadamage' }}
    + +
    +
    {{{system.megadamage.html}}}
    + +
    +
    + + +
    + +
    +
    +
    + + +
    + + +
    +
    {{ localize 'Mosh.Macros' }}
    + +
    + +
    +
    {{ localize 'Mosh.Emergency' }}
    + +
    {{ localize 'Mosh.DistressSignal' }}
    + +
    + +
    + + +
    + +
    {{ localize 'Mosh.Finances' }}
    + + +
    + +
    +
    + {{ localize 'Mosh.Bankruptcy' }} +
    + +
    {{ localize 'Mosh.BankruptcyCheck' }}
    + + +
    + +
    + +
    +
    {{ localize 'Mosh.MaintenanceAndRepairs' }}
    + +
    {{ localize 'Mosh.MaintenanceCheck' }}
    + + +
    + +
    + +
    +
    {{ localize 'Mosh.EnemyShips' }}
    + +
    {{ localize 'Mosh.MoraleCheck' }}
    +
    + + +
    + +
    + + + {{!-- Sheet Header --}} +
    + + + +
    + + + +
    +
    {{ localize 'Mosh.ShipIdentifier' }}
    +
    +
    + + + + + +
    +
    {{ localize 'Mosh.Transponder' }}
    +
    + {{#if system.transponder }} {{ localize 'Mosh.Enabled'}} {{ else }} {{ localize 'Mosh.Disabled' }} {{/if}} + +
    +
    + + + + + + + + + + + + + + +
    +
    + + +
    + + +
    +
    +
    {{ localize 'Mosh.StatsAndSaves' }}
    + + + +
    + + + + +
    +
    + {{ localize 'Mosh.Thrusters' }} +
    + + +
    + +
    +
    + {{ localize 'Mosh.Battle' }} +
    + + +
    + +
    +
    + {{ localize 'Mosh.Systems' }} +
    +
    + + +
    +
    + +
    +
    + {{ localize 'Mosh.O2Remaining' }} +
    +
    +
    + +
    + + +
    Make / Model / Jump / Class / Type
    + + +
    + +
    + + +
    + +
    + +
    + +
    Current
    +
    Maximum
    +
    + + +
    +
    + +
    +
    + WARP + CORES +
    +
    +
    + +
    + +
    +
    + +
    +
    + {{ localize 'Mosh.Cryopods' }} +
    +
    + + +
    +
    + +
    +
    + {{ localize 'Mosh.EscapePods' }} +
    +
    +
    + + +
    {{ localize 'Mosh.OpenDeckplan' }}
    + +
    + + + +
    + + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + +
    + + {{#each crew as | crew id|}} +
    +
    + {{crew.name}} + +
    +
    {{{crew.system.job}}}
    + +
    + + {{/each}} + {{ localize 'Mosh.Add' }} +
    +
    + + + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Biography Tab --}} +
    + + + {{editor system.biography target="system.biography" button=true owner=owner editable=true}} +
    + + {{!-- Layout Tab --}} +
    + +
    + {{!-- Owned Weapons Tab --}} +
    + +
    + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Base' }}
    +
    {{ localize 'Mosh.Total' }}
    +
    + + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Base' }}
    +
    {{ localize 'Mosh.Total' }}
    +
    + + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Installed' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + +
    + + +
      +
    1. +
      +
      {{ localize 'Mosh.Name' }}
      +
      {{ localize 'Mosh.Bonus' }}
      + +
    2. + {{#each weapons as |weapon id|}} +
    3. + +
      +
      +
      {{weapon.name}}
      +
      {{weapon.system.bonus}}
      +
      + + +
      +
    4. + {{/each}} +
    +
    + {{!-- Owned Modules Tab --}} +
    + +
    + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Base' }}
    +
    {{ localize 'Mosh.Total' }}
    +
    + +
    + + +
      +
    1. +
      +
      {{ localize 'Mosh.ModuleName' }}
      +
      {{ localize 'Mosh.Quantity' }}
      +
      {{ localize 'Mosh.Cost' }}
      +
      {{ localize 'Mosh.Feature' }}
      + +
    2. + {{#each modules as |module id|}} +
    3. +
      +
      +

      {{module.name}}

      +
      {{module.system.quantity}}
      +
      {{module.system.cost}}
      +
      {{module.system.feature}}
      +
      + + +
      +
    4. + {{/each}} +
    +
    + {{!-- Owned Cargo Tab --}} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.ItemName' }}
      +
      {{ localize 'Mosh.Quantity' }}
      +
      {{ localize 'Mosh.Weight' }}
      +
      {{ localize 'Mosh.Value' }}
      +
      + Add +
      +
    2. + {{#each cargo as |item id|}} +
    3. +
      +
      +

      {{item.name}}

      +
      {{item.system.quantity}}
      +
      {{item.system.weight}}
      +
      {{item.system.cost}}
      +
      + + +
      +
    4. + {{/each}} +
    +
    + {{!-- Repair Tab --}} +
    +
    + +
      +
    1. +
      +
      Repairs
      +
      Type
      +
      + Add +
      +
    2. + {{#each majorRepairs as |item id|}} +
    3. +
      +
      +

      {{item.name}}

      +
      + Major +
      +
      + + +
      +
    4. + {{/each}} + {{#each minorRepairs as |item id|}} +
    5. +
      +
      +

      {{item.name}}

      +
      + Minor +
      +
      + + +
      +
    6. + {{/each}} +
    +
    +
    +
    +
    diff --git a/templates/actor/ship-sheet.html b/templates/actor/ship-sheet.html new file mode 100644 index 0000000..a4664c9 --- /dev/null +++ b/templates/actor/ship-sheet.html @@ -0,0 +1,308 @@ +
    + + {{!-- Sheet Header --}} +
    + + +
    + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    {{ localize 'Mosh.Class' }}
    +
    +
    + + +
    +
    {{ localize 'Mosh.Type' }}
    +
    +
    + + +
    +
    {{ localize 'Mosh.Cost' }}
    +
    +
    + + +
    +
    {{ localize 'Mosh.Owed' }}
    +
    +
    +
    +
    + +
    + + +
    + +
    +
    +
    + {{ localize 'Mosh.Armor' }} +
    + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Speed' }} +
    + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Intellect' }} +
    + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Combat' }} +
    + +
    + +
    +
    +
    +
    + +
    + +
    + +
    {{system.supplies.hull.percentage}}
    + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    + + + +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    +
    + + +
    + +
    + +
    + +
    {{ localize 'Mosh.Current' }}
    +
    {{ localize 'Mosh.Maximum' }}
    +
    +
    + +
    +
    {{ localize 'Mosh.Notes' }}
    +
    + {{#each abilities as |ability id|}} +
    +
    {{ability.name}}
    +
    {{{ability.system.description}}}
    +
    + + +
    +
    + + {{/each}} + + Add +
    +
    + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Biography Tab --}} +
    + {{editor enriched.biography target="system.biography" button=true owner=owner editable=true}} +
    + + {{!-- Layout Tab --}} +
    + +
    + {{!-- Owned Weapons Tab --}} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.Name' }}
      +
      {{ localize 'Mosh.Damage' }}
      +
      {{ localize 'Mosh.Ammo' }}
      +
      {{ localize 'Mosh.Shots' }}
      + +
    2. + {{#each weapons as |weapon id|}} +
    3. + +
      +
      {{weapon.name}}
      +
      {{weapon.system.damage}}
      + {{#if weapon.system.useAmmo}} +
      {{weapon.system.ammo}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} + {{#if weapon.system.shots}} +
      {{weapon.system.curShots}}/{{weapon.system.shots}}
      + {{else}} +
      {{ localize 'Mosh.NA' }}
      + {{/if}} +
      + + +
      +
    4. + {{/each}} +
    +
    + {{!-- Owned Modules Tab --}} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.ModuleName' }}
      +
      {{ localize 'Mosh.Quantity' }}
      +
      {{ localize 'Mosh.Hull' }}
      +
      {{ localize 'Mosh.Feature' }}
      + +
    2. + {{#each modules as |module id|}} +
    3. +
      +
      +

      {{module.name}}

      +
      {{module.system.quantity}}
      +
      {{module.system.hull}}
      +
      {{module.system.feature}}
      +
      + + +
      +
    4. + {{/each}} +
    +
    + {{!-- Owned Cargo Tab --}} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.ItemName' }}
      +
      {{ localize 'Mosh.Quantity' }}
      +
      {{ localize 'Mosh.Weight' }}
      +
      {{ localize 'Mosh.Value' }}
      + +
    2. + {{#each cargo as |item id|}} +
    3. +
      +
      +

      {{item.name}}

      +
      {{item.system.quantity}}
      +
      {{item.system.weight}}
      +
      {{item.system.cost}}
      +
      + + +
      +
    4. + {{/each}} +
    +
    +
    +
    diff --git a/templates/chat/itemRoll.html b/templates/chat/itemRoll.html new file mode 100644 index 0000000..18733a6 --- /dev/null +++ b/templates/chat/itemRoll.html @@ -0,0 +1,88 @@ +
    +
    +
    +
    +
    + {{#if swapNameDesc}} +
    {{swapName}}
    + {{else}} + {{#if (compare 'int' item.name.length '>=' 22)}} +
    {{item.name}}
    + {{else}} +
    {{item.name}}
    + {{/if}} + {{/if}} + {{#if (compare 'str' item.type '===' 'ability')}} + {{#if (compare 'str' actor.img '===' 'icons/svg/mystery-man.svg')}} +
    + {{else}} +
    + {{/if}} + {{else}} +
    + {{/if}} +
    + {{#if item.system.roll}} +
    + {{#if (compare 'str' item.system.sla.impact '===' 'heal')}} +
    You restore [[{{item.system.roll}}[damage]]] points of healing.
    + {{else}} +
    You inflict [[{{item.system.roll}}[damage]]] points of damage.
    + {{/if}} +
    +
    +
    +
    + {{/if}} + {{#if item.system.severity}} +
    +
    {{ localize 'Mosh.Severity' }}: {{item.system.severity}}
    +
    +
    +
    +
    + {{/if}} + {{#if item.system.armorPoints}} +
    +
    {{ localize 'Mosh.ArmorPoints' }}: {{item.system.armorPoints}}
    +
    +
    +
    +
    + {{/if}} + {{#if item.system.damageReduction}} +
    +
    {{ localize 'Mosh.DMGReduction' }}: {{item.system.damageReduction}}
    +
    +
    +
    +
    + {{/if}} + {{#if swapNameDesc}} +
    +
    {{{item.name}}}
    +
    +
    + {{else if (compare 'str' item.system.type '===' 'repair')}} +
    + {{#if item.system.major}} +
    {{ localize 'Mosh.MajorRepair' }}
    + {{else}} +
    {{ localize 'Mosh.MinorRepair' }}
    + {{/if}} +
    +
    +
    +
    +
    +
    {{{item.name}}}
    +
    +
    + {{else}} +
    +
    {{{item.system.description}}}
    +
    +
    + {{/if}} +
    diff --git a/templates/chat/modifyActor.html b/templates/chat/modifyActor.html new file mode 100644 index 0000000..d25639f --- /dev/null +++ b/templates/chat/modifyActor.html @@ -0,0 +1,28 @@ +
    +
    +
    + {{#if (compare 'int' msgHeader.length '>=' 22)}} +
    {{{msgHeader}}}
    + {{else}} +
    {{{msgHeader}}}
    + {{/if}} +
    +
    +
    +
    + {{{msgFlavor}}} + {{#if modRollString}} +
    + {{{parsedRollResult.rollHtml}}} + {{else}} +

    + {{/if}} + {{{msgOutcome}}} + {{#if halfDamage}} +

    @UUID[Compendium.mosh.macros_hotbar_0e.eyGvbBi1BhWSgfUP]{Make a Panic Check} + {{/if}} +
    +
    +
    +
    \ No newline at end of file diff --git a/templates/chat/modifyItem.html b/templates/chat/modifyItem.html new file mode 100644 index 0000000..fe61dbd --- /dev/null +++ b/templates/chat/modifyItem.html @@ -0,0 +1,16 @@ +
    +
    +
    + {{#if (compare 'int' msgHeader.length '>=' 22)}} +
    {{{msgHeader}}}
    + {{else}} +
    {{{msgHeader}}}
    + {{/if}} +
    +
    +
    +
    {{{flavorText}}}
    +
    +
    +
    \ No newline at end of file diff --git a/templates/chat/reload.html b/templates/chat/reload.html new file mode 100644 index 0000000..16f644c --- /dev/null +++ b/templates/chat/reload.html @@ -0,0 +1,17 @@ +
    +
    +
    + {{#if (compare 'int' item.name.length '>=' 22)}} +
    {{{item.name}}}
    + {{else}} +
    {{{item.name}}}
    + {{/if}} +
    +
    +
    +
    {{{msgBody}}}
    +
    +
    +
    +
    \ No newline at end of file diff --git a/templates/chat/rollCheck.html b/templates/chat/rollCheck.html new file mode 100644 index 0000000..b36d0a3 --- /dev/null +++ b/templates/chat/rollCheck.html @@ -0,0 +1,157 @@ +
    +
    +
    + {{#if (compare 'int' msgHeader.length '>=' 22)}} +
    {{{msgHeader}}}
    + {{else}} +
    {{{msgHeader}}}
    + {{/if}} +
    +
    + {{#if (compare 'str' specialRoll '!==' 'damage')}} + {{{parsedRollResult.outcomeHtml}}} +
    +
    + {{#if (compare 'int' parsedRollResult.total '>=' 90)}} + {{ localize 'Mosh.YouRolled90OrHigher' }} + {{else}} + {{#if isSlaEbbSkill}} + {{#if (compare 'int' skillValue '>' 0)}} + You {{{outcomeVerb}}} {{{comparisonText}}} your {{{attribute}}} plus the {{{skill}}} discipline. + {{else}} + You {{{outcomeVerb}}} {{{comparisonText}}} your {{{attribute}}} while channeling {{{skill}}}. + {{/if}} + {{else}} + {{#if (compare 'int' skillValue '>' 0)}} + You {{{outcomeVerb}}} {{{comparisonText}}} your {{{attribute}}} plus {{{skill}}} skill bonus. + {{else}} + You {{{outcomeVerb}}} {{{comparisonText}}} your {{{attribute}}}. + {{/if}} + {{/if}} + {{/if}} +
    +
    + {{{parsedRollResult.rollHtml}}} + {{#if isSlaEbbSkill}} +
    +
    Ebb Discipline
    +
    {{skill}}{{#if skillCategory}} | {{skillCategory}}{{/if}} | Bonus +{{skillValue}}
    + {{#if ebbTier}}
    Tier: {{ebbTier}}
    {{/if}} + {{#if fluxCost}}
    Flux Used: {{fluxCost}}
    {{/if}} + {{#if rollBreakdown}} +
    Target Number: {{#each rollBreakdown.parts as |part index|}}{{#if index}} + {{/if}}{{part.label}} {{part.value}}{{/each}} = {{rollBreakdown.total}}
    + {{/if}} + {{#if rollBreakdown.support.length}} +
    Support:
    + {{#each rollBreakdown.support as |part|}} +
    {{part.label}} {{#if (compare 'int' part.value '>=' 0)}}+{{/if}}{{part.value}}{{#if part.note}} ({{part.note}}){{/if}}
    + {{/each}} + {{/if}} +
    + {{/if}} + {{/if}} +
    + {{#if (compare 'str' specialRoll '===' 'damage')}} +
    {{{flavorText}}}
    + {{#if needsDesc}} +
    +
    +
    +
    DESCRIPTION
    +
    +
    +
    +
    +
    {{{weapon.system.description}}}
    + {{#if woundEffect}} +
    +
    {{ localize 'Mosh.WoundEffect' }} +
    + {{{woundEffect}}} +
    + {{/if}} + {{/if}} +
    +
    + {{else}} + {{#if parsedRollResult.success}} + {{#if weapon}} +
    {{{flavorText}}}
    + {{#if criticalSuccessOptions.length}} +
    +
    Critical Success Options
    +
      + {{#each criticalSuccessOptions as |option|}} +
    1. {{option}}
    2. + {{/each}} +
    +
    + {{/if}} + {{#if needsDesc}} +
    +
    +
    +
    {{ localize 'Mosh.Description' }}
    +
    +
    +
    +
    +
    {{{weapon.system.description}}}
    + {{#if woundEffect}} +
    +
    {{ localize 'Mosh.WoundEffect' }} +
    + {{{woundEffect}}} +
    + {{/if}} + {{/if}} +
    +
    + {{else}} +
    {{{flavorText}}}
    + {{#if criticalSuccessOptions.length}} +
    +
    Critical Success Options
    +
      + {{#each criticalSuccessOptions as |option|}} +
    1. {{option}}
    2. + {{/each}} +
    +
    + {{/if}} + {{/if}} + {{else}} + {{#if flavorText}}
    {{{flavorText}}}
    {{/if}} + {{#if criticalFailureTable}} +
    +
    {{criticalFailureTable.label}}
    +
    d10: {{criticalFailureTable.roll}}
    +
    {{criticalFailureTable.entry.title}}
    +
    {{criticalFailureTable.entry.effect}}
    +
    + {{/if}} + {{#if critFail}} +

    @UUID[Compendium.mosh.macros_hotbar_1e.IgWvaabVqzKDzLL4]{Make a Panic Check} + {{/if}} + {{/if}} + {{/if}} + {{#if targetingResult}} +
    +
    Target Resolution
    +
    {{targetingResult.targetName}} took {{targetingResult.finalDamage}} damage.
    +
    Rolled {{targetingResult.rawDamage}}. Armour reduced {{targetingResult.armourReduced}}{{#if targetingResult.armourPiercing}} after AP/anti-armour effects{{/if}}.
    + {{#if targetingResult.additionalTargets}} +
    {{targetingResult.additionalTargets}} additional targeted token(s) were ignored for this automatic application.
    + {{/if}} + {{#if targetingResult.updateText}} +
    {{{targetingResult.updateText}}}
    + {{/if}} + {{#if targetingResult.warning}} +
    {{targetingResult.warning}}
    + {{/if}} +
    + {{/if}} +
    +
    +
    diff --git a/templates/chat/rollTable.html b/templates/chat/rollTable.html new file mode 100644 index 0000000..11e1d4a --- /dev/null +++ b/templates/chat/rollTable.html @@ -0,0 +1,54 @@ +
    +
    +
    +
    {{{tableName}}}
    +
    +
    + {{{parsedRollResult.outcomeHtml}}} +
    +
    {{{msgDesc}}}
    +
    + {{{parsedRollResult.rollHtml}}} + {{#if secondRoll}} +
    + {{#if (compare 'str' specialRoll '===' 'panicCheck')}} +
    {{ localize 'Mosh.RollingForPanicEffect' }}
    + {{/if}} + {{#if (compare 'str' specialRoll '===' 'maintenanceCheck')}} +
    {{ localize 'Mosh.RollingForMaintenanceIssue' }}
    + {{/if}} +
    + {{{parsedRollResult2.rollHtml}}} + {{/if}} + {{#if parsedRollResult.success}} +
    {{{flavorText}}}
    + {{else}} + {{#if woundText}} + {{{woundText}}}

    + {{/if}} + {{#if (compare 'str' tableResultType '===' 'document')}} +
      + {{#each tableResult}} +
    1. + + +
    2. + {{/each}} +
    + {{/if}} + {{#if (compare 'str' tableResultType '===' 'text')}} + {{#if tableResultEdited}} +
    {{{tableResultEdited}}}{{{tableResultFooter}}}
    + {{else}} +
    {{{tableResult.[0].description}}}{{{tableResultFooter}}}
    + {{/if}} + {{/if}} + {{#if (compare 'str' specialRoll '===' 'maintenanceCheck')}} + {{#if critFail}} +

    @UUID[Compendium.mosh.macros_hotbar_1e.IgWvaabVqzKDzLL4]{Make a Panic Check} + {{/if}} + {{/if}} + {{/if}} +
    +
    diff --git a/templates/dialogs/actor-generator-dialog.html b/templates/dialogs/actor-generator-dialog.html new file mode 100644 index 0000000..39ad2ac --- /dev/null +++ b/templates/dialogs/actor-generator-dialog.html @@ -0,0 +1,306 @@ +
    + + {{!-- Sheet Header --}} +
    + +
    + +
    +
    {{ localize 'Mosh.Name' }}
    +
    + +
    +
    + +
    +
    {{ localize 'Mosh.CLASS' }}
    +
    + + + + + + + +
    + + +
    + + +
    +
    {{ localize 'Mosh.Wounds'}}
    +
    + +
    +
    + +
    +
    {{ localize 'Mosh.Credits' }}
    +
    + + roll + +
    +
    + + +
    + +
    + {{!-- The grid classes are defined in scss/global/_grid.scss. To use, + use both the "grid" and "grid-Ncol" class where "N" can be any number + from 1 to 12 and will create that number of columns. --}} + +
    + +
    +
    +
    + {{ localize + 'Mosh.Strength' }} +
    + roll + +
    + +
    +
    +
    + + +
    +
    +
    + {{ + localize 'Mosh.Speed' }} +
    + roll + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Intellect' }} +
    + roll + +
    + +
    +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Combat' }} +
    + roll + +
    + +
    +
    +
    +
    + +
    + +
    +
    +
    + HEALTH +
    + roll + +
    + +
    +
    + +
    + + +
    +
    +
    + {{ localize 'Mosh.Sanity' }} +
    + roll + +
    + +
    +
    +
    + + +
    +
    +
    + {{ + localize 'Mosh.Fear' }} +
    + roll + +
    + +
    +
    +
    + + +
    +
    +
    + {{ + localize 'Mosh.Body' }} +
    + roll + +
    + +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    + PATCH +
    + roll + +
    +
    + + +
    + + +
    + +
    +
    +
    + TRINKET +
    + roll + +
    +
    + + +
    + + +
    +
    +
    + + + +
    +
    +
    + {{ localize 'Mosh.Skills' }} +
    + +
    +
    + +
      +
    +
    +
    + + +
    +
    +
    + loadout +
    + roll + +
    +
    + +
      +
    +
    + +
    +
    + +
    +
    +
    +
    + + Roll everything +
    + roll +
    +
    + +
    +
    + Remove previous items +
    + +
    + +
    +
    + + Save character +
    + save +
    +
    +
    \ No newline at end of file diff --git a/templates/dialogs/actor-generator/actor-generator-skill-option-choice-dialog.html b/templates/dialogs/actor-generator/actor-generator-skill-option-choice-dialog.html new file mode 100644 index 0000000..f8a691d --- /dev/null +++ b/templates/dialogs/actor-generator/actor-generator-skill-option-choice-dialog.html @@ -0,0 +1,53 @@ +
    + +
    +
    +

    {{localize 'Mosh.CharacterGenerator.SkillOption.ChoiceText'}}

    +
    +
    + {{#each options}} +
    + +

    {{this.name}}: +

    + +
      + {{#if this.master}} +
    • + {{localize 'Mosh.SkillRankMaster'}} : {{this.master}} +
    • + {{/if}} + {{#if this.expert}} +
    • + {{localize 'Mosh.SkillRankExpert'}} : {{this.expert}} +
    • + {{/if}} + {{#if this.trained}} +
    • + {{localize 'Mosh.SkillRankTrained'}} : {{this.trained}} +
    • + {{/if}} + {{#if this.master_full_set}} +
    • + {{localize 'Mosh.SkillRankMaster'}} & {{localize 'Mosh.SkillsPrerequisite'}} : + {{this.master_full_set}} +
    • + {{/if}} + {{#if this.expert_full_set}} +
    • + {{localize 'Mosh.SkillRankExpert'}} & {{localize 'Mosh.SkillsPrerequisite'}} : + {{this.expert_full_set}} +
    • + {{/if}} + {{#if this.from_list}} +
    • + {{UUidListToNames this.from_list}} +
    • + {{/if}} +
    +
    + {{/each}} + +
    +
    +
    \ No newline at end of file diff --git a/templates/dialogs/actor-generator/actor-generator-skill-option-full-expert-dialog.html b/templates/dialogs/actor-generator/actor-generator-skill-option-full-expert-dialog.html new file mode 100644 index 0000000..2b7d170 --- /dev/null +++ b/templates/dialogs/actor-generator/actor-generator-skill-option-full-expert-dialog.html @@ -0,0 +1,40 @@ +
    + +
    +
    +

    {{localize + 'Mosh.CharacterGenerator.SkillOption.PopupFullExpertDescription'}}

    +
    +
    + + + +
    +
    +
    \ No newline at end of file diff --git a/templates/dialogs/actor-generator/actor-generator-skill-option-full-master-dialog.html b/templates/dialogs/actor-generator/actor-generator-skill-option-full-master-dialog.html new file mode 100644 index 0000000..e14bf2d --- /dev/null +++ b/templates/dialogs/actor-generator/actor-generator-skill-option-full-master-dialog.html @@ -0,0 +1,55 @@ + + +
    + +
    +
    +

    {{localize + 'Mosh.CharacterGenerator.SkillOption.PopupFullMasterDescription'}}

    +
    +
    + + + + +
    +
    +
    \ No newline at end of file diff --git a/templates/dialogs/actor-generator/actor-generator-skill-option-single-dialog.html b/templates/dialogs/actor-generator/actor-generator-skill-option-single-dialog.html new file mode 100644 index 0000000..5675f66 --- /dev/null +++ b/templates/dialogs/actor-generator/actor-generator-skill-option-single-dialog.html @@ -0,0 +1,24 @@ +
    +
    +
    +

    {{description}}:

    +
    +
    + + +
    +
    + +
    \ No newline at end of file diff --git a/templates/dialogs/bankrupcy-save-dialog.html b/templates/dialogs/bankrupcy-save-dialog.html new file mode 100644 index 0000000..7818482 --- /dev/null +++ b/templates/dialogs/bankrupcy-save-dialog.html @@ -0,0 +1,33 @@ + +
    +
    +
    +

    {{ localize "Mosh.BankruptcySave"}}

    + {{ localize "Mosh.BankrupcyCheckExplanation"}} ({{ localize "Mosh.OrQuarterAsDetermineByWarden" }}), {{localize 'Mosh.MakeA'}} {{ localize "Mosh.BankrupcySave " }} {{ localize "Mosh.BankrupcySaveExplanationEnd"}}.
    +
    +
    +

    {{ localize "Mosh.SelectYourRollType"}}:

    \ No newline at end of file diff --git a/templates/dialogs/choose-cover-dialog.html b/templates/dialogs/choose-cover-dialog.html new file mode 100644 index 0000000..a1a114b --- /dev/null +++ b/templates/dialogs/choose-cover-dialog.html @@ -0,0 +1,125 @@ +
    +
    +
    +

    {{ localize 'Mosh.Cover' }}

    + {{ localize 'Mosh.TheEnvironmentCanProvideProtectionCalled'}} {{ localize 'Mosh.Cover'}}. + {{ localize 'Mosh.ItCanBeDestroyedLikeArmor' }} + {{ localize 'Mosh.IfYouShotWhileInCover'}}. {{ localize 'Mosh.YourCoverValuesAreDisplayedIn'}} {{ localize 'Mosh.Orange' }}.
    +
    +
    +
    + {{ localize 'Mosh.SelectYourCurrentCoverSituation'}}: +
    + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/dialogs/choose-skill-dialog-header.html b/templates/dialogs/choose-skill-dialog-header.html new file mode 100644 index 0000000..7003300 --- /dev/null +++ b/templates/dialogs/choose-skill-dialog-header.html @@ -0,0 +1,28 @@ +
    +
    +

    {{ localize 'Mosh.AddASkill'}}

    + {{ localize 'Mosh.IfYouHaveARelevantSkill'}} {{ localize 'Mosh.GivingYouAHigherNumber' }} + {{#if statSummary}} +
    {{statSummary}}
    + {{/if}} + {{#if attackSummary.length}} +
    + {{#each attackSummary as |entry|}} +
    {{entry}}
    + {{/each}} +
    + {{/if}} +
    +
    + diff --git a/templates/dialogs/creature-settings-dialog.html b/templates/dialogs/creature-settings-dialog.html new file mode 100644 index 0000000..1a7ab7d --- /dev/null +++ b/templates/dialogs/creature-settings-dialog.html @@ -0,0 +1,36 @@ +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    diff --git a/templates/dialogs/distress-signal-dialog.html b/templates/dialogs/distress-signal-dialog.html new file mode 100644 index 0000000..97e7c72 --- /dev/null +++ b/templates/dialogs/distress-signal-dialog.html @@ -0,0 +1,32 @@ + +
    +
    +
    +

    {{ localize 'Mosh.DistressSignal'}}

    {{ localize 'Mosh.DistressSignalTableExplanation' }}
    +
    +
    +

    {{localize 'Mosh.SelectYourRollType'}}:

    \ No newline at end of file diff --git a/templates/dialogs/minteance-check-dialog.html b/templates/dialogs/minteance-check-dialog.html new file mode 100644 index 0000000..224cebe --- /dev/null +++ b/templates/dialogs/minteance-check-dialog.html @@ -0,0 +1,34 @@ + +
    +
    +
    +

    {{ localize 'Mosh.MaintenanceCheck'}}

    + {{ localize 'Mosh.MaintenanceCheckExplanation1' }} + {{ localize 'Mosh.MinorRepairs'}} {{localize 'Mosh.MinorRepairsExplanation'}} . {{ localize 'Mosh.MajorRepairs'}}
    +
    +
    +

    {{ localize 'Mosh.SelectYourRollType:

    \ No newline at end of file diff --git a/templates/dialogs/settings-rolltableconfig-dialog.html b/templates/dialogs/settings-rolltableconfig-dialog.html new file mode 100644 index 0000000..2e089cf --- /dev/null +++ b/templates/dialogs/settings-rolltableconfig-dialog.html @@ -0,0 +1,119 @@ +
    +
    + +
    +
    + +
    Rolltable Configuration
    +
    + +
    +
    Panic Check
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +
    +
    Wound Check
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +
    +
    Death Save
    +
    +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    Ship Checks
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + +
    +
    FINISH
    +
    +
    \ No newline at end of file diff --git a/templates/dialogs/ship-deckplan-dialog.html b/templates/dialogs/ship-deckplan-dialog.html new file mode 100644 index 0000000..d84c63c --- /dev/null +++ b/templates/dialogs/ship-deckplan-dialog.html @@ -0,0 +1,10 @@ +
    +
    +
    +
    + +
    +
    +
    +
    \ No newline at end of file diff --git a/templates/dialogs/ship-macro-dialog.html b/templates/dialogs/ship-macro-dialog.html new file mode 100644 index 0000000..8a22dda --- /dev/null +++ b/templates/dialogs/ship-macro-dialog.html @@ -0,0 +1,69 @@ +
    +
    + +
    + +
    +
    +
    {{actor.name}}
    +
    + +
    +
    {{ localize 'Mosh.Emergency' }}
    + + +
    {{ localize 'Mosh.DistressSignal' }}
    + +
    + +
    + + +
    + +
    {{ localize 'Mosh.Finances' }}
    + + +
    + +
    +
    + {{ localize 'Mosh.Bankruptcy' }} +
    + +
    {{ localize 'Mosh.BankruptcyCheck' }}
    + + +
    + +
    + +
    +
    {{ localize 'Mosh.MaintenanceAndRepairs' }}
    + +
    {{ localize 'Mosh.MaintenanceCheck' }}
    + + +
    + +
    + + +
    +
    {{ localize 'Mosh.EnemyShips' }}
    + + +
    {{ localize 'Mosh.MoraleCheck' }}
    +
    + + + + + + +
    {{ localize 'Mosh.CloseMenu' }}
    + +
    diff --git a/templates/dialogs/ship-megadamage-dialog.html b/templates/dialogs/ship-megadamage-dialog.html new file mode 100644 index 0000000..135ff5d --- /dev/null +++ b/templates/dialogs/ship-megadamage-dialog.html @@ -0,0 +1,18 @@ +
    +
    + +
    + +
    +
    + +
    +
    {{ localize 'Mosh.MegadamageEffects' }}
    + + +
    {{{actor.system.megadamage.menu.html}}}
    +
    +
    +
    {{ localize 'Mosh.Finish' }}
    + +
    diff --git a/templates/dialogs/ship-setup-dialog.html b/templates/dialogs/ship-setup-dialog.html new file mode 100644 index 0000000..321008c --- /dev/null +++ b/templates/dialogs/ship-setup-dialog.html @@ -0,0 +1,34 @@ +
    +
    + +
    + +
    +
    + +
    +
    {{ localize 'Mosh.ShipSetup' }}
    + +
    {{ localize 'Mosh.RollStartingCondition' }}
    + +
    {{ localize 'Mosh.Finish' }}
    + +
    + + + + + + + + + +
    diff --git a/templates/dialogs/skill-check-stat-selection-dialog.html b/templates/dialogs/skill-check-stat-selection-dialog.html new file mode 100644 index 0000000..8893afd --- /dev/null +++ b/templates/dialogs/skill-check-stat-selection-dialog.html @@ -0,0 +1,58 @@ +
    +

    {{ localize "Mosh.SelectAStat" }}

    + {{ localize "Mosh.ChooseTheStatForSkillCheck" }}{{ localize "Mosh.GivingYouAHigherNumber"}} + +
    +
    + + + + \ No newline at end of file diff --git a/templates/dialogs/sla-character-generator.html b/templates/dialogs/sla-character-generator.html new file mode 100644 index 0000000..5db79e8 --- /dev/null +++ b/templates/dialogs/sla-character-generator.html @@ -0,0 +1,92 @@ +
    +
    +
    + +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    {{#if editingExisting}}{{actorName}}{{else}}Create New Operative{{/if}}
    +
    +
    + +
    + + + + + {{#if editingExisting}} + + {{/if}} +
    + +
    +
    +
    Species Briefing
    +
    {{briefing.speciesTitle}}
    +
    {{briefing.speciesCopy}}
    +
    + {{#each briefing.speciesNotes as |note|}} +
    {{note}}
    + {{/each}} +
    +
    +
    +
    Package Briefing
    +
    {{briefing.packageTitle}}
    +
    {{briefing.packageCopy}}
    +
    + {{#each briefing.packageSkills as |skill|}} +
    {{skill}}
    + {{/each}} +
    +
    +
    + +
    +
    Flux Outlook
    +
    {{briefing.fluxCopy}}
    +
    + +

    + This generator uses the SLA species, package, loadout, and Ebb seed data already installed in the world, then rolls direct Mothership-style stats tailored to the selected species. +

    + +
    + +
    +
    diff --git a/templates/dialogs/sla-world-tools.html b/templates/dialogs/sla-world-tools.html new file mode 100644 index 0000000..8768ba4 --- /dev/null +++ b/templates/dialogs/sla-world-tools.html @@ -0,0 +1,39 @@ +
    +

    SLA Mothership world helpers for seeding content, creating operatives, and building a ready-to-play starter cast.

    + +
    +
    + +
    {{seededItems}}
    +
    +
    + +
    {{actorCount}}
    +
    +
    + +
    {{skillCount}} / {{weaponCount}}
    +
    +
    + +
    {{gearCount}} / {{starterCount}}
    +
    +
    + +
    {{ebbActorCount}}
    +
    +
    + +
    + + + + + + + + {{#if quickBattleMapBuilderReady}} + + {{/if}} +
    +
    diff --git a/templates/item/item-ability-sheet.html b/templates/item/item-ability-sheet.html new file mode 100644 index 0000000..28e12f3 --- /dev/null +++ b/templates/item/item-ability-sheet.html @@ -0,0 +1,91 @@ +
    + +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    + +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    + + {{#if system.sla.tiers.length}} +
    + +
    + {{#each system.sla.tiers as |tier|}} +
    {{tier.label}} | {{tier.cost}} Flux{{#if tier.damage}} | {{tier.damage}}{{/if}}{{#if tier.healing}} | {{tier.healing}}{{/if}}
    + {{/each}} +
    +
    + {{/if}} + + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    +
    +
    diff --git a/templates/item/item-armor-sheet.html b/templates/item/item-armor-sheet.html new file mode 100644 index 0000000..2e432e1 --- /dev/null +++ b/templates/item/item-armor-sheet.html @@ -0,0 +1,161 @@ +
    + +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    + + + + +
    +
    +
    + +
    + + +
    + + +
    + +
    +
    + {{#if system.settings.firstEdition}} + +
    + + +
    + +
    +
    + {{/if}} +
    + + +
    + +
    + + +
    + + + +
    + + +
    + +
    +
    + +
    +
    + + +
    + + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    +
    + +
    + + + + +
    + + +
    + +
    +
    + +
    + + {{!-- Sheet Tab Navigation --}} + + +
    + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    + + {{!-- Item Tab --}} +
    +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    diff --git a/templates/item/item-class-sheet.html b/templates/item/item-class-sheet.html new file mode 100644 index 0000000..e8b6679 --- /dev/null +++ b/templates/item/item-class-sheet.html @@ -0,0 +1,423 @@ +
    + +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    +
    +
    + {{!-- The grid classes are defined in scss/global/_grid.scss. To use, + use both the "grid" and "grid-Ncol" class where "N" can be any number + from 1 to 12 and will create that number of columns. --}} + +
    + +
    +
    +
    + {{ localize + 'Mosh.Strength' }} +
    + +
    +
    + + +
    +
    +
    + {{ localize + 'Mosh.Speed' }} +
    + +
    +
    + + +
    +
    +
    + {{ localize + 'Mosh.Intellect' }} +
    + +
    +
    + + +
    +
    +
    + {{ localize + 'Mosh.Combat' }} +
    + +
    +
    +
    + +
    + +
    +
    +
    + + {{#if system.settings.firstEdition}} + {{ localize 'Mosh.Wounds' }} + {{else}} + {{ localize 'Mosh.Hits' }} + {{/if}} + +
    + +
    +
    + + +
    +
    +
    + {{ localize + 'Mosh.Sanity' }} +
    + +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Fear' + }} +
    + +
    +
    + + +
    +
    +
    + {{ localize 'Mosh.Body' + }} +
    + +
    +
    + + +
    +
    +
    + {{localize + 'Mosh.Robotic'}} +
    + +
    +
    +
    +
    +
    +
    + {{#if system.settings.firstEdition}} +
    {{ localize 'Mosh.TraumaResponse' }}
    + {{else}} +
    {{ localize 'Mosh.StressResponse' }}
    + {{/if}} + + +
    + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    + {{!-- stats&saves Tab --}} +
    + +
      +
    1. +
      {{ localize 'Mosh.Value' }}
      +
      {{ localize 'Mosh.StatsAndSaves' }}
      + +
    2. + {{#each system.selected_adjustment.choose_stat as |group id|}} +
    3. +
      {{group.modification}}
      +
      {{#each group.stats as |stat id|}}{{stat}}{{#if @last}}{{else}}, {{/if}}{{/each}} +
      +
      + +
      +
    4. + {{/each}} +
    +
    + {{!-- skills Tab --}} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.SkillName' }}
      +
      {{ localize 'Mosh.SkillRank' }}
      +
      {{ localize 'Mosh.SkillBonus' }}
      +
      + +
      +
    2. + + {{#each system.base_adjustment.skills_granted_object as |skill id|}} +
    3. +
      +
      {{skill.name}}
      +
      {{skill.system.rank}}
      +
      {{skill.system.bonus}}
      +
      + +
      +
    4. + {{/each}} +
    +
    + + {{!-- skills Tab --}} +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    + + +
    + +
    +
    +
    +
    + + {{!-- skills Tab --}} +
    + + {{#each system.selected_adjustment.choose_skill_or as |group id|}} + +
      +
    1. +
      +
      +
      {{ localize 'Mosh.SkillRankTrained' }}
      +
      {{ localize 'Mosh.SkillRankExpert' }}
      +
      {{ localize 'Mosh.SkillRankMaster' }}
      +
      {{ localize 'Mosh.CharacterGenerator.SkillOption.PopupFullExpertName' }}
      +
      {{ localize 'Mosh.CharacterGenerator.SkillOption.PopupFullMasterName' }}
      +
      {{ localize 'Mosh.Skills' }}
      +
      + +
      +
    2. + {{#each group}} +
    3. +
      {{this.name}}
      + + +
      {{this.trained}}
      +
      {{this.expert}}
      +
      {{this.master}}
      +
      {{this.expert_full_set}}
      +
      {{this.master_full_set}}
      +
      {{this.from_list.length}}
      +
      + +
      +
    4. + {{/each}} +
    5. +
      +
      +
      +
      +
      +
      +
      {{ localize 'Mosh.classNewSkillOptionSkillTip'}}
      +
      + +
      +
    6. +
    + {{/each}} +
    + + +
    + +
    + +
    + + +
    + +
    +
    +
    + +
    + + +
    + +
    +
    +
    + +
    + + +
    + +
    +
    +
    + + + {{!-- Common skills Tab --}} +
    +
    + {{ localize 'Mosh.CharacterGenerator.CommonSkillExplanation' }} +
    + +
      +
    1. +
      +
      {{ localize 'Mosh.SkillName' }}
      +
      {{ localize 'Mosh.SkillRank' }}
      +
      {{ localize 'Mosh.SkillBonus' }}
      +
      +
      +
    2. + {{#each system.common_skills_object as |skill id|}} +
    3. +
      +
      {{skill.name}}
      +
      {{skill.system.rank}}
      +
      {{skill.system.bonus}}
      +
      + +
      +
    4. + {{/each}} +
    +
    +
    +
    + \ No newline at end of file diff --git a/templates/item/item-condition-sheet.html b/templates/item/item-condition-sheet.html new file mode 100644 index 0000000..f3f5347 --- /dev/null +++ b/templates/item/item-condition-sheet.html @@ -0,0 +1,44 @@ +
    + +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    +
    +
    + +
    + + +
    + +
    +
    +
    +
    + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    +
    +
    diff --git a/templates/item/item-crew-sheet.html b/templates/item/item-crew-sheet.html new file mode 100644 index 0000000..e611ddf --- /dev/null +++ b/templates/item/item-crew-sheet.html @@ -0,0 +1,50 @@ +
    +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    + +
    +
    + +
    + + +
    + +
    +
    +
    +
    + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    + + {{!-- Attributes Tab --}} +
    + {{!-- As you add new fields, add them in here! --}} +
    +
    +
    diff --git a/templates/item/item-drug-sheet.html b/templates/item/item-drug-sheet.html new file mode 100644 index 0000000..bb9b9cd --- /dev/null +++ b/templates/item/item-drug-sheet.html @@ -0,0 +1,58 @@ +
    +
    +
    + +
    +
    {{ localize 'Mosh.Name' }}
    +
    + +
    +
    +
    +
    +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + +
    + +
    +
    +
    + {{#if drugDefinition}} +
    +
    + +
    {{drugDefinition.category}} | Rating {{drugDefinition.rating}} | Addiction {{drugDefinition.addiction.threshold}}
    +
    {{drugDefinition.activeSummary}}
    + {{#if drugDefinition.withdrawalSummary}}
    {{drugDefinition.withdrawalSummary}}
    {{/if}} +
    + {{/if}} +
    + +
    +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    +
    +
    diff --git a/templates/item/item-item-sheet.html b/templates/item/item-item-sheet.html new file mode 100644 index 0000000..0e45661 --- /dev/null +++ b/templates/item/item-item-sheet.html @@ -0,0 +1,61 @@ +
    +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    +
    +
    + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    +
    +
    + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    +
    +
    diff --git a/templates/item/item-module-sheet.html b/templates/item/item-module-sheet.html new file mode 100644 index 0000000..3664fc5 --- /dev/null +++ b/templates/item/item-module-sheet.html @@ -0,0 +1,93 @@ +
    + + +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    +
    +
    + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    +
    +
    + +
    + + +
    + +
    +
    +
    + + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    +
    +
    diff --git a/templates/item/item-persTrait-sheet.html b/templates/item/item-persTrait-sheet.html new file mode 100644 index 0000000..9aa0449 --- /dev/null +++ b/templates/item/item-persTrait-sheet.html @@ -0,0 +1,60 @@ +
    +
    + +
    +
    + + +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    + + + +
    +
    +
    + +
    + + +
    +
    +
    + + +
    +
    + +
    +
    + + +
    +
    +
    +
    diff --git a/templates/item/item-repair-sheet.html b/templates/item/item-repair-sheet.html new file mode 100644 index 0000000..b8dd16a --- /dev/null +++ b/templates/item/item-repair-sheet.html @@ -0,0 +1,53 @@ +
    +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    + +
    +
    + +
    + + +
    + +
    +
    + + +
    + + +
    + +
    +
    + + + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    +
    +
    diff --git a/templates/item/item-skill-sheet.html b/templates/item/item-skill-sheet.html new file mode 100644 index 0000000..42a8083 --- /dev/null +++ b/templates/item/item-skill-sheet.html @@ -0,0 +1,84 @@ +
    + +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    + +
    +
    +
    + +
    + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    +
    + +
    + + + {{!-- Sheet Tab Navigation --}} + + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    + + {{!-- Skills Prerequisite Tab --}} +
    + + +
      +
    1. +
      +
      {{ localize 'Mosh.SkillName' }}
      +
      {{ localize 'Mosh.SkillRank' }}
      +
      {{ localize 'Mosh.SkillBonus' }}
      +
      +
      +
    2. + {{#each system.prerequisite_object as |skill id|}} +
    3. +
      +
      {{skill.name}}
      +
      {{skill.system.rank}}
      +
      {{skill.system.bonus}}
      +
      + +
      +
    4. + {{/each}} +
    +
    +
    +
    diff --git a/templates/item/item-weapon-sheet.html b/templates/item/item-weapon-sheet.html new file mode 100644 index 0000000..543bf97 --- /dev/null +++ b/templates/item/item-weapon-sheet.html @@ -0,0 +1,279 @@ +
    + + +
    +
    + + + + +
    +
    {{ localize 'Mosh.Name' }}
    +
    +
    +
    +
    +
    +
    + +
    + + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    +
    + + +
    + {{#if system.settings.firstEdition}} + +
    + + +
    + {{/if}} + + +
    + + +
    + +
    +
    +
    + + +
    + +
    + + +
    + +
    +
    + + +
    + + +
    +
    + + +
    + +
    + {{#if system.settings.firstEdition}} + + + + + {{/if}} +
    + +
    + + +
    + + +
    + + +
    + +
    +
    + + +
    + + +
    + +
    +
    + + +
    + + +
    + +
    +
    + + +
    + + +
    + +
    +
    + + +
    + + +
    + +
    +
    + + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    + +
    + + +
    + +
    +
    + +
    + +
    + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + + {{!-- Sheet Tab Navigation --}} + + +
    + + {{!-- Sheet Body --}} +
    + + {{!-- Description Tab --}} +
    + {{editor enriched.description target="system.description" button=true owner=owner editable=true}} +
    + + {{!-- Item Tab --}} +
    +
    + +
    + + +
    + +
    +
    + + + +
    + + +
    + +
    +
    + + +
    + + +
    + +
    +
    + + +
    +
    + +
    +