Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
ecb7fc2757 | |||
1fde7e4d2c | |||
b5a0405403 | |||
36279aa6eb | |||
d5eba47ab6 | |||
b21c5ac9bb | |||
a43bebc63b | |||
2b418695c4 | |||
5dbb168891 | |||
009024296c | |||
968c7da5c5 | |||
67ff06f953 | |||
24c5c685d0 | |||
d62b5472fe | |||
a1ef74a3ad | |||
ff89b62133 | |||
b3eb908f05 | |||
2ac0f53c4f | |||
270471f137 | |||
da9d0e41a5 | |||
42f25aa186 | |||
5f9057db37 | |||
82731c2d40 | |||
a75a3bf157 | |||
e6e6de35df | |||
7341580a7b | |||
75a81e589b | |||
74f237c30f | |||
440e5c0b66 | |||
554220a812 | |||
e7ea8138c9 | |||
6a18f7fa29 | |||
7070d4c1da | |||
3b79a19ca5 | |||
f882a04c0b | |||
eda24442e8 | |||
0ec2d53415 | |||
401a94da40 | |||
7758085bf8 | |||
70c4fd5a74 | |||
03a54d86e6 | |||
3adb34d721 | |||
034a60bf19 | |||
522bb08d35 | |||
c144488d1d | |||
704dd83b1b | |||
3aab98b4b4 | |||
2c05594a7e | |||
ce1844a070 | |||
fa7d3ecfca | |||
adb4923d00 | |||
44842ff655 | |||
4671f6f9fe | |||
50b7bafb43 | |||
2c3a92994a | |||
dfe4aa0c56 | |||
efc23f466b | |||
1b1c2b0cfd | |||
e0f02ecacb | |||
4e39c5d0dc | |||
9f13961eaf | |||
3d6cd35fa4 | |||
33c11e2c05 | |||
b600148247 | |||
c0d240c5d0 | |||
d6a1b2c62a | |||
82139eb634 |
63
.gitea/workflows/release.yaml
Normal file
63
.gitea/workflows/release.yaml
Normal file
@ -0,0 +1,63 @@
|
||||
name: Release Creation
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- run: echo "💡 The ${{ gitea.repository }} repository will cloned to the runner."
|
||||
|
||||
#- uses: actions/checkout@v3
|
||||
- uses: RouxAntoine/checkout@v3.5.4
|
||||
|
||||
# get part of the tag after the `v`
|
||||
- name: Extract tag version number
|
||||
id: get_version
|
||||
uses: battila7/get-version-action@v2
|
||||
|
||||
# Substitute the Manifest and Download URLs in the module.json
|
||||
- name: Substitute Manifest and Download Links For Versioned Ones
|
||||
id: sub_manifest_link_version
|
||||
uses: microsoft/variable-substitution@v1
|
||||
with:
|
||||
files: 'system.json'
|
||||
env:
|
||||
version: ${{steps.get_version.outputs.version-without-v}}
|
||||
url: https://www.uberwald.me/gitea/${{gitea.repository}}
|
||||
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
|
||||
- run: |
|
||||
apt update -y
|
||||
apt install -y zip
|
||||
|
||||
- run: zip -r ./fvtt-cthulhu-eternal.zip system.json README.md LICENSE assets/ css/ fonts/ lang/ module/ packs-system/ templates/ cthulhu-eternal.mjs
|
||||
|
||||
- name: setup go
|
||||
uses: https://github.com/actions/setup-go@v4
|
||||
with:
|
||||
go-version: '>=1.20.1'
|
||||
|
||||
- name: Use Go Action
|
||||
id: use-go-action
|
||||
uses: https://gitea.com/actions/release-action@main
|
||||
with:
|
||||
files: |-
|
||||
./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'
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -6,6 +6,3 @@ styles/*.css
|
||||
# Node Modules
|
||||
node_modules/
|
||||
|
||||
# Foundry VTT
|
||||
packs/*
|
||||
|
||||
|
15
README.md
15
README.md
@ -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)
|
||||
|
BIN
assets/fonts/Chantelli_Antiqua.ttf
Normal file
BIN
assets/fonts/Chantelli_Antiqua.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/FeFCrm2.ttf
Normal file
BIN
assets/fonts/FeFCrm2.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/FeGPrm2.ttf
Normal file
BIN
assets/fonts/FeGPrm2.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/IMFeDPrm28P.ttf
Normal file
BIN
assets/fonts/IMFeDPrm28P.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Sail-Regular.ttf
Normal file
BIN
assets/fonts/Sail-Regular.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Skranji-Bold.ttf
Normal file
BIN
assets/fonts/Skranji-Bold.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Skranji-Regular.ttf
Normal file
BIN
assets/fonts/Skranji-Regular.ttf
Normal file
Binary file not shown.
258
assets/fonts/Skranji.g2n
Normal file
258
assets/fonts/Skranji.g2n
Normal 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
BIN
assets/fonts/Skranji.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/Skranji.woff
Normal file
BIN
assets/fonts/Skranji.woff
Normal file
Binary file not shown.
BIN
assets/fonts/Skranji.woff2
Normal file
BIN
assets/fonts/Skranji.woff2
Normal file
Binary file not shown.
1
assets/icons/icon_fist.svg
Normal file
1
assets/icons/icon_fist.svg
Normal 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="M227.227 21.777c-1.845 0-3.704.05-5.567.157-15.314.875-30.76 5.305-39.494 10.863l-.008 73.15c2.884-.094 5.777-.147 8.676-.142 23.382.036 47.104 3.286 68.47 9.513l.01-87.507c-7.034-3.518-19.178-6.03-32.087-6.033zm80.74 9.16c-11.925.15-23.077 2.364-29.967 5.596l-.008 77.602v7.658c38.486 15.67 64.814 42.48 58.735 78.764l-.96 5.73-5.562 1.674c-17.45 5.253-34.872 9.703-52.225 13.335V246.53c25.562-.704 51.327-2.687 77.145-6.098l.02-197.928c-8.284-5.563-23.508-10.243-38.842-11.328-2.792-.198-5.584-.273-8.336-.238zM143.223 46.294c-1.176-.015-2.374-.01-3.588.02-4.175.1-8.533.468-12.903 1.152-15.67 2.454-31.477 8.565-40.406 15.402l-.01 72.955c18.808-15.81 46.704-25.143 77.15-28.54l.007-57.966c-4.82-1.752-12.018-2.916-20.25-3.023zm258.394 3.46c-10.804.117-20.722 1.93-27.043 4.655l-.02 183.182c25.074-4.02 50.16-9.412 75.122-16.358l1.99-158.447c-8.352-5.9-23.648-11.025-39.05-12.553-3.698-.366-7.398-.517-11-.478zm-222.775 74.202c-53.72.702-101.407 20.365-97.887 66.6 15.836-3.918 30.84-5.893 44.94-6.1 34.84-.51 64.213 9.704 87.318 27.613 34.608-3.11 69.852-10 105.412-20.314.14-41.287-74.098-68.657-139.783-67.8zm-48.877 78.65c-1.296-.003-2.603.012-3.92.045-17.256.436-36.45 4.03-57.566 11.037 5.79 53.808 26.325 106.41 58.5 143.346 6.226 7.15 12.856 13.712 19.875 19.615 29.303 9.282 69.26 12.917 110.534 12.14 3.777-55.805-8.717-108.357-36.193-142.74-21.265-26.61-51.064-43.39-91.232-43.444zm129.326 22.282c-9.358 1.637-18.69 3.016-27.995 4.15 1.54 1.74 3.043 3.52 4.502 5.346 3.146 3.937 6.094 8.062 8.873 12.334 9.916.144 19.868.125 29.857-.106H259.29v-21.723zm191.817 15.343c-65.406 17.826-131.462 25.41-195.85 25.315 16.998 35.144 23.828 78.093 21.013 122.6 42.482-2.08 85.03-8.23 118.187-15.983 26.693-32.78 47.37-77.118 56.65-131.932zM400.51 389.9c-38.334 9.145-87.95 16.056-136.873 17.454-47.67 1.36-94.336-2.228-129.448-15.262l-.01 78.93c27.187 12.568 76.414 20.205 127.318 20.298 51.224.094 104.214-7.173 139-20.773l.012-80.647z" fill="#a7de9a" fill-opacity="1" filter="url(#shadow-1)"></path></g></svg>
|
After Width: | Height: | Size: 2.6 KiB |
1
assets/icons/icon_ritual.svg
Normal file
1
assets/icons/icon_ritual.svg
Normal 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 |
1
assets/icons/icon_tome.svg
Normal file
1
assets/icons/icon_tome.svg
Normal 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 |
BIN
assets/ui/background_01.webp
Normal file
BIN
assets/ui/background_01.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 77 KiB |
47
assets/ui/d100.svg
Normal file
47
assets/ui/d100.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 12 KiB |
13
changelog.md
Normal file
13
changelog.md
Normal 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
@ -12,11 +12,9 @@ import * as documents from "./module/documents/_module.mjs"
|
||||
import * as applications from "./module/applications/_module.mjs"
|
||||
|
||||
import { handleSocketEvent } from "./module/socket.mjs"
|
||||
import { Macros } from "./module/macros.mjs"
|
||||
import { setupTextEnrichers } from "./module/enrichers.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")
|
||||
@ -34,7 +32,9 @@ Hooks.once("init", function () {
|
||||
|
||||
CONFIG.Actor.documentClass = documents.CthulhuEternalActor
|
||||
CONFIG.Actor.dataModels = {
|
||||
protagonist: models.CthulhuEternalProtagonist
|
||||
protagonist: models.CthulhuEternalProtagonist,
|
||||
vehicle: models.CthulhuEternalVehicle,
|
||||
creature: models.CthulhuEternalCreature
|
||||
}
|
||||
|
||||
CONFIG.Item.documentClass = documents.CthulhuEternalItem
|
||||
@ -48,24 +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 })
|
||||
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
|
||||
@ -84,25 +90,14 @@ Hooks.once("init", function () {
|
||||
// Activate socket handler
|
||||
game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent)
|
||||
|
||||
setupTextEnrichers()
|
||||
CthulhuEternalUtils.registerSettings()
|
||||
CthulhuEternalUtils.registerHandlebarsHelpers()
|
||||
CthulhuEternalUtils.setupCSSRootVariables()
|
||||
|
||||
// Gestion des jets de dés depuis les journaux
|
||||
document.addEventListener("click", (event) => {
|
||||
const anchor = event.target.closest("a.ask-roll-journal")
|
||||
if (!anchor) return
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
const type = anchor.dataset.rollType
|
||||
const target = anchor.dataset.rollTarget
|
||||
const title = anchor.dataset.rollTitle
|
||||
})
|
||||
|
||||
console.info("CTHULHU ETERNAL | System Initialized")
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Perform one-time configuration of system configuration objects.
|
||||
*/
|
||||
@ -118,46 +113,28 @@ function preLocalizeConfig() {
|
||||
|
||||
Hooks.once("ready", function () {
|
||||
console.info("CTHULHU ETERNAL | Ready")
|
||||
ClassCounter.registerUsageCount("fvtt-cthulhu-eternal", {})
|
||||
_showUserGuide()
|
||||
|
||||
/* Display the user guide */
|
||||
async function _showUserGuide() {
|
||||
if (game.user.isGM) {
|
||||
const newVer = game.system.version
|
||||
}
|
||||
if (game.user.isGM) {
|
||||
ClassCounter.registerUsageCount("fvtt-cthulhu-eternal", {})
|
||||
}
|
||||
preLocalizeConfig()
|
||||
|
||||
})
|
||||
|
||||
Hooks.on("renderChatMessage", (message, html, data) => {
|
||||
const typeMessage = data.message.flags.CthulhuEternal?.typeMessage
|
||||
// Message de demande de jet de dés
|
||||
if (typeMessage === "askRoll") {
|
||||
// Affichage des boutons de jet de dés uniquement pour les joueurs
|
||||
if (game.user.isGM) {
|
||||
html.find(".ask-roll-dice").each((i, btn) => {
|
||||
btn.style.display = "none"
|
||||
})
|
||||
} else {
|
||||
html.find(".ask-roll-dice").click((event) => {
|
||||
const btn = $(event.currentTarget)
|
||||
const type = btn.data("type")
|
||||
const value = btn.data("value")
|
||||
const avantage = btn.data("avantage") ?? "="
|
||||
const character = game.user.character
|
||||
if (type === SYSTEM.ROLL_TYPE.RESOURCE) character.rollResource(value)
|
||||
else if (type === SYSTEM.ROLL_TYPE.SAVE) character.rollSave(value, avantage)
|
||||
})
|
||||
}
|
||||
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) => {
|
||||
btn.style.display = "inline"
|
||||
})
|
||||
$(html).find(".nudge-roll").click((event) => {
|
||||
CthulhuEternalUtils.nudgeRoll(message)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
Hooks.on("updateSetting", async (setting, update, options, id) => {
|
||||
})
|
||||
|
||||
// Dice-so-nice Ready
|
||||
Hooks.once("diceSoNiceReady", (dice3d) => {
|
||||
configureDiceSoNice(dice3d)
|
||||
//configureDiceSoNice(dice3d)
|
||||
})
|
||||
|
||||
/**
|
||||
@ -167,18 +144,8 @@ Hooks.once("diceSoNiceReady", (dice3d) => {
|
||||
* Journal - open journal sheet
|
||||
*/
|
||||
Hooks.on("hotbarDrop", (bar, data, slot) => {
|
||||
if (["Actor", "Item", "JournalEntry", "roll", "rollDamage", "rollAttack"].includes(data.type)) {
|
||||
Macros.createCthulhuEternalMacro(data, slot);
|
||||
if (["Actor", "Item", "JournalEntry", "skill", "weapon"].includes(data.type)) {
|
||||
// TODO -> Manage this
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Register world usage statistics
|
||||
* @param {string} registerKey
|
||||
*/
|
||||
function registerWorldCount(registerKey) {
|
||||
if (game.user.isGM) {
|
||||
ClassCounter.registerUsageCount(game.system.id, {})
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
const gulp = require('gulp');
|
||||
const less = require('gulp-less');
|
||||
|
||||
function onError(err) {
|
||||
util.log(util.colors.red.bold('[ERROR LESS]:'),util.colors.bgRed(err.message));
|
||||
this.emit('end');
|
||||
};
|
||||
|
||||
/* ----------------------------------------- */
|
||||
/* Compile LESS
|
||||
/* ----------------------------------------- */
|
||||
function compileLESS() {
|
||||
return gulp.src("styles/fvtt-cthulhu-eternal.less")
|
||||
.pipe(less())
|
||||
.pipe(less()).on('error',console.log.bind(console))
|
||||
.pipe(gulp.dest("./css"))
|
||||
}
|
||||
const css = gulp.series(compileLESS);
|
||||
|
310
lang/en.json
310
lang/en.json
@ -1,7 +1,9 @@
|
||||
{
|
||||
"TYPES": {
|
||||
"Actor": {
|
||||
"protagonist": "Protagonist"
|
||||
"protagonist": "Protagonist",
|
||||
"vehicle": "Vehicle",
|
||||
"creature": "Creature"
|
||||
},
|
||||
"Item": {
|
||||
"skill": "Skill",
|
||||
@ -13,11 +15,15 @@
|
||||
"mentaldisorder": "Mental Disorder",
|
||||
"bond": "Bond" ,
|
||||
"arcane": "Arcane",
|
||||
"archetype": "Archetype"
|
||||
"archetype": "Archetype",
|
||||
"ritual": "Ritual",
|
||||
"tome": "Tome"
|
||||
}
|
||||
},
|
||||
"CTHULHUETERNAL": {
|
||||
"Settings": {
|
||||
"era": "Select the era of your game",
|
||||
"eraHint": "Select the era of your game",
|
||||
"Common": "Common",
|
||||
"Classical": "Classical",
|
||||
"Medieval": "Medieval",
|
||||
@ -34,7 +40,33 @@
|
||||
},
|
||||
"Protagonist": {
|
||||
"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"
|
||||
},
|
||||
@ -83,6 +115,89 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"Submit": "Submit",
|
||||
"Struggle": "Struggle"
|
||||
},
|
||||
"Skill": {
|
||||
"Unnatural": "Unnatural",
|
||||
"Melee": "Melee Weapons",
|
||||
@ -97,7 +212,7 @@
|
||||
},
|
||||
"settings": {
|
||||
"label": "Settings era"
|
||||
},
|
||||
},
|
||||
"diceEvolved": {
|
||||
"label": "Can increase on failure"
|
||||
},
|
||||
@ -120,6 +235,9 @@
|
||||
"resourceLevel": {
|
||||
"label": "Resource level"
|
||||
},
|
||||
"state": {
|
||||
"label": "State"
|
||||
},
|
||||
"settings": {
|
||||
"label": "Settings era"
|
||||
}
|
||||
@ -147,7 +265,22 @@
|
||||
"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"
|
||||
},
|
||||
"settings": {
|
||||
"label": "Settings era"
|
||||
},
|
||||
@ -157,6 +290,12 @@
|
||||
"weaponSubtype": {
|
||||
"label": "Firearm Subtype"
|
||||
},
|
||||
"hasSelectiveFire": {
|
||||
"label": "Has selective fire"
|
||||
},
|
||||
"applyDamageBonus": {
|
||||
"label": "Add damage bonus"
|
||||
},
|
||||
"damage": {
|
||||
"label": "Damage"
|
||||
},
|
||||
@ -203,10 +342,41 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Vehicle": {
|
||||
"FIELDS": {
|
||||
"description": {
|
||||
"label": "Description"
|
||||
},
|
||||
"notes": {
|
||||
"label": "Notes"
|
||||
},
|
||||
"surfaceSpeed": {
|
||||
"label": "Surface Speed"
|
||||
},
|
||||
"airSpeed": {
|
||||
"label": "Air Speed"
|
||||
},
|
||||
"armor": {
|
||||
"label": "Armor"
|
||||
},
|
||||
"settings": {
|
||||
"label": "Settings era"
|
||||
},
|
||||
"crew": {
|
||||
"label": "Crew"
|
||||
},
|
||||
"state": {
|
||||
"label": "State"
|
||||
}
|
||||
}
|
||||
},
|
||||
"MentalDisorder": {
|
||||
"FIELDS": {
|
||||
"description": {
|
||||
"label": "Description"
|
||||
},
|
||||
"cured": {
|
||||
"label": "Cured"
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -237,7 +407,7 @@
|
||||
"FIELDS": {
|
||||
"settings": {
|
||||
"label": "Settings era"
|
||||
},
|
||||
},
|
||||
"value": {
|
||||
"label": "Value"
|
||||
},
|
||||
@ -255,9 +425,111 @@
|
||||
"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": {
|
||||
"titleSkill": "Skill",
|
||||
"titleWeapon": "Weapon",
|
||||
"creature": "Creature",
|
||||
"Rituals": "Rituals",
|
||||
"Tomes": "Tomes",
|
||||
"otherBenefits": "Other Benefits",
|
||||
"Unarmed": "Unarmed",
|
||||
"Cured": "Cured",
|
||||
"Uncured": "Uncured",
|
||||
"nudgedRoll": "Nudged Roll",
|
||||
"selectNewValue": "Select the new value",
|
||||
"wpCost": "WP Cost",
|
||||
"Hand": "Hand",
|
||||
"Stowed": "Stowed",
|
||||
"Storage": "Storage",
|
||||
"resourceRating": "Resource rating",
|
||||
"Resources": "Resources",
|
||||
"multiplier": "Multiplier",
|
||||
"setBP": "Set BP",
|
||||
"Vehicle": "Vehicle",
|
||||
"Speed": "Speed",
|
||||
"Slow": "Slow",
|
||||
"Fast": "Fast",
|
||||
"Average": "Average",
|
||||
"None": "None",
|
||||
"Pristine": "Pristine",
|
||||
"Worn": "Worn",
|
||||
"Junk": "Junk",
|
||||
"resources": "Resources",
|
||||
"resourceChecks": "Resource Checks",
|
||||
"sanBPShort": "BP",
|
||||
"tempInsanity": "Temp. Insanity",
|
||||
"distinguishingFeatures": "Distinguishing Features",
|
||||
"titleSkill": "Skill Roll",
|
||||
"titleWeapon": "Weapon Roll",
|
||||
"titleCharacteristic": "Characteristic Roll",
|
||||
"titleSAN": "SAN Roll",
|
||||
"biodata": "Biodata",
|
||||
"skill": "Skill",
|
||||
"modifier": "Modifier",
|
||||
@ -270,7 +542,7 @@
|
||||
"intShort": "INT",
|
||||
"powShort": "POW",
|
||||
"conShort": "CON",
|
||||
"chaShort": "CHA",
|
||||
"chaShort": "CHA",
|
||||
"strLong": "Strength",
|
||||
"dexLong": "Dexterity",
|
||||
"intLong": "Intelligence",
|
||||
@ -309,6 +581,7 @@
|
||||
"criticalSuccess": "Critical Success",
|
||||
"criticalFailure": "Critical Failure",
|
||||
"Characteristic": "Characteristic",
|
||||
"characteristic": "Characteristic",
|
||||
"targetScore": "Target Score",
|
||||
"gears": "Gears",
|
||||
"armors": "Armors",
|
||||
@ -331,7 +604,12 @@
|
||||
"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."
|
||||
},
|
||||
"Edit": "Edit",
|
||||
"Delete": "Delete",
|
||||
@ -341,14 +619,22 @@
|
||||
},
|
||||
"Roll": {
|
||||
"skill": "Skill",
|
||||
"roll": "Roll"
|
||||
"roll": "Roll",
|
||||
"applyNudge": "Apply",
|
||||
"cancel": "Cancel",
|
||||
"nudgeRoll": "Nudge Roll"
|
||||
},
|
||||
"Tooltip": {
|
||||
"sanBP": ">5 SAN lost in one roll, temporary insanity. If SAN less reaches BP = a Disorder unconscious Breaking and AND reset BP."
|
||||
},
|
||||
"Setting": {
|
||||
"sanBP": ">5 SAN lost in one roll, temporary insanity. If SAN less reaches BP = a Disorder unconscious Breaking and AND reset BP.",
|
||||
"setBP": "Set the current Breaking Point based on the current SAN value"
|
||||
},
|
||||
"Chat": {
|
||||
},
|
||||
"Notifications": {
|
||||
"NoWeaponSkill": "No weapon skill found for this weapon. Check Weapon definition or available skills/era",
|
||||
"NoWeaponType": "No weapon type found for this weapon subtype. Check Weapon definition or available skills/era",
|
||||
"skillAlreadyExists": "Skill already exists",
|
||||
"WrongEra": "The era of the item does not match the ear of the system"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,3 +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"
|
||||
|
294
module/applications/hud/action-handler.js
Normal file
294
module/applications/hud/action-handler.js
Normal 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() {
|
||||
}
|
||||
}
|
||||
})
|
38
module/applications/hud/constants.js
Normal file
38
module/applications/hud/constants.js
Normal 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' }
|
||||
}
|
49
module/applications/hud/defaults.js
Normal file
49
module/applications/hud/defaults.js
Normal 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
|
||||
}
|
||||
})
|
304
module/applications/hud/roll-handler.js
Normal file
304
module/applications/hud/roll-handler.js
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
91
module/applications/hud/system-manager.js
Normal file
91
module/applications/hud/system-manager.js
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
55
module/applications/hud/utils.js
Normal file
55
module/applications/hud/utils.js
Normal 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`)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 })
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
175
module/applications/sheets/creature-sheet.mjs
Normal file
175
module/applications/sheets/creature-sheet.mjs
Normal 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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -18,4 +18,12 @@ export default class CthulhuEternalMentalDisorderSheet extends CthulhuEternalIte
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/mentaldisorder.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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -22,6 +22,8 @@ export default class CthulhuEternalMotivationSheet extends CthulhuEternalItemShe
|
||||
/** @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
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,13 +5,14 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["protagonist"],
|
||||
position: {
|
||||
width: 848,
|
||||
width: 860,
|
||||
height: 620,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["protagonist-content"],
|
||||
},
|
||||
actions: {
|
||||
setBP: CthulhuEternalProtagonistSheet.#onSetBP,
|
||||
createGear: CthulhuEternalProtagonistSheet.#onCreateGear,
|
||||
createArmor: CthulhuEternalProtagonistSheet.#onCreateArmor,
|
||||
createWeapon: CthulhuEternalProtagonistSheet.#onCreateWeapon,
|
||||
@ -19,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,
|
||||
},
|
||||
}
|
||||
|
||||
@ -73,6 +76,9 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
const context = await super._prepareContext()
|
||||
context.tabs = this.#getTabs()
|
||||
|
||||
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"),
|
||||
@ -82,23 +88,9 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
cha: game.i18n.localize("CTHULHUETERNAL.Characteristic.Cha")
|
||||
}
|
||||
|
||||
context.tooltipsRessources = {
|
||||
}
|
||||
|
||||
context.rollType = {
|
||||
str: "characteristic",
|
||||
dex: "characteristic",
|
||||
con: "characteristic",
|
||||
int: "characteristic",
|
||||
pow: "characteristic",
|
||||
cha: "characteristic"
|
||||
}
|
||||
return context
|
||||
}
|
||||
|
||||
_generateTooltip(type, target) {
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
const doc = this.document
|
||||
@ -108,24 +100,36 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
case "skills":
|
||||
context.tab = context.tabs.skills
|
||||
context.skills = doc.itemTypes.skill
|
||||
context.skills.sort((a, b) => a.name.localeCompare(b.name))
|
||||
break
|
||||
case "equipment":
|
||||
context.tab = context.tabs.equipment
|
||||
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))
|
||||
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
|
||||
context.injuries = doc.itemTypes.injury
|
||||
context.injuries.sort((a, b) => a.name.localeCompare(b.name))
|
||||
context.mentaldisorders = doc.itemTypes.mentaldisorder
|
||||
context.mentaldisorders.sort((a, b) => a.name.localeCompare(b.name))
|
||||
context.motivations = doc.itemTypes.motivation
|
||||
context.motivations.sort((a, b) => a.name.localeCompare(b.name))
|
||||
context.bonds = doc.itemTypes.bond
|
||||
context.bonds.sort((a, b) => a.name.localeCompare(b.name))
|
||||
break
|
||||
case "biography":
|
||||
context.tab = context.tabs.biography
|
||||
context.motivations = doc.itemTypes.motivation
|
||||
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
|
||||
@ -136,6 +140,10 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
* @param {Event} event The initiating click event.
|
||||
* @param {HTMLElement} target The current target of the event listener.
|
||||
*/
|
||||
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" }])
|
||||
}
|
||||
@ -168,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.
|
||||
*
|
||||
@ -189,10 +205,15 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
// Debug : console.log(">>>>", event, target, rollType)
|
||||
// Deprecated : if (this.isEditMode) return
|
||||
switch (rollType) {
|
||||
case "resource":
|
||||
item = foundry.utils.duplicate(this.actor.system.resources)
|
||||
item.name = game.i18n.localize(`CTHULHUETERNAL.Label.Resources`)
|
||||
item.targetScore = item.permanentRating
|
||||
break
|
||||
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.name = game.i18n.localize(`CTHULHUETERNAL.Label.${charId}Long`)
|
||||
item.targetScore = item.value * 5
|
||||
break
|
||||
case "skill":
|
||||
@ -203,7 +224,13 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
case "damage":
|
||||
li = $(event.currentTarget).parents(".item");
|
||||
item = this.actor.items.get(li.data("item-id"));
|
||||
item.damageBonus = this.actor.system.damageBonus
|
||||
break
|
||||
case "san":
|
||||
item = foundry.utils.duplicate(this.actor.system.san)
|
||||
item.name = game.i18n.localize("CTHULHUETERNAL.Label.SAN")
|
||||
item.targetScore = item.value
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unknown roll type ${rollType}`)
|
||||
}
|
||||
@ -222,5 +249,4 @@ export default class CthulhuEternalProtagonistSheet extends CthulhuEternalActorS
|
||||
}
|
||||
}
|
||||
|
||||
// #endregion
|
||||
}
|
||||
|
28
module/applications/sheets/ritual-sheet.mjs
Normal file
28
module/applications/sheets/ritual-sheet.mjs
Normal 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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
28
module/applications/sheets/tome-sheet.mjs
Normal file
28
module/applications/sheets/tome-sheet.mjs
Normal 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
|
||||
}
|
||||
}
|
117
module/applications/sheets/vehicle-sheet.mjs
Normal file
117
module/applications/sheets/vehicle-sheet.mjs
Normal file
@ -0,0 +1,117 @@
|
||||
import CthulhuEternalActorSheet from "./base-actor-sheet.mjs"
|
||||
|
||||
export default class CthulhuEternalVehicleSheet extends CthulhuEternalActorSheet {
|
||||
/** @override */
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ["vehicle"],
|
||||
position: {
|
||||
width: 680,
|
||||
height: 540,
|
||||
},
|
||||
window: {
|
||||
contentClasses: ["vehicle-content"],
|
||||
},
|
||||
actions: {
|
||||
createGear: CthulhuEternalVehicleSheet.#onCreateGear,
|
||||
createWeapon: CthulhuEternalVehicleSheet.#onCreateWeapon,
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/vehicle-main.hbs",
|
||||
},
|
||||
tabs: {
|
||||
template: "templates/generic/tab-navigation.hbs",
|
||||
},
|
||||
equipment: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/vehicle-equipment.hbs",
|
||||
},
|
||||
description: {
|
||||
template: "systems/fvtt-cthulhu-eternal/templates/vehicle-description.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
/** @override */
|
||||
tabGroups = {
|
||||
sheet: "equipment",
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an array of form header tabs.
|
||||
* @returns {Record<string, Partial<ApplicationTab>>}
|
||||
*/
|
||||
#getTabs() {
|
||||
const tabs = {
|
||||
equipment: { id: "equipment", group: "sheet", icon: "fa-solid fa-shapes", label: "CTHULHUETERNAL.Label.equipment" },
|
||||
description: { id: "description", group: "sheet", icon: "fa-solid fa-book", label: "CTHULHUETERNAL.Label.description" },
|
||||
}
|
||||
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 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
|
||||
}
|
||||
|
||||
_generateTooltip(type, target) {
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async _preparePartContext(partId, context) {
|
||||
const doc = this.document
|
||||
switch (partId) {
|
||||
case "main":
|
||||
break
|
||||
case "equipment":
|
||||
context.tab = context.tabs.equipment
|
||||
context.weapons = doc.itemTypes.weapon
|
||||
context.gears = doc.itemTypes.gear
|
||||
break
|
||||
case "description":
|
||||
context.tab = context.tabs.description
|
||||
context.enrichedDescription = await TextEditor.enrichHTML(doc.system.description, { async: true })
|
||||
context.enrichedNotes = await TextEditor.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 #onCreateGear(event, target) {
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newGear"), type: "gear" }])
|
||||
}
|
||||
|
||||
static #onCreateWeapon(event, target) {
|
||||
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("CTHULHUETERNAL.Label.newWeapon"), type: "weapon" }])
|
||||
}
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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"],
|
||||
|
@ -6,16 +6,16 @@ import * as BOND from "./bond.mjs"
|
||||
export const SYSTEM_ID = "fvtt-cthulhu-eternal"
|
||||
|
||||
export const ASCII = `
|
||||
▄████▄ ▄▄▄█████▓ ██░ ██ █ ██ ██▓ ██░ ██ █ ██ ▓█████▄▄▄█████▓▓█████ ██▀███ ███▄ █ ▄▄▄ ██▓
|
||||
▒██▀ ▀█ ▓ ██▒ ▓▒▓██░ ██▒ ██ ▓██▒▓██▒ ▓██░ ██▒ ██ ▓██▒ ▓█ ▀▓ ██▒ ▓▒▓█ ▀ ▓██ ▒ ██▒ ██ ▀█ █ ▒████▄ ▓██▒
|
||||
▒▓█ ▄ ▒ ▓██░ ▒░▒██▀▀██░▓██ ▒██░▒██░ ▒██▀▀██░▓██ ▒██░ ▒███ ▒ ▓██░ ▒░▒███ ▓██ ░▄█ ▒▓██ ▀█ ██▒▒██ ▀█▄ ▒██░
|
||||
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█ ░██ ▓▓█ ░██░▒██░ ░▓█ ░██ ▓▓█ ░██░ ▒▓█ ▄░ ▓██▓ ░ ▒▓█ ▄ ▒██▀▀█▄ ▓██▒ ▐▌██▒░██▄▄▄▄██ ▒██░
|
||||
▄████▄ ▄▄▄█████▓ ██░ ██ █ ██ ██▓ ██░ ██ █ ██ ▓█████▄▄▄█████▓▓█████ ██▀███ ███▄ █ ▄▄▄ ██▓
|
||||
▒██▀ ▀█ ▓ ██▒ ▓▒▓██░ ██▒ ██ ▓██▒▓██▒ ▓██░ ██▒ ██ ▓██▒ ▓█ ▀▓ ██▒ ▓▒▓█ ▀ ▓██ ▒ ██▒ ██ ▀█ █ ▒████▄ ▓██▒
|
||||
▒▓█ ▄ ▒ ▓██░ ▒░▒██▀▀██░▓██ ▒██░▒██░ ▒██▀▀██░▓██ ▒██░ ▒███ ▒ ▓██░ ▒░▒███ ▓██ ░▄█ ▒▓██ ▀█ ██▒▒██ ▀█▄ ▒██░
|
||||
▒▓▓▄ ▄██▒░ ▓██▓ ░ ░▓█ ░██ ▓▓█ ░██░▒██░ ░▓█ ░██ ▓▓█ ░██░ ▒▓█ ▄░ ▓██▓ ░ ▒▓█ ▄ ▒██▀▀█▄ ▓██▒ ▐▌██▒░██▄▄▄▄██ ▒██░
|
||||
▒ ▓███▀ ░ ▒██▒ ░ ░▓█▒░██▓▒▒█████▓ ░██████▒░▓█▒░██▓▒▒█████▓ ░▒████▒ ▒██▒ ░ ░▒████▒░██▓ ▒██▒▒██░ ▓██░ ▓█ ▓██▒░██████▒
|
||||
░ ░▒ ▒ ░ ▒ ░░ ▒ ░░▒░▒░▒▓▒ ▒ ▒ ░ ▒░▓ ░ ▒ ░░▒░▒░▒▓▒ ▒ ▒ ░░ ▒░ ░ ▒ ░░ ░░ ▒░ ░░ ▒▓ ░▒▓░░ ▒░ ▒ ▒ ▒▒ ▓▒█░░ ▒░▓ ░
|
||||
░ ▒ ░ ▒ ░▒░ ░░░▒░ ░ ░ ░ ░ ▒ ░ ▒ ░▒░ ░░░▒░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░▒ ░ ▒░░ ░░ ░ ▒░ ▒ ▒▒ ░░ ░ ▒ ░
|
||||
░ ░ ░ ░░ ░ ░░░ ░ ░ ░ ░ ░ ░░ ░ ░░░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ▒ ░ ░
|
||||
░ ░ ░ ░░ ░ ░░░ ░ ░ ░ ░ ░ ░░ ░ ░░░ ░ ░ ░ ░ ░ ░░ ░ ░ ░ ░ ░ ▒ ░ ░
|
||||
░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░ ░
|
||||
░
|
||||
░
|
||||
`
|
||||
|
||||
|
||||
@ -34,19 +34,26 @@ export const AVAILABLE_SETTINGS = {
|
||||
postapo: "CTHULHUETERNAL.Settings.PostApo"
|
||||
}
|
||||
|
||||
export const INSANITY = {
|
||||
"none": "CTHULHUETERNAL.Insanity.None",
|
||||
"flee": "CTHULHUETERNAL.Insanity.Flee",
|
||||
"struggle": "CTHULHUETERNAL.Insanity.Struggle",
|
||||
"submit": "CTHULHUETERNAL.Insanity.Submit"
|
||||
}
|
||||
|
||||
export const ERA_CSS = {
|
||||
jazz: { primaryFont: "RozhaOne", secondaryFont: "RozhaOne", titleFont: "Broadway", 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", imgFilter: "brightness(0) saturate(100%) invert(92%) sepia(11%) saturate(1214%) hue-rotate(51deg) brightness(93%) contrast(86%)" },
|
||||
future: { primaryFont: "Megrim", secondaryFont: "Megrim", titleFont: "Seabreed", imgFilter: "brightness(0) saturate(100%) invert(83%) sepia(30%) saturate(588%) hue-rotate(168deg) brightness(105%) contrast(103%)" },
|
||||
victorian: { primaryFont: "Volkhov", secondaryFont: "Volkhov", titleFont: "Excelsior", imgFilter: "brightness(0) saturate(100%) invert(100%) sepia(59%) saturate(1894%) hue-rotate(337deg) brightness(88%) contrast(98%)" },
|
||||
coldwar: { primaryFont: "BebasNeue", secondaryFont: "BebasNeue", titleFont: "TopSecret", 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", 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", 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", imgFilter: "brightness(0) saturate(100%) invert(95%) sepia(9%) saturate(1471%) hue-rotate(342deg) brightness(103%) contrast(107%)"},
|
||||
ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", imgFilter: "brightness(0) saturate(100%) invert(90%) sepia(38%) saturate(341%) hue-rotate(21deg) brightness(105%) contrast(105%)"},
|
||||
ageofsail: { primaryFont: "Tangerine", secondaryFont: "Tangerine", titleFont: "P22Operina", imgFilter: "brightness(0) saturate(100%) invert(43%) sepia(74%) saturate(3154%) hue-rotate(336deg) brightness(95%) contrast(83%)" },
|
||||
classical: { primaryFont: "SpectralSC", secondaryFont: "SpectralSC", titleFont: "TrajanPro", 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", imgFilter: "brightness(0) saturate(100%) invert(44%) sepia(55%) saturate(2341%) hue-rotate(329deg) brightness(122%) contrast(103%))" }
|
||||
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: "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.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 = {
|
||||
@ -82,6 +89,45 @@ export const RESOURCE_RATING = {
|
||||
}
|
||||
}
|
||||
|
||||
export const RESOURCE_BREAKDOWN = [
|
||||
{ value: 0, hand: 0, stowed: 0, storage: 0, checks: 0},
|
||||
{ value: 1, hand: 1, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 2, hand: 2, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 3, hand: 3, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 4, hand: 4, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 5, hand: 5, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 6, hand: 6, stowed: 0, storage: 0, checks: 1},
|
||||
{ value: 7, hand: 6, stowed: 1, storage: 0, checks: 2},
|
||||
{ value: 8, hand: 6, stowed: 2, storage: 0, checks: 2},
|
||||
{ value: 9, hand: 6, stowed: 3, storage: 0, checks: 2},
|
||||
{ value: 10, hand: 6, stowed: 4, storage: 0, checks: 2},
|
||||
{ value: 11, hand: 6, stowed: 5, storage: 0, checks: 2},
|
||||
{ value: 12, hand: 6, stowed: 6, storage: 0, checks: 2},
|
||||
{ value: 13, hand: 6, stowed: 6, storage: 1, checks: 3},
|
||||
{ value: 14, hand: 6, stowed: 6, storage: 2, checks: 3},
|
||||
{ value: 15, hand: 6, stowed: 6, storage: 3, checks: 3},
|
||||
{ value: 16, hand: 6, stowed: 6, storage: 4, checks: 3},
|
||||
{ value: 17, hand: 6, stowed: 6, storage: 5, checks: 3},
|
||||
{ value: 18, hand: 6, stowed: 6, storage: 6, checks: 3},
|
||||
{ value: 19, hand: 6, stowed: 6, storage: 7, checks: 3},
|
||||
{ value: 20, hand: 6, stowed: 6, storage: 8, checks: 3}
|
||||
]
|
||||
|
||||
export const DAMAGE_BONUS = [ -2, -2, -2, -2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]
|
||||
|
||||
export const VEHICLE_SPEED = {
|
||||
"none": "CTHULHUETERNAL.Label.None",
|
||||
"slow": "CTHULHUETERNAL.Label.Slow",
|
||||
"average": "CTHULHUETERNAL.Label.Average",
|
||||
"fast": "CTHULHUETERNAL.Label.Fast"
|
||||
}
|
||||
|
||||
export const EQUIPMENT_STATES = {
|
||||
"pristine": "CTHULHUETERNAL.Label.Pristine",
|
||||
"worn": "CTHULHUETERNAL.Label.Worn",
|
||||
"junk": "CTHULHUETERNAL.Label.Junk"
|
||||
}
|
||||
|
||||
export const MENTAL_ILLNESS_CURE_SKILL = {
|
||||
jazz: "CTHULHUETERNAL.Skill.Psychoanalyze",
|
||||
modern: "CTHULHUETERNAL.Skill.Psychoanalyze",
|
||||
@ -96,6 +142,13 @@ export const WEAPON_SKILL_MAPPING = {
|
||||
"rangedfirearm": "CTHULHUETERNAL.Skill.Firearms",
|
||||
"unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat"
|
||||
},
|
||||
postapo: {
|
||||
"melee": "CTHULHUETERNAL.Skill.Melee",
|
||||
"rangedprimitive": "CTHULHUETERNAL.Skill.Firearms",
|
||||
"rangedthrown": "CTHULHUETERNAL.Skill.Athletics",
|
||||
"rangedfirearm": "CTHULHUETERNAL.Skill.Firearms",
|
||||
"unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat"
|
||||
},
|
||||
jazz: {
|
||||
"melee": "CTHULHUETERNAL.Skill.Melee",
|
||||
"rangedprimitive": "CTHULHUETERNAL.Skill.Firearms",
|
||||
@ -165,6 +218,40 @@ export const WEAPON_SKILL_MAPPING = {
|
||||
"unarmed": "CTHULHUETERNAL.Skill.UnarmedCombat"
|
||||
}
|
||||
}
|
||||
|
||||
export const MODIFIER_CHOICES = {
|
||||
"-40": "-40",
|
||||
"-20": "-20",
|
||||
"-10": "-10",
|
||||
"+0": "+0",
|
||||
"+10": "+10",
|
||||
"+20": "+20",
|
||||
"+40": "+40",
|
||||
}
|
||||
|
||||
export const MULTIPLIER_CHOICES = {
|
||||
"0.25": "0.25",
|
||||
"0.5": "0.5",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"4": "4",
|
||||
"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}
|
||||
@ -175,11 +262,20 @@ 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,
|
||||
RESOURCE_RATING,
|
||||
MENTAL_ILLNESS_CURE_SKILL,
|
||||
ERA_CSS,
|
||||
ASCII
|
||||
INSANITY,
|
||||
EQUIPMENT_STATES,
|
||||
RESOURCE_BREAKDOWN,
|
||||
VEHICLE_SPEED,
|
||||
MODIFIER_CHOICES,
|
||||
MULTIPLIER_CHOICES,
|
||||
ASCII,
|
||||
DAMAGE_BONUS,
|
||||
RITUAL_TYPES
|
||||
}
|
||||
|
@ -17,4 +17,4 @@ export const WEAPON_SUBTYPE = {
|
||||
export const WEAPON_RANGE_UNIT = {
|
||||
"yard": "CTHULHUETERNAL.Weapon.RangeUnit.yard",
|
||||
"meter": "CTHULHUETERNAL.Weapon.RangeUnit.meter"
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import CthulhuEternalUtils from "../utils.mjs"
|
||||
|
||||
export default class CthulhuEternalActor extends Actor {
|
||||
|
||||
|
||||
static async create(data, options) {
|
||||
|
||||
// Case of compendium global import
|
||||
@ -19,29 +19,68 @@ export default class CthulhuEternalActor extends Actor {
|
||||
const skills = await CthulhuEternalUtils.loadCompendium("fvtt-cthulhu-eternal.skills")
|
||||
data.items = data.items || []
|
||||
for (let skill of skills) {
|
||||
if (skill.system.settings === era ) {
|
||||
if (skill.system.settings === era) {
|
||||
data.items.push(skill.toObject())
|
||||
}
|
||||
}
|
||||
data.items.push({ type:"weapon", img: "systems/fvtt-cthulhu-eternal/assets/icons/icon_fist.svg",
|
||||
name: game.i18n.localize("CTHULHUETERNAL.Label.Unarmed"), system: { damage: "1d4-1", weaponType: "unarmed" } })
|
||||
}
|
||||
|
||||
return super.create(data, options);
|
||||
}
|
||||
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
await super._preCreate(data, options, user)
|
||||
|
||||
// Configure prototype token settings
|
||||
const prototypeToken = {}
|
||||
if (this.type === "protagonist") {
|
||||
Object.assign(prototypeToken, {
|
||||
sight: { enabled: true },
|
||||
actorLink: true,
|
||||
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
|
||||
_onUpdate(changed, options, userId) {
|
||||
// DEBUG : console.log("CthulhuEternalActor.update", changed, options, userId)
|
||||
if (changed?.system?.wp?.exhausted) {
|
||||
ChatMessage.create({
|
||||
user: userId,
|
||||
speaker: { alias: this.name },
|
||||
rollMode: "selfroll",
|
||||
content: game.i18n.localize("CTHULHUETERNAL.ChatMessage.exhausted"),
|
||||
type: CONST.CHAT_MESSAGE_STYLES.OTHER
|
||||
})
|
||||
this.updateSource({ prototypeToken })
|
||||
}
|
||||
return super._onUpdate(changed, options, userId)
|
||||
}
|
||||
|
||||
async createEmbeddedDocuments(embeddedName, data, operation) {
|
||||
let newData = []
|
||||
if (embeddedName === "Item") {
|
||||
for (let i of data) {
|
||||
if (i.type === "skill") {
|
||||
if (this.items.find(item => item.name.toLowerCase() === i.name.toLowerCase())) {
|
||||
ui.notifications.warn(game.i18n.localize("CTHULHUETERNAL.Notifications.skillAlreadyExists"))
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (i.type === "bond") {
|
||||
if (i.system.bondType === "individual") {
|
||||
i.system.value = this.system.characteristics.cha.value
|
||||
} else {
|
||||
i.system.value = Math.floor(this.system.resources.permanentRating / 2)
|
||||
}
|
||||
}
|
||||
newData.push(i)
|
||||
}
|
||||
return super.createEmbeddedDocuments(embeddedName, newData, operation)
|
||||
}
|
||||
return super.createEmbeddedDocuments(embeddedName, data, operation)
|
||||
}
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
await super._preCreate(data, options, user)
|
||||
|
||||
// Configure prototype token settings
|
||||
const prototypeToken = {}
|
||||
if (this.type === "protagonist") {
|
||||
Object.assign(prototypeToken, {
|
||||
sight: { enabled: true },
|
||||
actorLink: true,
|
||||
disposition: CONST.TOKEN_DISPOSITIONS.FRIENDLY,
|
||||
})
|
||||
this.updateSource({ prototypeToken })
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
export const defaultItemImg = {
|
||||
weapon: "systems/fvtt-cthulhu-eternal/assets/icons/icon_weapon.svg",
|
||||
armor: "systems/fvtt-cthulhu-eternal/assets/icons/icon_armor.svg",
|
||||
gear: "systems/fvtt-cthulhu-eternal/assets/icons/icon_gear.svg",
|
||||
gear: "systems/fvtt-cthulhu-eternal/assets/icons/icon_equipment.svg",
|
||||
skill: "systems/fvtt-cthulhu-eternal/assets/icons/icon_skill.svg",
|
||||
archetype: "systems/fvtt-cthulhu-eternal/assets/icons/icon_archetype.svg",
|
||||
bond: "systems/fvtt-cthulhu-eternal/assets/icons/icon_bond.svg",
|
||||
@ -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 {
|
||||
|
@ -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
|
||||
@ -59,18 +60,6 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
return this.options.hasTarget
|
||||
}
|
||||
|
||||
get targetName() {
|
||||
return this.options.targetName
|
||||
}
|
||||
|
||||
get targetArmor() {
|
||||
return this.options.targetArmor
|
||||
}
|
||||
|
||||
get targetMalus() {
|
||||
return this.options.targetMalus
|
||||
}
|
||||
|
||||
get realDamage() {
|
||||
return this.options.realDamage
|
||||
}
|
||||
@ -79,6 +68,43 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
return this.options.weapon
|
||||
}
|
||||
|
||||
get isLowWP() {
|
||||
return this.options.isLowWP
|
||||
}
|
||||
|
||||
get isZeroWP() {
|
||||
return this.options.isZeroWP
|
||||
}
|
||||
|
||||
get isExhausted() {
|
||||
return this.options.isExhausted
|
||||
}
|
||||
|
||||
get isNudgedRoll() {
|
||||
return this.options.isNudgedRoll
|
||||
}
|
||||
|
||||
get wpCost() {
|
||||
return this.options.wpCost
|
||||
}
|
||||
|
||||
static updateResourceDialog(options) {
|
||||
let rating = 0
|
||||
if (options.rollItem.enableHand) {
|
||||
rating += options.rollItem.hand
|
||||
}
|
||||
if (options.rollItem.enableStowed) {
|
||||
rating += options.rollItem.stowed
|
||||
}
|
||||
if (options.rollItem.enableStorage) {
|
||||
rating += options.rollItem.storage
|
||||
}
|
||||
let multiplier = Number($(`.roll-skill-multiplier`).val())
|
||||
options.initialScore = rating
|
||||
options.percentScore = rating * multiplier
|
||||
$(".resource-score").text(`${rating} (${options.percentScore}%)`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt the user with a dialog to configure and execute a roll.
|
||||
*
|
||||
@ -95,85 +121,135 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
*/
|
||||
static async prompt(options = {}) {
|
||||
let formula = "1d100"
|
||||
let hasModifier = true
|
||||
let hasMultiplier = false
|
||||
options.isNudge = true
|
||||
|
||||
switch (options.rollType) {
|
||||
case "skill":
|
||||
console.log(options.rollItem)
|
||||
options.initialScore = options.rollItem.system.computeScore()
|
||||
break
|
||||
case "san":
|
||||
case "char":
|
||||
options.initialScore = options.rollItem.targetScore
|
||||
options.isNudge = (options.rollType !== "san")
|
||||
break
|
||||
case "damage":
|
||||
let formula = options.rollItem.system.damage
|
||||
case "resource":
|
||||
hasModifier = false
|
||||
hasMultiplier = true
|
||||
options.initialScore = options.rollItem.targetScore
|
||||
options.totalRating = options.rollItem.targetScore
|
||||
options.percentScore = options.rollItem.targetScore * 5
|
||||
options.rollItem.enableHand = true
|
||||
options.rollItem.enableStowed = true
|
||||
options.rollItem.enableStorage = true
|
||||
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}`
|
||||
}
|
||||
let damageRoll = new Roll(formula)
|
||||
await damageRoll.evaluate()
|
||||
await damageRoll.toMessage({
|
||||
flavor: `${options.rollItem.name} - Damage Roll`
|
||||
});
|
||||
let isLethal = 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":
|
||||
case "weapon":
|
||||
let era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
|
||||
let skillName = game.i18n.localize(SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType])
|
||||
let actor = game.actors.get(options.actorId)
|
||||
if (era !== options.rollItem.system.settings) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.WrongEra"))
|
||||
console.log("WP Wrong Era", era, options.rollItem.system.weaponType)
|
||||
return
|
||||
}
|
||||
if (!SYSTEM.WEAPON_SKILL_MAPPING[era] || !SYSTEM.WEAPON_SKILL_MAPPING[era][options.rollItem.system.weaponType]) {
|
||||
ui.notifications.error(game.i18n.localize("CTHULHUETERNAL.Notifications.NoWeaponType"))
|
||||
console.log("WP Not found", era, options.rollItem.system.weaponType)
|
||||
return
|
||||
}
|
||||
options.weapon = options.rollItem
|
||||
options.rollItem = actor.items.find(i => i.type === "skill" && i.name.toLowerCase() === skillName.toLowerCase())
|
||||
options.initialScore = options.rollItem.system.computeScore()
|
||||
console.log("WEAPON", skillName, era, options.rollItem)
|
||||
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)
|
||||
}
|
||||
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,
|
||||
default: "public",
|
||||
})
|
||||
|
||||
const choiceModifier = {
|
||||
"-10": "-10",
|
||||
"-20": "-20",
|
||||
"-40": "-40",
|
||||
"0": "0",
|
||||
"+10": "+10",
|
||||
"+20": "+20",
|
||||
"+40": "+40",
|
||||
}
|
||||
const choiceModifier = SYSTEM.MODIFIER_CHOICES
|
||||
const choiceMultiplier = SYSTEM.MULTIPLIER_CHOICES
|
||||
const choiceSelectiveFire = SYSTEM.WEAPON_SELECTIVE_FIRE_CHOICES
|
||||
|
||||
let modifier = "0"
|
||||
let targetMalus = "0"
|
||||
let targetName
|
||||
let targetArmor
|
||||
let modifier = "+0"
|
||||
let multiplier = "5"
|
||||
|
||||
let dialogContext = {
|
||||
rollType: options.rollType,
|
||||
rollItem: foundry.utils.duplicate(options.rollItem), // Object only, no class
|
||||
weapon: options?.weapon,
|
||||
weapon: options?.weapon,
|
||||
initialScore: options.initialScore,
|
||||
targetScore: options.initialScore,
|
||||
isLowWP: options.isLowWP,
|
||||
isZeroWP: options.isZeroWP,
|
||||
isExhausted: options.isExhausted,
|
||||
enableHand: options.rollItem.enableHand,
|
||||
enableStowed: options.rollItem.enableStowed,
|
||||
enableStorage: options.rollItem.enableStorage,
|
||||
rollModes,
|
||||
fieldRollMode,
|
||||
choiceModifier,
|
||||
choiceMultiplier,
|
||||
choiceSelectiveFire,
|
||||
formula,
|
||||
hasTarget: options.hasTarget,
|
||||
hasModifier,
|
||||
hasMultiplier,
|
||||
modifier,
|
||||
targetName,
|
||||
targetArmor
|
||||
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")
|
||||
@ -193,67 +269,95 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
},
|
||||
},
|
||||
],
|
||||
actions: {
|
||||
"selectHand": (event, button, dialog) => {
|
||||
options.rollItem.enableHand = !options.rollItem.enableHand
|
||||
this.updateResourceDialog(options)
|
||||
},
|
||||
"selectStowed": (event, button, dialog) => {
|
||||
options.rollItem.enableStowed = !options.rollItem.enableStowed
|
||||
this.updateResourceDialog(options)
|
||||
},
|
||||
"selectStorage": (event, button, dialog) => {
|
||||
options.rollItem.enableStorage = !options.rollItem.enableStorage
|
||||
this.updateResourceDialog(options)
|
||||
}
|
||||
},
|
||||
rejectClose: false, // Click on Close button will not launch an error
|
||||
render: (event, dialog) => {
|
||||
},
|
||||
$(".roll-skill-multiplier").change(event => {
|
||||
options.multiplier = Number(event.target.value)
|
||||
this.updateResourceDialog(options)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// If the user cancels the dialog, exit
|
||||
if (rollContext === null) return
|
||||
|
||||
let rollData = foundry.utils.mergeObject(foundry.utils.duplicate(options), rollContext)
|
||||
rollData.rollMode = rollContext.visibility
|
||||
rollData.targetName = targetName
|
||||
rollData.targetArmor = targetArmor
|
||||
rollData.targetMalus = targetMalus
|
||||
rollData.rollMode = rollContext.visibility
|
||||
|
||||
// Update target score
|
||||
console.log(rollData)
|
||||
rollData.targetScore = Math.min( Math.max(options.initialScore + Number(rollData.modifier), 0), 100)
|
||||
if ( rollData.isLowWP ) {
|
||||
rollData.targetScore -= 20
|
||||
console.log("Rolldata", rollData, options)
|
||||
if (options.rollType === "resource") {
|
||||
rollData.targetScore = options.initialScore * Number(rollContext.multiplier)
|
||||
} else {
|
||||
rollData.targetScore = Math.min(Math.max(options.initialScore + Number(rollData.modifier), 0), 100)
|
||||
if (rollData.isLowWP || rollData.isExhausted) {
|
||||
rollData.targetScore -= 20
|
||||
}
|
||||
if (rollData.isZeroWP) {
|
||||
rollData.targetScore = 0
|
||||
}
|
||||
rollData.targetScore = Math.min(Math.max(rollData.targetScore, 0), 100)
|
||||
}
|
||||
if ( rollData.isZeroWP ) {
|
||||
rollData.targetScore = 0
|
||||
}
|
||||
rollData.targetScore = Math.min( Math.max(rollData.targetScore, 0), 100)
|
||||
|
||||
/**
|
||||
* A hook event that fires before the roll is made.
|
||||
*/
|
||||
if (Hooks.call("fvtt-cthulhu-eternal.preRoll", options, rollData) === false) return
|
||||
|
||||
const roll = new this(formula, options.data, rollData)
|
||||
await roll.evaluate()
|
||||
|
||||
roll.displayRollResult(roll, options, rollData)
|
||||
|
||||
if (Hooks.call("fvtt-cthulhu-eternal.Roll", options, rollData, roll) === false) return
|
||||
|
||||
return roll
|
||||
}
|
||||
|
||||
displayRollResult(formula, options, rollData) {
|
||||
|
||||
// Compute the result quality
|
||||
let resultType = "failure"
|
||||
let dec = Math.floor(roll.total/10)
|
||||
let unit = roll.total - (dec*10)
|
||||
if (roll.total <= rollData.targetScore) {
|
||||
let resultType = "failure"
|
||||
let dec = Math.floor(this.total / 10)
|
||||
let unit = this.total - (dec * 10)
|
||||
if (this.total <= rollData.targetScore) {
|
||||
resultType = "success"
|
||||
// Detect if decimal == unit in the dire total result
|
||||
if (dec === unit || roll.total === 1) {
|
||||
// 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
|
||||
if (dec === unit || roll.total === 100) {
|
||||
// Detect if decimal == unit in the dire total result
|
||||
if (dec === unit || this.total === 100) {
|
||||
resultType = "failureCritical"
|
||||
}
|
||||
}
|
||||
|
||||
roll.options.resultType = resultType
|
||||
roll.options.isSuccess = resultType === "success" || resultType === "successCritical"
|
||||
roll.options.isFailure = resultType === "failure" || resultType === "failureCritical"
|
||||
roll.options.isCritical = resultType === "successCritical" || resultType === "failureCritical"
|
||||
|
||||
/**
|
||||
* A hook event that fires after the roll has been made.
|
||||
*/
|
||||
if (Hooks.call("fvtt-cthulhu-eternal.Roll", options, rollData, roll) === false) return
|
||||
|
||||
return roll
|
||||
this.options.resultType = resultType
|
||||
if (this.options.isNudgedRoll) {
|
||||
this.options.isSuccess = resultType === "success" || resultType === "successCritical"
|
||||
this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
|
||||
this.options.isCritical = false
|
||||
} else {
|
||||
this.options.isSuccess = resultType === "success" || resultType === "successCritical"
|
||||
this.options.isFailure = resultType === "failure" || resultType === "failureCritical"
|
||||
this.options.isCritical = resultType === "successCritical" || resultType === "failureCritical"
|
||||
}
|
||||
this.options.isLowWP = rollData.isLowWP
|
||||
this.options.isZeroWP = rollData.isZeroWP
|
||||
this.options.isExhausted = rollData.isExhausted
|
||||
this.options.rollData = foundry.utils.duplicate(rollData)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -269,6 +373,10 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
return `${game.i18n.localize("CTHULHUETERNAL.Label.titleSkill")}`
|
||||
case "weapon":
|
||||
return `${game.i18n.localize("CTHULHUETERNAL.Label.titleWeapon")}`
|
||||
case "char":
|
||||
return `${game.i18n.localize("CTHULHUETERNAL.Label.titleCharacteristic")}`
|
||||
case "san":
|
||||
return `${game.i18n.localize("CTHULHUETERNAL.Label.titleSAN")}`
|
||||
default:
|
||||
return game.i18n.localize("CTHULHUETERNAL.Label.titleStandard")
|
||||
}
|
||||
@ -277,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)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,10 +414,10 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
*/
|
||||
async _getChatCardData(isPrivate) {
|
||||
let cardData = foundry.utils.duplicate(this.options)
|
||||
cardData.css = [SYSTEM.id, "dice-roll"]
|
||||
cardData.data = this.data
|
||||
cardData.diceTotal = this.dice.reduce((t, d) => t + d.total, 0)
|
||||
cardData.isGM = game.user.isGM
|
||||
cardData.css = [SYSTEM.id, "dice-roll"]
|
||||
cardData.data = this.data
|
||||
cardData.diceTotal = this.dice.reduce((t, d) => t + d.total, 0)
|
||||
cardData.isGM = game.user.isGM
|
||||
cardData.formula = this.formula
|
||||
cardData.total = this.total
|
||||
cardData.actorId = this.actorId
|
||||
@ -322,8 +430,11 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
cardData.realDamage = this.realDamage
|
||||
cardData.isPrivate = isPrivate
|
||||
cardData.weapon = this.weapon
|
||||
|
||||
console.log(cardData)
|
||||
cardData.isLowWP = this.isLowWP
|
||||
cardData.isZeroWP = this.isZeroWP
|
||||
cardData.isExhausted = this.isExhausted
|
||||
cardData.isNudgedRoll = this.isNudgedRoll
|
||||
cardData.wpCost = this.wpCost
|
||||
|
||||
cardData.cssClass = cardData.css.join(" ")
|
||||
cardData.tooltip = isPrivate ? "" : await this.getTooltip()
|
||||
@ -346,9 +457,6 @@ export default class CthulhuEternalRoll extends Roll {
|
||||
actingCharName: this.actorName,
|
||||
actingCharImg: this.actorImage,
|
||||
hasTarget: this.hasTarget,
|
||||
targetName: this.targetName,
|
||||
targetArmor: this.targetArmor,
|
||||
targetMalus: this.targetMalus,
|
||||
realDamage: this.realDamage,
|
||||
...messageData,
|
||||
},
|
||||
|
@ -1,80 +0,0 @@
|
||||
/**
|
||||
* Enricher qui permet de transformer un texte en un lien de lancer de dés
|
||||
* Pour une syntaxe de type @jet[x]{y}(z) avec x la caractéristique, y le titre et z l'avantage
|
||||
* x de type rob, dex, int, per, vol pour les caractéristiques
|
||||
* et de type oeil, verbe, san, bourse, magie pour les ressources
|
||||
* y est le titre du jet et permet de décrire l'action
|
||||
* z est l'avantage du jet, avec pour valeurs possibles : --, -, +, ++
|
||||
*/
|
||||
export function setupTextEnrichers() {
|
||||
CONFIG.TextEditor.enrichers = CONFIG.TextEditor.enrichers.concat([
|
||||
{
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
pattern: /\@jet\[(.+?)\]{(.*?)}\((.*?)\)/gm,
|
||||
enricher: async (match, options) => {
|
||||
const a = document.createElement("a")
|
||||
a.classList.add("ask-roll-journal")
|
||||
const target = match[1]
|
||||
const title = match[2]
|
||||
const avantage = match[3]
|
||||
|
||||
let type = "resource"
|
||||
if (["rob", "dex", "int", "per", "vol"].includes(target)) {
|
||||
type = "save"
|
||||
}
|
||||
|
||||
let rollAvantage = "normal"
|
||||
if (avantage) {
|
||||
switch (avantage) {
|
||||
case "++":
|
||||
rollAvantage = "++"
|
||||
break
|
||||
case "+":
|
||||
rollAvantage = "+"
|
||||
break
|
||||
case "-":
|
||||
rollAvantage = "-"
|
||||
break
|
||||
case "--":
|
||||
rollAvantage = "--"
|
||||
break
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
a.dataset.rollType = type
|
||||
a.dataset.rollTarget = target
|
||||
a.dataset.rollTitle = title
|
||||
a.dataset.rollAvantage = rollAvantage
|
||||
a.innerHTML = `
|
||||
<i class="fas fa-dice-d20"></i> ${getLibelle(target)}${rollAvantage !== "normal" ? rollAvantage : ""}
|
||||
`
|
||||
return a
|
||||
},
|
||||
},
|
||||
])
|
||||
}
|
||||
const mapLibelles = {
|
||||
rob: "ROB",
|
||||
dex: "DEX",
|
||||
int: "INT",
|
||||
per: "PER",
|
||||
vol: "VOL",
|
||||
oeil: "OEIL",
|
||||
verbe: "VERBE",
|
||||
san: "SANTE MENTALE",
|
||||
bourse: "BOURSE",
|
||||
magie: "MAGIE",
|
||||
}
|
||||
|
||||
/**
|
||||
* Retourne le libellé associé à la valeur qui sera affiché dans le journal
|
||||
* @param {string} value
|
||||
*/
|
||||
function getLibelle(value) {
|
||||
if (mapLibelles[value]) {
|
||||
return mapLibelles[value]
|
||||
}
|
||||
return null
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
export class Macros {
|
||||
/**
|
||||
* Creates a macro based on the type of data dropped onto the hotbar.
|
||||
*
|
||||
* @param {Object} dropData The data object representing the item dropped.
|
||||
* @param {string} dropData.type The type of the dropped item (e.g., "Actor", "JournalEntry", "roll").
|
||||
* @param {string} dropData.uuid The UUID of the dropped item.
|
||||
* @param {string} [dropData.actorId] The ID of the actor (required if type is "roll").
|
||||
* @param {string} [dropData.rollType] The type of roll (required if type is "roll").
|
||||
* @param {string} [dropData.rollTarget] The target of the roll (required if type is "roll").
|
||||
* @param {string} [dropData.value] The value of the roll (required if type is "roll").
|
||||
* @param {number} slot The hotbar slot where the macro will be created.
|
||||
*
|
||||
* @returns {Promise<void>} A promise that resolves when the macro is created.
|
||||
*/
|
||||
static createCthulhuEternalMacro = async function (dropData, slot) {
|
||||
switch (dropData.type) {
|
||||
case "Actor":
|
||||
const actor = await fromUuid(dropData.uuid)
|
||||
const actorCommand = `game.actors.get("${actor.id}").sheet.render(true)`
|
||||
this.createMacro(slot, actor.name, actorCommand, actor.img)
|
||||
break
|
||||
|
||||
case "JournalEntry":
|
||||
const journal = await fromUuid(dropData.uuid)
|
||||
const journalCommand = `game.journal.get("${journal.id}").sheet.render(true)`
|
||||
this.createMacro(slot, journal.name, journalCommand, journal.img ? journal.img : "icons/svg/book.svg")
|
||||
break
|
||||
|
||||
case "roll":
|
||||
const rollCommand =
|
||||
dropData.rollType === "save"
|
||||
? `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}', '=');`
|
||||
: `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');`
|
||||
const rollName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${game.i18n.localize(`TENEBRIS.Manager.${dropData.rollTarget}`)}`
|
||||
this.createMacro(slot, rollName, rollCommand, "icons/svg/d20-grey.svg")
|
||||
break
|
||||
|
||||
case "rollDamage":
|
||||
const weapon = game.actors.get(dropData.actorId).items.get(dropData.rollTarget)
|
||||
const rollDamageCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollType}', '${dropData.rollTarget}');`
|
||||
const rollDamageName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${weapon.name}`
|
||||
this.createMacro(slot, rollDamageName, rollDamageCommand, weapon.img)
|
||||
break
|
||||
|
||||
case "rollAttack":
|
||||
const rollAttackCommand = `game.actors.get('${dropData.actorId}').system.roll('${dropData.rollValue}', '${dropData.rollTarget}');`
|
||||
const rollAttackName = `${game.i18n.localize("TENEBRIS.Label.jet")} ${dropData.rollTarget}`
|
||||
this.createMacro(slot, rollAttackName, rollAttackCommand, "icons/svg/d20-grey.svg")
|
||||
break
|
||||
|
||||
default:
|
||||
// Handle other cases or do nothing
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a macro
|
||||
* All macros are flaged with a tenebris.macro flag at true
|
||||
* @param {*} slot
|
||||
* @param {*} name
|
||||
* @param {*} command
|
||||
* @param {*} img
|
||||
*/
|
||||
static createMacro = async function (slot, name, command, img) {
|
||||
let macro = game.macros.contents.find((m) => m.name === name && m.command === command)
|
||||
if (!macro) {
|
||||
macro = await Macro.create(
|
||||
{
|
||||
name: name,
|
||||
type: "script",
|
||||
img: img,
|
||||
command: command,
|
||||
flags: { "tenebris.macro": true },
|
||||
},
|
||||
{ displaySheet: false },
|
||||
)
|
||||
game.user.assignHotbarMacro(macro, slot)
|
||||
}
|
||||
}
|
||||
}
|
@ -9,3 +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"
|
||||
|
||||
|
@ -5,7 +5,8 @@ export default class CthulhuEternalArchetype extends foundry.abstract.TypeDataMo
|
||||
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||
const schema = {}
|
||||
|
||||
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
|
||||
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
schema.description = new fields.HTMLField({
|
||||
required: false,
|
||||
@ -19,4 +20,5 @@ export default class CthulhuEternalArchetype extends foundry.abstract.TypeDataMo
|
||||
|
||||
/** @override */
|
||||
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Archetype"]
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,10 @@ export default class CthulhuEternalArmor extends foundry.abstract.TypeDataModel
|
||||
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||
|
||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
|
||||
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
schema.protection = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||
|
||||
|
80
module/models/creature.mjs
Normal file
80
module/models/creature.mjs
Normal 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 })
|
||||
}
|
||||
|
||||
}
|
@ -7,8 +7,12 @@ export default class CthulhuEternalGHear extends foundry.abstract.TypeDataModel
|
||||
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||
|
||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
|
||||
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 })
|
||||
schema.state = new fields.StringField({ required: true, initial: "pristine", choices: SYSTEM.EQUIPMENT_STATES })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
@ -5,7 +5,8 @@ export default class CthulhuEternalMentalDisorder extends foundry.abstract.TypeD
|
||||
const schema = {}
|
||||
|
||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||
|
||||
schema.cured = new fields.BooleanField({ required: true, initial: false })
|
||||
|
||||
return schema
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
})
|
||||
|
||||
schema.hp = new fields.SchemaField({
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
max: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
|
||||
max: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
|
||||
stunned: new fields.BooleanField({ required: true, initial: false })
|
||||
})
|
||||
|
||||
@ -44,16 +44,23 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
recovery: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
violence: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min:3, max:3}),
|
||||
helplessness: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min:3, max:3 }),
|
||||
breakingPoint: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
breakingPoint: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
insanity: new fields.StringField({ required: true, nullable: false, initial: "none", choices:SYSTEM.INSANITY }),
|
||||
})
|
||||
|
||||
schema.damageBonus = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
|
||||
schema.resources = new fields.SchemaField({
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }), // Unused but kept for compatibility
|
||||
permanentRating: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
hand: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
currentHand: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
stowed: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
storage: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
currentStowed: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
storage: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
currentStorage: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
|
||||
checks: new fields.ArrayField(new fields.BooleanField(), { required: true, initial: [false, false, false], min:3, max:3 }),
|
||||
nbValidChecks: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
})
|
||||
|
||||
schema.biodata = new fields.SchemaField({
|
||||
@ -66,6 +73,8 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
eyes: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
hair: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
harshness: new fields.StringField({ required: true, nullable: false, initial: "normal", choices:SYSTEM.HARSHNESS }),
|
||||
adaptedToViolence: new fields.BooleanField({ required: true, initial: false }),
|
||||
adaptedToHelplessness: new fields.BooleanField({ required: true, initial: false })
|
||||
})
|
||||
|
||||
return schema
|
||||
@ -90,18 +99,13 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
let unnatural = this.parent.items.find(i => i.type === "skill" && i.name.toLowerCase() === game.i18n.localize("CTHULHUETERNAL.Skill.Unnatural").toLowerCase())
|
||||
let minus = 0
|
||||
if (unnatural) {
|
||||
minus = unnatural.data.skillTotal
|
||||
minus = unnatural.system.skillTotal
|
||||
}
|
||||
let maxSan = Math.max(99 - minus, 0)
|
||||
if ( this.san.max !== maxSan) {
|
||||
updates[`system.san.max`] = maxSan
|
||||
}
|
||||
|
||||
let bp = Math.max(this.san.value - this.characteristics.pow.value, 0)
|
||||
if ( this.san.breakingPoint !== bp) {
|
||||
updates[`system.san.breakingPoint`] = bp
|
||||
}
|
||||
|
||||
let recoverySan = this.characteristics.pow.value * 5
|
||||
if (recoverySan > this.san.max) {
|
||||
recoverySan = this.san.max
|
||||
@ -137,12 +141,30 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
updates[`system.hp.value`] = this.hp.max
|
||||
}
|
||||
|
||||
if (this.resources.permanentRating < 0) {
|
||||
updates[`system.resources.permanentRating`] = 0
|
||||
}
|
||||
|
||||
let resourceIndex = Math.max(Math.min(this.resources.permanentRating, 20), 0)
|
||||
let breakdown = SYSTEM.RESOURCE_BREAKDOWN[resourceIndex]
|
||||
if (this.resources.hand !== breakdown.hand) {
|
||||
updates[`system.resources.hand`] = breakdown.hand
|
||||
}
|
||||
if (this.resources.stowed !== breakdown.stowed) {
|
||||
updates[`system.resources.stowed`] = breakdown.stowed
|
||||
}
|
||||
if (this.resources.storage !== breakdown.storage) {
|
||||
updates[`system.resources.storage`] = breakdown.storage + (this.resources.permanentRating - resourceIndex)
|
||||
}
|
||||
if (this.resources.nbValidChecks !== breakdown.checks) {
|
||||
updates[`system.resources.nbValidChecks`] = breakdown.checks
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length > 0) {
|
||||
this.parent.update(updates)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isLowWP() {
|
||||
return this.wp.value <= 2
|
||||
}
|
||||
@ -151,6 +173,32 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
return this.wp.value === 0
|
||||
}
|
||||
|
||||
isExhausted() {
|
||||
return this.wp.exhausted
|
||||
}
|
||||
|
||||
modifyWP(value) {
|
||||
let updates = {}
|
||||
let wp = Math.max(Math.min(this.wp.value + value, this.wp.max), 0)
|
||||
if ( this.wp.value !== wp) {
|
||||
updates[`system.wp.value`] = wp
|
||||
}
|
||||
if (Object.keys(updates).length > 0) {
|
||||
this.parent.update(updates)
|
||||
}
|
||||
}
|
||||
|
||||
setBP() {
|
||||
let updates = {}
|
||||
let bp = Math.max(this.san.value - this.characteristics.pow.value, 0)
|
||||
if ( this.san.breakingPoint !== bp) {
|
||||
updates[`system.san.breakingPoint`] = bp
|
||||
}
|
||||
if (Object.keys(updates).length > 0) {
|
||||
this.parent.update(updates)
|
||||
}
|
||||
}
|
||||
|
||||
/** */
|
||||
/**
|
||||
* Rolls a dice for a character.
|
||||
@ -167,6 +215,7 @@ export default class CthulhuEternalProtagonist extends foundry.abstract.TypeData
|
||||
rollItem,
|
||||
isLowWP: this.isLowWP(),
|
||||
isZeroWP: this.isZeroWP(),
|
||||
isExhausted: this.isExhausted(),
|
||||
actorId: this.parent.id,
|
||||
actorName: this.parent.name,
|
||||
actorImage: this.parent.img,
|
||||
|
24
module/models/ritual.mjs
Normal file
24
module/models/ritual.mjs
Normal 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"]
|
||||
|
||||
}
|
@ -6,7 +6,9 @@ export default class CthulhuEternalSkill extends foundry.abstract.TypeDataModel
|
||||
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||
|
||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
|
||||
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
schema.base = new fields.StringField({ required: true, initial: "0" })
|
||||
schema.bonus = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 })
|
||||
@ -20,7 +22,6 @@ export default class CthulhuEternalSkill extends foundry.abstract.TypeDataModel
|
||||
/** @override */
|
||||
static LOCALIZATION_PREFIXES = ["CTHULHUETERNAL.Skill"]
|
||||
|
||||
|
||||
prepareDerivedData() {
|
||||
super.prepareDerivedData();
|
||||
this.skillTotal = this.computeScore();
|
||||
|
64
module/models/tome.mjs
Normal file
64
module/models/tome.mjs
Normal 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"];
|
||||
}
|
35
module/models/vehicle.mjs
Normal file
35
module/models/vehicle.mjs
Normal file
@ -0,0 +1,35 @@
|
||||
import { SYSTEM } from "../config/system.mjs"
|
||||
import CthulhuEternalRoll from "../documents/roll.mjs"
|
||||
|
||||
export default class CthulhuEternalVehicle extends foundry.abstract.TypeDataModel {
|
||||
static defineSchema() {
|
||||
const fields = foundry.data.fields
|
||||
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||
const schema = {}
|
||||
|
||||
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
|
||||
schema.settings = new fields.StringField({ required: true, initial: setting, choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
schema.hp = new fields.SchemaField({
|
||||
value: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 }),
|
||||
max: new fields.NumberField({ ...requiredInteger, initial: 1, min: 0 })
|
||||
})
|
||||
|
||||
schema.armor = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.surfaceSpeed = new fields.StringField({ required: true, initial: "slow", choices: SYSTEM.VEHICLE_SPEED })
|
||||
schema.airSpeed = new fields.StringField({ required: true, initial: "none", choices: SYSTEM.VEHICLE_SPEED })
|
||||
schema.state = new fields.StringField({ required: true, initial: "pristine", choices: SYSTEM.EQUIPMENT_STATES })
|
||||
|
||||
schema.crew = new fields.ArrayField(new fields.StringField(), { required: false, initial: [], min:0 })
|
||||
schema.resourceLevel = new fields.NumberField({ required: true, 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.Vehicle"]
|
||||
|
||||
}
|
@ -1,25 +1,33 @@
|
||||
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 = {}
|
||||
const requiredInteger = { required: true, nullable: false, integer: true }
|
||||
|
||||
schema.description = new fields.HTMLField({ required: true, textSearch: true })
|
||||
schema.settings = new fields.StringField({ required: true, initial: "modern", choices: SYSTEM.AVAILABLE_SETTINGS })
|
||||
|
||||
let setting = game.settings.get("fvtt-cthulhu-eternal", "settings-era") || "modern"
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -9,24 +9,5 @@
|
||||
*/
|
||||
export function handleSocketEvent({ action = null, data = {} } = {}) {
|
||||
console.debug("handleSocketEvent", action, data)
|
||||
switch (action) {
|
||||
case "fortune":
|
||||
return CthulhuEternalFortune.handleSocketEvent(data)
|
||||
case "askRoll":
|
||||
return _askRoll(data)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the socket event to ask for a roll.
|
||||
*
|
||||
* @param {Object} [options={}] The options object.
|
||||
* @param {string} [options.userId] The ID of the user who initiated the roll.
|
||||
*/
|
||||
export function _askRoll({ userId } = {}) {
|
||||
console.debug(`handleSocketEvent _askRoll from ${userId} !`)
|
||||
const currentUser = game.user._id
|
||||
if (userId === currentUser) {
|
||||
foundry.audio.AudioHelper.play({ src: "/systems/fvtt-cthulhu-eternal/sounds/drums.wav", volume: 0.8, autoplay: true, loop: false }, false)
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
|
||||
import CthulhuEternalRoll from "./documents/roll.mjs"
|
||||
import { SystemManager } from './applications/hud/system-manager.js'
|
||||
import { SYSTEM } from "./config/system.mjs"
|
||||
|
||||
export default class CthulhuEternalUtils {
|
||||
|
||||
static registerSettings() {
|
||||
game.settings.register("fvtt-cthulhu-eternal", "settings-era", {
|
||||
name: game.i18n.localize("CHTUHLUETERNAL.Settings.era"),
|
||||
hint: game.i18n.localize("CHTUHLUETERNAL.Settings.eraHint"),
|
||||
default: true,
|
||||
name: game.i18n.localize("CTHULHUETERNAL.Settings.era"),
|
||||
hint: game.i18n.localize("CTHULHUETERNAL.Settings.eraHint"),
|
||||
default: "jazz",
|
||||
scope: "world",
|
||||
type: String,
|
||||
choices: SYSTEM.AVAILABLE_SETTINGS,
|
||||
@ -177,12 +181,82 @@ export default class CthulhuEternalUtils {
|
||||
|
||||
}
|
||||
|
||||
static async nudgeRoll(rollMessage) {
|
||||
|
||||
let dialogContext = rollMessage.rolls[0]?.options
|
||||
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)
|
||||
dialogContext.maxValue = Math.min(rollMessage.rolls[0].total + (dialogContext.wpValue * 5), 100)
|
||||
dialogContext.wpCost = 0
|
||||
|
||||
// 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 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({
|
||||
window: { title: title },
|
||||
classes: ["fvtt-cthulhu-eternal"],
|
||||
content,
|
||||
buttons: [
|
||||
{
|
||||
action: "apply",
|
||||
label: game.i18n.localize("CTHULHUETERNAL.Roll.applyNudge"),
|
||||
callback: (event, button, dialog) => {
|
||||
const output = Array.from(button.form.elements).reduce((obj, input) => {
|
||||
if (input.name) obj[input.name] = input.value
|
||||
return obj
|
||||
}, {})
|
||||
return output
|
||||
},
|
||||
},
|
||||
{
|
||||
action: "cancel",
|
||||
label: game.i18n.localize("CTHULHUETERNAL.Roll.cancel"),
|
||||
callback: (event, button, dialog) => { }
|
||||
}
|
||||
],
|
||||
actions: {
|
||||
},
|
||||
rejectClose: false, // Click on Close button will not launch an error
|
||||
render: (event, dialog) => {
|
||||
$(".nudged-score-select").change(event => {
|
||||
dialogContext.nudgedValue = Number(event.target.value)+1
|
||||
dialogContext.wpCost = Math.ceil(Math.abs(rollMessage.rolls[0].total - dialogContext.nudgedValue) / 5)
|
||||
$("#nudged-wp-cost").val(dialogContext.wpCost)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// If the user cancels the dialog, exit
|
||||
if (rollContext === null || dialogContext.wpCost === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const roll = new CthulhuEternalRoll(String(dialogContext.nudgedValue))
|
||||
await roll.evaluate()
|
||||
roll.options = dialogContext
|
||||
roll.options.isNudgedRoll = true
|
||||
roll.options.isNudge = false
|
||||
roll.displayRollResult(roll, dialogContext, dialogContext.rollData)
|
||||
roll.toMessage()
|
||||
|
||||
actor.system.modifyWP(-dialogContext.wpCost)
|
||||
}
|
||||
|
||||
static setupCSSRootVariables() {
|
||||
const era = game.settings.get("fvtt-cthulhu-eternal", "settings-era")
|
||||
|
||||
let eraCSS = SYSTEM.ERA_CSS[era];
|
||||
if (!eraCSS) eraCSS = SYSTEM.ERA_CSS["jazz"];
|
||||
|
||||
document.documentElement.style.setProperty('--font-size-standard', eraCSS.baseFontSize);
|
||||
document.documentElement.style.setProperty('--font-size-title', eraCSS.titleFontSize);
|
||||
document.documentElement.style.setProperty('--font-size-result', eraCSS.titleFontSize);
|
||||
document.documentElement.style.setProperty('--font-primary', eraCSS.primaryFont);
|
||||
document.documentElement.style.setProperty('--font-secondary', eraCSS.secondaryFont);
|
||||
document.documentElement.style.setProperty('--font-title', eraCSS.titleFont);
|
||||
|
BIN
packs-system/rituals/000031.ldb
Normal file
BIN
packs-system/rituals/000031.ldb
Normal file
Binary file not shown.
0
packs-system/rituals/000038.log
Normal file
0
packs-system/rituals/000038.log
Normal file
1
packs-system/rituals/CURRENT
Normal file
1
packs-system/rituals/CURRENT
Normal file
@ -0,0 +1 @@
|
||||
MANIFEST-000036
|
0
packs-system/rituals/LOCK
Normal file
0
packs-system/rituals/LOCK
Normal file
7
packs-system/rituals/LOG
Normal file
7
packs-system/rituals/LOG
Normal 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)
|
7
packs-system/rituals/LOG.old
Normal file
7
packs-system/rituals/LOG.old
Normal 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)
|
BIN
packs-system/rituals/MANIFEST-000036
Normal file
BIN
packs-system/rituals/MANIFEST-000036
Normal file
Binary file not shown.
0
packs-system/rituals/lost/000016.log
Normal file
0
packs-system/rituals/lost/000016.log
Normal file
0
packs-system/rituals/lost/000024.log
Normal file
0
packs-system/rituals/lost/000024.log
Normal file
BIN
packs-system/rituals/lost/MANIFEST-000022
Normal file
BIN
packs-system/rituals/lost/MANIFEST-000022
Normal file
Binary file not shown.
BIN
packs-system/skills/000195.ldb
Normal file
BIN
packs-system/skills/000195.ldb
Normal file
Binary file not shown.
0
packs-system/skills/000202.log
Normal file
0
packs-system/skills/000202.log
Normal file
1
packs-system/skills/CURRENT
Normal file
1
packs-system/skills/CURRENT
Normal file
@ -0,0 +1 @@
|
||||
MANIFEST-000200
|
0
packs-system/skills/LOCK
Normal file
0
packs-system/skills/LOCK
Normal file
7
packs-system/skills/LOG
Normal file
7
packs-system/skills/LOG
Normal file
@ -0,0 +1,7 @@
|
||||
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)
|
7
packs-system/skills/LOG.old
Normal file
7
packs-system/skills/LOG.old
Normal file
@ -0,0 +1,7 @@
|
||||
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)
|
BIN
packs-system/skills/MANIFEST-000200
Normal file
BIN
packs-system/skills/MANIFEST-000200
Normal file
Binary file not shown.
0
packs-system/skills/lost/000159.log
Normal file
0
packs-system/skills/lost/000159.log
Normal file
0
packs-system/skills/lost/000180.log
Normal file
0
packs-system/skills/lost/000180.log
Normal file
0
packs-system/skills/lost/000188.log
Normal file
0
packs-system/skills/lost/000188.log
Normal file
BIN
packs-system/skills/lost/MANIFEST-000186
Normal file
BIN
packs-system/skills/lost/MANIFEST-000186
Normal file
Binary file not shown.
644
styles/creature.less
Normal file
644
styles/creature.less
Normal 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;
|
||||
}
|
||||
}
|
@ -44,9 +44,19 @@
|
||||
src: url("../assets/fonts/Volkhov-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "ChantelliAntiqua";
|
||||
src: url("../assets/fonts/Chantelli_Antiqua.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "IMFell";
|
||||
src: url("../assets/fonts/IMFell.ttf") format("truetype");
|
||||
src: url("../assets/fonts/IMFeDPrm28P.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "SailRegular";
|
||||
src: url("../assets/fonts/Sail-Regular.ttf") format("truetype");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
@ -110,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");
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
.fvtt-cthulhu-eternal {
|
||||
@import "mixins.less";
|
||||
@import "protagonist.less";
|
||||
@import "vehicle.less";
|
||||
@import "creature.less";
|
||||
@import "skill.less";
|
||||
@import "injury.less";
|
||||
@import "weapon.less";
|
||||
@ -15,6 +17,8 @@
|
||||
@import "gear.less";
|
||||
@import "arcane.less";
|
||||
@import "archetype.less";
|
||||
@import "ritual.less";
|
||||
@import "tome.less";
|
||||
}
|
||||
|
||||
@import "roll.less";
|
||||
@import "roll.less";
|
@ -1,19 +1,28 @@
|
||||
:root {
|
||||
--font-size-standard: 0.9rem;
|
||||
--font-size-result: 1.4rem;
|
||||
--background-image-base: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)),
|
||||
url("../assets/ui/jazz_background_main.webp");
|
||||
/*--background-image-base: url("../assets/ui/jazzage_background_main.webp");*/
|
||||
--font-primary: "RozhaOne";
|
||||
--font-secondary: "RozhaOne";
|
||||
--font-title: "Broadway";
|
||||
--logo-standard: url("../assets/logos/reanimated-ce-logo.webp");
|
||||
--color-success: darkgreen;
|
||||
--color-success: rgb(15, 122, 15);
|
||||
--color-failure: darkred;
|
||||
--color-critical-success: lightgreen;
|
||||
--color-critical-failure: lightcoral;
|
||||
--color-warning: darkorange;
|
||||
--color-critical-success: rgb(21, 39, 204);
|
||||
--color-critical-failure: rgb(141, 32, 231);
|
||||
--img-icon-color-filter: brightness(0) saturate(100%) invert(52%) sepia(9%) saturate(2368%) hue-rotate(360deg) brightness(86%) contrast(84%);
|
||||
}
|
||||
|
||||
.d100 {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
color: black;
|
||||
border-width: 0px;
|
||||
filter: var(--img-icon-color-filter);
|
||||
}
|
||||
|
||||
.item .thumbnail,
|
||||
.item-img {
|
||||
/*filter: invert(90%) sepia(10%) saturate(1215%) hue-rotate(55deg) brightness(93%) contrast(89%);*/
|
||||
|
@ -21,7 +21,7 @@
|
||||
}
|
||||
|
||||
input[name="name"] {
|
||||
height: 50px;
|
||||
height: 40px;
|
||||
margin-right: 10px;
|
||||
font-family: var(--font-secondary);
|
||||
font-size: calc(var(--font-size-standard) * 1);
|
||||
@ -30,8 +30,8 @@
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin-bottom: 5px;
|
||||
border-radius: 5px;
|
||||
margin-bottom: 4px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.form-fields {
|
||||
@ -57,13 +57,27 @@
|
||||
.protagonist-sheet-common {
|
||||
label {
|
||||
font-family: var(--font-secondary);
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
.vehicle-sheet-common {
|
||||
label {
|
||||
font-family: var(--font-secondary);
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
.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: 5px;
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
label {
|
||||
|
@ -34,6 +34,25 @@
|
||||
}
|
||||
}
|
||||
|
||||
.protagonist-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;
|
||||
}
|
||||
}
|
||||
|
||||
.protagonist-dv,
|
||||
.protagonist-dmax {
|
||||
.form-fields {
|
||||
@ -62,81 +81,93 @@
|
||||
display: flex;
|
||||
input {
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1.4);
|
||||
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-field {
|
||||
flex-grow: 0;
|
||||
.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.2rem;
|
||||
min-width: 2.4rem;
|
||||
max-width: 2.4rem;
|
||||
}
|
||||
.label-field {
|
||||
flex-grow: 0;
|
||||
margin-left: 4px;
|
||||
}
|
||||
.checkbox {
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
.protagonist-infos {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
label {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.protagonist-hp {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
.protagonist-hp-value {
|
||||
.form-fields input {
|
||||
flex: none;
|
||||
width: 50px;
|
||||
margin-left: 4px;
|
||||
font-size: calc(var(--font-size-standard) * 1.4);
|
||||
}
|
||||
}
|
||||
.protagonist-hp-max {
|
||||
clear: both;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 3px 0;
|
||||
align-items: center;
|
||||
input {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
font-size: calc(var(--font-size-standard) * 1.4);
|
||||
}
|
||||
}
|
||||
.hp-separator {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
label {
|
||||
min-width: 120px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -164,12 +195,24 @@
|
||||
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: 1;
|
||||
flex: 0;
|
||||
padding-left: 5px;
|
||||
.form-fields {
|
||||
font-size: 1.1rem;
|
||||
flex: none;
|
||||
width: 70px;
|
||||
width: 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -195,39 +238,44 @@
|
||||
.field-label {
|
||||
margin-left: 8px;
|
||||
}
|
||||
.biodata {
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
.motivations {
|
||||
|
||||
.features,
|
||||
.biodata {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 4px;
|
||||
.motivation {
|
||||
gap: 8px;
|
||||
label {
|
||||
min-width: 3rem;
|
||||
}
|
||||
.feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 14rem;
|
||||
max-width: 14rem;
|
||||
.controls {
|
||||
min-width: 2rem;
|
||||
max-width: 2rem;
|
||||
}
|
||||
.name {
|
||||
min-width: 8rem;
|
||||
max-width: 8rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
min-width: 18rem;
|
||||
max-width: 18rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab.protagonist-skills {
|
||||
.tab.protagonist-skills .main-div {
|
||||
background-color: var(--color-light-1);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
@ -245,31 +293,37 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 10rem;
|
||||
max-width: 10rem;
|
||||
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 {
|
||||
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: 8rem;
|
||||
max-width: 8rem;
|
||||
min-width: 10rem;
|
||||
max-width: 10rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab.protagonist-status {
|
||||
.tab.protagonist-status .main-div {
|
||||
background-color: var(--color-light-1);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
@ -279,6 +333,7 @@
|
||||
padding-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.bonds {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@ -287,31 +342,60 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 16rem;
|
||||
max-width: 16rem;
|
||||
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;
|
||||
max-width: 12rem;
|
||||
}
|
||||
.type {
|
||||
min-width: 4rem;
|
||||
max-width: 4rem;
|
||||
min-width: 6rem;
|
||||
max-width: 6rem;
|
||||
}
|
||||
.level {
|
||||
min-width: 2rem;
|
||||
max-width: 2rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
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);
|
||||
@ -320,23 +404,29 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 16rem;
|
||||
max-width: 16rem;
|
||||
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;
|
||||
max-width: 14rem;
|
||||
}
|
||||
.cured {
|
||||
min-width: 5rem;
|
||||
max-width: 5rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.injuries {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@ -348,23 +438,24 @@
|
||||
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;
|
||||
max-width: 14rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tab.protagonist-equipment {
|
||||
.tab.protagonist-equipment .main-div {
|
||||
background-color: var(--color-light-1);
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
@ -383,27 +474,28 @@
|
||||
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;
|
||||
}
|
||||
.damage {
|
||||
min-width: 5rem;
|
||||
max-width: 5rem;
|
||||
min-width: 6rem;
|
||||
max-width: 6rem;
|
||||
}
|
||||
.name {
|
||||
min-width: 8rem;
|
||||
max-width: 8rem;
|
||||
min-width: 10rem;
|
||||
max-width: 10rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
@ -417,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;
|
||||
@ -436,12 +529,13 @@
|
||||
max-width: 8rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gears {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
@ -451,27 +545,88 @@
|
||||
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: 32px;
|
||||
height: 32px;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
30
styles/ritual.less
Normal file
30
styles/ritual.less
Normal 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%;
|
||||
}
|
||||
}
|
@ -31,11 +31,18 @@
|
||||
border: none;
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
color: var(--color-dark-2);
|
||||
width: 60px;
|
||||
width: 4rem;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.red-warning {
|
||||
color: var(--color-failure);
|
||||
}
|
||||
|
||||
.orange-warning {
|
||||
color: var(--color-warning);
|
||||
}
|
||||
|
||||
.dialog-damage {
|
||||
display: flex;
|
||||
@ -86,25 +93,30 @@
|
||||
font-family: var(--font-primary);
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
}
|
||||
.nudge-roll {
|
||||
font-size: calc(var(--font-size-standard) * 1.0);
|
||||
margin-left: 4rem;
|
||||
display: none;
|
||||
}
|
||||
.result-success {
|
||||
color: var(--color-success);
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
font-size: var(--font-size-result);
|
||||
}
|
||||
.result-critical-success {
|
||||
color: var(--color-critical-success);
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
font-size: var(--font-size-result);
|
||||
}
|
||||
.result-failure {
|
||||
color: var(--color-failure);
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
font-size: var(--font-size-result);
|
||||
}
|
||||
.result-critical-failure {
|
||||
color: var(--color-critical-failure);
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
font-size: var(--font-size-result);
|
||||
}
|
||||
}
|
||||
.introText {
|
||||
|
22
styles/tome.less
Normal file
22
styles/tome.less
Normal 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%;
|
||||
}
|
||||
}
|
223
styles/vehicle.less
Normal file
223
styles/vehicle.less
Normal file
@ -0,0 +1,223 @@
|
||||
.vehicle-content {
|
||||
.sheet-common();
|
||||
.vehicle-sheet-common();
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.sheet-tabs {
|
||||
background-color: var(--color-light-1);
|
||||
}
|
||||
|
||||
.vehicle-main {
|
||||
background-color: var(--color-light-1);
|
||||
display: flex;
|
||||
|
||||
.vehicle-pc {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
flex: 1;
|
||||
|
||||
.vehicle-left {
|
||||
min-width: 180px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.vehicle-left-image {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding-bottom: 8px;
|
||||
.vehicle-img {
|
||||
height: 140px;
|
||||
width: auto;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.vehicle-right {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 5px;
|
||||
|
||||
.vehicle-name {
|
||||
display: flex;
|
||||
input {
|
||||
font-family: var(--font-title);
|
||||
font-size: calc(var(--font-size-standard) * 1.4);
|
||||
width: 400px;
|
||||
}
|
||||
}
|
||||
|
||||
.vehicle-infos {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
label {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
.vehicle-hp {
|
||||
display: flex;
|
||||
gap: 2px;
|
||||
align-items: center;
|
||||
.vehicle-hp-value {
|
||||
.form-fields input {
|
||||
flex: none;
|
||||
width: 50px;
|
||||
margin-left: 4px;
|
||||
font-size: calc(var(--font-size-standard) * 1.4);
|
||||
}
|
||||
}
|
||||
.vehicle-hp-max {
|
||||
clear: both;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin: 3px 0;
|
||||
align-items: center;
|
||||
input {
|
||||
width: 50px;
|
||||
text-align: center;
|
||||
font-size: calc(var(--font-size-standard) * 1.4);
|
||||
}
|
||||
}
|
||||
.hp-separator {
|
||||
font-size: calc(var(--font-size-standard) * 1.2);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.vehicle-pc-play {
|
||||
min-width: 500px;
|
||||
}
|
||||
|
||||
.vehicle-pc-edit {
|
||||
min-width: 650px;
|
||||
}
|
||||
}
|
||||
|
||||
.vehicle-biography {
|
||||
background-color: var(--color-light-1);
|
||||
prose-mirror.inactive {
|
||||
min-height: 40px;
|
||||
}
|
||||
prose-mirror.active {
|
||||
min-height: 150px;
|
||||
}
|
||||
.field-label {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
|
||||
.biodata {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 8px;
|
||||
label {
|
||||
min-width: 3.0rem;
|
||||
}
|
||||
.feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 18rem;
|
||||
max-width: 18rem;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.tab.vehicle-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;
|
||||
}
|
||||
}
|
||||
.weapons {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 4px;
|
||||
.weapon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 13rem;
|
||||
max-width: 13srem;
|
||||
.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;
|
||||
}
|
||||
.name {
|
||||
min-width: 8rem;
|
||||
max-width: 8rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.gears {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 4px;
|
||||
.gear {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
min-width: 13rem;
|
||||
max-width: 13srem;
|
||||
.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;
|
||||
}
|
||||
.name {
|
||||
min-width: 8rem;
|
||||
max-width: 8rem;
|
||||
}
|
||||
.item-img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
prose-mirror.inactive {
|
||||
min-height: 40px;
|
||||
}
|
||||
prose-mirror.active {
|
||||
min-height: 150px;
|
||||
}
|
||||
}
|
152
system.json
152
system.json
@ -1,62 +1,162 @@
|
||||
{
|
||||
"id": "fvtt-cthulhu-eternal",
|
||||
"title": "Cthulhu Eternal RPG",
|
||||
"description": "",
|
||||
"description": "The OGL Cthulhu Eternal RPG system for Foundry VTT",
|
||||
"manifest": "https://www.uberwald.me/gitea/public/fvtt-cthulhu-eternal/raw/branch/main/system.json",
|
||||
"download": "#{DOWNLOAD}#",
|
||||
"url": "https://www.uberwald.me/gitea/public/fvtt-cthulhu-eternal",
|
||||
"license": "LICENSE",
|
||||
"version": "12.0.1",
|
||||
"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"] }
|
||||
"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/skills",
|
||||
"type": "Item"
|
||||
"path": "packs-system/skills",
|
||||
"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": {
|
||||
@ -65,5 +165,5 @@
|
||||
},
|
||||
"primaryTokenAttribute": "hp",
|
||||
"socket": true,
|
||||
"background": "systems/fvtt-cthulhu-eternal/assets/background.webp"
|
||||
}
|
||||
"background": "systems/fvtt-cthulhu-eternal/assets/ui/background_01.webp"
|
||||
}
|
@ -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>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user