Compare commits

..

18 Commits

Author SHA1 Message Date
ecb7fc2757 Update for pure v13 release
Some checks failed
Release Creation / build (release) Failing after 48s
2025-05-20 22:25:35 +02:00
1fde7e4d2c Fix CSS for sheets
Some checks failed
Release Creation / build (release) Failing after 47s
2025-05-14 23:53:49 +02:00
b5a0405403 Foundry v13 migration 2025-05-09 22:44:55 +02:00
36279aa6eb Foundry v13 migration
Some checks failed
Release Creation / build (release) Failing after 53s
2025-05-09 22:41:08 +02:00
d5eba47ab6 Enhance appeareance 2025-05-09 22:17:00 +02:00
b21c5ac9bb Add rituals !
Some checks failed
Release Creation / build (release) Failing after 44s
2025-04-25 00:26:28 +02:00
a43bebc63b Add rituals !
Some checks failed
Release Creation / build (release) Failing after 21s
2025-04-24 23:54:52 +02:00
2b418695c4 Actualiser README.md 2025-03-31 16:34:00 +02:00
5dbb168891 Improve release management 2025-03-31 14:31:23 +02:00
009024296c Improve release management
Some checks failed
Release Creation / build (release) Failing after 58s
2025-03-31 14:27:55 +02:00
968c7da5c5 Improve release management 2025-03-31 14:26:08 +02:00
67ff06f953 Add missing eras 2025-03-31 14:19:19 +02:00
24c5c685d0 Sync version 2025-03-30 20:39:03 +02:00
d62b5472fe Sync version 2025-03-30 20:36:41 +02:00
a1ef74a3ad Sync compendiums 2025-03-30 20:35:44 +02:00
ff89b62133 Fix LethalFantasy stuff 2025-02-13 23:23:32 +01:00
b3eb908f05 Add rituals and tomes and creatures
All checks were successful
Release Creation / build (release) Successful in 48s
2025-02-07 18:06:08 +01:00
2ac0f53c4f Add rituals and tomes 2025-02-07 08:34:57 +01:00
96 changed files with 4196 additions and 434 deletions

View File

@ -27,7 +27,7 @@ jobs:
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://www.uberwald.me/gitea/${{gitea.repository}}
manifest: https://www.uberwald.me/gitea/public/${{gitea.repository}}/releases/download/latest/system.json
manifest: https://www.uberwald.me/gitea/public/fvtt-cthulhu-eternal/releases/download/latest/system.json
download: https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-cthulhu-eternal.zip
# Create a zip file with all files required by the module to add to the release
@ -50,3 +50,14 @@ jobs:
./fvtt-cthulhu-eternal.zip
system.json
api_key: '${{secrets.ALLOW_PUSH_RELEASE}}'
- name: Publish to Foundry server
uses: djlechuck/foundryvtt-publish-package-action@v1
with:
token: ${{ secrets.FOUNDRYVTT_RELEASE_TOKEN }}
id: 'fvtt-cthulhu-eternal'
version: ${{github.event.release.tag_name}}
manifest: 'https://www.uberwald.me/gitea/public/fvtt-cthulhu-eternal/releases/download/latest/system.json'
notes: 'https://www.uberwald.me/gitea/${{gitea.repository}}/releases/download/${{github.event.release.tag_name}}/fvtt-cthulhu-eternal.zip'
compatibility-minimum: '12'
compatibility-verified: '12'

View File

@ -1,6 +1,15 @@
<h2><em>Cthulhu Eternal RPG</em> for Foundry Virtual TableTop</h2>
# Cthulhu Eternal RPG for FoundryVTT
<div align="center">
Cthulhu Eternal : https://cthulhueternal.com/
</div>
The system contains :
- Protagonist, Creature and Vehicle sheet
- Arcane, Archetype, Armor, Bond, Gear, Injury, Mental Disorder, Motivation, Ritual, Skill, Tome, Weapon items
- Support for all available eras
- Pre-filled compendium for each era
- Specific look&fell for each era
- And much more !
Discord Contact : LeRatierBretonnien (at Official Foundry Discord of French Foundry Discord)

Binary file not shown.

Binary file not shown.

258
assets/fonts/Skranji.g2n Normal file
View File

@ -0,0 +1,258 @@
GLYPHID 0 PSNAME .notdef
GLYPHID 146 PSNAME Eth UNICODE 00D0
GLYPHID 178 PSNAME eth UNICODE 00F0
GLYPHID 206 PSNAME Lslash UNICODE 0141
GLYPHID 207 PSNAME lslash UNICODE 0142
GLYPHID 217 PSNAME Scaron UNICODE 0160
GLYPHID 218 PSNAME scaron UNICODE 0161
GLYPHID 159 PSNAME Yacute UNICODE 00DD
GLYPHID 191 PSNAME yacute UNICODE 00FD
GLYPHID 160 PSNAME Thorn UNICODE 00DE
GLYPHID 192 PSNAME thorn UNICODE 00FE
GLYPHID 220 PSNAME Zcaron UNICODE 017D
GLYPHID 221 PSNAME zcaron UNICODE 017E
GLYPHID 127 PSNAME onehalf UNICODE 00BD
GLYPHID 126 PSNAME onequarter UNICODE 00BC
GLYPHID 123 PSNAME onesuperior UNICODE 00B9
GLYPHID 128 PSNAME threequarters UNICODE 00BE
GLYPHID 117 PSNAME threesuperior UNICODE 00B3
GLYPHID 116 PSNAME twosuperior UNICODE 00B2
GLYPHID 104 PSNAME brokenbar UNICODE 00A6
GLYPHID 251 PSNAME minus UNICODE 2212
GLYPHID 153 PSNAME multiply UNICODE 00D7
GLYPHID 3 PSNAME space UNICODE 0020
GLYPHID 4 PSNAME exclam UNICODE 0021
GLYPHID 5 PSNAME quotedbl UNICODE 0022
GLYPHID 6 PSNAME numbersign UNICODE 0023
GLYPHID 7 PSNAME dollar UNICODE 0024
GLYPHID 8 PSNAME percent UNICODE 0025
GLYPHID 9 PSNAME ampersand UNICODE 0026
GLYPHID 10 PSNAME quotesingle UNICODE 0027
GLYPHID 11 PSNAME parenleft UNICODE 0028
GLYPHID 12 PSNAME parenright UNICODE 0029
GLYPHID 13 PSNAME asterisk UNICODE 002A
GLYPHID 14 PSNAME plus UNICODE 002B
GLYPHID 15 PSNAME comma UNICODE 002C
GLYPHID 16 PSNAME hyphen UNICODE 002D
GLYPHID 17 PSNAME period UNICODE 002E
GLYPHID 18 PSNAME slash UNICODE 002F
GLYPHID 19 PSNAME zero UNICODE 0030
GLYPHID 20 PSNAME one UNICODE 0031
GLYPHID 21 PSNAME two UNICODE 0032
GLYPHID 22 PSNAME three UNICODE 0033
GLYPHID 23 PSNAME four UNICODE 0034
GLYPHID 24 PSNAME five UNICODE 0035
GLYPHID 25 PSNAME six UNICODE 0036
GLYPHID 26 PSNAME seven UNICODE 0037
GLYPHID 27 PSNAME eight UNICODE 0038
GLYPHID 28 PSNAME nine UNICODE 0039
GLYPHID 29 PSNAME colon UNICODE 003A
GLYPHID 30 PSNAME semicolon UNICODE 003B
GLYPHID 31 PSNAME less UNICODE 003C
GLYPHID 32 PSNAME equal UNICODE 003D
GLYPHID 33 PSNAME greater UNICODE 003E
GLYPHID 34 PSNAME question UNICODE 003F
GLYPHID 35 PSNAME at UNICODE 0040
GLYPHID 36 PSNAME A UNICODE 0041
GLYPHID 37 PSNAME B UNICODE 0042
GLYPHID 38 PSNAME C UNICODE 0043
GLYPHID 39 PSNAME D UNICODE 0044
GLYPHID 40 PSNAME E UNICODE 0045
GLYPHID 41 PSNAME F UNICODE 0046
GLYPHID 42 PSNAME G UNICODE 0047
GLYPHID 43 PSNAME H UNICODE 0048
GLYPHID 44 PSNAME I UNICODE 0049
GLYPHID 45 PSNAME J UNICODE 004A
GLYPHID 46 PSNAME K UNICODE 004B
GLYPHID 47 PSNAME L UNICODE 004C
GLYPHID 48 PSNAME M UNICODE 004D
GLYPHID 49 PSNAME N UNICODE 004E
GLYPHID 50 PSNAME O UNICODE 004F
GLYPHID 51 PSNAME P UNICODE 0050
GLYPHID 52 PSNAME Q UNICODE 0051
GLYPHID 53 PSNAME R UNICODE 0052
GLYPHID 54 PSNAME S UNICODE 0053
GLYPHID 55 PSNAME T UNICODE 0054
GLYPHID 56 PSNAME U UNICODE 0055
GLYPHID 57 PSNAME V UNICODE 0056
GLYPHID 58 PSNAME W UNICODE 0057
GLYPHID 59 PSNAME X UNICODE 0058
GLYPHID 60 PSNAME Y UNICODE 0059
GLYPHID 61 PSNAME Z UNICODE 005A
GLYPHID 62 PSNAME bracketleft UNICODE 005B
GLYPHID 63 PSNAME backslash UNICODE 005C
GLYPHID 64 PSNAME bracketright UNICODE 005D
GLYPHID 65 PSNAME asciicircum UNICODE 005E
GLYPHID 66 PSNAME underscore UNICODE 005F
GLYPHID 67 PSNAME grave UNICODE 0060
GLYPHID 68 PSNAME a UNICODE 0061
GLYPHID 69 PSNAME b UNICODE 0062
GLYPHID 70 PSNAME c UNICODE 0063
GLYPHID 71 PSNAME d UNICODE 0064
GLYPHID 72 PSNAME e UNICODE 0065
GLYPHID 73 PSNAME f UNICODE 0066
GLYPHID 74 PSNAME g UNICODE 0067
GLYPHID 75 PSNAME h UNICODE 0068
GLYPHID 76 PSNAME i UNICODE 0069
GLYPHID 77 PSNAME j UNICODE 006A
GLYPHID 78 PSNAME k UNICODE 006B
GLYPHID 79 PSNAME l UNICODE 006C
GLYPHID 80 PSNAME m UNICODE 006D
GLYPHID 81 PSNAME n UNICODE 006E
GLYPHID 82 PSNAME o UNICODE 006F
GLYPHID 83 PSNAME p UNICODE 0070
GLYPHID 84 PSNAME q UNICODE 0071
GLYPHID 85 PSNAME r UNICODE 0072
GLYPHID 86 PSNAME s UNICODE 0073
GLYPHID 87 PSNAME t UNICODE 0074
GLYPHID 88 PSNAME u UNICODE 0075
GLYPHID 89 PSNAME v UNICODE 0076
GLYPHID 90 PSNAME w UNICODE 0077
GLYPHID 91 PSNAME x UNICODE 0078
GLYPHID 92 PSNAME y UNICODE 0079
GLYPHID 93 PSNAME z UNICODE 007A
GLYPHID 94 PSNAME braceleft UNICODE 007B
GLYPHID 95 PSNAME bar UNICODE 007C
GLYPHID 96 PSNAME braceright UNICODE 007D
GLYPHID 97 PSNAME asciitilde UNICODE 007E
GLYPHID 134 PSNAME Adieresis UNICODE 00C4
GLYPHID 135 PSNAME Aring UNICODE 00C5
GLYPHID 137 PSNAME Ccedilla UNICODE 00C7
GLYPHID 139 PSNAME Eacute UNICODE 00C9
GLYPHID 147 PSNAME Ntilde UNICODE 00D1
GLYPHID 152 PSNAME Odieresis UNICODE 00D6
GLYPHID 158 PSNAME Udieresis UNICODE 00DC
GLYPHID 163 PSNAME aacute UNICODE 00E1
GLYPHID 162 PSNAME agrave UNICODE 00E0
GLYPHID 164 PSNAME acircumflex UNICODE 00E2
GLYPHID 166 PSNAME adieresis UNICODE 00E4
GLYPHID 165 PSNAME atilde UNICODE 00E3
GLYPHID 167 PSNAME aring UNICODE 00E5
GLYPHID 169 PSNAME ccedilla UNICODE 00E7
GLYPHID 171 PSNAME eacute UNICODE 00E9
GLYPHID 170 PSNAME egrave UNICODE 00E8
GLYPHID 172 PSNAME ecircumflex UNICODE 00EA
GLYPHID 173 PSNAME edieresis UNICODE 00EB
GLYPHID 175 PSNAME iacute UNICODE 00ED
GLYPHID 174 PSNAME igrave UNICODE 00EC
GLYPHID 176 PSNAME icircumflex UNICODE 00EE
GLYPHID 177 PSNAME idieresis UNICODE 00EF
GLYPHID 179 PSNAME ntilde UNICODE 00F1
GLYPHID 181 PSNAME oacute UNICODE 00F3
GLYPHID 180 PSNAME ograve UNICODE 00F2
GLYPHID 182 PSNAME ocircumflex UNICODE 00F4
GLYPHID 184 PSNAME odieresis UNICODE 00F6
GLYPHID 183 PSNAME otilde UNICODE 00F5
GLYPHID 188 PSNAME uacute UNICODE 00FA
GLYPHID 187 PSNAME ugrave UNICODE 00F9
GLYPHID 189 PSNAME ucircumflex UNICODE 00FB
GLYPHID 190 PSNAME udieresis UNICODE 00FC
GLYPHID 240 PSNAME dagger UNICODE 2020
GLYPHID 114 PSNAME degree UNICODE 00B0
GLYPHID 100 PSNAME cent UNICODE 00A2
GLYPHID 101 PSNAME sterling UNICODE 00A3
GLYPHID 105 PSNAME section UNICODE 00A7
GLYPHID 242 PSNAME bullet UNICODE 2022
GLYPHID 120 PSNAME paragraph UNICODE 00B6
GLYPHID 161 PSNAME germandbls UNICODE 00DF
GLYPHID 112 PSNAME registered UNICODE 00AE
GLYPHID 107 PSNAME copyright UNICODE 00A9
GLYPHID 249 PSNAME trademark UNICODE 2122
GLYPHID 118 PSNAME acute UNICODE 00B4
GLYPHID 106 PSNAME dieresis UNICODE 00A8
GLYPHID 253 PSNAME notequal UNICODE 2260
GLYPHID 136 PSNAME AE UNICODE 00C6
GLYPHID 154 PSNAME Oslash UNICODE 00D8
GLYPHID 115 PSNAME plusminus UNICODE 00B1
GLYPHID 254 PSNAME lessequal UNICODE 2264
GLYPHID 255 PSNAME greaterequal UNICODE 2265
GLYPHID 103 PSNAME yen UNICODE 00A5
GLYPHID 119 PSNAME mu UNICODE 00B5
GLYPHID 250 PSNAME partialdiff UNICODE 2202
GLYPHID 108 PSNAME ordfeminine UNICODE 00AA
GLYPHID 124 PSNAME ordmasculine UNICODE 00BA
GLYPHID 168 PSNAME ae UNICODE 00E6
GLYPHID 186 PSNAME oslash UNICODE 00F8
GLYPHID 129 PSNAME questiondown UNICODE 00BF
GLYPHID 99 PSNAME exclamdown UNICODE 00A1
GLYPHID 110 PSNAME logicalnot UNICODE 00AC
GLYPHID 222 PSNAME florin UNICODE 0192
GLYPHID 252 PSNAME approxequal UNICODE 2248
GLYPHID 109 PSNAME guillemotleft UNICODE 00AB
GLYPHID 125 PSNAME guillemotright UNICODE 00BB
GLYPHID 243 PSNAME ellipsis UNICODE 2026
GLYPHID 98 PSNAME uni00A0 UNICODE 00A0
GLYPHID 130 PSNAME Agrave UNICODE 00C0
GLYPHID 133 PSNAME Atilde UNICODE 00C3
GLYPHID 151 PSNAME Otilde UNICODE 00D5
GLYPHID 210 PSNAME OE UNICODE 0152
GLYPHID 211 PSNAME oe UNICODE 0153
GLYPHID 232 PSNAME endash UNICODE 2013
GLYPHID 233 PSNAME emdash UNICODE 2014
GLYPHID 237 PSNAME quotedblleft UNICODE 201C
GLYPHID 238 PSNAME quotedblright UNICODE 201D
GLYPHID 234 PSNAME quoteleft UNICODE 2018
GLYPHID 235 PSNAME quoteright UNICODE 2019
GLYPHID 185 PSNAME divide UNICODE 00F7
GLYPHID 256 PSNAME lozenge UNICODE 25CA
GLYPHID 193 PSNAME ydieresis UNICODE 00FF
GLYPHID 219 PSNAME Ydieresis UNICODE 0178
GLYPHID 247 PSNAME fraction UNICODE 2044
GLYPHID 248 PSNAME Euro UNICODE 20AC
GLYPHID 245 PSNAME guilsinglleft UNICODE 2039
GLYPHID 246 PSNAME guilsinglright UNICODE 203A
GLYPHID 258 PSNAME fi UNICODE FB01
GLYPHID 259 PSNAME fl UNICODE FB02
GLYPHID 241 PSNAME daggerdbl UNICODE 2021
GLYPHID 121 PSNAME periodcentered UNICODE 00B7
GLYPHID 236 PSNAME quotesinglbase UNICODE 201A
GLYPHID 239 PSNAME quotedblbase UNICODE 201E
GLYPHID 244 PSNAME perthousand UNICODE 2030
GLYPHID 132 PSNAME Acircumflex UNICODE 00C2
GLYPHID 140 PSNAME Ecircumflex UNICODE 00CA
GLYPHID 131 PSNAME Aacute UNICODE 00C1
GLYPHID 141 PSNAME Edieresis UNICODE 00CB
GLYPHID 138 PSNAME Egrave UNICODE 00C8
GLYPHID 143 PSNAME Iacute UNICODE 00CD
GLYPHID 144 PSNAME Icircumflex UNICODE 00CE
GLYPHID 145 PSNAME Idieresis UNICODE 00CF
GLYPHID 142 PSNAME Igrave UNICODE 00CC
GLYPHID 149 PSNAME Oacute UNICODE 00D3
GLYPHID 150 PSNAME Ocircumflex UNICODE 00D4
GLYPHID 148 PSNAME Ograve UNICODE 00D2
GLYPHID 156 PSNAME Uacute UNICODE 00DA
GLYPHID 157 PSNAME Ucircumflex UNICODE 00DB
GLYPHID 155 PSNAME Ugrave UNICODE 00D9
GLYPHID 197 PSNAME dotlessi UNICODE 0131
GLYPHID 224 PSNAME circumflex UNICODE 02C6
GLYPHID 230 PSNAME tilde UNICODE 02DC
GLYPHID 113 PSNAME macron UNICODE 00AF
GLYPHID 226 PSNAME breve UNICODE 02D8
GLYPHID 227 PSNAME dotaccent UNICODE 02D9
GLYPHID 228 PSNAME ring UNICODE 02DA
GLYPHID 122 PSNAME cedilla UNICODE 00B8
GLYPHID 231 PSNAME hungarumlaut UNICODE 02DD
GLYPHID 229 PSNAME ogonek UNICODE 02DB
GLYPHID 225 PSNAME caron UNICODE 02C7
GLYPHID 102 PSNAME currency UNICODE 00A4
GLYPHID 194 PSNAME hbar UNICODE 0127
GLYPHID 223 PSNAME dotlessj UNICODE 0237
GLYPHID 195 PSNAME Itilde UNICODE 0128
GLYPHID 196 PSNAME itilde UNICODE 0129
GLYPHID 198 PSNAME IJ UNICODE 0132
GLYPHID 199 PSNAME ij UNICODE 0133
GLYPHID 200 PSNAME Jcircumflex UNICODE 0134
GLYPHID 201 PSNAME jcircumflex UNICODE 0135
GLYPHID 204 PSNAME Ldot UNICODE 013F
GLYPHID 203 PSNAME kgreenlandic UNICODE 0138
GLYPHID 205 PSNAME ldotaccent UNICODE 0140
GLYPHID 202 PSNAME kcommaaccent UNICODE 0137
GLYPHID 208 PSNAME Nacute UNICODE 0143
GLYPHID 209 PSNAME nacute UNICODE 0144
GLYPHID 212 PSNAME Racute UNICODE 0154
GLYPHID 213 PSNAME Rcommaaccent UNICODE 0156
GLYPHID 214 PSNAME rcommaaccent UNICODE 0157
GLYPHID 215 PSNAME Rcaron UNICODE 0158
GLYPHID 216 PSNAME rcaron UNICODE 0159
GLYPHID 257 PSNAME commaaccent UNICODE F6C3
GLYPHID 111 PSNAME sfthyphen UNICODE 00AD

