forked from public/fvtt-cthulhu-eternal
		
	Compare commits
	
		
			62 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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.
										
									
								
							
							
								
								
									
										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 | 
							
								
								
									
										8
									
								
								changelog.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								changelog.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| # 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,12 +48,16 @@ Hooks.once("init", function () { | ||||
|     bond: models.CthulhuEternalBond, | ||||
|     arcane: models.CthulhuEternalArcane, | ||||
|     gear: models.CthulhuEternalGear, | ||||
|     archetype: models.CthulhuEternalArchetype | ||||
|     archetype: models.CthulhuEternalArchetype, | ||||
|     ritual: models.CthulhuEternalRitual, | ||||
|     tome: models.CthulhuEternalTome | ||||
|   } | ||||
|  | ||||
|   // Register sheet application classes | ||||
|   Actors.unregisterSheet("core", ActorSheet) | ||||
|   Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalProtagonistSheet, { types: ["protagonist"], makeDefault: true }) | ||||
|   Actors.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalVehicleSheet, { types: ["vehicle"], makeDefault: true }) | ||||
|   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 }) | ||||
| @@ -66,6 +70,8 @@ Hooks.once("init", function () { | ||||
|   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 }) | ||||
|   Items.registerSheet("fvtt-cthulhu-eternal", applications.CthulhuEternalRitualSheet, { types: ["ritual"], makeDefault: true }) | ||||
|   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) | ||||
|       }) | ||||
|     } | ||||
|   // 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); | ||||
|   | ||||
							
								
								
									
										298
									
								
								lang/en.json
									
									
									
									
									
								
							
							
						
						
									
										298
									
								
								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" | ||||
