diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..dfa1d18 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,163 @@ +{ + "env": { + "browser": true, + "es2022": true, + "node": true, + "jquery": true + }, + "ignorePatterns": ["**/*compiled.mjs"], + "parserOptions": { + "requireConfigFile": false, + "sourceType": "module", + "ecmaVersion": 2022 + }, + "rules": { + "array-bracket-spacing": ["warn", "never"], + "array-callback-return": "warn", + "arrow-spacing": "warn", + "brace-style": ["error", "stroustrup"], + "comma-dangle": ["warn", { + "arrays": "always-multiline", + "objects": "always-multiline", + "imports": "always-multiline", + "exports": "always-multiline", + "functions": "never" + }], + "comma-style": "warn", + "computed-property-spacing": "warn", + "constructor-super": "error", + "default-param-last": "warn", + "disallowTabs": 0, + "dot-location": ["warn", "property"], + "eol-last": ["error", "always"], + "eqeqeq": ["warn", "smart"], + "func-call-spacing": "warn", + "func-names": ["warn", "never"], + "getter-return": "warn", + "linebreak-style": ["warn", "unix"], + "lines-between-class-members": "warn", + "new-parens": ["warn", "always"], + "no-alert": "warn", + "no-array-constructor": "warn", + "no-class-assign": "warn", + "no-compare-neg-zero": "warn", + "no-cond-assign": "warn", + "no-const-assign": "error", + "no-constant-condition": "warn", + "no-constructor-return": "warn", + "no-delete-var": "warn", + "no-dupe-args": "warn", + "no-dupe-class-members": "warn", + "no-dupe-keys": "warn", + "no-duplicate-case": "warn", + "no-duplicate-imports": ["warn", {"includeExports": true}], + "no-empty": ["warn", {"allowEmptyCatch": true}], + "no-empty-character-class": "warn", + "no-empty-pattern": "warn", + "no-func-assign": "warn", + "no-global-assign": "warn", + "no-implicit-coercion": ["warn", {"allow": ["!!"]}], + "no-implied-eval": "warn", + "no-import-assign": "warn", + "no-invalid-regexp": "warn", + "no-irregular-whitespace": "warn", + "no-iterator": "warn", + "no-lone-blocks": "warn", + "no-lonely-if": "warn", + "no-loop-func": "warn", + "no-misleading-character-class": "warn", + "no-mixed-operators": "warn", + "no-multi-str": "warn", + "no-multiple-empty-lines": "warn", + "no-new-func": "warn", + "no-new-object": "warn", + "no-new-symbol": "warn", + "no-new-wrappers": "warn", + "no-nonoctal-decimal-escape": "warn", + "no-obj-calls": "warn", + "no-octal": "warn", + "no-octal-escape": "warn", + "no-promise-executor-return": "warn", + "no-proto": "warn", + "no-regex-spaces": "warn", + "no-script-url": "warn", + "no-self-assign": "warn", + "no-self-compare": "warn", + "no-setter-return": "warn", + "no-sequences": "warn", + "no-template-curly-in-string": "warn", + "no-this-before-super": "error", + "no-unexpected-multiline": "warn", + "no-unmodified-loop-condition": "warn", + "no-unneeded-ternary": "off", + "no-unreachable": "warn", + "no-unreachable-loop": "warn", + "no-unsafe-negation": ["warn", {"enforceForOrderingRelations": true}], + "no-unsafe-optional-chaining": ["warn", {"disallowArithmeticOperators": true}], + "no-unused-expressions": "warn", + "no-useless-backreference": "warn", + "no-useless-call": "warn", + "no-useless-catch": "warn", + "no-useless-computed-key": ["warn", {"enforceForClassMembers": true}], + "no-useless-concat": "warn", + "no-useless-constructor": "warn", + "no-useless-rename": "warn", + "no-useless-return": "warn", + "no-var": "warn", + "no-void": "warn", + "no-whitespace-before-property": "warn", + "prefer-numeric-literals": "warn", + "prefer-object-spread": "warn", + "prefer-regex-literals": "warn", + "prefer-spread": "warn", + "rest-spread-spacing": ["warn", "never"], + "semi-spacing": "warn", + "semi-style": ["warn", "last"], + "space-unary-ops": ["warn", {"words": true, "nonwords": false}], + "switch-colon-spacing": "warn", + "symbol-description": "warn", + "template-curly-spacing": ["warn", "never"], + "unicode-bom": ["warn", "never"], + "use-isnan": ["warn", {"enforceForSwitchCase": true, "enforceForIndexOf": true}], + "valid-typeof": ["warn", {"requireStringLiterals": true}], + "wrap-iife": ["warn", "inside"], + "arrow-parens": ["warn", "as-needed", {"requireForBlockBody": false}], + "capitalized-comments": "off", + "comma-spacing": "warn", + "dot-notation": "warn", + "indent": ["error", "tab", {"SwitchCase": 1}], + "key-spacing": "warn", + "keyword-spacing": ["warn", {"overrides": {"catch": {"before": true, "after": false}}}], + "max-len": ["warn", { + "code": 100, + "ignoreTrailingComments": false, + "ignoreUrls": true, + "ignoreStrings": true, + "ignoreTemplateLiterals": true + }], + "no-extra-boolean-cast": ["warn", {"enforceForLogicalOperands": true}], + "no-extra-semi": "warn", + "no-multi-spaces": "off", + "no-tabs": "off", + "no-throw-literal": "error", + "no-trailing-spaces": "error", + "no-useless-escape": "warn", + "no-unused-vars": ["warn", {"args": "none"}], + "nonblock-statement-body-position": ["warn", "beside"], + "one-var": ["warn", "never"], + "operator-linebreak": ["warn", "before", { + "overrides": {"=": "after", "+=": "after", "-=": "after"} + }], + "prefer-template": "warn", + "quote-props": ["warn", "consistent-as-needed", {"keywords": false}], + "quotes": ["warn", "double", {"avoidEscape": true, "allowTemplateLiterals": false}], + "semi": "warn", + "space-before-blocks": ["warn", "always"], + "space-before-function-paren": ["warn", { + "anonymous": "never", + "named": "never", + "asyncArrow": "always" + }], + "spaced-comment": "warn" + } +} diff --git a/.github/workflows/npm-gulp.yml b/.github/workflows/npm-gulp.yml index ac73e46..aef65ff 100644 --- a/.github/workflows/npm-gulp.yml +++ b/.github/workflows/npm-gulp.yml @@ -1,10 +1,12 @@ -name: NodeJS with Gulp +name: Build CI on: push: branches: [ "develop" ] pull_request: branches: [ "develop" ] + workflow_dispatch: + branches: [ "develop" ] jobs: build: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6a5e760..6884702 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,9 +1,8 @@ name: Create Release on: - push: - tags: - - 'release-*' + workflow_dispatch: + branches: [main] jobs: build: @@ -16,46 +15,6 @@ jobs: steps: - uses: actions/checkout@v3 - - name: Set up variables - id: get_vars - run: | - TAG=${GITHUB_REF/refs\/tags\//} - echo ::set-output name=TAG_NAME::$TAG - echo ::set-output name=ZIP_NAME::ac2d20.zip - echo ::set-output name=RELEASE_DOWNLOAD_URL::https://github.com/${{github.repository}}/releases/latest/download/ac2d20.zip - echo ::set-output name=RELEASE_INSTALL_URL::https://github.com/${{github.repository}}/releases/download/$TAG/system.json - JSON=$(cat ./system/system.json) - echo ::set-output name=SYSTEM_JSON::${JSON//'%'/'%25'} - - # Run some tests to make sure our `system.json` is correct - # Exit before setting up node if not - - name: Verify Naming - env: - TAG_NAME: ${{ steps.get_vars.outputs.TAG_NAME }} - RELEASE_DOWNLOAD: ${{steps.get_vars.outputs.RELEASE_DOWNLOAD_URL}} - # Extract version and download url from system.json - # https://docs.github.com/en/actions/learn-github-actions/expressions#fromjson - PACKAGE_VERSION: ${{fromJSON(steps.get_vars.outputs.SYSTEM_JSON).version}} - PACKAGE_DOWNLOAD: ${{fromJSON(steps.get_vars.outputs.SYSTEM_JSON).download}} - run: | - # Validate that the tag being released matches the package version. - if [[ ! $TAG_NAME == release-$PACKAGE_VERSION ]]; then - echo "The system.json version does not match tag name." - echo "system.json: $PACKAGE_VERSION" - echo "tag name: $TAG_NAME" - echo "Please fix this and push the tag again." - exit 1 - fi - - # Validate that the package download url matches the release asset that will be created. - if [[ ! $RELEASE_DOWNLOAD == $PACKAGE_DOWNLOAD ]]; then - echo "The system.json download url does not match the created release asset url." - echo "system.json: $PACKAGE_DOWNLOAD" - echo "release asset url: $RELEASE_DOWNLOAD" - echo "Please fix this and push the tag again." - exit 1 - fi - - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v3 with: @@ -70,19 +29,20 @@ jobs: npm run build cp --force LICENSE.txt system/. cp --force README.md system/. + SYSTEM_VERSION=$(grep -oP '(?<="version": ")[^"]+' system/system.json | tr -d '\n') + perl -pi -E "s|latest/download/ac2d20\\.zip|download/$SYSTEM_VERSION/ac2d20.zip|" system/system.json + echo "systemVersion=$SYSTEM_VERSION" >> $GITHUB_ENV - - run: cd system && zip ../${{steps.get_vars.outputs.ZIP_NAME}} -r assets css fonts lang packs src templates ac2d20.mjs ac2d20-compiled.mjs ac2d20-compiled.mjs.map LICENSE.txt README.md system.json template.json + - run: cd system && zip -r ../ac2d20.zip ./* - # Create a release for this specific version - - name: Update Release with Files + - name: Create Version Release id: create_version_release uses: ncipollo/release-action@v1 with: - allowUpdates: true # Set this to false if you want to prevent updating existing releases - name: ${{steps.get_vars.outputs.TAG_NAME}} + allowUpdates: false + name: ${{ env.systemVersion }} draft: false prerelease: false token: ${{ secrets.GITHUB_TOKEN }} - artifacts: './system/system.json, ./${{steps.get_vars.outputs.ZIP_NAME}}' - tag: ${{steps.get_vars.outputs.TAG_NAME}} - body: '**Installation:** To manually install this release, please use the following manifest URL: ${{steps.get_vars.outputs.RELEASE_INSTALL_URL}}' + artifacts: './system/system.json, ./ac2d20.zip' + tag: ${{ env.systemVersion }} diff --git a/.vscode/launch.json b/.vscode/launch.json index 2cb0dba..43bf413 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -7,8 +7,8 @@ { "type": "chrome", "request": "launch", - "name": "Achtung! Cthulhu 2d20 System", - "url": "http://localhost:30000", + "name": "Achtung! Cthulhu 2d20", + "url": "http://localhost:31000", "webRoot": "${workspaceFolder}/system" } ] diff --git a/CHANGELOG.md b/CHANGELOG.md index 3833684..5552a79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +## v11.1.2 + +### Bugfix +- [#8] Weapon sizes not correctly displayed on Gear tab of character sheet +- [#9] Gear category labels for Skill Kits and Equipment not translated +- [#10] Spellcasting type always shows as Traditional when posted to chat +- [#11] Don't show brackets on spell display unless it has a Focus set + +## v11.1.1 + +### Bugfix +- [#3] Actor skills being overwritten when an Actor is duplicated + +### Chore +- Translation updates are now all handled via Crowdin to simplify the process of contributing translations. See here for more details: https://github.com/Muttley/foundryvtt-ac2d20/wiki/Other-ways-to-contribute#translation + ## v11.1.0 - System migrated to new home and build process diff --git a/README.md b/README.md index 51a6c54..1856ccf 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ ![GitHub Release](https://img.shields.io/github/release-date/Muttley/foundryvtt-ac2d20) ![All Versions](https://img.shields.io/github/downloads/Muttley/foundryvtt-ac2d20/total) -![Latest Version](https://img.shields.io/github/downloads/Muttley/foundryvtt-ac2d20/latest/total) +![Latest Version](https://img.shields.io/github/downloads/Muttley/foundryvtt-ac2d20/latest/ac2d20.zip) +[![Crowdin](https://badges.crowdin.net/foundryvtt-ac2d20/localized.svg)](https://crowdin.com/project/foundryvtt-ac2d20) ![Forge Installs](https://img.shields.io/badge/dynamic/json?label=Forge%20Installs&query=package.installs&suffix=%25&url=https%3A%2F%2Fforge-vtt.com%2Fapi%2Fbazaar%2Fpackage%2Fac2d20) # Achtung! Cthulhu 2d20 System for Foundry VTT @@ -19,5 +20,5 @@ This is the unofficial Achtung Cthulhu 2d20 system for Foundry VTT. ## Featuring -- The system supports Dice-So-Nice module and introduces its own stress dice shortcut ("s") that you can use in chat or in journals (example: "`/r 1ds`", "`[[/r 1ds]]`", "`[[1ds]]`" +- The system supports Dice-So-Nice module and introduces its own stress dice shortcut ("s") that you can use in chat or in journals (example: "`/r 1ds`", "`[[/r 1ds]]`", "`[[1ds]]`") - IMPORTANT: The system doesn't provide any pre-populated content. diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 0000000..f342c93 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,3 @@ +files: + - source: i18n/en.yaml + translation: /i18n/%two_letters_code%.yaml diff --git a/gulpfile.mjs b/gulpfile.mjs index c1d3477..0ba9e01 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -1,29 +1,29 @@ import gulp from "gulp"; import * as css from "./utils/css.mjs"; -// import * as lang from "./utils/lang.mjs"; +import * as lang from "./utils/lang.mjs"; import * as javascript from "./utils/javascript.mjs"; import * as packs from "./utils/packs.mjs"; export default gulp.series( gulp.parallel( css.compile, - // lang.compile, - // javascript.lint, + lang.compile, + javascript.lint, javascript.compile ), gulp.parallel( css.watchUpdates, - // lang.watchUpdates, + lang.watchUpdates, javascript.watchUpdates ) ); export const build = gulp.parallel( css.compile, - // lang.compile, - // javascript.lint, + lang.compile, + javascript.lint, javascript.compile, packs.compile ); @@ -31,6 +31,6 @@ export const build = gulp.parallel( // export const clean = gulp.parallel(css.clean, lang.clean, packs.clean); export const clean = gulp.parallel(css.clean, packs.clean); export const compileCss = gulp.series(css.compile); -// export const compileLang = gulp.series(lang.compile); +export const compileLang = gulp.series(lang.compile); export const compilePacks = gulp.series(packs.compile); export const lintJs = gulp.series(javascript.lint); diff --git a/i18n/en.yaml b/i18n/en.yaml new file mode 100644 index 0000000..cbb87e7 --- /dev/null +++ b/i18n/en.yaml @@ -0,0 +1,326 @@ + +"AC2D20.VEHICLES.QUALITIES.singleSeat:": Single Seat +AC2D20.Ability.agi: Agility +AC2D20.Ability.bra: Brawn +AC2D20.Ability.coo: Coordination +AC2D20.Ability.ins: Insight +AC2D20.Ability.rea: Reason +AC2D20.Ability.wil: Will +AC2D20.AbilityAbbr.agi: agi +AC2D20.AbilityAbbr.bra: bra +AC2D20.AbilityAbbr.coo: coo +AC2D20.AbilityAbbr.ins: ins +AC2D20.AbilityAbbr.rea: rea +AC2D20.AbilityAbbr.wil: wil +AC2D20.ARMOR.qualities.heavy: Heavy +AC2D20.ARMOR.qualities.shield: Shield +AC2D20.ARMOR.qualities.uncomfortable: Uncomfortable +AC2D20.Combat.CombatantsTurnDone: Turn Completed +AC2D20.Combat.CombatantsTurnNotDone: Turn Not Completed +AC2D20.Combat.CombatEndMomentumPoolDecremented: Momentum Pool Decremented at End of Combat +AC2D20.Combat.CombatHasNotStarted: Combat Has Not Started +AC2D20.Combat.CombatRoundMomentumPoolDecremented: Momentum Pool Decremented at Start of New Round +AC2D20.Combat.ToggleCombatantsTurnDone: Toggle Turn Completed +AC2D20.EffectCreate: Create Effect +AC2D20.EffectDelete: Delete Effect +AC2D20.EffectEdit: Edit Effect +AC2D20.EffectToggle: Toggle Effect +AC2D20.equipped: Equipped +AC2D20.FOCUS.Air Force: Air Force +AC2D20.FOCUS.Aircraft: Aircraft +AC2D20.FOCUS.Animal Handling: Animal Handling +AC2D20.FOCUS.Architecture: Architecture +AC2D20.FOCUS.Army: Army +AC2D20.FOCUS.Art: Art +AC2D20.FOCUS.Camouflage: Camouflage +AC2D20.FOCUS.Cars: Cars +AC2D20.FOCUS.Charm: Charm +AC2D20.FOCUS.Climbing: Climbing +AC2D20.FOCUS.Close Quarters: Close Quarters +AC2D20.FOCUS.Combat Engineering: Combat Engineering +AC2D20.FOCUS.Covert Operations: Covert Operations +AC2D20.FOCUS.Cryptography: Cryptography +AC2D20.FOCUS.Deceive: Deceive +AC2D20.FOCUS.Discipline: Discipline +AC2D20.FOCUS.Disguise: Disguise +AC2D20.FOCUS.Electronics: Electronics +AC2D20.FOCUS.Exotic: Exotic +AC2D20.FOCUS.Explosives: Explosives +AC2D20.FOCUS.Finance: Finance +AC2D20.FOCUS.First Aid: First Aid +AC2D20.FOCUS.Foraging: Foraging +AC2D20.FOCUS.Fortitude: Fortitude +AC2D20.FOCUS.Hand-to-Hand: Hand-to-Hand +AC2D20.FOCUS.Handguns: Handguns +AC2D20.FOCUS.Hearing: Hearing +AC2D20.FOCUS.Heavy Vehicles: Heavy Vehicles +AC2D20.FOCUS.Heavy Weapons: Heavy Weapons +AC2D20.FOCUS.History: History +AC2D20.FOCUS.Hunting: Hunting +AC2D20.FOCUS.Immunity: Immunity +AC2D20.FOCUS.Infectious Diseases: Infectious Diseases +AC2D20.FOCUS.Innuendo: Innuendo +AC2D20.FOCUS.Instincts: Instincts +AC2D20.FOCUS.Intimidation: Intimidation +AC2D20.FOCUS.Invocation: Invocation +AC2D20.FOCUS.Leadership: Leadership +AC2D20.FOCUS.Lifting: Lifting +AC2D20.FOCUS.Linguistics: Linguistics +AC2D20.FOCUS.Mechanical Engineering: Mechanical Engineering +AC2D20.FOCUS.Melee Weapons: Melee Weapons +AC2D20.FOCUS.Motorcycles: Motorcycles +AC2D20.FOCUS.Mysticism: Mysticism +AC2D20.FOCUS.Navy: Navy +AC2D20.FOCUS.Negotiation: Negotiation +AC2D20.FOCUS.Occultism: Occultism +AC2D20.FOCUS.Orienteering: Orienteering +AC2D20.FOCUS.Pharmacology: Pharmacology +AC2D20.FOCUS.Physical Training: Physical Training +AC2D20.FOCUS.Psychiatry: Psychiatry +AC2D20.FOCUS.Rhetoric: Rhetoric +AC2D20.FOCUS.Rifles: Rifles +AC2D20.FOCUS.Running: Running +AC2D20.FOCUS.Rural Stealth: Rural Stealth +AC2D20.FOCUS.Science: Science +AC2D20.FOCUS.Sight: Sight +AC2D20.FOCUS.Smell and Taste: Smell and Taste +AC2D20.FOCUS.Surgery: Surgery +AC2D20.FOCUS.Swimming: Swimming +AC2D20.FOCUS.Tanks: Tanks +AC2D20.FOCUS.Technical Projects: Technical Projects +AC2D20.FOCUS.Threat Awareness: Threat Awareness +AC2D20.FOCUS.Throwing: Throwing +AC2D20.FOCUS.Toxicology: Toxicology +AC2D20.FOCUS.Tracking: Tracking +AC2D20.FOCUS.Urban Stealth: Urban Stealth +AC2D20.FOCUS.Watercraft: Watercraft +AC2D20.OTHER: Other +AC2D20.RANGE.close: Close +AC2D20.RANGE.extreme: Extreme +AC2D20.RANGE.long: Long +AC2D20.RANGE.medium: Medium +AC2D20.RANGE.reach: Reach +AC2D20.RESISTANCE.armor: Armor +AC2D20.RESISTANCE.courage: Courage +AC2D20.RESISTANCE.fatigue: Fatigue +AC2D20.RESISTANCE.resistance: Resistance +AC2D20.SKILL.ACADEMIA: Academia +AC2D20.SKILL.ATHLETICS: Athletics +AC2D20.SKILL.ENGINEERING: Engineering +AC2D20.SKILL.FIGHTING: Fighting +AC2D20.SKILL.MEDICINE: Medicine +AC2D20.SKILL.OBSERVATION: Observation +AC2D20.SKILL.PERSUASION: Persuasion +AC2D20.SKILL.RESILIENCE: Resilience +AC2D20.SKILL.STEALTH: Stealth +AC2D20.SKILL.SURVIVAL: Survival +AC2D20.SKILL.TACTICS: Tactics +AC2D20.SKILL.VEHICLES: Vehicles +AC2D20.SPELL.SpellTypes.ins: Traditional +AC2D20.SPELL.SpellTypes.rea: Researcher +AC2D20.SPELL.SpellTypes.wil: Dabbler +AC2D20.Spellcasting.dabbler: dabbler +AC2D20.Spellcasting.researcher: researcher +AC2D20.Spellcasting.SpellcastingType: Spellcasting Type +AC2D20.Spellcasting.traditional: traditional +AC2D20.STRESS.current: Current Stress +AC2D20.STRESS.max: Max Stress +AC2D20.STRESS.stress: Stress +AC2D20.TEMPLATES.Abilities: Abilities +AC2D20.TEMPLATES.AddFocus: Add Focus +AC2D20.TEMPLATES.Ammo: Ammo +AC2D20.TEMPLATES.Attacks: ATTACKS +AC2D20.TEMPLATES.Attr: Attr. +AC2D20.TEMPLATES.Attribute: Attribute +AC2D20.TEMPLATES.Attributes: Attributes +AC2D20.TEMPLATES.bonus: Bonus +AC2D20.TEMPLATES.Compl: Compl. +AC2D20.TEMPLATES.Complications: Complications +AC2D20.TEMPLATES.Conditions: Conditions +AC2D20.TEMPLATES.Cost: Cost +AC2D20.TEMPLATES.CostEffects: Cost Effects +AC2D20.TEMPLATES.Create_Ammo: Create Ammo +AC2D20.TEMPLATES.Create_Special_Rule: Create Special Rule +AC2D20.TEMPLATES.Create_Weapon: Create Weapon +AC2D20.TEMPLATES.current: current +AC2D20.TEMPLATES.DAMAGE_EFFECTS: DAMAGE EFFECTS +AC2D20.TEMPLATES.DAMAGE_TYPE: DAMAGE TYPE +AC2D20.TEMPLATES.DAMAGE: DAMAGE +AC2D20.TEMPLATES.Data: Data +AC2D20.TEMPLATES.Default_Attribute: Default Attribute +AC2D20.TEMPLATES.DEFENSE: DEFENSE +AC2D20.TEMPLATES.Delete_Item: Delete Item +AC2D20.TEMPLATES.Delete: Delete +AC2D20.TEMPLATES.DERIVED: DERIVED +AC2D20.TEMPLATES.Description: Description +AC2D20.TEMPLATES.Diff: Diff +AC2D20.TEMPLATES.Difficulty: Difficulty +AC2D20.TEMPLATES.Dur: Dur +AC2D20.TEMPLATES.Duration: Duration +AC2D20.TEMPLATES.Edit_Item: Edit Item +AC2D20.TEMPLATES.Effect: Effect +AC2D20.TEMPLATES.Effects: Effects +AC2D20.TEMPLATES.Encumbered: ENCUMBERED +AC2D20.TEMPLATES.Encumbrance_Level: Encumbrance Level +AC2D20.TEMPLATES.Encumbrance: Encumbrance +AC2D20.TEMPLATES.ENG: ENG +AC2D20.TEMPLATES.equipped: equipped +AC2D20.TEMPLATES.FAVORITE_WEAPONS: FAVORITE WEAPONS +AC2D20.TEMPLATES.FIRE_RATE: FIRE RATE +AC2D20.TEMPLATES.Focus: Focus +AC2D20.TEMPLATES.fortune: Fortune +AC2D20.TEMPLATES.Gear: Gear +AC2D20.TEMPLATES.GENERAL: GENERAL +AC2D20.TEMPLATES.GM_MOMENTUM: GM Threat +AC2D20.TEMPLATES.Healthy: Healthy +AC2D20.TEMPLATES.HP_Healed: HP Healed +AC2D20.TEMPLATES.INITIATIVE: INITIATIVE +AC2D20.TEMPLATES.INJURIES: Injuries +AC2D20.TEMPLATES.Issue: Issue +AC2D20.TEMPLATES.Keywords: Keywords +AC2D20.TEMPLATES.lbs: lbs +AC2D20.TEMPLATES.Learned: Learned +AC2D20.TEMPLATES.Luck: Luck +AC2D20.TEMPLATES.MAX_PARTY_MOMENTUM: Max Momentum +AC2D20.TEMPLATES.max: max +AC2D20.TEMPLATES.MAX: MAX +AC2D20.TEMPLATES.MELEE_BONUS: MELEE BONUS +AC2D20.TEMPLATES.MELEE_DAMAGE: MELEE DAMAGE +AC2D20.TEMPLATES.Mod_Type: Mod Type +AC2D20.TEMPLATES.MODULES: MODULES +AC2D20.TEMPLATES.Name_Prefix: Name Prefix +AC2D20.TEMPLATES.PARTY_MOMENTUM: Party Momentum +AC2D20.TEMPLATES.Personal_Truth_Scars: Personal Truths & Scars +AC2D20.TEMPLATES.PHYS: PHYS +AC2D20.TEMPLATES.Points: Points +AC2D20.TEMPLATES.POISON: POISON +AC2D20.TEMPLATES.Power: Power +AC2D20.TEMPLATES.Qualities: Qualities +AC2D20.TEMPLATES.RANGE: Range +AC2D20.TEMPLATES.Rank: Rank +AC2D20.TEMPLATES.Ranks_current_maximum: Ranks [current/maximum] +AC2D20.TEMPLATES.rating: Rating +AC2D20.TEMPLATES.Re_roll: Re-roll +AC2D20.TEMPLATES.Requirements: Requirements +AC2D20.TEMPLATES.Resistance: Resistance +AC2D20.TEMPLATES.Resistances: Resistances +AC2D20.TEMPLATES.RESISTANCES: RESISTANCES +AC2D20.TEMPLATES.Resources: Resources +AC2D20.TEMPLATES.Restriction: Restriction +AC2D20.TEMPLATES.ritual_requirements: Requirements +AC2D20.TEMPLATES.ritual_resistance: Resistance +AC2D20.TEMPLATES.ritual_steps: Ritual Steps +AC2D20.TEMPLATES.ritual_stress: Ritual Stress +AC2D20.TEMPLATES.Ritual: Ritual +AC2D20.TEMPLATES.Roll_Formula: Roll Formula +AC2D20.TEMPLATES.Salvo: Salvo +AC2D20.TEMPLATES.scale: Scale +AC2D20.TEMPLATES.Size: Size +AC2D20.TEMPLATES.SizeLevels.Major: Major +AC2D20.TEMPLATES.SizeLevels.Minor: Minor +AC2D20.TEMPLATES.SizeLevels.Trivial: Trivial +AC2D20.TEMPLATES.Skill_Focus: Skill Focus +AC2D20.TEMPLATES.skill_focus: Skill/Focus +AC2D20.TEMPLATES.Skill_Value: Skill Value +AC2D20.TEMPLATES.Skill: Skill +AC2D20.TEMPLATES.SkillFocus: Skill Focus +AC2D20.TEMPLATES.Skills: Skills +AC2D20.TEMPLATES.Source: Source +AC2D20.TEMPLATES.SpecialRule: SpecialRule +AC2D20.TEMPLATES.SpecialRules: Special Rules +AC2D20.TEMPLATES.speed: Speed +AC2D20.TEMPLATES.Spells_Rituals: Spells And Rituals +AC2D20.TEMPLATES.Spells: Spells +AC2D20.TEMPLATES.Status: Status +AC2D20.TEMPLATES.Successes: Successes +AC2D20.TEMPLATES.Talents: Talents +AC2D20.TEMPLATES.TN: TN +AC2D20.TEMPLATES.Total: Total +AC2D20.TEMPLATES.Truths: Truths +AC2D20.TEMPLATES.Use_Agility: Use Agility +AC2D20.TEMPLATES.Use_Brawn: Use Brawn +AC2D20.TEMPLATES.Use_Coordination: Use Coordination +AC2D20.TEMPLATES.Use_Insight: Use Insight +AC2D20.TEMPLATES.Use_Reason: Use Reason +AC2D20.TEMPLATES.Use_Will: Use Will +AC2D20.TEMPLATES.Weapon_Qualities: WEAPON QUALITIES +AC2D20.TEMPLATES.Weapon_Type: Weapon Type +AC2D20.TEMPLATES.Weapons: Weapons +AC2D20.UI.Add: Add +AC2D20.UI.CarryWeight: Carry Weight +AC2D20.UI.Cost: Cost +AC2D20.UI.Damage: Damage +AC2D20.UI.favorite: Favorite +AC2D20.UI.INVENTORY: Inventory +AC2D20.UI.Name: Name +AC2D20.UI.ORIGIN: ORIGIN +AC2D20.UI.OTHER: Other +AC2D20.UI.Quantity: Quantity +AC2D20.UI.Rarity: Rarity +AC2D20.UI.SPECIAL_RULE: Special Rule +AC2D20.UI.stashed: Stashed +AC2D20.UI.Type: Type +AC2D20.UI.UNSORTED: Unsorted +AC2D20.UI.Weight: Weight +AC2D20.VEHICLES.QUALITIES.cargo: Cargo +AC2D20.VEHICLES.QUALITIES.cumbersome: Cumbersome +AC2D20.VEHICLES.QUALITIES.enclosed: Enclosed +AC2D20.VEHICLES.QUALITIES.exposed: Exposed +AC2D20.VEHICLES.QUALITIES.highPerformance: High Performance +AC2D20.VEHICLES.QUALITIES.singleSeat: Single Seat +AC2D20.VEHICLES.QUALITIES.tough: Tough +AC2D20.WEAPONS.damageEffect.area: Area +AC2D20.WEAPONS.damageEffect.backlash: Backlash +AC2D20.WEAPONS.damageEffect.drain: Drain +AC2D20.WEAPONS.damageEffect.intense: Intense +AC2D20.WEAPONS.damageEffect.persistent: Persistent +AC2D20.WEAPONS.damageEffect.piercing: Piercing +AC2D20.WEAPONS.damageEffect.snare: Snare +AC2D20.WEAPONS.damageEffect.stun: Stun +AC2D20.WEAPONS.damageEffect.vicious: Vicious +AC2D20.WEAPONS.damageType.energy: Energy +AC2D20.WEAPONS.damageType.physical: Physical +AC2D20.WEAPONS.damageType.poison: Poison +AC2D20.WEAPONS.damageType.radiation: Radiation +AC2D20.WEAPONS.qualities: Qualities +AC2D20.WEAPONS.type: Weapon Type +AC2D20.WEAPONS.weaponQuality.accurate: Accurate +AC2D20.WEAPONS.weaponQuality.bane: Bane +AC2D20.WEAPONS.weaponQuality.closeQuarters: Close Quarters +AC2D20.WEAPONS.weaponQuality.cumbersome: Cumbersome +AC2D20.WEAPONS.weaponQuality.debilitating: Debilitating +AC2D20.WEAPONS.weaponQuality.escalation: Escalation +AC2D20.WEAPONS.weaponQuality.giant-killer: Giant-Killer +AC2D20.WEAPONS.weaponQuality.heavy: Heavy +AC2D20.WEAPONS.weaponQuality.hidden: Hidden +AC2D20.WEAPONS.weaponQuality.hunger: Hunger +AC2D20.WEAPONS.weaponQuality.inaccurate: Inaccurate +AC2D20.WEAPONS.weaponQuality.indirect: Indirect +AC2D20.WEAPONS.weaponQuality.munition: Munition +AC2D20.WEAPONS.weaponQuality.parrying: Parrying +AC2D20.WEAPONS.weaponQuality.reliable: Reliable +AC2D20.WEAPONS.weaponQuality.subtle: Subtle +AC2D20.WEAPONS.weaponQuality.unreliable: Unreliable +AC2D20.WEAPONS.weaponTypes.agi: Melee +AC2D20.WEAPONS.weaponTypes.coo: Ranged +AC2D20.WEAPONS.weaponTypes.Melee: Melee +AC2D20.WEAPONS.weaponTypes.Mental: Mental +AC2D20.WEAPONS.weaponTypes.Ranged: Ranged +AC2D20.WEAPONS.weaponTypes.wil: Mental +ACTOR.NpcType.Lieutenant: Lieutenant +ACTOR.NpcType.Nemesis: Nemesis +ACTOR.NpcType.Trooper: Trooper +ACTOR.Vehicle.Cover: Cover +ACTOR.Vehicle.Impact: Impact +ACTOR.Vehicle.Passengers: Passengers +TYPES.Actor.character: Character +TYPES.Actor.npc: NPC +TYPES.Actor.vehicle: Vehicle +TYPES.Item.armor: Armor +TYPES.Item.equipment: Equipment +TYPES.Item.skill: Skill +TYPES.Item.skillkit: Skill Kit +TYPES.Item.special_rule: Special Rule +TYPES.Item.spell: Spell +TYPES.Item.talent: Talent +TYPES.Item.weapon: Weapon diff --git a/i18n/es.yaml b/i18n/es.yaml new file mode 100644 index 0000000..1c23371 --- /dev/null +++ b/i18n/es.yaml @@ -0,0 +1,325 @@ +"AC2D20.VEHICLES.QUALITIES.singleSeat:": Asiento único +AC2D20.Ability.agi: Agilidad +AC2D20.Ability.bra: Músculo +AC2D20.Ability.coo: Coordinación +AC2D20.Ability.ins: Perspicacia +AC2D20.Ability.rea: Razón +AC2D20.Ability.wil: Voluntad +AC2D20.AbilityAbbr.agi: agi +AC2D20.AbilityAbbr.bra: mus +AC2D20.AbilityAbbr.coo: coo +AC2D20.AbilityAbbr.ins: pers +AC2D20.AbilityAbbr.rea: raz +AC2D20.AbilityAbbr.wil: vol +AC2D20.ARMOR.qualities.heavy: Pesada +AC2D20.ARMOR.qualities.shield: Escudo +AC2D20.ARMOR.qualities.uncomfortable: Incómoda +AC2D20.Combat.CombatantsTurnDone: Turn Completed +AC2D20.Combat.CombatantsTurnNotDone: Turn Not Completed +AC2D20.Combat.CombatEndMomentumPoolDecremented: Momentum Pool Decremented at End of Combat +AC2D20.Combat.CombatHasNotStarted: Combat Has Not Started +AC2D20.Combat.CombatRoundMomentumPoolDecremented: Momentum Pool Decremented at Start of New Round +AC2D20.Combat.ToggleCombatantsTurnDone: Toggle Turn Completed +AC2D20.EffectCreate: Crear Efecto +AC2D20.EffectDelete: Borrar Efecto +AC2D20.EffectEdit: Editar Efecto +AC2D20.EffectToggle: Alternar Efecto +AC2D20.equipped: Equipado +AC2D20.FOCUS.Air Force: Fuerza Aérea +AC2D20.FOCUS.Aircraft: Vehículos Aéreos +AC2D20.FOCUS.Animal Handling: Manejo de Animales +AC2D20.FOCUS.Architecture: Arquitectura +AC2D20.FOCUS.Army: Ejército +AC2D20.FOCUS.Art: Arte +AC2D20.FOCUS.Camouflage: Camuflaje +AC2D20.FOCUS.Cars: Coches +AC2D20.FOCUS.Charm: Encanto +AC2D20.FOCUS.Climbing: Escalar +AC2D20.FOCUS.Close Quarters: Cercana +AC2D20.FOCUS.Combat Engineering: Ingeniería de Combate +AC2D20.FOCUS.Covert Operations: Operaciones Encubiertas +AC2D20.FOCUS.Cryptography: Criptografía +AC2D20.FOCUS.Deceive: Engaño +AC2D20.FOCUS.Discipline: Disciplina +AC2D20.FOCUS.Disguise: Disfraz +AC2D20.FOCUS.Electronics: Electrónica +AC2D20.FOCUS.Exotic: Exoticas +AC2D20.FOCUS.Explosives: Explosivos +AC2D20.FOCUS.Finance: Finanzas +AC2D20.FOCUS.First Aid: Primeros Auxilios +AC2D20.FOCUS.Foraging: Forrajeo +AC2D20.FOCUS.Fortitude: Fortaleza Interior +AC2D20.FOCUS.Hand-to-Hand: Mano a mano +AC2D20.FOCUS.Handguns: Pístolas +AC2D20.FOCUS.Hearing: Escuchar +AC2D20.FOCUS.Heavy Vehicles: Vehículos Pesados +AC2D20.FOCUS.Heavy Weapons: Armas Pesadas +AC2D20.FOCUS.History: Historia +AC2D20.FOCUS.Hunting: Caza +AC2D20.FOCUS.Immunity: Inmunidad +AC2D20.FOCUS.Infectious Diseases: Enfermedades Infecciosas +AC2D20.FOCUS.Innuendo: Seducción +AC2D20.FOCUS.Instincts: Instintos +AC2D20.FOCUS.Intimidation: Intimidación +AC2D20.FOCUS.Invocation: Invocación +AC2D20.FOCUS.Leadership: Liderazgo +AC2D20.FOCUS.Lifting: Levantar +AC2D20.FOCUS.Linguistics: Lingüística +AC2D20.FOCUS.Mechanical Engineering: Ingeniería Mecánica +AC2D20.FOCUS.Melee Weapons: Armas de Melé +AC2D20.FOCUS.Motorcycles: Motocicletas +AC2D20.FOCUS.Mysticism: Misticismo +AC2D20.FOCUS.Navy: Armada +AC2D20.FOCUS.Negotiation: Negociación +AC2D20.FOCUS.Occultism: Ocultismo +AC2D20.FOCUS.Orienteering: Orientación +AC2D20.FOCUS.Pharmacology: Farmacología +AC2D20.FOCUS.Physical Training: Entrenamiento Físico +AC2D20.FOCUS.Psychiatry: Psiquiatría +AC2D20.FOCUS.Rhetoric: Retórica +AC2D20.FOCUS.Rifles: Rifles +AC2D20.FOCUS.Running: Correr +AC2D20.FOCUS.Rural Stealth: Sigilo a campo abierto +AC2D20.FOCUS.Science: Ciencia +AC2D20.FOCUS.Sight: Ver +AC2D20.FOCUS.Smell and Taste: Oler y Saborear +AC2D20.FOCUS.Surgery: Cirugía +AC2D20.FOCUS.Swimming: Nadar +AC2D20.FOCUS.Tanks: Tanques +AC2D20.FOCUS.Technical Projects: Proyectos Técnicos +AC2D20.FOCUS.Threat Awareness: Sentir el Peligro +AC2D20.FOCUS.Throwing: Lanzar +AC2D20.FOCUS.Toxicology: Toxicología +AC2D20.FOCUS.Tracking: Rastrear +AC2D20.FOCUS.Urban Stealth: Sigilo Urbano +AC2D20.FOCUS.Watercraft: Vehículos Acuáticos +AC2D20.OTHER: Otro +AC2D20.RANGE.close: Corto +AC2D20.RANGE.extreme: Extremo +AC2D20.RANGE.long: Largo +AC2D20.RANGE.medium: Medio +AC2D20.RANGE.reach: Alcance +AC2D20.RESISTANCE.armor: Armadura +AC2D20.RESISTANCE.courage: Coraje +AC2D20.RESISTANCE.fatigue: Fatiga +AC2D20.RESISTANCE.resistance: Resistencia +AC2D20.SKILL.ACADEMIA: Académicas +AC2D20.SKILL.ATHLETICS: Atletismo +AC2D20.SKILL.ENGINEERING: Ingeniería +AC2D20.SKILL.FIGHTING: Combate +AC2D20.SKILL.MEDICINE: Medicina +AC2D20.SKILL.OBSERVATION: Observación +AC2D20.SKILL.PERSUASION: Persuasión +AC2D20.SKILL.RESILIENCE: Resiliencia +AC2D20.SKILL.STEALTH: Sigilo +AC2D20.SKILL.SURVIVAL: Supervivencia +AC2D20.SKILL.TACTICS: Tácticas +AC2D20.SKILL.VEHICLES: Vehículos +AC2D20.SPELL.SpellTypes.ins: Tradicional +AC2D20.SPELL.SpellTypes.rea: Investigador +AC2D20.SPELL.SpellTypes.wil: Aficionado +AC2D20.Spellcasting.dabbler: dabbler +AC2D20.Spellcasting.researcher: researcher +AC2D20.Spellcasting.SpellcastingType: Spellcasting Type +AC2D20.Spellcasting.traditional: traditional +AC2D20.STRESS.current: Estrés actual +AC2D20.STRESS.max: Estrés Máximo +AC2D20.STRESS.stress: Estrés +AC2D20.TEMPLATES.Abilities: Habilidades +AC2D20.TEMPLATES.AddFocus: Añadir Especialidad +AC2D20.TEMPLATES.Ammo: Munición +AC2D20.TEMPLATES.Attacks: ATAQUES +AC2D20.TEMPLATES.Attr: Atri. +AC2D20.TEMPLATES.Attribute: Atributo +AC2D20.TEMPLATES.Attributes: Atributos +AC2D20.TEMPLATES.bonus: Bono +AC2D20.TEMPLATES.Compl: Compl. +AC2D20.TEMPLATES.Complications: Complicaciones +AC2D20.TEMPLATES.Conditions: Condiciones +AC2D20.TEMPLATES.Cost: Coste +AC2D20.TEMPLATES.CostEffects: Coste de Efectos +AC2D20.TEMPLATES.Create_Ammo: Crear Munición +AC2D20.TEMPLATES.Create_Special_Rule: Crear Regla Especial +AC2D20.TEMPLATES.Create_Weapon: Crear Arma +AC2D20.TEMPLATES.current: actual +AC2D20.TEMPLATES.DAMAGE_EFFECTS: EFECTOS DE DAÑO +AC2D20.TEMPLATES.DAMAGE_TYPE: TIPO DE DAÑO +AC2D20.TEMPLATES.DAMAGE: DAÑO +AC2D20.TEMPLATES.Data: Datos +AC2D20.TEMPLATES.Default_Attribute: Atributo por Defecto +AC2D20.TEMPLATES.DEFENSE: DEFENSA +AC2D20.TEMPLATES.Delete_Item: Borrar Objeto +AC2D20.TEMPLATES.Delete: Borrar +AC2D20.TEMPLATES.DERIVED: DERIVADO +AC2D20.TEMPLATES.Description: Descripción +AC2D20.TEMPLATES.Diff: Dif +AC2D20.TEMPLATES.Difficulty: Dificultad +AC2D20.TEMPLATES.Dur: Dur +AC2D20.TEMPLATES.Duration: Duración +AC2D20.TEMPLATES.Edit_Item: Editar Objeto +AC2D20.TEMPLATES.Effect: Efecto +AC2D20.TEMPLATES.Effects: Efectos +AC2D20.TEMPLATES.Encumbered: SOBRECARGADO +AC2D20.TEMPLATES.Encumbrance_Level: Nivel de Carga +AC2D20.TEMPLATES.Encumbrance: Carga +AC2D20.TEMPLATES.ENG: ENG +AC2D20.TEMPLATES.equipped: Equipado +AC2D20.TEMPLATES.FAVORITE_WEAPONS: ARMAS FAVORITAS +AC2D20.TEMPLATES.FIRE_RATE: CADENCIA DE FUEG +AC2D20.TEMPLATES.Focus: Especialización +AC2D20.TEMPLATES.fortune: Fortuna +AC2D20.TEMPLATES.Gear: Equipo +AC2D20.TEMPLATES.GENERAL: GENERAL +AC2D20.TEMPLATES.GM_MOMENTUM: Amenaza DJ +AC2D20.TEMPLATES.Healthy: Saludable +AC2D20.TEMPLATES.HP_Healed: PV Curados +AC2D20.TEMPLATES.INITIATIVE: INICIATIVA +AC2D20.TEMPLATES.INJURIES: Heridas +AC2D20.TEMPLATES.Issue: Problema +AC2D20.TEMPLATES.Keywords: Palabras Clave +AC2D20.TEMPLATES.lbs: lbs +AC2D20.TEMPLATES.Learned: Aprendida +AC2D20.TEMPLATES.Luck: Suerte +AC2D20.TEMPLATES.MAX_PARTY_MOMENTUM: Inercia Máxima +AC2D20.TEMPLATES.max: max +AC2D20.TEMPLATES.MAX: MAX +AC2D20.TEMPLATES.MELEE_BONUS: BONO MELÉ +AC2D20.TEMPLATES.MELEE_DAMAGE: DAÑO MELÉ +AC2D20.TEMPLATES.Mod_Type: Tipo Mod +AC2D20.TEMPLATES.MODULES: MODULOS +AC2D20.TEMPLATES.Name_Prefix: Prefijo del Nombre +AC2D20.TEMPLATES.PARTY_MOMENTUM: Inercia Grupo +AC2D20.TEMPLATES.Personal_Truth_Scars: Verdades Personales & Cicatrices +AC2D20.TEMPLATES.PHYS: FIS +AC2D20.TEMPLATES.Points: Puntos +AC2D20.TEMPLATES.POISON: VENENO +AC2D20.TEMPLATES.Power: Poder +AC2D20.TEMPLATES.Qualities: Cualidades +AC2D20.TEMPLATES.RANGE: Alcance +AC2D20.TEMPLATES.Rank: Rango +AC2D20.TEMPLATES.Ranks_current_maximum: Rangos [actual/máximo] +AC2D20.TEMPLATES.rating: Valor +AC2D20.TEMPLATES.Re_roll: Tirar de Nuevo +AC2D20.TEMPLATES.Requirements: Requerimientos +AC2D20.TEMPLATES.Resistance: Resistencia +AC2D20.TEMPLATES.Resistances: Resistencias +AC2D20.TEMPLATES.RESISTANCES: RESISTENCIAS +AC2D20.TEMPLATES.Resources: Recursos +AC2D20.TEMPLATES.Restriction: Restricción +AC2D20.TEMPLATES.ritual_requirements: Requerimientos +AC2D20.TEMPLATES.ritual_resistance: Resistencia +AC2D20.TEMPLATES.ritual_steps: Fases del Ritual +AC2D20.TEMPLATES.ritual_stress: Estrés Ritual +AC2D20.TEMPLATES.Ritual: Ritual +AC2D20.TEMPLATES.Roll_Formula: Fórmula de Tirada +AC2D20.TEMPLATES.Salvo: Salva +AC2D20.TEMPLATES.scale: Escala +AC2D20.TEMPLATES.Size: Tamaño +AC2D20.TEMPLATES.SizeLevels.Major: Mayor +AC2D20.TEMPLATES.SizeLevels.Minor: Menor +AC2D20.TEMPLATES.SizeLevels.Trivial: Trivial +AC2D20.TEMPLATES.Skill_Focus: Especialidad de Habilidad +AC2D20.TEMPLATES.skill_focus: Habilidad/Especialidad +AC2D20.TEMPLATES.Skill_Value: Valor de Habilidad +AC2D20.TEMPLATES.Skill: Habilidad +AC2D20.TEMPLATES.SkillFocus: Especialidad de Habilidad +AC2D20.TEMPLATES.Skills: Habilidades +AC2D20.TEMPLATES.Source: Origen +AC2D20.TEMPLATES.SpecialRule: Regla Especial +AC2D20.TEMPLATES.SpecialRules: Reglas Especiales +AC2D20.TEMPLATES.speed: Velocidad +AC2D20.TEMPLATES.Spells_Rituals: Conjuros y Rituales +AC2D20.TEMPLATES.Spells: Conjuros +AC2D20.TEMPLATES.Status: Estatus +AC2D20.TEMPLATES.Successes: Éxitos +AC2D20.TEMPLATES.Talents: Talentos +AC2D20.TEMPLATES.TN: TN +AC2D20.TEMPLATES.Total: Total +AC2D20.TEMPLATES.Truths: Verdades +AC2D20.TEMPLATES.Use_Agility: Usa Agilidad +AC2D20.TEMPLATES.Use_Brawn: Usa Músculo +AC2D20.TEMPLATES.Use_Coordination: Usa Coordinación +AC2D20.TEMPLATES.Use_Insight: Usa Perspicacia +AC2D20.TEMPLATES.Use_Reason: Usa Razón +AC2D20.TEMPLATES.Use_Will: Usa Voluntad +AC2D20.TEMPLATES.Weapon_Qualities: CUALIDADES DE ARMA +AC2D20.TEMPLATES.Weapon_Type: Tipo de Arma +AC2D20.TEMPLATES.Weapons: Armas +AC2D20.UI.Add: Añadir +AC2D20.UI.CarryWeight: Peso Acarreado +AC2D20.UI.Cost: Coste +AC2D20.UI.Damage: Daño +AC2D20.UI.favorite: Favorito +AC2D20.UI.INVENTORY: Inventario +AC2D20.UI.Name: Nombre +AC2D20.UI.ORIGIN: ORIGEN +AC2D20.UI.OTHER: Otro +AC2D20.UI.Quantity: Cantidad +AC2D20.UI.Rarity: Rareza +AC2D20.UI.SPECIAL_RULE: Regla Especial +AC2D20.UI.stashed: Reservado +AC2D20.UI.Type: Tipo +AC2D20.UI.UNSORTED: Desordenado +AC2D20.UI.Weight: Peso +AC2D20.VEHICLES.QUALITIES.cargo: Carga +AC2D20.VEHICLES.QUALITIES.cumbersome: Incómodo +AC2D20.VEHICLES.QUALITIES.enclosed: Cerrado +AC2D20.VEHICLES.QUALITIES.exposed: Expuesto +AC2D20.VEHICLES.QUALITIES.highPerformance: Alta Eficacia +AC2D20.VEHICLES.QUALITIES.singleSeat: Asiento único +AC2D20.VEHICLES.QUALITIES.tough: Duro +AC2D20.WEAPONS.damageEffect.area: Área +AC2D20.WEAPONS.damageEffect.backlash: Retroceso +AC2D20.WEAPONS.damageEffect.drain: Drenar +AC2D20.WEAPONS.damageEffect.intense: Intensa +AC2D20.WEAPONS.damageEffect.persistent: Persistente +AC2D20.WEAPONS.damageEffect.piercing: Perforante +AC2D20.WEAPONS.damageEffect.snare: Trampa +AC2D20.WEAPONS.damageEffect.stun: Aturdidora +AC2D20.WEAPONS.damageEffect.vicious: Feroz +AC2D20.WEAPONS.damageType.energy: Enegía +AC2D20.WEAPONS.damageType.physical: Física +AC2D20.WEAPONS.damageType.poison: Veneno +AC2D20.WEAPONS.damageType.radiation: Radiación +AC2D20.WEAPONS.qualities: Cualidades +AC2D20.WEAPONS.type: Tipo de Arma +AC2D20.WEAPONS.weaponQuality.accurate: Precisa +AC2D20.WEAPONS.weaponQuality.bane: Flagelo +AC2D20.WEAPONS.weaponQuality.closeQuarters: Cercana +AC2D20.WEAPONS.weaponQuality.cumbersome: Incómoda +AC2D20.WEAPONS.weaponQuality.debilitating: Debilitante +AC2D20.WEAPONS.weaponQuality.escalation: Recrudecimiento +AC2D20.WEAPONS.weaponQuality.giant-killer: Mata-Gigantes +AC2D20.WEAPONS.weaponQuality.heavy: Pesada +AC2D20.WEAPONS.weaponQuality.hidden: Oculta +AC2D20.WEAPONS.weaponQuality.hunger: Hambrienta +AC2D20.WEAPONS.weaponQuality.inaccurate: Imprecisa +AC2D20.WEAPONS.weaponQuality.indirect: Indirecta +AC2D20.WEAPONS.weaponQuality.munition: Munición +AC2D20.WEAPONS.weaponQuality.parrying: Parada +AC2D20.WEAPONS.weaponQuality.reliable: Fiable +AC2D20.WEAPONS.weaponQuality.subtle: Sutil +AC2D20.WEAPONS.weaponQuality.unreliable: No fiable +AC2D20.WEAPONS.weaponTypes.agi: Melé +AC2D20.WEAPONS.weaponTypes.coo: Distancia +AC2D20.WEAPONS.weaponTypes.Melee: Melé +AC2D20.WEAPONS.weaponTypes.Mental: Mental +AC2D20.WEAPONS.weaponTypes.Ranged: Distancia +AC2D20.WEAPONS.weaponTypes.wil: Mental +ACTOR.NpcType.Lieutenant: Teniente +ACTOR.NpcType.Nemesis: Némesis +ACTOR.NpcType.Trooper: Tropa +ACTOR.Vehicle.Cover: Cobertura +ACTOR.Vehicle.Impact: Impacto +ACTOR.Vehicle.Passengers: Pasajeros +TYPES.Actor.character: Personaje +TYPES.Actor.npc: PNJ +TYPES.Actor.vehicle: Vehículo +TYPES.Item.armor: Armor +TYPES.Item.equipment: Equipment +TYPES.Item.skill: Skill +TYPES.Item.skillkit: Skill Kit +TYPES.Item.special_rule: Special Rule +TYPES.Item.spell: Spell +TYPES.Item.talent: Talent +TYPES.Item.weapon: Weapon diff --git a/package-lock.json b/package-lock.json index 2070cfa..d63185d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "gulp": "^4.0.2", "gulp-eslint-new": "^1.8.0", "gulp-if": "^3.0.0", - "gulp-livereload": "^4.0.2", "gulp-sass": "^5.1.0", "gulp-yaml": "^2.0.4", "jest": "^29.5.0", @@ -22,7 +21,7 @@ "nedb-promises": "^6.2.1", "rollup": "^3.25.1", "sass": "^1.63.4", - "yaml": "^2.3.1", + "yaml": "^2.3.4", "yargs": "^17.7.2" } }, @@ -2701,18 +2700,6 @@ "node": ">= 6" } }, - "node_modules/body": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", - "dev": true, - "dependencies": { - "continuable-cache": "^0.3.1", - "error": "^7.0.0", - "raw-body": "~1.1.0", - "safe-json-parse": "~1.0.1" - } - }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", @@ -2850,12 +2837,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/bytes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", - "dev": true - }, "node_modules/cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", @@ -3305,12 +3286,6 @@ "typedarray": "^0.0.6" } }, - "node_modules/continuable-cache": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", - "dev": true - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -3724,15 +3699,6 @@ "once": "^1.4.0" } }, - "node_modules/error": { - "version": "7.2.1", - "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", - "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", - "dev": true, - "dependencies": { - "string-template": "~0.2.1" - } - }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", @@ -4304,18 +4270,6 @@ "reusify": "^1.0.4" } }, - "node_modules/faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", - "dev": true, - "dependencies": { - "websocket-driver": ">=0.5.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", @@ -5370,103 +5324,6 @@ "through2": "^3.0.1" } }, - "node_modules/gulp-livereload": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp-livereload/-/gulp-livereload-4.0.2.tgz", - "integrity": "sha512-InmaR50Xl1xB1WdEk4mrUgGHv3VhhlRLrx7u60iY5AAer90FlK95KXitPcGGQoi28zrUJM189d/h6+V470Ncgg==", - "dev": true, - "dependencies": { - "chalk": "^2.4.1", - "debug": "^3.1.0", - "fancy-log": "^1.3.2", - "lodash.assign": "^4.2.0", - "readable-stream": "^3.0.6", - "tiny-lr": "^1.1.1", - "vinyl": "^2.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/gulp-livereload/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/gulp-livereload/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/gulp-livereload/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/gulp-livereload/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/gulp-livereload/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/gulp-livereload/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/gulp-livereload/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/gulp-match": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/gulp-match/-/gulp-match-1.1.0.tgz", @@ -5820,12 +5677,6 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http-parser-js": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", - "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", - "dev": true - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -8104,12 +7955,6 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true }, - "node_modules/livereload-js": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", - "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", - "dev": true - }, "node_modules/load-json-file": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", @@ -8174,12 +8019,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha512-hFuH8TY+Yji7Eja3mGiuAxBqLagejScbG8GbG0j6o9vzn0YL14My+ktnqtZgFTosKymC9/44wP6s7xyuLfnClw==", - "dev": true - }, "node_modules/lodash.clonedeep": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", @@ -8827,15 +8666,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -9460,21 +9290,6 @@ } ] }, - "node_modules/qs": { - "version": "6.11.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz", - "integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9501,25 +9316,6 @@ "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", "dev": true }, - "node_modules/raw-body": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", - "dev": true, - "dependencies": { - "bytes": "1", - "string_decoder": "0.10" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/raw-body/node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", - "dev": true - }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -10107,12 +9903,6 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, - "node_modules/safe-json-parse": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", - "dev": true - }, "node_modules/safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", @@ -10391,20 +10181,6 @@ "node": ">=8" } }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -10788,12 +10564,6 @@ "node": ">=10" } }, - "node_modules/string-template": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", - "dev": true - }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -11070,29 +10840,6 @@ "node": ">=0.10.0" } }, - "node_modules/tiny-lr": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", - "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", - "dev": true, - "dependencies": { - "body": "^5.1.0", - "debug": "^3.1.0", - "faye-websocket": "~0.10.0", - "livereload-js": "^2.3.0", - "object-assign": "^4.1.0", - "qs": "^6.4.0" - } - }, - "node_modules/tiny-lr/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -11718,29 +11465,6 @@ "makeerror": "1.0.12" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", - "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", - "dev": true, - "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/websocket-extensions": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", - "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/package.json b/package.json index 519bd2b..445ad23 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "gulp": "^4.0.2", "gulp-eslint-new": "^1.8.0", "gulp-if": "^3.0.0", - "gulp-livereload": "^4.0.2", "gulp-sass": "^5.1.0", "gulp-yaml": "^2.0.4", "jest": "^29.5.0", @@ -28,7 +27,7 @@ "nedb-promises": "^6.2.1", "rollup": "^3.25.1", "sass": "^1.63.4", - "yaml": "^2.3.1", + "yaml": "^2.3.4", "yargs": "^17.7.2" } } diff --git a/scss/ac2d20.scss b/scss/ac2d20.scss index 2308c6b..3b28ba2 100644 --- a/scss/ac2d20.scss +++ b/scss/ac2d20.scss @@ -2,10 +2,11 @@ @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap'); .cth-ico-cth:before { - content: "\e900"; + content: "\e900"; } + .cth-ico-cth-cross:before { - content: "\e901"; + content: "\e901"; } // Import utilities. @@ -22,10 +23,8 @@ /* Styles limited to ac2d20 sheets */ .ac2d20 { - @import 'components/forms'; - @import 'components/resource'; - @import 'components/items'; - @import 'components/effects'; + @import 'components/forms'; + @import 'components/resource'; + @import 'components/items'; + @import 'components/effects'; } - - diff --git a/scss/components/_effects.scss b/scss/components/_effects.scss index 4c3b2c7..e9406c0 100644 --- a/scss/components/_effects.scss +++ b/scss/components/_effects.scss @@ -1,14 +1,15 @@ .effects .item { - .effect-source, - .effect-duration, - .effect-controls { - text-align: center; - border-left: 1px solid #c9c7b8; - border-right: 1px solid #c9c7b8; - font-size: 12px; - } - .effect-controls { - border: none; - } + .effect-source, + .effect-duration, + .effect-controls { + text-align: center; + border-left: 1px solid #c9c7b8; + border-right: 1px solid #c9c7b8; + font-size: 12px; + } + + .effect-controls { + border: none; + } } diff --git a/scss/components/_forms.scss b/scss/components/_forms.scss index 1229327..5061a91 100644 --- a/scss/components/_forms.scss +++ b/scss/components/_forms.scss @@ -1,495 +1,566 @@ .item-form { - font-family: $font-primary; + font-family: $font-primary; } .sheet-header { - flex: 0 auto; - overflow: hidden; - display: flex; - flex-direction: row; - flex-wrap: wrap; - justify-content: flex-start; - margin-bottom: 10px; - - .profile-img { - flex: 0 0 100px; - height: 100px; - margin-right: 10px; - margin-bottom: 5px; - box-shadow: 0px 1px 5px black; - border: 5px solid $c-white; - background-color: $c-light; - } - - .paperclip{ - position: absolute; - height: 60px; - margin-right: 10px; - border: none; - top:23px; - } - - .header-fields { - flex: 1; - .post-item{ - padding-top: 2rem; - cursor: pointer; - color: $c-green-olive; - } - } - - h1.sheet-name { - font-family: $font-germania; - padding: 0; - margin: 0; - border-bottom: 0; - flex: 2; - input { - width: 100%; - height: 100%; - margin: 0; - } - } + flex: 0 auto; + overflow: hidden; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + margin-bottom: 10px; + + .profile-img { + flex: 0 0 100px; + height: 100px; + margin-right: 10px; + margin-bottom: 5px; + box-shadow: 0px 1px 5px black; + border: 5px solid $c-white; + background-color: $c-light; + } + + .paperclip { + position: absolute; + height: 60px; + margin-right: 10px; + border: none; + top: 23px; + } + + .header-fields { + flex: 1; + + .post-item { + padding-top: 2rem; + cursor: pointer; + color: $c-green-olive; + } + } + + h1.sheet-name { + font-family: $font-germania; + padding: 0; + margin: 0; + border-bottom: 0; + flex: 2; + + input { + width: 100%; + height: 100%; + margin: 0; + } + } } -nav{ - &.sheet-tabs{ - z-index: 1; - position: absolute; - display: flex; - top: 30px; - right: 0; - border: none; - line-height: unset; - margin: 0; - .buttons{ - padding: 0 5px; - background-color: $c-green-olive; - display: flex; - &.blue{ - background-color: $c-blue-dark; - } - .item{ - margin-top: 5px; - position: relative; - padding: 5px 10px; - border-top-left-radius: 5px; - border-top-right-radius: 5px; - font-family: $font-germania; - color: $c-black; - background-color: $c-light; - border: 1px solid $c-green-olive; - text-shadow: none; - &.active{ - color: $c-light; - background-color: $c-green-light; - text-shadow: none; - margin-top: 2px; - } - &.active.blue{ - background-color: $c-blue-light; - } - &.blue{border: 1px solid $c-blue-dark;} - } - } - img{ - border: none; - border-radius: unset; - } - } +nav { + &.sheet-tabs { + z-index: 1; + position: absolute; + display: flex; + top: 30px; + right: 0; + border: none; + line-height: unset; + margin: 0; + + .buttons { + padding: 0 5px; + background-color: $c-green-olive; + display: flex; + + &.blue { + background-color: $c-blue-dark; + } + + .item { + margin-top: 5px; + position: relative; + padding: 5px 10px; + border-top-left-radius: 5px; + border-top-right-radius: 5px; + font-family: $font-germania; + color: $c-black; + background-color: $c-light; + border: 1px solid $c-green-olive; + text-shadow: none; + + &.active { + color: $c-light; + background-color: $c-green-light; + text-shadow: none; + margin-top: 2px; + } + + &.active.blue { + background-color: $c-blue-light; + } + + &.blue { + border: 1px solid $c-blue-dark; + } + } + } + + img { + border: none; + border-radius: unset; + } + } } .sheet-body, .sheet-body .tab, .sheet-body .tab .editor { - height: 100%; + height: 100%; } -.sheet-body .tab .editor{ - border: 1px solid $c-green-light; - padding: 5px; + +.sheet-body .tab .editor { + border: 1px solid $c-green-light; + padding: 5px; } + .sheet-body .tab { - &.flex-tab{ - display: flex; - flex-direction: column; - } + &.flex-tab { + display: flex; + flex-direction: column; + } } .tox { - .tox-editor-container { - background: $c-white; - } + .tox-editor-container { + background: $c-white; + } - .tox-edit-area { - padding: 0 8px; - } + .tox-edit-area { + padding: 0 8px; + } } -.section-title{ - display: flex; - flex-direction: row; - - h3{ - display: flex; - align-items: center; - font-family: Germania One; - color: $c-light; - background-color: $c-green-olive; - padding: 2px 5px; - margin-bottom: 0; - width: fit-content; - &.blue{ - background-color: $c-blue-dark; - } - } - .right-slope{ - min-width: 22px; - background-repeat: no-repeat; - &.olive{ - background-image: url(../assets/right-slope-olive.webp); - } - &.blue{ - background-image: url(../assets/right-slope-blue.webp); - } - } +.section-title { + display: flex; + flex-direction: row; + + h3 { + display: flex; + align-items: center; + font-family: Germania One; + color: $c-light; + background-color: $c-green-olive; + padding: 2px 5px; + margin-bottom: 0; + width: fit-content; + + &.blue { + background-color: $c-blue-dark; + } + } + + .right-slope { + min-width: 22px; + background-repeat: no-repeat; + + &.olive { + background-image: url(../assets/right-slope-olive.webp); + } + + &.blue { + background-image: url(../assets/right-slope-blue.webp); + } + } } -.attribute-grid{ - display: grid; - grid-template-columns: repeat(7, 1fr); - color:$c-light; - - .attribute-cell { - display: flex; - align-items: center; - padding: 1px; - justify-content: center; - border: 1px solid $c-green-light; - margin:0 -1px -1px 0; - &.green{ - background-color: $c-green-light; - } - &.olive{ - font-family: $font-germania; - background-color: $c-green-olive; - } - input[type="number"] { - text-align: center; - } - } +.attribute-grid { + display: grid; + grid-template-columns: repeat(7, 1fr); + color: $c-light; + + .attribute-cell { + display: flex; + align-items: center; + padding: 1px; + justify-content: center; + border: 1px solid $c-green-light; + margin: 0 -1px -1px 0; + + &.green { + background-color: $c-green-light; + } + + &.olive { + font-family: $font-germania; + background-color: $c-green-olive; + } + + input[type="number"] { + text-align: center; + } + } } -.stress-derived-box{ - display: flex; - justify-content: space-between; - margin-bottom: 10px; +.stress-derived-box { + display: flex; + justify-content: space-between; + margin-bottom: 10px; } -.derived-box{ - display:flex; - //justify-content: flex-end; - align-items: center; - input[type="number"]{ - font-size: 1.2rem; - line-height: 1.2rem; - height: 30px; - font-family: 'Germania One'; - } - h3{ - padding: 2px 5px; - margin: 0; - color: $c-light; - background-color: $c-green-olive; - font-family: Germania One; - &.minmax{ - padding-right: 5px; - background-color: $c-green-olive; - } - } +.derived-box { + display: flex; + //justify-content: flex-end; + align-items: center; + + input[type="number"] { + font-size: 1.2rem; + line-height: 1.2rem; + height: 30px; + font-family: 'Germania One'; + } + + h3 { + padding: 2px 5px; + margin: 0; + color: $c-light; + background-color: $c-green-olive; + font-family: Germania One; + + &.minmax { + padding-right: 5px; + background-color: $c-green-olive; + } + } } -.injuries-grid{ - display: grid; - grid-template-columns: repeat(3, 1fr); - //margin-bottom: 10px; - .injury-cell { - .controls{ - display: flex; - justify-content: space-between; - input[type="checkbox"] { - -webkit-appearance: none; - -moz-appearance: none; - filter: none; - box-sizing: borer-box; - width: 20px; - height: 20px; - cursor: pointer; - margin: 0; - &.treated{ - background: url(../assets/injury-not-treated.webp); - } - &.injury-type{ - background: url(../assets/injury-p.webp); - } - } - input[type="checkbox"]:checked { - margin: 0; - filter: none; - &.treated{background: url(../assets/injury-treated.webp);} - &.injury-type{ - background: url(../assets/injury-m.webp); - } - - } - } - - padding: 2px; - border: 1px solid $c-green-light; - margin:0 -1px -1px 0; - .injury-text{ - padding: 0; - resize: none; - border: none; - background-color: unset; - white-space: normal; - min-height: 6rem; - } - } +.injuries-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + + //margin-bottom: 10px; + .injury-cell { + .controls { + display: flex; + justify-content: space-between; + + input[type="checkbox"] { + -webkit-appearance: none; + -moz-appearance: none; + filter: none; + box-sizing: borer-box; + width: 20px; + height: 20px; + cursor: pointer; + margin: 0; + + &.treated { + background: url(../assets/injury-not-treated.webp); + } + + &.injury-type { + background: url(../assets/injury-p.webp); + } + } + + input[type="checkbox"]:checked { + margin: 0; + filter: none; + + &.treated { + background: url(../assets/injury-treated.webp); + } + + &.injury-type { + background: url(../assets/injury-m.webp); + } + + } + } + + padding: 2px; + border: 1px solid $c-green-light; + margin:0 -1px -1px 0; + + .injury-text { + padding: 0; + resize: none; + border: none; + background-color: unset; + white-space: normal; + min-height: 6rem; + } + } } -.truths-grid{ - display: grid; - grid-template-columns: repeat(5, 1fr); - margin-bottom: 10px; - .truth-cell { - padding: 2px; - border: 1px solid $c-green-light; - margin:0 -1px -1px 0; - textarea{ - resize: none; - border: none; - background-color: unset; - } - } +.truths-grid { + display: grid; + grid-template-columns: repeat(5, 1fr); + margin-bottom: 10px; + + .truth-cell { + padding: 2px; + border: 1px solid $c-green-light; + margin: 0 -1px -1px 0; + + textarea { + resize: none; + border: none; + background-color: unset; + } + } } -.skills{ - display: flex; - flex-direction: column; - border: 1px solid $c-green-light; - - .skill{ - display: flex; - flex-direction: row; - flex: 0; - border-bottom: 1px solid $c-green-light; - align-items: stretch; - .skill-name{ - display: flex; - flex: 1; - align-items: center; - padding: 5px; - color: $c-light; - background-color: $c-green-light; - font-weight: 900; - cursor: pointer; - } - .skill-value{ - display: flex; - align-items: center; - padding: 0 5px; - border-left: 1px solid $c-green-light; - border-right: 1px solid $c-green-light; - } - .skill-focuses{ - display: flex; - align-items: center; - flex-direction: row; - flex-wrap: wrap; - flex: 5; - padding: 5px; - .skill-focus{ - color:rgb(150, 150, 150); - &.focused{ - cursor: pointer; - color:beige; - background-color: $c-green-light; - border-radius: 3px; - padding: 0 2px; - } - } - } - } - .skill:last-child{ - border-bottom: none; - } +.skills { + display: flex; + flex-direction: column; + border: 1px solid $c-green-light; + + .skill { + display: flex; + flex-direction: row; + flex: 0; + border-bottom: 1px solid $c-green-light; + align-items: stretch; + + .skill-name { + display: flex; + flex: 1; + align-items: center; + padding: 5px; + color: $c-light; + background-color: $c-green-light; + font-weight: 900; + cursor: pointer; + } + + .skill-value { + display: flex; + align-items: center; + padding: 0 5px; + border-left: 1px solid $c-green-light; + border-right: 1px solid $c-green-light; + } + + .skill-focuses { + display: flex; + align-items: center; + flex-direction: row; + flex-wrap: wrap; + flex: 5; + padding: 5px; + color: rgb(150, 150, 150); + + .skill-focus { + + &.focused { + cursor: pointer; + color: beige; + background-color: $c-green-light; + border-radius: 3px; + padding: 0 2px; + margin: 0 1px; + } + } + } + } + + .skill:last-child { + border-bottom: none; + } } -.ac-grid{ - display: flex; - flex-direction: column; - border: 1px solid $c-green-light; - .item{ - border-bottom: 1px solid $c-green-light; - &:last-child{ - border-bottom: none; - } - .row{ - display: flex; - flex-direction: row; - flex: 0; - - align-items: stretch; - &:last-child{ - border-bottom: none; - } - .cell{ - display: flex; - padding: 5px; - border-right: 1px solid $c-green-light; - //text-align: center; - //justify-content: center; - &.align-center{ - align-items: center; - } - &.align-left{ - justify-content: start; - text-align: left; - } - &.cell-name{ - img{ - max-width: 1.563rem; - max-height: 1.563rem; - margin-right: 0.313rem; - } - } - &.column{ - flex-direction: column; - } - &:last-child{ - border-right: none; - } - &.f1{ - flex: 1; - } - &.f2{ - flex: 2; - } - &.f3{ - flex: 3; - } - &.f4{ - flex: 4; - } - &.f5{ - flex: 5; - } - &.f05{ - flex: 0.5; - } - &.roll{ - cursor: pointer; - } - &.green{ - color: $c-light; - background-color: $c-green-light; - font-weight: 900; - } - } - } - .item-summary{ - padding: 5px; - border-top: 1px solid $c-green-light; - border-bottom: 1px solid $c-green-light; - } - } +.ac-grid { + display: flex; + flex-direction: column; + border: 1px solid $c-green-light; + + .item { + border-bottom: 1px solid $c-green-light; + + &:last-child { + border-bottom: none; + } + + .row { + display: flex; + flex-direction: row; + flex: 0; + + align-items: stretch; + + &:last-child { + border-bottom: none; + } + + .cell { + display: flex; + padding: 5px; + border-right: 1px solid $c-green-light; + + //text-align: center; + //justify-content: center; + &.align-center { + align-items: center; + } + + &.align-left { + justify-content: start; + text-align: left; + } + + &.cell-name { + img { + max-width: 1.563rem; + max-height: 1.563rem; + margin-right: 0.313rem; + } + } + + &.column { + flex-direction: column; + } + + &:last-child { + border-right: none; + } + + &.f1 { + flex: 1; + } + + &.f2 { + flex: 2; + } + + &.f3 { + flex: 3; + } + + &.f4 { + flex: 4; + } + + &.f5 { + flex: 5; + } + + &.f05 { + flex: 0.5; + } + + &.roll { + cursor: pointer; + } + + &.green { + color: $c-light; + background-color: $c-green-light; + font-weight: 900; + } + } + } + + .item-summary { + padding: 5px; + border-top: 1px solid $c-green-light; + border-bottom: 1px solid $c-green-light; + } + } } -.label-number-box{ - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - padding: 0.3rem; - margin-bottom: 0.3rem; - background-color: $c-green-light; - input[type="number"]{ - height: 1.1rem; - } - &.blue{ - background-color: $c-blue-light; - } - label{ - font-weight: 900; - color: $c-light; - text-transform: capitalize; - } +.label-number-box { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 0.3rem; + margin-bottom: 0.3rem; + background-color: $c-green-light; + + input[type="number"] { + height: 1.1rem; + } + + &.blue { + background-color: $c-blue-light; + } + + label { + font-weight: 900; + color: $c-light; + text-transform: capitalize; + } } -.item-sheet{ - .focus-item{ - display: flex; - flex-direction: row; - margin-bottom: 5px; - } +.item-sheet { + .focus-item { + display: flex; + flex-direction: row; + margin-bottom: 5px; + } } -.editor-small{ - display: flex; - flex-direction: column; - //height: auto; - flex:1; - overflow: hidden; - // min-height: 220px; - // height: 200px; - .editor{ - flex: 0.96; - } - .tox { - flex: 1; - .tox-editor-container { - min-height: 100px; - flex: 1; - background: $c-white; - } - - .tox-edit-area { - flex: 1; - padding: 0 8px; - } - } +.editor-small { + display: flex; + flex-direction: column; + //height: auto; + flex: 1; + overflow: hidden; + + // min-height: 220px; + // height: 200px; + .editor { + flex: 0.96; + } + + .tox { + flex: 1; + + .tox-editor-container { + min-height: 100px; + flex: 1; + background: $c-white; + } + + .tox-edit-area { + flex: 1; + padding: 0 8px; + } + } } .cell-expander, -.expandable-info{ - cursor: pointer; +.expandable-info { + cursor: pointer; } #context-menu { - left: unset; - right: 0; - min-width: unset; - width: unset; - li.context-item { - line-height: 26px; - } - .context-items { - display: flex; - } + left: unset; + right: 0; + min-width: unset; + width: unset; + + li.context-item { + line-height: 26px; + } + + .context-items { + display: flex; + } } + .expand-down { - top: 3px !important; - right: 3px !important; - bottom: 0 !important; + top: 3px !important; + right: 3px !important; + bottom: 0 !important; } + .expand-up { - top: 3px !important; - right: 3px !important; - bottom: 0 !important; -} \ No newline at end of file + top: 3px !important; + right: 3px !important; + bottom: 0 !important; +} diff --git a/scss/components/_items.scss b/scss/components/_items.scss index f4909bb..6bf00aa 100644 --- a/scss/components/_items.scss +++ b/scss/components/_items.scss @@ -1,23 +1,25 @@ // Section Header .items-header { - height: 28px; - margin: 2px 0; - padding: 0; - align-items: center; - background: rgba(0, 0, 0, 0.05); - border: $c-green-light; - font-weight: bold; - > * { - font-size: 14px; - text-align: center; - } - .item-name { - font-weight: bold; - padding-left: 5px; - text-align: left; - display: flex; - // font-size: 16px; - } + height: 28px; + margin: 2px 0; + padding: 0; + align-items: center; + background: rgba(0, 0, 0, 0.05); + border: $c-green-light; + font-weight: bold; + + > * { + font-size: 14px; + text-align: center; + } + + .item-name { + font-weight: bold; + padding-left: 5px; + text-align: left; + display: flex; + // font-size: 16px; + } } /* ----------------------------------------- */ @@ -25,96 +27,106 @@ /* ----------------------------------------- */ // Child lists .item-list { - .item{ - margin: 0; - .effect-name{ - .item-image{ - max-width: 25px; - max-height:25px; - } - } - } - .item-list { - list-style: none; - margin: 0; - padding: 0; - } + .item { + margin: 0; + + .effect-name { + .item-image { + max-width: 25px; + max-height: 25px; + } + } + } + + .item-list { + list-style: none; + margin: 0; + padding: 0; + } } -.items-list-npc{ - list-style: none; - margin: 0; - padding: 0; - overflow-y: auto; - scrollbar-width: thin; - //color: $c-dark; - - // Child lists - .item-list { - list-style: none; - margin: 0; - padding: 0; - } - - .item{ - padding: 0.313rem; - .main-row{ - display: flex; - flex-direction: row; - justify-content: space-between; - - .item-name { - font-weight: 900; - font-size: 0.875rem; - } - } - .skill-focuses{ - *{ - font-size: 0.688rem; - } - } - } - - .item:nth-child(odd) { - background: lighten($c-light, 0%) - } - .item:nth-child(even) { - background: lighten($c-light, 5%) - } +.items-list-npc { + list-style: none; + margin: 0; + padding: 0; + overflow-y: auto; + scrollbar-width: thin; + //color: $c-dark; + + // Child lists + .item-list { + list-style: none; + margin: 0; + padding: 0; + } + + .item { + padding: 0.313rem; + + .main-row { + display: flex; + flex-direction: row; + justify-content: space-between; + + .item-name { + font-weight: 900; + font-size: 0.875rem; + } + } + + .skill-focuses { + * { + font-size: 0.688rem; + } + } + } + + .item:nth-child(odd) { + background: lighten($c-light, 0%) + } + + .item:nth-child(even) { + background: lighten($c-light, 5%) + } } - // Control Buttons - .item-controls { - display: flex; - flex: 0 0 100px; - justify-content: flex-end; - align-items: center; - a { - font-size: 12px; - text-align: center; - margin: 0 6px; - color: grey; - } +// Control Buttons +.item-controls { + display: flex; + flex: 0 0 100px; + justify-content: flex-end; + align-items: center; + + a { + font-size: 12px; + text-align: center; + margin: 0 6px; + color: grey; + } } + /* Example style for Boilerplate (can be removed if not needed) */ .item-formula { - flex: 0 0 200px; - padding: 0 8px; + flex: 0 0 200px; + padding: 0 8px; } -.item-control{ - color: $c-green-olive; - &.blue{ - color: $c-blue-dark; - } - margin-right: 3px; - &.item-unequipped, - .item-unstashed, - .item-unpowered, - .favorite-start-dim { - color: rgba(73, 78, 49, 0.3); - } -} \ No newline at end of file +.item-control { + color: $c-green-olive; + + &.blue { + color: $c-blue-dark; + } + + margin-right: 3px; + + &.item-unequipped, + .item-unstashed, + .item-unpowered, + .favorite-start-dim { + color: rgba(73, 78, 49, 0.3); + } +} diff --git a/scss/components/_momentum-app.scss b/scss/components/_momentum-app.scss index 7e840f9..4def081 100644 --- a/scss/components/_momentum-app.scss +++ b/scss/components/_momentum-app.scss @@ -8,7 +8,7 @@ //background-color: $f-vault-blue; bottom: 40px !important; right: 320px !important; - max-width: 180px; + max-width: 180px; z-index: 1000; .ap-resource { @@ -16,17 +16,20 @@ padding: 10px 20px; background-size: 100% 100%; background-repeat: no-repeat; - border-radius:9px; + border-radius: 9px; font-family: $font-germania; + //color: white; &.gm { - background-color: $c-green-olive; + background-color: $c-green-olive; } + &.party { - background-color: $c-green-light; + background-color: $c-green-light; } + &.maxMomentum-box { - background-color: $c-green-olive; + background-color: $c-green-olive; } .toggle-maxAp { @@ -37,17 +40,20 @@ } margin-bottom: 10px; + &:last-child { margin-bottom: 0; } + h4 { margin: 0 0 2px 0; color: bisque; } + input[type="number"] { margin: 0 5px; font-size: 16px; - text-align: center; + text-align: center; } .ap-btn { diff --git a/scss/components/_resource.scss b/scss/components/_resource.scss index 87cde1d..f062918 100644 --- a/scss/components/_resource.scss +++ b/scss/components/_resource.scss @@ -2,17 +2,20 @@ input[type="text"], input[type="number"] { background-color: $c-light; color: $c-dark; + &.underline { background-color: unset; border: unset; border-bottom: 1px solid $c-dark; color: $c-dark; + &::placeholder { color: #999; } } - &.borderless { - border: none; + + &.borderless { + border: none; } } @@ -20,30 +23,34 @@ input[type="number"] { input[type="checkbox"] { display: none; } + label { cursor: pointer; display: flex; - align-items: center; + align-items: center; } - padding: 3px; + + padding: 3px; + &.active { color: $c-light; - background-color:$c-green-light; + background-color: $c-green-light; } } -.resource{ +.resource { margin-bottom: 5px; align-items: center; - &.green-field{ + + &.green-field { padding: 5px; background-color: $c-green-olive; color: $c-light; } } -.resource-label{ +.resource-label { text-transform: capitalize; } @@ -69,30 +76,34 @@ select { max-width: 2rem; text-align: center; } + .num-short-3 { max-width: 3rem; text-align: center; } -.num-small{ - height:1.1rem ; + +.num-small { + height: 1.1rem; } -.clickable{ +.clickable { cursor: pointer; - &:hover{ + + &:hover { //font-weight: bold; text-shadow: 0 0 0.313rem #999; } } -.textbox{ - width: 100%; - height: 100%; - padding: 0.3rem; - border:1px solid grey; - textarea{ +.textbox { + width: 100%; + height: 100%; + padding: 0.3rem; + border: 1px solid grey; + + textarea { resize: none; - padding: 0; + padding: 0; border: unset; border-radius: 0; background-color: unset; diff --git a/scss/global/_flex.scss b/scss/global/_flex.scss index a95b5a6..8280087 100644 --- a/scss/global/_flex.scss +++ b/scss/global/_flex.scss @@ -1,57 +1,59 @@ // Flexbox. -.flex{ - display: flex; +.flex { + display: flex; } .flex-group-center, .flex-group-left, .flex-group-right { - justify-content: center; - align-items: center; - text-align: center; + justify-content: center; + align-items: center; + text-align: center; } .flex-group-left { - justify-content: flex-start; - text-align: left; + justify-content: flex-start; + text-align: left; } .flex-group-right { - justify-content: flex-end; - text-align: right; + justify-content: flex-end; + text-align: right; } .flexshrink { - flex: 0; + flex: 0; } .flex-between { - justify-content: space-between; + justify-content: space-between; } .flex-1 { - flex: 1; + flex: 1; } + .flex-2 { - flex: 2; + flex: 2; } + .flex-3 { - flex: 3; + flex: 3; } // Alignment styles. .align-left { - justify-content: flex-start; - text-align: left; + justify-content: flex-start; + text-align: left; } .align-right { - justify-content: flex-end; - text-align: right; + justify-content: flex-end; + text-align: right; } .align-center { - justify-content: center; - text-align: center; - align-items: center; -} \ No newline at end of file + justify-content: center; + text-align: center; + align-items: center; +} diff --git a/scss/global/_grid.scss b/scss/global/_grid.scss index 452a7b3..ae3bf34 100644 --- a/scss/global/_grid.scss +++ b/scss/global/_grid.scss @@ -1,85 +1,149 @@ // Grid. .grid, .grid-2col { - display: grid; - grid-column: span 2 / span 2; - grid-template-columns: repeat(2, minmax(0, 1fr)); - gap: 10px; - margin: 0 0 0.3rem 0; - padding: 0; + display: grid; + grid-column: span 2 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 10px; + margin: 0 0 0.3rem 0; + padding: 0; } .grid-3col { - grid-column: span 3 / span 3; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-column: span 3 / span 3; + grid-template-columns: repeat(3, minmax(0, 1fr)); } .grid-4col { - grid-column: span 4 / span 4; - grid-template-columns: repeat(4, minmax(0, 1fr)); + grid-column: span 4 / span 4; + grid-template-columns: repeat(4, minmax(0, 1fr)); } .grid-5col { - grid-column: span 5 / span 5; - grid-template-columns: repeat(5, minmax(0, 1fr)); + grid-column: span 5 / span 5; + grid-template-columns: repeat(5, minmax(0, 1fr)); } .grid-6col { - grid-column: span 6 / span 6; - grid-template-columns: repeat(6, minmax(0, 1fr)); + grid-column: span 6 / span 6; + grid-template-columns: repeat(6, minmax(0, 1fr)); } .grid-7col { - grid-column: span 7 / span 7; - grid-template-columns: repeat(7, minmax(0, 1fr)); + grid-column: span 7 / span 7; + grid-template-columns: repeat(7, minmax(0, 1fr)); } .grid-8col { - grid-column: span 8 / span 8; - grid-template-columns: repeat(8, minmax(0, 1fr)); + grid-column: span 8 / span 8; + grid-template-columns: repeat(8, minmax(0, 1fr)); } .grid-9col { - grid-column: span 9 / span 9; - grid-template-columns: repeat(9, minmax(0, 1fr)); + grid-column: span 9 / span 9; + grid-template-columns: repeat(9, minmax(0, 1fr)); } .grid-10col { - grid-column: span 10 / span 10; - grid-template-columns: repeat(10, minmax(0, 1fr)); + grid-column: span 10 / span 10; + grid-template-columns: repeat(10, minmax(0, 1fr)); } .grid-11col { - grid-column: span 11 / span 11; - grid-template-columns: repeat(11, minmax(0, 1fr)); + grid-column: span 11 / span 11; + grid-template-columns: repeat(11, minmax(0, 1fr)); } .grid-12col { - grid-column: span 12 / span 12; - grid-template-columns: repeat(12, minmax(0, 1fr)); + grid-column: span 12 / span 12; + grid-template-columns: repeat(12, minmax(0, 1fr)); } // Grid offset. -.grid-start-2 { grid-column-start: 2 } -.grid-start-3 { grid-column-start: 3 } -.grid-start-4 { grid-column-start: 4 } -.grid-start-5 { grid-column-start: 5 } -.grid-start-6 { grid-column-start: 6 } -.grid-start-7 { grid-column-start: 7 } -.grid-start-8 { grid-column-start: 8 } -.grid-start-9 { grid-column-start: 9 } -.grid-start-10 { grid-column-start: 10 } -.grid-start-11 { grid-column-start: 11 } -.grid-start-12 { grid-column-start: 12 } - -.grid-span-2 { grid-column-end: span 2 } -.grid-span-3 { grid-column-end: span 3 } -.grid-span-4 { grid-column-end: span 4 } -.grid-span-5 { grid-column-end: span 5 } -.grid-span-6 { grid-column-end: span 6 } -.grid-span-7 { grid-column-end: span 7 } -.grid-span-8 { grid-column-end: span 8 } -.grid-span-9 { grid-column-end: span 9 } -.grid-span-10 { grid-column-end: span 10 } -.grid-span-11 { grid-column-end: span 11 } -.grid-span-12 { grid-column-end: span 12 } +.grid-start-2 { + grid-column-start: 2 +} + +.grid-start-3 { + grid-column-start: 3 +} + +.grid-start-4 { + grid-column-start: 4 +} + +.grid-start-5 { + grid-column-start: 5 +} + +.grid-start-6 { + grid-column-start: 6 +} + +.grid-start-7 { + grid-column-start: 7 +} + +.grid-start-8 { + grid-column-start: 8 +} + +.grid-start-9 { + grid-column-start: 9 +} + +.grid-start-10 { + grid-column-start: 10 +} + +.grid-start-11 { + grid-column-start: 11 +} + +.grid-start-12 { + grid-column-start: 12 +} + +.grid-span-2 { + grid-column-end: span 2 +} + +.grid-span-3 { + grid-column-end: span 3 +} + +.grid-span-4 { + grid-column-end: span 4 +} + +.grid-span-5 { + grid-column-end: span 5 +} + +.grid-span-6 { + grid-column-end: span 6 +} + +.grid-span-7 { + grid-column-end: span 7 +} + +.grid-span-8 { + grid-column-end: span 8 +} + +.grid-span-9 { + grid-column-end: span 9 +} + +.grid-span-10 { + grid-column-end: span 10 +} + +.grid-span-11 { + grid-column-end: span 11 +} + +.grid-span-12 { + grid-column-end: span 12 +} diff --git a/scss/global/_window.scss b/scss/global/_window.scss index d9d2d8a..b5c5b02 100644 --- a/scss/global/_window.scss +++ b/scss/global/_window.scss @@ -1,20 +1,22 @@ .window-app { - font-family: $font-primary; - .window-content{ - background-image: url(../assets/paper.webp); - } + font-family: $font-primary; + + .window-content { + background-image: url(../assets/paper.webp); + } } -button{ - font-family: $font-germania; - font-size: 16px; - color: $c-green-olive; - background-color: $c-beige; - &:hover { - //text-shadow: 0 0 10px $c-green-light; - box-shadow: 0 0 5px $c-green-light; - cursor: pointer; - } +button { + font-family: $font-germania; + font-size: 16px; + color: $c-green-olive; + background-color: $c-beige; + + &:hover { + //text-shadow: 0 0 10px $c-green-light; + box-shadow: 0 0 5px $c-green-light; + cursor: pointer; + } } .font-primary { @@ -33,23 +35,29 @@ button{ font-size: 12px; } -input[type="text"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="date"]:focus, input[type="time"]:focus { - box-shadow: 0 0 5px $c-green-light; +input[type="text"]:focus, +input[type="number"]:focus, +input[type="password"]:focus, +input[type="date"]:focus, +input[type="time"]:focus { + box-shadow: 0 0 5px $c-green-light; } -a{ - &:hover{ - text-shadow: 0 0 10px $c-green-olive; - cursor: pointer; - } +a { + &:hover { + text-shadow: 0 0 10px $c-green-olive; + cursor: pointer; + } } + .rollable { - &:hover, - &:focus { - color: #000; - text-shadow: 0 0 10px $c-green-light; - cursor: pointer; - } + + &:hover, + &:focus { + color: #000; + text-shadow: 0 0 10px $c-green-light; + cursor: pointer; + } } @@ -62,32 +70,37 @@ a{ text-overflow: ''; margin-left: 5px; font-family: $font-germania; - } + } .resource { margin: 0 2px 5px; padding: 0 5px 0 0; background-color: $c-green-light; - //border: 1px solid $c-green-light ; + + //border: 1px solid $c-green-light ; .title-label { padding: 5px; font-family: $font-germania; - font-size: 1rem; + font-size: 1rem; color: $c-white; } + input[type="number"] { text-align: center; - background-color:$c-beige; + background-color: $c-beige; } } + ul { list-style: none; padding: 5px 20px; margin: 0 2px 5px; + //background-color: $c-beige; li { text-decoration: none; text-align: center; + .dice-icon { cursor: pointer; width: 32px; @@ -101,6 +114,7 @@ a{ font-weight: bold; text-align: center; background-image: url(../assets/chat/d20-green-light.svg); + &.marked { color: $c-light; background-image: url(../assets/chat/d20-olive.svg); @@ -117,21 +131,25 @@ a{ .ac2d20-chat-message { .content { padding: 5px; + h2 { border: none; font-family: $font-germania; font-weight: 700; } + .dices-result { margin: 5px 0 5px 0; min-height: 32px; } + .success-plaq { margin: 0 0 5px 0; font-family: $font-germania; - color: $c-green-olive; + color: $c-green-olive; //padding: 10px; font-size: 16px; + //background-image: url(../assets/chat/green-placq.webp); //background-size: 100% 100%; //background-repeat: no-repeat; @@ -141,16 +159,18 @@ a{ font-weight: bold; } } + .complication-plaq { margin: 0 0 5px 0; font-family: $font-germania; - color: $c-red-dark; + color: $c-red-dark; //padding: 14px 10px 10px 10px; //font-size: 12px; //background-image: url(../assets/chat/red-placq.webp); //background-size: 100% 100%; //background-repeat: no-repeat; } + .damage-plaq { //color: white; margin: 0 0 5px 0; @@ -161,6 +181,7 @@ a{ //background-size: 100% 100%; //background-repeat: no-repeat; } + .dice-icon { cursor: pointer; position: relative; @@ -174,20 +195,25 @@ a{ color: rgb(0, 0, 0); font-weight: bold; text-align: center; + //-webkit-text-stroke: 1px rgb(255, 255, 255); &.d20 { background-image: url(../assets/chat/d20-white.svg); + &.complication { color: honeydew !important; background-image: url(../assets/chat/d20-complication.svg); } + &.success { background-image: url(../assets/chat/d20-success.svg); } + &.crit { color: gold !important; background-image: url(../assets/chat/d20-crit.svg); } + &.reroll { color: #1d1d1d; } @@ -198,21 +224,27 @@ a{ line-height: 32px; background-size: 32px 32px; margin: 2px; + &.face-1 { background-image: url(../assets/chat/d1.webp); } + &.face-2 { background-image: url(../assets/chat/d2.webp); } + &.face-3 { background-image: url(../assets/chat/d3.webp); } + &.face-4 { background-image: url(../assets/chat/d4.webp); } + &.face-5 { background-image: url(../assets/chat/d5.webp); } + &.face-6 { background-image: url(../assets/chat/d6.webp); } @@ -225,15 +257,17 @@ a{ } } -.chat-item{ - .item-name{ +.chat-item { + .item-name { text-align: center; - h3{ + + h3 { font-family: $font-germania; font-size: 1.5rem; } } - img{ + + img { width: 4rem; height: 4rem; } @@ -241,10 +275,11 @@ a{ .dice-tooltip .dice-rolls .roll.max { - color: unset; - filter: none; + color: unset; + filter: none; } + .dice-tooltip .dice-rolls .roll.min { - color: unset; - filter: none; -} \ No newline at end of file + color: unset; + filter: none; +} diff --git a/scss/utils/_colors.scss b/scss/utils/_colors.scss index 3270ee8..55eb92c 100644 --- a/scss/utils/_colors.scss +++ b/scss/utils/_colors.scss @@ -9,5 +9,5 @@ $c-green-olive: #494e31; $c-green-light: #759549; $c-green-neon: #b4bb5b; $c-red-dark: #6b0b0b; -$c-blue-dark:#3d485a; -$c-blue-light:#548da9; \ No newline at end of file +$c-blue-dark: #3d485a; +$c-blue-light: #548da9; diff --git a/scss/utils/_mixins.scss b/scss/utils/_mixins.scss index 69dd2ad..cd1394d 100644 --- a/scss/utils/_mixins.scss +++ b/scss/utils/_mixins.scss @@ -1,16 +1,16 @@ @mixin element-invisible { - position: absolute; + position: absolute; - width: 1px; - height: 1px; - margin: -1px; - border: 0; - padding: 0; + width: 1px; + height: 1px; + margin: -1px; + border: 0; + padding: 0; - clip: rect(0 0 0 0); - overflow: hidden; + clip: rect(0 0 0 0); + overflow: hidden; } @mixin hide { - display: none; -} \ No newline at end of file + display: none; +} diff --git a/scss/utils/_typography.scss b/scss/utils/_typography.scss index a4a4521..5926c69 100644 --- a/scss/utils/_typography.scss +++ b/scss/utils/_typography.scss @@ -6,67 +6,76 @@ $font-secondary: 'Roboto', sans-serif; $font-germania: 'Germania One', cursive; $icomoon-font-family: "cthulhu-icons" !default; -$icomoon-font-path: "../fonts" !default; +$icomoon-font-path: "../assets/fonts" !default; $cth-ico-cth: "\e900"; $cth-ico-cth-cross: "\e901"; @font-face { - font-family: '#{$icomoon-font-family}'; - src: url('#{$icomoon-font-path}/#{$icomoon-font-family}.eot?h5tze8'); - src: url('#{$icomoon-font-path}/#{$icomoon-font-family}.eot?h5tze8#iefix') format('embedded-opentype'), - url('#{$icomoon-font-path}/#{$icomoon-font-family}.ttf?h5tze8') format('truetype'), - url('#{$icomoon-font-path}/#{$icomoon-font-family}.woff?h5tze8') format('woff'), - url('#{$icomoon-font-path}/#{$icomoon-font-family}.svg?h5tze8##{$icomoon-font-family}') format('svg'); - font-weight: normal; - font-style: normal; - font-display: block; - } - - [class^="cth-"], [class*=" cth-"] { - /* use !important to prevent issues with browser extensions that change fonts */ - font-family: '#{$icomoon-font-family}' !important; - font-style: normal; - font-weight: normal; - font-variant: normal; - text-transform: none; - line-height: 1; - /* Better Font Rendering =========== */ - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } - - .cth-ico-cth { - &:before { - content: $cth-ico-cth; - } - } - .cth-ico-cth-cross { - &:before { - content: $cth-ico-cth-cross; - } - } + font-family: '#{$icomoon-font-family}'; + src: url('#{$icomoon-font-path}/#{$icomoon-font-family}.eot?h5tze8'); + src: url('#{$icomoon-font-path}/#{$icomoon-font-family}.eot?h5tze8#iefix') format('embedded-opentype'), + url('#{$icomoon-font-path}/#{$icomoon-font-family}.ttf?h5tze8') format('truetype'), + url('#{$icomoon-font-path}/#{$icomoon-font-family}.woff?h5tze8') format('woff'), + url('#{$icomoon-font-path}/#{$icomoon-font-family}.svg?h5tze8##{$icomoon-font-family}') format('svg'); + font-weight: normal; + font-style: normal; + font-display: block; +} + +[class^="cth-"], +[class*=" cth-"] { + /* use !important to prevent issues with browser extensions that change fonts */ + font-family: '#{$icomoon-font-family}' !important; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + /* Better Font Rendering =========== */ + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.cth-ico-cth { + &:before { + content: $cth-ico-cth; + } +} + +.cth-ico-cth-cross { + &:before { + content: $cth-ico-cth-cross; + } +} - /* Generated by Glyphter (http://www.glyphter.com) on Wed Sep 21 2022*/ +/* Generated by Glyphter (http://www.glyphter.com) on Wed Sep 21 2022*/ @font-face { - font-family: 'AC Cthulhu Icons'; - src: url('../fonts/AC-Cthulhu-Icons.eot'); - src: url('../fonts/AC-Cthulhu-Icons.eot?#iefix') format('embedded-opentype'), - url('../fonts/AC-Cthulhu-Icons.woff') format('woff'), - url('../fonts/AC-Cthulhu-Icons.ttf') format('truetype'), - url('../fonts/AC-Cthulhu-Icons.svg#AC-Cthulhu-Icons') format('svg'); - font-weight: normal; - font-style: normal; + font-family: 'AC Cthulhu Icons'; + src: url('../fonts/AC-Cthulhu-Icons.eot'); + src: url('../fonts/AC-Cthulhu-Icons.eot?#iefix') format('embedded-opentype'), + url('../fonts/AC-Cthulhu-Icons.woff') format('woff'), + url('../fonts/AC-Cthulhu-Icons.ttf') format('truetype'), + url('../fonts/AC-Cthulhu-Icons.svg#AC-Cthulhu-Icons') format('svg'); + font-weight: normal; + font-style: normal; +} + +[class*='cthl-']:before { + display: inline-block; + font-family: 'AC Cthulhu Icons'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale } -[class*='cthl-']:before{ -display: inline-block; - font-family: 'AC Cthulhu Icons'; - font-style: normal; - font-weight: normal; - line-height: 1; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale + +.cthl-cthulhu:before { + content: '\0041'; +} + +.cthl-cross:before { + content: '\0043'; } -.cthl-cthulhu:before{content:'\0041';} -.cthl-cross:before{content:'\0043';} \ No newline at end of file diff --git a/scss/utils/_variables.scss b/scss/utils/_variables.scss index 6d22f61..260808e 100644 --- a/scss/utils/_variables.scss +++ b/scss/utils/_variables.scss @@ -2,4 +2,4 @@ $padding-sm: 5px; $padding-md: 10px; $padding-lg: 20px; -$border-groove: 2px groove #eeede0; \ No newline at end of file +$border-groove: 2px groove #eeede0; diff --git a/system/ac2d20.mjs b/system/ac2d20.mjs index 201c47e..e3084f8 100644 --- a/system/ac2d20.mjs +++ b/system/ac2d20.mjs @@ -9,19 +9,19 @@ import { ACItemSheet } from "./src/sheets/item-sheet.mjs"; // Import helper/utility classes and constants. import { AC2D20 } from "./src/helpers/config.mjs"; import { preloadHandlebarsTemplates } from "./src/helpers/templates.mjs"; -import { registerHandlebarsHelpers } from "./src/helpers/handlebars.mjs" -//Import Roll2D20 -import { Roller2D20 } from "./src/roller/ac2d20-roller.mjs" -import { Dialog2d20 } from './src/roller/dialog2d20.js' -import { DialogD6 } from './src/roller/dialogD6.js' -import DieACChallenge from './src/roller/challengeDie.js' -//Settings -import { registerSettings } from './src/settings.js'; +import { registerHandlebarsHelpers } from "./src/helpers/handlebars.mjs"; +// Import Roll2D20 +import { Roller2D20 } from "./src/roller/ac2d20-roller.mjs"; +import { Dialog2d20 } from "./src/roller/dialog2d20.js"; +import { DialogD6 } from "./src/roller/dialogD6.js"; +import DieACChallenge from "./src/roller/challengeDie.js"; +// Settings +import { registerSettings } from "./src/settings.js"; // Text Enrichers -import { registerEnrichers } from './src/enrichers.mjs'; -//Momentum -import { MomentumTracker } from './src/app/momentum-tracker.mjs' -//Combat Tracker +import { registerEnrichers } from "./src/enrichers.mjs"; +// Momentum +import { MomentumTracker } from "./src/app/momentum-tracker.mjs"; +// Combat Tracker import Combat2d20 from "./src/combat/combat.mjs"; import CombatTracker2d20 from "./src/combat/combat-tracker.mjs"; @@ -30,187 +30,196 @@ import CombatTracker2d20 from "./src/combat/combat-tracker.mjs"; /* -------------------------------------------- */ registerHandlebarsHelpers(); +Hooks.once("init", async function() { + // Add utility classes to the global game object so that they're more easily + // accessible in global contexts. -Hooks.once('init', async function () { - // Add utility classes to the global game object so that they're more easily - // accessible in global contexts. + game.ac2d20 = { + ACActor, + ACItem, + Roller2D20, + Dialog2d20, + DialogD6, + MomentumTracker, + }; - game.ac2d20 = { - ACActor, - ACItem, - Roller2D20, - Dialog2d20, - DialogD6, - MomentumTracker, - }; + // Add custom constants for configuration. + CONFIG.AC2D20 = AC2D20; - // Add custom constants for configuration. - CONFIG.AC2D20 = AC2D20; - - /** + /** * Set an initiative formula for the system * @type {String} */ - CONFIG.Combat.initiative = { - formula: "1", - decimals: 0 - }; + CONFIG.Combat.initiative = { + formula: "1", + decimals: 0, + }; - // Define custom Document classes - CONFIG.Actor.documentClass = ACActor; - CONFIG.Item.documentClass = ACItem; - CONFIG.Dice.terms["s"] = DieACChallenge; + // Define custom Document classes + CONFIG.Actor.documentClass = ACActor; + CONFIG.Item.documentClass = ACItem; + CONFIG.Dice.terms.s = DieACChallenge; // Combat tracker stuff CONFIG.Combat.documentClass = Combat2d20; CONFIG.ui.combat = CombatTracker2d20; - // Register sheet application classes - Actors.unregisterSheet("core", ActorSheet); - Actors.registerSheet("ac2d20", ACActorSheet, { types: ["character"], makeDefault: true }); - Actors.registerSheet("ac2d20", ACNPCSheet, { types: ["npc"], makeDefault: true }); - Actors.registerSheet("ac2d20", ACVehicleSheet, { types: ["vehicle"], makeDefault: true }); - Items.unregisterSheet("core", ItemSheet); - Items.registerSheet("ac2d20", ACItemSheet, { makeDefault: true }); + // Register sheet application classes + Actors.unregisterSheet("core", ActorSheet); + Actors.registerSheet("ac2d20", ACActorSheet, { types: ["character"], makeDefault: true }); + Actors.registerSheet("ac2d20", ACNPCSheet, { types: ["npc"], makeDefault: true }); + Actors.registerSheet("ac2d20", ACVehicleSheet, { types: ["vehicle"], makeDefault: true }); + Items.unregisterSheet("core", ItemSheet); + Items.registerSheet("ac2d20", ACItemSheet, { makeDefault: true }); - // Register custom system settings - registerSettings(); + // Register custom system settings + registerSettings(); // Register text enrichers. registerEnrichers(); - return preloadHandlebarsTemplates(); + return preloadHandlebarsTemplates(); }); -Hooks.on('ready', async () => { - // set skill list - const skillPackName = game.settings.get('ac2d20', 'compendium-skills'); - let packSkills = await game.packs.get(skillPackName).getDocuments(); - let _skills = [] - packSkills.forEach(s => { - _skills.push({ - 'label': s.name.toUpperCase(), - 'key': s.name, - 'focuses': s.system.focuses.map(f=> f.title) - }); - }); - AC2D20.SKILLS = [..._skills]; - const listLocation = await game.settings.get('ac2d20', 'hoversJsonLocation') - const jsonFile = await fetch(listLocation) - const content = await jsonFile.json(); - CONFIG.AC2D20.WEAPONS.effects = content.effects; - CONFIG.AC2D20.WEAPONS.qualities = content.qualities; - - for await (const key of Object.keys(content.effects)){ - let qEnriched = await TextEditor.enrichHTML(content.effects[key], {async: true}); - content.effects[key] = qEnriched.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", '''); - } - - for await (const key of Object.keys(content.qualities)){ - let qEnriched = await TextEditor.enrichHTML(content.qualities[key], {async: true}); - content.qualities[key] = qEnriched.replaceAll('&', '&').replaceAll('<', '<').replaceAll('>', '>').replaceAll('"', '"').replaceAll("'", '''); - } - -}) - - -Hooks.on('renderChatMessage', (message, html, data) => { - let rrlBtn = html.find('.reroll-button'); - if (rrlBtn.length > 0) { - rrlBtn[0].setAttribute('data-messageId', message.id); - rrlBtn.click((el) => { - //let selectedDiceForReroll = $(el.currentTarget).parent().find('.dice-selected'); - let selectedDiceForReroll = html.find('.dice-selected'); - let rerollIndex = []; - for (let d of selectedDiceForReroll) { - rerollIndex.push($(d).data('index')); - } - if (!rerollIndex.length) { - ui.notifications.notify('Select Dice you want to Reroll'); - } - else { - let ac2d20Roll = message.flags.ac2d20roll; - if (ac2d20Roll.diceFace == "d20") { - Roller2D20.rerollD20({ - rollname: ac2d20Roll.rollname, - rerollIndexes: rerollIndex, - successTreshold: ac2d20Roll.successTreshold, - critTreshold: ac2d20Roll.critTreshold, - complicationTreshold: ac2d20Roll.complicationTreshold, - dicesRolled: ac2d20Roll.dicesRolled - }); - } else if (ac2d20Roll.diceFace == "d6") { - Roller2D20.rerollD6({ - rollname: ac2d20Roll.rollname, - rerollIndexes: rerollIndex, - dicesRolled: ac2d20Roll.dicesRolled, - itemId: message.flags.itemId, - actorId: message.flags.actorId, - }); - } else { - ui.notifications.notify('No dice face reckognized'); - } - - } - }) - } - html.find('.dice-icon').click((el) => { - //if ($(el.currentTarget).hasClass('reroll')) - //return; - if ($(el.currentTarget).hasClass('dice-selected')) { - $(el.currentTarget).removeClass('dice-selected'); - } else { - $(el.currentTarget).addClass('dice-selected') - } - }); - let addBtn = html.find('.add-button'); - if (addBtn.length > 0) { - addBtn[0].setAttribute('data-messageId', message.id); - addBtn.click((ev) => { - let ac2d20Roll = message.flags.ac2d20roll; - let itemId = message.flags.itemId; - let actorId = message.flags.actorId; - game.ac2d20.DialogD6.createDialog({ rollname: ac2d20Roll.rollname, diceNum: 1, ac2d20Roll: ac2d20Roll, itemId: itemId, actorId: actorId }) - }); - } +Hooks.on("ready", async () => { + // set skill list + const skillPackName = game.settings.get("ac2d20", "compendium-skills"); + let packSkills = await game.packs.get(skillPackName).getDocuments(); + let _skills = []; + packSkills.forEach(s => { + _skills.push({ + label: s.name.toUpperCase(), + key: s.name, + focuses: s.system.focuses.map(f => f.title), + }); + }); + + AC2D20.SKILLS = _skills.sort((a, b) => a.key.localeCompare(b.key)); + + const listLocation = await game.settings.get("ac2d20", "hoversJsonLocation"); + const jsonFile = await fetch(listLocation); + const content = await jsonFile.json(); + CONFIG.AC2D20.WEAPONS.effects = content.effects; + CONFIG.AC2D20.WEAPONS.qualities = content.qualities; + + for await (const key of Object.keys(content.effects)) { + let qEnriched = await TextEditor.enrichHTML(content.effects[key], {async: true}); + content.effects[key] = qEnriched.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"); + } + + for await (const key of Object.keys(content.qualities)) { + let qEnriched = await TextEditor.enrichHTML(content.qualities[key], {async: true}); + content.qualities[key] = qEnriched.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'"); + } }); +Hooks.on("renderChatMessage", (message, html, data) => { + let rrlBtn = html.find(".reroll-button"); + if (rrlBtn.length > 0) { + rrlBtn[0].setAttribute("data-messageId", message.id); + rrlBtn.click(el => { + // let selectedDiceForReroll = $(el.currentTarget).parent().find('.dice-selected'); + let selectedDiceForReroll = html.find(".dice-selected"); + let rerollIndex = []; + for (let d of selectedDiceForReroll) { + rerollIndex.push($(d).data("index")); + } + if (!rerollIndex.length) { + ui.notifications.notify("Select Dice you want to Reroll"); + } + else { + let ac2d20Roll = message.flags.ac2d20roll; + if (ac2d20Roll.diceFace === "d20") { + Roller2D20.rerollD20({ + rollname: ac2d20Roll.rollname, + rerollIndexes: rerollIndex, + successTreshold: ac2d20Roll.successTreshold, + critTreshold: ac2d20Roll.critTreshold, + complicationTreshold: ac2d20Roll.complicationTreshold, + dicesRolled: ac2d20Roll.dicesRolled, + }); + } + else if (ac2d20Roll.diceFace === "d6") { + Roller2D20.rerollD6({ + rollname: ac2d20Roll.rollname, + rerollIndexes: rerollIndex, + dicesRolled: ac2d20Roll.dicesRolled, + itemId: message.flags.itemId, + actorId: message.flags.actorId, + }); + } + else { + ui.notifications.notify("No dice face reckognized"); + } + + } + }); + } + html.find(".dice-icon").click(el => { + // if ($(el.currentTarget).hasClass('reroll')) + // return; + if ($(el.currentTarget).hasClass("dice-selected")) { + $(el.currentTarget).removeClass("dice-selected"); + } + else { + $(el.currentTarget).addClass("dice-selected"); + } + }); + let addBtn = html.find(".add-button"); + if (addBtn.length > 0) { + addBtn[0].setAttribute("data-messageId", message.id); + addBtn.click(ev => { + let ac2d20Roll = message.flags.ac2d20roll; + let itemId = message.flags.itemId; + let actorId = message.flags.actorId; + game.ac2d20.DialogD6.createDialog({ + rollname: ac2d20Roll.rollname, + diceNum: 1, + ac2d20Roll: ac2d20Roll, + itemId: itemId, + actorId: actorId, + }); + }); + } + +}); + /* -------------------------------------------- */ /* DICE SO NICE */ /* -------------------------------------------- */ -Hooks.once("diceSoNiceReady", (dice3d) => { - dice3d.addSystem( - { id: "ac2d20", name: "Achtung Cthulhu 2d20" }, - true - ); - - dice3d.addColorset( - { - name: "ac2d20", - description: "Achtung Cthulhu 2d20", - category: "Colors", - foreground: "#000000", - background: "#000000", - outline: "#000000", - texture: "none", - } - ); - - dice3d.addDicePreset({ - type: "ds", - labels: [ - "systems/ac2d20/assets/dice/d1.webp", - "systems/ac2d20/assets/dice/d2.webp", - "systems/ac2d20/assets/dice/d3.webp", - "systems/ac2d20/assets/dice/d4.webp", - "systems/ac2d20/assets/dice/d5.webp", - "systems/ac2d20/assets/dice/d6.webp", - ], - system: "ac2d20", - colorset: "ac2d20" - }); +Hooks.once("diceSoNiceReady", dice3d => { + dice3d.addSystem( + { id: "ac2d20", name: "Achtung Cthulhu 2d20" }, + true + ); + + dice3d.addColorset( + { + name: "ac2d20", + description: "Achtung Cthulhu 2d20", + category: "Colors", + foreground: "#000000", + background: "#000000", + outline: "#000000", + texture: "none", + } + ); + + dice3d.addDicePreset({ + type: "ds", + labels: [ + "systems/ac2d20/assets/dice/d1.webp", + "systems/ac2d20/assets/dice/d2.webp", + "systems/ac2d20/assets/dice/d3.webp", + "systems/ac2d20/assets/dice/d4.webp", + "systems/ac2d20/assets/dice/d5.webp", + "systems/ac2d20/assets/dice/d6.webp", + ], + system: "ac2d20", + colorset: "ac2d20", + }); }); diff --git a/system/fonts/AC-Cthulhu-Icons.eot b/system/assets/fonts/AC-Cthulhu-Icons.eot similarity index 100% rename from system/fonts/AC-Cthulhu-Icons.eot rename to system/assets/fonts/AC-Cthulhu-Icons.eot diff --git a/system/fonts/AC-Cthulhu-Icons.svg b/system/assets/fonts/AC-Cthulhu-Icons.svg similarity index 100% rename from system/fonts/AC-Cthulhu-Icons.svg rename to system/assets/fonts/AC-Cthulhu-Icons.svg diff --git a/system/fonts/AC-Cthulhu-Icons.ttf b/system/assets/fonts/AC-Cthulhu-Icons.ttf similarity index 100% rename from system/fonts/AC-Cthulhu-Icons.ttf rename to system/assets/fonts/AC-Cthulhu-Icons.ttf diff --git a/system/fonts/AC-Cthulhu-Icons.woff b/system/assets/fonts/AC-Cthulhu-Icons.woff similarity index 100% rename from system/fonts/AC-Cthulhu-Icons.woff rename to system/assets/fonts/AC-Cthulhu-Icons.woff diff --git a/system/fonts/cthulhu-icons.eot b/system/assets/fonts/cthulhu-icons.eot similarity index 100% rename from system/fonts/cthulhu-icons.eot rename to system/assets/fonts/cthulhu-icons.eot diff --git a/system/fonts/cthulhu-icons.svg b/system/assets/fonts/cthulhu-icons.svg similarity index 100% rename from system/fonts/cthulhu-icons.svg rename to system/assets/fonts/cthulhu-icons.svg diff --git a/system/fonts/cthulhu-icons.ttf b/system/assets/fonts/cthulhu-icons.ttf similarity index 100% rename from system/fonts/cthulhu-icons.ttf rename to system/assets/fonts/cthulhu-icons.ttf diff --git a/system/fonts/cthulhu-icons.woff b/system/assets/fonts/cthulhu-icons.woff similarity index 100% rename from system/fonts/cthulhu-icons.woff rename to system/assets/fonts/cthulhu-icons.woff diff --git a/system/lang/en.json b/system/lang/en.json deleted file mode 100644 index d17ae05..0000000 --- a/system/lang/en.json +++ /dev/null @@ -1,371 +0,0 @@ -{ - "AC2D20.AbilityAbbr.agi": "agi", - "AC2D20.AbilityAbbr.bra": "bra", - "AC2D20.AbilityAbbr.coo": "coo", - "AC2D20.AbilityAbbr.ins": "ins", - "AC2D20.AbilityAbbr.rea": "rea", - "AC2D20.AbilityAbbr.wil": "wil", - "AC2D20.Ability.agi": "Agility", - "AC2D20.Ability.bra": "Brawn", - "AC2D20.Ability.coo": "Coordination", - "AC2D20.Ability.ins": "Insight", - "AC2D20.Ability.rea": "Reason", - "AC2D20.Ability.wil": "Will", - "AC2D20.EffectCreate": "Create Effect", - "AC2D20.EffectDelete": "Delete Effect", - "AC2D20.EffectEdit": "Edit Effect", - "AC2D20.EffectToggle": "Toggle Effect", - "AC2D20.equipped": "Equipped", - "AC2D20.STRESS": { - "current": "Current Stress", - "stress": "Stress", - "max": "Max Stress" - }, - "AC2D20.OTHER": "Other", - "AC2D20.RANGE": { - "reach": "Reach", - "close": "Close", - "medium": "Medium", - "long": "Long", - "extreme": "Extreme" - }, - "AC2D20.RESISTANCE": { - "armor": "Armor", - "courage": "Courage", - "fatigue": "Fatigue", - "resistance": "Resistance" - }, - "AC2D20.SKILL": { - "ACADEMIA": "Academia", - "ATHLETICS": "Athletics", - "ENGINEERING": "Engineering", - "FIGHTING": "Fighting", - "MEDICINE": "Medicine", - "OBSERVATION": "Observation", - "PERSUASION": "Persuasion", - "RESILIENCE": "Resilience", - "STEALTH": "Stealth", - "SURVIVAL": "Survival", - "TACTICS": "Tactics", - "VEHICLES": "Vehicles" - }, - "AC2D20.FOCUS": { - "Art": "Art", - "Cryptography": "Cryptography", - "Finance": "Finance", - "History": "History", - "Linguistics": "Linguistics", - "Occultism": "Occultism", - "Science": "Science", - "Climbing": "Climbing", - "Lifting": "Lifting", - "Physical Training": "Physical Training", - "Running": "Running", - "Swimming": "Swimming", - "Throwing": "Throwing", - "Architecture": "Architecture", - "Combat Engineering": "Combat Engineering", - "Electronics": "Electronics", - "Explosives": "Explosives", - "Mechanical Engineering": "Mechanical Engineering", - "Close Quarters": "Close Quarters", - "Handguns": "Handguns", - "Hand-to-Hand": "Hand-to-Hand", - "Heavy Weapons": "Heavy Weapons", - "Melee Weapons": "Melee Weapons", - "Threat Awareness": "Threat Awareness", - "Exotic": "Exotic", - "First Aid": "First Aid", - "Infectious Diseases": "Infectious Diseases", - "Pharmacology": "Pharmacology", - "Psychiatry": "Psychiatry", - "Rifles": "Rifles", - "Surgery": "Surgery", - "Toxicology": "Toxicology", - "Hearing": "Hearing", - "Instincts": "Instincts", - "Sight": "Sight", - "Smell and Taste": "Smell and Taste", - "Charm": "Charm", - "Innuendo": "Innuendo", - "Intimidation": "Intimidation", - "Negotiation": "Negotiation", - "Rhetoric": "Rhetoric", - "Deceive": "Deceive", - "Invocation": "Invocation", - "Fortitude": "Fortitude", - "Discipline": "Discipline", - "Immunity": "Immunity", - "Camouflage": "Camouflage", - "Disguise": "Disguise", - "Rural Stealth": "Rural Stealth", - "Urban Stealth": "Urban Stealth", - "Animal Handling": "Animal Handling", - "Foraging": "Foraging", - "Hunting": "Hunting", - "Mysticism": "Mysticism", - "Orienteering": "Orienteering", - "Tracking": "Tracking", - "Air Force": "Air Force", - "Army": "Army", - "Covert Operations": "Covert Operations", - "Leadership": "Leadership", - "Navy": "Navy", - "Technical Projects": "Technical Projects", - "Cars": "Cars", - "Motorcycles": "Motorcycles", - "Heavy Vehicles": "Heavy Vehicles", - "Tanks": "Tanks", - "Aircraft": "Aircraft", - "Watercraft": "Watercraft" - }, - "AC2D20.SPELL": { - "SpellTypes": { - "ins": "Traditional", - "rea": "Researcher", - "wil": "Dabbler" - } - }, - "AC2D20.TEMPLATES": { - "Salvo": "Salvo", - "Resistance": "Resistance", - "Qualities": "Qualities", - "SkillFocus": "Skill Focus", - "Resources": "Resources", - "Restriction": "Restriction", - "SpecialRule": "SpecialRule", - "SpecialRules": "Special Rules", - "Power": "Power", - "Size": "Size", - "speed": "Speed", - "bonus": "Bonus", - "scale": "Scale", - "equipped": "equipped", - "SizeLevels": { - "Trivial": "Trivial", - "Minor": "Minor", - "Major": "Major" - }, - "Abilities": "Abilities", - "Difficulty": "Difficulty", - "Diff": "Diff", - "Cost": "Cost", - "SpellType": "Type", - "Talents": "Talents", - "Spells": "Spells", - "Spells_Rituals": "Spells And Rituals", - "Ammo": "Ammo", - "Attacks": "ATTACKS", - "Attribute": "Attribute", - "Attributes": "Attributes", - "Attr": "Attr.", - "Compl": "Compl.", - "Complications": "Complications", - "Conditions": "Conditions", - "Create_Ammo": "Create Ammo", - "Create_Special_Rule": "Create Special Rule", - "Create_Weapon": "Create Weapon", - "current": "current", - "CostEffects": "Cost Effects", - "DAMAGE": "DAMAGE", - "DAMAGE_EFFECTS": "DAMAGE EFFECTS", - "DAMAGE_TYPE": "DAMAGE TYPE", - "Data": "Data", - "Default_Attribute": "Default Attribute", - "DEFENSE": "DEFENSE", - "Delete": "Delete", - "Delete_Item": "Delete Item", - "DERIVED": "DERIVED", - "Description": "Description", - "Duration": "Duration", - "Dur": "Dur", - "Edit_Item": "Edit Item", - "Effect": "Effect", - "Effects": "Effects", - "Encumbrance": "Encumbrance", - "Encumbrance_Level": "Encumbrance Level", - "Encumbered": "ENCUMBERED", - "ENG": "ENG", - "FAVORITE_WEAPONS": "FAVORITE WEAPONS", - "FIRE_RATE": "FIRE RATE", - "Gear": "Gear", - "GENERAL": "GENERAL", - "Healthy": "Healthy", - "HP_Healed": "HP Healed", - "INITIATIVE": "INITIATIVE", - "INJURIES": "Injuries", - "Issue": "Issue", - "Keywords": "Keywords", - "lbs": "lbs", - "Learned": "Learned", - "Luck": "Luck", - "MAX": "MAX", - "max": "max", - "MAX_PARTY_MOMENTUM": "Max Momentum", - "MELEE_BONUS": "MELEE BONUS", - "MELEE_DAMAGE": "MELEE DAMAGE", - "Mod_Type": "Mod Type", - "MODULES": "MODULES", - "Name_Prefix": "Name Prefix", - "GM_MOMENTUM": "GM Threat", - "PARTY_MOMENTUM": "Party Momentum", - "PHYS": "PHYS", - "Points": "Points", - "POISON": "POISON", - "RANGE": "Range", - "Rank": "Rank", - "Ranks_current_maximum": "Ranks [current/maximum]", - "Re_roll": "Re-roll", - "Requirements": "Requirements", - "RESISTANCES": "RESISTANCES", - "Resistances": "Resistances", - "Roll_Formula": "Roll Formula", - "Skill": "Skill", - "Skill_Focus": "Skill Focus", - "Skill_Value": "Skill Value", - "Skills": "Skills", - "Source": "Source", - "Status": "Status", - "Successes": "Successes", - "Focus": "Focus", - "TN": "TN", - "Total": "Total", - "Use_Agility": "Use Agility", - "Use_Brawn": "Use Brawn", - "Use_Coordination": "Use Coordination", - "Use_Insight": "Use Insight", - "Use_Reason": "Use Reason", - "Use_Will": "Use Will", - "Weapon_Qualities": "WEAPON QUALITIES", - "Weapon_Type": "Weapon Type", - "Weapons": "Weapons", - "Ritual": "Ritual", - "ritual_stress": "Ritual Stress", - "ritual_steps": "Ritual Steps", - "ritual_resistance": "Resistance", - "ritual_requirements": "Requirements", - "fortune": "Fortune", - "Personal_Truth_Scars": "Personal Truths & Scars", - "Truths": "Truths", - "rating": "Rating", - "skill_focus": "Skill/Focus", - "AddFocus": "Add Focus" - }, - "AC2D20.UI": { - "Add": "Add", - "CarryWeight": "Carry Weight", - "Cost": "Cost", - "Damage": "Damage", - "favorite": "Favorite", - "INVENTORY": "Inventory", - "Name": "Name", - "ORIGIN": "ORIGIN", - "OTHER": "Other", - "Quantity": "Quantity", - "Rarity": "Rarity", - "SPECIAL_RULE": "Special Rule", - "stashed": "Stashed", - "Type": "Type", - "UNSORTED": "Unsorted", - "Weight": "Weight" - }, - "AC2D20.WEAPONS": { - "qualities": "Qualities", - "type": "Weapon Type", - "damageEffect": { - "area": "Area", - "backlash": "Backlash", - "drain": "Drain", - "intense": "Intense", - "persistent": "Persistent", - "piercing": "Piercing", - "snare": "Snare", - "stun": "Stun", - "vicious": "Vicious" - }, - "damageType": { - "energy": "Energy", - "physical": "Physical", - "poison": "Poison", - "radiation": "Radiation" - }, - "weaponQuality": { - "accurate": "Accurate", - "closeQuarters": "Close Quarters", - "cumbersome": "Cumbersome", - "debilitating": "Debilitating", - "escalation": "Escalation", - "giant-killer": "Giant-Killer", - "heavy": "Heavy", - "hidden": "Hidden", - "inaccurate": "Inaccurate", - "indirect": "Indirect", - "munition": "Munition", - "parrying": "Parrying", - "reliable": "Reliable", - "subtle": "Subtle", - "unreliable": "Unreliable", - "bane": "Bane", - "hunger": "Hunger" - }, - "weaponTypes": { - "Melee": "Melee", - "Ranged": "Ranged", - "Mental": "Mental", - "agi": "Melee", - "coo": "Ranged", - "wil": "Mental" - } - }, - "AC2D20.ARMOR": { - "qualities": { - "heavy": "Heavy", - "uncomfortable": "Uncomfortable", - "shield": "Shield" - } - }, - "AC2D20.VEHICLES.QUALITIES": { - "cargo": "Cargo", - "cumbersome": "Cumbersome", - "enclosed": "Enclosed", - "exposed": "Exposed", - "highPerformance": "High Performance", - "singleSeat:": "Single Seat", - "tough": "Tough" - }, - "TYPES.Actor.character": "Character", - "TYPES.Actor.npc": "NPC", - "ACTOR.NpcType": { - "Trooper": "Trooper", - "Lieutenant": "Lieutenant", - "Nemesis": "Nemesis" - }, - "TYPES.Actor.vehicle": "Vehicle", - "ACTOR.Vehicle": { - "Passengers": "Passengers", - "Cover": "Cover", - "Impact": "Impact" - }, - "TYPES.Item.armor": "Armor", - "TYPES.Item.talent": "Talent", - "TYPES.Item.spell": "Spell", - "TYPES.Item.skill": "Skill", - "TYPES.Item.skillkit": "Skill Kit", - "TYPES.Item.equipment": "Equipment", - "TYPES.Item.special_rule": "Special Rule", - "TYPES.Item.weapon": "Weapon", - "AC2D20.Spellcasting":{ - "SpellcastingType":"Spellcasting Type", - "traditional":"traditional", - "researcher":"researcher", - "dabbler":"dabbler" - }, - "AC2D20.Combat": { - "CombatantsTurnDone": "Turn Completed", - "CombatantsTurnNotDone": "Turn Not Completed", - "CombatEndMomentumPoolDecremented": "Momentum Pool Decremented at End of Combat", - "CombatHasNotStarted": "Combat Has Not Started", - "CombatRoundMomentumPoolDecremented": "Momentum Pool Decremented at Start of New Round", - "ToggleCombatantsTurnDone": "Toggle Turn Completed" - } -} diff --git a/system/lang/es.json b/system/lang/es.json deleted file mode 100644 index bf52532..0000000 --- a/system/lang/es.json +++ /dev/null @@ -1,357 +0,0 @@ -{ - "AC2D20.AbilityAbbr.agi": "agi", - "AC2D20.AbilityAbbr.bra": "mus", - "AC2D20.AbilityAbbr.coo": "coo", - "AC2D20.AbilityAbbr.ins": "pers", - "AC2D20.AbilityAbbr.rea": "raz", - "AC2D20.AbilityAbbr.wil": "vol", - "AC2D20.Ability.agi": "Agilidad", - "AC2D20.Ability.bra": "Músculo", - "AC2D20.Ability.coo": "Coordinación", - "AC2D20.Ability.ins": "Perspicacia", - "AC2D20.Ability.rea": "Razón", - "AC2D20.Ability.wil": "Voluntad", - "AC2D20.EffectCreate": "Crear Efecto", - "AC2D20.EffectDelete": "Borrar Efecto", - "AC2D20.EffectEdit": "Editar Efecto", - "AC2D20.EffectToggle": "Alternar Efecto", - "AC2D20.equipped": "Equipado", - "AC2D20.STRESS": { - "current": "Estrés actual", - "stress": "Estrés", - "max": "Estrés Máximo" - }, - "AC2D20.OTHER": "Otro", - "AC2D20.RANGE": { - "reach": "Alcance", - "close": "Corto", - "medium": "Medio", - "long": "Largo", - "extreme": "Extremo" - }, - "AC2D20.RESISTANCE": { - "armor": "Armadura", - "courage": "Coraje", - "fatigue": "Fatiga", - "resistance": "Resistencia" - }, - "AC2D20.SKILL": { - "ACADEMIA": "Académicas", - "ATHLETICS": "Atletismo", - "ENGINEERING": "Ingeniería", - "FIGHTING": "Combate", - "MEDICINE": "Medicina", - "OBSERVATION": "Observación", - "PERSUASION": "Persuasión", - "RESILIENCE": "Resiliencia", - "STEALTH": "Sigilo", - "SURVIVAL": "Supervivencia", - "TACTICS": "Tácticas", - "VEHICLES": "Vehículos" - }, - "AC2D20.FOCUS": { - "Art": "Arte", - "Cryptography": "Criptografía", - "Finance": "Finanzas", - "History": "Historia", - "Linguistics": "Linguística", - "Occultism": "Ocultismo", - "Science": "Ciencia", - "Climbing": "Escalar", - "Lifting": "Levantar", - "Physical Training": "Entrenamiento Físico", - "Running": "Correr", - "Swimming": "Nadar", - "Throwing": "Lanzar", - "Architecture": "Arquitectura", - "Combat Engineering": "Ingeniería de Combate", - "Electronics": "Electrónica", - "Explosives": "Explosivos", - "Mechanical Engineering": "Ingeniería Mecánica", - "Close Quarters": "Cercana", - "Handguns": "Pístolas", - "Hand-to-Hand": "Mano a mano", - "Heavy Weapons": "Armas Pesadas", - "Melee Weapons": "Armas de Melé", - "Threat Awareness": "Sentir el Peligro", - "Exotic": "Exoticas", - "First Aid": "Primeros Auxilios", - "Infectious Diseases": "Enfermedades Infecciosas", - "Pharmacology": "Farmacología", - "Psychiatry": "Psiquiatría", - "Rifles": "Rifles", - "Surgery": "Cirugía", - "Toxicology": "Toxicología", - "Hearing": "Escuchar", - "Instincts": "Instintos", - "Sight": "Ver", - "Smell and Taste": "Oler y Saborear", - "Charm": "Encanto", - "Innuendo": "Seducción", - "Intimidation": "Intimidación", - "Negotiation": "Negociación", - "Rhetoric": "Retórica", - "Deceive": "Engaño", - "Invocation": "Invocación", - "Fortitude": "Fortaleza Interior", - "Discipline": "Disciplina", - "Immunity": "Inmunidad", - "Camouflage": "Camuflaje", - "Disguise": "Disfraz", - "Rural Stealth": "Sigilo a campo abierto", - "Urban Stealth": "Sigilo Urbano", - "Animal Handling": "Manejo de Animales", - "Foraging": "Forrajeo", - "Hunting": "Caza", - "Mysticism": "Misticismo", - "Orienteering": "Orientación", - "Tracking": "Rastrear", - "Air Force": "Fuerza Aérea", - "Army": "Ejército", - "Covert Operations": "Operaciones Encubiertas", - "Leadership": "Liderazgo", - "Navy": "Armada", - "Technical Projects": "Proyectos Técnicos", - "Cars": "Coches", - "Motorcycles": "Motocicletas", - "Heavy Vehicles": "Vehículos Pesados", - "Tanks": "Tanques", - "Aircraft": "Vehículos Aéreos", - "Watercraft": "Vehículos Acuáticos" - }, - "AC2D20.SPELL": { - "SpellTypes": { - "ins": "Tradicional", - "rea": "Investigador", - "wil": "Aficionado" - } - }, - "AC2D20.TEMPLATES": { - "Salvo": "Salva", - "Resistance": "Resistencia", - "Qualities": "Cualidades", - "SkillFocus": "Especialidad de Habilidad", - "Resources": "Recursos", - "Restriction": "Restricción", - "SpecialRule": "Regla Especial", - "SpecialRules": "Reglas Especiales", - "Power": "Poder", - "Size": "Tamaño", - "speed": "Velocidad", - "bonus": "Bono", - "scale": "Escala", - "equipped": "Equipado", - "SizeLevels": { - "Trivial": "Trivial", - "Minor": "Menor", - "Major": "Mayor" - }, - "Abilities": "Habilidades", - "Difficulty": "Dificultad", - "Diff": "Dif", - "Cost": "Coste", - "SpellType": "Tipo", - "Talents": "Talentos", - "Spells": "Conjuros", - "Spells_Rituals": "Conjuros y Rituales", - "Ammo": "Munición", - "Attacks": "ATAQUES", - "Attribute": "Atributo", - "Attributes": "Atributos", - "Attr": "Atri.", - "Compl": "Compl.", - "Complications": "Complicaciones", - "Conditions": "Condiciones", - "Create_Ammo": "Crear Munición", - "Create_Special_Rule": "Crear Regla Especial", - "Create_Weapon": "Crear Arma", - "current": "actual", - "CostEffects": "Coste de Efectos", - "DAMAGE": "DAÑO", - "DAMAGE_EFFECTS": "EFECTOS DE DAÑO", - "DAMAGE_TYPE": "TIPO DE DAÑO", - "Data": "Datos", - "Default_Attribute": "Atributo por Defecto", - "DEFENSE": "DEFENSA", - "Delete": "Borrar", - "Delete_Item": "Borrar Objeto", - "DERIVED": "DERIVADO", - "Description": "Descripción", - "Duration": "Duración", - "Dur": "Dur", - "Edit_Item": "Editar Objeto", - "Effect": "Efecto", - "Effects": "Efectos", - "Encumbrance": "Carga", - "Encumbrance_Level": "Nivel de Carga", - "Encumbered": "SOBRECARGADO", - "ENG": "ENG", - "FAVORITE_WEAPONS": "ARMAS FAVORITAS", - "FIRE_RATE": "CADENCIA DE FUEG", - "Gear": "Equipo", - "GENERAL": "GENERAL", - "Healthy": "Saludable", - "HP_Healed": "PV Curados", - "INITIATIVE": "INICIATIVA", - "INJURIES": "Heridas", - "Issue": "Problema", - "Keywords": "Palabras Clave", - "lbs": "lbs", - "Learned": "Aprendida", - "Luck": "Suerte", - "MAX": "MAX", - "max": "max", - "MAX_PARTY_MOMENTUM": "Inercia Máxima", - "MELEE_BONUS": "BONO MELÉ", - "MELEE_DAMAGE": "DAÑO MELÉ", - "Mod_Type": "Tipo Mod", - "MODULES": "MODULOS", - "Name_Prefix": "Prefijo del Nombre", - "GM_MOMENTUM": "Amenaza DJ", - "PARTY_MOMENTUM": "Inercia Grupo", - "PHYS": "FIS", - "Points": "Puntos", - "POISON": "VENENO", - "RANGE": "Alcance", - "Rank": "Rango", - "Ranks_current_maximum": "Rangos [actual/máximo]", - "Re_roll": "Tirar de Nuevo", - "Requirements": "Requerimientos", - "RESISTANCES": "RESISTENCIAS", - "Resistances": "Resistencias", - "Roll_Formula": "Fórmula de Tirada", - "Skill": "Habilidad", - "Skill_Focus": "Especialidad de Habilidad", - "Skill_Value": "Valor de Habilidad", - "Skills": "Habilidades", - "Source": "Origen", - "Status": "Estatus", - "Successes": "Éxitos", - "Focus": "Especialización", - "TN": "TN", - "Total": "Total", - "Use_Agility": "Usa Agilidad", - "Use_Brawn": "Usa Músculo", - "Use_Coordination": "Usa Coordinación", - "Use_Insight": "Usa Perspicacia", - "Use_Reason": "Usa Razón", - "Use_Will": "Usa Voluntad", - "Weapon_Qualities": "CUALIDADES DE ARMA", - "Weapon_Type": "Tipo de Arma", - "Weapons": "Armas", - "Ritual": "Ritual", - "ritual_stress": "Estrés Ritual", - "ritual_steps": "Fases del Ritual", - "ritual_resistance": "Resistencia", - "ritual_requirements": "Requerimientos", - "fortune": "Fortuna", - "Personal_Truth_Scars": "Verdades Personales & Cicatrices", - "Truths": "Verdades", - "rating": "Valor", - "skill_focus": "Habilidad/Especialidad", - "AddFocus": "Añadir Especialidad" - }, - "AC2D20.UI": { - "Add": "Añadir", - "CarryWeight": "Peso Acarreado", - "Cost": "Coste", - "Damage": "Daño", - "favorite": "Favorito", - "INVENTORY": "Inventario", - "Name": "Nombre", - "ORIGIN": "ORIGEN", - "OTHER": "Otro", - "Quantity": "Cantidad", - "Rarity": "Rareza", - "SPECIAL_RULE": "Regla Especial", - "stashed": "Reservado", - "Type": "Tipo", - "UNSORTED": "Desordenado", - "Weight": "Peso" - }, - "AC2D20.WEAPONS": { - "qualities": "Cualidades", - "type": "Tipo de Arma", - "damageEffect": { - "area": "Área", - "backlash": "Retroceso", - "drain": "Drenar", - "intense": "Intensa", - "persistent": "Persistente", - "piercing": "Perforante", - "snare": "Trampa", - "stun": "Aturdidora", - "vicious": "Feroz" - }, - "damageType": { - "energy": "Enegía", - "physical": "Física", - "poison": "Veneno", - "radiation": "Radiación" - }, - "weaponQuality": { - "accurate": "Precisa", - "closeQuarters": "Cercana", - "cumbersome": "Incómoda", - "debilitating": "Debilitante", - "escalation": "Recrudecimiento", - "giant-killer": "Mata-Gigantes", - "heavy": "Pesada", - "hidden": "Oculta", - "inaccurate": "Imprecisa", - "indirect": "Indirecta", - "munition": "Munición", - "parrying": "Parada", - "reliable": "Fiable", - "subtle": "Sutil", - "unreliable": "No fiable", - "bane": "Flagelo", - "hunger": "Hambrienta" - }, - "weaponTypes": { - "Melee": "Melé", - "Ranged": "Distancia", - "Mental": "Mental", - "agi": "Melé", - "coo": "Distancia", - "wil": "Mental" - } - }, - "AC2D20.ARMOR": { - "qualities": { - "heavy": "Pesada", - "uncomfortable": "Incómoda", - "shield": "Escudo" - } - }, - "AC2D20.VEHICLES.QUALITIES": { - "cargo": "Carga", - "cumbersome": "Incómodo", - "enclosed": "Cerrado", - "exposed": "Expuesto", - "highPerformance": "Alta Eficacia", - "singleSeat:": "Asiento único", - "tough": "Duro" - }, - "ACTOR.TypeCharacter": "Personaje Jugador", - "ACTOR.TypeNpc": "PNJ", - "ACTOR.NpcType": { - "Trooper": "Tropa", - "Lieutenant": "Teniente", - "Nemesis": "Némesis" - }, - "ACTOR.TypeVehicle": "Vehículo", - "ACTOR.Vehicle": { - "Passengers": "Pasajeros", - "Cover": "Cobertura", - "Impact": "Impacto" - }, - "ITEM.TypeArmor": "Armadura", - "ITEM.TypeTalent": "Talento", - "ITEM.TypeSpell": "Conjuro", - "ITEM.TypeSkill": "Habilidad", - "ITEM.TypeSkillkit": "Kit de Habilidades", - "ITEM.TypeEquipment": "Equipo", - "ITEM.TypeSpecial_rule": "Regla Especial", - "ITEM.TypeWeapon": "Arma" -} \ No newline at end of file diff --git a/system/src/app/momentum-tracker.mjs b/system/src/app/momentum-tracker.mjs index a698388..1053268 100644 --- a/system/src/app/momentum-tracker.mjs +++ b/system/src/app/momentum-tracker.mjs @@ -1,145 +1,153 @@ export class MomentumTracker extends Application { - constructor(options = {}) { - if (MomentumTracker._instance) { - throw new Error("MomentumTracker already has an instance!!!"); - } - super(options); - MomentumTracker._instance = this; - MomentumTracker.closed = true; - this.data = {}; - } - // override - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - title: "AP Tracker", - template: "systems/ac2d20/templates/ap/momentum-tracker.html", - classes: ["ac2d20", "momentum-tracker"], - id: "momentum-tracker-app", - popOut: false, - resizable: false, - width: "auto", - height: "200" - }); - } - // override - getData() { - super.getData(); - this.data["isGM"] = game.user.isGM; - this.data["partyMomentum"] = game.settings.get('ac2d20', 'partyMomentum'); - this.data["gmMomentum"] = game.settings.get('ac2d20', 'gmMomentum'); - this.data["maxMomentum"] = game.settings.get('ac2d20', 'maxMomentum'); - if(game.user.isGM) this.data["showGMMomentumToPlayers"] = true; - else this.data["showGMMomentumToPlayers"] = game.settings.get('ac2d20', 'gmMomentumShowToPlayers') - if(game.user.isGM) this.data["maxAppShowToPlayers"] = true; - else this.data["maxAppShowToPlayers"] = game.settings.get('ac2d20', 'maxAppShowToPlayers') - return this.data; - } - - static renderApTracker() { - if (MomentumTracker._instance) - MomentumTracker._instance.render(true); - } - - activateListeners(html) { - super.activateListeners(html); - - if (MomentumTracker.closed) { - html.find('.ap-resource.maxMomentum-box').css("display", "none"); - } - - html.find('.ap-input').change(ev => { - const type = $(ev.currentTarget).parents('.ap-resource').attr('data-type'); - const value = ev.target.value; - MomentumTracker.setAP(type, value); - }); - - html.find('.ap-add, .ap-sub').click(ev => { - const type = $(ev.currentTarget).parents('.ap-resource').attr('data-type'); - const change = $(ev.currentTarget).hasClass('ap-add') ? 1 : -1; - let currentValue = game.settings.get('ac2d20', type); - let maxMomentum = game.settings.get('ac2d20', 'maxMomentum'); - if (parseInt(currentValue) < maxMomentum || parseInt(currentValue) > 0) { - let newValue = parseInt(currentValue) + change; - MomentumTracker.setAP(type, newValue); - } - - }); - - html.find('.toggle-maxAp').click(ev => { - html.find('.ap-resource.maxMomentum-box').slideToggle("fast", function () { MomentumTracker.closed = !MomentumTracker.closed }); - }) - } - - static async adjustAP(type, diff) { - diff = Math.round(diff); - - if (!game.user.isGM) { - game.socket.emit('system.ac2d20', { - operation: 'adjustAP', - data: { diff, type }, - }); - return; - } - - let momentum = game.settings.get('ac2d20', type); - momentum += diff; - - this.setAP(type, momentum); - } - - static async setAP(type, value) { - value = Math.round(value); - if (!game.user.isGM) { - game.socket.emit('system.ac2d20', { - operation: 'setAP', - data: { 'value': value, 'type': type }, - }); - return; - } - - let maxMomentum = game.settings.get('ac2d20', 'maxMomentum'); - let partyMomentum = game.settings.get('ac2d20', 'partyMomentum'); - if (partyMomentum > value && type === 'maxMomentum') { - await game.settings.set('ac2d20', 'maxMomentum', value); - await game.settings.set('ac2d20', 'partyMomentum', value); - MomentumTracker.renderApTracker(); - game.socket.emit('system.ac2d20', { operation: 'updateAP' }); - return; - } - - if (value > maxMomentum && type === 'partyMomentum') { - await game.settings.set('ac2d20', type, maxMomentum); - MomentumTracker.renderApTracker(); - } else if (value < 0) { - await game.settings.set('ac2d20', type, 0); - MomentumTracker.renderApTracker(); - } else { - await game.settings.set('ac2d20', type, value); - MomentumTracker.renderApTracker(); - } - - // emit socket event for the players to update - game.socket.emit('system.ac2d20', { operation: 'updateAP' }); - } - - static updateAP() { - MomentumTracker.renderApTracker(); - } + constructor(options = {}) { + if (MomentumTracker._instance) { + throw new Error("MomentumTracker already has an instance!!!"); + } + super(options); + MomentumTracker._instance = this; + MomentumTracker.closed = true; + this.data = {}; + } + + // override + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + title: "AP Tracker", + template: "systems/ac2d20/templates/ap/momentum-tracker.hbs", + classes: ["ac2d20", "momentum-tracker"], + id: "momentum-tracker-app", + popOut: false, + resizable: false, + width: "auto", + height: "200", + }); + } + + // override + getData() { + super.getData(); + this.data.isGM = game.user.isGM; + this.data.partyMomentum = game.settings.get("ac2d20", "partyMomentum"); + this.data.gmMomentum = game.settings.get("ac2d20", "gmMomentum"); + this.data.maxMomentum = game.settings.get("ac2d20", "maxMomentum"); + if (game.user.isGM) this.data.showGMMomentumToPlayers = true; + else this.data.showGMMomentumToPlayers = game.settings.get("ac2d20", "gmMomentumShowToPlayers"); + if (game.user.isGM) this.data.maxAppShowToPlayers = true; + else this.data.maxAppShowToPlayers = game.settings.get("ac2d20", "maxAppShowToPlayers"); + return this.data; + } + + static renderApTracker() { + if (MomentumTracker._instance) MomentumTracker._instance.render(true); + } + + activateListeners(html) { + super.activateListeners(html); + + if (MomentumTracker.closed) { + html.find(".ap-resource.maxMomentum-box").css("display", "none"); + } + + html.find(".ap-input").change(ev => { + const type = $(ev.currentTarget).parents(".ap-resource").attr("data-type"); + const value = ev.target.value; + MomentumTracker.setAP(type, value); + }); + + html.find(".ap-add, .ap-sub").click(ev => { + const type = $(ev.currentTarget).parents(".ap-resource").attr("data-type"); + const change = $(ev.currentTarget).hasClass("ap-add") ? 1 : -1; + let currentValue = game.settings.get("ac2d20", type); + let maxMomentum = game.settings.get("ac2d20", "maxMomentum"); + if (parseInt(currentValue) < maxMomentum || parseInt(currentValue) > 0) { + let newValue = parseInt(currentValue) + change; + MomentumTracker.setAP(type, newValue); + } + + }); + + html.find(".toggle-maxAp").click(ev => { + html.find(".ap-resource.maxMomentum-box").slideToggle("fast", function() { + MomentumTracker.closed = !MomentumTracker.closed; + }); + }); + } + + static async adjustAP(type, diff) { + diff = Math.round(diff); + + if (!game.user.isGM) { + game.socket.emit("system.ac2d20", { + operation: "adjustAP", + data: { diff, type }, + }); + return; + } + + let momentum = game.settings.get("ac2d20", type); + momentum += diff; + + this.setAP(type, momentum); + } + + static async setAP(type, value) { + value = Math.round(value); + if (!game.user.isGM) { + game.socket.emit("system.ac2d20", { + operation: "setAP", + data: { value: value, type: type }, + }); + return; + } + + let maxMomentum = game.settings.get("ac2d20", "maxMomentum"); + let partyMomentum = game.settings.get("ac2d20", "partyMomentum"); + if (partyMomentum > value && type === "maxMomentum") { + await game.settings.set("ac2d20", "maxMomentum", value); + await game.settings.set("ac2d20", "partyMomentum", value); + MomentumTracker.renderApTracker(); + game.socket.emit("system.ac2d20", { operation: "updateAP" }); + return; + } + + if (value > maxMomentum && type === "partyMomentum") { + await game.settings.set("ac2d20", type, maxMomentum); + MomentumTracker.renderApTracker(); + } + else if (value < 0) { + await game.settings.set("ac2d20", type, 0); + MomentumTracker.renderApTracker(); + } + else { + await game.settings.set("ac2d20", type, value); + MomentumTracker.renderApTracker(); + } + + // emit socket event for the players to update + game.socket.emit("system.ac2d20", { operation: "updateAP" }); + } + + static updateAP() { + MomentumTracker.renderApTracker(); + } } Hooks.once("ready", () => { - if (MomentumTracker._instance) return; - let ap = new MomentumTracker(); - MomentumTracker.renderApTracker(); - game.socket.on("system.ac2d20", (ev) => { - if (ev.operation === "adjustAP") { - if (game.user.isGM) - MomentumTracker.adjustAP(ev.data.type, ev.data.diff); - } - if (ev.operation === "setAP") { - if (game.user.isGM) - MomentumTracker.setAP(ev.data.type, ev.data.value); - } - if (ev.operation === "updateAP") MomentumTracker.updateAP(); - }); + if (MomentumTracker._instance) return; + + new MomentumTracker(); + + MomentumTracker.renderApTracker(); + + game.socket.on("system.ac2d20", ev => { + if (ev.operation === "adjustAP") { + if (game.user.isGM) MomentumTracker.adjustAP(ev.data.type, ev.data.diff); + } + + if (ev.operation === "setAP") { + if (game.user.isGM) MomentumTracker.setAP(ev.data.type, ev.data.value); + } + + if (ev.operation === "updateAP") MomentumTracker.updateAP(); + }); }); diff --git a/system/src/combat/combat-tracker.mjs b/system/src/combat/combat-tracker.mjs index fdb1008..2f1fa82 100644 --- a/system/src/combat/combat-tracker.mjs +++ b/system/src/combat/combat-tracker.mjs @@ -1,82 +1,82 @@ export default class CombatTracker2d20 extends CombatTracker { - static get defaultOptions() { - return { - ...super.defaultOptions, - template: 'systems/ac2d20/templates/combat/combat-tracker.html', - }; - } - - activateListeners(html) { - const tracker = html.find('#combat-tracker'); - const combatants = tracker.find('.combatant'); - - html.find('.ac-combatant-control').click( - ev => this._onACCombatantControl(ev) - ); - - combatants.click(this._onACCombatantMouseDown.bind(this)); - - super.activateListeners(html); - } - - async getData(options) { - const context = await super.getData(options); - - const combat = this.viewed; - for (const turn of context.turns) { - const combatantsTurnDone = combat.combatantsTurnDone; - turn.turnDone = combatantsTurnDone[turn.id] ?? false; - } - - return context; - } - - async _onACCombatantControl(event) { - event.preventDefault(); - event.stopPropagation(); - - if (!game.user.isGM) return; - - if (!this.viewed.started) { - ui.notifications.warn( - game.i18n.localize('AC2D20.Combat.CombatHasNotStarted') - ); - return; - } - - const btn = event.currentTarget; - const li = btn.closest('.combatant'); - const combatant = this.viewed.combatants.get(li.dataset.combatantId); - - if (combatant.isOwner) { - this.viewed.toggleTurnDone(combatant.id); - } - } - - async _onACCombatantMouseDown(event) { - event.preventDefault(); - if (game.user.isGM && this.viewed.started) { - const li = event.currentTarget; - const combatantId = li.dataset.combatantId; - - const combat = this.viewed; - - const currentTurn = combat.turn ?? -1; - - let newTurn = currentTurn; - - for (let [i, turn] of combat.turns.entries()) { - if (turn.isDefeated) continue; - if (turn.id === combatantId) { - newTurn = i; - break; - } - } - - if (newTurn !== currentTurn) { - combat.setTurn(newTurn); - } - } - } + static get defaultOptions() { + return { + ...super.defaultOptions, + template: "systems/ac2d20/templates/combat/combat-tracker.hbs", + }; + } + + activateListeners(html) { + const tracker = html.find("#combat-tracker"); + const combatants = tracker.find(".combatant"); + + html.find(".ac-combatant-control").click( + ev => this._onACCombatantControl(ev) + ); + + combatants.click(this._onACCombatantMouseDown.bind(this)); + + super.activateListeners(html); + } + + async getData(options) { + const context = await super.getData(options); + + const combat = this.viewed; + for (const turn of context.turns) { + const combatantsTurnDone = combat.combatantsTurnDone; + turn.turnDone = combatantsTurnDone[turn.id] ?? false; + } + + return context; + } + + async _onACCombatantControl(event) { + event.preventDefault(); + event.stopPropagation(); + + if (!game.user.isGM) return; + + if (!this.viewed.started) { + ui.notifications.warn( + game.i18n.localize("AC2D20.Combat.CombatHasNotStarted") + ); + return; + } + + const btn = event.currentTarget; + const li = btn.closest(".combatant"); + const combatant = this.viewed.combatants.get(li.dataset.combatantId); + + if (combatant.isOwner) { + this.viewed.toggleTurnDone(combatant.id); + } + } + + async _onACCombatantMouseDown(event) { + event.preventDefault(); + if (game.user.isGM && this.viewed.started) { + const li = event.currentTarget; + const combatantId = li.dataset.combatantId; + + const combat = this.viewed; + + const currentTurn = combat.turn ?? -1; + + let newTurn = currentTurn; + + for (let [i, turn] of combat.turns.entries()) { + if (turn.isDefeated) continue; + if (turn.id === combatantId) { + newTurn = i; + break; + } + } + + if (newTurn !== currentTurn) { + combat.setTurn(newTurn); + } + } + } } diff --git a/system/src/combat/combat.mjs b/system/src/combat/combat.mjs index 4358141..b04881c 100644 --- a/system/src/combat/combat.mjs +++ b/system/src/combat/combat.mjs @@ -2,164 +2,164 @@ export default class Combat2d20 extends Combat { - constructor(options) { - super(options); - - this.flags.combatantsTurnDone = this.flags.combatantsTurnDone ?? []; - } - - get combatantsTurnDone() { - const combatantsTurnDone = this.flags.combatantsTurnDone ?? []; - return combatantsTurnDone[this.round] ?? {}; - } - - get momentumLog() { - const momentumLog = this.flags.momentumLog ?? []; - return momentumLog[this.round] ?? {}; - } - - get shouldUpdateMomentum() { - return game.settings.get( - 'ac2d20', 'combatTrackerMomentumUpdate' - ); - } - - async endCombat() { - return Dialog.confirm({ - title: game.i18n.localize('COMBAT.EndTitle'), - content: `

${game.i18n.localize('COMBAT.EndConfirmation')}

`, - yes: () => { - if (this.shouldUpdateMomentum && this.started) { - if (game.user.isGM) { - game.ac2d20.MomentumTracker.adjustAP('partyMomentum', -1); - } - else { - game.socket.emit('system.ac2d20', { - operation: 'adjustAP', - data: { diff: -1, type: 'partyMomentum' }, - }); - } - - ui.notifications.info( - game.i18n.localize('AC2D20.Combat.CombatEndMomentumPoolDecremented') - ); - } - this.delete(); - }, - }); - } - - async nextRound() { - this.turn = null; - - if (this.shouldUpdateMomentum) { - if (game.user.isGM) { - game.ac2d20.MomentumTracker.adjustAP('partyMomentum', -1); - } - else { - game.socket.emit('system.ac2d20', { - operation: 'adjustAP', - data: { diff: -1, type: 'partyMomentum' }, - }); - } - - ui.notifications.info( - game.i18n.localize('AC2D20.Combat.CombatRoundMomentumPoolDecremented') - ); - } - - let advanceTime = Math.max(this.turns.length - this.turn, 0) * CONFIG.time.turnTime; - advanceTime += CONFIG.time.roundTime; - let nextRound = this.round + 1; - - // Update the document, passing data through a hook first - const updateData = {round: nextRound, turn: this.turn}; - const updateOptions = {advanceTime, direction: 1}; - Hooks.callAll('combatRound', this, updateData, updateOptions); - return this.update(updateData, updateOptions); - } - - async rollInitiative() { - return this; - } - - async setTurn(newTurn) { - this.turn = newTurn; - - // Update the document, passing data through a hook first - const updateData = {round: this.round, turn: newTurn}; - const updateOptions = {advanceTime: CONFIG.time.turnTime, direction: 1}; - Hooks.callAll('combatTurn', this, updateData, updateOptions); - return this.update(updateData, updateOptions); - } - - setupTurns() { - // Determine the turn order and the current turn - const turns = this.combatants.contents; - - // Sort alphabetically by name first - turns.sort((a, b) => { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }); - - // Now sort by type - turns.sort((a, b) => { - const actorA = game.actors.get(a.actorId); - const actorB = game.actors.get(b.actorId); - - if (actorA.type < actorB.type) { - return -1; - } - if (actorA.type > actorB.type) { - return 1; - } - return 0; - }); - - if ( this.turn !== null) this.turn = Math.clamped(this.turn, 0, turns.length-1); - - // Update state tracking - let c = turns[this.turn]; - this.current = { - round: this.round, - turn: this.turn, - combatantId: c ? c.id : null, - tokenId: c ? c.tokenId : null, - }; - - // Return the array of prepared turns - return this.turns = turns; - } - - async startCombat() { - const updateData = { - round: 1, - turn: 0, - 'flags.combatantsTurnDone': [], - }; - - Hooks.callAll('combatStart', this, updateData); - - return this.update(updateData); - } - - async toggleTurnDone(combatantId) { - if (!game.user.isGM) return; - if (!this.started) return; - - const combatantsTurnDone = this.combatantsTurnDone; - - const turnDone = !(combatantsTurnDone[combatantId] ?? false); - combatantsTurnDone[combatantId] = turnDone; - - this.flags.combatantsTurnDone[this.round] = combatantsTurnDone; - - return this.update({'flags.combatantsTurnDone': this.flags.combatantsTurnDone}); - } + constructor(options) { + super(options); + + this.flags.combatantsTurnDone = this.flags.combatantsTurnDone ?? []; + } + + get combatantsTurnDone() { + const combatantsTurnDone = this.flags.combatantsTurnDone ?? []; + return combatantsTurnDone[this.round] ?? {}; + } + + get momentumLog() { + const momentumLog = this.flags.momentumLog ?? []; + return momentumLog[this.round] ?? {}; + } + + get shouldUpdateMomentum() { + return game.settings.get( + "ac2d20", "combatTrackerMomentumUpdate" + ); + } + + async endCombat() { + return Dialog.confirm({ + title: game.i18n.localize("COMBAT.EndTitle"), + content: `

${game.i18n.localize("COMBAT.EndConfirmation")}

`, + yes: () => { + if (this.shouldUpdateMomentum && this.started) { + if (game.user.isGM) { + game.ac2d20.MomentumTracker.adjustAP("partyMomentum", -1); + } + else { + game.socket.emit("system.ac2d20", { + operation: "adjustAP", + data: { diff: -1, type: "partyMomentum" }, + }); + } + + ui.notifications.info( + game.i18n.localize("AC2D20.Combat.CombatEndMomentumPoolDecremented") + ); + } + this.delete(); + }, + }); + } + + async nextRound() { + this.turn = null; + + if (this.shouldUpdateMomentum) { + if (game.user.isGM) { + game.ac2d20.MomentumTracker.adjustAP("partyMomentum", -1); + } + else { + game.socket.emit("system.ac2d20", { + operation: "adjustAP", + data: { diff: -1, type: "partyMomentum" }, + }); + } + + ui.notifications.info( + game.i18n.localize("AC2D20.Combat.CombatRoundMomentumPoolDecremented") + ); + } + + let advanceTime = Math.max(this.turns.length - this.turn, 0) * CONFIG.time.turnTime; + advanceTime += CONFIG.time.roundTime; + let nextRound = this.round + 1; + + // Update the document, passing data through a hook first + const updateData = {round: nextRound, turn: this.turn}; + const updateOptions = {advanceTime, direction: 1}; + Hooks.callAll("combatRound", this, updateData, updateOptions); + return this.update(updateData, updateOptions); + } + + async rollInitiative() { + return this; + } + + async setTurn(newTurn) { + this.turn = newTurn; + + // Update the document, passing data through a hook first + const updateData = {round: this.round, turn: newTurn}; + const updateOptions = {advanceTime: CONFIG.time.turnTime, direction: 1}; + Hooks.callAll("combatTurn", this, updateData, updateOptions); + return this.update(updateData, updateOptions); + } + + setupTurns() { + // Determine the turn order and the current turn + const turns = this.combatants.contents; + + // Sort alphabetically by name first + turns.sort((a, b) => { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + + // Now sort by type + turns.sort((a, b) => { + const actorA = game.actors.get(a.actorId); + const actorB = game.actors.get(b.actorId); + + if (actorA.type < actorB.type) { + return -1; + } + if (actorA.type > actorB.type) { + return 1; + } + return 0; + }); + + if ( this.turn !== null) this.turn = Math.clamped(this.turn, 0, turns.length-1); + + // Update state tracking + let c = turns[this.turn]; + this.current = { + round: this.round, + turn: this.turn, + combatantId: c ? c.id : null, + tokenId: c ? c.tokenId : null, + }; + + // Return the array of prepared turns + return this.turns = turns; + } + + async startCombat() { + const updateData = { + "round": 1, + "turn": 0, + "flags.combatantsTurnDone": [], + }; + + Hooks.callAll("combatStart", this, updateData); + + return this.update(updateData); + } + + async toggleTurnDone(combatantId) { + if (!game.user.isGM) return; + if (!this.started) return; + + const combatantsTurnDone = this.combatantsTurnDone; + + const turnDone = !(combatantsTurnDone[combatantId] ?? false); + combatantsTurnDone[combatantId] = turnDone; + + this.flags.combatantsTurnDone[this.round] = combatantsTurnDone; + + return this.update({"flags.combatantsTurnDone": this.flags.combatantsTurnDone}); + } } diff --git a/system/src/documents/actor.mjs b/system/src/documents/actor.mjs index 3469d4d..d954056 100644 --- a/system/src/documents/actor.mjs +++ b/system/src/documents/actor.mjs @@ -1,36 +1,43 @@ /** - * Extend the base Actor document by defining a custom roll data structure which is ideal for the Simple system. + * Extend the base Actor document by defining a custom roll data structure which + * is ideal for the Simple system. * @extends {Actor} */ export class ACActor extends Actor { - /** @override */ - prepareData() { - super.prepareData(); - } - - /** @override */ - prepareBaseData() { - // Data modifications in this step occur before processing embedded - // documents or derived data. - - // Carry capacity - let carryCapacity = 6; - if(this.system.attributes.bra.value < 9){ - carryCapacity = 6 - }else if(this.system.attributes.bra.value == 9){ - carryCapacity = 7 - } - else if(this.system.attributes.bra.value == 10 || this.system.attributes.bra.value == 11){ - carryCapacity = 8 - }else{ - carryCapacity = 9 - } - this.system.carryCapacity.value = parseInt(carryCapacity) - } - - /** + /** @override */ + prepareData() { + super.prepareData(); + } + + /** @override */ + prepareBaseData() { + // Data modifications in this step occur before processing embedded + // documents or derived data. + + // Carry capacity + const brawn = this.system.attributes.bra.value; + + let carryCapacity = 6; + + if (brawn < 9) { + carryCapacity = 6; + } + else if (brawn === 9) { + carryCapacity = 7; + } + else if (brawn === 10 || brawn === 11) { + carryCapacity = 8; + } + else if (brawn >= 12) { + carryCapacity = 9; + } + + this.system.carryCapacity.value = carryCapacity; + } + + /** * @override * Augment the basic actor data with additional dynamic data. Typically, * you'll want to handle most of your calculated/derived data in this step. @@ -39,108 +46,133 @@ export class ACActor extends Actor { * available both inside and outside of character sheets (such as if an actor * is queried and has a roll executed directly from it). */ - prepareDerivedData() { - // Make separate methods for each Actor type (character, npc, etc.) to keep - // things organized. - this._prepareCharacterData(this); - this._prepareNpcData(this); - } - - /** + prepareDerivedData() { + // Make separate methods for each Actor type (character, npc, etc.) to keep + // things organized. + this._prepareCharacterData(this); + this._prepareNpcData(this); + } + + /** * Prepare Character type specific data */ - _prepareCharacterData(actorData) { - if (this.type !== 'character') return; - } + _prepareCharacterData(actorData) { + // if (this.type !== "character") return; + } - /** + /** * Prepare NPC type specific data. */ - _prepareNpcData(actorData) { - if (this.type !== 'npc') return; - } + _prepareNpcData(actorData) { + // if (this.type !== "npc") return; + } - /** + /** * Override getRollData() that's supplied to rolls. */ - getRollData() { - const data = super.getRollData(); - // Prepare character roll data. - this._getCharacterRollData(data); - this._getNpcRollData(data); - return data; - } - - /** + getRollData() { + const data = super.getRollData(); + // Prepare character roll data. + this._getCharacterRollData(data); + this._getNpcRollData(data); + return data; + } + + /** * Prepare character roll data. */ - _getCharacterRollData(data) { - if (this.type !== 'character') return; - // Copy the ability scores to the top level, so that rolls can use - // formulas like `@bra.value + 4`. - if (data.attributes) { - for (let [k, v] of Object.entries(data.attributes)) { - data[k] = foundry.utils.deepClone(v); - } - } - } - - getComplicationFromInjuries() { - const injuries = [this.system.injuries.injury0, this.system.injuries.injury1, this.system.injuries.injury2] - let inj = injuries.filter((_i) => { - return (_i.text != "" && !_i.treated) - }) - return inj.length; - } - - /** + _getCharacterRollData(data) { + if (this.type !== "character") return; + // Copy the ability scores to the top level, so that rolls can use + // formulas like `@bra.value + 4`. + if (data.attributes) { + for (let [k, v] of Object.entries(data.attributes)) { + data[k] = foundry.utils.deepClone(v); + } + } + } + + getComplicationFromInjuries() { + const injuries = [ + this.system.injuries.injury0, + this.system.injuries.injury1, + this.system.injuries.injury2, + ]; + + let inj = injuries.filter(_i => { + return (_i.text !== "" && !_i.treated); + }); + + return inj.length; + } + + /** * Prepare NPC roll data. */ - _getNpcRollData(data) { - if (this.type !== 'npc') return; - // Process additional NPC data here. - } - - async _preCreate(data, options, user) { - await super._preCreate(data, options, user); - // set icon based on actor type - if(data.img == undefined){ - let ico = `systems/ac2d20/assets/doc-icons/${this.type}.svg`; - this.updateSource({ 'img': ico }); - } - // Setup Tokens - if (this.type === 'character') { - this.prototypeToken.updateSource({ actorLink: true, sight: { enabled: true }, disposition: 1 }) - } - if (this.type === 'npc') { - this.prototypeToken.updateSource({ sight: { enabled: true }, disposition: -1 }) - } - if (this.type === 'vehicle') { - this.prototypeToken.updateSource({ sight: { enabled: true }, disposition: 0 }) - } - // Add Skills to Characters - if (this.type === 'character') { - const packName = game.settings.get('ac2d20', 'compendium-skills'); - if(!packName) - packName = "ac2d20.skills" - - let packSkills = await game.packs.get(packName).getDocuments(); - const items = this.items.map(i => i.toObject()); - packSkills.forEach(s => { - items.push(s.toObject()); - }); - this.updateSource({ items }); - } - } - - getRollShortcuts() { - let out = {}; - // Attributes - for (const name of ["bra", "agi", "coo", "rea", "ins", "wil"]) { - out[name.substring(0, 3)] = this.system.attributes[name].value; - } - // Power - out['pow'] = this.system.power.value; - return out; - } -} \ No newline at end of file + _getNpcRollData(data) { + // if (this.type !== "npc") return; + // Process additional NPC data here. + } + + async _preCreate(data, options, user) { + await super._preCreate(data, options, user); + // set icon based on actor type + if (data.img === undefined) { + let ico = `systems/ac2d20/assets/doc-icons/${this.type}.svg`; + this.updateSource({ img: ico }); + } + // Setup Tokens + if (this.type === "character") { + this.prototypeToken.updateSource({ + actorLink: true, + sight: { + enabled: true, + }, + disposition: 1, + }); + } + if (this.type === "npc") { + this.prototypeToken.updateSource({ sight: { enabled: true }, disposition: -1 }); + } + if (this.type === "vehicle") { + this.prototypeToken.updateSource({ sight: { enabled: true }, disposition: 0 }); + } + // Add Skills to Characters + if (this.type === "character") { + // If the Actor data already contains skill items then this is an + // Actor being duplicated and we don't want to touch their + // items at all + // + const alreadyHasSkills = Array.isArray(data.items) + && data.items.filter(i => i.type === "skill").length > 0; + + if (!alreadyHasSkills) { + let skillsCompendium = game.settings.get("ac2d20", "compendium-skills"); + + if (!skillsCompendium) skillsCompendium = "ac2d20.skills"; + + let packSkills = + await game.packs.get(skillsCompendium).getDocuments(); + + const items = this.items.map(i => i.toObject()); + + packSkills.forEach(s => { + items.push(s.toObject()); + }); + + this.updateSource({ items }); + } + } + } + + getRollShortcuts() { + let out = {}; + // Attributes + for (const name of ["bra", "agi", "coo", "rea", "ins", "wil"]) { + out[name.substring(0, 3)] = this.system.attributes[name].value; + } + // Power + out.pow = this.system.power.value; + return out; + } +} diff --git a/system/src/documents/item.mjs b/system/src/documents/item.mjs index b0c01fb..da1cf92 100644 --- a/system/src/documents/item.mjs +++ b/system/src/documents/item.mjs @@ -3,114 +3,118 @@ * @extends {Item} */ export class ACItem extends Item { - - /** @override */ - prepareData() { - super.prepareData(); - } - async _preCreate(data, options, user) { - await super._preCreate(data, options, user); - if(data.img==undefined){ - let ico = `systems/ac2d20/assets/doc-icons/${data.type}.svg`; - this.updateSource({ 'img': ico }); - } - } + /** @override */ + prepareData() { + super.prepareData(); + } - /** - * Prepare a data object which is passed to any Roll formulas which are created related to this Item + async _preCreate(data, options, user) { + await super._preCreate(data, options, user); + if (data.img === undefined) { + let ico = `systems/ac2d20/assets/doc-icons/${data.type}.svg`; + this.updateSource({ img: ico }); + } + } + + /** + * Prepare a data object which is passed to any Roll formulas which are + * created related to this Item * @private */ - getRollData() { - // If present, return the actor's roll data. - if (!this.actor) return null; - const rollData = this.actor.getRollData(); - rollData.item = foundry.utils.deepClone(this.system); + getRollData() { + // If present, return the actor's roll data. + if (!this.actor) return null; + const rollData = this.actor.getRollData(); + rollData.item = foundry.utils.deepClone(this.system); + + return rollData; + } + + // FOCUS + async addFocus() { + let focuses = this.system.focuses; + const focus = { title: "", isfocus: false, description: "" }; + focuses = [...focuses, focus]; + let updatedItem = { "_id": this.id, "system.focuses": focuses }; + await this.update(updatedItem); + } + + async deleteFocus(_index) { + let focuses = this.system.focuses; + focuses.splice(_index, 1); + let updatedItem = { "_id": this.id, "system.focuses": focuses }; + await this.update(updatedItem); + } - return rollData; - } + async updateFocuses(_focuses) { + let updatedItem = { "_id": this.id, "system.focuses": _focuses }; + await this.update(updatedItem); + } - // FOCUS - async addFocus() { - let focuses = this.system.focuses; - const focus = { title: '', isfocus: false, description: '' } - focuses = [...focuses, focus]; - let updatedItem = { _id: this.id, "system.focuses": focuses }; - await this.update(updatedItem); - } - async deleteFocus(_index) { - let focuses = this.system.focuses; - focuses.splice(_index, 1); - let updatedItem = { _id: this.id, "system.focuses": focuses } ; - await this.update(updatedItem); - } - async updateFocuses(_focuses) { - let updatedItem = { _id: this.id, "system.focuses": _focuses }; - await this.update(updatedItem); - } - /** + /** * Handle clickable rolls. * @param {Event} event The originating click event * @private */ - async roll() { - // Initialize chat data - const speaker = ChatMessage.getSpeaker({ actor: this.actor }); - const rollMode = game.settings.get('core', 'rollMode'); - const label = `[${this.type}] ${this.name}`; + async roll() { + // Initialize chat data + const speaker = ChatMessage.getSpeaker({ actor: this.actor }); + const rollMode = game.settings.get("core", "rollMode"); + const label = `[${this.type}] ${this.name}`; - // If there's no roll data, send a chat message. - if (!this.system.formula) { - ChatMessage.create({ - speaker: speaker, - rollMode: rollMode, - flavor: label, - content: this.system.description ?? '' - }); - } - // Otherwise, create a roll and send a chat message from it. - else { - // Retrieve roll data. - const rollData = this.getRollData(); + // If there's no roll data, send a chat message. + if (!this.system.formula) { + ChatMessage.create({ + speaker: speaker, + rollMode: rollMode, + flavor: label, + content: this.system.description ?? "", + }); + } + // Otherwise, create a roll and send a chat message from it. + else { + // Retrieve roll data. + const rollData = this.getRollData(); - // Invoke the roll and submit it to chat. - const roll = new Roll(rollData.item.formula, rollData).roll(); - roll.toMessage({ - speaker: speaker, - rollMode: rollMode, - flavor: label, - }); - return roll; - } - } + // Invoke the roll and submit it to chat. + const roll = new Roll(rollData.item.formula, rollData).roll(); + roll.toMessage({ + speaker: speaker, + rollMode: rollMode, + flavor: label, + }); + return roll; + } + } - async sendToChat() { - const itemData = duplicate(this.system); - itemData._id = this._id; - itemData.img = this.img; - itemData.name = this.name; - itemData.type = this.type; - itemData.isPhysical = this.system.hasOwnProperty('weight') - itemData.isWeapon = this.type === "weapon"; - itemData.isArmor = this.type === "armor"; - itemData.isTalent = this.type === "talent"; - itemData.isSpell = this.type === "spell"; - itemData.isSkillkit = this.type === "skillkit"; - itemData.isSkillkit = this.type === "skillkit"; - itemData.isEquipment = this.type === "equipment"; - itemData.isSpecial_rule = this.type === "special_rule"; - itemData.isSkill = this.type === "skill"; - const html = await renderTemplate("systems/ac2d20/templates/chat/item.html", itemData); - const chatData = { - user: game.user.id, - rollMode: game.settings.get("core", "rollMode"), - content: html, - }; - if (["gmroll", "blindroll"].includes(chatData.rollMode)) { - chatData.whisper = ChatMessage.getWhisperRecipients("GM"); - } else if (chatData.rollMode === "selfroll") { - chatData.whisper = [game.user]; - } - ChatMessage.create(chatData); - } + async sendToChat() { + const itemData = duplicate(this.system); + itemData._id = this._id; + itemData.img = this.img; + itemData.name = this.name; + itemData.type = this.type; + itemData.isPhysical = this.system.hasOwnProperty("weight"); + itemData.isWeapon = this.type === "weapon"; + itemData.isArmor = this.type === "armor"; + itemData.isTalent = this.type === "talent"; + itemData.isSpell = this.type === "spell"; + itemData.isSkillkit = this.type === "skillkit"; + itemData.isEquipment = this.type === "equipment"; + itemData.isSpecial_rule = this.type === "special_rule"; + itemData.isSkill = this.type === "skill"; + const html = await renderTemplate("systems/ac2d20/templates/chat/item.hbs", itemData); + const chatData = { + user: game.user.id, + rollMode: game.settings.get("core", "rollMode"), + content: html, + }; + if (["gmroll", "blindroll"].includes(chatData.rollMode)) { + chatData.whisper = ChatMessage.getWhisperRecipients("GM"); + } + else if (chatData.rollMode === "selfroll") { + chatData.whisper = [game.user]; + } + ChatMessage.create(chatData); + } } diff --git a/system/src/enrichers.mjs b/system/src/enrichers.mjs index fe58db9..516e21c 100644 --- a/system/src/enrichers.mjs +++ b/system/src/enrichers.mjs @@ -4,12 +4,12 @@ export function registerEnrichers() { { pattern: /@(s(tress)?|c(hallenge)?)/gim, enricher: async (match, options) => { - const i = document.createElement('i'); - i.className = 'cthl-cthulhu'; + const i = document.createElement("i"); + i.className = "cthl-cthulhu"; // Adjust positioning slightly to align better with text. - i.style.position = 'relative'; - i.style.top = '0.2em'; + i.style.position = "relative"; + i.style.top = "0.2em"; return i; }, @@ -17,15 +17,15 @@ export function registerEnrichers() { { pattern: /@(x(ross)?)/gim, enricher: async (match, options) => { - const i = document.createElement('i'); - i.className = 'cth-ico-cth-cross'; + const i = document.createElement("i"); + i.className = "cth-ico-cth-cross"; // Adjust positioning slightly to align better with text. - i.style.position = 'relative'; - i.style.top = '0.1em'; + i.style.position = "relative"; + i.style.top = "0.1em"; return i; }, - } + }, ]; -} \ No newline at end of file +} diff --git a/system/src/helpers/config.mjs b/system/src/helpers/config.mjs index ed0e527..1c2c3fd 100644 --- a/system/src/helpers/config.mjs +++ b/system/src/helpers/config.mjs @@ -1,119 +1,53 @@ export const AC2D20 = {}; AC2D20.attributes = { - "agi": "AC2D20.AbilityAgi", - "bra": "AC2D20.AbilityBra", - "coo": "AC2D20.AbilityCoo", - "ins": "AC2D20.AbilityIns", - "rea": "AC2D20.AbilityRea", - "wil": "AC2D20.AbilityWil", + agi: "AC2D20.AbilityAgi", + bra: "AC2D20.AbilityBra", + coo: "AC2D20.AbilityCoo", + ins: "AC2D20.AbilityIns", + rea: "AC2D20.AbilityRea", + wil: "AC2D20.AbilityWil", }; AC2D20.abilityAbbreviations = { - "agi": "AC2D20.AbilityAgiAbr", - "bra": "AC2D20.AbilityBraAbr", - "coo": "AC2D20.AbilityCooAbr", - "ins": "AC2D20.AbilityInsAbr", - "rea": "AC2D20.AbilityReaAbr", - "wil": "AC2D20.AbilityWilAbr", + agi: "AC2D20.AbilityAgiAbr", + bra: "AC2D20.AbilityBraAbr", + coo: "AC2D20.AbilityCooAbr", + ins: "AC2D20.AbilityInsAbr", + rea: "AC2D20.AbilityReaAbr", + wil: "AC2D20.AbilityWilAbr", }; -// Depricated. This is now created from the skill compendium -// AC2D20.SKILLS = [ -// { -// 'label': 'ACADEMIA', -// 'key': "Academia", -// 'focuses': ['Art', 'Cryptography', 'Finance', 'History', 'Linguistics', 'Occultism', 'Science'] -// }, -// { -// 'label': 'ATHLETICS', -// 'key': "Athletics", -// 'focuses': ['Climbing', 'Lifting', 'Physical Training', 'Running', 'Swimming', 'Throwing'] -// }, -// { -// 'label': 'ENGINEERING', -// 'key': "Engineering", -// 'focuses': ['Architecture', 'Combat Engineering', 'Electronics', 'Explosives', 'Mechanical Engineering'] -// }, -// { -// 'label': 'FIGHTING', -// 'key': "Fighting", -// 'focuses': ['Close Quarters', 'Handguns', 'Hand-to-Hand', 'Heavy Weapons', 'Melee Weapons', 'Rifles', -// 'Threat Awareness', 'Exotic'] -// }, -// { -// 'label': 'MEDICINE', -// 'key': "Medicine", -// 'focuses': ['First Aid', 'Infectious Diseases', 'Pharmacology', 'Psychiatry', 'Surgery', 'Toxicology'] -// }, -// { -// 'label': 'OBSERVATION', -// 'key': "Observation", -// 'focuses': ['Hearing', 'Instincts', 'Sight', 'Smell and Taste'] -// }, -// { -// 'label': 'PERSUASION', -// 'key': "Persuasion", -// 'focuses': ['Charm', 'Innuendo', 'Intimidation', 'Negotiation', 'Rhetoric', 'Deceive', 'Invocation'] -// }, -// { -// 'label': 'RESILIENCE', -// 'key': "Resilience", -// 'focuses': ['Fortitude', 'Discipline', 'Immunity'] -// }, -// { -// 'label': 'STEALTH', -// 'key': "Stealth", -// 'focuses': ['Camouflage', 'Disguise', 'Rural Stealth', 'Urban Stealth'] -// }, -// { -// 'label': 'SURVIVAL', -// 'key': "Survival", -// 'focuses': ['Animal Handling', 'Foraging', 'Hunting', 'Mysticism', 'Orienteering', 'Tracking'] -// }, -// { -// 'label': 'TACTICS', -// 'key': "Tactics", -// 'focuses': ['Air Force', 'Army', 'Covert Operations', 'Leadership', 'Navy', 'Technical Projects'] -// }, -// { -// 'label': 'VEHICLES', -// 'key': "Vehicles", -// 'focuses': ['Cars', 'Motorcycles', 'Heavy Vehicles', 'Tanks', 'Aircraft', 'Watercraft'] -// } -// ]; - AC2D20.Size = ["Trivial", "Minor", "Major"]; AC2D20.WEAPONS = { - "range": { - "reach": "AC2D20.RANGE.reach", - "close": "AC2D20.RANGE.close", - "medium": "AC2D20.RANGE.medium", - "long": "AC2D20.RANGE.long", - "extreme": "AC2D20.RANGE.extreme" - }, - "weaponTypes": [ - { - 'label': "Melee", - 'bonusAttribute': 'agi' - }, - { - 'label': "Ranged", - 'bonusAttribute': 'coo' - }, - { - 'label': "Mental", - 'bonusAttribute': 'wil' - } - ] -} + range: { + reach: "AC2D20.RANGE.reach", + close: "AC2D20.RANGE.close", + medium: "AC2D20.RANGE.medium", + long: "AC2D20.RANGE.long", + extreme: "AC2D20.RANGE.extreme", + }, + weaponTypes: [ + { + label: "Melee", + bonusAttribute: "agi", + }, + { + label: "Ranged", + bonusAttribute: "coo", + }, + { + label: "Mental", + bonusAttribute: "wil", + }, + ], +}; AC2D20.spellcastingTypes = { - "traditional":"traditional", - "researcher":"researcher", - "dabbler":"dabbler" -} - + traditional: "traditional", + researcher: "researcher", + dabbler: "dabbler", +}; diff --git a/system/src/helpers/effects.mjs b/system/src/helpers/effects.mjs index ae677fa..806d1b7 100644 --- a/system/src/helpers/effects.mjs +++ b/system/src/helpers/effects.mjs @@ -3,27 +3,27 @@ * @param {MouseEvent} event The left-click event on the effect control * @param {Actor|Item} owner The owning entity which manages this effect */ - export function onManageActiveEffect(event, owner) { - event.preventDefault(); - const a = event.currentTarget; - const li = a.closest("li"); - const effect = li.dataset.effectId ? owner.effects.get(li.dataset.effectId) : null; - switch ( a.dataset.action ) { - case "create": - return owner.createEmbeddedDocuments("ActiveEffect", [{ - label: "New Effect", - icon: "icons/svg/aura.svg", - origin: owner.uuid, - "duration.rounds": li.dataset.effectType === "temporary" ? 1 : undefined, - disabled: li.dataset.effectType === "inactive" - }]); - case "edit": - return effect.sheet.render(true); - case "delete": - return effect.delete(); - case "toggle": - return effect.update({disabled: !effect.data.disabled}); - } +export function onManageActiveEffect(event, owner) { + event.preventDefault(); + const a = event.currentTarget; + const li = a.closest("li"); + const effect = li.dataset.effectId ? owner.effects.get(li.dataset.effectId) : null; + switch ( a.dataset.action ) { + case "create": + return owner.createEmbeddedDocuments("ActiveEffect", [{ + "label": "New Effect", + "icon": "icons/svg/aura.svg", + "origin": owner.uuid, + "duration.rounds": li.dataset.effectType === "temporary" ? 1 : undefined, + "disabled": li.dataset.effectType === "inactive", + }]); + case "edit": + return effect.sheet.render(true); + case "delete": + return effect.delete(); + case "toggle": + return effect.update({disabled: !effect.data.disabled}); + } } /** @@ -33,31 +33,31 @@ */ export function prepareActiveEffectCategories(effects) { - // Define effect header categories - const categories = { - temporary: { - type: "temporary", - label: "Temporary Effects", - effects: [] - }, - passive: { - type: "passive", - label: "Passive Effects", - effects: [] - }, - inactive: { - type: "inactive", - label: "Inactive Effects", - effects: [] - } - }; + // Define effect header categories + const categories = { + temporary: { + type: "temporary", + label: "Temporary Effects", + effects: [], + }, + passive: { + type: "passive", + label: "Passive Effects", + effects: [], + }, + inactive: { + type: "inactive", + label: "Inactive Effects", + effects: [], + }, + }; - // Iterate over active effects, classifying them into categories - for ( let e of effects ) { - e._getSourceName(); // Trigger a lookup for the source name - if ( e.data.disabled ) categories.inactive.effects.push(e); - else if ( e.isTemporary ) categories.temporary.effects.push(e); - else categories.passive.effects.push(e); - } - return categories; -} \ No newline at end of file + // Iterate over active effects, classifying them into categories + for ( let e of effects ) { + e._getSourceName(); // Trigger a lookup for the source name + if ( e.data.disabled ) categories.inactive.effects.push(e); + else if ( e.isTemporary ) categories.temporary.effects.push(e); + else categories.passive.effects.push(e); + } + return categories; +} diff --git a/system/src/helpers/handlebars.mjs b/system/src/helpers/handlebars.mjs index 36f7d26..6336e34 100644 --- a/system/src/helpers/handlebars.mjs +++ b/system/src/helpers/handlebars.mjs @@ -1,210 +1,199 @@ -export const registerHandlebarsHelpers = function () { - - /* -------------------------------------------- */ - /* GENERAL HELPERS */ - /* -------------------------------------------- */ - Handlebars.registerHelper('concat', function () { - var outStr = ''; - for (var arg in arguments) { - if (typeof arguments[arg] != 'object') { - outStr += arguments[arg]; - } - } - return outStr; - }); - - Handlebars.registerHelper('toLowerCase', function (str) { - return str.toLowerCase(); - }); - - Handlebars.registerHelper('toUpperCase', function (str) { - return str.toUpperCase(); - }); - - Handlebars.registerHelper('subString', function (str, s, e) { - return str.substring(s, e); - }); - - Handlebars.registerHelper("ifCond", function (v1, operator, v2, options) { - switch (operator) { - case "==": - return v1 == v2 ? options.fn(this) : options.inverse(this); - case "===": - return v1 === v2 ? options.fn(this) : options.inverse(this); - case "!=": - return v1 != v2 ? options.fn(this) : options.inverse(this); - case "!==": - return v1 !== v2 ? options.fn(this) : options.inverse(this); - case "<": - return v1 < v2 ? options.fn(this) : options.inverse(this); - case "<=": - return v1 <= v2 ? options.fn(this) : options.inverse(this); - case ">": - return v1 > v2 ? options.fn(this) : options.inverse(this); - case ">=": - return v1 >= v2 ? options.fn(this) : options.inverse(this); - case "&&": - return v1 && v2 ? options.fn(this) : options.inverse(this); - case "||": - return v1 || v2 ? options.fn(this) : options.inverse(this); - default: - return options.inverse(this); - } - }); - - Handlebars.registerHelper("math", function (lvalue, operator, rvalue, options) { - lvalue = parseFloat(lvalue); - rvalue = parseFloat(rvalue); - return { - "+": lvalue + rvalue, - "-": lvalue - rvalue, - "*": lvalue * rvalue, - "/": lvalue / rvalue, - "%": lvalue % rvalue - }[operator]; - }); - - /* -------------------------------------------- */ - /* AC2D20 HELPERS */ - /* -------------------------------------------- */ - - Handlebars.registerHelper('damageFaIconClass', function (str) { - if (str == "physical") - return "fas fa-fist-raised"; - else if (str == "energy") - return "fas fa-bolt"; - else if (str == "radiation") - return "fas fa-radiation"; - else if (str == "poison") - return "fas fa-biohazard"; - }); - - Handlebars.registerHelper('getSkillFocusList', function (key) { - if(key=="") - return []; - const _skill = CONFIG.AC2D20.SKILLS.filter((s) => s.key === key) - return _skill[0].focuses; - }); - - Handlebars.registerHelper('getWeaponEffects', function (effect) { - let effects = []; - Object.entries(effect).forEach(([k, v]) => { - let effString = ''; - let tooltip = '' - if (v.value) { - let tstr = 'AC2D20.WEAPONS.effects.'+ k; - tooltip = Handlebars.helpers.getTooltipFromConfigKey(tstr) - effString += `${v.label}`; - if (v.rank) { - effString += ` ${v.rank}`; - } - effString += `` - effects.push(effString) - } - }) - return effects.join(', ') - }); - - Handlebars.registerHelper('getWeaponQualities', function (qualities) { - let _qualities = []; - Object.entries(qualities).forEach(([k, v]) => { - let quString = ''; - let tooltip = '' - if (v.value) { - let tstr = 'AC2D20.WEAPONS.qualities.'+ k; - tooltip = Handlebars.helpers.getTooltipFromConfigKey(tstr) - quString += `${v.label}`; - _qualities.push(quString) - } - }) - return _qualities.join(', ') - }); - - Handlebars.registerHelper('isCreaturesWeapon', function (weapon) { - if (weapon.system.weaponType == "creatureAttack" || weapon.actor?.type == "creature") - return true; - else - return false; - }); - - Handlebars.registerHelper('isWeaponUsingMeleeBonus', function (weapon, actor) { - if ((weapon.weaponType == "unarmed" || weapon.weaponType == "meleeWeapons") && actor?.type != "creature") - return true; - else - return false; - }); - - Handlebars.registerHelper('hasInjury', function (txt) { - if (txt.length > 0) - return true; - else - return false; - }); - - Handlebars.registerHelper('getAttributeBonus', function (actor, weaponType) { - if (weaponType == 'agi') - return actor.system.attributes['bra'].bonus; - else if (weaponType == 'coo') - return actor.system.attributes['ins'].bonus; - else if (weaponType == 'wil') - return actor.system.attributes['wil'].bonus; - }); - - Handlebars.registerHelper('getArmorQualities', function (qualities) { - let qual = Object.entries(qualities).filter(([k, v]) => v.value).map(m => m[0]); - return qual; - }); - - Handlebars.registerHelper('getSizeLabel', function (num) { - if (num == 0) - return 'Trivial' - else if (num == 1) - return 'Minor' - else if (num == 3) - return 'Major' - else - return '-' - }); - - - Handlebars.registerHelper('clearTextAreaText', function (txt) { - txt.trim(); - txt = txt.replace(/ +/g, ' '); - //! replace new lines with encided \n so stupid textarea doesn't break - txt = txt.replace(/(?:\r\n|\r|\n)/g, ' '); - return txt; - }); - - // FOR TIMES LOOP - Handlebars.registerHelper('times', function (n, block) { - var accum = ''; - for (var i = 0; i < n; ++i) - accum += block.fn(i); - return accum; - }); - - // * Use with #if - // {{#if (or - // (eq section1 "foo") - //(ne section2 "bar"))}} - //.. content - //{{/if}} - Handlebars.registerHelper({ - eq: (v1, v2) => v1 === v2, - ne: (v1, v2) => v1 !== v2, - lt: (v1, v2) => v1 < v2, - gt: (v1, v2) => v1 > v2, - lte: (v1, v2) => v1 <= v2, - gte: (v1, v2) => v1 >= v2, - and() { - return Array.prototype.every.call(arguments, Boolean); - }, - or() { - return Array.prototype.slice.call(arguments, 0, -1).some(Boolean); - } - }); - - Handlebars.registerHelper('getTooltipFromConfigKey', function (key) { - return key.split('.').reduce((o,i)=> o[i], CONFIG) - }) -} \ No newline at end of file +export const registerHandlebarsHelpers = function() { + + /* -------------------------------------------- */ + /* GENERAL HELPERS */ + /* -------------------------------------------- */ + Handlebars.registerHelper("concat", function() { + let outStr = ""; + for (let arg in arguments) { + if (typeof arguments[arg] != "object") { + outStr += arguments[arg]; + } + } + return outStr; + }); + + Handlebars.registerHelper("toLowerCase", function(str) { + return str.toLowerCase(); + }); + + Handlebars.registerHelper("toUpperCase", function(str) { + return str.toUpperCase(); + }); + + Handlebars.registerHelper("subString", function(str, s, e) { + return str.substring(s, e); + }); + + Handlebars.registerHelper("ifCond", function(v1, operator, v2, options) { + switch (operator) { + case "==": + // eslint-disable-next-line eqeqeq + return v1 == v2 ? options.fn(this) : options.inverse(this); + case "===": + return v1 === v2 ? options.fn(this) : options.inverse(this); + case "!=": + // eslint-disable-next-line eqeqeq + return v1 != v2 ? options.fn(this) : options.inverse(this); + case "!==": + return v1 !== v2 ? options.fn(this) : options.inverse(this); + case "<": + return v1 < v2 ? options.fn(this) : options.inverse(this); + case "<=": + return v1 <= v2 ? options.fn(this) : options.inverse(this); + case ">": + return v1 > v2 ? options.fn(this) : options.inverse(this); + case ">=": + return v1 >= v2 ? options.fn(this) : options.inverse(this); + case "&&": + return v1 && v2 ? options.fn(this) : options.inverse(this); + case "||": + return v1 || v2 ? options.fn(this) : options.inverse(this); + default: + return options.inverse(this); + } + }); + + Handlebars.registerHelper("math", function(lvalue, operator, rvalue, options) { + lvalue = parseFloat(lvalue); + rvalue = parseFloat(rvalue); + return { + "+": lvalue + rvalue, + "-": lvalue - rvalue, + "*": lvalue * rvalue, + "/": lvalue / rvalue, + "%": lvalue % rvalue, + }[operator]; + }); + + /* -------------------------------------------- */ + /* AC2D20 HELPERS */ + /* -------------------------------------------- */ + + Handlebars.registerHelper("damageFaIconClass", function(str) { + if (str === "physical") return "fas fa-fist-raised"; + else if (str === "energy") return "fas fa-bolt"; + else if (str === "radiation") return "fas fa-radiation"; + else if (str === "poison") return "fas fa-biohazard"; + }); + + Handlebars.registerHelper("getSkillFocusList", function(key) { + if (key === "") return []; + const _skill = CONFIG.AC2D20.SKILLS.filter(s => s.key === key); + return _skill[0].focuses; + }); + + Handlebars.registerHelper("getWeaponEffects", function(effect) { + let effects = []; + Object.entries(effect).forEach(([k, v]) => { + let effString = ""; + let tooltip = ""; + if (v.value) { + let tstr = `AC2D20.WEAPONS.effects.${k}`; + tooltip = Handlebars.helpers.getTooltipFromConfigKey(tstr); + effString += `${v.label}`; + if (v.rank) { + effString += ` ${v.rank}`; + } + effString += ""; + effects.push(effString); + } + }); + return effects.join(", "); + }); + + Handlebars.registerHelper("getWeaponQualities", function(qualities) { + let _qualities = []; + Object.entries(qualities).forEach(([k, v]) => { + let quString = ""; + let tooltip = ""; + if (v.value) { + let tstr = `AC2D20.WEAPONS.qualities.${k}`; + tooltip = Handlebars.helpers.getTooltipFromConfigKey(tstr); + quString += `${v.label}`; + _qualities.push(quString); + } + }); + return _qualities.join(", "); + }); + + Handlebars.registerHelper("isCreaturesWeapon", function(weapon) { + if (weapon.system.weaponType === "creatureAttack" || weapon.actor?.type === "creature") return true; + else return false; + }); + + Handlebars.registerHelper("isWeaponUsingMeleeBonus", function(weapon, actor) { + if ((weapon.weaponType === "unarmed" || weapon.weaponType === "meleeWeapons") && actor?.type !== "creature") return true; + else return false; + }); + + Handlebars.registerHelper("hasInjury", function(txt) { + if (txt.length > 0) return true; + else return false; + }); + + Handlebars.registerHelper("getAttributeBonus", function(actor, weaponType) { + if (weaponType === "agi") return actor.system.attributes.bra.bonus; + else if (weaponType === "coo") return actor.system.attributes.ins.bonus; + else if (weaponType === "wil") return actor.system.attributes.wil.bonus; + }); + + Handlebars.registerHelper("getArmorQualities", function(qualities) { + let qual = Object.entries(qualities).filter(([k, v]) => v.value).map(m => m[0]); + return qual; + }); + + Handlebars.registerHelper("getSizeLabel", function(num) { + switch (parseInt(num) ?? null) { + case 0: + return "Trivial"; + case 1: + return "Minor"; + case 3: + return "Major"; + default: + return "-"; + } + }); + + + Handlebars.registerHelper("clearTextAreaText", function(txt) { + txt.trim(); + txt = txt.replace(/ +/g, " "); + // ! replace new lines with encided \n so stupid textarea doesn't break + txt = txt.replace(/(?:\r\n|\r|\n)/g, " "); + return txt; + }); + + // FOR TIMES LOOP + Handlebars.registerHelper("times", function(n, block) { + let accum = ""; + for (let i = 0; i < n; ++i) accum += block.fn(i); + return accum; + }); + + // * Use with #if + // {{#if (or + // (eq section1 "foo") + // (ne section2 "bar"))}} + // .. content + // {{/if}} + Handlebars.registerHelper({ + eq: (v1, v2) => v1 === v2, + ne: (v1, v2) => v1 !== v2, + lt: (v1, v2) => v1 < v2, + gt: (v1, v2) => v1 > v2, + lte: (v1, v2) => v1 <= v2, + gte: (v1, v2) => v1 >= v2, + and() { + return Array.prototype.every.call(arguments, Boolean); + }, + or() { + return Array.prototype.slice.call(arguments, 0, -1).some(Boolean); + }, + }); + + Handlebars.registerHelper("getTooltipFromConfigKey", function(key) { + return key.split(".").reduce((o, i) => o[i], CONFIG); + }); +}; diff --git a/system/src/helpers/templates.mjs b/system/src/helpers/templates.mjs index b888d93..f4fe407 100644 --- a/system/src/helpers/templates.mjs +++ b/system/src/helpers/templates.mjs @@ -3,24 +3,24 @@ * Pre-loaded templates are compiled and cached for fast access when rendering * @return {Promise} */ -export const preloadHandlebarsTemplates = async function () { - return loadTemplates([ - "systems/ac2d20/templates/actor/parts/actor-header.html", - "systems/ac2d20/templates/actor/parts/actor-abilities.html", - "systems/ac2d20/templates/actor/parts/actor-talents.html", - "systems/ac2d20/templates/actor/parts/actor-spells.html", - "systems/ac2d20/templates/actor/parts/actor-weapons.html", - "systems/ac2d20/templates/actor/parts/actor-armor.html", - "systems/ac2d20/templates/actor/parts/actor-skillkit.html", - "systems/ac2d20/templates/actor/parts/actor-equipment.html", - "systems/ac2d20/templates/actor/parts/actor-encumbrance.html", - "systems/ac2d20/templates/actor/parts/actor-effects.html", - "systems/ac2d20/templates/actor/parts/npc-abilities.html", - "systems/ac2d20/templates/actor/parts/npc-header.html", - "systems/ac2d20/templates/actor/parts/vehicle-header.html", - "systems/ac2d20/templates/actor/parts/vehicle-abilities.html", - "systems/ac2d20/templates/item/parts/item-header.html", - "systems/ac2d20/templates/item/parts/item-effects.html", - "systems/ac2d20/templates/actor/parts/simple-expandable-item.html" - ]); +export const preloadHandlebarsTemplates = async function() { + return loadTemplates([ + "systems/ac2d20/templates/actor/parts/actor-header.hbs", + "systems/ac2d20/templates/actor/parts/actor-abilities.hbs", + "systems/ac2d20/templates/actor/parts/actor-talents.hbs", + "systems/ac2d20/templates/actor/parts/actor-spells.hbs", + "systems/ac2d20/templates/actor/parts/actor-weapons.hbs", + "systems/ac2d20/templates/actor/parts/actor-armor.hbs", + "systems/ac2d20/templates/actor/parts/actor-skillkit.hbs", + "systems/ac2d20/templates/actor/parts/actor-equipment.hbs", + "systems/ac2d20/templates/actor/parts/actor-encumbrance.hbs", + "systems/ac2d20/templates/actor/parts/actor-effects.hbs", + "systems/ac2d20/templates/actor/parts/npc-abilities.hbs", + "systems/ac2d20/templates/actor/parts/npc-header.hbs", + "systems/ac2d20/templates/actor/parts/vehicle-header.hbs", + "systems/ac2d20/templates/actor/parts/vehicle-abilities.hbs", + "systems/ac2d20/templates/item/parts/item-header.hbs", + "systems/ac2d20/templates/item/parts/item-effects.hbs", + "systems/ac2d20/templates/actor/parts/simple-expandable-item.hbs", + ]); }; diff --git a/system/src/roller/ac2d20-roller.mjs b/system/src/roller/ac2d20-roller.mjs index 659d579..6914138 100644 --- a/system/src/roller/ac2d20-roller.mjs +++ b/system/src/roller/ac2d20-roller.mjs @@ -1,330 +1,325 @@ export class Roller2D20 { - dicesRolled = []; - successTreshold = 0; - critTreshold = 0; - complicationTreshold = 20; - successes = 0; + dicesRolled = []; - static async rollD20({ rollname = "Roll xD20", dicenum = 2, attribute = 0, skill = 0, focus = false, difficulty = 1, complication = 20, actorId = null, itemId = null } = {}) { - let dicesRolled = []; - let successTreshold = parseInt(attribute) + parseInt(skill); - let critTreshold = focus ? parseInt(skill) : 1; - let complicationTreshold = parseInt(complication); - let formula = `${dicenum}d20`; - let roll = new Roll(formula); - await roll.evaluate({ async: true }); - await Roller2D20.parseD20Roll({ - rollname: rollname, - roll: roll, - successTreshold: successTreshold, - critTreshold: critTreshold, - complicationTreshold: complicationTreshold, - actorId: actorId, - itemId: itemId - }); - } + successTreshold = 0; - static async parseD20Roll({ rollname = "Roll xD20", roll = null, successTreshold = 0, critTreshold = 1, complicationTreshold = 20, dicesRolled = [], rerollIndexes = [], actorId = null, itemId = null }) { - let i = 0; - roll.dice.forEach(d => { - d.results.forEach(r => { - let diceSuccess = 0; - let diceComplication = 0; - if (r.result <= successTreshold) { - diceSuccess++; - } - if (r.result <= critTreshold) { - diceSuccess++; - } - if (r.result >= complicationTreshold) { - diceComplication = 1; - } - // if there are no rollIndexes sent then it is a new roll. Otherwise it's a re-roll and we should replace dices at given indexes - if (!rerollIndexes.length) { - dicesRolled.push({ success: diceSuccess, reroll: false, result: r.result, complication: diceComplication }); - } - else { - dicesRolled[rerollIndexes[i]] = { success: diceSuccess, reroll: true, result: r.result, complication: diceComplication }; - i++; - } - }) - }); - await Roller2D20.sendToChat({ - rollname: rollname, - roll: roll, - successTreshold: successTreshold, - critTreshold: critTreshold, - complicationTreshold: complicationTreshold, - dicesRolled: dicesRolled, - rerollIndexes: rerollIndexes, - actorId: actorId, - itemId: itemId - }); - } + critTreshold = 0; - static async rerollD20({ rollname = "Roll xD20", roll = null, successTreshold = 0, critTreshold = 1, complicationTreshold = 20, dicesRolled = [], rerollIndexes = [] } = {}) { - if (!rerollIndexes.length) { - ui.notifications.notify('Select Dice you want to Reroll'); - return; - } - let numOfDice = rerollIndexes.length; - let formula = `${numOfDice}d20`; - let _roll = new Roll(formula); - await _roll.evaluate({ async: true }); - await Roller2D20.parseD20Roll({ - rollname: `${rollname} re-roll`, - roll: _roll, - successTreshold: successTreshold, - critTreshold: critTreshold, - complicationTreshold: complicationTreshold, - dicesRolled: dicesRolled, - rerollIndexes: rerollIndexes - }); - } + complicationTreshold = 20; - static async sendToChat({ rollname = "Roll xD20", roll = null, successTreshold = 0, critTreshold = 1, complicationTreshold = 20, dicesRolled = [], rerollIndexes = [], actorId = null, itemId = null } = {}) { - let successesNum = Roller2D20.getNumOfSuccesses(dicesRolled); - let complicationsNum = Roller2D20.getNumOfComplications(dicesRolled); - let rollData = { - rollname: rollname, - successes: successesNum, - complications: complicationsNum, - results: dicesRolled, - successTreshold: successTreshold, - actorId: actorId, - itemId: itemId - } - const html = await renderTemplate("systems/ac2d20/templates/chat/roll2d20.html", rollData); - let ac2d20Roll = {} - ac2d20Roll.rollname = rollname; - ac2d20Roll.dicesRolled = dicesRolled; - ac2d20Roll.successTreshold = successTreshold; - ac2d20Roll.critTreshold = critTreshold; - ac2d20Roll.complicationTreshold = complicationTreshold; - ac2d20Roll.rerollIndexes = rerollIndexes; - ac2d20Roll.diceFace = "d20"; - let speaker = {actor:actorId} - let chatData = { - user: game.user.id, - speaker: speaker, - rollMode: game.settings.get("core", "rollMode"), - content: html, - flags: { ac2d20roll: ac2d20Roll }, - type: CONST.CHAT_MESSAGE_TYPES.ROLL, - roll: roll, - }; - if (["gmroll", "blindroll"].includes(chatData.rollMode)) { - chatData.whisper = ChatMessage.getWhisperRecipients("GM"); - } else if (chatData.rollMode === "selfroll") { - chatData.whisper = [game.user]; - } - await ChatMessage.create(chatData); - } + successes = 0; - static getNumOfSuccesses(results) { - let s = 0; - results.forEach(d => { - s += d.success; - }); - return s; - } + static async rollD20({ rollname = "Roll xD20", dicenum = 2, attribute = 0, skill = 0, focus = false, difficulty = 1, complication = 20, actorId = null, itemId = null } = {}) { + // let dicesRolled = []; + let successTreshold = parseInt(attribute) + parseInt(skill); + let critTreshold = focus ? parseInt(skill) : 1; + let complicationTreshold = parseInt(complication); + let formula = `${dicenum}d20`; + let roll = new Roll(formula); - static getNumOfComplications(results) { - let r = 0; - results.forEach(d => { - r += d.complication; - }); - return r; - } + await roll.evaluate({ async: true }); - static async rollD6({ rollname = "Roll D6", dicenum = 2, itemId = null, actorId = null } = {}) { - let formula = `${dicenum}ds`; - let roll = new Roll(formula); - await roll.evaluate({ async: true }); - await Roller2D20.parseD6Roll({ - rollname: rollname, - roll: roll, - itemId: itemId, - actorId: actorId - }); - } + await Roller2D20.parseD20Roll({ + rollname: rollname, + roll: roll, + successTreshold: successTreshold, + critTreshold: critTreshold, + complicationTreshold: complicationTreshold, + actorId: actorId, + itemId: itemId, + }); + } - static async parseD6Roll({ rollname = "Roll D6", roll = null, dicesRolled = [], rerollIndexes = [], addDice = [], itemId = null, actorId = null } = {}) { - let diceResults = [ - { result: 1, effect: 0 }, - { result: 2, effect: 0 }, - { result: 0, effect: 0 }, - { result: 0, effect: 0 }, - { result: 1, effect: 1 }, - { result: 1, effect: 1 }, - ]; + static async parseD20Roll({ rollname = "Roll xD20", roll = null, successTreshold = 0, critTreshold = 1, complicationTreshold = 20, dicesRolled = [], rerollIndexes = [], actorId = null, itemId = null }) { + let i = 0; + roll.dice.forEach(d => { + d.results.forEach(r => { + let diceSuccess = 0; + let diceComplication = 0; + if (r.result <= successTreshold) { + diceSuccess++; + } + if (r.result <= critTreshold) { + diceSuccess++; + } + if (r.result >= complicationTreshold) { + diceComplication = 1; + } + // if there are no rollIndexes sent then it is a new roll. + // Otherwise it's a re-roll and we should replace dices at given + // indexes + if (!rerollIndexes.length) { + dicesRolled.push({ + success: diceSuccess, + reroll: false, + result: r.result, + complication: diceComplication, + }); + } + else { + dicesRolled[rerollIndexes[i]] = { + success: diceSuccess, + reroll: true, + result: r.result, + complication: diceComplication, + }; + i++; + } + }); + }); + await Roller2D20.sendToChat({ + rollname: rollname, + roll: roll, + successTreshold: successTreshold, + critTreshold: critTreshold, + complicationTreshold: complicationTreshold, + dicesRolled: dicesRolled, + rerollIndexes: rerollIndexes, + actorId: actorId, + itemId: itemId, + }); + } - let i = 0; - roll.dice.forEach(d => { - d.results.forEach(r => { - let diceResult = diceResults[r.result - 1]; - diceResult.face = r.result; - // if there are no rollIndexes sent then it is a new roll. Otherwise it's a re-roll and we should replace dices at given indexes - if (!rerollIndexes.length) { - dicesRolled.push(diceResult); - } - else { - dicesRolled[rerollIndexes[i]] = diceResult; - i++; - } - }); - }); + static async rerollD20({ rollname = "Roll xD20", roll = null, successTreshold = 0, critTreshold = 1, complicationTreshold = 20, dicesRolled = [], rerollIndexes = [] } = {}) { + if (!rerollIndexes.length) { + ui.notifications.notify("Select Dice you want to Reroll"); + return; + } + let numOfDice = rerollIndexes.length; + let formula = `${numOfDice}d20`; + let _roll = new Roll(formula); + await _roll.evaluate({ async: true }); + await Roller2D20.parseD20Roll({ + rollname: `${rollname} re-roll`, + roll: _roll, + successTreshold: successTreshold, + critTreshold: critTreshold, + complicationTreshold: complicationTreshold, + dicesRolled: dicesRolled, + rerollIndexes: rerollIndexes, + }); + } - if (addDice.length) { - dicesRolled = addDice.concat(dicesRolled); - } + static async sendToChat({ rollname = "Roll xD20", roll = null, successTreshold = 0, critTreshold = 1, complicationTreshold = 20, dicesRolled = [], rerollIndexes = [], actorId = null, itemId = null } = {}) { + let successesNum = Roller2D20.getNumOfSuccesses(dicesRolled); + let complicationsNum = Roller2D20.getNumOfComplications(dicesRolled); + let rollData = { + rollname: rollname, + successes: successesNum, + complications: complicationsNum, + results: dicesRolled, + successTreshold: successTreshold, + actorId: actorId, + itemId: itemId, + }; + const html = await renderTemplate("systems/ac2d20/templates/chat/roll2d20.hbs", rollData); + let ac2d20Roll = {}; + ac2d20Roll.rollname = rollname; + ac2d20Roll.dicesRolled = dicesRolled; + ac2d20Roll.successTreshold = successTreshold; + ac2d20Roll.critTreshold = critTreshold; + ac2d20Roll.complicationTreshold = complicationTreshold; + ac2d20Roll.rerollIndexes = rerollIndexes; + ac2d20Roll.diceFace = "d20"; + let speaker = {actor: actorId}; + let chatData = { + user: game.user.id, + speaker: speaker, + rollMode: game.settings.get("core", "rollMode"), + content: html, + flags: { ac2d20roll: ac2d20Roll }, + type: CONST.CHAT_MESSAGE_TYPES.ROLL, + roll: roll, + }; + if (["gmroll", "blindroll"].includes(chatData.rollMode)) { + chatData.whisper = ChatMessage.getWhisperRecipients("GM"); + } + else if (chatData.rollMode === "selfroll") { + chatData.whisper = [game.user]; + } + await ChatMessage.create(chatData); + } - await Roller2D20.sendD6ToChat({ - rollname: rollname, - roll: roll, - dicesRolled: dicesRolled, - rerollIndexes: rerollIndexes, - itemId: itemId, - actorId: actorId - }); - } + static getNumOfSuccesses(results) { + let s = 0; + results.forEach(d => { + s += d.success; + }); + return s; + } - static async rerollD6({ rollname = "Roll D6", roll = null, dicesRolled = [], rerollIndexes = [], itemId = null, actorId = null } = {}) { - if (!rerollIndexes.length) { - ui.notifications.notify('Select Dice you want to Reroll'); - return; - } - let numOfDice = rerollIndexes.length; - let formula = `${numOfDice}ds`; - let _roll = new Roll(formula); - await _roll.evaluate({ async: true }); - await Roller2D20.parseD6Roll({ - rollname: `${rollname} [re-roll]`, - roll: _roll, - dicesRolled: dicesRolled, - rerollIndexes: rerollIndexes, - itemId: itemId, - actorId: actorId - }); - } + static getNumOfComplications(results) { + let r = 0; + results.forEach(d => { + r += d.complication; + }); + return r; + } - static async addD6({ rollname = "Roll D6", dicenum = 2, ac2d20Roll = null, dicesRolled = [], itemId = null, actorId = null } = {}) { - let formula = `${dicenum}ds`; - let _roll = new Roll(formula); - await _roll.evaluate({ async: true }); - let newRollName = `${ac2d20Roll.rollname} [+ ${dicenum} DC]`; - let oldDiceRolled = ac2d20Roll.dicesRolled; - await Roller2D20.parseD6Roll({ - rollname: newRollName, - roll: _roll, - dicesRolled: dicesRolled, - addDice: oldDiceRolled, - itemId: itemId, - actorId: actorId - }); - } + static async rollD6({ rollname = "Roll D6", dicenum = 2, itemId = null, actorId = null } = {}) { + let formula = `${dicenum}ds`; + let roll = new Roll(formula); + await roll.evaluate({ async: true }); + await Roller2D20.parseD6Roll({ + rollname: rollname, + roll: roll, + itemId: itemId, + actorId: actorId, + }); + } - static async sendD6ToChat({ rollname = "Roll D6", roll = null, dicesRolled = [], rerollIndexes = [], itemId = null, actorId = null } = {}) { - let damage = dicesRolled.reduce((a, b) => ({ result: a.result + b.result })).result; - let effects = dicesRolled.reduce((a, b) => ({ effect: a.effect + b.effect })).effect; - //let weaponDamageTypesList = []; - //let weaponDamageEffectsList = []; - //let weaponQualityList = []; + static async parseD6Roll({ rollname = "Roll D6", roll = null, dicesRolled = [], rerollIndexes = [], addDice = [], itemId = null, actorId = null } = {}) { + let diceResults = [ + { result: 1, effect: 0 }, + { result: 2, effect: 0 }, + { result: 0, effect: 0 }, + { result: 0, effect: 0 }, + { result: 1, effect: 1 }, + { result: 1, effect: 1 }, + ]; - let itemEffects = []; - let itemQualities = []; + let i = 0; + roll.dice.forEach(d => { + d.results.forEach(r => { + let diceResult = diceResults[r.result - 1]; + diceResult.face = r.result; + // if there are no rollIndexes sent then it is a new roll. + // Otherwise it's a re-roll and we should replace dices at given + // indexes + if (!rerollIndexes.length) { + dicesRolled.push(diceResult); + } + else { + dicesRolled[rerollIndexes[i]] = diceResult; + i++; + } + }); + }); - if (itemId && actorId) { - let actor = game.actors.get(actorId); - let item = null - if (actor) { - item = actor.items.get(itemId) - } - if (item) { - if (item.type === 'spell') { - itemEffects = item.system.costEffects; - } else if (item.type === 'weapon') { - for (let de in item.system.effect) { - if (item.system.effect[de].value) { - let rank = item.system.effect[de].rank ?? ""; - let damageEffectLabel = game.i18n.localize(`AC2D20.WEAPONS.damageEffect.${de}`); - let efectLabel = `${damageEffectLabel}${rank}`; - itemEffects.push(efectLabel); - } - } - itemEffects = itemEffects.join(', ') + if (addDice.length) { + dicesRolled = addDice.concat(dicesRolled); + } - for (let qu in item.system.qualities) { - if (item.system.qualities[qu].value) { - let quLabel = game.i18n.localize(`AC2D20.WEAPONS.qualities.${qu}`); - itemQualities.push(quLabel) - } - } - } - } + await Roller2D20.sendD6ToChat({ + rollname: rollname, + roll: roll, + dicesRolled: dicesRolled, + rerollIndexes: rerollIndexes, + itemId: itemId, + actorId: actorId, + }); + } - } + static async rerollD6({ rollname = "Roll D6", roll = null, dicesRolled = [], rerollIndexes = [], itemId = null, actorId = null } = {}) { + if (!rerollIndexes.length) { + ui.notifications.notify("Select Dice you want to Reroll"); + return; + } + let numOfDice = rerollIndexes.length; + let formula = `${numOfDice}ds`; + let _roll = new Roll(formula); + await _roll.evaluate({ async: true }); + await Roller2D20.parseD6Roll({ + rollname: `${rollname} [re-roll]`, + roll: _roll, + dicesRolled: dicesRolled, + rerollIndexes: rerollIndexes, + itemId: itemId, + actorId: actorId, + }); + } - // if (weapon != null) { - // for (let de in weapon.data.effect) { - // if (weapon.data.effect[de].value) { - // let rank = weapon.data.effect[de].rank ?? ""; - // let damageEffectLabel = game.i18n.localize(`AC2D20.WEAPONS.damageEffect.${de}`); - // let efectLabel = `${damageEffectLabel}${rank}`; - // weaponDamageEffectsList.push(efectLabel); - // } - // } + static async addD6({ rollname = "Roll D6", dicenum = 2, ac2d20Roll = null, dicesRolled = [], itemId = null, actorId = null } = {}) { + let formula = `${dicenum}ds`; + let _roll = new Roll(formula); + await _roll.evaluate({ async: true }); + let newRollName = `${ac2d20Roll.rollname} [+ ${dicenum} DC]`; + let oldDiceRolled = ac2d20Roll.dicesRolled; + await Roller2D20.parseD6Roll({ + rollname: newRollName, + roll: _roll, + dicesRolled: dicesRolled, + addDice: oldDiceRolled, + itemId: itemId, + actorId: actorId, + }); + } - // for (let qu in weapon.data.qualities) { - // if (weapon.data.qualities[qu].value) { - // //let rank = weapon.system.effect[qu].rank ?? ""; - // let quLabel = game.i18n.localize(`AC2D20.WEAPONS.qualities.${qu}`); - // //let quLabel = `${damageEffectLabel}${rank}`; - // weaponQualityList.push(quLabel); - // } - // } - // } - //let weaponDamageEffects = weaponDamageEffectsList.join(', '); - // let rollData = { - // rollname: rollname, - // damage: damage, - // effects: effects, - // results: dicesRolled, - // weaponDamageEffects: weaponDamageEffects, - // weaponQualityList: weaponQualityList - // } - let rollData = { - rollname: rollname, - damage: damage, - effects: effects, - results: dicesRolled, - itemEffects: itemEffects, - itemQualities: itemQualities - } - const html = await renderTemplate("systems/ac2d20/templates/chat/rollD6.html", rollData); - let ac2d20Roll = {} - ac2d20Roll.rollname = rollname; - ac2d20Roll.dicesRolled = dicesRolled; - ac2d20Roll.damage = damage; - ac2d20Roll.effects = effects; - ac2d20Roll.rerollIndexes = rerollIndexes; - ac2d20Roll.diceFace = "d6"; + static async sendD6ToChat({ rollname = "Roll D6", roll = null, dicesRolled = [], rerollIndexes = [], itemId = null, actorId = null } = {}) { + let damage = dicesRolled.reduce((a, b) => ({ result: a.result + b.result })).result; + let effects = dicesRolled.reduce((a, b) => ({ effect: a.effect + b.effect })).effect; + // let weaponDamageTypesList = []; + // let weaponDamageEffectsList = []; + // let weaponQualityList = []; - let chatData = { - user: game.user.id, - rollMode: game.settings.get("core", "rollMode"), - content: html, - flags: { ac2d20roll: ac2d20Roll, itemId: itemId, actorId: actorId }, - type: CONST.CHAT_MESSAGE_TYPES.ROLL, - roll: roll, - }; - if (["gmroll", "blindroll"].includes(chatData.rollMode)) { - chatData.whisper = ChatMessage.getWhisperRecipients("GM"); - } else if (chatData.rollMode === "selfroll") { - chatData.whisper = [game.user]; - } - await ChatMessage.create(chatData); + let itemEffects = []; + let itemQualities = []; - } + if (itemId && actorId) { + let actor = game.actors.get(actorId); + let item = null; + if (actor) { + item = actor.items.get(itemId); + } + if (item) { + if (item.type === "spell") { + itemEffects = item.system.costEffects; + } + else if (item.type === "weapon") { + for (let de in item.system.effect) { + if (item.system.effect[de].value) { + let rank = item.system.effect[de].rank ?? ""; + let damageEffectLabel = game.i18n.localize(`AC2D20.WEAPONS.damageEffect.${de}`); + let efectLabel = `${damageEffectLabel}${rank}`; + itemEffects.push(efectLabel); + } + } + itemEffects = itemEffects.join(", "); + + for (let qu in item.system.qualities) { + if (item.system.qualities[qu].value) { + let quLabel = game.i18n.localize(`AC2D20.WEAPONS.qualities.${qu}`); + itemQualities.push(quLabel); + } + } + } + } + + } + + let rollData = { + rollname: rollname, + damage: damage, + effects: effects, + results: dicesRolled, + itemEffects: itemEffects, + itemQualities: itemQualities, + }; + const html = await renderTemplate("systems/ac2d20/templates/chat/rollD6.hbs", rollData); + let ac2d20Roll = {}; + ac2d20Roll.rollname = rollname; + ac2d20Roll.dicesRolled = dicesRolled; + ac2d20Roll.damage = damage; + ac2d20Roll.effects = effects; + ac2d20Roll.rerollIndexes = rerollIndexes; + ac2d20Roll.diceFace = "d6"; + + let chatData = { + user: game.user.id, + rollMode: game.settings.get("core", "rollMode"), + content: html, + flags: { ac2d20roll: ac2d20Roll, itemId: itemId, actorId: actorId }, + type: CONST.CHAT_MESSAGE_TYPES.ROLL, + roll: roll, + }; + if (["gmroll", "blindroll"].includes(chatData.rollMode)) { + chatData.whisper = ChatMessage.getWhisperRecipients("GM"); + } + else if (chatData.rollMode === "selfroll") { + chatData.whisper = [game.user]; + } + await ChatMessage.create(chatData); + + } } diff --git a/system/src/roller/challengeDie.js b/system/src/roller/challengeDie.js index 6b22540..1c8db85 100644 --- a/system/src/roller/challengeDie.js +++ b/system/src/roller/challengeDie.js @@ -1,61 +1,59 @@ export default class DieACChallenge extends Die { - constructor(termData) { - termData.faces = 6; - super(termData); - } - - static DENOMINATION = 's'; - - /** @override */ - getResultLabel(result) { - return { - "1": '', - "2": '', - "3": '', - "4": '', - "5": '', - "6": '' - }[result.result]; - } - - static values = { - 1: 1, - 2: 2, - 3: 0, - 4: 0, - 5: "", - 6: "", - }; - - get total() { - if (!this._evaluated) return null; - return this.results.reduce((t, r) => { - if (!r.active) return t; - if (r.count !== undefined) return t + r.count; - return t + DieACChallenge.getValue(r.result); - }, 0); - } - - /** @override */ - roll(options) { - const roll = super.roll(options); - roll.effect = roll.result === 5 || roll.result === 6; - return roll; - } - - get resultValues() { - return this.results.map(result => { - return DieACChallenge.getResultLabel(result.result); - }); - } - - static getValue(dieSide) { - // 1 if Effect, otherwise take the value - return typeof DieACChallenge.values[dieSide] === 'string' - ? 1 - : DieACChallenge.values[dieSide]; - } - + constructor(termData) { + termData.faces = 6; + super(termData); + } + + static DENOMINATION = "s"; + + /** @override */ + getResultLabel(result) { + return { + 1: '', + 2: '', + 3: '', + 4: '', + 5: '', + 6: '', + }[result.result]; + } + + static values = { + 1: 1, + 2: 2, + 3: 0, + 4: 0, + 5: "", + 6: "", + }; + + get total() { + if (!this._evaluated) return null; + return this.results.reduce((t, r) => { + if (!r.active) return t; + if (r.count !== undefined) return t + r.count; + return t + DieACChallenge.getValue(r.result); + }, 0); + } + + /** @override */ + roll(options) { + const roll = super.roll(options); + roll.effect = roll.result === 5 || roll.result === 6; + return roll; + } + + get resultValues() { + return this.results.map(result => { + return DieACChallenge.getResultLabel(result.result); + }); + } + + static getValue(dieSide) { + // 1 if Effect, otherwise take the value + return typeof DieACChallenge.values[dieSide] === "string" + ? 1 + : DieACChallenge.values[dieSide]; + } } - diff --git a/system/src/roller/dialog2d20.js b/system/src/roller/dialog2d20.js index 45fb8a0..3cb1b5e 100644 --- a/system/src/roller/dialog2d20.js +++ b/system/src/roller/dialog2d20.js @@ -1,74 +1,109 @@ export class Dialog2d20 extends Dialog { + constructor( + rollName, + diceNum, + attribute, + skill, + focus, + complication, + actor, + prefAttribute, + actorId, + itemId, + dialogData={}, + options={} + ) { + super(dialogData, options); + this.rollName = rollName; + this.diceNum = diceNum; + this.attribute = attribute; + this.skill = skill; + this.focus = focus; + this.complication = complication; + this.actor = actor; + this.prefAttribute = prefAttribute; + this.actorId = actorId; + this.itemId = itemId; + this.options.classes = ["dice-icon"]; + } - constructor(rollName, diceNum, attribute, skill, focus, complication, actor, prefAttribute, actorId, itemId, dialogData = {}, options = {}) { - super(dialogData, options); - this.rollName = rollName; - this.diceNum = diceNum; - this.attribute = attribute; - this.skill = skill; - this.focus = focus; - this.complication = complication; - this.actor = actor; - this.prefAttribute = prefAttribute; - this.actorId = actorId; - this.itemId = itemId; - this.options.classes = ["dice-icon"]; - } + activateListeners(html) { + super.activateListeners(html); - //override - activateListeners(html) { - super.activateListeners(html); - html.ready((e) => { - this.markDiceNumber(html, this.diceNum); - }) - html.on('click', '.dice-icon', (e, i, a) => { - let index = e.currentTarget.dataset.index; - this.diceNum = parseInt(index); - this.markDiceNumber(html, this.diceNum); - }); - html.on('click', '.roll', (event) => { - let attr = html.find('[name="attribute"]').val(); - if (!attr) { - let attrAbr = html.find('.select-attribute').val(); - attr = this.actor.attributes[attrAbr].value; - } - let skill = html.find('[name="skill"]').val(); - let complication = html.find('[name="complication"]').val(); - let isFocus = html.find('[name="focus"]').is(':checked'); - game.ac2d20.Roller2D20.rollD20({ rollname: this.rollName, dicenum: this.diceNum, attribute: attr, skill: skill, focus: isFocus, complication: complication, actorId: this.actorId, itemId: this.itemId }) - }); - } + html.ready(e => { + this.markDiceNumber(html, this.diceNum); + }); - markDiceNumber(html) { - $(html).find('.dice-icon').removeClass('marked'); - $(html).find(`[data-index="${this.diceNum}"]`).addClass('marked'); - } + html.on("click", ".dice-icon", (e, i, a) => { + let index = e.currentTarget.dataset.index; + this.diceNum = parseInt(index); + this.markDiceNumber(html, this.diceNum); + }); - static async createDialog({ rollName = "Roll D20", diceNum = 2, attribute = 0, skill = 0, focus = false, complication = 20, actor = null, prefAttribute = null, actorId = null, itemId=null } = {}) { - let dialogData = {} - dialogData.rollName = rollName; - dialogData.diceNum = diceNum; - dialogData.attribute = attribute; - dialogData.skill = skill; - dialogData.focus = focus; - dialogData.complication = complication; - dialogData.attributes = ['agi', 'bra', 'coo', 'ins', 'rea', 'wil']; - dialogData.actor = actor; - dialogData.prefAttribute = prefAttribute; - dialogData.actorId = actorId; - dialogData.itemId = itemId; - const html = await renderTemplate("systems/ac2d20/templates/dialogs/dialog2d20.html", dialogData); - let d = new Dialog2d20(rollName, diceNum, attribute, skill, focus, complication, actor, prefAttribute, actorId, itemId, { - title: rollName, - content: html, - buttons: { - roll: { - icon: '', - label: "ROLL" - } - } - }); - d.render(true); - } -} \ No newline at end of file + html.on("click", ".roll", event => { + let attr = html.find('[name="attribute"]').val(); + if (!attr) { + let attrAbr = html.find(".select-attribute").val(); + attr = this.actor.attributes[attrAbr].value; + } + let skill = html.find('[name="skill"]').val(); + let complication = html.find('[name="complication"]').val(); + let isFocus = html.find('[name="focus"]').is(":checked"); + game.ac2d20.Roller2D20.rollD20({ + rollname: this.rollName, + dicenum: this.diceNum, + attribute: attr, + skill: skill, + focus: isFocus, + complication: complication, + actorId: this.actorId, + itemId: this.itemId, + }); + }); + } + + markDiceNumber(html) { + $(html).find(".dice-icon").removeClass("marked"); + $(html).find(`[data-index="${this.diceNum}"]`).addClass("marked"); + } + + static async createDialog({ rollName = "Roll D20", diceNum = 2, attribute = 0, skill = 0, focus = false, complication = 20, actor = null, prefAttribute = null, actorId = null, itemId=null } = {}) { + let dialogData = {}; + dialogData.rollName = rollName; + dialogData.diceNum = diceNum; + dialogData.attribute = attribute; + dialogData.skill = skill; + dialogData.focus = focus; + dialogData.complication = complication; + dialogData.attributes = ["agi", "bra", "coo", "ins", "rea", "wil"]; + dialogData.actor = actor; + dialogData.prefAttribute = prefAttribute; + dialogData.actorId = actorId; + dialogData.itemId = itemId; + const html = await renderTemplate("systems/ac2d20/templates/dialogs/dialog2d20.hbs", dialogData); + let d = new Dialog2d20( + rollName, + diceNum, + attribute, + skill, + focus, + complication, + actor, + prefAttribute, + actorId, + itemId, + { + title: rollName, + content: html, + buttons: { + roll: { + icon: '', + label: "ROLL", + }, + }, + } + ); + d.render(true); + } +} diff --git a/system/src/roller/dialogD6.js b/system/src/roller/dialogD6.js index 40d0f26..8713a50 100644 --- a/system/src/roller/dialogD6.js +++ b/system/src/roller/dialogD6.js @@ -1,43 +1,68 @@ export class DialogD6 extends Dialog { - constructor(rollName, diceNum, dialogData = {}, options = {}) { - super(dialogData, options); - this.rollName = rollName; - this.diceNum = diceNum; - this.options.classes = ["dice-icon"]; - } + constructor(rollName, diceNum, dialogData = {}, options = {}) { + super(dialogData, options); + this.rollName = rollName; + this.diceNum = diceNum; + this.options.classes = ["dice-icon"]; + } - static async createDialog({ rollName = "Challenge Roll", diceNum = 2, ac2d20Roll = null, itemId = null, actorId = null } = {}) { - let dialogData = {} - dialogData.rollName = rollName; - dialogData.diceNum = diceNum; - dialogData.ac2d20Roll = ac2d20Roll; - dialogData.itemId = itemId; - dialogData.actorId = actorId; - const html = `
-
- -
-
` - let d = new DialogD6(rollName, diceNum, { - title: rollName, - content: html, - buttons: { - roll: { - icon: '', - label: "ROLL", - callback: (html) => { - let diceNum = html.find('.d-number')[0].value; - if (!ac2d20Roll) - game.ac2d20.Roller2D20.rollD6({ rollname: rollName, dicenum: parseInt(diceNum), itemId: itemId, actorId: actorId }); - else - game.ac2d20.Roller2D20.addD6({ rollname: rollName, dicenum: parseInt(diceNum), ac2d20Roll: ac2d20Roll, itemId: itemId, actorId: actorId }); - } - } - }, - default: "roll", - close: () => { }, - }); - d.render(true); - } -} \ No newline at end of file + static async createDialog({ + rollName = "Challenge Roll", + diceNum = 2, + ac2d20Roll = null, + itemId = null, + actorId = null, + }={}) { + let dialogData = {}; + dialogData.rollName = rollName; + dialogData.diceNum = diceNum; + dialogData.ac2d20Roll = ac2d20Roll; + dialogData.itemId = itemId; + dialogData.actorId = actorId; + + const html = ` +
+
+ + +
+
`; + + let d = new DialogD6(rollName, diceNum, { + title: rollName, + content: html, + buttons: { + roll: { + icon: '', + label: "ROLL", + callback: html => { + let diceNum = html.find(".d-number")[0].value; + if (!ac2d20Roll) { + game.ac2d20.Roller2D20.rollD6({ + rollname: rollName, + dicenum: parseInt(diceNum), + itemId: itemId, + actorId: actorId, + }); + } + else { + game.ac2d20.Roller2D20.addD6({ + rollname: rollName, + dicenum: parseInt(diceNum), + ac2d20Roll: ac2d20Roll, + itemId: itemId, + actorId: actorId, + }); + } + }, + }, + }, + default: "roll", + close: () => { }, + }); + d.render(true); + } +} diff --git a/system/src/settings.js b/system/src/settings.js index 3c283b9..480c9e9 100644 --- a/system/src/settings.js +++ b/system/src/settings.js @@ -1,66 +1,74 @@ -const debounceReload = debounce(() => window.location.reload(), 100) +const debounceReload = debounce(() => window.location.reload(), 100); + export function registerSettings() { - game.settings.register('ac2d20', 'partyMomentum', { - name: 'Party Momentum', - scope: 'world', - config: false, - default: 0, - type: Number, - }); - game.settings.register('ac2d20', 'gmMomentum', { - name: 'GM Momentum', - scope: 'world', - config: false, - default: 0, - type: Number, - }); - game.settings.register('ac2d20', 'maxMomentum', { - name: 'Max Momentum', - scope: 'world', - config: false, - default: 6, - type: Number, - }); - game.settings.register('ac2d20', 'gmMomentumShowToPlayers', { - name: 'Show GM Momentum To Players', - hint: "Shows the GM momentum window to everyone. Requires refresh on players side.", - scope: 'world', - config: true, - default: false, - type: Boolean, - }); - game.settings.register('ac2d20', 'maxAppShowToPlayers', { - name: 'Players Can Setup Max App', - hint: "Allows players to settup the Party's MAX AP. Requires refresh on players side.", - scope: 'world', - config: true, - default: false, - type: Boolean, - }); - game.settings.register('ac2d20', 'compendium-skills', { - name: 'Skills Compendium', - scope: 'world', - config: true, - default: "ac2d20.skills", - type: String, - }); - game.settings.register('ac2d20', "hoversJsonLocation",{ - name: "Mouse Hover JSON file", - hint: "Location of the json file containing the text for qualities and damage effects.", - scope: "world", - config: true, - default: "systems/ac2d20/assets/hovers.json", - type: String, - filePicker: true, - restricted: true, - onChange: debounceReload - }); - game.settings.register('ac2d20', 'combatTrackerMomentumUpdate', { - name: 'Combat Tracker Updates Momentum?', - hint: 'If enabled the Combat Tracker will decrement the Momentum Pool when a new Combat Round starts, or when Combat ends.', - scope: 'world', - config: true, - default: true, - type: Boolean, - }); + game.settings.register("ac2d20", "partyMomentum", { + name: "Party Momentum", + scope: "world", + config: false, + default: 0, + type: Number, + }); + + game.settings.register("ac2d20", "gmMomentum", { + name: "GM Momentum", + scope: "world", + config: false, + default: 0, + type: Number, + }); + + game.settings.register("ac2d20", "maxMomentum", { + name: "Max Momentum", + scope: "world", + config: false, + default: 6, + type: Number, + }); + + game.settings.register("ac2d20", "gmMomentumShowToPlayers", { + name: "Show GM Momentum To Players", + hint: "Shows the GM momentum window to everyone. Requires refresh on players side.", + scope: "world", + config: true, + default: false, + type: Boolean, + }); + + game.settings.register("ac2d20", "maxAppShowToPlayers", { + name: "Players Can Setup Max App", + hint: "Allows players to settup the Party's MAX AP. Requires refresh on players side.", + scope: "world", + config: true, + default: false, + type: Boolean, + }); + + game.settings.register("ac2d20", "compendium-skills", { + name: "Skills Compendium", + scope: "world", + config: true, + default: "ac2d20.skills", + type: String, + }); + + game.settings.register("ac2d20", "hoversJsonLocation", { + name: "Mouse Hover JSON file", + hint: "Location of the json file containing the text for qualities and damage effects.", + scope: "world", + config: true, + default: "systems/ac2d20/assets/hovers.json", + type: String, + filePicker: true, + restricted: true, + onChange: debounceReload, + }); + + game.settings.register("ac2d20", "combatTrackerMomentumUpdate", { + name: "Combat Tracker Updates Momentum?", + hint: "If enabled the Combat Tracker will decrement the Momentum Pool when a new Combat Round starts, or when Combat ends.", + scope: "world", + config: true, + default: true, + type: Boolean, + }); } diff --git a/system/src/sheets/actor-sheet.mjs b/system/src/sheets/actor-sheet.mjs index e1ba690..af23aac 100644 --- a/system/src/sheets/actor-sheet.mjs +++ b/system/src/sheets/actor-sheet.mjs @@ -1,4 +1,4 @@ -import { AC2D20 } from "../helpers/config.mjs"; +// import { AC2D20 } from "../helpers/config.mjs"; import { onManageActiveEffect, prepareActiveEffectCategories } from "../helpers/effects.mjs"; /** @@ -7,695 +7,741 @@ import { onManageActiveEffect, prepareActiveEffectCategories } from "../helpers/ */ export class ACActorSheet extends ActorSheet { - /** @override */ - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - classes: ["ac2d20", "sheet", "actor"], - template: "systems/ac2d20/templates/actor/actor-sheet.html", - width: 720, - height: 780, - tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "abilities" }] - }); - } - - /** @override */ - get template() { - return `systems/ac2d20/templates/actor/actor-${this.actor.type}-sheet.html`; - } - - /* -------------------------------------------- */ - - /** @override */ - async getData() { - - //const context = super.getData(); - - //const actorData = context.actor.data; - - const source = this.actor.toObject(); - const actorData = this.actor.toObject(false); - - // Sort all items alphabetically for display on the character sheet - actorData.items.sort((a, b) => { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }); - - const context = { - actor: actorData, - source: source.system, - system: actorData.system, - items: actorData.items, - effects: prepareActiveEffectCategories(this.actor.effects), - owner: this.actor.isOwner, - limited: this.actor.limited, - options: this.options, - editable: this.isEditable, - type: this.actor.type, - isCharacter: this.actor.type === "character", - isNPC: this.actor.type === "npc", - isVehicle: this.actor.type === "vehicle", - rollData: this.actor.getRollData.bind(this.actor) - } - - // Add the actor's data to context.data for easier access, as well as flags. - //context.data = actorData.data; - //context.flags = actorData.flags; - - context.biographyHTML = await TextEditor.enrichHTML(context.system.biography, { - secrets: this.actor.isOwner, - rollData: context.rollData, - async: true - }); - - // Prepare character data and items. - if (actorData.type == 'character') { - this._prepareItems(context); - this._prepareCharacterData(context); - } - - // Prepare NPC data and items. - if (actorData.type == 'npc') { - this._prepareItems(context) - } - - // Prepare Creature data and items. - if (actorData.type == 'vehicle') { - this._prepareItems(context) - - } - - // Add roll data for TinyMCE editors. - //context.rollData = context.actor.getRollData(); - - //Prepare Items Enriched Descriptions - const itemTypes = ['talent'] - let itemsEnrichedDescriptions = {}; - for await(let itm of this.actor.items){ - if(itemTypes.includes(itm.type)){ - const descriptionRich = await TextEditor.enrichHTML(itm.system.description, {async:true}) - itemsEnrichedDescriptions[itm._id] = descriptionRich; - } - } - - context.itemsEnrichedDescriptions = itemsEnrichedDescriptions; - - // Prepare active effects - context.effects = prepareActiveEffectCategories(this.actor.effects); - context.AC2D20 = CONFIG.AC2D20; - - return context; - } - - /** + /** @override */ + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + classes: ["ac2d20", "sheet", "actor"], + template: "systems/ac2d20/templates/actor/actor-sheet.hbs", + width: 720, + height: 780, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "abilities" }], + }); + } + + /** @override */ + get template() { + return `systems/ac2d20/templates/actor/actor-${this.actor.type}-sheet.hbs`; + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + + // const context = super.getData(); + + // const actorData = context.actor.data; + + const source = this.actor.toObject(); + const actorData = this.actor.toObject(false); + + // Sort all items alphabetically for display on the character sheet + actorData.items.sort((a, b) => { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + + const context = { + actor: actorData, + source: source.system, + system: actorData.system, + items: actorData.items, + effects: prepareActiveEffectCategories(this.actor.effects), + owner: this.actor.isOwner, + limited: this.actor.limited, + options: this.options, + editable: this.isEditable, + type: this.actor.type, + isCharacter: this.actor.type === "character", + isNPC: this.actor.type === "npc", + isVehicle: this.actor.type === "vehicle", + rollData: this.actor.getRollData.bind(this.actor), + }; + + // Add the actor's data to context.data for easier access, as well as flags. + // context.data = actorData.data; + // context.flags = actorData.flags; + + context.biographyHTML = await TextEditor.enrichHTML(context.system.biography, { + secrets: this.actor.isOwner, + rollData: context.rollData, + async: true, + }); + + // Prepare character data and items. + if (actorData.type === "character") { + this._prepareItems(context); + this._prepareCharacterData(context); + } + + // Prepare NPC data and items. + if (actorData.type === "npc") { + this._prepareItems(context); + } + + // Prepare Creature data and items. + if (actorData.type === "vehicle") { + this._prepareItems(context); + + } + + // Add roll data for TinyMCE editors. + // context.rollData = context.actor.getRollData(); + + // Prepare Items Enriched Descriptions + const itemTypes = ["talent"]; + let itemsEnrichedDescriptions = {}; + for await (let itm of this.actor.items) { + if (itemTypes.includes(itm.type)) { + const descriptionRich = + await TextEditor.enrichHTML(itm.system.description, {async: true}); + + itemsEnrichedDescriptions[itm._id] = descriptionRich; + } + } + + context.itemsEnrichedDescriptions = itemsEnrichedDescriptions; + + // Prepare active effects + context.effects = prepareActiveEffectCategories(this.actor.effects); + context.AC2D20 = CONFIG.AC2D20; + + return context; + } + + /** * Organize and classify Items for Character sheets. * * @param {Object} actorData The actor to prepare. * * @return {undefined} */ - async _prepareCharacterData(context) { - let isEncumbered = false; - let physicalItems = context.items.filter(i => i.system.hasOwnProperty('weight')); - let encumberingItems = physicalItems.filter((i) => { - if (i.type != 'armor') { - return true; - } - else { - if (!i.system.equipped || (i.system.equipped && i.system.qualities.heavy.value)) { - return true - } - } - }); - context.minorItemsTotal = encumberingItems.filter(i => parseInt(i.system.weight) === 1).length; - context.majorItemsTotal = encumberingItems.filter(i => parseInt(i.system.weight) === 3).length; - let totalEncumbrance = 0; - for (let i = 0; i < encumberingItems.length; i++) { - totalEncumbrance += parseInt(encumberingItems[i].system.quantity) * parseInt(encumberingItems[i].system.weight) - } - - if (totalEncumbrance > this.actor.system.carryCapacity.value) - isEncumbered = true; - - context.totalEncumbrance = totalEncumbrance; - context.isEncumbered = isEncumbered; - } - - /** + async _prepareCharacterData(context) { + let isEncumbered = false; + let physicalItems = context.items.filter(i => i.system.hasOwnProperty("weight")); + let encumberingItems = physicalItems.filter(i => { + if (i.type !== "armor") { + return true; + } + else if (!i.system.equipped || (i.system.equipped && i.system.qualities.heavy.value)) { + return true; + } + else { + return false; + } + }); + context.minorItemsTotal = encumberingItems.filter( + i => parseInt(i.system.weight) === 1 + ).length; + + context.majorItemsTotal = encumberingItems.filter( + i => parseInt(i.system.weight) === 3 + ).length; + + let totalEncumbrance = 0; + for (let i = 0; i < encumberingItems.length; i++) { + totalEncumbrance += parseInt(encumberingItems[i].system.quantity) + * parseInt(encumberingItems[i].system.weight); + } + + if (totalEncumbrance > this.actor.system.carryCapacity.value) isEncumbered = true; + + context.totalEncumbrance = totalEncumbrance; + context.isEncumbered = isEncumbered; + } + + /** * Organize and classify Items for Character sheets. * * @param {Object} actorData The actor to prepare. * * @return {undefined} */ - _prepareItems(context) { - // Initialize containers. - - const skills = []; - const talents = []; - const spells = []; - const weapons = []; - const armor = []; - const skillkits = []; - const equipment = []; - const specialRules = [] - - // Iterate through items, allocating to containers - for (let i of context.items) { - i.img = i.img || DEFAULT_TOKEN; - // Append to gear. - if (i.type === 'skill') { - skills.push(i); - } - else if (i.type === 'talent') { - talents.push(i); - } - else if (i.type === 'spell') { - spells.push(i); - } - else if (i.type === 'armor') { - armor.push(i); - } - else if (i.type === 'weapon') { - weapons.push(i); - } - else if (i.type === 'skillkit') { - skillkits.push(i); - } - else if (i.type === 'equipment') { - equipment.push(i); - } - else if (i.type === 'special_rule') { - specialRules.push(i) - } - } - - // Assign and return - skills.sort(function (a, b) { - var nameA = a.name.toUpperCase(); - var nameB = b.name.toUpperCase(); - return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0; - }); - context.skills = skills; - context.talents = talents; - context.spells = spells; - context.armor = armor; - context.skillkits = skillkits; - context.equipment = equipment; - context.weapons = weapons; - context.specialRules = specialRules; - - - // WRAP INVENTORY DEPENDING ON THE CHARACTER TYPE: - // for example put apparel in inventory for all except the character actor. - - // NPC and Creature Inventory = all physical items that are not weapons - // if (this.actor.type == 'npc' || this.actor.type == 'creature') { - // context.inventory = context.items.filter(i => { - // return (i.type !== 'weapon' && i.data.weight != null) - // }); - // } - // if (this.actor.type == 'character') { - // context.inventory = [...robotApparel, ...robot_mods]; - // } - - } - - /* -------------------------------------------- */ - - /** @override */ - activateListeners(html) { - super.activateListeners(html); - - // SWITCH TABS - html.find('.tab-switch').click((evt) => { - evt.preventDefault(); - const el = evt.currentTarget; - const tab = el.dataset.tab; - this._tabs[0].activate(tab); - }); - - // Render the item sheet for viewing/editing prior to the editable check. - html.find('.item-edit').click(ev => { - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - item.sheet.render(true); - }); - - - // ------------------------------------------------------------- - // ! Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - // ATTRIBUTE ROLL - html.find('.roll-attribute.clickable').click((event) => { - event.preventDefault(); - let attr = $(event.currentTarget).data('attr'); - let attribute = this.actor.system.attributes[attr]; - let complication = 20; - if (this.actor.type == 'character') - complication -= this.actor.getComplicationFromInjuries(); - - if (this.actor.type == 'npc' || this.actor.type == 'vehicle') - complication -= this.actor.system.injuries.value; - - const attrName = game.i18n.localize('AC2D20.Ability.' + attr); - game.ac2d20.Dialog2d20.createDialog({ rollName: `Roll ${attrName}`, diceNum: 2, attribute: attribute.value, skill: 0, focus: false, complication: complication }) - }) - - // * SKILLS LISTENERS [clic, right-click, value change, focus ] - // Click Skill Item - html.find('.roll-skill.clickable, .roll-focus.clickable').click(ev => { - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let isFocused = $(ev.currentTarget).hasClass('focused'); - this._onRollSkill(item.name, item.system.value, this.actor.system.attributes[item.system.defaultAttribute].value, isFocused); - }); - // Change Skill Rank value - html.find('.skill-value-input').change(async (ev) => { - let newRank = parseInt($(ev.currentTarget).val()); - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let updatedItem = { _id: item.id, data: { value: newRank } }; - await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); - }); - // Toggle Focus value - html.find('.skill .item-skill-focus').click(async (ev) => { - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let updatedItem = { _id: item.id, data: { focus: !item.system.focus } }; - await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); - }); - // * END SKILLS - - // * TRUTHS - html.find('.truth-text').change(async (ev) => { - let updates = []; - $('.truth-cell').each((i, el) => { - let _txt = this._clearTextAreaText($(el).find('.truth-text').val()); - let truth = { - text: _txt - } - updates.push(truth); - }); - await this.actor.update({ 'system.truths': updates }); - }); - // * END TRUTHS - - // * SPELLS GRID - html.find('.cell-expander').click((event) => { this._onItemSummary(event) }); - - html.find('.roll-spell.clickable').click((event) => { - event.preventDefault(); - const li = $(event.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let complication = 20 - parseInt(item.system.difficulty - 1) - if (item.actor.type == 'character') - complication -= item.actor.getComplicationFromInjuries(); - - if (item.actor.type == 'npc') - complication -= item.actor.system.injuries.value; - - const skillName = item.system.skill; - const focusName = item.system.focus; - if (!skillName) - return; - - const skill = this.actor.items.getName(skillName); - let skillRank = 0; - try { - skillRank = skill.system.value; - } catch (err) { } - let isFocus = false; - try { - for (const [key, value] of Object.entries(skill.system.focuses)) { - if (value.title === focusName && value.isfocus) - isFocus = true; - } - } catch (err) { } - - const attrValue = -1; - let prefAttribute = "ins"; - if(this.actor.system.spellcastingType=='researcher') - prefAttribute = "rea" - else if(this.actor.system.spellcastingType=='dabbler') - prefAttribute = "wil" - - game.ac2d20.Dialog2d20.createDialog({ rollName: item.name, diceNum: 2, attribute: attrValue, skill: skillRank, focus: isFocus, complication: complication, actor: this.actor.system, prefAttribute: prefAttribute }) - - }); - - html.find('.roll-spell-cost.clickable').click((event) => { - event.preventDefault(); - const li = $(event.currentTarget).parents(".item"); - const itemId = li.data("itemId"); - const item = this.actor.items.get(li.data("itemId")); - const cost = parseInt(item.system.cost); - game.ac2d20.DialogD6.createDialog({ rollName: `${item.name} - Cost`, diceNum: cost, ac2d20Roll: null, itemId: itemId, actorId: this.actor._id }) - }) - - html.find('.item-value-changer').change(async (event) => { - event.preventDefault(); - const keyToChange = $(event.currentTarget).data('field'); - const newValue = $(event.currentTarget).val(); - const li = $(event.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let data = {}; - data[keyToChange] = newValue; - let updatedItem = { _id: item.id, data: data }; - await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); - }) - - // * WEAPON - html.find('.roll-weapon.clickable').click((event) => { - event.preventDefault(); - const li = $(event.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let complication = 20; - // if unrelliable increase complication - for (const [k, v] of Object.entries(item.system.qualities)) { - if (v.value && k == 'unreliable') - complication -= 1; - } - if (item.actor.type == 'character') - complication -= item.actor.getComplicationFromInjuries(); - - if (item.actor.type == 'npc' || item.actor.type == 'vehicle') - complication -= item.actor.system.injuries.value; - - const focusName = item.system.focus; - //if (!focusName) - //return; - - const skill = this.actor.items.getName(item.system.skill); - let skillRank = 0; - try { - skillRank = skill.system.value; - } catch (err) { - console.log(err) - } - let isFocus = false; - try { - for (const [key, value] of Object.entries(skill.system.focuses)) { - if (value.title === focusName && value.isfocus) - isFocus = true; - } - } catch (err) { console.log(err) } - - const attrValue = item.actor.type == 'vehicle' ? 6 : -1; - // weaponType is actualy attribute abrevation - const prefAttribute = item.system.weaponType; - game.ac2d20.Dialog2d20.createDialog({ rollName: item.name, diceNum: 2, attribute: attrValue, skill: skillRank, focus: isFocus, complication: complication, actor: this.actor.system, prefAttribute: prefAttribute, actorId:this.actor._id, itemId: item._id }) - - }); - - html.find('.roll-stress.clickable').click((event) => { - event.preventDefault(); - const li = $(event.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - const itemId = li.data("itemId"); - let stressBonus = 0; - if (item.system.weaponType == 'agi') - stressBonus = item.actor.system.attributes['bra'].bonus; - else if (item.system.weaponType == 'coo') - stressBonus = item.actor.system.attributes['ins'].bonus; - else if (item.system.weaponType == 'wil') - stressBonus = item.actor.system.attributes['wil'].bonus; - let stress = parseInt(item.system.stress) + parseInt(stressBonus); - game.ac2d20.DialogD6.createDialog({ rollName: item.name, diceNum: stress, ac2d20Roll: null, itemId: itemId, actorId: this.actor._id }) - }) - - // * AMMO COUNT UPDATE - html.find('.ammo-quantity').change(async (ev) => { - let newQuantity = parseInt($(ev.currentTarget).val()); - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let updatedItem = { _id: item.id, data: { ammo: newQuantity } }; - await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); - }); - - // * RESOURCE COUNT - html.find('.resources-quantity').change(async (ev) => { - let newQuantity = parseInt($(ev.currentTarget).val()); - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let updatedItem = { _id: item.id, data: { resources: newQuantity } }; - await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); - }); - - //* Quantity Change - html.find('.quantity-count').change(async (ev) => { - let newQuantity = parseInt($(ev.currentTarget).val()); - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - let updatedItem = { _id: item.id, data: { quantity: newQuantity } }; - await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); - }); - - html.find('.roll-impact.clickable').click((event) => { - event.preventDefault(); - const impact = this.actor.system.impact; - game.ac2d20.DialogD6.createDialog({ rollName: `${this.actor.name} Impact`, diceNum: impact, ac2d20Roll: null }) - }) - - // * CLICK TO EXPAND - html.find(".expandable-info").click((event) => this._onItemSummary(event)); - - // * Add Inventory Item - html.find('.item-create').click(this._onItemCreate.bind(this)); - - // * Delete Inventory Item - html.find('.item-delete').click(async (ev) => { - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("itemId")); - await item.delete(); - li.slideUp(200, () => this.render(false)); - }); - - // * Toggle Stash Inventory Item - html.find(".item-stash").click(async (ev) => { - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("item-id")); - await this.actor.updateEmbeddedDocuments("Item", [this._toggleStashed(li.data("item-id"), item)]); - }); - - // * Toggle Equip Inventory Item - html.find(".item-toggle").click(async (ev) => { - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("item-id")); - await this.actor.updateEmbeddedDocuments("Item", [this._toggleEquipped(li.data("item-id"), item)]); - }); - - // * Toggle Favorite Inventory Item - html.find(".item-favorite").click(async (ev) => { - const li = $(ev.currentTarget).parents(".item"); - const item = this.actor.items.get(li.data("item-id")); - await this.actor.updateEmbeddedDocuments("Item", [this._toggleFavorite(li.data("item-id"), item)]); - }); - - // * INJURIES - // html.find('.injury-text, .treated, .injury-type').change(async (ev) => { - // let updates = []; - // $('.injury-cell.injury').each((i, el) => { - // console.warn($(el).find('.injury-text').val()) - // let _txt = this._clearTextAreaText($(el).find('.injury-text').val()); - // let inj = { - // text: _txt, - // treated: $(el).find('.controls .treated').is(":checked"), - // injuryType: $(el).find('.controls .injury-type').is(":checked") - // } - // updates.push(inj); - // }); - // await this.actor.update({ 'data.injuries.list': updates }); - // }); - html.find('.injury-text, .treated, .injury-type').change(async (ev) => { - const $parent = $(ev.currentTarget).parents(".injury"); - const injuryNum = $parent.data("injury"); - let inj = { - text: $parent.find('.injury-text').val(), - treated: $parent.find('.controls .treated').is(":checked"), - injuryType: $parent.find('.controls .injury-type').is(":checked") - } - const dataPath = `system.injuries.${injuryNum}` - await this.actor.update({[`${dataPath}`]: inj }); - - }) - // * END INJURIES - - // * Active Effect management - html.find(".effect-control").click(ev => onManageActiveEffect(ev, this.actor)); - - /* -------------------------------------------- */ - /* ADD RIGH CLICK CONTENT MENU + _prepareItems(context) { + // Initialize containers. + + const skills = []; + const talents = []; + const spells = []; + const weapons = []; + const armor = []; + const skillkits = []; + const equipment = []; + const specialRules = []; + + // Iterate through items, allocating to containers + for (let i of context.items) { + i.img = i.img || DEFAULT_TOKEN; + // Append to gear. + if (i.type === "skill") { + skills.push(i); + } + else if (i.type === "talent") { + talents.push(i); + } + else if (i.type === "spell") { + spells.push(i); + } + else if (i.type === "armor") { + armor.push(i); + } + else if (i.type === "weapon") { + weapons.push(i); + } + else if (i.type === "skillkit") { + skillkits.push(i); + } + else if (i.type === "equipment") { + equipment.push(i); + } + else if (i.type === "special_rule") { + specialRules.push(i); + } + } + + // Assign and return + skills.sort(function(a, b) { + let nameA = a.name.toUpperCase(); + let nameB = b.name.toUpperCase(); + return (nameA < nameB) ? -1 : (nameA > nameB) ? 1 : 0; + }); + context.skills = skills; + context.talents = talents; + context.spells = spells; + context.armor = armor; + context.skillkits = skillkits; + context.equipment = equipment; + context.weapons = weapons; + context.specialRules = specialRules; + + + // WRAP INVENTORY DEPENDING ON THE CHARACTER TYPE: + // for example put apparel in inventory for all except the character actor. + + // NPC and Creature Inventory = all physical items that are not weapons + // if (this.actor.type == 'npc' || this.actor.type == 'creature') { + // context.inventory = context.items.filter(i => { + // return (i.type !== 'weapon' && i.data.weight != null) + // }); + // } + // if (this.actor.type == 'character') { + // context.inventory = [...robotApparel, ...robot_mods]; + // } + + } + + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // SWITCH TABS + html.find(".tab-switch").click(evt => { + evt.preventDefault(); + const el = evt.currentTarget; + const tab = el.dataset.tab; + this._tabs[0].activate(tab); + }); + + // Render the item sheet for viewing/editing prior to the editable check. + html.find(".item-edit").click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + item.sheet.render(true); + }); + + + // ------------------------------------------------------------- + // ! Everything below here is only needed if the sheet is editable + if (!this.isEditable) return; + + // ATTRIBUTE ROLL + html.find(".roll-attribute.clickable").click(event => { + event.preventDefault(); + let attr = $(event.currentTarget).data("attr"); + let attribute = this.actor.system.attributes[attr]; + let complication = 20; + if (this.actor.type === "character") complication -= this.actor.getComplicationFromInjuries(); + + if (this.actor.type === "npc" || this.actor.type === "vehicle") complication -= this.actor.system.injuries.value; + + const attrName = game.i18n.localize(`AC2D20.Ability.${attr}`); + game.ac2d20.Dialog2d20.createDialog({ rollName: `Roll ${attrName}`, diceNum: 2, attribute: attribute.value, skill: 0, focus: false, complication: complication }); + }); + + // * SKILLS LISTENERS [clic, right-click, value change, focus ] + // Click Skill Item + html.find(".roll-skill.clickable, .roll-focus.clickable").click(ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let isFocused = $(ev.currentTarget).hasClass("focused"); + + this._onRollSkill( + item.name, + item.system.value, + this.actor.system.attributes[item.system.defaultAttribute].value, + isFocused + ); + }); + // Change Skill Rank value + html.find(".skill-value-input").change(async ev => { + let newRank = parseInt($(ev.currentTarget).val()); + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let updatedItem = { _id: item.id, data: { value: newRank } }; + await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); + }); + // Toggle Focus value + html.find(".skill .item-skill-focus").click(async ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let updatedItem = { _id: item.id, data: { focus: !item.system.focus } }; + await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); + }); + // * END SKILLS + + // * TRUTHS + html.find(".truth-text").change(async ev => { + let updates = []; + $(".truth-cell").each((i, el) => { + let _txt = this._clearTextAreaText($(el).find(".truth-text").val()); + let truth = { + text: _txt, + }; + updates.push(truth); + }); + await this.actor.update({ "system.truths": updates }); + }); + // * END TRUTHS + + // * SPELLS GRID + html.find(".cell-expander").click(event => { + this._onItemSummary(event); + }); + + html.find(".roll-spell.clickable").click(event => { + event.preventDefault(); + const li = $(event.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let complication = 20 - parseInt(item.system.difficulty - 1); + if (item.actor.type === "character") complication -= item.actor.getComplicationFromInjuries(); + + if (item.actor.type === "npc") complication -= item.actor.system.injuries.value; + + const skillName = item.system.skill; + const focusName = item.system.focus; + if (!skillName) return; + + const skill = this.actor.items.getName(skillName); + let skillRank = 0; + try { + skillRank = skill.system.value; + } + catch(err) { } + let isFocus = false; + try { + for (const [, value] of Object.entries(skill.system.focuses)) { + if (value.title === focusName && value.isfocus) isFocus = true; + } + } + catch(err) { } + + const attrValue = -1; + let prefAttribute = "ins"; + if (this.actor.system.spellcastingType === "researcher") { + prefAttribute = "rea"; + } + else if (this.actor.system.spellcastingType === "dabbler") { + prefAttribute = "wil"; + } + + game.ac2d20.Dialog2d20.createDialog({ + rollName: item.name, + diceNum: 2, + attribute: attrValue, + skill: skillRank, + focus: isFocus, + complication: complication, + actor: this.actor.system, + prefAttribute: prefAttribute, + }); + + }); + + html.find(".roll-spell-cost.clickable").click(event => { + event.preventDefault(); + const li = $(event.currentTarget).parents(".item"); + const itemId = li.data("itemId"); + const item = this.actor.items.get(li.data("itemId")); + const cost = parseInt(item.system.cost); + game.ac2d20.DialogD6.createDialog({ rollName: `${item.name} - Cost`, diceNum: cost, ac2d20Roll: null, itemId: itemId, actorId: this.actor._id }); + }); + + html.find(".item-value-changer").change(async event => { + event.preventDefault(); + const keyToChange = $(event.currentTarget).data("field"); + const newValue = $(event.currentTarget).val(); + const li = $(event.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let data = {}; + data[keyToChange] = newValue; + let updatedItem = { _id: item.id, data: data }; + await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); + }); + + // * WEAPON + html.find(".roll-weapon.clickable").click(event => { + event.preventDefault(); + const li = $(event.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let complication = 20; + // if unrelliable increase complication + for (const [k, v] of Object.entries(item.system.qualities)) { + if (v.value && k === "unreliable") complication -= 1; + } + + if (item.actor.type === "character") { + complication -= item.actor.getComplicationFromInjuries(); + } + + if (item.actor.type === "npc" || item.actor.type === "vehicle") { + complication -= item.actor.system.injuries.value; + } + + const focusName = item.system.focus; + // if (!focusName) + // return; + + const skill = this.actor.items.getName(item.system.skill); + let skillRank = 0; + try { + skillRank = skill.system.value; + } + catch(err) { + console.log(err); + } + let isFocus = false; + try { + for (const [, value] of Object.entries(skill.system.focuses)) { + if (value.title === focusName && value.isfocus) isFocus = true; + } + } + catch(err) { + console.log(err); + } + + const attrValue = item.actor.type === "vehicle" ? 6 : -1; + // weaponType is actualy attribute abrevation + const prefAttribute = item.system.weaponType; + game.ac2d20.Dialog2d20.createDialog({ + rollName: item.name, + diceNum: 2, + attribute: attrValue, + skill: skillRank, + focus: isFocus, + complication: complication, + actor: this.actor.system, + prefAttribute: prefAttribute, + actorId: this.actor._id, + itemId: item._id, + }); + + }); + + html.find(".roll-stress.clickable").click(event => { + event.preventDefault(); + const li = $(event.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + const itemId = li.data("itemId"); + let stressBonus = 0; + if (item.system.weaponType === "agi") stressBonus = item.actor.system.attributes.bra.bonus; + else if (item.system.weaponType === "coo") stressBonus = item.actor.system.attributes.ins.bonus; + else if (item.system.weaponType === "wil") stressBonus = item.actor.system.attributes.wil.bonus; + let stress = parseInt(item.system.stress) + parseInt(stressBonus); + game.ac2d20.DialogD6.createDialog({ + rollName: item.name, + diceNum: stress, + ac2d20Roll: null, + itemId: itemId, + actorId: this.actor._id, + }); + }); + + // * AMMO COUNT UPDATE + html.find(".ammo-quantity").change(async ev => { + let newQuantity = parseInt($(ev.currentTarget).val()); + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let updatedItem = { _id: item.id, data: { ammo: newQuantity } }; + await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); + }); + + // * RESOURCE COUNT + html.find(".resources-quantity").change(async ev => { + let newQuantity = parseInt($(ev.currentTarget).val()); + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let updatedItem = { _id: item.id, data: { resources: newQuantity } }; + await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); + }); + + //* Quantity Change + html.find(".quantity-count").change(async ev => { + let newQuantity = parseInt($(ev.currentTarget).val()); + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + let updatedItem = { _id: item.id, data: { quantity: newQuantity } }; + await this.actor.updateEmbeddedDocuments("Item", [updatedItem]); + }); + + html.find(".roll-impact.clickable").click(event => { + event.preventDefault(); + const impact = this.actor.system.impact; + game.ac2d20.DialogD6.createDialog({ rollName: `${this.actor.name} Impact`, diceNum: impact, ac2d20Roll: null }); + }); + + // * CLICK TO EXPAND + html.find(".expandable-info").click(event => this._onItemSummary(event)); + + // * Add Inventory Item + html.find(".item-create").click(this._onItemCreate.bind(this)); + + // * Delete Inventory Item + html.find(".item-delete").click(async ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("itemId")); + await item.delete(); + li.slideUp(200, () => this.render(false)); + }); + + // * Toggle Stash Inventory Item + html.find(".item-stash").click(async ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("item-id")); + await this.actor.updateEmbeddedDocuments("Item", [this._toggleStashed(li.data("item-id"), item)]); + }); + + // * Toggle Equip Inventory Item + html.find(".item-toggle").click(async ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("item-id")); + await this.actor.updateEmbeddedDocuments("Item", [this._toggleEquipped(li.data("item-id"), item)]); + }); + + // * Toggle Favorite Inventory Item + html.find(".item-favorite").click(async ev => { + const li = $(ev.currentTarget).parents(".item"); + const item = this.actor.items.get(li.data("item-id")); + await this.actor.updateEmbeddedDocuments("Item", [this._toggleFavorite(li.data("item-id"), item)]); + }); + + // * INJURIES + html.find(".injury-text, .treated, .injury-type").change(async ev => { + const $parent = $(ev.currentTarget).parents(".injury"); + const injuryNum = $parent.data("injury"); + let inj = { + text: $parent.find(".injury-text").val(), + treated: $parent.find(".controls .treated").is(":checked"), + injuryType: $parent.find(".controls .injury-type").is(":checked"), + }; + const dataPath = `system.injuries.${injuryNum}`; + await this.actor.update({[`${dataPath}`]: inj }); + + }); + // * END INJURIES + + // * Active Effect management + html.find(".effect-control").click(ev => onManageActiveEffect(ev, this.actor)); + + /* -------------------------------------------- */ + /* ADD RIGHT CLICK CONTENT MENU /* -------------------------------------------- */ - const editLabel = game.i18n.localize("AC2D20.EDIT"); - const deleteLabel = game.i18n.localize("AC2D20.DELETE"); - const postLabel = game.i18n.localize("AC2D20.POST"); - - let menu_items = [ - { - icon: '', - name: '', - callback: (t) => { - this._onPostItem(t.data("item-id")); - }, - }, - { - icon: '', - name: '', - callback: (t) => { - this._editOwnedItemById(t.data("item-id")); - }, - }, - { - icon: '', - name: '', - callback: (t) => { - this._deleteOwnedItemById(t.data("item-id")); - }, - condition: (t) => { - if (t.data("coreskill")) { - return t.data("coreskill").length < 1; - } else { - return true; - } - }, - }, - ]; - new ContextMenu(html,".editable-item", menu_items); - - - // ! DON'T LET NUMBER FIELDS EMPTY - const numInputs = document.querySelectorAll('input[type=number]'); - numInputs.forEach(function (input) { - input.addEventListener('change', function (e) { - if (e.target.value == '') { - e.target.value = 0 - } - }) - }); - } - - - - _editOwnedItemById(_itemId) { - const item = this.actor.items.get(_itemId); - item.sheet.render(true); - } - async _deleteOwnedItemById(_itemId) { - const item = this.actor.items.get(_itemId); - await item.delete(); - } - _onPostItem(_itemId) { - const item = this.actor.items.get(_itemId); - item.sendToChat(); - } - - // * UTILS - _clearTextAreaText(txt) { - txt.trim(); - txt = txt.replace(/ +/g, ' '); - //! replace new lines with encided \n so stupid textarea doesn't break - txt = txt.replace(/(?:\r\n|\r|\n)/g, ' '); - return txt; - }; - - /** + let menu_items = [ + { + icon: '', + name: "", + + callback: t => { + this._onPostItem(t.data("item-id")); + }, + }, + { + icon: '', + name: "", + callback: t => { + this._editOwnedItemById(t.data("item-id")); + }, + }, + { + icon: '', + name: "", + callback: t => { + this._deleteOwnedItemById(t.data("item-id")); + }, + condition: t => { + if (t.data("coreskill")) { + return t.data("coreskill").length < 1; + } + else { + return true; + } + }, + }, + ]; + + new ContextMenu(html, ".editable-item", menu_items); + + + // ! DON'T LET NUMBER FIELDS EMPTY + const numInputs = document.querySelectorAll("input[type=number]"); + numInputs.forEach(function(input) { + input.addEventListener("change", function(e) { + if (e.target.value === "") { + e.target.value = 0; + } + }); + }); + } + + + _editOwnedItemById(_itemId) { + const item = this.actor.items.get(_itemId); + item.sheet.render(true); + } + + async _deleteOwnedItemById(_itemId) { + const item = this.actor.items.get(_itemId); + await item.delete(); + } + + _onPostItem(_itemId) { + const item = this.actor.items.get(_itemId); + item.sendToChat(); + } + + // * UTILS + _clearTextAreaText(txt) { + txt.trim(); + txt = txt.replace(/ +/g, " "); + // ! replace new lines with encided \n so stupid textarea doesn't break + txt = txt.replace(/(?:\r\n|\r|\n)/g, " "); + return txt; + } + + /** * Handle creating a new Owned Item for the actor using initial data defined in the HTML dataset * @param {Event} event The originating click event * @private */ - async _onItemCreate(event) { - event.preventDefault(); - const header = event.currentTarget; - // Get the type of item to create. - const type = header.dataset.type; - // Grab any data associated with this control. - const data = duplicate(header.dataset); - // Initialize a default name. - const name = `New ${type.capitalize()}`; - // Prepare the item object. - const itemData = { - name: name, - type: type, - data: data - }; - // Remove the type from the dataset since it's in the itemData.type prop. - delete itemData.data["type"]; - // Finally, create the item! - return await Item.create(itemData, { parent: this.actor }); - } - - async _onRightClickDelete(itemId) { - const item = this.actor.items.get(itemId); - await item.delete(); - //li.slideUp(200, () => this.render(false)); - } - - _onRightClickSkill(itemId, attribute) { - const item = this.actor.items.get(itemId); - this._onRollSkill(item.name, item.system.value, this.actor.system.attributes[attribute].value, item.system.focus); - } - _onRollSkill(skillName, rank, attribute, focus) { - let complication = 20 - this.actor.getComplicationFromInjuries(); - game.ac2d20.Dialog2d20.createDialog({ rollName: skillName, diceNum: 2, attribute: -1, skill: rank, focus: focus, complication: complication, actor: this.actor.system }) - } - - async _onItemSummary(event) { - event.preventDefault(); - let li = $(event.currentTarget).parents(".item"); - let item = this.actor.items.get(li.data("itemId")); - // Toggle summary - if (li.hasClass("expanded")) { - let summary = li.children(".item-summary"); - summary.slideUp(200, () => { - summary.remove(); - }); - } else { - let _descriptionText = await TextEditor.enrichHTML(item.system.description, {async:true}) - let div = $( - `
${_descriptionText}
` - ); - li.append(div.hide()); - div.slideDown(200); - } - li.toggleClass("expanded"); - } - - - // Toggle Stashed Item - _toggleStashed(id, item) { - return { - _id: id, - data: { - stashed: !item.system.stashed, - }, - }; - } - - // Toggle Equipment - _toggleEquipped(id, item) { - return { - _id: id, - data: { - equipped: !item.system.equipped, - }, - }; - } - - // Toggle Favorite - _toggleFavorite(id, item) { - return { - _id: id, - data: { - favorite: !item.system.favorite, - }, - }; - } + async _onItemCreate(event) { + event.preventDefault(); + const header = event.currentTarget; + // Get the type of item to create. + const type = header.dataset.type; + // Grab any data associated with this control. + const data = duplicate(header.dataset); + // Initialize a default name. + const name = `New ${type.capitalize()}`; + // Prepare the item object. + const itemData = { + name: name, + type: type, + data: data, + }; + // Remove the type from the dataset since it's in the itemData.type prop. + delete itemData.data.type; + // Finally, create the item! + return await Item.create(itemData, { parent: this.actor }); + } + + async _onRightClickDelete(itemId) { + const item = this.actor.items.get(itemId); + await item.delete(); + // li.slideUp(200, () => this.render(false)); + } + + _onRightClickSkill(itemId, attribute) { + const item = this.actor.items.get(itemId); + this._onRollSkill( + item.name, + item.system.value, + this.actor.system.attributes[attribute].value, + item.system.focus + ); + } + + _onRollSkill(skillName, rank, attribute, focus) { + let complication = 20 - this.actor.getComplicationFromInjuries(); + game.ac2d20.Dialog2d20.createDialog({ + rollName: skillName, + diceNum: 2, + attribute: -1, + skill: rank, + focus: focus, + complication: complication, + actor: this.actor.system, + }); + } + + async _onItemSummary(event) { + event.preventDefault(); + let li = $(event.currentTarget).parents(".item"); + let item = this.actor.items.get(li.data("itemId")); + // Toggle summary + if (li.hasClass("expanded")) { + let summary = li.children(".item-summary"); + summary.slideUp(200, () => { + summary.remove(); + }); + } + else { + let _descriptionText = await TextEditor.enrichHTML( + item.system.description, {async: true} + ); + + let div = $(`
${_descriptionText}
`); + + li.append(div.hide()); + div.slideDown(200); + } + li.toggleClass("expanded"); + } + + + // Toggle Stashed Item + _toggleStashed(id, item) { + return { + _id: id, + data: { + stashed: !item.system.stashed, + }, + }; + } + + // Toggle Equipment + _toggleEquipped(id, item) { + return { + _id: id, + data: { + equipped: !item.system.equipped, + }, + }; + } + + // Toggle Favorite + _toggleFavorite(id, item) { + return { + _id: id, + data: { + favorite: !item.system.favorite, + }, + }; + } } diff --git a/system/src/sheets/item-sheet.mjs b/system/src/sheets/item-sheet.mjs index 6db9bec..3517ebd 100644 --- a/system/src/sheets/item-sheet.mjs +++ b/system/src/sheets/item-sheet.mjs @@ -6,119 +6,119 @@ import { onManageActiveEffect, prepareActiveEffectCategories } from "../helpers/ */ export class ACItemSheet extends ItemSheet { - /** @override */ - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - classes: ["ac2d20", "sheet", "item"], - width: 520, - height: 560, - tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }] - }); - } - - /** @override */ - get template() { - const path = "systems/ac2d20/templates/item"; - return `${path}/item-${this.item.type}-sheet.html`; - } - - /* -------------------------------------------- */ - - /** @override */ - async getData() { - // Retrieve base data structure. - const context = await super.getData(); - const item = context.item; - const source = item.toObject(); - - // Use a safe clone of the item data for further operations. - //const itemData = context.item.data; - - foundry.utils.mergeObject(context, { - source: source.system, - system: item.system, - isEmbedded: item.isEmbedded, - type: item.type, - flags: item.flags, - AC2D20: CONFIG.AC2D20, - effects: prepareActiveEffectCategories(item.effects), - descriptionHTML: await TextEditor.enrichHTML(item.system.description, { - secrets: item.isOwner, - async: true - }) - }); - - // Retrieve the roll data for TinyMCE editors. - context.rollData = {}; - let actor = this.object?.parent ?? null; - if (actor) { - context.rollData = actor.getRollData(); - } - - // Add the actor's data to context.data for easier access, as well as flags. - //context.data = itemData.data; - //context.flags = itemData.flags; - - //context.effects = prepareActiveEffectCategories(this.item.effects); - //context.AC2D20 = CONFIG.AC2D20; - - - // Prepare Aditional Data - // if (itemData.type == 'apaprel') { - //context.apparelTypes = CONFIG.AC2D20.APPAREL_TYPE; - //} - - return context; - } - - /* -------------------------------------------- */ - - /** @override */ - activateListeners(html) { - super.activateListeners(html); - - // Everything below here is only needed if the sheet is editable - if (!this.isEditable) return; - - // SKILL AND FOCUS - html.find('.focus-add').click(async (ev) => { - await this.item.addFocus(); - }); - - html.find('.focus-delete').click(async (ev) => { - await this.item.deleteFocus($(ev.currentTarget).data('index')); - }); - - html.find('.focus-title, .focus-cb').change(async (ev) => { - let focuses = []; - html.find(".focus-item").each(function (index) { - focuses = [...focuses, { - title: $(this).find('.focus-title').val(), - isfocus: $(this).find('.focus-cb').is(':checked') - }]; - }); - await this.item.updateFocuses(focuses) - }); - - // Effects. - html.find(".effect-control").click(ev => { - if (this.item.isOwned) return ui.notifications.warn("Managing Active Effects within an Owned Item is not currently supported and will be added in a subsequent update.") - onManageActiveEffect(ev, this.item) - }); - - // Send to Chat - html.find(".post-item").click((ev) => { - this.item.sendToChat(); - }) - - // DON't LET NUMBER FIELDS EMPTY - const numInputs = document.querySelectorAll('input[type=number]'); - numInputs.forEach(function (input) { - input.addEventListener('change', function (e) { - if (e.target.value == '') { - e.target.value = 0 - } - }) - }); - } + /** @override */ + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + classes: ["ac2d20", "sheet", "item"], + width: 520, + height: 560, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "attributes" }], + }); + } + + /** @override */ + get template() { + const path = "systems/ac2d20/templates/item"; + return `${path}/item-${this.item.type}-sheet.hbs`; + } + + /* -------------------------------------------- */ + + /** @override */ + async getData() { + // Retrieve base data structure. + const context = await super.getData(); + const item = context.item; + const source = item.toObject(); + + // Use a safe clone of the item data for further operations. + // const itemData = context.item.data; + + foundry.utils.mergeObject(context, { + source: source.system, + system: item.system, + isEmbedded: item.isEmbedded, + type: item.type, + flags: item.flags, + AC2D20: CONFIG.AC2D20, + effects: prepareActiveEffectCategories(item.effects), + descriptionHTML: await TextEditor.enrichHTML(item.system.description, { + secrets: item.isOwner, + async: true, + }), + }); + + // Retrieve the roll data for TinyMCE editors. + context.rollData = {}; + let actor = this.object?.parent ?? null; + if (actor) { + context.rollData = actor.getRollData(); + } + + // Add the actor's data to context.data for easier access, as well as flags. + // context.data = itemData.data; + // context.flags = itemData.flags; + + // context.effects = prepareActiveEffectCategories(this.item.effects); + // context.AC2D20 = CONFIG.AC2D20; + + + // Prepare Aditional Data + // if (itemData.type == 'apaprel') { + // context.apparelTypes = CONFIG.AC2D20.APPAREL_TYPE; + // } + + return context; + } + + /* -------------------------------------------- */ + + /** @override */ + activateListeners(html) { + super.activateListeners(html); + + // Everything below here is only needed if the sheet is editable + if (!this.isEditable) return; + + // SKILL AND FOCUS + html.find(".focus-add").click(async ev => { + await this.item.addFocus(); + }); + + html.find(".focus-delete").click(async ev => { + await this.item.deleteFocus($(ev.currentTarget).data("index")); + }); + + html.find(".focus-title, .focus-cb").change(async ev => { + let focuses = []; + html.find(".focus-item").each(function(index) { + focuses = [...focuses, { + title: $(this).find(".focus-title").val(), + isfocus: $(this).find(".focus-cb").is(":checked"), + }]; + }); + await this.item.updateFocuses(focuses); + }); + + // Effects. + html.find(".effect-control").click(ev => { + if (this.item.isOwned) return ui.notifications.warn("Managing Active Effects within an Owned Item is not currently supported and will be added in a subsequent update."); + onManageActiveEffect(ev, this.item); + }); + + // Send to Chat + html.find(".post-item").click(ev => { + this.item.sendToChat(); + }); + + // DON't LET NUMBER FIELDS EMPTY + const numInputs = document.querySelectorAll("input[type=number]"); + numInputs.forEach(function(input) { + input.addEventListener("change", function(e) { + if (e.target.value === "") { + e.target.value = 0; + } + }); + }); + } } diff --git a/system/src/sheets/npc-sheet.mjs b/system/src/sheets/npc-sheet.mjs index 4be1f18..3c26b52 100644 --- a/system/src/sheets/npc-sheet.mjs +++ b/system/src/sheets/npc-sheet.mjs @@ -1,5 +1,5 @@ -import { AC2D20 } from "../helpers/config.mjs"; -import { onManageActiveEffect, prepareActiveEffectCategories } from "../helpers/effects.mjs"; +// import { AC2D20 } from "../helpers/config.mjs"; +// import { onManageActiveEffect, prepareActiveEffectCategories } from "../helpers/effects.mjs"; import { ACActorSheet } from "./actor-sheet.mjs"; /** @@ -8,14 +8,14 @@ import { ACActorSheet } from "./actor-sheet.mjs"; */ export class ACNPCSheet extends ACActorSheet { - /** @override */ - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - classes: ["ac2d20", "sheet", "actor"], - template: "systems/ac2d20/templates/actor/npc-sheet.html", - width: 550, - height: 780, - tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "abilities" }] - }); - } + /** @override */ + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + classes: ["ac2d20", "sheet", "actor"], + template: "systems/ac2d20/templates/actor/npc-sheet.hbs", + width: 550, + height: 780, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "abilities" }], + }); + } } diff --git a/system/src/sheets/vehicle-sheet.mjs b/system/src/sheets/vehicle-sheet.mjs index 408a27c..71a67b0 100644 --- a/system/src/sheets/vehicle-sheet.mjs +++ b/system/src/sheets/vehicle-sheet.mjs @@ -1,5 +1,5 @@ -import { AC2D20 } from "../helpers/config.mjs"; -import { onManageActiveEffect, prepareActiveEffectCategories } from "../helpers/effects.mjs"; +// import { AC2D20 } from "../helpers/config.mjs"; +// import { onManageActiveEffect, prepareActiveEffectCategories } from "../helpers/effects.mjs"; import { ACActorSheet } from "./actor-sheet.mjs"; /** @@ -8,14 +8,14 @@ import { ACActorSheet } from "./actor-sheet.mjs"; */ export class ACVehicleSheet extends ACActorSheet { - /** @override */ - static get defaultOptions() { - return mergeObject(super.defaultOptions, { - classes: ["ac2d20", "sheet", "actor"], - template: "systems/ac2d20/templates/actor/vehicle-sheet.html", - width: 550, - height: 550, - tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "abilities" }] - }); - } + /** @override */ + static get defaultOptions() { + return mergeObject(super.defaultOptions, { + classes: ["ac2d20", "sheet", "actor"], + template: "systems/ac2d20/templates/actor/vehicle-sheet.hbs", + width: 550, + height: 550, + tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "abilities" }], + }); + } } diff --git a/system/system.json b/system/system.json index 54ead80..aecdf36 100644 --- a/system/system.json +++ b/system/system.json @@ -2,7 +2,7 @@ "id": "ac2d20", "title": "Achtung! Cthulhu 2d20", "description": "The Unofficial Achtung! Cthulhu 2d20 System for FoundryVTT", - "version": "11.1.0", + "version": "11.1.2", "compatibility": { "minimum": "11", "verified": "11" @@ -59,13 +59,13 @@ { "lang": "en", "name": "English", - "path": "lang/en.json", + "path": "i18n/en.json", "flags": {} }, { "lang": "es", "name": "Español", - "path": "lang/es.json", + "path": "i18n/es.json", "flags": {} } ], @@ -73,7 +73,7 @@ "gridDistance": 1, "gridUnits": "m", "url": "https://github.com/Muttley/foundryvtt-ac2d20", - "manifest": "https://raw.githubusercontent.com/Muttley/foundryvtt-ac2d20/main/system/system.json", + "manifest": "https://github.com/Muttley/foundryvtt-ac2d20/releases/latest/download/system.json", "download": "https://github.com/Muttley/foundryvtt-ac2d20/releases/latest/download/ac2d20.zip", "initiative": null } diff --git a/system/template.json b/system/template.json index 23e51e2..a454af5 100644 --- a/system/template.json +++ b/system/template.json @@ -1,257 +1,478 @@ { "Actor": { - "types": ["character", "npc", "vehicle"], + "types": [ + "character", + "npc", + "vehicle" + ], "templates": { "base": { - "fortune":{ - "max":0, - "value":0 - }, - "injuries":{ - "count":3, - "value":0, - "treated":0, - "injury0":{ - "text":"", "injuryType":false, "treated":false + "biography": "", + "fortune": { + "max": 0, + "value": 0 + }, + "injuries": { + "count": 3, + "injury0": { + "injuryType": false, + "text": "", + "treated": false + }, + "injury1": { + "injuryType": false, + "text": "", + "treated": false + }, + "injury2": { + "injuryType": false, + "text": "", + "treated": false + }, + "list": [ + { + "injuryType": false, + "text": "", + "treated": false + }, + { + "injuryType": false, + "text": "", + "treated": false + }, + { + "injuryType": false, + "text": "", + "treated": false + } + ], + "treated": 0, + "value": 0 + }, + "truths": [ + { + "text": "" + }, + { + "text": "" }, - "injury1":{ - "text":"", "injuryType":false, "treated":false + { + "text": "" }, - "injury2":{ - "text":"", "injuryType":false, "treated":false + { + "text": "" }, - "list":[ - {"text":"", "injuryType":false, "treated":false}, - {"text":"", "injuryType":false, "treated":false}, - {"text":"", "injuryType":false, "treated":false}] - }, - "truthsText":"", - "truths":[ - {"text":""}, - {"text":""}, - {"text":""}, - {"text":""}, - {"text":""} + { + "text": "" + } ], - "biography":"" + "truthsText": "" + }, + "derived": { + "armorResistance": { + "max": 0, + "value": 0 + }, + "carryCapacity": { + "mod": 0, + "value": 6 + }, + "courageResistance": { + "max": 0, + "value": 0 + }, + "fatigue": 0, + "power": { + "max": 0, + "value": 0 + }, + "stress": { + "max": 0, + "value": 0 + } }, "stats": { "attributes": { "agi": { - "value": 6, - "bonus":0 + "bonus": 0, + "value": 6 }, "bra": { - "value": 6, - "bonus":0 + "bonus": 0, + "value": 6 }, "coo": { - "value": 6, - "bonus":0 + "bonus": 0, + "value": 6 }, "ins": { - "value": 6, - "bonus":0 + "bonus": 0, + "value": 6 }, "rea": { - "value": 6, - "bonus":0 + "bonus": 0, + "value": 6 }, "wil": { - "value": 6, - "bonus":0 + "bonus": 0, + "value": 6 } } - }, - "derived": { - "stress":{ - "max":0, - "value":0 - }, - "armorResistance":{ - "max":0, - "value":0 - }, - "courageResistance":{ - "max":0, - "value":0 - }, - "power":{ - "max":0, - "value":0 - }, - "carryCapacity":{ - "value":6, - "mod":0 - }, - "fatigue":0 } }, "character": { - "templates": ["base", "stats", "derived"], - "nationality":"", - "rank":"", - "archetype":"", - "background":"", - "characteristic":"", - "spellcastingType":"traditional" + "archetype": "", + "background": "", + "characteristic": "", + "nationality": "", + "rank": "", + "spellcastingType": "traditional", + "templates": [ + "base", + "derived", + "stats" + ] }, "npc": { - "templates": ["base", "derived", "stats"], - "level":"trooper", - "truthsText":"", - "spellcastingType":"traditional" + "level": "trooper", + "spellcastingType": "traditional", + "templates": [ + "base", + "derived", + "stats" + ], + "truthsText": "" }, "vehicle": { - "templates": ["base", "derived", "stats"], - "truthsText":"", - "speed":{"value":0, "max":0}, - "scale":0, - "cover":{"value": "0", "max":0}, - "impact":0, - "passengers":{"value":"1", "pilots":[], "gunners":[]}, - "qualities":{ - "cargo":{"value": false, "rank": 1, "description": "" }, - "cumbersome":{"value": false, "description": "" }, - "enclosed":{"value": false, "description": "" }, - "exposed":{"value": false, "description": "" }, - "highPerformance":{"value": false, "description": "" }, - "singleSeat:":{"value": false, "description": "" }, - "tough":{"value": false, "rank": 1, "description": "" } - } + "cover": { + "max": 0, + "value": "0" + }, + "impact": 0, + "passengers": { + "gunners": [], + "pilots": [], + "value": "1" + }, + "qualities": { + "cargo": { + "description": "", + "rank": 1, + "value": false + }, + "cumbersome": { + "description": "", + "value": false + }, + "enclosed": { + "description": "", + "value": false + }, + "exposed": { + "description": "", + "value": false + }, + "highPerformance": { + "description": "", + "value": false + }, + "singleSeat:": { + "description": "", + "value": false + }, + "tough": { + "description": "", + "rank": 1, + "value": false + } + }, + "scale": 0, + "speed": { + "max": 0, + "value": 0 + }, + "templates": [ + "base", + "derived", + "stats" + ], + "truthsText": "" } }, "Item": { "types": [ - "weapon", "armor", - "talent", - "spell", - "skillkit", "equipment", + "skill", + "skillkit", "special_rule", - "skill" + "spell", + "talent", + "weapon" ], "templates": { "base": { "description": "", "favorite": false }, + "equipable": { + "equippable": true, + "equipped": false + }, "physical": { - "size":0, - "weight": 0, "cost": 0, "quantity": 1, "rarity": 0, + "restriction": 0, + "size": 0, "stashed": false, - "restriction":0 - }, - "equipable": { - "equippable": true, - "equipped": false + "weight": 0 } }, + "armor": { + "qualities": { + "heavy": { + "description": "", + "label": "Heavy", + "value": false + }, + "shield": { + "description": "", + "label": "Shield", + "value": false + }, + "uncomfortable": { + "description": "", + "label": "Uncomfortable", + "value": false + } + }, + "resistance": 1, + "templates": [ + "base", + "physical", + "equipable" + ] + }, + "equipment": { + "templates": [ + "base", + "physical", + "equipable" + ] + }, "skill": { - "templates": ["base"], - "value": 0, - "focuses": [], "defaultAttribute": "agi", - "summary": "" + "focuses": [], + "summary": "", + "templates": [ + "base" + ], + "value": 0 + }, + "skillkit": { + "resources": 3, + "skill": "", + "templates": [ + "base", + "physical", + "equipable" + ] }, - "talent":{ - "templates": ["base"], - "keywords":"" + "special_rule": { + "templates": [ + "base" + ] }, - "spell":{ - "templates": ["base"], - "skill":"", - "focus":"", - "difficulty":1, - "cost":1, - "costEffects":"", - "damage":0, - "damageFormula":"", - "damageStressType":"", - "damageEffects":"", - "duration":"", - "effect":"", - "flawed":"", - "momentum":"", - "complication":20, - "bonusChallenge":0, - "spellType":"ins", - "mantle":false, - "ritualStress":{ - "value":0, - "max":0 + "spell": { + "bonusChallenge": 0, + "complication": 20, + "cost": 1, + "costEffects": "", + "damage": 0, + "damageEffects": "", + "damageFormula": "", + "damageStressType": "", + "difficulty": 1, + "duration": "", + "effect": "", + "flawed": "", + "focus": "", + "mantle": false, + "momentum": "", + "ritualRequirements": "", + "ritualResistance": "", + "ritualSteps": { + "max": 0, + "value": 0 }, - "ritualSteps":{ - "value":0, - "max":0 + "ritualStress": { + "max": 0, + "value": 0 }, - "ritualResistance":"", - "ritualRequirements":"" + "skill": "Academia", + "spellType": "ins", + "templates": [ + "base" + ] + }, + "talent": { + "keywords": "", + "templates": [ + "base" + ] }, "weapon": { - "templates": ["base", "physical", "equipable"], + "ammo": 0, + "effect": { + "area": { + "description": "", + "label": "Area", + "value": false + }, + "backlash": { + "description": "", + "label": "Backlash", + "rank": 1, + "value": false + }, + "drain": { + "description": "", + "label": "Drain", + "value": false + }, + "intense": { + "description": "", + "label": "Intense", + "value": false + }, + "persistent": { + "description": "", + "label": "Persistent", + "rank": 1, + "value": false + }, + "piercing": { + "description": "", + "label": "Piercing", + "rank": 1, + "value": false + }, + "snare": { + "description": "", + "label": "Snare", + "value": false + }, + "stun": { + "description": "", + "label": "Stun", + "value": false + }, + "vicious": { + "description": "", + "label": "Vicious", + "value": false + } + }, + "focus": "", "melee": false, - "weaponType": "agi", - "range":"close", - "focus":"", - "stress":0, - "ammo":0, - "skill":"", - "effect":{ - "area": { "label": "Area", "value": false, "description": "" }, - "backlash": { "label": "Backlash", "value": false, "rank": 1, "description": "" }, - "drain": { "label": "Drain", "value": false, "description": "" }, - "intense": { "label": "Intense", "value": false, "description": "" }, - "persistent": { "label": "Persistent", "value": false, "rank": 1, "description": "" }, - "piercing": { "label": "Piercing", "value": false, "rank": 1, "description": "" }, - "snare": { "label": "Snare", "value": false, "description": "" }, - "stun": { "label": "Stun", "value": false, "description": "" }, - "vicious": { "label": "Vicious", "value": false, "description": "" } + "qualities": { + "accurate": { + "description": "", + "label": "Accurate", + "value": false + }, + "bane": { + "description": "", + "label": "Bane", + "value": false + }, + "closeQuarters": { + "description": "", + "label": "Close Quarters", + "value": false + }, + "cumbersome": { + "description": "", + "label": "Cumbersome", + "value": false + }, + "debilitating": { + "description": "", + "label": "Debilitating", + "value": false + }, + "escalation": { + "description": "", + "label": "Escalation", + "value": false + }, + "giant-killer": { + "description": "", + "label": "Giant-Killer", + "value": false + }, + "heavy": { + "description": "", + "label": "Heavy", + "value": false + }, + "hidden": { + "description": "", + "label": "Hidden", + "value": false + }, + "hunger": { + "description": "", + "label": "Hunger", + "value": false + }, + "inaccurate": { + "description": "", + "label": "Inaccurate", + "value": false + }, + "indirect": { + "description": "", + "label": "Indirect", + "value": false + }, + "munition": { + "description": "", + "label": "Munition", + "value": false + }, + "parrying": { + "description": "", + "label": "Parrying", + "value": false + }, + "reliable": { + "description": "", + "label": "Reliable", + "value": false + }, + "subtle": { + "description": "", + "label": "Subtle", + "value": false + }, + "unreliable": { + "description": "", + "label": "Unreliable", + "value": false + } }, - "salvo":"", - "qualities":{ - "accurate": { "label": "Accurate", "value": false, "description": "" }, - "bane": { "label": "Bane", "value": false, "description": "" }, - "closeQuarters": { "label": "Close Quarters", "value": false, "description": "" }, - "cumbersome": { "label": "Cumbersome", "value": false, "description": "" }, - "debilitating": { "label": "Debilitating", "value": false, "description": "" }, - "escalation": { "label": "Escalation", "value": false, "description": "" }, - "giant-killer": { "label": "Giant-Killer", "value": false, "description": "" }, - "heavy": { "label": "Heavy", "value": false, "description": "" }, - "hidden": { "label": "Hidden", "value": false, "description": "" }, - "hunger": { "label": "Hunger", "value": false, "description": "" }, - "inaccurate": { "label": "Inaccurate", "value": false, "description": "" }, - "indirect": { "label": "Indirect", "value": false, "description": "" }, - "munition": { "label": "Munition", "value": false, "description": "" }, - "parrying": { "label": "Parrying", "value": false, "description": "" }, - "reliable": { "label": "Reliable", "value": false, "description": "" }, - "subtle": { "label": "Subtle", "value": false, "description": "" }, - "unreliable": { "label": "Unreliable", "value": false, "description": "" } - } - }, - "armor":{ - "templates": ["base", "physical", "equipable"], - "resistance":1, - "qualities":{ - "heavy": { "label": "Heavy", "value": false, "description": "" }, - "uncomfortable": { "label": "Uncomfortable", "value": false, "description": "" }, - "shield": { "label": "Shield", "value": false, "description": "" } - } - }, - "skillkit":{ - "templates": ["base", "physical", "equipable"], - "skill":"", - "resources":3 - }, - "equipment":{ - "templates": ["base", "physical", "equipable"] - }, - "special_rule":{ - "templates": ["base"] + "range": "close", + "salvo": "", + "skill": "", + "stress": 0, + "templates": [ + "base", + "physical", + "equipable" + ], + "weaponType": "agi" } } } diff --git a/system/templates/actor/actor-character-sheet.html b/system/templates/actor/actor-character-sheet.hbs similarity index 77% rename from system/templates/actor/actor-character-sheet.html rename to system/templates/actor/actor-character-sheet.hbs index a97f5f6..8ced9ac 100644 --- a/system/templates/actor/actor-character-sheet.html +++ b/system/templates/actor/actor-character-sheet.hbs @@ -16,35 +16,35 @@ {{!-- Sheet Header --}} - {{> "systems/ac2d20/templates/actor/parts/actor-header.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-header.hbs"}} {{!-- Sheet Body --}}
{{!-- Owned skills Tab --}} -
{{> "systems/ac2d20/templates/actor/parts/actor-abilities.html"}}
+
{{> "systems/ac2d20/templates/actor/parts/actor-abilities.hbs"}}
{{!-- Talents Tab --}}
- {{> "systems/ac2d20/templates/actor/parts/actor-talents.html" itemsEnrichedDescriptions=itemsEnrichedDescriptions}} + {{> "systems/ac2d20/templates/actor/parts/actor-talents.hbs" itemsEnrichedDescriptions=itemsEnrichedDescriptions}}
{{!-- Spells Tab --}}
- {{> "systems/ac2d20/templates/actor/parts/actor-spells.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-spells.hbs"}}
{{!-- Inventory Tab --}}
- {{> "systems/ac2d20/templates/actor/parts/actor-encumbrance.html"}} - {{> "systems/ac2d20/templates/actor/parts/actor-weapons.html"}} - {{> "systems/ac2d20/templates/actor/parts/actor-armor.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-encumbrance.hbs"}} + {{> "systems/ac2d20/templates/actor/parts/actor-weapons.hbs"}} + {{> "systems/ac2d20/templates/actor/parts/actor-armor.hbs"}}
- {{> "systems/ac2d20/templates/actor/parts/actor-skillkit.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-skillkit.hbs"}}
- {{> "systems/ac2d20/templates/actor/parts/actor-equipment.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-equipment.hbs"}}
@@ -57,8 +57,8 @@ {{!-- Active Effects Tab --}}
- {{> "systems/ac2d20/templates/actor/parts/actor-effects.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-effects.hbs"}}
- \ No newline at end of file + diff --git a/system/templates/actor/actor-npc-sheet.html b/system/templates/actor/actor-npc-sheet.hbs similarity index 89% rename from system/templates/actor/actor-npc-sheet.html rename to system/templates/actor/actor-npc-sheet.hbs index efcaa3b..79d823c 100644 --- a/system/templates/actor/actor-npc-sheet.html +++ b/system/templates/actor/actor-npc-sheet.hbs @@ -12,13 +12,13 @@ {{!-- Sheet Header --}} - {{> "systems/ac2d20/templates/actor/parts/npc-header.html"}} + {{> "systems/ac2d20/templates/actor/parts/npc-header.hbs"}} {{!-- Sheet Body --}}
{{!-- Abilities Tab !!! DONT INDENT OR TEXT AREAS INSIDE WILL BREAK !!! --}} -
{{> "systems/ac2d20/templates/actor/parts/npc-abilities.html"}}
+
{{> "systems/ac2d20/templates/actor/parts/npc-abilities.hbs"}}
{{!-- Biography Tab --}}
@@ -28,8 +28,8 @@ {{!-- Active Effects Tab --}}
- {{> "systems/ac2d20/templates/actor/parts/actor-effects.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-effects.hbs"}}
- \ No newline at end of file + diff --git a/system/templates/actor/actor-vehicle-sheet.html b/system/templates/actor/actor-vehicle-sheet.hbs similarity index 93% rename from system/templates/actor/actor-vehicle-sheet.html rename to system/templates/actor/actor-vehicle-sheet.hbs index 0458514..ee8b7a0 100644 --- a/system/templates/actor/actor-vehicle-sheet.html +++ b/system/templates/actor/actor-vehicle-sheet.hbs @@ -12,13 +12,13 @@ {{!-- Sheet Header --}} - {{> "systems/ac2d20/templates/actor/parts/vehicle-header.html"}} + {{> "systems/ac2d20/templates/actor/parts/vehicle-header.hbs"}} {{!-- Sheet Body --}}
{{!-- Abilities Tab --}} -
{{> "systems/ac2d20/templates/actor/parts/vehicle-abilities.html"}}
+
{{> "systems/ac2d20/templates/actor/parts/vehicle-abilities.hbs"}}
{{!-- Biography Tab --}}
@@ -28,8 +28,8 @@ {{!-- Active Effects Tab --}}
- {{> "systems/ac2d20/templates/actor/parts/actor-effects.html"}} + {{> "systems/ac2d20/templates/actor/parts/actor-effects.hbs"}}
- \ No newline at end of file + diff --git a/system/templates/actor/parts/actor-abilities.html b/system/templates/actor/parts/actor-abilities.hbs similarity index 95% rename from system/templates/actor/parts/actor-abilities.html rename to system/templates/actor/parts/actor-abilities.hbs index 33c580a..f0e6abd 100644 --- a/system/templates/actor/parts/actor-abilities.html +++ b/system/templates/actor/parts/actor-abilities.hbs @@ -79,34 +79,34 @@

{{localize "AC2D20.TEMPLATES.INJURIES"}}

-
+
{{#if (hasInjury system.injuries.injury0.text)}}

- {{/if}} + {{/if}}
-
+
{{#if (hasInjury system.injuries.injury1.text)}}

- {{/if}} + {{/if}}
-
+
{{#if (hasInjury system.injuries.injury2.text)}}

- {{/if}} + {{/if}}
@@ -128,9 +128,9 @@

{{localize "AC2D20.TEMPLATES.Skills"}}

{{#each item.system.focuses}} - {{this.title}},  + {{this.title}},  {{/each}}
{{/each}} -
\ No newline at end of file + diff --git a/system/templates/actor/parts/actor-armor.html b/system/templates/actor/parts/actor-armor.hbs similarity index 100% rename from system/templates/actor/parts/actor-armor.html rename to system/templates/actor/parts/actor-armor.hbs diff --git a/system/templates/actor/parts/actor-effects.html b/system/templates/actor/parts/actor-effects.hbs similarity index 100% rename from system/templates/actor/parts/actor-effects.html rename to system/templates/actor/parts/actor-effects.hbs diff --git a/system/templates/actor/parts/actor-encumbrance.html b/system/templates/actor/parts/actor-encumbrance.hbs similarity index 100% rename from system/templates/actor/parts/actor-encumbrance.html rename to system/templates/actor/parts/actor-encumbrance.hbs diff --git a/system/templates/actor/parts/actor-equipment.html b/system/templates/actor/parts/actor-equipment.hbs similarity index 87% rename from system/templates/actor/parts/actor-equipment.html rename to system/templates/actor/parts/actor-equipment.hbs index 98103af..45072a2 100644 --- a/system/templates/actor/parts/actor-equipment.html +++ b/system/templates/actor/parts/actor-equipment.hbs @@ -1,5 +1,5 @@
-

{{localize "ITEM.TypeEquipment"}}     +

+

{{localize "TYPES.Item.equipment"}}     +

@@ -20,4 +20,4 @@

{{localize "ITEM.TypeEquipment"}} {{/each}} - \ No newline at end of file + diff --git a/system/templates/actor/parts/actor-header.html b/system/templates/actor/parts/actor-header.hbs similarity index 100% rename from system/templates/actor/parts/actor-header.html rename to system/templates/actor/parts/actor-header.hbs diff --git a/system/templates/actor/parts/actor-skillkit.html b/system/templates/actor/parts/actor-skillkit.hbs similarity index 90% rename from system/templates/actor/parts/actor-skillkit.html rename to system/templates/actor/parts/actor-skillkit.hbs index 4f3f934..d71bb33 100644 --- a/system/templates/actor/parts/actor-skillkit.html +++ b/system/templates/actor/parts/actor-skillkit.hbs @@ -1,5 +1,5 @@
-

{{localize "ITEM.TypeSkillkit"}}     +

+

{{localize "TYPES.Item.skillkit"}}     +

@@ -27,4 +27,4 @@

{{localize "ITEM.TypeSkillkit"}} {{/each}} - \ No newline at end of file + diff --git a/system/templates/actor/parts/actor-spells.html b/system/templates/actor/parts/actor-spells.hbs similarity index 89% rename from system/templates/actor/parts/actor-spells.html rename to system/templates/actor/parts/actor-spells.hbs index 0af7be8..4dddb9e 100644 --- a/system/templates/actor/parts/actor-spells.html +++ b/system/templates/actor/parts/actor-spells.hbs @@ -35,10 +35,23 @@

{{localize "AC2D20.TEMPLATES.Power"}}

{{#each spells as |item key|}}
-
{{item.name}}
-
 {{item.system.skill}} ({{item.system.focus}})
+
+ + {{item.name}} +
+
+  {{item.system.skill}} + {{#if item.system.focus}} + ({{item.system.focus}}) + {{/if}} +
{{item.system.difficulty}}
-
{{item.system.cost}} {{item.system.costEffects}}
+
+ {{item.system.cost}} + {{#if item.system.costEffects}} + {{item.system.costEffects}} + {{/if}} +
{{item.system.duration}}
@@ -56,4 +69,4 @@

{{localize "AC2D20.TEMPLATES.Power"}}

{{/each}} - \ No newline at end of file + diff --git a/system/templates/actor/parts/actor-talents.html b/system/templates/actor/parts/actor-talents.hbs similarity index 100% rename from system/templates/actor/parts/actor-talents.html rename to system/templates/actor/parts/actor-talents.hbs diff --git a/system/templates/actor/parts/actor-weapons.html b/system/templates/actor/parts/actor-weapons.hbs similarity index 100% rename from system/templates/actor/parts/actor-weapons.html rename to system/templates/actor/parts/actor-weapons.hbs diff --git a/system/templates/actor/parts/npc-abilities.html b/system/templates/actor/parts/npc-abilities.hbs similarity index 100% rename from system/templates/actor/parts/npc-abilities.html rename to system/templates/actor/parts/npc-abilities.hbs diff --git a/system/templates/actor/parts/npc-header.html b/system/templates/actor/parts/npc-header.hbs similarity index 100% rename from system/templates/actor/parts/npc-header.html rename to system/templates/actor/parts/npc-header.hbs diff --git a/system/templates/actor/parts/simple-expandable-item.html b/system/templates/actor/parts/simple-expandable-item.hbs similarity index 100% rename from system/templates/actor/parts/simple-expandable-item.html rename to system/templates/actor/parts/simple-expandable-item.hbs diff --git a/system/templates/actor/parts/vehicle-abilities.html b/system/templates/actor/parts/vehicle-abilities.hbs similarity index 100% rename from system/templates/actor/parts/vehicle-abilities.html rename to system/templates/actor/parts/vehicle-abilities.hbs diff --git a/system/templates/actor/parts/vehicle-header.html b/system/templates/actor/parts/vehicle-header.hbs similarity index 100% rename from system/templates/actor/parts/vehicle-header.html rename to system/templates/actor/parts/vehicle-header.hbs diff --git a/system/templates/ap/momentum-tracker.html b/system/templates/ap/momentum-tracker.hbs similarity index 100% rename from system/templates/ap/momentum-tracker.html rename to system/templates/ap/momentum-tracker.hbs diff --git a/system/templates/chat/item.html b/system/templates/chat/item.hbs similarity index 82% rename from system/templates/chat/item.html rename to system/templates/chat/item.hbs index 0e60356..1cc83f4 100644 --- a/system/templates/chat/item.html +++ b/system/templates/chat/item.hbs @@ -46,11 +46,28 @@

{{name}}

{{/if}} {{#if isSpell}} -

{{localize "AC2D20.TEMPLATES.SpellType"}}: {{localize (concat 'AC2D20.SPELL.SpellTypes.' spellType)}}

-

{{localize "AC2D20.TEMPLATES.Skill"}}: {{skill}} ({{focus}})

-

{{localize "AC2D20.TEMPLATES.Difficulty"}}: {{difficulty}}

-

{{localize "AC2D20.TEMPLATES.Cost"}}: {{cost}} ({{costEffects}})

-

{{localize "AC2D20.TEMPLATES.Duration"}}: {{duration}}

+

+ {{localize "AC2D20.TEMPLATES.Skill"}}: + {{skill}} + {{#if focus}} + ({{focus}}) + {{/if}} +

+

+ {{localize "AC2D20.TEMPLATES.Difficulty"}}: + {{difficulty}} +

+

+ {{localize "AC2D20.TEMPLATES.Cost"}}: + {{cost}} + {{#if costEffects}} + ({{costEffects}}) + {{/if}} +

+

+ {{localize "AC2D20.TEMPLATES.Duration"}}: + {{duration}} +

{{/if}} {{#if isSkill}} @@ -67,4 +84,4 @@

{{name}}

{{{description}}}
- \ No newline at end of file + diff --git a/system/templates/chat/roll2d20.html b/system/templates/chat/roll2d20.hbs similarity index 100% rename from system/templates/chat/roll2d20.html rename to system/templates/chat/roll2d20.hbs diff --git a/system/templates/chat/rollD6.html b/system/templates/chat/rollD6.hbs similarity index 100% rename from system/templates/chat/rollD6.html rename to system/templates/chat/rollD6.hbs diff --git a/system/templates/combat/combat-tracker.html b/system/templates/combat/combat-tracker.hbs similarity index 100% rename from system/templates/combat/combat-tracker.html rename to system/templates/combat/combat-tracker.hbs diff --git a/system/templates/dialogs/dialog2d20.html b/system/templates/dialogs/dialog2d20.hbs similarity index 100% rename from system/templates/dialogs/dialog2d20.html rename to system/templates/dialogs/dialog2d20.hbs diff --git a/system/templates/item/item-armor-sheet.html b/system/templates/item/item-armor-sheet.hbs similarity index 96% rename from system/templates/item/item-armor-sheet.html rename to system/templates/item/item-armor-sheet.hbs index c9b7a08..00d1e1d 100644 --- a/system/templates/item/item-armor-sheet.html +++ b/system/templates/item/item-armor-sheet.hbs @@ -9,7 +9,7 @@ - {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Body --}}
@@ -49,4 +49,4 @@

{{localize "AC2D20.TEMPLATES.Description"}}

- \ No newline at end of file + diff --git a/system/templates/item/item-equipment-sheet.html b/system/templates/item/item-equipment-sheet.hbs similarity index 92% rename from system/templates/item/item-equipment-sheet.html rename to system/templates/item/item-equipment-sheet.hbs index cf8996c..d797b8a 100644 --- a/system/templates/item/item-equipment-sheet.html +++ b/system/templates/item/item-equipment-sheet.hbs @@ -9,7 +9,7 @@ - {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Body --}}
@@ -22,4 +22,4 @@

{{localize "AC2D20.TEMPLATES.Description"}}

{{editor descriptionHTML target="system.description" rollData=rollData button=true owner=owner editable=editable}}
- \ No newline at end of file + diff --git a/system/templates/item/item-item-sheet.html b/system/templates/item/item-item-sheet.hbs similarity index 94% rename from system/templates/item/item-item-sheet.html rename to system/templates/item/item-item-sheet.hbs index 579e676..56d4417 100644 --- a/system/templates/item/item-item-sheet.html +++ b/system/templates/item/item-item-sheet.hbs @@ -1,5 +1,5 @@
- {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Tab Navigation --}}
- {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Body --}}
@@ -41,4 +41,4 @@

{{localize "AC2D20.TEMPLATES.Description"}}

{{editor descriptionHTML target="system.description" rollData=rollData button=true owner=owner editable=editable}}
- \ No newline at end of file + diff --git a/system/templates/item/item-special_rule-sheet.html b/system/templates/item/item-special_rule-sheet.hbs similarity index 92% rename from system/templates/item/item-special_rule-sheet.html rename to system/templates/item/item-special_rule-sheet.hbs index cf8996c..d797b8a 100644 --- a/system/templates/item/item-special_rule-sheet.html +++ b/system/templates/item/item-special_rule-sheet.hbs @@ -9,7 +9,7 @@ - {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Body --}}
@@ -22,4 +22,4 @@

{{localize "AC2D20.TEMPLATES.Description"}}

{{editor descriptionHTML target="system.description" rollData=rollData button=true owner=owner editable=editable}}
- \ No newline at end of file + diff --git a/system/templates/item/item-spell-sheet.html b/system/templates/item/item-spell-sheet.hbs similarity index 98% rename from system/templates/item/item-spell-sheet.html rename to system/templates/item/item-spell-sheet.hbs index 678cbf6..ef2a9a8 100644 --- a/system/templates/item/item-spell-sheet.html +++ b/system/templates/item/item-spell-sheet.hbs @@ -9,7 +9,7 @@ - {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Body --}}
@@ -22,7 +22,7 @@ {{!-- Attributes Tab --}}
- +
@@ -103,4 +103,4 @@

{{localize "AC2D20.TEMPLATES.Ritual"}}

- \ No newline at end of file + diff --git a/system/templates/item/item-talent-sheet.html b/system/templates/item/item-talent-sheet.hbs similarity index 94% rename from system/templates/item/item-talent-sheet.html rename to system/templates/item/item-talent-sheet.hbs index 867464e..f3f4423 100644 --- a/system/templates/item/item-talent-sheet.html +++ b/system/templates/item/item-talent-sheet.hbs @@ -8,7 +8,7 @@ - {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Body --}}
@@ -29,4 +29,4 @@

{{localize "AC2D20.TEMPLATES.Description"}}

- \ No newline at end of file + diff --git a/system/templates/item/item-weapon-sheet.html b/system/templates/item/item-weapon-sheet.hbs similarity index 98% rename from system/templates/item/item-weapon-sheet.html rename to system/templates/item/item-weapon-sheet.hbs index 339db91..1325dcd 100644 --- a/system/templates/item/item-weapon-sheet.html +++ b/system/templates/item/item-weapon-sheet.hbs @@ -9,7 +9,7 @@ - {{> "systems/ac2d20/templates/item/parts/item-header.html"}} + {{> "systems/ac2d20/templates/item/parts/item-header.hbs"}} {{!-- Sheet Body --}}
@@ -129,4 +129,4 @@

{{localize "AC2D20.TEMPLATES.DAMAGE_EFFECTS"}}

- \ No newline at end of file + diff --git a/system/templates/item/parts/item-effects.html b/system/templates/item/parts/item-effects.hbs similarity index 100% rename from system/templates/item/parts/item-effects.html rename to system/templates/item/parts/item-effects.hbs diff --git a/system/templates/item/parts/item-header.html b/system/templates/item/parts/item-header.hbs similarity index 100% rename from system/templates/item/parts/item-header.html rename to system/templates/item/parts/item-header.hbs diff --git a/utils/javascript.mjs b/utils/javascript.mjs index ccb7244..4ab1b09 100644 --- a/utils/javascript.mjs +++ b/utils/javascript.mjs @@ -1,7 +1,6 @@ import { rollup } from "rollup"; import eslint from "gulp-eslint-new"; import gulp from "gulp"; -import livereload from "gulp-livereload"; import gulpIf from "gulp-if"; import mergeStream from "merge-stream"; import nodeResolve from "@rollup/plugin-node-resolve"; @@ -38,7 +37,7 @@ function lintJavascript() { return gulp .src(src) - .pipe(eslint({ fix: false })) + .pipe(eslint({ fix: true })) .pipe(eslint.format()) .pipe( gulpIf( @@ -55,7 +54,6 @@ export const lint = lintJavascript; // Watch for file changes and lint when they do // export async function watchJavascriptUpdates() { - livereload.listen(); gulp.watch(SRC_LINT_PATHS, gulp.parallel(lint, compile)); } export const watchUpdates = watchJavascriptUpdates;