BIN
assets/fonts/Skranji.ttf Normal file

Binary file not shown.

BIN
assets/fonts/Skranji.woff Normal file

Binary file not shown.

BIN
assets/fonts/Skranji.woff2 Normal file

Binary file not shown.

View File

@ -0,0 +1 @@
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(255, 255, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="15" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" style="" transform="translate(0,0)"><path d="M245.813 23.188c-1.228-.006-2.455.027-3.657.093-10.103.56-19.646 3.682-30.156 11.25l20.72 196.782c-8.394 2.127-16.676 4.47-24.814 7.094L137.72 57.812c-7.032-1.706-17.442-.3-27.126 4.626-10.248 5.213-19.034 13.84-22.813 22.937L155.03 261.5c-7.414 4.345-14.59 9.137-21.5 14.47l-74.343-94.25c-16.34.698-34.965 14.455-37.562 32.655C28.89 222.693 93.978 297.77 126 357.405c10.3 19.184 29.543 50.725 39.188 70.064 5.83 11.693 16.004 24.238 27.843 32.342 11.84 8.104 24.7 11.82 37.907 8.282l112.907-30.22c5.493-1.47 9.196-5.39 13.22-11.937 4.02-6.545 7.535-15.137 12.905-23 20.61-30.185 50.432-76.085 115.186-112.062-2.696-15.053-7.405-24.57-12.72-29.563-6.03-5.667-13.198-7.372-23.686-5.843-18.062 2.63-43.498 17.063-69.594 36.874-1.68 1.39-3.318 2.802-4.937 4.22l-7-61.252 42.5-155.718c-4.478-7.355-13.806-13.258-24.845-15.97-10.874-2.67-22.506-1.698-30.28 1.595l-38.75 149.874c-9.365 1.58-18.732 3.17-28.064 4.812L273.69 27.5c-10.057-2.52-19.284-4.272-27.875-4.313zM234.343 255l30.157 56.625 54.406-33.906-33.78 54.186L341.562 362l-64.157-2.188 2.188 64.032-30.03-56.344-54.283 33.813 33.97-54.438-56.53-30.125 63.78 2.156L234.344 255z" fill="#a7de9a" fill-opacity="1" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@ -0,0 +1 @@
<svg style="height: 512px; width: 512px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><defs><filter id="shadow-1" height="300%" width="300%" x="-100%" y="-100%"><feFlood flood-color="rgba(255, 255, 255, 1)" result="flood"></feFlood><feComposite in="flood" in2="SourceGraphic" operator="atop" result="composite"></feComposite><feGaussianBlur in="composite" stdDeviation="15" result="blur"></feGaussianBlur><feOffset dx="0" dy="0" result="offset"></feOffset><feComposite in="SourceGraphic" in2="offset" operator="over"></feComposite></filter></defs><g class="" style="" transform="translate(0,0)"><path d="M102.5 26.03l90.03 345.75 289.22 23.25-90.063-345.75L102.5 26.03zm-18.906 1.564c-30.466 11.873-55.68 53.098-49.75 75.312l3.25 11.78c.667-1.76 1.36-3.522 2.093-5.28C49.097 85.7 65.748 62.64 89.564 50.5l-5.97-22.906zm10.844 41.593c-16.657 10.012-29.92 28.077-38 47.407-5.247 12.55-8.038 25.63-8.75 36.53L112.5 388.407c.294-.55.572-1.106.875-1.656 10.603-19.252 27.823-37.695 51.125-48.47L94.437 69.19zm74.874 287.594c-17.677 9.078-31.145 23.717-39.562 39-4.464 8.107-7.27 16.364-8.688 23.75l11.688 42.408 1.625.125c-3.84-27.548 11.352-60.504 41.25-81.094l-6.313-24.19zm26.344 34c-32.567 17.27-46.51 52.44-41.844 72.94l289.844 24.5c-5.34-7.79-8.673-17.947-8.594-28.5l-22.406-9L459 443.436l-13.5-12.875c5.604-6.917 13.707-13.05 24.813-17.687L195.656 390.78z" fill="#a7de9a" fill-opacity="1" filter="url(#shadow-1)"></path></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

13
changelog.md Normal file
View File

@ -0,0 +1,13 @@
# 13.0.0
- Foundry v13 support
- New font for medieval era
# 12.0.12
- Add missing skills for WW1, WW2, future and post-apocalyptic
- Fix packaging
# 12.0.11
- Initial release

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@ import * as applications from "./module/applications/_module.mjs"
import { handleSocketEvent } from "./module/socket.mjs"
import CthulhuEternalUtils from "./module/utils.mjs"
export class ClassCounter{static printHello(){console.log("Hello")}static sendJsonPostRequest(e,s){const t={method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(s)};return fetch(e,t).then((e=>{if(!e.ok)throw new Error("La requête a échoué avec le statut "+e.status);return e.json()})).catch((e=>{throw console.error("Erreur envoi de la requête:",e),e}))}static registerUsageCount(e=game.system.id,s={}){if(game.user.isGM){game.settings.register(e,"world-key",{name:"Unique world key",scope:"world",config:!1,default:"",type:String});let t=game.settings.get(e,"world-key");null!=t&&""!=t&&"NONE"!=t&&"none"!=t.toLowerCase()||(t=foundry.utils.randomID(32),game.settings.set(e,"world-key",t));let a={name:e,system:game.system.id,worldKey:t,version:game.system.version,language:game.settings.get("core","language"),remoteAddr:game.data.addresses.remote,nbInstalledModules:game.modules.size,nbActiveModules:game.modules.filter((e=>e.active)).length,nbPacks:game.world.packs.size,nbUsers:game.users.size,nbScenes:game.scenes.size,nbActors:game.actors.size,nbPlaylist:game.playlists.size,nbTables:game.tables.size,nbCards:game.cards.size,optionsData:s,foundryVersion:`${game.release.generation}.${game.release.build}`};this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php",a)}}}
export class ClassCounter { static printHello() { console.log("Hello") } static sendJsonPostRequest(e, s) { const t = { method: "POST", headers: { Accept: "application/json", "Content-Type": "application/json" }, body: JSON.stringify(s) }; return fetch(e, t).then((e => { if (!e.ok) throw new Error("La requête a échoué avec le statut " + e.status); return e.json() })).catch((e => { throw console.error("Erreur envoi de la requête:", e), e })) } static registerUsageCount(e = game.system.id, s = {}) { if (game.user.isGM) { game.settings.register(e, "world-key", { name: "Unique world key", scope: "world", config: !1, default: "", type: String }); let t = game.settings.get(e, "world-key"); null != t && "" != t && "NONE" != t && "none" != t.toLowerCase() || (t = foundry.utils.randomID(32), game.settings.set(e, "world-key", t)); let a = { name: e, system: game.system.id, worldKey: t, version: game.system.version, language: game.settings.get("core", "language"), remoteAddr: game.data.addresses.remote, nbInstalledModules: game.modules.size, nbActiveModules: game.modules.filter((e => e.active)).length, nbPacks: game.world.packs.size, nbUsers: game.users.size, nbScenes: game.scenes.size, nbActors: game.actors.size, nbPlaylist: game.playlists.size, nbTables: game.tables.size, nbCards: game.cards.size, optionsData: s, foundryVersion: `${game.release.generation}.${game.release.build}` }; this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php", a) } } }
Hooks.once("init", function () {
console.info("Cthulhu Eternal RPG | Initializing System")
@ -33,7 +33,8 @@ Hooks.once("init", function () {
CONFIG.Actor.documentClass = documents.CthulhuEternalActor
CONFIG.Actor.dataModels = {
protagonist: models.CthulhuEternalProtagonist,
vehicle: models.CthulhuEternalVehicle
vehicle: models.CthulhuEternalVehicle,
creature: models.CthulhuEternalCreature
}
CONFIG.Item.documentClass = documents.CthulhuEternalItem
@ -47,25 +48,30 @@ Hooks.once("init", function () {
bond: models.CthulhuEternalBond,
arcane: models.CthulhuEternalArcane,
gear: models.CthulhuEternalGear,
archetype: models.CthulhuEternalArchetype
archetype: models.CthulhuEternalArchetype,
ritual: models.CthulhuEternalRitual,
tome: models.CthulhuEternalTome
}
// Register sheet application classes
Actors.unregisterSheet("core", ActorSheet)
Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalProtagonistSheet, { types: ["protagonist"], makeDefault: true })
Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalVehicleSheet, { types: ["vehicle"], makeDefault: true })
foundry.documents.collections.Actors.unregisterSheet("core", foundry.appv1.sheets.ActorSheet)
foundry.documents.collections.Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalProtagonistSheet, { types: ["protagonist"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalVehicleSheet, { types: ["vehicle"], makeDefault: true })
foundry.documents.collections.Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalCreatureSheet, { types: ["creature"], makeDefault: true })
Items.unregisterSheet("core", ItemSheet)
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalSkillSheet, { types: ["skill"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalInjurySheet, { types: ["injury"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalMotivationSheet, { types: ["motivation"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalMentalDisorderSheet, { types: ["mentaldisorder"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalWeaponSheet, { types: ["weapon"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArcaneSheet, { types: ["arcane"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArmorSheet, { types: ["armor"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalBondSheet, { types: ["bond"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalGearSheet, { types: ["gear"], makeDefault: true })
Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArchetypeSheet, { types: ["archetype"], makeDefault: true })
foundry.documents.collections.Items.unregisterSheet("core", foundry.appv1.sheets.ItemSheet)
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalSkillSheet, { types: ["skill"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalInjurySheet, { types: ["injury"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalMotivationSheet, { types: ["motivation"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalMentalDisorderSheet, { types: ["mentaldisorder"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalWeaponSheet, { types: ["weapon"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArcaneSheet, { types: ["arcane"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArmorSheet, { types: ["armor"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalBondSheet, { types: ["bond"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalGearSheet, { types: ["gear"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalArchetypeSheet, { types: ["archetype"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalRitualSheet, { types: ["ritual"], makeDefault: true })
foundry.documents.collections.Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalTomeSheet, { types: ["tome"], makeDefault: true })
// Other Document Configuration
CONFIG.ChatMessage.documentClass = documents.CthulhuEternalChatMessage
@ -91,6 +97,7 @@ Hooks.once("init", function () {
console.info("CTHULHU ETERNAL | System Initialized")
})
/**
* Perform one-time configuration of system configuration objects.
*/
@ -113,21 +120,21 @@ Hooks.once("ready", function () {
})
Hooks.on("renderChatMessage", (message, html, data) => {
Hooks.on("renderChatMessageHTML", (message, html, data) => {
// Affichage des boutons de jet de dés uniquement pour les joueurs
if (message.author.id === game.user.id) {
html.find(".nudge-roll").each((i, btn) => {
$(html).find(".nudge-roll").each((i, btn) => {
btn.style.display = "inline"
})
html.find(".nudge-roll").click((event) => {
CthulhuEternalUtils.nudgeRoll(message)
$(html).find(".nudge-roll").click((event) => {
CthulhuEternalUtils.nudgeRoll(message)
})
}
})
// Dice-so-nice Ready
Hooks.once("diceSoNiceReady", (dice3d) => {
configureDiceSoNice(dice3d)
//configureDiceSoNice(dice3d)
})
/**

View File

@ -2,7 +2,8 @@
"TYPES": {
"Actor": {
"protagonist": "Protagonist",
"vehicle": "Vehicle"
"vehicle": "Vehicle",
"creature": "Creature"
},
"Item": {
"skill": "Skill",
@ -14,7 +15,9 @@
"mentaldisorder": "Mental Disorder",
"bond": "Bond" ,
"arcane": "Arcane",
"archetype": "Archetype"
"archetype": "Archetype",
"ritual": "Ritual",
"tome": "Tome"
}
},
"CTHULHUETERNAL": {
@ -112,6 +115,83 @@
}
}
},
"Creature": {
"FIELDS": {
"damageBonus": {
"label": "Dmg.Bonus"
},
"resources": {
"permanentRating": {
"label": "Permanent Rating"
},
"hand": {
"label": "Hand"
},
"stowed": {
"label": "Stowed"
},
"storage": {
"label": "Storage"
}
},
"biodata": {
"feature": {
"label": "Feature"
},
"adaptedToViolence": {
"label": "Adapted to violence"
},
"adaptedToHelplessness": {
"label": "Adapted to helplessness"
},
"harshness": {
"label": "Harshness"
},
"age": {
"label": "Age"
},
"gender": {
"label": "Gender"
},
"hair": {
"label": "Hair"
},
"eyes": {
"label": "Eyes"
},
"height": {
"label": "Height"
},
"home": {
"label": "Home"
},
"birthplace": {
"label": "Birthplace"
},
"label": "Biodata"
},
"characteristics:": {
"str": {
"label": "Strength"
},
"dex": {
"label": "Dexterity"
},
"int": {
"label": "Intelligence"
},
"pow": {
"label": "Power"
},
"con": {
"label": "Constitution"
},
"char": {
"label": "Charisma"
}
}
}
},
"Insanity": {
"None": "None",
"Flee": "Flee",
@ -132,7 +212,7 @@
},
"settings": {
"label": "Settings era"
},
},
"diceEvolved": {
"label": "Can increase on failure"
},
@ -185,7 +265,19 @@
"submachinegun": "Submachinegun",
"riflecarabine": "Rifle/Carabine"
},
"SelectiveFire": {
"shortburst": "Short Burst",
"longburst": "Long Burst",
"shortspray": "Short Spray",
"longspray": "Long Spray"
},
"FIELDS": {
"hasDirectSkill": {
"label": "Has direct skill"
},
"directSkillValue": {
"label": "Direct skill value"
},
"state": {
"label": "State"
},
@ -198,6 +290,12 @@
"weaponSubtype": {
"label": "Firearm Subtype"
},
"hasSelectiveFire": {
"label": "Has selective fire"
},
"applyDamageBonus": {
"label": "Add damage bonus"
},
"damage": {
"label": "Damage"
},
@ -309,7 +407,7 @@
"FIELDS": {
"settings": {
"label": "Settings era"
},
},
"value": {
"label": "Value"
},
@ -327,7 +425,80 @@
"harsh": "Harsh",
"veryHarsh": "Very Harsh"
},
"Tome": {
"FIELDS": {
"language": {
"label": "Language"
},
"settings": {
"label": "Settings"
},
"studyTime": {
"label": "Study Time"
},
"sanLoss": {
"label": "SAN Loss"
},
"unnaturalSkill": {
"label": "Unnatural Skill"
},
"rituals": {
"label": "Rituals"
},
"minimumEra": {
"label": "Minimum Era"
},
"otherBenefits": {
"label": "Other Benefits"
},
"creationDate": {
"label": "Creation Date"
},
"description": {
"label": "Description"
}
},
"Label": {
"tomeDetails": "Tome Details"
},
"Button": {
"addRitual": "Add Ritual"
}
},
"Ritual": {
"Simple": "Simple",
"Complex": "Complex",
"Elaborate": "Elaborate",
"Difficult": "Difficult",
"FIELDS": {
"ritualType": {
"label": "Type"
},
"studyTime": {
"label": "Study time"
},
"studySAN": {
"label": "Study SAN"
},
"activationTime": {
"label": "Activation time"
},
"activationSAN": {
"label": "Activation SAN"
},
"activationWP": {
"label": "Activation WP"
},
"description": {
"label": "Description"
}
}
},
"Label": {
"creature": "Creature",
"Rituals": "Rituals",
"Tomes": "Tomes",
"otherBenefits": "Other Benefits",
"Unarmed": "Unarmed",
"Cured": "Cured",
"Uncured": "Uncured",
@ -371,7 +542,7 @@
"intShort": "INT",
"powShort": "POW",
"conShort": "CON",
"chaShort": "CHA",
"chaShort": "CHA",
"strLong": "Strength",
"dexLong": "Dexterity",
"intLong": "Intelligence",
@ -433,7 +604,9 @@
"newGear": "New Gear",
"newArcane": "New Arcane",
"newArchetype": "New Archetype",
"newSkill": "New Skill"
"newSkill": "New Skill",
"newTome": "New Tome",
"newRitual": "New Ritual"
},
"ChatMessage": {
"exhausted": "Your protagonist is exhausted. He loses [[/r 1d6]] Willpower Points."

View File

@ -9,4 +9,7 @@ export { default as CthulhuEternalMentalDisorderSheet } from "./sheets/mentaldis
export { default as CthulhuEternalGearSheet } from "./sheets/gear-sheet.mjs"
export { default as CthulhuEternalMotivationSheet } from "./sheets/motivation-sheet.mjs"
export { default as CthulhuEternalArchetypeSheet } from "./sheets/archetype-sheet.mjs"
export { default as CthulhuEternalRitualSheet } from "./sheets/ritual-sheet.mjs"
export { default as CthulhuEternalVehicleSheet } from "./sheets/vehicle-sheet.mjs"
export { default as CthulhuEternalCreatureSheet } from "./sheets/creature-sheet.mjs"
export { default as CthulhuEternalTomeSheet } from "./sheets/tome-sheet.mjs"

View File

@ -0,0 +1,294 @@
// System Module Imports
import { Utils } from './utils.js'
import { SYSTEM } from "../../config/system.mjs"
export let ActionHandler = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Extends Token Action HUD Core's ActionHandler class and builds system-defined actions for the HUD
*/
ActionHandler = class ActionHandler extends coreModule.api.ActionHandler {
/**
* Build system actions
* Called by Token Action HUD Core
* @override
* @param {array} groupIds
*/
async buildSystemActions(groupIds) {
// Set actor and token variables
this.actors = (!this.actor) ? this._getActors() : [this.actor]
this.actorType = this.actor?.type
// Set items variable
if (this.actor) {
let items = this.actor.items
items = coreModule.api.Utils.sortItemsByName(items)
this.items = items
}
if (this.actorType !== 'vehicle') {
this.#buildCharacterActions()
} else if (!this.actor) {
this.#buildMultipleTokenActions()
}
}
/**
* Build character actions
* @private
*/
#buildCharacterActions() {
this.buildAttributes()
this.buildOther()
this.buildLuck()
this.buildSkills()
this.buildEquipment()
}
#showValue() {
return game.settings.get('token-action-hud-core', 'tooltips') === 'none'
}
async buildAttributes() {
const actions = []
for (const key in this.actor.system.characteristics) {
const encodedValue = [coreModule.api.Utils.i18n('attributes'), key].join(this.delimiter)
const tooltip = {
content: String(this.actor.system.characteristics[key].value * 5),
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.' + key),
id: key,
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue
})
}
await this.addActions(actions, {
id: 'attributes',
type: 'system'
})
}
async buildLuck() {
const actions = []
const tooltip = {
content: '50',
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Luck'),
id: 'luck',
info1: this.#showValue() ? { text: '50' } : null,
tooltip,
encodedValue: ['attributes', 'luck'].join(this.delimiter)
})
await this.addActions(actions, { id: 'luck', type: 'system' })
}
async buildOther() {
if (typeof this.actor.system.sanity.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_sanity',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'),
type: 'system'
}
this.addGroup(groupData, { id: 'other', type: 'system' }, true)
const tooltip = {
content: String(this.actor.system.san.value + '/' + this.actor.system.san.max),
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.SAN'),
id: 'sanity',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['attributes', 'sanity'].join(this.delimiter)
},
{
name: '+',
id: 'sanity_add',
encodedValue: ['attributes', 'sanity_add'].join(this.delimiter)
},
{
name: '-',
id: 'sanity_subtract',
encodedValue: ['attributes', 'sanity_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_sanity', type: 'system' })
}
if (typeof this.actor.system.hp.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_health',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'),
type: 'system'
}
this.addGroup(groupData, { id: 'other', type: 'system' }, true)
const tooltip = {
content: String(this.actor.system.hp.value + '/' + this.actor.system.hp.max),
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.HP'),
id: 'health',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['attributes', 'health'].join(this.delimiter)
},
{
name: '+',
id: 'health_add',
encodedValue: ['attributes', 'health_add'].join(this.delimiter)
},
{
name: '-',
id: 'health_subtract',
encodedValue: ['attributes', 'health_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_health', type: 'system' })
}
if (typeof this.actor.system.wp.value !== 'undefined') {
const actions = []
const groupData = {
id: 'other_wp',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.WP'),
type: 'system'
}
this.addGroup(groupData, { id: 'other', type: 'system' }, true)
const tooltip = {
content: String(this.actor.system.wp.value + '/' + this.actor.system.wp.max),
class: 'tah-system-tooltip',
direction: 'LEFT'
}
actions.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.WP'),
id: 'wp',
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['attributes', 'wp'].join(this.delimiter)
},
{
name: '+',
id: 'wp_add',
encodedValue: ['attributes', 'wp_add'].join(this.delimiter)
},
{
name: '-',
id: 'wp_subtract',
encodedValue: ['attributes', 'wp_subtract'].join(this.delimiter)
})
await this.addActions(actions, { id: 'other_wp', type: 'system' })
}
}
async buildSkills() {
const actions = []
let actorSkills = this.actor.items.filter(item => item.type === 'skill')
for (const skill in actorSkills) {
if (skill.system.computeScore() > 0) {
const tooltip = {
content: String(skill.skill.system.computeScore()),
direction: 'LEFT'
}
actions.push({
name: skill.name,
id: skill.id,
info1: this.#showValue() ? { text: tooltip.content } : null,
tooltip,
encodedValue: ['skills', s].join(this.delimiter)
})
}
}
await this.addActions(actions, { id: 'skills', type: 'system' })
}
async buildEquipment() {
let weapons = this.actor.items.filter(item => item.type === 'weapon')
let skills = this.actor.items.filter(item => item.type === 'skill')
for (const item of weapons) {
// Push the weapon name as a new group
const groupData = {
id: 'weapons_' + item._id,
name: item.name,
type: 'system'
}
if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) {
continue
}
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
let skill = skills.find(skill => skill.name.toLowerCase() === skillName.toLowerCase())
this.addGroup(groupData, { id: 'weapons', type: 'system' }, true)
if (item.type === 'weapon') {
const weapons = []
const tooltip = {
content: String(skill.system.computeScore()),
direction: 'LEFT'
}
weapons.push({
name: skill.name,
id: skill._id,
info1: this.#showValue() ? { text: tooltip.content } : null,
encodedValue: ['weapons', item._id].join(this.delimiter),
tooltip
})
const damageTooltip = {
content: String(item.system.damage),
direction: 'LEFT'
}
if (item.system.damage !== '') {
weapons.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Damage'),
id: item._id,
info1: this.#showValue() ? { text: damageTooltip.content } : null,
encodedValue: ['damage', item._id].join(this.delimiter),
tooltip: damageTooltip
})
}
if (item.system.isLethal) {
const lethalityTooltip = {
content: String(item.system.lethality),
direction: 'LEFT'
}
weapons.push({
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Lethality'),
id: item._id,
info1: this.#showValue() ? { text: lethalityTooltip.content } : null,
encodedValue: ['lethality', item._id].join(this.delimiter),
tooltip: lethalityTooltip
})
}
await this.addActions(weapons, {
id: 'weapons_' + item._id,
type: 'system'
})
}/* else if (item.type === 'ritual') {
rituals.push({
name: item.name,
id: item._id,
encodedValue: ['rituals', item.name].join(this.delimiter)
})
} */
/* await this.addActions(rituals, {
id: 'rituals',
type: 'system'
}) */
}
}
/**
* Build multiple token actions
* @private
* @returns {object}
*/
#buildMultipleTokenActions() {
}
}
})

View File

@ -0,0 +1,38 @@
/**
* Module-based constants
*/
export const SYSTEM = {
ID: 'fvtt-cthulhu-eternal'
}
/**
* Core module
*/
export const CORE_MODULE = {
ID: 'token-action-hud-core'
}
/**
* Core module version required by the system module
*/
export const REQUIRED_CORE_MODULE_VERSION = '2.0'
/**
* Action types
*/
export const ACTION_TYPE = {
attributes: 'CTHULHUETERNAL.Label.Characteristics',
skills: 'CTHULHUETERNAL.Label.Skill',
equipment: 'CTHULHUETERNAL.Label.Gear'
}
/**
* Groups
*/
export const GROUP = {
attributes: { id: 'attributes', name: 'CTHULHUETERNAL.Label.Characteristics', type: 'system' },
luck: { id: 'luck', name: 'CTHULHUETERNAL.Label.Luck', type: 'system'},
skills: { id: 'skills', name: 'CTHULHUETERNAL.Label.Skills', type: 'system' },
weapons: { id: 'weapons', name: 'CTHULHUETERNAL.Label.Weapons', type: 'system' },
rituals: { id: 'rituals', name: 'CTHULHUETERNAL.Label.Rituals', type: 'system' }
}

View File

@ -0,0 +1,49 @@
import { GROUP } from './constants.js'
/**
* Default layout and groups
*/
export let DEFAULTS = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
const groups = GROUP
Object.values(groups).forEach(group => {
group.name = coreModule.api.Utils.i18n(group.name)
group.listName = `Group: ${coreModule.api.Utils.i18n(group.listName ?? group.name)}`
})
const groupsArray = Object.values(groups)
DEFAULTS = {
layout: [
{
nestId: 'statistics',
id: 'statistics',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Characteristics'),
groups: [
{ ...groups.attributes, nestId: 'statistics_attributes' },
{ ...groups.other, nestId: 'statistics_other' },
{ ...groups.luck, nestId: 'statistics_luck' }
]
},
{
nestId: 'skills',
id: 'skills',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Skills'),
groups: [
{ ...groups.skills, nestId: 'skills_skills' },
{ ...groups.typedSkills, nestId: 'skills_typed' },
{ ...groups.specialTraining, nestId: 'skills_special' }
]
},
{
nestId: 'equipment',
id: 'equipment',
name: coreModule.api.Utils.i18n('CTHULHUETERNAL.Label.Gear'),
groups: [
{ ...groups.weapons, nestId: 'equipment_weapons' },
{ ...groups.rituals, nestId: 'equipment_rituals' }
]
}
],
groups: groupsArray
}
})

View File

@ -0,0 +1,304 @@
import { SYSTEM } from "../../config/system.mjs"
import CthulhuEternalRoll from '../../documents/roll.mjs'
export let RollHandler = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Extends Token Action HUD Core's RollHandler class and handles action events triggered when an action is clicked
*/
RollHandler = class RollHandler extends coreModule.api.RollHandler {
/**
* Handle action click
* Called by Token Action HUD Core when an action is left or right-clicked
* @override
* @param {object} event The event
* @param {string} encodedValue The encoded value
*/
async handleActionClick (event, encodedValue) {
const [actionTypeId, actionId] = encodedValue.split('|')
const knownCharacters = ['character']
// If single actor is selected
if (this.actor) {
await this.#handleAction(event, this.actor, this.token, actionTypeId, actionId)
return
}
const controlledTokens = canvas.tokens.controlled
.filter((token) => knownCharacters.includes(token.actor?.type))
// If multiple actors are selected
for (const token of controlledTokens) {
const actor = token.actor
await this.#handleAction(event, actor, token, actionTypeId, actionId)
}
}
/**
* Handle action hover
* Called by Token Action HUD Core when an action is hovered on or off
* @override
* @param {object} event The event
* @param {string} encodedValue The encoded value
*/
async handleActionHover (event, encodedValue) {
}
/**
* Handle group click
* Called by Token Action HUD Core when a group is right-clicked while the HUD is locked
* @override
* @param {object} event The event
* @param {object} group The group
*/
async handleGroupClick (event, group) {
}
/**
* Handle action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {object} token The token
* @param {string} actionTypeId The action type id
* @param {string} actionId The actionId
*/
async #handleAction (event, actor, token, actionTypeId, actionId) {
switch (actionTypeId) {
case 'attributes':
await this.#handleAttributesAction(event, actor, actionId)
break
case 'skills':
await this.#handleSkillsAction(event, actor, actionId)
break
case 'weapons':
await this.#handleWeaponsAction(event, actor, actionId)
break
case 'damage':
await this.#handleDamageAction(event, actor, actionId)
break
case 'lethality':
await this.#handleLethalityAction(event, actor, actionId)
break
case 'specialTraining':
await this.#handleSpecialTrainingAction(event, actor, actionId)
break
case 'typedSkills':
await this.#handleCustomTypedAction(event, actor, actionId)
break
/* case 'rituals':
await this.#handleRitualsAction(event, actor, actionId)
break */
case 'utility':
await this.#handleUtilityAction(token, actionId)
break
}
}
/**
* Handle Attribute action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleAttributesAction (event, actor, actionId) {
let rollType
if (actionId === 'wp' || actionId === 'health') return
if (actionId.includes('_add') || actionId.includes('_subtract')) {
const attr = actionId.split('_')[0]
const action = actionId.split('_')[1]
const update = {}
update.system = {}
update.system[attr] = {}
update.system[attr].value = action === 'add' ? this.actor.system[attr].value + 1 : this.actor.system[attr].value - 1
if (update.system[attr].value > this.actor.system[attr].max || update.system[attr].value < this.actor.system[attr].min) return
return await this.actor.update(update)
}
if (actionId === 'sanity') {
rollType = actionId
} else if (actionId === 'luck') {
rollType = actionId
} else {
rollType = 'stat'
}
const options = {
actor: this.actor,
rollType,
key: actionId
}
const roll = new DGPercentileRoll('1D100', {}, options)
return await this.actor.sheet.processRoll(event, roll)
}
/**
* Handle Skill action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleSkillsAction (event, actor, actionId) {
const options = {
actor: this.actor,
rollType: 'skill',
key: actionId
}
const skill = this.actor.system.skills[actionId]
if (!skill) return ui.notifications.warn('Bad skill name in HUD.')
const roll = new DGPercentileRoll('1D100', {}, options)
await this.actor.sheet.processRoll(event, roll)
}
/**
* Handle Typed/Custom skills action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleCustomTypedAction (event, actor, actionId) {
const options = {
actor: this.actor,
rollType: 'skill',
key: actionId
}
const roll = new DGPercentileRoll('1D100', {}, options)
await this.actor.sheet.processRoll(event, roll)
}
/**
* Handle SoecialTraining action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleSpecialTrainingAction (event, actor, actionId) {
const attr = this.actor.system.specialTraining.find(a => a.name === actionId).attribute
let target = 0
if (DG.statistics.includes(attr)) {
target = this.actor.system.statistics[attr].x5
} else if (DG.skills.includes(attr)) {
target = this.actor.system.skills[attr].proficiency
} else {
target = this.actor.system.typedSkills[attr].proficiency
}
const options = {
actor: this.actor,
rollType: 'special-training',
key: attr,
specialTrainingName: actionId,
target
}
const roll = new DGPercentileRoll('1D100', {}, options)
await this.actor.sheet.processRoll(event, roll)
}
/**
* Handle Weapon action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleWeaponsAction (event, actor, actionId) {
const item = this.actor.items.get(actionId)
const options = {
actor: this.actor,
rollType: 'weapon',
key: item.system.skill,
item
}
const roll = new DGPercentileRoll('1D100', {}, options)
await this.actor.sheet.processRoll(event, roll)
}
/**
* Handle Damage action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleDamageAction (event, actor, actionId) {
const item = this.actor.items.get(actionId)
if (item.system.lethality > 0 && event.ctrlKey) {
// Toggle on/off lethality
const isLethal = !item.system.isLethal
await item.update({ 'system.isLethal': isLethal })
} else {
const options = {
actor: this.actor,
rollType: 'damage',
key: item.system.damage,
item
}
const roll = new DGDamageRoll(item.system.damage, {}, options)
await this.actor.sheet.processRoll(event, roll)
}
}
/**
* Handle Lethality action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleLethalityAction (event, actor, actionId) {
const item = await this.actor.items.get(actionId)
if (item.system.damage !== '' && event.ctrlKey) {
const isLethal = !item.system.isLethal
await item.update({ 'system.isLethal': isLethal })
} else {
const options = {
actor: this.actor,
rollType: 'lethality',
key: item.system.lethality,
item
}
const roll = new DGLethalityRoll(item.system.damage, {}, options)
await this.actor.sheet.processRoll(event, roll)
}
}
/**
* Handle Ritual action
* @private
* @param {object} event The event
* @param {object} actor The actor
* @param {string} actionId The action id
*/
async #handleRitualsAction (event, actor, actionId) {
const options = {
actor: this.actor,
rollType: 'ritual',
key: actionId
}
const roll = new DGPercentileRoll('1D100', {}, options)
await this.actor.sheet.processRoll(event, roll)
}
/**
* Handle utility action
* @private
* @param {object} token The token
* @param {string} actionId The action id
*/
async #handleUtilityAction (token, actionId) {
switch (actionId) {
case 'endTurn':
if (game.combat?.current?.tokenId === token.id) {
await game.combat?.nextTurn()
}
break
}
}
}
})

View File

@ -0,0 +1,91 @@
// System Module Imports
import { ActionHandler } from './action-handler.js'
import { RollHandler as Core } from './roll-handler.js'
import { SYSTEM } from './constants.js'
import { DEFAULTS } from './defaults.js'
export let SystemManager = null
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Extends Token Action HUD Core's SystemManager class
*/
SystemManager = class SystemManager extends coreModule.api.SystemManager {
/**
* Returns an instance of the ActionHandler to Token Action HUD Core
* Called by Token Action HUD Core
* @override
* @returns {class} The ActionHandler instance
*/
getActionHandler () {
return new ActionHandler()
}
/**
* Returns a list of roll handlers to Token Action HUD Core
* Used to populate the Roll Handler module setting choices
* Called by Token Action HUD Core
* @override
* @returns {object} The available roll handlers
*/
getAvailableRollHandlers () {
const coreTitle = 'Core Template'
const choices = { core: coreTitle }
return choices
}
/**
* Returns an instance of the RollHandler to Token Action HUD Core
* Called by Token Action HUD Core
* @override
* @param {string} rollHandlerId The roll handler ID
* @returns {class} The RollHandler instance
*/
getRollHandler (rollHandlerId) {
let rollHandler
switch (rollHandlerId) {
case 'core':
default:
rollHandler = new Core()
break
}
return rollHandler
}
/**
* Returns the default layout and groups to Token Action HUD Core
* Called by Token Action HUD Core
* @returns {object} The default layout and groups
*/
async registerDefaults () {
return DEFAULTS
}
/**
* Register Token Action HUD system module settings
* Called by Token Action HUD Core
* @override
* @param {function} coreUpdate The Token Action HUD Core update function
*/
registerSettings (coreUpdate) {
/*systemSettings.register(coreUpdate)*/
}
/**
* Returns styles to Token Action HUD Core
* Called by Token Action HUD Core
* @override
* @returns {object} The TAH system styles
*/
registerStyles () {
return {
template: {
class: 'tah-style-template-style', // The class to add to first DIV element
file: 'tah-template-style', // The file without the css extension
moduleId: SYSTEM.ID, // The module ID
name: 'Template Style' // The name to display in the Token Action HUD Core 'Style' module setting
}
}
}
}
})

View File

@ -0,0 +1,55 @@
import { SYSTEM } from './constants.js'
export let Utils = null
function registerHUD() {
Hooks.on('tokenActionHudCoreApiReady', async () => {
/**
* Return the SystemManager and requiredCoreModuleVersion to Token Action HUD Core
*/
const module = game.system
module.api = {
requiredCoreModuleVersion: "2.0",
SystemManager
}
Hooks.call('tokenActionHudSystemReady', module)
})
}
Hooks.once('tokenActionHudCoreApiReady', async (coreModule) => {
/**
* Utility functions
*/
Utils = class Utils {
/**
* Get setting
* @param {string} key The key
* @param {string=null} defaultValue The default value
* @returns {string} The setting value
*/
static getSetting(key, defaultValue = null) {
let value = defaultValue ?? null
try {
value = game.settings.get(SYSTEM.ID, key)
} catch {
coreModule.api.Logger.debug(`Setting '${key}' not found`)
}
return value
}
/**
* Set setting
* @param {string} key The key
* @param {string} value The value
*/
static async setSetting(key, value) {
try {
value = await game.settings.set(MODULE.ID, key, value)
coreModule.api.Logger.debug(`Setting '${key}' set to '${value}'`)
} catch {
coreModule.api.Logger.debug(`Setting '${key}' not found`)
}
}
}
})

View File

@ -22,7 +22,7 @@ export default class CthulhuEternalArcaneSheet extends CthulhuEternalItemSheet {
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -22,7 +22,7 @@ export default class CthulhuEternalArchetypeSheet extends CthulhuEternalItemShee
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -67,7 +67,7 @@ export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin
actor: this.document,
system: this.document.system,
source: this.document.toObject(),
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isEditable: this.isEditable,
@ -96,11 +96,10 @@ export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin
drop: this._canDragDrop.bind(this),
}
d.callbacks = {
dragstart: this._onDragStart.bind(this),
dragover: this._onDragOver.bind(this),
drop: this._onDrop.bind(this),
}
return new DragDrop(d)
return new foundry.applications.ux.DragDrop.implementation(d)
})
}
@ -133,70 +132,6 @@ export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin
return true //this.isEditable && this.document.isOwner
}
/**
* Callback actions which occur at the beginning of a drag start workflow.
* @param {DragEvent} event The originating DragEvent
* @protected
*/
_onDragStart(event) {
if ("link" in event.target.dataset) return
const el = event.currentTarget.closest('[data-drag="true"]')
const dragType = el.dataset.dragType
let dragData = {}
let target
switch (dragType) {
case "save":
target = event.currentTarget.querySelector("input")
dragData = {
actorId: this.document.id,
type: "roll",
rollType: target.dataset.rollType,
rollTarget: target.dataset.rollTarget,
value: target.value,
}
break
case "resource":
target = event.currentTarget.querySelector("select")
dragData = {
actorId: this.document.id,
type: "roll",
rollType: target.dataset.rollType,
rollTarget: target.dataset.rollTarget,
value: target.value,
}
break
case "damage":
dragData = {
actorId: this.document.id,
type: "rollDamage",
rollType: el.dataset.dragType,
rollTarget: el.dataset.itemId,
}
break
case "attack":
dragData = {
actorId: this.document.id,
type: "rollAttack",
rollValue: el.dataset.rollValue,
rollTarget: el.dataset.rollTarget,
}
break
default:
// Handle other cases or do nothing
break
}
// Extract the data you need
if (!dragData) return
// Set data transfer
event.dataTransfer.setData("text/plain", JSON.stringify(dragData))
}
/**
* Callback actions which occur when a dragged element is over a drop target.
* @param {DragEvent} event The originating DragEvent
@ -205,7 +140,7 @@ export default class CthulhuEternalActorSheet extends HandlebarsApplicationMixin
_onDragOver(event) {}
async _onDropItem(item) {
console.log("Dropped item", item)
console.log("Dropped item", item)
let itemData = item.toObject()
await this.document.createEmbeddedDocuments("Item", [itemData], { renderSheet: false })
}

View File

@ -64,7 +64,7 @@ export default class CthulhuEternalItemSheet extends HandlebarsApplicationMixin(
item: this.document,
system: this.document.system,
source: this.document.toObject(),
enrichedDescription: await TextEditor.enrichHTML(this.document.system.description, { async: true }),
enrichedDescription: await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true }),
isEditMode: this.isEditMode,
isPlayMode: this.isPlayMode,
isEditable: this.isEditable,

View File

@ -22,7 +22,7 @@ export default class CthulhuEternalGiftSheet extends CthulhuEternalItemSheet {
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -0,0 +1,175 @@
import CthulhuEternalActorSheet from "./base-actor-sheet.mjs"
export default class CthulhuEternalCreatureSheet extends CthulhuEternalActorSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["creature"],
position: {
width: 860,
height: 620,
},
window: {
contentClasses: ["creature-content"],
},
actions: {
createArmor: CthulhuEternalCreatureSheet.#onCreateArmor,
createWeapon: CthulhuEternalCreatureSheet.#onCreateWeapon,
createSkill: CthulhuEternalCreatureSheet.#onCreateSkill,
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-cthulhu-eternal/templates/creature-main.hbs",
},
tabs: {
template: "templates/generic/tab-navigation.hbs",
},
skills: {
template: "systems/fvtt-cthulhu-eternal/templates/creature-skills.hbs",
},
biography: {
template: "systems/fvtt-cthulhu-eternal/templates/creature-biography.hbs",
},
}
/** @override */
tabGroups = {
sheet: "skills",
}
/**
* Prepare an array of form header tabs.
* @returns {Record<string, Partial<ApplicationTab>>}
*/
#getTabs() {
const tabs = {
skills: { id: "skills", group: "sheet", icon: "fa-solid fa-shapes", label: "CTHULHUETERNAL.Label.skills" },
biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "CTHULHUETERNAL.Label.biography" },
}
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id
v.cssClass = v.active ? "active" : ""
}
return tabs
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.tabs = this.#getTabs()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedNotes = await TextEditor.enrichHTML(this.document.system.notes, { async: true })
context.tooltipsCharacteristic = {
str: game.i18n.localize("CTHULHUETERNAL.Characteristic.Str"),
dex: game.i18n.localize("CTHULHUETERNAL.Characteristic.Dex"),
con: game.i18n.localize("CTHULHUETERNAL.Characteristic.Con"),
int: game.i18n.localize("CTHULHUETERNAL.Characteristic.Int"),
pow: game.i18n.localize("CTHULHUETERNAL.Characteristic.Pow"),
cha: game.i18n.localize("CTHULHUETERNAL.Characteristic.Cha")
}
return context
}
/** @override */
async _preparePartContext(partId, context) {
const doc = this.document
switch (partId) {
case "main":
break
case "skills":
context.tab = context.tabs.skills
context.skills = doc.itemTypes.skill
context.skills.sort((a, b) => a.name.localeCompare(b.name))
context.weapons = doc.itemTypes.weapon
context.weapons.sort((a, b) => a.name.localeCompare(b.name))
context.armors = doc.itemTypes.armor
context.armors.sort((a, b) => a.name.localeCompare(b.name))
break
case "biography":
context.tab = context.tabs.biography
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.description, { async: true })
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.notes, { async: true })
break
}
return context
}
/**
* Creates a new attack item directly from the sheet and embeds it into the document.
* @param {Event} event The initiating click event.
* @param {HTMLElement} target The current target of the event listener.
*/
static #onCreateWeapon(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newWeapon"), type: "weapon" }])
}
static #onCreateArmor(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newArmor"), type: "armor" }])
}
static #onCreateSkill(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newSkill"), type: "skill" }])
}
/**
* Handles the roll action triggered by user interaction.
*
* @param {PointerEvent} event The event object representing the user interaction.
* @param {HTMLElement} target The target element that triggered the roll.
*
* @returns {Promise<void>} A promise that resolves when the roll action is complete.
*
* @throws {Error} Throws an error if the roll type is not recognized.
*
* @description This method checks the current mode (edit or not) and determines the type of roll
* (save, resource, or damage) based on the target element's data attributes. It retrieves the
* corresponding value from the document's system and performs the roll.
*/
async _onRoll(event, target) {
const rollType = $(event.currentTarget).data("roll-type")
let item
let li
// Debug : console.log(">>>>", event, target, rollType)
// Deprecated : if (this.isEditMode) return
switch (rollType) {
case "char":
let charId = $(event.currentTarget).data("char-id")
item = foundry.utils.duplicate(this.actor.system.characteristics[charId])
item.name = game.i18n.localize(`CTHULHUETERNAL.Label.${charId}Long`)
item.targetScore = item.value * 5
break
case "skill":
li = $(event.currentTarget).parents(".item");
item = this.actor.items.get(li.data("item-id"));
break
case "weapon":
case "damage":
li = $(event.currentTarget).parents(".item");
item = this.actor.items.get(li.data("item-id"));
item.damageBonus = this.actor.system.damageBonus
break
default:
throw new Error(`Unknown roll type ${rollType}`)
}
await this.document.system.roll(rollType, item)
}
async _onDrop(event) {
if (!this.isEditable || !this.isEditMode) return
const data = TextEditor.getDragEventData(event)
// Handle different data types
switch (data.type) {
case "Item":
const item = await fromUuid(data.uuid)
return super._onDropItem(item)
}
}
}

View File

@ -22,7 +22,7 @@ export default class CthulhuEternalInjurySheet extends CthulhuEternalItemSheet {
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -22,7 +22,7 @@ export default class CthulhuEternalMentalDisorderSheet extends CthulhuEternalIte
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}

View File

@ -22,7 +22,7 @@ export default class CthulhuEternalMotivationSheet extends CthulhuEternalItemShe
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}

View File

@ -20,7 +20,9 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
createInjury: CthulhuEternalProtagonistSheet.#onCreateInjury,
createMentalDisorder: CthulhuEternalProtagonistSheet.#onCreateMentalDisorder,
createMotivation: CthulhuEternalProtagonistSheet.#onCreateMotivation,
createSkill: CthulhuEternalProtagonistSheet.#onCreateSkill
createSkill: CthulhuEternalProtagonistSheet.#onCreateSkill,
createRitual: CthulhuEternalProtagonistSheet.#onCreateRitual,
createTome: CthulhuEternalProtagonistSheet.#onCreateTome,
},
}
@ -74,9 +76,9 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
const context = await super._prepareContext()
context.tabs = this.#getTabs()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedNotes = await TextEditor.enrichHTML(this.document.system.notes, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.notes, { async: true })
context.tooltipsCharacteristic = {
str: game.i18n.localize("CTHULHUETERNAL.Characteristic.Str"),
dex: game.i18n.localize("CTHULHUETERNAL.Characteristic.Dex"),
@ -108,6 +110,10 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
context.armors.sort((a, b) => a.name.localeCompare(b.name))
context.gears = doc.itemTypes.gear
context.gears.sort((a, b) => a.name.localeCompare(b.name))
context.rituals = doc.itemTypes.ritual
context.rituals.sort((a, b) => a.name.localeCompare(b.name))
context.tomes = doc.itemTypes.tome
context.tomes.sort((a, b) => a.name.localeCompare(b.name))
break
case "status":
context.tab = context.tabs.status
@ -122,8 +128,8 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
break
case "biography":
context.tab = context.tabs.biography
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
context.enrichedNotes = await TextEditor.enrichHTML(doc.system.notes, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.description, { async: true })
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(doc.system.notes, { async: true })
break
}
return context
@ -137,7 +143,7 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
static #onSetBP(event, target) {
this.document.system.setBP()
}
static #onCreateGear(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newGear"), type: "gear" }])
}
@ -170,6 +176,14 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newSkill"), type: "skill" }])
}
static #onCreateRitual(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newRitual"), type: "ritual" }])
}
static #onCreateTome(event, target) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newTome"), type: "tome" }])
}
/**
* Handles the roll action triggered by user interaction.
*
@ -191,7 +205,7 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
// Debug : console.log(">>>>", event, target, rollType)
// Deprecated : if (this.isEditMode) return
switch (rollType) {
case "resource":
case "resource":
item = foundry.utils.duplicate(this.actor.system.resources)
item.name = game.i18n.localize(`CTHULHUETERNAL.Label.Resources`)
item.targetScore = item.permanentRating
@ -212,7 +226,7 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
item = this.actor.items.get(li.data("item-id"));
item.damageBonus = this.actor.system.damageBonus
break
case "san":
case "san":
item = foundry.utils.duplicate(this.actor.system.san)
item.name = game.i18n.localize("CTHULHUETERNAL.Label.SAN")
item.targetScore = item.value

View File

@ -0,0 +1,28 @@
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
export default class CthulhuEternalRitualSheet extends CthulhuEternalItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["ritual"],
position: {
width: 600,
},
window: {
contentClasses: ["ritual-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-cthulhu-eternal/templates/ritual.hbs",
},
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -22,7 +22,7 @@ export default class CthulhuEternalSkillSheet extends CthulhuEternalItemSheet {
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -0,0 +1,28 @@
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
export default class CthulhuEternalTomeSheet extends CthulhuEternalItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["tome"],
position: {
width: 600,
},
window: {
contentClasses: ["tome-content"],
},
}
/** @override */
static PARTS = {
main: {
template: "systems/fvtt-cthulhu-eternal/templates/tome.hbs",
},
}
/** @override */
async _prepareContext() {
const context = await super._prepareContext()
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
return context
}
}

View File

@ -37,7 +37,7 @@ export default class CthulhuEternalVehicleSheet extends CthulhuEternalActorSheet
tabGroups = {
sheet: "equipment",
}
/**
* Prepare an array of form header tabs.
* @returns {Record<string, Partial<ApplicationTab>>}
@ -59,9 +59,9 @@ export default class CthulhuEternalVehicleSheet extends CthulhuEternalActorSheet
const context = await super._prepareContext()
context.tabs = this.#getTabs()
context.enrichedDescription = await TextEditor.enrichHTML(this.document.system.description, { async: true })
context.enrichedNotes = await TextEditor.enrichHTML(this.document.system.notes, { async: true })
context.enrichedDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.description, { async: true })
context.enrichedNotes = await foundry.applications.ux.TextEditor.implementation.enrichHTML(this.document.system.notes, { async: true })
return context
}
@ -78,7 +78,7 @@ export default class CthulhuEternalVehicleSheet extends CthulhuEternalActorSheet
context.tab = context.tabs.equipment
context.weapons = doc.itemTypes.weapon
context.gears = doc.itemTypes.gear
break
break
case "description":
context.tab = context.tabs.description
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })

View File

@ -1,6 +1,6 @@
import LethalFantasyItemSheet from "./base-item-sheet.mjs"
import CthulhuEternalItemSheet from "./base-item-sheet.mjs"
export default class LethalFantasyWeaponSheet extends LethalFantasyItemSheet {
export default class CthulhuEternalWeaponSheet extends CthulhuEternalItemSheet {
/** @override */
static DEFAULT_OPTIONS = {
classes: ["weapon"],

View File

@ -6,16 +6,16 @@ import * as BOND from "./bond.mjs"
export const SYSTEM_ID = "fvtt-cthulhu-eternal"
export const ASCII = `
`
@ -42,18 +42,18 @@ export const INSANITY = {
}
export const ERA_CSS = {
jazz: { primaryFont: "RozhaOne", secondaryFont: "RozhaOne", titleFont: "Broadway", baseFontSize: "1.0rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(9%) saturate(2368%) hue-rotate(360deg) brightness(86%) contrast(84%)" },
jazz: { primaryFont: "RozhaOne", secondaryFont: "RozhaOne", titleFont: "Broadway", baseFontSize: "0.95rem", titleFontSize: "1.2rem", imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(9%) saturate(2368%) hue-rotate(360deg) brightness(86%) contrast(84%)" },
modern: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Georama", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(92%) sepia(11%) saturate(1214%) hue-rotate(51deg) brightness(93%) contrast(86%)" },
future: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "Seabreed", baseFontSize: "1.0rem", titleFontSize: "2.0rem",imgFilter: "invert(90%) sepia(6%) saturate(1818%) hue-rotate(152deg) brightness(91%) contrast(91%)" },
victorian: { primaryFont: "Volkhov", secondaryFont: "Volkhov", titleFont: "Excelsior", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(100%) sepia(59%) saturate(1894%) hue-rotate(337deg) brightness(88%) contrast(98%)" },
coldwar: { primaryFont: "Georama", secondaryFont: "Georama", titleFont: "TopSecret", baseFontSize: "1.0rem", titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(14%) saturate(2508%) hue-rotate(202deg) brightness(99%) contrast(105%)"},
revolution: { primaryFont: "IMFell", secondaryFont: "IMFell", titleFont: "Dominican", baseFontSize: "1.0rem",titleFontSize: "1.3rem",imgFilter: "brightness(0) saturate(100%) invert(81%) sepia(25%) saturate(386%) hue-rotate(7deg) brightness(101%) contrast(84%)" },
medieval: { primaryFont: "UncialAntiqua", secondaryFont: "UncialAntiqua", titleFont: "Luminari", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)"},
ww2: { primaryFont: "SairaStencilOne", secondaryFont: "SairaStencilOne", titleFont: "Armalite", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "filter: invert(44%) sepia(8%) saturate(2657%) hue-rotate(40deg) brightness(96%) contrast(75%)"},
ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "invert(28%) sepia(27%) saturate(475%) hue-rotate(76deg) brightness(95%) contrast(93%)"},
medieval: { primaryFont: "Skranji", secondaryFont: "UncialAntiqua", titleFont: "Luminari", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)"},
ww2: { primaryFont: "SairaStencilOne", secondaryFont: "SairaStencilOne", titleFont: "Armalite", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "filter: invert(44%) sepia(8%) saturate(2657%) hue-rotate(40deg) brightness(96%) contrast(75%)"},
ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "invert(28%) sepia(27%) saturate(475%) hue-rotate(76deg) brightness(95%) contrast(93%)"},
ageofsail: { primaryFont: "SailRegular", secondaryFont: "SailRegular", titleFont: "P22Operina", baseFontSize: "1.1rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(43%) sepia(74%) saturate(3154%) hue-rotate(336deg) brightness(95%) contrast(83%)" },
classical: { primaryFont: "ChantelliAntiqua", secondaryFont: "ChantelliAntiqua", titleFont: "TrajanPro", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "brightness(0) saturate(100%) invert(52%) sepia(32%) saturate(7492%) hue-rotate(265deg) brightness(89%) contrast(95%)" },
postapo: { primaryFont: "Teko", secondaryFont: "Teko", titleFont: "Teko", baseFontSize: "1.25rem",titleFontSize: "1.5rem",imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" }
postapo: { primaryFont: "Teko", secondaryFont: "Teko", titleFont: "Teko", baseFontSize: "1.35rem",titleFontSize: "1.5rem",imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" }
}
export const RESOURCE_RATING = {
@ -122,7 +122,7 @@ export const VEHICLE_SPEED = {
"fast": "CTHULHUETERNAL.Label.Fast"
}
export const EQUIPMENT_STATES = {
export const EQUIPMENT_STATES = {
"pristine": "CTHULHUETERNAL.Label.Pristine",
"worn": "CTHULHUETERNAL.Label.Worn",
"junk": "CTHULHUETERNAL.Label.Junk"
@ -238,6 +238,20 @@ export const MULTIPLIER_CHOICES = {
"5": "5"
}
export const WEAPON_SELECTIVE_FIRE_CHOICES = {
"shortburst": { id: "shortburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortburst", ammoUsed: 3, lethality: 10, killRadius: 0},
"longburst": { id: "longburst", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longburst", ammoUsed: 5, lethality: 10, killRadius: 1},
"shortspray": { id: "shortspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.shortspray", ammoUsed: 10, lethality: 10, killRadius: 2},
"longspray": { id: "longspray", label: "CTHULHUETERNAL.Weapon.SelectiveFire.longspray", ammoUsed: 20, lethality: 10, killRadius: 3},
}
export const RITUAL_TYPES = {
"simple": "CTHULHUETERNAL.Ritual.Simple",
"difficult": "CTHULHUETERNAL.Ritual.Difficult",
"complex": "CTHULHUETERNAL.Ritual.Complex",
"elaborate": "CTHULHUETERNAL.Ritual.Elaborate"
}
/**
* Include all constant definitions within the SYSTEM global export
* @type {Object}
@ -248,6 +262,7 @@ export const SYSTEM = {
HARSHNESS: PROTAGONIST.HARSHNESS,
WEAPON_TYPE: WEAPON.WEAPON_TYPE,
WEAPON_SUBTYPE: WEAPON.WEAPON_SUBTYPE,
WEAPON_SELECTIVE_FIRE_CHOICES,
WEAPON_SKILL_MAPPING,
BOND_TYPE: BOND.BOND_TYPE,
AVAILABLE_SETTINGS,
@ -261,5 +276,6 @@ export const SYSTEM = {
MODIFIER_CHOICES,
MULTIPLIER_CHOICES,
ASCII,
DAMAGE_BONUS
DAMAGE_BONUS,
RITUAL_TYPES
}

View File

@ -17,4 +17,4 @@ export const WEAPON_SUBTYPE = {
export const WEAPON_RANGE_UNIT = {
"yard": "CTHULHUETERNAL.Weapon.RangeUnit.yard",
"meter": "CTHULHUETERNAL.Weapon.RangeUnit.meter"
}
}

View File

@ -9,6 +9,8 @@ export const defaultItemImg = {
arcane: "systems/fvtt-cthulhu-eternal/assets/icons/icon_arcane.svg",
injury: "systems/fvtt-cthulhu-eternal/assets/icons/icon_injury.svg",
motivation: "systems/fvtt-cthulhu-eternal/assets/icons/icon_motivation.svg",
ritual: "systems/fvtt-cthulhu-eternal/assets/icons/icon_ritual.svg",
tome: "systems/fvtt-cthulhu-eternal/assets/icons/icon_tome.svg",
}
export default class CthulhuEternalItem extends Item {

View File

@ -1,5 +1,6 @@
import { SYSTEM } from "../config/system.mjs"
export default class CthulhuEternalRoll extends Roll {
/**
* The HTML template path used to render dice checks of this type
@ -146,6 +147,24 @@ export default class CthulhuEternalRoll extends Roll {
options.isNudge = false
break
case "damage":
let isLethal = false
options.isNudge = false
if (options.rollItem.system.lethality > 0) {
let lethalityRoll = new Roll("1d100")
await lethalityRoll.evaluate()
isLethal = (lethalityRoll.total <= options.rollItem.system.lethality)
let flavor = `${options.rollItem.name} - <strong>Lethality Roll</strong> : ${lethalityRoll.total} <= ${options.rollItem.system.lethality} => ${isLethal}`
if ( isLethal) {
flavor += `<br>The target is lethally wounded => HP = 0`
} else {
let wounds = Math.floor(lethalityRoll.total/10) + (lethalityRoll.total % 10)
flavor += `<br>The target is not lethally wounded => HP loss = ${wounds}`
}
await lethalityRoll.toMessage({
flavor:flavor
});
return
}
let formula = options.rollItem.system.damage
if ( options.rollItem.system.weaponType === "melee" || options.rollItem.system.weaponType === "unarmed") {
formula += ` + ${options.rollItem.damageBonus}`
@ -155,16 +174,6 @@ export default class CthulhuEternalRoll extends Roll {
await damageRoll.toMessage({
flavor: `${options.rollItem.name} - Damage Roll`
});
let isLethal = false
options.isNudge = false
if (options.rollItem.system.lethality > 0) {
let lethalityRoll = new Roll("1d100")
await lethalityRoll.evaluate()
isLethal = (lethalityRoll.total <= options.rollItem.system.lethality)
await lethalityRoll.toMessage({
flavor: `${options.rollItem.name} - Lethality Roll : ${lethalityRoll.total} <= ${options.rollItem.system.lethality} => ${isLethal}`
});
}
return
case "weapon":
let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
@ -178,23 +187,30 @@ export default class CthulhuEternalRoll extends Roll {
console.log("WP Not found", era, options.rollItem.system.weaponType)
return
}
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
let actor = game.actors.get(options.actorId)
options.weapon = options.rollItem
options.rollItem = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase())
if (!options.rollItem) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill"))
return
if (options.rollItem.system.hasDirectSkill) {
let skillName = options.rollItem.name
options.rollItem = {type: "skill", name: skillName, system: {base: 0, bonus: options.weapon.system.directSkillValue} }
options.initialScore = options.weapon.system.directSkillValue
} else {
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
let actor = game.actors.get(options.actorId)
options.rollItem = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase())
if (!options.rollItem) {
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponSkill"))
return
}
options.initialScore = options.rollItem.system.computeScore()
console.log("WEAPON", skillName, era, options.rollItem)
}
options.initialScore = options.rollItem.system.computeScore()
console.log("WEAPON", skillName, era, options.rollItem)
break
default:
options.initialScore = 50
break
}
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
console.log("Roll options", CONFIG.Dice.rollModes);
const rollModes = foundry.utils.duplicate(CONFIG.Dice.rollModes); //Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
const fieldRollMode = new foundry.data.fields.StringField({
choices: rollModes,
blank: false,
@ -203,6 +219,7 @@ export default class CthulhuEternalRoll extends Roll {
const choiceModifier = SYSTEM.MODIFIER_CHOICES
const choiceMultiplier = SYSTEM.MULTIPLIER_CHOICES
const choiceSelectiveFire = SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES
let modifier = "+0"
let multiplier = "5"
@ -223,14 +240,16 @@ export default class CthulhuEternalRoll extends Roll {
fieldRollMode,
choiceModifier,
choiceMultiplier,
choiceSelectiveFire,
formula,
hasTarget: options.hasTarget,
hasModifier,
hasMultiplier,
modifier,
selectiveFireChoice: "shortburst",
multiplier
}
const content = await renderTemplate("systems/fvtt-cthulhu-eternal/templates/roll-dialog.hbs", dialogContext)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/roll-dialog.hbs", dialogContext)
const title = CthulhuEternalRoll.createTitle(options.rollType, options.rollTarget)
const label = game.i18n.localize("CTHULHUETERNAL.Roll.roll")
@ -314,19 +333,19 @@ export default class CthulhuEternalRoll extends Roll {
let unit = this.total - (dec * 10)
if (this.total <= rollData.targetScore) {
resultType = "success"
// Detect if decimal == unit in the dire total result
// Detect if decimal == unit in the dire total result
if (dec === unit || this.total === 1) {
resultType = "successCritical"
}
} else {
// Detect if decimal == unit in the dire total result
// Detect if decimal == unit in the dire total result
if (dec === unit || this.total === 100) {
resultType = "failureCritical"
}
}
this.options.resultType = resultType
if (this.options.isNudgedRoll) {
if (this.options.isNudgedRoll) {
this.options.isSuccess = resultType === "success" || resultType === "successCritical"
this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
this.options.isCritical = false
@ -366,7 +385,7 @@ export default class CthulhuEternalRoll extends Roll {
/** @override */
async render(chatOptions = {}) {
let chatData = await this._getChatCardData(chatOptions.isPrivate)
return await renderTemplate(this.constructor.CHAT_TEMPLATE, chatData)
return await foundry.applications.handlebars.renderTemplate(this.constructor.CHAT_TEMPLATE, chatData)
}
/**

View File

@ -9,5 +9,8 @@ export { default as CthulhuEternalBond } from "./bond.mjs"
export { default as CthulhuEternalGear } from "./gear.mjs"
export { default as CthulhuEternalMotivation } from "./motivation.mjs"
export { default as CthulhuEternalArchetype } from "./archetype.mjs"
export { default as CthulhuEternalRitual } from "./ritual.mjs"
export { default as CthulhuEternalVehicle } from "./vehicle.mjs"
export { default as CthulhuEternalCreature } from "./creature.mjs"
export { default as CthulhuEternalTome } from "./tome.mjs"

View File

@ -0,0 +1,80 @@
import { SYSTEM } from "../config/system.mjs"
import CthulhuEternalRoll from "../documents/roll.mjs"
export default class CthulhuEternalCreature extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
// Carac
const characteristicField = (label) => {
const schema = {
value: new fields.NumberField({ ...requiredInteger, initial: 3, min: 0 }),
feature: new fields.StringField({ required: true, nullable: false, initial: "" })
}
return new fields.SchemaField(schema, { label })
}
schema.characteristics = new fields.SchemaField(
Object.values(SYSTEM.CHARACTERISTICS).reduce((obj, characteristic) => {
obj[characteristic.id] = characteristicField(characteristic.label)
return obj
}, {}),
)
schema.wp = new fields.SchemaField({
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
max: new fields.NumberField({ ...requiredInteger, initial: 3, min: 0 }),
exhausted: new fields.BooleanField({ required: true, initial: false })
})
schema.hp = new fields.SchemaField({
value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
max: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 })
})
schema.movement = new fields.StringField({ required: true, initial: "" })
schema.sanLoss = new fields.StringField({ required: true, initial: "1/1D6" })
schema.armor = new fields.StringField({ required: true, initial: "" })
schema.size = new fields.StringField({ required: true, initial: "medium", choices: SYSTEM.CREATURE_SIZE })
schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
schema.description = new fields.HTMLField({ required: true, textSearch: true })
schema.notes = new fields.HTMLField({ required: true, textSearch: true })
return schema
}
/** @override */
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Creature"]
/** */
/**
* Rolls a dice for a character.
* @param {("save"|"resource|damage")} rollType The type of the roll.
* @param {number} rollItem The target value for the roll. Which caracteristic or resource. If the roll is a damage roll, this is the id of the item.
* @returns {Promise<null>} - A promise that resolves to null if the roll is cancelled.
*/
async roll(rollType, rollItem) {
let opponentTarget
const hasTarget = opponentTarget !== undefined
let roll = await CthulhuEternalRoll.prompt({
rollType,
rollItem,
isLowWP: false,
isZeroWP: false,
isExhausted: false,
actorId: this.parent.id,
actorName: this.parent.name,
actorImage: this.parent.img,
hasTarget,
target: opponentTarget
})
if (!roll) return null
await roll.toMessage({}, { rollMode: roll.options.rollMode })
}
}

24
module/models/ritual.mjs Normal file
View File

@ -0,0 +1,24 @@
import { SYSTEM } from "../config/system.mjs"
export default class CthulhuEternalRitual extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const requiredInteger = { required: true, nullable: false, integer: true }
const schema = {}
schema.ritualType = new fields.StringField({ required: true, initial: "simple", choices: SYSTEM.RITUAL_TYPES })
schema.studyTime = new fields.StringField({ required: true, initial: "X days", textSearch: true })
schema.studySAN = new fields.StringField({ required: true, initial: "1d4", textSearch: true })
schema.activationTime = new fields.StringField({ required: true, initial: "X turns", textSearch: true })
schema.activationWP = new fields.StringField({ required: true, initial: "1d4", textSearch: true })
schema.activationSAN = new fields.StringField({ required: true, initial: "1d6", textSearch: true })
schema.description = new fields.HTMLField({ required: true, textSearch: true })
return schema
}
/** @override */
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Ritual"]
}

64
module/models/tome.mjs Normal file
View File

@ -0,0 +1,64 @@
import { SYSTEM } from "../config/system.mjs";
export default class CthulhuEternalTome extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields;
const schema = {};
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
schema.minimumEra = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.creationDate = new fields.StringField({
required: true,
initial: "",
textSearch: true
});
// Language field
schema.language = new fields.StringField({
required: true,
initial: "Latin",
textSearch: true
});
// studyTime field
schema.studyTime = new fields.StringField({
required: true,
initial: "X days",
textSearch: true
});
// SAN loss field
schema.sanLoss = new fields.StringField({
required: true,
initial: "1d4",
textSearch: true
});
// Unnatural skill field
schema.unnaturalSkill = new fields.StringField({
required: true,
initial: "1d4",
textSearch: true
});
schema.rituals = new fields.StringField({
required: true,
initial: "",
textSearch: true
});
schema.otherBenefits = new fields.StringField({
required: true,
initial: "",
textSearch: true
});
schema.description = new fields.HTMLField({ required: true, textSearch: true })
return schema;
}
/** @override */
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Tome"];
}

View File

@ -1,6 +1,6 @@
import { SYSTEM } from "../config/system.mjs"
export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
export default class CthulhuEternalWeapon extends foundry.abstract.TypeDataModel {
static defineSchema() {
const fields = foundry.data.fields
const schema = {}
@ -12,17 +12,22 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
schema.weaponType = new fields.StringField({ required: true, initial: "melee", choices: SYSTEM.WEAPON_TYPE })
schema.damage = new fields.StringField({required: true, initial: "1d6"})
schema.hasDirectSkill = new fields.BooleanField({ required: true, initial: false })
schema.directSkillValue = new fields.NumberField({ required: true, initial: 0, min: 0, max:99 })
schema.hasSelectiveFire = new fields.BooleanField({ required: true, initial: false })
schema.damage = new fields.StringField({required: true, initial: "1d6"})
schema.applyDamageBonus = new fields.BooleanField({ required: true, initial: false })
schema.baseRange = new fields.StringField({required: true, initial: ""})
schema.rangeUnit = new fields.StringField({ required: true, initial: "yard", choices: SYSTEM.WEAPON_RANGE_UNIT })
schema.lethality = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.killRadius = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.armorPiercing = new fields.NumberField({ required: true, initial: 0, min: 0 })
schema.weaponSubtype = new fields.StringField({ required: true, initial: "basicfirearm", choices: SYSTEM.WEAPON_SUBTYPE })
schema.weaponSubtype = new fields.StringField({ required: true, initial: "basicfirearm", choices: SYSTEM.WEAPON_SUBTYPE })
schema.state = new fields.StringField({ required: true, initial: "pristine", choices: SYSTEM.EQUIPMENT_STATES })
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })
return schema
}

View File

@ -1,5 +1,7 @@
import CthulhuEternalRoll from "./documents/roll.mjs"
import { SystemManager } from './applications/hud/system-manager.js'
import { SYSTEM } from "./config/system.mjs"
export default class CthulhuEternalUtils {
@ -179,10 +181,10 @@ export default class CthulhuEternalUtils {
}
static async nudgeRoll(rollMessage) {
static async nudgeRoll(rollMessage) {
let dialogContext = rollMessage.rolls[0]?.options
let actor = game.actors.get(dialogContext.actorId)
let actor = game.actors.get(dialogContext.actorId)
dialogContext.wpValue = actor.system.wp.value
dialogContext.rollResultIndex = rollMessage.rolls[0].total - 1
dialogContext.minValue = Math.max(rollMessage.rolls[0].total - (dialogContext.wpValue * 5), 1)
@ -191,9 +193,9 @@ export default class CthulhuEternalUtils {
// Build options table for the select operator between minValue and maxValue
dialogContext.nudgeOptions = Array.from({ length: dialogContext.maxValue - dialogContext.minValue + 1 }, (_, i) => dialogContext.minValue + i)
console.log(dialogContext)
const content = await renderTemplate("systems/fvtt-cthulhu-eternal/templates/nudge-dialog.hbs", dialogContext)
console.log(dialogContext)
const content = await foundry.applications.handlebars.renderTemplate("systems/fvtt-cthulhu-eternal/templates/nudge-dialog.hbs", dialogContext)
const title = game.i18n.localize("CTHULHUETERNAL.Roll.nudgeRoll")
const rollContext = await foundry.applications.api.DialogV2.wait({
@ -234,7 +236,7 @@ export default class CthulhuEternalUtils {
if (rollContext === null || dialogContext.wpCost === 0) {
return
}
const roll = new CthulhuEternalRoll(String(dialogContext.nudgedValue))
await roll.evaluate()
roll.options = dialogContext

Binary file not shown.

View File

@ -0,0 +1 @@
MANIFEST-000036

View File

7
packs-system/rituals/LOG Normal file
View File

@ -0,0 +1,7 @@
2025/05/18-22:05:58.774845 7f89057fa6c0 Recovering log #34
2025/05/18-22:05:58.784751 7f89057fa6c0 Delete type=3 #32
2025/05/18-22:05:58.784813 7f89057fa6c0 Delete type=0 #34
2025/05/18-22:06:27.441454 7f8667fff6c0 Level-0 table #39: started
2025/05/18-22:06:27.441484 7f8667fff6c0 Level-0 table #39: 0 bytes OK
2025/05/18-22:06:27.447800 7f8667fff6c0 Delete type=0 #37
2025/05/18-22:06:27.447999 7f8667fff6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)

View File

@ -0,0 +1,7 @@
2025/05/14-23:46:13.953928 7fa2e5ffb6c0 Recovering log #29
2025/05/14-23:46:13.965264 7fa2e5ffb6c0 Delete type=3 #27
2025/05/14-23:46:13.965329 7fa2e5ffb6c0 Delete type=0 #29
2025/05/14-23:53:27.523831 7fa2e57fa6c0 Level-0 table #35: started
2025/05/14-23:53:27.523897 7fa2e57fa6c0 Level-0 table #35: 0 bytes OK
2025/05/14-23:53:27.564827 7fa2e57fa6c0 Delete type=0 #33
2025/05/14-23:53:27.634207 7fa2e57fa6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end)

Binary file not shown.

View File

View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

View File

@ -1 +1 @@
MANIFEST-000112
MANIFEST-000200

View File

@ -1,8 +1,7 @@
2025/02/06-21:12:01.561879 7ffae7fff6c0 Recovering log #110
2025/02/06-21:12:01.618398 7ffae7fff6c0 Delete type=3 #108
2025/02/06-21:12:01.618459 7ffae7fff6c0 Delete type=0 #110
2025/02/06-22:37:39.915470 7ffae6bff6c0 Level-0 table #115: started
2025/02/06-22:37:39.915518 7ffae6bff6c0 Level-0 table #115: 0 bytes OK
2025/02/06-22:37:39.952549 7ffae6bff6c0 Delete type=0 #113
2025/02/06-22:37:39.952742 7ffae6bff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/02/06-22:37:39.952774 7ffae6bff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/05/18-22:05:58.759366 7f8904ff96c0 Recovering log #198
2025/05/18-22:05:58.769708 7f8904ff96c0 Delete type=3 #196
2025/05/18-22:05:58.769762 7f8904ff96c0 Delete type=0 #198
2025/05/18-22:06:27.422044 7f8667fff6c0 Level-0 table #203: started
2025/05/18-22:06:27.422086 7f8667fff6c0 Level-0 table #203: 0 bytes OK
2025/05/18-22:06:27.428820 7f8667fff6c0 Delete type=0 #201
2025/05/18-22:06:27.447959 7f8667fff6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)

View File

@ -1,8 +1,7 @@
2025/02/06-21:10:37.808165 7ffae77fe6c0 Recovering log #106
2025/02/06-21:10:37.818622 7ffae77fe6c0 Delete type=3 #104
2025/02/06-21:10:37.818703 7ffae77fe6c0 Delete type=0 #106
2025/02/06-21:11:20.037362 7ffae6bff6c0 Level-0 table #111: started
2025/02/06-21:11:20.037398 7ffae6bff6c0 Level-0 table #111: 0 bytes OK
2025/02/06-21:11:20.043269 7ffae6bff6c0 Delete type=0 #109
2025/02/06-21:11:20.043465 7ffae6bff6c0 Manual compaction at level-0 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/02/06-21:11:20.043496 7ffae6bff6c0 Manual compaction at level-1 from '!folders!DD8331Hda4rhvEf9' @ 72057594037927935 : 1 .. '!items!zplzTG30QXHURusr' @ 0 : 0; will stop at (end)
2025/05/14-23:46:13.940336 7fa2e67fc6c0 Recovering log #193
2025/05/14-23:46:13.950153 7fa2e67fc6c0 Delete type=3 #191
2025/05/14-23:46:13.950214 7fa2e67fc6c0 Delete type=0 #193
2025/05/14-23:53:27.493872 7fa2e57fa6c0 Level-0 table #199: started
2025/05/14-23:53:27.493910 7fa2e57fa6c0 Level-0 table #199: 0 bytes OK
2025/05/14-23:53:27.523581 7fa2e57fa6c0 Delete type=0 #197
2025/05/14-23:53:27.634194 7fa2e57fa6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end)

Binary file not shown.

Binary file not shown.

View File

View File

View File

Binary file not shown.

644
styles/creature.less Normal file
View File

@ -0,0 +1,644 @@
.creature-content {
.sheet-common();
.creature-sheet-common();
overflow: scroll;
}
.sheet-tabs {
background-color: var(--color-light-1);
}
.creature-main {
background-color: var(--color-light-1);
display: flex;
.creature-pc {
display: flex;
gap: 4px;
flex: 1;
.creature-left {
min-width: 180px;
display: flex;
flex-direction: column;
.creature-left-image {
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 8px;
.creature-img {
height: 140px;
width: auto;
border: none;
}
}
.creature-hp {
gap: 2px;
align-items: center;
input {
flex: none;
width: 2rem;
margin-left: 4px;
}
.damage-bonus {
font-size: calc(var(--font-size-standard) * 0.8);
}
.hp-separator {
font-size: calc(var(--font-size-standard) * 1.2);
display: flex;
align-items: center;
justify-content: center;
}
}
.creature-dv,
.creature-dmax {
.form-fields {
flex: none;
}
}
.creature-dmax-edit {
input {
display: flex;
width: 60px;
font-size: calc(var(--font-size-standard) * 1.4);
align-items: center;
justify-content: center;
padding: 0 5px 0 5px;
text-align: center;
}
}
}
.creature-right {
display: flex;
flex-direction: column;
gap: 5px;
.creature-name {
display: flex;
input {
font-family: var(--font-title);
font-size: var(--font-size-title);
width: 400px;
}
}
.san {
align-content: flex-start;
input {
min-width: 2.2rem;
max-width: 2.2rem;
margin-bottom: 4px;
}
select {
min-width: 6rem;
max-width: 6rem;
}
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
font-size: 0.9rem;
}
.button {
min-width: 4rem;
max-width: 4rem;
}
.san-checkbox {
min-width: 1rem;
max-width: 1rem;
}
.label-short-field {
font-size: 0.9rem;
max-width: 3rem;
min-width: 3rem;
flex-grow: 1;
}
.label-recovery {
margin-left: 4px;
}
.label-field {
font-size: 0.9rem;
max-width: 6rem;
min-width: 6rem;
flex-grow: 1;
}
.label-bp {
flex-grow: 1;
max-width: 3rem;
min-width: 3rem;
margin-left: 4px;
}
.label-insanity {
flex-grow: 1;
margin-left: 4px;
max-width: 8rem;
min-width: 8rem;
}
.spacing {
margin-left: 4px;
}
.d100 {
flex: 0;
}
}
.willpower {
input {
min-width: 2.4rem;
max-width: 2.4rem;
}
input[type="checkbox"] {
min-width: 1rem;
max-width: 1rem;
}
.label-field {
flex-grow: 1;
margin-left: 4px;
max-width: 5rem;
min-width: 5rem;
font-size: 0.9rem;
}
.checkbox {
flex-grow: 0;
min-width: 1rem;
max-width: 1rem;
}
}
label {
min-width: 120px;
}
}
}
.creature-pc-play {
min-width: 500px;
}
.creature-pc-edit {
min-width: 650px;
}
.creature-characteristics {
background-color: var(--color-light-1);
display: flex;
flex-direction: column;
gap: 5px;
flex: 1;
.creature-characteristic {
display: flex;
align-items: center;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.rollable {
min-width: 3rem;
max-width: 3rem;
}
.char-text {
margin-left: 0.5rem;
}
.d100 {
flex: 0;
max-width: 0.6rem;
}
.form-group {
flex: 0;
padding-left: 5px;
.form-fields {
font-size: 1.1rem;
flex: none;
width: 40px;
}
}
}
}
.creature-characteristic-play {
min-width: 225px;
}
.creature-characteristic-edit {
min-width: 400px;
}
}
.creature-biography {
background-color: var(--color-light-1);
prose-mirror.inactive {
min-height: 40px;
}
prose-mirror.active {
min-height: 150px;
}
.field-label {
margin-left: 8px;
}
.adapted {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
label {
min-width: 20rem;
}
}
.resources {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
label {
min-width: 8rem;
}
}
.features,
.biodata {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 8px;
label {
min-width: 3rem;
}
.feature {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
}
}
}
.tab.creature-skills .main-div {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
legend {
a {
font-size: calc(var(--font-size-standard) * 1.4);
padding-left: 5px;
}
}
.armors {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
.armor {
display: flex;
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.protection {
min-width: 5rem;
max-width: 5rem;
}
.name {
min-width: 8rem;
max-width: 8rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.weapons {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.weapon {
display: flex;
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.damage {
min-width: 6rem;
max-width: 6rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.skills {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
.skill {
display: flex;
align-items: center;
gap: 4px;
margin-left: 4px;
min-width: 12.3rem;
max-width: 12.3rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.score {
min-width: 1.2rem;
max-width: 1.2rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
}
.tab.creature-status .main-div {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
legend {
a {
font-size: calc(var(--font-size-standard) * 1.4);
padding-left: 5px;
}
}
.bonds {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.bond {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 12rem;
max-width: 12rem;
}
.type {
min-width: 6rem;
max-width: 6rem;
}
.level {
min-width: 2rem;
max-width: 2rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.motivations {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.motivation {
display: flex;
align-items: center;
gap: 4px;
min-width: 14rem;
max-width: 14rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 12rem;
max-width: 12rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.mentaldisorders {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.mentaldisorder {
display: flex;
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 14rem;
max-width: 14rem;
}
.cured {
min-width: 5rem;
max-width: 5rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.injuries {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.injury {
display: flex;
align-items: center;
gap: 4px;
min-width: 16rem;
max-width: 16rem;
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 14rem;
max-width: 14rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
}
.tab.creature-equipment .main-div {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
legend {
a {
font-size: calc(var(--font-size-standard) * 1.4);
padding-left: 5px;
}
}
.gears {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 4px;
.gear {
display: flex;
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.rituals {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.ritual {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.tomes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.tome {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
prose-mirror.inactive {
min-height: 40px;
}
prose-mirror.active {
min-height: 150px;
}
}

View File

@ -120,21 +120,6 @@
}
@font-face {
font-family: "Caslon";
src: url("../fonts/caslonpro-regular.otf") format("truetype");
}
@font-face {
font-family: "Caslon Bold";
src: url("../fonts/caslonpro-bold.otf") format("truetype");
}
@font-face {
font-family: "Caslon Bold Italic";
src: url("../fonts/caslonpro-bolditalic.otf") format("truetype");
}
@font-face {
font-family: "Caslon Italic";
src: url("../fonts/caslonpro-italic.otf") format("truetype");
font-family: "Skranji";
src: url("../assets/fonts/Skranji.woff") format("woff");
}

View File

@ -5,6 +5,7 @@
@import "mixins.less";
@import "protagonist.less";
@import "vehicle.less";
@import "creature.less";
@import "skill.less";
@import "injury.less";
@import "weapon.less";
@ -16,6 +17,8 @@
@import "gear.less";
@import "arcane.less";
@import "archetype.less";
@import "ritual.less";
@import "tome.less";
}
@import "roll.less";

View File

@ -68,6 +68,13 @@
}
}
.creature-sheet-common {
label {
font-family: var(--font-secondary);
font-size: calc(var(--font-size-standard) * 1.0);
}
}
.item-sheet-common {
.form-fields {
padding-top: 4px;

View File

@ -275,7 +275,7 @@
}
}
.tab.protagonist-skills {
.tab.protagonist-skills .main-div {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
@ -294,20 +294,25 @@
align-items: center;
gap: 4px;
margin-left: 4px;
min-width: 12rem;
max-width: 12rem;
min-width: 12.3rem;
max-width: 12.3rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
min-width: 2rem;
max-width: 2rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.score {
min-width: 1.2rem;
max-width: 1.2rem;
}
.name {
min-width: 11rem;
max-width: 11rem;
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
@ -318,7 +323,7 @@
}
}
.tab.protagonist-status {
.tab.protagonist-status .main-div {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
@ -340,8 +345,9 @@
min-width: 18rem;
max-width: 18rem;
.controls {
min-width: 2rem;
max-width: 2rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 12rem;
@ -374,8 +380,9 @@
min-width: 14rem;
max-width: 14rem;
.controls {
min-width: 2rem;
max-width: 2rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 12rem;
@ -400,8 +407,9 @@
min-width: 18rem;
max-width: 18rem;
.controls {
min-width: 2rem;
max-width: 2rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 14rem;
@ -430,8 +438,9 @@
min-width: 16rem;
max-width: 16rem;
.controls {
min-width: 2rem;
max-width: 2rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 14rem;
@ -446,7 +455,7 @@
}
}
.tab.protagonist-equipment {
.tab.protagonist-equipment .main-div {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;
@ -472,8 +481,9 @@
cursor: pointer;
}
.controls {
min-width: 2rem;
max-width: 2rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.damage {
min-width: 6rem;
@ -499,15 +509,16 @@
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13srem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
min-width: 2rem;
max-width: 2rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.protection {
min-width: 5rem;
@ -524,6 +535,7 @@
}
}
}
.gears {
display: grid;
grid-template-columns: repeat(3, 1fr);
@ -533,23 +545,84 @@
align-items: center;
gap: 4px;
min-width: 13rem;
max-width: 13srem;
max-width: 13rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
min-width: 2rem;
max-width: 2rem;
}
.damage {
min-width: 5rem;
max-width: 5rem;
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 8rem;
max-width: 8rem;
min-width: 10rem;
max-width: 10rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.rituals {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.ritual {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
}
.item-img {
width: 24px;
height: 24px;
margin: 4px 0 0 0;
}
}
}
.tomes {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 4px;
.tome {
display: flex;
align-items: center;
gap: 4px;
min-width: 20rem;
max-width: 20rem;
.rollable:hover,
.rollable:focus {
text-shadow: 0 0 8px var(--color-shadow-primary);
cursor: pointer;
}
.controls {
font-size: 0.7rem;
min-width: 1.8rem;
max-width: 1.8rem;
}
.name {
min-width: 17rem;
max-width: 17rem;
}
.item-img {
width: 24px;

30
styles/ritual.less Normal file
View File

@ -0,0 +1,30 @@
.ritual-content {
.sheet-common();
.item-sheet-common();
fieldset {
margin-top: 8px;
background-color: var(--color-light-1);
.editor-content {
max-height: 400px;
overflow-y: auto;
}
.editor-container {
max-height: 400px;
overflow-y: auto;
}
}
.header {
background-color: var(--color-light-1);
display: flex;
img {
width: 50px;
height: 50px;
}
}
label {
flex: 10%;
}
}

22
styles/tome.less Normal file
View File

@ -0,0 +1,22 @@
.tome-content {
.sheet-common();
.item-sheet-common();
fieldset {
margin-top: 8px;
background-color: var(--color-light-1);
}
.header {
background-color: var(--color-light-1);
display: flex;
img {
width: 50px;
height: 50px;
}
}
label {
flex: 10%;
}
}

View File

@ -70,7 +70,7 @@
margin-left: 4px;
font-size: calc(var(--font-size-standard) * 1.4);
}
}
}
.vehicle-hp-max {
clear: both;
display: flex;
@ -115,8 +115,8 @@
.field-label {
margin-left: 8px;
}
.biodata {
display: grid;
grid-template-columns: repeat(2, 1fr);
@ -129,13 +129,13 @@
align-items: center;
gap: 4px;
min-width: 18rem;
max-width: 18rem;
max-width: 18rem;
}
}
}
.tab.vehicle-equipment {
.tab.vehicle-equipment .main-div {
background-color: var(--color-light-1);
display: grid;
grid-template-columns: 1fr;

View File

@ -6,58 +6,157 @@
"download": "#{DOWNLOAD}#",
"url": "https://www.uberwald.me/gitea/public/fvtt-cthulhu-eternal",
"license": "LICENSE",
"version": "12.0.5",
"version": "13.0.1",
"authors": [
{
"name": "Uberwald",
"discord": "LeRatierBretonnien"
"discord": "LeRatierBretonnien",
"flags": {}
}
],
"flags": {
"hotReload": {
"extensions": ["css", "html", "hbs", "json"],
"paths": ["acks.css", "./", "templates", "css", "lang/en.json"]
"extensions": [
"css",
"html",
"hbs",
"json"
],
"paths": [
"acks.css",
"./",
"templates",
"css",
"lang/en.json"
]
}
},
"compatibility": {
"minimum": "12",
"verified": "12"
"minimum": "13",
"verified": "13"
},
"esmodules": ["cthulhu-eternal.mjs"],
"styles": ["css/fvtt-cthulhu-eternal.css"],
"esmodules": [
"cthulhu-eternal.mjs"
],
"styles": [
"css/fvtt-cthulhu-eternal.css"
],
"languages": [
{
"lang": "en",
"name": "Anglais",
"path": "lang/en.json"
"path": "lang/en.json",
"flags": {}
}
],
"documentTypes": {
"Actor": {
"protagonist": { "htmlFields": ["description", "notes"] },
"vehicle": { "htmlFields": ["description", "notes"] }
"protagonist": {
"htmlFields": [
"description",
"notes"
]
},
"vehicle": {
"htmlFields": [
"description",
"notes"
]
},
"creature": {
"htmlFields": [
"description",
"notes"
]
}
},
"Item": {
"skill": { "htmlFields": ["description"] },
"injury": { "htmlFields": ["description"] },
"weapon": { "htmlFields": ["description"] },
"armor": { "htmlFields": ["description"] },
"bond": { "htmlFields": ["description"] },
"mentaldisorder": { "htmlFields": ["description"] },
"motivation": { "htmlFields": ["description"] },
"arcane": { "htmlFields": ["description"] },
"gear": { "htmlFields": ["description"] },
"archetype": { "htmlFields": ["description"] }
"skill": {
"htmlFields": [
"description"
]
},
"injury": {
"htmlFields": [
"description"
]
},
"weapon": {
"htmlFields": [
"description"
]
},
"armor": {
"htmlFields": [
"description"
]
},
"bond": {
"htmlFields": [
"description"
]
},
"mentaldisorder": {
"htmlFields": [
"description"
]
},
"motivation": {
"htmlFields": [
"description"
]
},
"arcane": {
"htmlFields": [
"description"
]
},
"gear": {
"htmlFields": [
"description"
]
},
"archetype": {
"htmlFields": [
"description"
]
},
"ritual": {
"htmlFields": [
"description"
]
},
"tome": {
"htmlFields": [
"description"
]
}
}
},
"packs": [
{
"name": "skills",
"banner": "",
"label": "Skills",
"system": "fvtt-cthulhu-eternal",
"path": "packs-system/skills",
"type": "Item"
"type": "Item",
"ownership": {
"PLAYER": "OBSERVER",
"ASSISTANT": "OWNER"
},
"flags": {}
},
{
"name": "rituals",
"label": "Rituals",
"system": "fvtt-cthulhu-eternal",
"path": "packs-system/rituals",
"type": "Item",
"ownership": {
"PLAYER": "OBSERVER",
"ASSISTANT": "OWNER"
},
"flags": {}
}
],
"grid": {
@ -67,4 +166,4 @@
"primaryTokenAttribute": "hp",
"socket": true,
"background": "systems/fvtt-cthulhu-eternal/assets/ui/background_01.webp"
}
}

View File

@ -2,11 +2,11 @@
<div class="header">
<img class="item-img era-icon-color" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
</div>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}}
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
</section>

View File

@ -2,15 +2,15 @@
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
</div>
<fieldset>
{{formField systemFields.settings value=system.settings localize=true}}
</fieldset>
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}}
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
</section>h

View File

@ -15,7 +15,7 @@
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput
systemFields.description
enriched=description
enriched=enrichedDescription
value=system.description
name="system.description"
toggled="false"

View File

@ -0,0 +1,13 @@
<section class="tab creature-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.notes"}}</legend>
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
</fieldset>
</div>
</section>

View File

@ -0,0 +1,95 @@
<section class="creature-main creature-main-{{ifThen isPlayMode 'play' 'edit'}}">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.creature"}}</legend>
<div class="creature-pc creature-pc-{{ifThen isPlayMode 'play' 'edit'}}">
<div class="creature-left">
<div class="creature-left-image">
<img class="creature-img" src="{{actor.img}}" data-edit="img" data-action="editImage"
data-tooltip="{{actor.name}}" />
</div>
</div>
<div class="creature-right">
<div class="creature-name">
{{formInput fields.name value=source.name rootId=partId disabled=isPlayMode}}
<a class="control" data-action="toggleSheet" data-tooltip="CTHULHUETERNAL.ToggleSheet"
data-tooltip-direction="UP">
<i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i>
</a>
</div>
<fieldset class="creature-hp">
<legend>{{localize "CTHULHUETERNAL.Label.HP"}}</legend>
<div class="flexrow">
{{formField systemFields.hp.fields.value value=system.hp.value}}
<span class="hp-separator">/</span>
{{formField systemFields.hp.fields.max value=system.hp.max }}
</div>
<div class="flexrow ">
{{formField systemFields.damageBonus value=system.damageBonus classes="damage-bonus"}}
</div>
</fieldset>
<fieldset class="willpower">
<legend>{{localize "CTHULHUETERNAL.Label.willpower"}}</legend>
<div class="flexrow">
<label class="label-field">{{localize "CTHULHUETERNAL.Label.current"}}</label>
{{formInput systemFields.wp.fields.value value=system.wp.value}}
<label class="label-field">{{localize "CTHULHUETERNAL.Label.max"}}</label>
{{formInput systemFields.wp.fields.max value=system.wp.max rootId=partId }}
<label class="label-field">{{localize "CTHULHUETERNAL.Label.exhausted"}}</label>
{{formInput systemFields.wp.fields.exhausted value=system.wp.exhausted classes="checkbox"}}
</div>
</fieldset>
</div>
</div>
</fieldset>
<fieldset class="creature-characteristics creature-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
<legend>{{localize "CTHULHUETERNAL.Label.characteristics"}}</legend>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="str" data-tooltip="{{system.characteristics.str.feature}}">{{localize
"CTHULHUETERNAL.Label.strShort"}}</label>
{{formField systemFields.characteristics.fields.str.fields.value value=system.characteristics.str.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.str.value 5}}</label>
</div>
<div class="creature-characteristic">
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="dex" data-tooltip="{{system.characteristics.dex.feature}}">{{localize
"CTHULHUETERNAL.Label.dexShort"}}</label>
{{formField systemFields.characteristics.fields.dex.fields.value value=system.characteristics.dex.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.dex.value 5}}</label>
</div>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="con" data-tooltip="{{system.characteristics.con.feature}}">{{localize
"CTHULHUETERNAL.Label.conShort"}}</label>
{{formField systemFields.characteristics.fields.con.fields.value value=system.characteristics.con.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.con.value 5}}</label>
</div>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="int" data-tooltip="{{system.characteristics.int.feature}}">{{localize
"CTHULHUETERNAL.Label.intShort"}}</label>
{{formField systemFields.characteristics.fields.int.fields.value value=system.characteristics.int.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.int.value 5}}</label>
</div>
<div class="creature-characteristic" >
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<label class="rollable" data-roll-type="char" data-char-id="pow" data-tooltip="{{system.characteristics.pow.feature}}">{{localize
"CTHULHUETERNAL.Label.powShort"}}</label>
{{formField systemFields.characteristics.fields.pow.fields.value value=system.characteristics.pow.value
rootId=partId disabled=isPlayMode }}
<label class="char-text">{{mul system.characteristics.pow.value 5}}</label>
</div>
</fieldset>
</section>

View File

@ -0,0 +1,57 @@
<section class="tab creature-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.weapons"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createWeapon"></i></a>{{/if}}
</legend>
<div class="weapons">
{{#each weapons as |item|}}
{{!log 'weapon' this}}
<div class="weapon item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<div class="name rollable" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<a class="damage rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage"
data-roll-value="{{item.system.damage}}">
{{localize "CTHULHUETERNAL.Label.damageShort"}} :
{{item.system.damage}}</a>
<div class="controls">
<a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.skills"}}" data-tooltip-direction="UP">{{localize "CTHULHUETERNAL.Label.skills"}}</legend>
<div class="skills">
{{#each skills as |item|}}
<div class="skill item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />
<div class="name rollable" data-roll-type="skill" data-tooltip="{{{item.description}}}" data-tooltip-direction="UP">{{item.name}}
</div>
<div class="score" >
{{item.system.skillTotal}}
</div>
<div class="controls">
<a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
</div>
</section>

View File

@ -12,7 +12,7 @@
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=description value=system.description name="system.description"
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description"
toggled=true}}
</fieldset>

View File

@ -2,8 +2,8 @@
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
</div>
<fieldset>
{{formField systemFields.cured value=system.cured localize=true}}
</fieldset>
@ -12,7 +12,7 @@
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput
systemFields.description
enriched=description
enriched=enrichedDescription
value=system.description
name="system.description"
toggled="false"

View File

@ -2,11 +2,11 @@
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
</div>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}}
{{formInput systemFields.description enriched=enrichedDescriptionw value=system.description name="system.description" toggled=true}}
</fieldset>
</section>

View File

@ -1,5 +1,5 @@
<section class="tab protagonist-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.resources"}}</legend>
<div class="resources">
@ -21,11 +21,11 @@
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.biodata"}}</legend>
<div class="adapted">
{{formField systemFields.biodata.fields.adaptedToViolence value=system.biodata.adaptedToViolence name="system.biodata.adaptedToViolence" localize=true}}
{{formField systemFields.biodata.fields.adaptedToHelplessness value=system.biodata.adaptedToHelplessness name="system.biodata.adaptedToHelplessness" localize=true}}
{{formField systemFields.biodata.fields.adaptedToViolence value=system.biodata.adaptedToViolence name="system.biodata.adaptedToViolence" localize=true}}
{{formField systemFields.biodata.fields.adaptedToHelplessness value=system.biodata.adaptedToHelplessness name="system.biodata.adaptedToHelplessness" localize=true}}
</div>
<div class="biodata">
{{formField systemFields.biodata.fields.harshness value=system.biodata.harshness name="system.biodata.harshness" localize=true}}
{{formField systemFields.biodata.fields.harshness value=system.biodata.harshness name="system.biodata.harshness" localize=true}}
{{formField systemFields.biodata.fields.age value=system.biodata.age name="system.biodata.age" localize=true classes="field-label"}}
{{formField systemFields.biodata.fields.gender value=system.biodata.gender name="system.biodata.gender" localize=true classes="field-label"}}
{{formField systemFields.biodata.fields.height value=system.biodata.height name="system.biodata.height" localize=true classes="field-label"}}
@ -39,41 +39,42 @@
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.distinguishingFeatures"}}</legend>
<div class="features">
<div class="feature">
<div class="feature">
<label>{{localize "CTHULHUETERNAL.Label.strShort"}}</label>
{{formInput systemFields.characteristics.fields.str.fields.feature value=system.characteristics.str.feature localize=true}}
{{formInput systemFields.characteristics.fields.str.fields.feature value=system.characteristics.str.feature localize=true}}
</div>
<div class="feature">
<div class="feature">
<label>{{localize "CTHULHUETERNAL.Label.dexShort"}}</label>
{{formInput systemFields.characteristics.fields.dex.fields.feature value=system.characteristics.dex.feature localize=true}}
{{formInput systemFields.characteristics.fields.dex.fields.feature value=system.characteristics.dex.feature localize=true}}
</div>
<div class="feature">
<div class="feature">
<label>{{localize "CTHULHUETERNAL.Label.conShort"}}</label>
{{formInput systemFields.characteristics.fields.con.fields.feature value=system.characteristics.con.feature localize=true}}
{{formInput systemFields.characteristics.fields.con.fields.feature value=system.characteristics.con.feature localize=true}}
</div>
<div class="feature">
<div class="feature">
<label>{{localize "CTHULHUETERNAL.Label.intShort"}}</label>
{{formInput systemFields.characteristics.fields.int.fields.feature value=system.characteristics.int.feature localize=true}}
{{formInput systemFields.characteristics.fields.int.fields.feature value=system.characteristics.int.feature localize=true}}
</div>
<div class="feature">
<div class="feature">
<label>{{localize "CTHULHUETERNAL.Label.powShort"}}</label>
{{formInput systemFields.characteristics.fields.pow.fields.feature value=system.characteristics.pow.feature localize=true}}
{{formInput systemFields.characteristics.fields.pow.fields.feature value=system.characteristics.pow.feature localize=true}}
</div>
<div class="feature">
<div class="feature">
<label>{{localize "CTHULHUETERNAL.Label.chaShort"}}</label>
{{formInput systemFields.characteristics.fields.cha.fields.feature value=system.characteristics.cha.feature localize=true}}
{{formInput systemFields.characteristics.fields.cha.fields.feature value=system.characteristics.cha.feature localize=true}}
</div>
</div>
</fieldset>
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.notes"}}</legend>
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
</fieldset>
</div>
</section>

View File

@ -1,5 +1,5 @@
<section class="tab protagonist-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.weapons"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i
@ -81,4 +81,56 @@
</div>
</fieldset>
{{#if (count tomes)}}
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.Tomes"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addTome"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createTome"></i></a>{{/if}}
</legend>
<div class="tomes">
{{#each tomes as |item|}}
<div class="tome" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<div class="controls">
<a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
{{/if}}
{{#if (count rituals)}}
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.Rituals"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addRitual"}}" data-tooltip-direction="UP"><i
class="fas fa-plus" data-action="createRitual"></i></a>{{/if}}
</legend>
<div class="rituals">
{{#each rituals as |item|}}
<div class="ritual" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.system.description}}}">
{{item.name}}
</div>
<div class="controls">
<a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
{{/if}}
</div>
</section>

View File

@ -1,5 +1,5 @@
<section class="tab protagonist-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
{{log this}}
<div class="main-div">
<fieldset>
<legend data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.skills"}}" data-tooltip-direction="UP">{{localize "CTHULHUETERNAL.Label.skills"}}</legend>
<div class="skills">
@ -21,5 +21,5 @@
</div>
</fieldset>
</div>
</section>

View File

@ -1,4 +1,5 @@
<section class="tab protagonist-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.bonds"}}{{#if isEditMode}}
@ -91,5 +92,5 @@
{{/each}}
</div>
</fieldset>
</div>
</section>

24
templates/ritual.hbs Normal file
View File

@ -0,0 +1,24 @@
<section>
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
<fieldset>
{{formField systemFields.ritualType value=system.ritualType localize=true}}
{{formField systemFields.studyTime value=system.studyTime}}
{{formField systemFields.studySAN value=system.studySAN}}
{{formField systemFields.activationTime value=system.activationTime}}
{{formField systemFields.activationSAN value=system.activationSAN}}
{{formField systemFields.activationWP value=system.activationWP}}
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
</section>

View File

@ -9,16 +9,23 @@
{{#if (eq rollType "resource")}}
<legend>{{localize "CTHULHUETERNAL.Label.resourceRating"}}</legend>
<div class="dialog-skill">{{rollItem.name}} : <span class="resource-score">{{initialScore}} ({{mul initialScore 5}}%)</span></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Hand"}} : {{rollItem.hand}} <input type="checkbox" data-action="selectHand" {{checked rollItem.enableHand}}></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Stowed"}} : {{rollItem.stowed}} <input type="checkbox" data-action="selectStowed" {{checked rollItem.enableStowed}}></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}} <input type="checkbox" data-action="selectStorage" {{checked rollItem.enableStorage}}></div>
<div class="dialog-skill">{{rollItem.name}} : <span class="resource-score">{{initialScore}} ({{mul initialScore 5}}%)</span></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Hand"}} : {{rollItem.hand}} <input type="checkbox" data-action="selectHand" {{checked rollItem.enableHand}}></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Stowed"}} : {{rollItem.stowed}} <input type="checkbox" data-action="selectStowed" {{checked rollItem.enableStowed}}></div>
<div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}} <input type="checkbox" data-action="selectStorage" {{checked rollItem.enableStorage}}></div>
{{else}}
<div class="dialog-skill">{{rollItem.name}} : {{initialScore}}%</div>
{{/if}}
{{#if weapon}}
<div class="dialog-skill">Weapon : {{weapon.name}}</div>
{{#if weapon.system.hasSelectiveFire}}
<div class="dialog-skill">Selective Fire :
<select name="selectiveFireChoice" class="roll-skill-modifier">
{{selectOptions choiceSelectiveFire localize=true selected=selectiveFireChoice nameAttr="id" labelAttr="label"}}
</select>
</div>
{{/if}}
{{/if}}
{{#if isZeroWP}}
@ -35,6 +42,7 @@
</fieldSet>
{{#if hasModifier}}
<fieldSet class="dialog-modifier">
<legend>{{localize "CTHULHUETERNAL.Label.modifier"}}</legend>
@ -56,7 +64,7 @@
<fieldSet>
<legend>{{localize "CTHULHUETERNAL.Label.rollView"}}</legend>
<select name="visibility">
{{selectOptions rollModes selected=visibility}}
{{selectOptions rollModes localize=true selected=visibility}}
</select>
</fieldSet>
</div>

42
templates/tome.hbs Normal file
View File

@ -0,0 +1,42 @@
<section>
<div class="header">
<img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" />
{{formInput fields.name value=source.name}}
</div>
<fieldset>
<div class="form-group">
{{formField systemFields.language value=system.language }}
</div>
<div class="form-group">
{{formField systemFields.minimumEra value=system.minimumEra localize=true }}
</div>
<div class="form-group">
{{formField systemFields.creationDate value=system.creationDate }}
</div>
<div class="form-group">
{{formField systemFields.studyTime value=system.studyTime }}
</div>
<div class="form-group">
{{formField systemFields.sanLoss value=system.sanLoss }}
</div>
<div class="form-group">
{{formField systemFields.unnaturalSkill value=system.unnaturalSkill }}
</div>
<div class="form-group">
<label>{{localize "CTHULHUETERNAL.Label.Rituals"}} </label>
<textarea class="form-control" rows="3" name="system.rituals" data-tooltip="{{localize "CTHULHUETERNAL.Label.Rituals"}}">{{system.rituals}}</textarea>
</div>
<div class="form-group">
<label>{{localize "CTHULHUETERNAL.Label.otherBenefits"}} </label>
<textarea class="form-control" rows="3" name="system.otherBenefits" data-tooltip="{{localize "CTHULHUETERNAL.Label.otherBenefits"}}">{{system.otherBenefits}}</textarea>
</div>
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
</section>

View File

@ -1,12 +1,13 @@
<section class="tab vehicle-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}}
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.notes"}}</legend>
{{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}}
</fieldset>
</div>
</section>

View File

@ -1,5 +1,5 @@
<section class="tab vehicle-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<div class="main-div">
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.weapons"}}{{#if isEditMode}}
<a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i
@ -50,5 +50,5 @@
{{/each}}
</div>
</fieldset>
</div>
</section>

View File

@ -13,7 +13,15 @@
{{formField systemFields.state value=system.state localize=true}}
{{formField systemFields.hasDirectSkill value=system.hasDirectSkill }}
{{#if system.hasDirectSkill}}
{{formField systemFields.directSkillValue value=system.directSkillValue }}
{{/if}}
{{formField systemFields.hasSelectiveFire value=system.hasSelectiveFire}}
{{formField systemFields.applyDamageBonus value=system.applyDamageBonus}}
{{formField systemFields.damage value=system.damage}}
{{formField systemFields.baseRange value=system.baseRange}}
{{formField systemFields.rangeUnit value=system.rangeUnit localize=true}}
{{formField systemFields.lethality value=system.lethality}}
@ -23,12 +31,12 @@
{{formField systemFields.resourceLevel value=system.resourceLevel}}
</fieldset>
<fieldset>
<legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend>
{{formInput
systemFields.description
enriched=description
enriched=enrichedDescription
value=system.description
name="system.description"
toggled=true