|         } | ||||
| @@ -148,6 +266,15 @@ | ||||
|         "riflecarabine": "Rifle/Carabine" | ||||
|       }, | ||||
|       "FIELDS": { | ||||
|         "hasDirectSkill": { | ||||
|           "label": "Has direct skill" | ||||
|         }, | ||||
|         "directSkillValue": { | ||||
|           "label": "Direct skill value" | ||||
|         }, | ||||
|         "state": { | ||||
|           "label": "State" | ||||
|         }, | ||||
|         "settings": { | ||||
|           "label": "Settings era" | ||||
|         }, | ||||
| @@ -203,10 +330,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 +395,7 @@ | ||||
|       "FIELDS": { | ||||
|         "settings": { | ||||
|           "label": "Settings era" | ||||
|         },   | ||||
|         }, | ||||
|         "value": { | ||||
|           "label": "Value" | ||||
|         }, | ||||
| @@ -255,9 +413,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 +530,7 @@ | ||||
|       "intShort": "INT", | ||||
|       "powShort": "POW", | ||||
|       "conShort": "CON", | ||||
|       "chaShort": "CHA",       | ||||
|       "chaShort": "CHA", | ||||
|       "strLong": "Strength", | ||||
|       "dexLong": "Dexterity", | ||||
|       "intLong": "Intelligence", | ||||
| @@ -309,6 +569,7 @@ | ||||
|       "criticalSuccess": "Critical Success", | ||||
|       "criticalFailure": "Critical Failure", | ||||
|       "Characteristic": "Characteristic", | ||||
|       "characteristic": "Characteristic", | ||||
|       "targetScore": "Target Score", | ||||
|       "gears": "Gears", | ||||
|       "armors": "Armors", | ||||
| @@ -331,7 +592,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 +607,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`) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }) | ||||
| @@ -96,7 +96,6 @@ 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), | ||||
|       } | ||||
| @@ -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 | ||||
|   | ||||
							
								
								
									
										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 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 #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) | ||||
|     } | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -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 TextEditor.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 TextEditor.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 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"), | ||||
| @@ -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,22 +100,34 @@ 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 }) | ||||
|         break | ||||
| @@ -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 TextEditor.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 TextEditor.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 TextEditor.enrichHTML(this.document.system.description, { async: true }) | ||||
|     context.enrichedNotes = await TextEditor.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: "UncialAntiqua", secondaryFont: "UncialAntiqua", titleFont: "Luminari", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "brightness(0) saturate(100%) invert(93%) sepia(46%) saturate(354%) hue-rotate(321deg) brightness(93%) contrast(87%)"}, | ||||
|   ww2: { primaryFont: "SairaStencilOne", secondaryFont: "SairaStencilOne", titleFont: "Armalite", baseFontSize: "0.9rem",titleFontSize: "1.2rem",imgFilter: "filter: invert(44%) sepia(8%) saturate(2657%) hue-rotate(40deg) brightness(96%) contrast(75%)"}, | ||||
|   ww1: { primaryFont: "CarterOne", secondaryFont: "CarterOne", titleFont: "SigmarOne", baseFontSize: "0.9rem",titleFontSize: "1.1rem",imgFilter: "invert(28%) sepia(27%) saturate(475%) hue-rotate(76deg) brightness(95%) contrast(93%)"}, | ||||
|   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,33 @@ 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 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} | ||||
| @@ -181,5 +261,13 @@ export const SYSTEM = { | ||||
|   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 | ||||
| } | ||||
|   | ||||
| @@ -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,39 +121,88 @@ 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 | ||||
| @@ -141,37 +216,34 @@ export default class CthulhuEternalRoll extends Roll { | ||||
|       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 | ||||
|  | ||||
|     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, | ||||
|       formula, | ||||
|       hasTarget: options.hasTarget, | ||||
|       hasModifier, | ||||
|       hasMultiplier, | ||||
|       modifier, | ||||
|       targetName, | ||||
|       targetArmor | ||||
|       multiplier | ||||
|     } | ||||
|     const content = await renderTemplate("systems/fvtt-cthulhu-eternal/templates/roll-dialog.hbs", dialogContext) | ||||
|  | ||||
| @@ -193,67 +265,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 +369,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") | ||||
|     } | ||||
| @@ -306,10 +410,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 +426,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 +453,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,15 +1,20 @@ | ||||
| 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.hasDirectSkill = new fields.BooleanField({ required: true, initial: false }) | ||||
|     schema.directSkillValue = new fields.NumberField({ required: true, initial: 0, min: 0, max:99 }) | ||||
|      | ||||
|     schema.damage = new fields.StringField({required: true, initial: "1d6"})   | ||||
|     schema.baseRange = new fields.StringField({required: true, initial: ""}) | ||||
|     schema.rangeUnit = new fields.StringField({ required: true, initial: "yard", choices: SYSTEM.WEAPON_RANGE_UNIT }) | ||||
| @@ -17,6 +22,7 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel { | ||||
|     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.state = new fields.StringField({ required: true, initial: "pristine", choices: SYSTEM.EQUIPMENT_STATES }) | ||||
|  | ||||
|     schema.resourceLevel = new fields.NumberField({ required: true, initial: 0, min: 0 }) | ||||
|      | ||||
|   | ||||
| @@ -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 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/000005.ldb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packs-system/rituals/000005.ldb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										0
									
								
								packs-system/rituals/000012.log
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								packs-system/rituals/000012.log
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								packs-system/rituals/CURRENT
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packs-system/rituals/CURRENT
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| MANIFEST-000010 | ||||
							
								
								
									
										0
									
								
								packs-system/rituals/LOCK
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								packs-system/rituals/LOCK
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										8
									
								
								packs-system/rituals/LOG
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								packs-system/rituals/LOG
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| 2025/04/25-00:23:55.566074 7fd0855fa6c0 Recovering log #8 | ||||
| 2025/04/25-00:23:55.627155 7fd0855fa6c0 Delete type=3 #6 | ||||
| 2025/04/25-00:23:55.627214 7fd0855fa6c0 Delete type=0 #8 | ||||
| 2025/04/25-00:24:39.296644 7fd07effd6c0 Level-0 table #13: started | ||||
| 2025/04/25-00:24:39.296707 7fd07effd6c0 Level-0 table #13: 0 bytes OK | ||||
| 2025/04/25-00:24:39.302890 7fd07effd6c0 Delete type=0 #11 | ||||
| 2025/04/25-00:24:39.309638 7fd07effd6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) | ||||
| 2025/04/25-00:24:39.309671 7fd07effd6c0 Manual compaction at level-1 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) | ||||
							
								
								
									
										8
									
								
								packs-system/rituals/LOG.old
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								packs-system/rituals/LOG.old
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| 2025/04/24-23:56:15.236151 7fd0855fa6c0 Recovering log #4 | ||||
| 2025/04/24-23:56:15.247158 7fd0855fa6c0 Delete type=0 #4 | ||||
| 2025/04/24-23:56:15.247228 7fd0855fa6c0 Delete type=3 #2 | ||||
| 2025/04/25-00:23:51.709456 7fd07effd6c0 Level-0 table #9: started | ||||
| 2025/04/25-00:23:51.709498 7fd07effd6c0 Level-0 table #9: 0 bytes OK | ||||
| 2025/04/25-00:23:51.747489 7fd07effd6c0 Delete type=0 #7 | ||||
| 2025/04/25-00:23:51.747677 7fd07effd6c0 Manual compaction at level-0 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) | ||||
| 2025/04/25-00:23:51.809910 7fd07effd6c0 Manual compaction at level-1 from '!items!4oyPRBWPBWAChrJP' @ 72057594037927935 : 1 .. '!items!zVFfp3o0G0Zg3Ia4' @ 0 : 0; will stop at (end) | ||||
							
								
								
									
										
											BIN
										
									
								
								packs-system/rituals/MANIFEST-000010
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packs-system/rituals/MANIFEST-000010
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								packs-system/skills/000165.ldb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packs-system/skills/000165.ldb
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										0
									
								
								packs-system/skills/000176.log
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								packs-system/skills/000176.log
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								packs-system/skills/CURRENT
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								packs-system/skills/CURRENT
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| MANIFEST-000174 | ||||
							
								
								
									
										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/04/25-00:23:55.465639 7fd07f7fe6c0 Recovering log #172 | ||||
| 2025/04/25-00:23:55.561118 7fd07f7fe6c0 Delete type=3 #170 | ||||
| 2025/04/25-00:23:55.561198 7fd07f7fe6c0 Delete type=0 #172 | ||||
| 2025/04/25-00:24:39.302991 7fd07effd6c0 Level-0 table #177: started | ||||
| 2025/04/25-00:24:39.303023 7fd07effd6c0 Level-0 table #177: 0 bytes OK | ||||
| 2025/04/25-00:24:39.309509 7fd07effd6c0 Delete type=0 #175 | ||||
| 2025/04/25-00:24:39.309652 7fd07effd6c0 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/04/24-23:56:15.221751 7fd07f7fe6c0 Recovering log #168 | ||||
| 2025/04/24-23:56:15.231420 7fd07f7fe6c0 Delete type=0 #168 | ||||
| 2025/04/24-23:56:15.231515 7fd07f7fe6c0 Delete type=3 #166 | ||||
| 2025/04/25-00:23:51.673765 7fd07effd6c0 Level-0 table #173: started | ||||
| 2025/04/25-00:23:51.673830 7fd07effd6c0 Level-0 table #173: 0 bytes OK | ||||
| 2025/04/25-00:23:51.709271 7fd07effd6c0 Delete type=0 #171 | ||||
| 2025/04/25-00:23:51.747663 7fd07effd6c0 Manual compaction at level-0 from '!folders!5PrT9QmN1cFPzDFP' @ 72057594037927935 : 1 .. '!items!zvoUByzWSWZ87fxA' @ 0 : 0; will stop at (end) | ||||
							
								
								
									
										
											BIN
										
									
								
								packs-system/skills/MANIFEST-000174
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								packs-system/skills/MANIFEST-000174
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										0
									
								
								packs-system/skills/lost/000159.log
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								packs-system/skills/lost/000159.log
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										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 { | ||||
|   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 { | ||||
|   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 { | ||||
|   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 { | ||||
|   | ||||
| @@ -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,34 +238,39 @@ | ||||
|   .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; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| @@ -245,24 +293,30 @@ | ||||
|       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; | ||||
|       } | ||||
|     } | ||||
| @@ -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,16 +438,17 @@ | ||||
|       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; | ||||
|       } | ||||
|     } | ||||
| @@ -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 { | ||||
|   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; | ||||
|   } | ||||
| } | ||||
							
								
								
									
										24
									
								
								system.json
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								system.json
									
									
									
									
									
								
							| @@ -1,12 +1,12 @@ | ||||
| { | ||||
|   "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": "12.0.6", | ||||
|   "authors": [ | ||||
|     { | ||||
|       "name": "Uberwald", | ||||
| @@ -34,7 +34,9 @@ | ||||
|   ], | ||||
|   "documentTypes": { | ||||
|     "Actor": { | ||||
|       "protagonist": { "htmlFields": ["description", "notes"] } | ||||
|       "protagonist": { "htmlFields": ["description", "notes"] }, | ||||
|       "vehicle": { "htmlFields": ["description", "notes"] }, | ||||
|       "creature": { "htmlFields": ["description", "notes"] } | ||||
|     }, | ||||
|     "Item": { | ||||
|       "skill": { "htmlFields": ["description"] }, | ||||
| @@ -46,7 +48,9 @@ | ||||
|       "motivation": { "htmlFields": ["description"] }, | ||||
|       "arcane": { "htmlFields": ["description"] }, | ||||
|       "gear": { "htmlFields": ["description"] }, | ||||
|       "archetype": { "htmlFields": ["description"] } | ||||
|       "archetype": { "htmlFields": ["description"] }, | ||||
|       "ritual": { "htmlFields": ["description"] }, | ||||
|       "tome": { "htmlFields": ["description"] } | ||||
|     } | ||||
|   }, | ||||
|   "packs": [ | ||||
| @@ -55,7 +59,15 @@ | ||||
|       "banner": "", | ||||
|       "label": "Skills", | ||||
|       "system": "fvtt-cthulhu-eternal", | ||||
|       "path": "packs/skills", | ||||
|       "path": "packs-system/skills", | ||||
|       "type": "Item" | ||||
|     }, | ||||
|     { | ||||
|       "name": "rituals", | ||||
|       "banner": "", | ||||
|       "label": "Rituals", | ||||
|       "system": "fvtt-cthulhu-eternal", | ||||
|       "path": "packs-system/rituals", | ||||
|       "type": "Item" | ||||
|     } | ||||
|   ], | ||||
| @@ -65,5 +77,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> | ||||
| @@ -2,15 +2,15 @@ | ||||
|   <div class="header"> | ||||
|     <img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" /> | ||||
|     {{formInput fields.name value=source.name}} | ||||
|   </div>   | ||||
|   </div> | ||||
|  | ||||
|   <fieldset> | ||||
|     {{formField systemFields.settings value=system.settings localize=true}} | ||||
|   </fieldset>   | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}} | ||||
|     {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} | ||||
|   </fieldset> | ||||
|  | ||||
| </section>h | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput | ||||
|     systemFields.description | ||||
|     enriched=description | ||||
|     enriched=enrichedDescription | ||||
|     value=system.description | ||||
|     name="system.description" | ||||
|     toggled="false" | ||||
|   | ||||
| @@ -1,6 +0,0 @@ | ||||
| <div class="tenebris ask-roll"> | ||||
|     <h4 class="ask-roll-title">{{title}}<br>{{text}}</h4> | ||||
|     <a class="ask-roll-dice" data-type="{{rollType}}" data-value="{{value}}" data-avantage="{{avantage}}"> | ||||
|         <i class="fas fa-dice-d20" title="{{localize 'TENEBRIS.Manager.roll'}}"></i>  {{localize 'TENEBRIS.Manager.roll'}} | ||||
|     </a> | ||||
| </div> | ||||
| @@ -1,55 +1,92 @@ | ||||
| {{!log 'chat-message' this}} | ||||
| <div class="{{cssClass}}"> | ||||
|     <div class="intro-chat"> | ||||
|         <div class="intro-img"> | ||||
|           <img src="{{actingCharImg}}" data-tooltip="{{actingCharName}}" /> | ||||
|         </div> | ||||
|         <div class="intro-right"> | ||||
|             <ul> | ||||
|               {{#if (eq rollType "char")}} | ||||
|               <li><strong>{{localize "CTHULHUETERNAL.Label.charRoll"}}</strong></li> | ||||
|               {{/if}} | ||||
|                | ||||
|               {{#if (eq rollType "skill")}} | ||||
|               <li><strong>{{localize "CTHULHUETERNAL.Label.skillRoll"}}</strong></li> | ||||
|               {{/if}}         | ||||
|  | ||||
|               {{#if weapon}} | ||||
|               <li><strong>Weapon : {{weapon.name}}</strong></li> | ||||
|               {{/if}}         | ||||
|  | ||||
|               <li><strong>{{rollItem.name}} : {{initialScore}}%</strong></li> | ||||
|               <li>{{localize "CTHULHUETERNAL.Label.modifier"}} : {{modifier}}%</li> | ||||
|               <li>{{localize "CTHULHUETERNAL.Label.targetScore"}} : {{targetScore}}%</li> | ||||
|               {{#if isSuccess}} | ||||
|                 {{#if isCritical}}   | ||||
|                 <li class="result-critical-success">{{localize "CTHULHUETERNAL.Label.criticalSuccess"}}</li> | ||||
|                 {{else}} | ||||
|                 <li class="result-success">{{localize "CTHULHUETERNAL.Label.success"}}</li> | ||||
|                 {{/if}} | ||||
|               {{/if}} | ||||
|               {{#if isFailure}} | ||||
|                 {{#if isCritical}} | ||||
|                 <li class="result-critical-failure">{{localize "CTHULHUETERNAL.Label.criticalFailure"}}</li> | ||||
|                 {{else}} | ||||
|                 <li class="result-failure">{{localize "CTHULHUETERNAL.Label.failure"}}</li> | ||||
|                 {{/if}}  | ||||
|               {{/if}} | ||||
|             </ul> | ||||
|         </div> | ||||
|   <div class="intro-chat"> | ||||
|     <div class="intro-img"> | ||||
|       <img src="{{actingCharImg}}" data-tooltip="{{actingCharName}}" /> | ||||
|     </div> | ||||
|      {{#if isDamage}} | ||||
|         <div> | ||||
|             {{#if (and isGM hasTarget)}} | ||||
|                     {{{localize "CTHULHUETERNAL.Roll.displayArmor" targetName=targetName targetArmor=targetArmor realDamage=realDamage}}} | ||||
|             {{/if}} | ||||
|         </div> | ||||
|      {{/if}} | ||||
|     {{#unless isPrivate}} | ||||
|         <div class="dice-result"> | ||||
|             <h4 class="dice-total">{{total}}</h4> | ||||
|             <div class="dice-formula">{{formula}}</div> | ||||
|             {{{tooltip}}}         | ||||
|         </div> | ||||
|     {{/unless}} | ||||
| </div> | ||||
|     <div class="intro-right"> | ||||
|       <ul> | ||||
|         {{#if (eq rollType "char")}} | ||||
|         <li><strong>{{localize "CTHULHUETERNAL.Label.charRoll"}}</strong></li> | ||||
|         {{/if}} | ||||
|  | ||||
|         {{#if (eq rollType "skill")}} | ||||
|         <li><strong>{{localize "CTHULHUETERNAL.Label.skillRoll"}}</strong></li> | ||||
|         {{/if}} | ||||
|  | ||||
|         {{#if isNudgedRoll}} | ||||
|         <li><strong>{{localize "CTHULHUETERNAL.Label.nudgedRoll"}} : {{wpCost}} WP spent</strong></li> | ||||
|         {{/if}} | ||||
|  | ||||
|         {{#if weapon}} | ||||
|         <li><strong>Weapon : {{weapon.name}}</strong></li> | ||||
|         {{/if}} | ||||
|          | ||||
|         {{#if (eq rollType "resource")}} | ||||
|         <li><strong>{{rollItem.name}} : {{initialScore}}</strong></li> | ||||
|         {{else}} | ||||
|         <li><strong>{{rollItem.name}} : {{initialScore}}%</strong></li> | ||||
|         {{/if}} | ||||
|  | ||||
|         {{#if isZeroWP}} | ||||
|         <li class="red-warning">Zero WP : Automatic failure (ie 0%)</li> | ||||
|         {{else}} | ||||
|         {{#if isLowWP}} | ||||
|         <li class="orange-warning">Low WP : -20%</li> | ||||
|         {{/if}} | ||||
|         {{/if}} | ||||
|  | ||||
|         {{#if isExhausted}} | ||||
|         <li class="orange-warning">Exhausted : -20%</li> | ||||
|         {{/if}} | ||||
|  | ||||
|         {{#if  (eq rollType "resource")}} | ||||
|         <li>{{localize "CTHULHUETERNAL.Label.multiplier"}} : {{multiplier}}</li> | ||||
|         {{else}} | ||||
|         <li>{{localize "CTHULHUETERNAL.Label.modifier"}} : {{modifier}}%</li> | ||||
|         {{/if}} | ||||
|    | ||||
|         <li>{{localize "CTHULHUETERNAL.Label.targetScore"}} : {{targetScore}}%</li> | ||||
|         {{#if isSuccess}} | ||||
|         {{#if isCritical}} | ||||
|         <li class="result-critical-success">{{localize "CTHULHUETERNAL.Label.criticalSuccess"}}</li> | ||||
|         {{else}} | ||||
|         <li class="result-success"> | ||||
|           {{localize "CTHULHUETERNAL.Label.success"}} | ||||
|           {{#if isNudge}} | ||||
|             <a class="nudge-roll"><i class="fa-solid fa-circle-sort-down"></i></a> | ||||
|           {{/if}} | ||||
|         </li> | ||||
|         {{/if}} | ||||
|         {{/if}} | ||||
|         {{#if isFailure}} | ||||
|         {{#if isCritical}} | ||||
|         <li class="result-critical-failure">{{localize "CTHULHUETERNAL.Label.criticalFailure"}}</li> | ||||
|         {{else}} | ||||
|         <li class="result-failure"> | ||||
|           {{localize "CTHULHUETERNAL.Label.failure"}} | ||||
|           {{#if isNudge}} | ||||
|             <a class="nudge-roll"><i class="fa-solid fa-circle-sort-down"></i></a> | ||||
|           {{/if}} | ||||
|         </li> | ||||
|         {{/if}} | ||||
|         {{/if}} | ||||
|       </ul> | ||||
|     </div> | ||||
|   </div> | ||||
|   {{#if isDamage}} | ||||
|   <div> | ||||
|     {{#if (and isGM hasTarget)}} | ||||
|     {{{localize "CTHULHUETERNAL.Roll.displayArmor" targetName=targetName targetArmor=targetArmor | ||||
|     realDamage=realDamage}}} | ||||
|     {{/if}} | ||||
|   </div> | ||||
|   {{/if}} | ||||
|   {{#unless isPrivate}} | ||||
|   <div class="dice-result"> | ||||
|     <h4 class="dice-total">{{total}}</h4> | ||||
|     <div class="dice-formula">{{formula}}</div> | ||||
|     {{{tooltip}}} | ||||
|   </div> | ||||
|   {{/unless}} | ||||
| </div> | ||||
							
								
								
									
										12
									
								
								templates/creature-biography.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								templates/creature-biography.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| <section class="tab creature-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}"> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} | ||||
|   </fieldset> | ||||
|    | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.notes"}}</legend> | ||||
|     {{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}} | ||||
|   </fieldset> | ||||
| </section> | ||||
							
								
								
									
										95
									
								
								templates/creature-main.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								templates/creature-main.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,95 @@ | ||||
| <section class="creature-main creature-main-{{ifThen isPlayMode 'play' 'edit'}}"> | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.creature"}}</legend> | ||||
|     <div class="creature-pc creature-pc-{{ifThen isPlayMode 'play' 'edit'}}"> | ||||
|       <div class="creature-left"> | ||||
|         <div class="creature-left-image"> | ||||
|           <img class="creature-img" src="{{actor.img}}" data-edit="img" data-action="editImage" | ||||
|             data-tooltip="{{actor.name}}" /> | ||||
|         </div> | ||||
|  | ||||
|       </div> | ||||
|       <div class="creature-right"> | ||||
|         <div class="creature-name"> | ||||
|           {{formInput fields.name value=source.name rootId=partId disabled=isPlayMode}} | ||||
|           <a class="control" data-action="toggleSheet" data-tooltip="CTHULHUETERNAL.ToggleSheet" | ||||
|             data-tooltip-direction="UP"> | ||||
|             <i class="fa-solid fa-user-{{ifThen isPlayMode 'lock' 'pen'}}"></i> | ||||
|           </a> | ||||
|         </div> | ||||
|         <fieldset class="creature-hp">  | ||||
|           <legend>{{localize "CTHULHUETERNAL.Label.HP"}}</legend> | ||||
|           <div class="flexrow"> | ||||
|             {{formField systemFields.hp.fields.value value=system.hp.value}} | ||||
|             <span class="hp-separator">/</span> | ||||
|             {{formField systemFields.hp.fields.max value=system.hp.max }} | ||||
|           </div> | ||||
|           <div class="flexrow "> | ||||
|             {{formField systemFields.damageBonus value=system.damageBonus classes="damage-bonus"}} | ||||
|           </div> | ||||
|         </fieldset> | ||||
|  | ||||
|         <fieldset class="willpower"> | ||||
|           <legend>{{localize "CTHULHUETERNAL.Label.willpower"}}</legend> | ||||
|           <div class="flexrow"> | ||||
|             <label class="label-field">{{localize "CTHULHUETERNAL.Label.current"}}</label> | ||||
|             {{formInput systemFields.wp.fields.value value=system.wp.value}} | ||||
|             <label class="label-field">{{localize "CTHULHUETERNAL.Label.max"}}</label> | ||||
|             {{formInput systemFields.wp.fields.max value=system.wp.max rootId=partId }} | ||||
|             <label class="label-field">{{localize "CTHULHUETERNAL.Label.exhausted"}}</label> | ||||
|             {{formInput systemFields.wp.fields.exhausted value=system.wp.exhausted classes="checkbox"}} | ||||
|           </div> | ||||
|         </fieldset> | ||||
|  | ||||
|       </div> | ||||
|  | ||||
|        | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset class="creature-characteristics creature-characteristics-{{ifThen isPlayMode 'play' 'edit'}}"> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.characteristics"}}</legend> | ||||
|     <div class="creature-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="str" data-tooltip="{{system.characteristics.str.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.strShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.str.fields.value value=system.characteristics.str.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       <label class="char-text">{{mul system.characteristics.str.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="creature-characteristic"> | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="dex" data-tooltip="{{system.characteristics.dex.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.dexShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.dex.fields.value value=system.characteristics.dex.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       <label class="char-text">{{mul system.characteristics.dex.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="creature-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="con" data-tooltip="{{system.characteristics.con.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.conShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.con.fields.value value=system.characteristics.con.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|        <label class="char-text">{{mul system.characteristics.con.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="creature-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="int" data-tooltip="{{system.characteristics.int.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.intShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.int.fields.value value=system.characteristics.int.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|        <label class="char-text">{{mul system.characteristics.int.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="creature-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="pow" data-tooltip="{{system.characteristics.pow.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.powShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.pow.fields.value value=system.characteristics.pow.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|        <label class="char-text">{{mul system.characteristics.pow.value 5}}</label> | ||||
|     </div> | ||||
|  | ||||
|   </fieldset> | ||||
|  | ||||
| </section> | ||||
							
								
								
									
										57
									
								
								templates/creature-skills.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								templates/creature-skills.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| <section class="tab creature-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}"> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.weapons"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i | ||||
|           class="fas fa-plus" data-action="createWeapon"></i></a>{{/if}} | ||||
|     </legend> | ||||
|     <div class="weapons"> | ||||
|       {{#each weapons as |item|}} | ||||
|       {{!log 'weapon' this}} | ||||
|       <div class="weapon item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true"> | ||||
|  | ||||
|         <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|         <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|         <div class="name rollable" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}"> | ||||
|           {{item.name}} | ||||
|         </div> | ||||
|  | ||||
|         <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|         <a class="damage rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage" | ||||
|           data-roll-value="{{item.system.damage}}"> | ||||
|           {{localize "CTHULHUETERNAL.Label.damageShort"}} : | ||||
|           {{item.system.damage}}</a> | ||||
|         <div class="controls"> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|         </div> | ||||
|       </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.skills"}}" data-tooltip-direction="UP">{{localize "CTHULHUETERNAL.Label.skills"}}</legend> | ||||
|     <div class="skills"> | ||||
|         {{#each skills as |item|}} | ||||
|           <div class="skill item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|             <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|             <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|             <div class="name rollable" data-roll-type="skill" data-tooltip="{{{item.description}}}" data-tooltip-direction="UP">{{item.name}} | ||||
|             </div> | ||||
|             <div class="score" > | ||||
|               {{item.system.skillTotal}} | ||||
|             </div> | ||||
|             <div class="controls"> | ||||
|               <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|               <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|             </div> | ||||
|           </div> | ||||
|         {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|  | ||||
| </section> | ||||
| @@ -7,11 +7,12 @@ | ||||
|   <fieldset> | ||||
|     {{formField systemFields.settings value=system.settings localize=true}} | ||||
|     {{formField systemFields.resourceLevel value=system.resourceLevel}} | ||||
|     {{formField systemFields.state value=system.state localize=true}} | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput systemFields.description enriched=description value=system.description name="system.description" | ||||
|     {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" | ||||
|     toggled=true}} | ||||
|   </fieldset> | ||||
|  | ||||
|   | ||||
| @@ -1,39 +0,0 @@ | ||||
| <table class="tenebris-table"> | ||||
|   <thead> | ||||
|     <tr> | ||||
|       <th>{{localize "TENEBRIS.Manager.player"}}</th> | ||||
|       <th>{{localize "TENEBRIS.Manager.character"}}</th> | ||||
|       <th>{{localize "TENEBRIS.Manager.pv"}}</th> | ||||
|       <td data-action="saveAll" data-save="rob">{{localize "TENEBRIS.Manager.rob"}}</td> | ||||
|       <td data-action="saveAll" data-save="dex">{{localize "TENEBRIS.Manager.dex"}}</td> | ||||
|       <td data-action="saveAll" data-save="int">{{localize "TENEBRIS.Manager.int"}}</td> | ||||
|       <td data-action="saveAll" data-save="per">{{localize "TENEBRIS.Manager.per"}}</td> | ||||
|       <td data-action="saveAll" data-save="vol">{{localize "TENEBRIS.Manager.vol"}}</td> | ||||
|       <td data-action="resourceAll" data-resource="san">{{localize "TENEBRIS.Manager.san"}}</td> | ||||
|       <td data-action="resourceAll" data-resource="oeil">{{localize "TENEBRIS.Manager.oeil"}}</td> | ||||
|       <td data-action="resourceAll" data-resource="verbe">{{localize "TENEBRIS.Manager.verbe"}}</td> | ||||
|       <td data-action="resourceAll" data-resource="bourse">{{localize "TENEBRIS.Manager.bourse"}}</td> | ||||
|       <td data-action="resourceAll" data-resource="magie">{{localize "TENEBRIS.Manager.magie"}}</td> | ||||
|     </tr> | ||||
|   </thead> | ||||
|   <tbody> | ||||
|     {{#each players as |player|}} | ||||
|       {{!log "player" this}} | ||||
|       <tr class="player" data-user-id="{{player.id}}" data-character-name="{{player.character.name}}" data-character-id="{{player.character.id}}"> | ||||
|         <td>{{player.name}}</td> | ||||
|         <td data-action="openSheet" data-character-id="{{player.character.id}}">{{player.character.name}}</td> | ||||
|         <td>{{player.character.system.pv.value}}</td> | ||||
|         <td data-action="saveOne" data-save="rob">{{player.character.system.caracteristiques.rob.valeur}}</td> | ||||
|         <td data-action="saveOne" data-save="dex">{{player.character.system.caracteristiques.dex.valeur}}</td> | ||||
|         <td data-action="saveOne" data-save="int">{{player.character.system.caracteristiques.int.valeur}}</td> | ||||
|         <td data-action="saveOne" data-save="per">{{player.character.system.caracteristiques.per.valeur}}</td> | ||||
|         <td data-action="saveOne" data-save="vol">{{player.character.system.caracteristiques.vol.valeur}}</td> | ||||
|         <td data-action="resourceOne" data-resource="san">{{player.character.system.ressources.san.valeur}}</td> | ||||
|         <td data-action="resourceOne" data-resource="oeil">{{player.character.system.ressources.oeil.valeur}}</td> | ||||
|         <td data-action="resourceOne" data-resource="verbe">{{player.character.system.ressources.verbe.valeur}}</td> | ||||
|         <td data-action="resourceOne" data-resource="bourse">{{player.character.system.ressources.bourse.valeur}}</td> | ||||
|         <td data-action="resourceOne" data-resource="magie">{{player.character.system.ressources.magie.valeur}}</td> | ||||
|       </tr> | ||||
|     {{/each}} | ||||
|   </tbody> | ||||
| </table> | ||||
| @@ -2,13 +2,17 @@ | ||||
|   <div class="header"> | ||||
|     <img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" /> | ||||
|     {{formInput fields.name value=source.name}} | ||||
|   </div>  | ||||
|    | ||||
|   </div> | ||||
|  | ||||
|   <fieldset> | ||||
|     {{formField systemFields.cured value=system.cured localize=true}} | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput | ||||
|       systemFields.description | ||||
|       enriched=description | ||||
|       enriched=enrichedDescription | ||||
|       value=system.description | ||||
|       name="system.description" | ||||
|       toggled="false" | ||||
|   | ||||
| @@ -2,11 +2,11 @@ | ||||
|   <div class="header"> | ||||
|     <img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" /> | ||||
|     {{formInput fields.name value=source.name}} | ||||
|   </div>   | ||||
|   </div> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}} | ||||
|     {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} | ||||
|   </fieldset> | ||||
|  | ||||
| </section> | ||||
							
								
								
									
										18
									
								
								templates/nudge-dialog.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								templates/nudge-dialog.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| <div class="fvtt-cthulhu-eternal-roll-dialog"> | ||||
|  | ||||
|   <fieldSet class="dialog-modifier"> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.selectNewValue"}}</legend> | ||||
|     <select name="modifiedValue" class="nudged-score-select"> | ||||
|       {{selectOptions nudgeOptions selected=rollResultIndex}} | ||||
|     </select> | ||||
|   </fieldSet> | ||||
|  | ||||
|   <fieldSet> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.wpCost"}}</legend> | ||||
|     <div> | ||||
|       Willpower points cost :  | ||||
|       <input class="text" value="0" id="nudged-wp-cost" disabled > | ||||
|     </div> | ||||
|   </fieldSet> | ||||
|  | ||||
| </div> | ||||
| @@ -1,7 +1,29 @@ | ||||
| <section class="tab protagonist-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}"> | ||||
|    | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.resources"}}</legend> | ||||
|      <div class="resources"> | ||||
|       {{formField systemFields.resources.fields.permanentRating value=system.resources.permanentRating name="system.resources.permanentRating" localize=true}} | ||||
|       <div> | ||||
|         <span class="label-field">{{localize "CTHULHUETERNAL.Label.resourceChecks"}}</span> | ||||
|         {{#each system.resources.checks as |check idx|}} | ||||
|         <input class="san-checkbox" type="checkbox" data-action="updateCheckResource" data-index="{{@index}}" | ||||
|           data-name="checks" {{#if check}} checked {{/if}}   {{#if (gte @index @root.system.resources.nbValidChecks)}} disabled {{/if}}> | ||||
|         {{/each}} | ||||
|       </div> | ||||
|       <button class="resource-roll rollable" data-roll-type="resource"><img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />Resource roll</button> | ||||
|       {{formField systemFields.resources.fields.hand value=system.resources.hand name="system.resources.hand" localize=true disabled=true}} | ||||
|       {{formField systemFields.resources.fields.stowed value=system.resources.stowed name="system.resources.stowed" localize=true disabled=true}} | ||||
|       {{formField systemFields.resources.fields.storage value=system.resources.storage name="system.resources.storage" localize=true disabled=true}} | ||||
|       </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.biodata"}}</legend> | ||||
|     <div class="adapted"> | ||||
|       {{formField systemFields.biodata.fields.adaptedToViolence value=system.biodata.adaptedToViolence name="system.biodata.adaptedToViolence" localize=true}}       | ||||
|       {{formField systemFields.biodata.fields.adaptedToHelplessness value=system.biodata.adaptedToHelplessness name="system.biodata.adaptedToHelplessness" localize=true}}             | ||||
|     </div> | ||||
|     <div class="biodata"> | ||||
|       {{formField systemFields.biodata.fields.harshness value=system.biodata.harshness name="system.biodata.harshness" localize=true}}       | ||||
|       {{formField systemFields.biodata.fields.age value=system.biodata.age name="system.biodata.age" localize=true classes="field-label"}} | ||||
| @@ -9,38 +31,49 @@ | ||||
|       {{formField systemFields.biodata.fields.height value=system.biodata.height name="system.biodata.height" localize=true classes="field-label"}} | ||||
|       {{formField systemFields.biodata.fields.eyes value=system.biodata.eyes name="system.biodata.eyes" localize=true classes="field-label"}} | ||||
|       {{formField systemFields.biodata.fields.hair value=system.biodata.hair name="system.biodata.hair" localize=true classes="field-label"}} | ||||
|       {{formField systemFields.biodata.fields.gender value=system.biodata.gender name="system.biodata.gender" localize=true classes="field-label"}} | ||||
|       {{formField systemFields.biodata.fields.home value=system.biodata.home name="system.biodata.home" localize=true classes="field-label"}} | ||||
|       {{formField systemFields.biodata.fields.birthplace value=system.biodata.birthplace name="system.biodata.birthplace" localize=true classes="field-label"}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.motivations"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addMotivation"}}" data-tooltip-direction="UP"><i class="fas fa-plus" data-action="createMotivation"></i></a>{{/if}}</legend> | ||||
|     <div class="motivations"> | ||||
|       {{#each motivations as |item|}} | ||||
|         {{!log 'armor' this}} | ||||
|         <div class="motivation" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|           <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|           <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|             {{item.name}} | ||||
|           </div> | ||||
|           <div class="controls"> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|           </div> | ||||
|         </div> | ||||
|       {{/each}} | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.distinguishingFeatures"}}</legend> | ||||
|     <div class="features"> | ||||
|       <div class="feature">  | ||||
|         <label>{{localize "CTHULHUETERNAL.Label.strShort"}}</label> | ||||
|         {{formInput systemFields.characteristics.fields.str.fields.feature value=system.characteristics.str.feature localize=true}}  | ||||
|       </div> | ||||
|       <div class="feature">  | ||||
|         <label>{{localize "CTHULHUETERNAL.Label.dexShort"}}</label> | ||||
|         {{formInput systemFields.characteristics.fields.dex.fields.feature value=system.characteristics.dex.feature localize=true}}  | ||||
|       </div> | ||||
|       <div class="feature">  | ||||
|         <label>{{localize "CTHULHUETERNAL.Label.conShort"}}</label> | ||||
|         {{formInput systemFields.characteristics.fields.con.fields.feature value=system.characteristics.con.feature localize=true}}  | ||||
|       </div> | ||||
|       <div class="feature">  | ||||
|         <label>{{localize "CTHULHUETERNAL.Label.intShort"}}</label> | ||||
|         {{formInput systemFields.characteristics.fields.int.fields.feature value=system.characteristics.int.feature localize=true}}  | ||||
|       </div> | ||||
|       <div class="feature">  | ||||
|         <label>{{localize "CTHULHUETERNAL.Label.powShort"}}</label> | ||||
|         {{formInput systemFields.characteristics.fields.pow.fields.feature value=system.characteristics.pow.feature localize=true}}  | ||||
|       </div> | ||||
|       <div class="feature">  | ||||
|         <label>{{localize "CTHULHUETERNAL.Label.chaShort"}}</label> | ||||
|         {{formInput systemFields.characteristics.fields.cha.fields.feature value=system.characteristics.cha.feature localize=true}}  | ||||
|       </div> | ||||
|     </div> | ||||
|   </fieldset> | ||||
|   </fieldset>  | ||||
|  | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput systemFields.description enriched=description value=system.description name="system.description" toggled=true}} | ||||
|     {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} | ||||
|   </fieldset> | ||||
|    | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.notes"}}</legend> | ||||
|     {{formInput systemFields.notes enriched=notes value=system.notes name="system.notes" toggled=true}} | ||||
|     {{formInput systemFields.notes enriched=enrichedNotes value=system.notes name="system.notes" toggled=true}} | ||||
|   </fieldset> | ||||
| </section> | ||||
| @@ -2,64 +2,134 @@ | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.weapons"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i class="fas fa-plus" data-action="createWeapon"></i></a>{{/if}}</legend> | ||||
|       <a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addWeapon"}}" data-tooltip-direction="UP"><i | ||||
|           class="fas fa-plus" data-action="createWeapon"></i></a>{{/if}} | ||||
|     </legend> | ||||
|     <div class="weapons"> | ||||
|       {{#each weapons as |item|}} | ||||
|         {{!log 'weapon' this}} | ||||
|         <div class="weapon item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true" > | ||||
|           <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|           <div class="name rollable" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}"> | ||||
|             {{item.name}} | ||||
|           </div> | ||||
|           <a class="damage rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage" data-roll-value="{{item.system.damage}}">{{localize "CTHULHUETERNAL.Label.damageShort"}} : {{item.system.damage}}</a> | ||||
|           <div class="controls"> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|           </div> | ||||
|       {{!log 'weapon' this}} | ||||
|       <div class="weapon item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true"> | ||||
|  | ||||
|         <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|         <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|         <div class="name rollable" data-roll-type="weapon" data-tooltip="{{{item.system.description}}}"> | ||||
|           {{item.name}} | ||||
|         </div> | ||||
|  | ||||
|         <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|         <a class="damage rollable" data-item-id="{{item.id}}" data-action="roll" data-roll-type="damage" | ||||
|           data-roll-value="{{item.system.damage}}"> | ||||
|           {{localize "CTHULHUETERNAL.Label.damageShort"}} : | ||||
|           {{item.system.damage}}</a> | ||||
|         <div class="controls"> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|         </div> | ||||
|       </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.armors"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addArmor"}}" data-tooltip-direction="UP"><i class="fas fa-plus" data-action="createArmor"></i></a>{{/if}}</legend> | ||||
|       <a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addArmor"}}" data-tooltip-direction="UP"><i | ||||
|           class="fas fa-plus" data-action="createArmor"></i></a>{{/if}} | ||||
|     </legend> | ||||
|     <div class="armors"> | ||||
|       {{#each armors as |item|}} | ||||
|         {{!log 'armor' this}} | ||||
|         <div class="armor" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|           <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|           <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|             {{item.name}} | ||||
|           </div> | ||||
|           <span class="protection">{{localize "CTHULHUETERNAL.Label.armor"}} : {{item.system.protection}}</span> | ||||
|           <div class="controls"> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|           </div> | ||||
|       {{!log 'armor' this}} | ||||
|       <div class="armor" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|         <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|         <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|           {{item.name}} | ||||
|         </div> | ||||
|         <span class="protection">{{localize "CTHULHUETERNAL.Label.armor"}} : {{item.system.protection}}</span> | ||||
|         <div class="controls"> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|         </div> | ||||
|       </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.gears"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addGear"}}" data-tooltip-direction="UP"><i class="fas fa-plus" data-action="createGear"></i></a>{{/if}}</legend> | ||||
|       <a class="action" data-tooltip="{{localize " CTHULHUETERNAL.Tooltip.addGear"}}" data-tooltip-direction="UP"><i | ||||
|           class="fas fa-plus" data-action="createGear"></i></a>{{/if}} | ||||
|     </legend> | ||||
|     <div class="gears"> | ||||
|       {{#each gears as |item|}} | ||||
|         {{!log 'armor' this}} | ||||
|         <div class="gear" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|           <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|           <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|             {{item.name}} | ||||
|           </div> | ||||
|           <div class="controls"> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|           </div> | ||||
|       {{!log 'armor' this}} | ||||
|       <div class="gear" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|         <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|         <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|           {{item.name}} | ||||
|         </div> | ||||
|         <div class="controls"> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|         </div> | ||||
|       </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   {{#if (count tomes)}} | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.Tomes"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addTome"}}" data-tooltip-direction="UP"><i | ||||
|           class="fas fa-plus" data-action="createTome"></i></a>{{/if}} | ||||
|     </legend> | ||||
|     <div class="tomes"> | ||||
|       {{#each tomes as |item|}} | ||||
|       <div class="tome" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|         <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|         <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|           {{item.name}} | ||||
|         </div> | ||||
|         <div class="controls"> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|         </div> | ||||
|       </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|   {{/if}} | ||||
|  | ||||
|   {{#if (count rituals)}} | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.Rituals"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addRitual"}}" data-tooltip-direction="UP"><i | ||||
|           class="fas fa-plus" data-action="createRitual"></i></a>{{/if}} | ||||
|     </legend> | ||||
|     <div class="rituals"> | ||||
|       {{#each rituals as |item|}} | ||||
|       <div class="ritual" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|         <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|         <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|           {{item.name}} | ||||
|         </div> | ||||
|         <div class="controls"> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|           <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" | ||||
|             data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|         </div> | ||||
|       </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|   {{/if}} | ||||
|  | ||||
|  | ||||
| </section> | ||||
| @@ -9,13 +9,16 @@ | ||||
|           <img class="protagonist-img" src="{{actor.img}}" data-edit="img" data-action="editImage" | ||||
|             data-tooltip="{{actor.name}}" /> | ||||
|         </div> | ||||
|         <fieldset> | ||||
|         <fieldset class="protagonist-hp">  | ||||
|           <legend>{{localize "CTHULHUETERNAL.Label.HP"}}</legend> | ||||
|           <div class="flexrow"> | ||||
|             {{formField systemFields.hp.fields.value value=system.hp.value}} | ||||
|             / | ||||
|             <span class="hp-separator">/</span> | ||||
|             {{formField systemFields.hp.fields.max value=system.hp.max rootId=partId disabled=true}} | ||||
|           </div> | ||||
|           <div class="flexrow "> | ||||
|             {{formField systemFields.damageBonus value=system.damageBonus classes="damage-bonus"}} | ||||
|           </div> | ||||
|         </fieldset> | ||||
|  | ||||
|       </div> | ||||
| @@ -32,41 +35,64 @@ | ||||
|         <fieldset class="san"> | ||||
|           <legend>{{localize "CTHULHUETERNAL.Label.SAN"}}</legend> | ||||
|           <div class="flexrow"> | ||||
|             <span class="label-field">{{localize "CTHULHUETERNAL.Label.current"}}</span> | ||||
|             {{formField systemFields.san.fields.value value=system.san.value}} | ||||
|              <span class="label-field">{{localize "CTHULHUETERNAL.Label.max"}}</span>  | ||||
|              {{formField systemFields.san.fields.max value=system.san.max rootId=partId disabled=true}} | ||||
|             <span class="label-field">{{localize "CTHULHUETERNAL.Label.recovery"}}</span>  | ||||
|             {{formField systemFields.san.fields.recovery value=system.san.recovery disabled=true}} | ||||
|             <span class="label-field" data-tooltip='{{localize "CTHULHUETERNAL.Tooltip.sanBP"}}'>{{localize | ||||
|               "CTHULHUETERNAL.Label.breakingPoint"}}</span>  | ||||
|               {{formField systemFields.san.fields.breakingPoint value=system.san.breakingPoint disabled=true}} | ||||
|              | ||||
|             <label class="label-field rollable" data-roll-type="san" ><img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" />  | ||||
|             {{localize "CTHULHUETERNAL.Label.current"}}</label> | ||||
|             {{formInput systemFields.san.fields.value value=system.san.value}} | ||||
|              | ||||
|             <span class="label-field label-recovery">{{localize "CTHULHUETERNAL.Label.recovery"}}</span>  | ||||
|             {{formInput systemFields.san.fields.recovery value=system.san.recovery disabled=true}} | ||||
|  | ||||
|             <span class="label-bp" data-tooltip='{{localize "CTHULHUETERNAL.Tooltip.sanBPShort"}}'>{{localize | ||||
|               "CTHULHUETERNAL.Label.sanBPShort"}}</span>  | ||||
|             {{formInput systemFields.san.fields.breakingPoint value=system.san.breakingPoint disabled=true}} | ||||
|  | ||||
|           </div> | ||||
|  | ||||
|           <div class="flexrow"> | ||||
|              | ||||
|             <div class="flexrow"> | ||||
|              <span class="label-short-field">{{localize "CTHULHUETERNAL.Label.max"}}</span>  | ||||
|               {{formInput systemFields.san.fields.max value=system.san.max rootId=partId disabled=true}} | ||||
|             </div> | ||||
|  | ||||
|             <span class="label-insanity" > | ||||
|               {{localize "CTHULHUETERNAL.Label.tempInsanity"}} | ||||
|             </span> | ||||
|             {{formInput systemFields.san.fields.insanity value=system.san.insanity localize=true}} | ||||
|  | ||||
|             {{#if (not isPlayMode)}} | ||||
|               <button data-action="setBP" class="button" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.setBP"}}">{{localize "CTHULHUETERNAL.Label.setBP"}}</button> | ||||
|             {{/if}} | ||||
|  | ||||
|           </div> | ||||
|           <div class="flexrow"> | ||||
|             {{localize "CTHULHUETERNAL.Label.violence"}} | ||||
|  | ||||
|             <span class="label-field">{{localize "CTHULHUETERNAL.Label.violence"}}</span> | ||||
|             {{#each system.san.violence as |violence idx|}} | ||||
|             <input class="san-checkbox" type="checkbox" data-action="updateCheckboxArray" data-index="{{@index}}" | ||||
|               data-name="violence" {{#if violence}} checked {{/if}}> | ||||
|             {{/each}} | ||||
|             <span class="spacing"></span> | ||||
|             {{localize "CTHULHUETERNAL.Label.helplessness"}} | ||||
|              | ||||
|             <span class="label-field">{{localize "CTHULHUETERNAL.Label.helplessness"}}</span> | ||||
|             {{#each system.san.helplessness as |helplessness idx|}} | ||||
|             <input class="san-checkbox" type="checkbox" data-action="updateCheckboxArray" data-index="{{@index}}" | ||||
|               data-name="helplessness" {{#if helplessness}} checked {{/if}}> | ||||
|             {{/each}} | ||||
|  | ||||
|           </div> | ||||
|  | ||||
|         </fieldset> | ||||
|  | ||||
|         <fieldset class="willpower"> | ||||
|           <legend>{{localize "CTHULHUETERNAL.Label.willpower"}}</legend> | ||||
|           <div class="flexrow"> | ||||
|             <span class="label-field">{{localize "CTHULHUETERNAL.Label.current"}}</span> | ||||
|             {{formField systemFields.wp.fields.value value=system.wp.value}} | ||||
|             <span class="label-field">{{localize "CTHULHUETERNAL.Label.max"}}</span> | ||||
|             {{formField systemFields.wp.fields.max value=system.wp.max rootId=partId disabled=true}} | ||||
|             <span class="label-field">{{localize "CTHULHUETERNAL.Label.exhausted"}}</span> | ||||
|             {{formField systemFields.wp.fields.exhausted value=system.wp.exhausted classes=checkbox}} | ||||
|  | ||||
|             <label class="label-field">{{localize "CTHULHUETERNAL.Label.current"}}</label> | ||||
|             {{formInput systemFields.wp.fields.value value=system.wp.value}} | ||||
|             <label class="label-field">{{localize "CTHULHUETERNAL.Label.max"}}</label> | ||||
|             {{formInput systemFields.wp.fields.max value=system.wp.max rootId=partId disabled=true}} | ||||
|             <label class="label-field">{{localize "CTHULHUETERNAL.Label.exhausted"}}</label> | ||||
|             {{formInput systemFields.wp.fields.exhausted value=system.wp.exhausted classes="checkbox"}} | ||||
|           </div> | ||||
|         </fieldset> | ||||
|  | ||||
| @@ -76,47 +102,53 @@ | ||||
|  | ||||
|   <fieldset class="protagonist-characteristics protagonist-characteristics-{{ifThen isPlayMode 'play' 'edit'}}"> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.characteristics"}}</legend> | ||||
|     <div class="protagonist-characteristic" data-drag="true" data-drag-type="characteristic"> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="str">{{localize | ||||
|     <div class="protagonist-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="str" data-tooltip="{{system.characteristics.str.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.strShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.str.fields.value value=system.characteristics.str.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       {{mul system.characteristics.str.value 5}} | ||||
|       <label class="char-text">{{mul system.characteristics.str.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="protagonist-characteristic" data-drag="true" data-drag-type="characteristic"> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="dex">{{localize | ||||
|     <div class="protagonist-characteristic"> | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="dex" data-tooltip="{{system.characteristics.dex.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.dexShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.dex.fields.value value=system.characteristics.dex.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       {{mul system.characteristics.dex.value 5}} | ||||
|       <label class="char-text">{{mul system.characteristics.dex.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="protagonist-characteristic" data-drag="true" data-drag-type="characteristic"> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="con">{{localize | ||||
|     <div class="protagonist-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="con" data-tooltip="{{system.characteristics.con.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.conShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.con.fields.value value=system.characteristics.con.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       {{mul system.characteristics.con.value 5}} | ||||
|        <label class="char-text">{{mul system.characteristics.con.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="protagonist-characteristic" data-drag="true" data-drag-type="characteristic"> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="int">{{localize | ||||
|     <div class="protagonist-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="int" data-tooltip="{{system.characteristics.int.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.intShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.int.fields.value value=system.characteristics.int.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       {{mul system.characteristics.int.value 5}} | ||||
|        <label class="char-text">{{mul system.characteristics.int.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="protagonist-characteristic" data-drag="true" data-drag-type="characteristic"> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="pow">{{localize | ||||
|     <div class="protagonist-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="pow" data-tooltip="{{system.characteristics.pow.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.powShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.pow.fields.value value=system.characteristics.pow.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       {{mul system.characteristics.pow.value 5}} | ||||
|        <label class="char-text">{{mul system.characteristics.pow.value 5}}</label> | ||||
|     </div> | ||||
|     <div class="protagonist-characteristic" data-drag="true" data-drag-type="characteristic"> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="cha">{{localize | ||||
|     <div class="protagonist-characteristic" > | ||||
|       <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|       <label class="rollable" data-roll-type="char" data-char-id="cha" data-tooltip="{{system.characteristics.cha.feature}}">{{localize | ||||
|         "CTHULHUETERNAL.Label.chaShort"}}</label> | ||||
|       {{formField systemFields.characteristics.fields.cha.fields.value value=system.characteristics.cha.value | ||||
|       rootId=partId disabled=isPlayMode }} | ||||
|       {{mul system.characteristics.cha.value 5}} | ||||
|        <label class="char-text">{{mul system.characteristics.cha.value 5}}</label> | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
|         {{#each skills as |item|}} | ||||
|           <div class="skill item" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|             <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|             <img src="systems/fvtt-cthulhu-eternal/assets/ui/d100.svg" class="d100" /> | ||||
|             <div class="name rollable" data-roll-type="skill" data-tooltip="{{{item.description}}}" data-tooltip-direction="UP">{{item.name}} | ||||
|             </div> | ||||
|             <div class="score" > | ||||
|   | ||||
| @@ -12,7 +12,7 @@ | ||||
|             {{item.name}} | ||||
|           </div> | ||||
|           <div class="type"> | ||||
|             {{item.system.bondType}} | ||||
|             {{upperFirst item.system.bondType}} | ||||
|           </div> | ||||
|           <div class="level"> | ||||
|             {{item.system.value}} | ||||
| @@ -52,6 +52,33 @@ | ||||
|       {{#each mentaldisorders as |item|}} | ||||
|         {{!log 'armor' this}} | ||||
|         <div class="mentaldisorder" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|           <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|           <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|             {{item.name}} | ||||
|           </div> | ||||
|           <div class="cured"> | ||||
|             {{#if item.system.cured}} | ||||
|               {{localize 'CTHULHUETERNAL.Label.Cured'}} | ||||
|             {{else}} | ||||
|               {{localize 'CTHULHUETERNAL.Label.Uncured'}} | ||||
|             {{/if}} | ||||
|           </div> | ||||
|           <div class="controls"> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Edit'}}" data-action="edit" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a> | ||||
|             <a data-tooltip="{{localize 'CTHULHUETERNAL.Delete'}}" data-action="delete" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a> | ||||
|           </div> | ||||
|         </div> | ||||
|       {{/each}} | ||||
|     </div> | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.motivations"}}{{#if isEditMode}} | ||||
|       <a class="action" data-tooltip="{{localize "CTHULHUETERNAL.Tooltip.addMotivation"}}" data-tooltip-direction="UP"><i class="fas fa-plus" data-action="createMotivation"></i></a>{{/if}}</legend> | ||||
|     <div class="motivations"> | ||||
|       {{#each motivations as |item|}} | ||||
|         {{!log 'armor' this}} | ||||
|         <div class="motivation" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}"> | ||||
|           <img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" /> | ||||
|           <div class="name" data-tooltip="{{{item.system.description}}}"> | ||||
|             {{item.name}} | ||||
|   | ||||
							
								
								
									
										24
									
								
								templates/ritual.hbs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								templates/ritual.hbs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| <section> | ||||
|   <div class="header"> | ||||
|     <img class="item-img" src="{{item.img}}" data-edit="img" data-action="editImage" data-tooltip="{{item.name}}" /> | ||||
|     {{formInput fields.name value=source.name}} | ||||
|   </div> | ||||
|  | ||||
|   <fieldset> | ||||
|  | ||||
|     {{formField systemFields.ritualType value=system.ritualType localize=true}} | ||||
|     {{formField systemFields.studyTime value=system.studyTime}} | ||||
|     {{formField systemFields.studySAN value=system.studySAN}} | ||||
|     {{formField systemFields.activationTime value=system.activationTime}} | ||||
|     {{formField systemFields.activationSAN value=system.activationSAN}} | ||||
|     {{formField systemFields.activationWP value=system.activationWP}} | ||||
|  | ||||
|   </fieldset> | ||||
|  | ||||
|   <fieldset> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.description"}}</legend> | ||||
|     {{formInput systemFields.description enriched=enrichedDescription value=system.description name="system.description" toggled=true}} | ||||
|  | ||||
|   </fieldset> | ||||
|  | ||||
| </section> | ||||
| @@ -1,34 +1,58 @@ | ||||
| {{log "roll-dialog" this}} | ||||
| <div class="fvtt-cthulhu-eternal-roll-dialog"> | ||||
|     <fieldSet> | ||||
|       {{#if (eq rollType "skill")}} | ||||
|       <legend>{{localize "CTHULHUETERNAL.Label.skill"}}</legend> | ||||
|       {{/if}} | ||||
|       {{#if (eq rollType "char")}} | ||||
|       <legend>{{localize "CTHULHUETERNAL.Label.characteristic"}}</legend> | ||||
|       {{/if}} | ||||
|   <fieldSet> | ||||
|     {{#if (eq rollType "skill")}} | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.skill"}}</legend> | ||||
|     {{/if}} | ||||
|     {{#if (eq rollType "char")}} | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.characteristic"}}</legend> | ||||
|     {{/if}} | ||||
|  | ||||
|       <div class="dialog-skill">{{rollItem.name}} : {{initialScore}}%</div> | ||||
|     {{#if (eq rollType "resource")}} | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.resourceRating"}}</legend> | ||||
|     <div class="dialog-skill">{{rollItem.name}} : <span class="resource-score">{{initialScore}} ({{mul initialScore 5}}%)</span></div>   | ||||
|     <div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Hand"}} : {{rollItem.hand}} <input type="checkbox" data-action="selectHand" {{checked rollItem.enableHand}}></div>   | ||||
|     <div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Stowed"}} : {{rollItem.stowed}} <input type="checkbox" data-action="selectStowed" {{checked rollItem.enableStowed}}></div>   | ||||
|     <div class="dialog-skill">{{localize "CTHULHUETERNAL.Label.Storage"}} : {{rollItem.storage}} <input type="checkbox" data-action="selectStorage" {{checked rollItem.enableStorage}}></div>   | ||||
|     {{else}} | ||||
|     <div class="dialog-skill">{{rollItem.name}} : {{initialScore}}%</div> | ||||
|     {{/if}} | ||||
|  | ||||
|       {{#if weapon}} | ||||
|       <div class="dialog-skill">Weapon : {{weapon.name}}</div> | ||||
|       {{/if}} | ||||
|     {{#if weapon}} | ||||
|     <div class="dialog-skill">Weapon : {{weapon.name}}</div> | ||||
|     {{/if}} | ||||
|  | ||||
|       {{#if isZeroWP}} | ||||
|       <div class="dialog-skill">Zero WP : Automatic failure (ie 0%)</div> | ||||
|       {{else}} | ||||
|         {{#if isLowWP}} | ||||
|         <div class="dialog-skill">Low WP : -20%</div> | ||||
|         {{/if}} | ||||
|       {{/if}} | ||||
|     </fieldSet> | ||||
|     {{#if isZeroWP}} | ||||
|     <div class="dialog-skill red-warning">Zero WP : Automatic failure (ie 0%)</div> | ||||
|     {{else}} | ||||
|     {{#if isLowWP}} | ||||
|     <div class="dialog-skill orange-warning">Low WP : -20%</div> | ||||
|     {{/if}} | ||||
|     {{/if}} | ||||
|  | ||||
|     {{#if isExhausted}} | ||||
|     <div class="dialog-skill orange-warning">Exhausted : -20%</div> | ||||
|     {{/if}} | ||||
|  | ||||
|   </fieldSet> | ||||
|  | ||||
|   {{#if hasModifier}} | ||||
|   <fieldSet class="dialog-modifier"> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.modifier"}}</legend> | ||||
|     <select name="modifier" class="roll-skill-modifier"> | ||||
|       {{selectOptions choiceModifier selected=modifier}} | ||||
|     </select> | ||||
|   </fieldSet> | ||||
|   {{/if}} | ||||
|  | ||||
|   {{#if hasMultiplier}} | ||||
|   <fieldSet class="dialog-modifier"> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.multiplier"}}</legend> | ||||
|     <select name="multiplier" class="roll-skill-modifier roll-skill-multiplier"> | ||||
|       {{selectOptions choiceMultiplier selected=multiplier}} | ||||
|     </select> | ||||
|   </fieldSet> | ||||
|   {{/if}} | ||||
|  | ||||
|     <fieldSet class="dialog-modifier"> | ||||
|       <legend>{{localize "CTHULHUETERNAL.Label.modifier"}}</legend> | ||||
|       <select name="modifier" class="roll-skill-modifier"> | ||||
|         {{selectOptions choiceModifier selected=modifier}} | ||||
|       </select> | ||||
|     </fieldSet> | ||||
|   <fieldSet> | ||||
|     <legend>{{localize "CTHULHUETERNAL.Label.rollView"}}</legend> | ||||
|     <select name="visibility"> | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user