├── .husky ├── .gitignore ├── pre-commit └── prepare-commit-msg ├── src ├── less │ ├── utils.less │ ├── dialog.less │ ├── ammo-mag.less │ ├── unit.less │ ├── t2k4e.less │ ├── symbols.less │ ├── encumbrance.less │ ├── tabs.less │ ├── flex-layout.css │ ├── flex-layout.less │ ├── inventory.less │ ├── grid-layout.less │ ├── party.less │ ├── journal.less │ ├── chat.less │ └── items.less ├── item │ └── templates │ │ ├── parts │ │ ├── item-description.hbs │ │ ├── item-header.hbs │ │ └── item-modifiers.hbs │ │ ├── specialty-sheet.hbs │ │ ├── injury-sheet.hbs │ │ ├── gear-sheet.hbs │ │ ├── armor-sheet.hbs │ │ └── grenade-sheet.hbs ├── actor │ ├── templates │ │ └── parts │ │ │ ├── actor-description.hbs │ │ │ ├── radiation-boxes.hbs │ │ │ ├── capacity-boxes.hbs │ │ │ ├── slots │ │ │ ├── gear-slot.hbs │ │ │ ├── ammo-slot.hbs │ │ │ ├── armor-slot.hbs │ │ │ ├── vehicle-weapon-slot.hbs │ │ │ ├── weapon-slot.hbs │ │ │ └── slot-buttons.hbs │ │ │ ├── vehicle-crew.hbs │ │ │ └── actor-stats.hbs │ ├── party │ │ ├── templates │ │ │ ├── components │ │ │ │ ├── member-component.hbs │ │ │ │ └── action-component.hbs │ │ │ ├── party-sheet.hbs │ │ │ └── sheet-tabs │ │ │ │ ├── main-tab.hbs │ │ │ │ └── travel-tab.hbs │ │ └── components │ │ │ ├── info-dialog.js │ │ │ ├── helpers.js │ │ │ └── character-picker-dialog.js │ └── unit │ │ ├── unitSheet.js │ │ └── unit-sheet.hbs ├── components │ ├── dialog │ │ └── templates │ │ │ ├── actor-choice-dialog.hbs │ │ │ ├── value-choice-dialog.hbs │ │ │ ├── damage-choice-dialog.hbs │ │ │ ├── cuf-dialog.hbs │ │ │ └── roll-dialog.hbs │ ├── chat │ │ └── templates │ │ │ ├── gear-chat.hbs │ │ │ ├── armor-chat.hbs │ │ │ ├── character-damage-chat.hbs │ │ │ └── weapon-chat.hbs │ ├── roll │ │ └── templates │ │ │ ├── roll.hbs │ │ │ ├── tooltip.hbs │ │ │ └── infos.hbs │ ├── armor.js │ ├── message-system.js │ └── modifier.js ├── utils │ ├── semver-compare.js │ ├── utils.js │ └── get-actor.js ├── system │ ├── statusEffects.js │ ├── enricher.js │ ├── settings.js │ └── handlebars.js └── lang │ └── uk.yml ├── pathconfig.example ├── .eslintignore ├── .gitattributes ├── static ├── fonts │ ├── roundels.ttf │ ├── Mukta-Bold.woff │ ├── daisywheel.otf │ ├── Mukta-Medium.woff │ ├── T2K4-Symbols.ttf │ ├── BlueHighway-Bold.woff │ ├── NunitoSans-ExtraBold.woff │ ├── Mukta.OFL.txt │ └── Nunito.OFL.txt ├── assets │ ├── t2k-banner.jpg │ ├── t2k-logo.webp │ ├── dice │ │ ├── dl │ │ │ ├── hit_A.png │ │ │ ├── hit_H.png │ │ │ ├── hit_L.png │ │ │ └── hit_T.png │ │ ├── d10 │ │ │ ├── t2k_d10_1.png │ │ │ ├── t2k_d10_6.png │ │ │ ├── t2k_d10_7.png │ │ │ ├── t2k_d10_8.png │ │ │ ├── t2k_d10_9.png │ │ │ ├── t2k_d10_10.png │ │ │ ├── t2k_d10_10_dsn.png │ │ │ ├── t2k_d10_1_dsn.png │ │ │ ├── t2k_d10_6_dsn.png │ │ │ ├── t2k_d10_7_dsn.png │ │ │ ├── t2k_d10_8_dsn.png │ │ │ ├── t2k_d10_9_dsn.png │ │ │ ├── t2k_d10_10_dsn_bump.png │ │ │ ├── t2k_d10_1_dsn_bump.png │ │ │ ├── t2k_d10_6_dsn_bump.png │ │ │ ├── t2k_d10_7_dsn_bump.png │ │ │ ├── t2k_d10_8_dsn_bump.png │ │ │ └── t2k_d10_9_dsn_bump.png │ │ ├── d12 │ │ │ ├── t2k_d12_1.png │ │ │ ├── t2k_d12_6.png │ │ │ ├── t2k_d12_7.png │ │ │ ├── t2k_d12_8.png │ │ │ ├── t2k_d12_9.png │ │ │ ├── t2k_d12_10.png │ │ │ ├── t2k_d12_11.png │ │ │ ├── t2k_d12_12.png │ │ │ ├── t2k_d12_10_dsn.png │ │ │ ├── t2k_d12_11_dsn.png │ │ │ ├── t2k_d12_12_dsn.png │ │ │ ├── t2k_d12_1_dsn.png │ │ │ ├── t2k_d12_6_dsn.png │ │ │ ├── t2k_d12_7_dsn.png │ │ │ ├── t2k_d12_8_dsn.png │ │ │ ├── t2k_d12_9_dsn.png │ │ │ ├── t2k_d12_10_dsn_bump.png │ │ │ ├── t2k_d12_11_dsn_bump.png │ │ │ ├── t2k_d12_12_dsn_bump.png │ │ │ ├── t2k_d12_1_dsn_bump.png │ │ │ ├── t2k_d12_6_dsn_bump.png │ │ │ ├── t2k_d12_7_dsn_bump.png │ │ │ ├── t2k_d12_8_dsn_bump.png │ │ │ └── t2k_d12_9_dsn_bump.png │ │ ├── d6 │ │ │ ├── t2k_d6_1.png │ │ │ ├── t2k_d6_6.png │ │ │ ├── t2k_d6_1_dsn.png │ │ │ ├── t2k_d6_6_dsn.png │ │ │ ├── t2k_d6_1_dsn_bump.png │ │ │ └── t2k_d6_6_dsn_bump.png │ │ ├── d8 │ │ │ ├── t2k_d8_1.png │ │ │ ├── t2k_d8_6.png │ │ │ ├── t2k_d8_7.png │ │ │ ├── t2k_d8_8.png │ │ │ ├── t2k_d8_1_dsn.png │ │ │ ├── t2k_d8_6_dsn.png │ │ │ ├── t2k_d8_7_dsn.png │ │ │ ├── t2k_d8_8_dsn.png │ │ │ ├── t2k_d8_1_dsn_bump.png │ │ │ ├── t2k_d8_6_dsn_bump.png │ │ │ ├── t2k_d8_7_dsn_bump.png │ │ │ └── t2k_d8_8_dsn_bump.png │ │ └── dm │ │ │ ├── t2k_dm_1.png │ │ │ ├── t2k_dm_6.png │ │ │ ├── t2k_dm_1_dsn.png │ │ │ └── t2k_dm_6_dsn.png │ ├── gear-intro_c.jpg │ ├── icons │ │ ├── bullet.png │ │ ├── bullet2.png │ │ ├── bullet3.png │ │ ├── token_chem.webp │ │ ├── token_fire.webp │ │ ├── token_mine.webp │ │ ├── token_smoke.webp │ │ ├── token_stop.webp │ │ ├── token_full_cover.webp │ │ ├── token_overwatch.webp │ │ ├── token_suppressed.webp │ │ ├── token_partial_cover.webp │ │ ├── bullet.svg │ │ ├── bullet3.svg │ │ └── bullet2.svg │ ├── frialigan-logo.png │ ├── t2k-banner-small.webp │ ├── textures │ │ ├── trombone.png │ │ ├── linea_beige.webp │ │ ├── linec_green.webp │ │ ├── linef_brown.webp │ │ ├── background_example.webp │ │ ├── background_texture.webp │ │ ├── lineb_bold_green.webp │ │ ├── lined_bold_brown.webp │ │ ├── linee_bold_brown2.webp │ │ ├── paper_texture_pm.webp │ │ ├── paper_texture_rm_c.jpg │ │ ├── paper_texture_sheet_c.jpg │ │ ├── lineb_bold_lightgreen.webp │ │ └── paper_texture_outline.webp │ ├── fvtt-fria-ligan-logo2.png │ └── t2k-war-office-stamp.webp ├── screenshots │ ├── 210117-chatlog.png │ ├── 210117-characterSheet-combat.png │ ├── 210117-characterSheet-stats.png │ ├── 210117-itemSheets-weapon-armor.png │ └── 210117-characterSheet-equipment.png └── system.json ├── .prettierignore ├── .vscode ├── tasks.json ├── settings.json └── i18n-ally-custom-framework.yml ├── .editorconfig ├── .gitignore ├── .prettierrc ├── jsconfig.json ├── tools ├── args-parser.js ├── get-template-paths.js └── link-project.js ├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── feature_request.yml │ └── bug_report.yml ├── FUNDING.yml ├── pull_request_template.md └── workflows │ └── release.yml ├── esbuild.config.js ├── patches └── fs-extra-plus+0.6.0.patch ├── .eslintrc └── package.json /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ -------------------------------------------------------------------------------- /src/less/utils.less: -------------------------------------------------------------------------------- 1 | .hide { 2 | display: none; 3 | } -------------------------------------------------------------------------------- /pathconfig.example: -------------------------------------------------------------------------------- 1 | /absolute/path/to/your/FoundryVTT/Data -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run lint:fix -------------------------------------------------------------------------------- /.husky/prepare-commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx devmoji -e --lint -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .github 2 | dist 3 | node_modules 4 | foundry.js 5 | static/system.json 6 | static/template.json 7 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | *.js text eol=lf 4 | *.db binary 5 | -------------------------------------------------------------------------------- /static/fonts/roundels.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/fonts/roundels.ttf -------------------------------------------------------------------------------- /static/assets/t2k-banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/t2k-banner.jpg -------------------------------------------------------------------------------- /static/assets/t2k-logo.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/t2k-logo.webp -------------------------------------------------------------------------------- /static/fonts/Mukta-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/fonts/Mukta-Bold.woff -------------------------------------------------------------------------------- /static/fonts/daisywheel.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/fonts/daisywheel.otf -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .github 2 | dist 3 | .eslintrc 4 | package-lock.json 5 | foundry.js 6 | static/system.json 7 | static/template.json 8 | -------------------------------------------------------------------------------- /static/assets/dice/dl/hit_A.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dl/hit_A.png -------------------------------------------------------------------------------- /static/assets/dice/dl/hit_H.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dl/hit_H.png -------------------------------------------------------------------------------- /static/assets/dice/dl/hit_L.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dl/hit_L.png -------------------------------------------------------------------------------- /static/assets/dice/dl/hit_T.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dl/hit_T.png -------------------------------------------------------------------------------- /static/assets/gear-intro_c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/gear-intro_c.jpg -------------------------------------------------------------------------------- /static/assets/icons/bullet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/bullet.png -------------------------------------------------------------------------------- /static/assets/icons/bullet2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/bullet2.png -------------------------------------------------------------------------------- /static/assets/icons/bullet3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/bullet3.png -------------------------------------------------------------------------------- /static/fonts/Mukta-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/fonts/Mukta-Medium.woff -------------------------------------------------------------------------------- /static/fonts/T2K4-Symbols.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/fonts/T2K4-Symbols.ttf -------------------------------------------------------------------------------- /static/assets/frialigan-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/frialigan-logo.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_1.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_6.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_7.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_8.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_9.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_1.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_6.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_7.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_8.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_9.png -------------------------------------------------------------------------------- /static/assets/dice/d6/t2k_d6_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d6/t2k_d6_1.png -------------------------------------------------------------------------------- /static/assets/dice/d6/t2k_d6_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d6/t2k_d6_6.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_1.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_6.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_7.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_8.png -------------------------------------------------------------------------------- /static/assets/dice/dm/t2k_dm_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dm/t2k_dm_1.png -------------------------------------------------------------------------------- /static/assets/dice/dm/t2k_dm_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dm/t2k_dm_6.png -------------------------------------------------------------------------------- /static/assets/icons/token_chem.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_chem.webp -------------------------------------------------------------------------------- /static/assets/icons/token_fire.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_fire.webp -------------------------------------------------------------------------------- /static/assets/icons/token_mine.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_mine.webp -------------------------------------------------------------------------------- /static/assets/icons/token_smoke.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_smoke.webp -------------------------------------------------------------------------------- /static/assets/icons/token_stop.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_stop.webp -------------------------------------------------------------------------------- /static/assets/t2k-banner-small.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/t2k-banner-small.webp -------------------------------------------------------------------------------- /static/assets/textures/trombone.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/trombone.png -------------------------------------------------------------------------------- /static/fonts/BlueHighway-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/fonts/BlueHighway-Bold.woff -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_10.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_10.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_11.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_12.png -------------------------------------------------------------------------------- /static/assets/dice/d6/t2k_d6_1_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d6/t2k_d6_1_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d6/t2k_d6_6_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d6/t2k_d6_6_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_1_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_1_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_6_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_6_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_7_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_7_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_8_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_8_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/dm/t2k_dm_1_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dm/t2k_dm_1_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/dm/t2k_dm_6_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/dm/t2k_dm_6_dsn.png -------------------------------------------------------------------------------- /static/fonts/NunitoSans-ExtraBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/fonts/NunitoSans-ExtraBold.woff -------------------------------------------------------------------------------- /static/screenshots/210117-chatlog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/screenshots/210117-chatlog.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_10_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_10_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_1_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_1_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_6_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_6_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_7_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_7_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_8_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_8_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_9_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_9_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_10_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_10_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_11_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_11_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_12_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_12_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_1_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_1_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_6_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_6_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_7_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_7_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_8_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_8_dsn.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_9_dsn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_9_dsn.png -------------------------------------------------------------------------------- /static/assets/fvtt-fria-ligan-logo2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/fvtt-fria-ligan-logo2.png -------------------------------------------------------------------------------- /static/assets/icons/token_full_cover.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_full_cover.webp -------------------------------------------------------------------------------- /static/assets/icons/token_overwatch.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_overwatch.webp -------------------------------------------------------------------------------- /static/assets/icons/token_suppressed.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_suppressed.webp -------------------------------------------------------------------------------- /static/assets/t2k-war-office-stamp.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/t2k-war-office-stamp.webp -------------------------------------------------------------------------------- /static/assets/textures/linea_beige.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/linea_beige.webp -------------------------------------------------------------------------------- /static/assets/textures/linec_green.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/linec_green.webp -------------------------------------------------------------------------------- /static/assets/textures/linef_brown.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/linef_brown.webp -------------------------------------------------------------------------------- /static/assets/dice/d6/t2k_d6_1_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d6/t2k_d6_1_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d6/t2k_d6_6_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d6/t2k_d6_6_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_1_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_1_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_6_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_6_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_7_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_7_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d8/t2k_d8_8_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d8/t2k_d8_8_dsn_bump.png -------------------------------------------------------------------------------- /src/less/dialog.less: -------------------------------------------------------------------------------- 1 | .window-app.t2k4e.dialog { 2 | .dialog-content { 3 | line-height: 1.15; 4 | } 5 | .dialog-buttons { 6 | flex: 0; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_10_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_10_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_1_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_1_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_6_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_6_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_7_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_7_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_8_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_8_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d10/t2k_d10_9_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d10/t2k_d10_9_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_10_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_10_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_11_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_11_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_12_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_12_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_1_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_1_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_6_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_6_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_7_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_7_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_8_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_8_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/dice/d12/t2k_d12_9_dsn_bump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/dice/d12/t2k_d12_9_dsn_bump.png -------------------------------------------------------------------------------- /static/assets/icons/token_partial_cover.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/icons/token_partial_cover.webp -------------------------------------------------------------------------------- /static/assets/textures/background_example.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/background_example.webp -------------------------------------------------------------------------------- /static/assets/textures/background_texture.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/background_texture.webp -------------------------------------------------------------------------------- /static/assets/textures/lineb_bold_green.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/lineb_bold_green.webp -------------------------------------------------------------------------------- /static/assets/textures/lined_bold_brown.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/lined_bold_brown.webp -------------------------------------------------------------------------------- /static/assets/textures/linee_bold_brown2.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/linee_bold_brown2.webp -------------------------------------------------------------------------------- /static/assets/textures/paper_texture_pm.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/paper_texture_pm.webp -------------------------------------------------------------------------------- /static/assets/textures/paper_texture_rm_c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/paper_texture_rm_c.jpg -------------------------------------------------------------------------------- /src/item/templates/parts/item-description.hbs: -------------------------------------------------------------------------------- 1 | {{editor system.description target='system.description' button=true editable=editable engine="prosemirror" collaborate=false }} -------------------------------------------------------------------------------- /static/assets/textures/paper_texture_sheet_c.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/paper_texture_sheet_c.jpg -------------------------------------------------------------------------------- /src/actor/templates/parts/actor-description.hbs: -------------------------------------------------------------------------------- 1 | {{editor system.description target='system.description' button=true editable=editable engine="prosemirror" collaborate=false }} -------------------------------------------------------------------------------- /static/assets/textures/lineb_bold_lightgreen.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/lineb_bold_lightgreen.webp -------------------------------------------------------------------------------- /static/assets/textures/paper_texture_outline.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/assets/textures/paper_texture_outline.webp -------------------------------------------------------------------------------- /static/screenshots/210117-characterSheet-combat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/screenshots/210117-characterSheet-combat.png -------------------------------------------------------------------------------- /static/screenshots/210117-characterSheet-stats.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/screenshots/210117-characterSheet-stats.png -------------------------------------------------------------------------------- /static/screenshots/210117-itemSheets-weapon-armor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/screenshots/210117-itemSheets-weapon-armor.png -------------------------------------------------------------------------------- /static/screenshots/210117-characterSheet-equipment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fvtt-fria-ligan/twilight2000-foundry-vtt/HEAD/static/screenshots/210117-characterSheet-equipment.png -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "gulp", 6 | "task": "build", 7 | "group": "build", 8 | "problemMatcher": [], 9 | "label": "gulp: build" 10 | } 11 | ] 12 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 2 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | 11 | [*.{hbs,htm,html}] 12 | indent_style = tab 13 | 14 | [{pathconfig,pathconfig.example}] 15 | insert_final_newline = false 16 | -------------------------------------------------------------------------------- /src/actor/templates/parts/radiation-boxes.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{#times 10}} 3 | {{#if (gte ../value @index)}} 4 | {{!-- Full square --}} 5 | {{{@root.config.Icons.boxes.full}}} 6 | {{else}} 7 | {{!-- Empty square --}} 8 | {{{@root.config.Icons.boxes.empty}}} 9 | {{/if}} 10 | {{/times}} 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS 2 | .DS_Store 3 | 4 | # IDE 5 | /.vs 6 | /.vscode/launch.json 7 | *.code-workspace 8 | 9 | # Node Modules 10 | /node_modules 11 | 12 | # Logs 13 | /logs 14 | npm-debug.log 15 | *.log 16 | /packs/**/* 17 | 18 | # Local Configuration 19 | pathconfig 20 | /*.lock 21 | src/lang/foundry 22 | 23 | # Distribution Files 24 | /dist 25 | /foundry.js 26 | -------------------------------------------------------------------------------- /src/actor/templates/parts/capacity-boxes.hbs: -------------------------------------------------------------------------------- 1 | 2 | {{#times max}} 3 | {{#if (gte ../value @index)}} 4 | {{!-- Full square --}} 5 | {{{@root.config.Icons.boxes.full}}} 6 | {{else}} 7 | {{!-- Empty square --}} 8 | {{{@root.config.Icons.boxes.empty}}} 9 | {{/if}} 10 | {{/times}} 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "i18n-ally.keystyle": "flat", 3 | "i18n-ally.localesPaths": ["src/lang"], 4 | "yaml.schemas": { 5 | "https://json.schemastore.org/github-workflow.json": "file:///d%3A/GITHUB/t2k4e/.github/workflows/deploy.yml", 6 | "https://json.schemastore.org/github-issue-config.json": "file:///d%3A/GITHUB/twilight2000-foundry-vtt/.github/ISSUE_TEMPLATE/config.yml" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/components/dialog/templates/actor-choice-dialog.hbs: -------------------------------------------------------------------------------- 1 |
2 | 3 | {{! ================================================== }} 4 | 5 |
6 | 12 |
13 | 14 |
-------------------------------------------------------------------------------- /src/less/ammo-mag.less: -------------------------------------------------------------------------------- 1 | .t2k4e.sheet .item-ammo { 2 | flex: 0 0 60px; 3 | height: 80px; 4 | 5 | padding: 2px; 6 | 7 | font-size: .7rem; 8 | 9 | background-color: @colorKhaki; 10 | border: 1px solid @colorBrown; 11 | border-radius: 4px; 12 | 13 | &:hover { 14 | background-color: @colorBeige; 15 | } 16 | &+.item-ammo { 17 | margin-left: 4px; 18 | } 19 | 20 | .ammo-icons { 21 | line-height: 0; 22 | color: red; 23 | } 24 | } -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true, 4 | "trailingComma": "all", 5 | "bracketSpacing": true, 6 | "endOfLine": "lf", 7 | "useTabs": false, 8 | "printWidth": 120, 9 | "tabWidth": 2, 10 | "quoteProps": "as-needed", 11 | "arrowParens": "avoid", 12 | "overrides": [ 13 | { 14 | "files": [".hbs", ".htm", ".html"], 15 | "options": { 16 | "useTabs": true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/less/unit.less: -------------------------------------------------------------------------------- 1 | .app.window-app.t2k4e.sheet.unit .window-content form { 2 | border: 10px solid @colorGrey; 3 | border-radius: 8px; 4 | 5 | &.unit-affiliation-friendly { 6 | border-color: @colorFriendly; 7 | } 8 | 9 | &.unit-affiliation-hostile { 10 | border-color: @colorHostile; 11 | } 12 | 13 | &.unit-affiliation-neutral { 14 | border-color: @colorNeutral; 15 | } 16 | 17 | &.unit-affiliation-unknown { 18 | border-color: @colorUnknown; 19 | } 20 | } -------------------------------------------------------------------------------- /src/actor/party/templates/components/member-component.hbs: -------------------------------------------------------------------------------- 1 |
  • 2 | {{#if deleteButton}} 3 |
    4 | 5 |
    6 | {{/if}} 7 | 8 | {{#if noCharSheetLink}} 9 | {{partyMember.name}} 10 | {{else}} {{{partyMember.enrichedName}}} {{/if}} 11 |
  • -------------------------------------------------------------------------------- /src/actor/templates/parts/slots/gear-slot.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 5 | {{detailedName}} 6 |
    7 | {{!--
    {{system.qty}}
    --}} 8 |
    {{system.encumbrance}}
    9 | 10 |
    11 | {{> "systems/t2k4e/templates/actor/parts/slots/slot-buttons.hbs"}} 12 |
    13 | 14 |
    15 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "ES6", 4 | "target": "ESNext", 5 | "moduleResolution": "Node", 6 | // "checkJs": true, 7 | "baseUrl": ".", 8 | "paths": { 9 | "*": ["./src"], 10 | // "@lib/*": ["./static/lib/*"], 11 | "@actor/*": ["./src/actor/*"], 12 | "@item/*": ["./src/item/*"], 13 | // "@module/*": ["src/module/*"], 14 | "@utils/*": ["./src/utils/*"] 15 | // "@components/*": ["./src/components/*"], 16 | } 17 | }, 18 | "include": ["src/**/*.js"], 19 | "exclude": ["node_modules/*", "dist/*"] 20 | } 21 | -------------------------------------------------------------------------------- /tools/args-parser.js: -------------------------------------------------------------------------------- 1 | export default (() => { 2 | const args = process.argv.slice(2); 3 | if (args.length === 0) return; 4 | return args.reduce((acc, arg, index, arr) => { 5 | if (arg.startsWith('--')) { 6 | // eslint-disable-next-line prefer-const 7 | let [key, value] = arg.split('='); 8 | if (!value) { 9 | if (index + 1 < arr.length && !arr[index + 1].startsWith('--')) { 10 | value = arr.splice(index + 1, 1).join(); 11 | } 12 | else value = true; 13 | } 14 | acc[key.replace('--', '')] = value; 15 | } 16 | 17 | return acc; 18 | }, {}); 19 | })(); 20 | -------------------------------------------------------------------------------- /tools/get-template-paths.js: -------------------------------------------------------------------------------- 1 | import { readdirSync, statSync } from 'node:fs'; 2 | import { join, sep, posix } from 'node:path'; 3 | 4 | const getPaths = path => { 5 | const paths = []; 6 | const files = readdirSync(path); 7 | files.forEach(file => { 8 | const filePath = join(path, file); 9 | if (statSync(filePath).isDirectory()) paths.push(...getPaths(filePath)); 10 | else paths.push(filePath); 11 | }); 12 | return paths; 13 | }; 14 | 15 | export default (() => 16 | getPaths('./src/templates').map(templatePath => { 17 | templatePath = templatePath.split(sep).slice(1).join(posix.sep); 18 | return `systems/t2k4e/${templatePath}`; 19 | }))(); 20 | -------------------------------------------------------------------------------- /src/actor/templates/parts/slots/ammo-slot.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 5 | {{detailedName}} 6 |
    7 | {{#with system}} 8 | {{!--
    {{qty}}× {{ammo.value}}/{{ammo.max}}
    --}} 9 |
    {{encumbrance}}
    10 | {{/with}} 11 | 12 |
    13 | {{> "systems/t2k4e/templates/actor/parts/slots/slot-buttons.hbs"}} 14 |
    15 | 16 |
    17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discord Chat 4 | url: https://discord.gg/foundryvtt 5 | about: 'Look for the `#free-league` channel to find a community dedicated to the Free League games.' 6 | - name: Buy the Roleplaying Game 7 | url: https://freeleaguepublishing.com/en/games/twilight-2000/ 8 | about: 'The new edition of the apocalyptic RPG Twilight: 2000 is the fourth in the series, the first being released by Game Designers’ Workshop in 1984. Just like the original version, the new edition is set in a year 2000 devastated by war – now in an alternate timeline where the Moscow Coup of 1991 succeeded and the Soviet Union never collapsed.' 9 | -------------------------------------------------------------------------------- /src/less/t2k4e.less: -------------------------------------------------------------------------------- 1 | // Primary variables 2 | @import "./variables.less"; 3 | 4 | // Layouts 5 | @import "./flex-layout.less"; 6 | @import "./grid-layout.less"; 7 | 8 | // Other utils 9 | @import "./utils.less"; 10 | @import "./symbols.less"; 11 | 12 | // App 13 | @import "./app.less"; 14 | @import "./dialog.less"; 15 | @import "./tabs.less"; 16 | @import "./inventory.less"; 17 | // @import "./ammo-mag.less"; 18 | @import "./encumbrance.less"; 19 | @import "./chat.less"; 20 | @import "./journal.less"; 21 | 22 | // Actors & Items 23 | @import "./actors.less"; 24 | @import "./vehicle.less"; 25 | @import "./unit.less"; 26 | @import "./party.less"; 27 | @import "./items.less"; 28 | 29 | // Modules Themes 30 | @import "./module-t2k4e-coreset.less"; 31 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Stefouch 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | custom: # ['https://www.paypal.me/stefouch'] 14 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | 4 | (Your summary.) 5 | 6 | ## Checklist 7 | 8 | ### PR Type 9 | 10 | - [ ] This PR is a code change that implements a feature request. 11 | - [ ] This PR fixes an issue. 12 | - [ ] This PR adds a new feature that is not an open feature request. 13 | - [ ] This PR is not a code change (e.g. documentation, README, ...) 14 | ### Other 15 | - [ ] This PR is a breaking change (e.g. methods or parameters removed/renamed) 16 | - [ ] If code changes were made then they have been tested. 17 | - [ ] I have updated the documentation to reflect the changes (wiki). -------------------------------------------------------------------------------- /src/components/chat/templates/gear-chat.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 |
    5 |

    {{name}}

    6 |
    7 | 8 |
    9 | {{name}} 10 |
    11 | 12 |
    13 | {{{system.description}}} 14 |
    15 | 16 | {{!--
    17 | 18 | {{#if system.mag.max}} 19 | 20 | {{/if}} 21 |
    --}} 22 | 23 |
    24 |
    -------------------------------------------------------------------------------- /src/actor/party/templates/components/action-component.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |

    4 | {{#if action.displayJournalEntry}} {{{action.enrichedEntryName}}} {{else}} {{ localize action.name }} {{/if}} 5 |

    6 |
    7 |
    8 | {{#each action.buttons as | button |}} 9 | 10 | {{/each}} 11 |
    12 |
    13 |
      14 | {{#each assignedCharacters as | partyMember |}} 15 | 16 | {{! prettier-ignore }} 17 | {{> systems/t2k4e/templates/actor/party/components/member-component.hbs partyMember=partyMember}} 18 | {{/each}} 19 |
    20 |
    21 |
    22 | -------------------------------------------------------------------------------- /src/actor/party/components/info-dialog.js: -------------------------------------------------------------------------------- 1 | export class InfoDialog { 2 | /** 3 | * Display informational message. 4 | * 5 | * @param {string} title 6 | * @param {string} message 7 | * @param {Function} onClose 8 | */ 9 | static show(title, message, onClose) { 10 | const d = new Dialog({ 11 | title: title, 12 | content: this.buildDivHtmlDialog(message), 13 | buttons: { 14 | ok: { 15 | icon: '', 16 | label: 'OK', 17 | callback: onClose, 18 | }, 19 | }, 20 | default: 'ok', 21 | close: onClose, 22 | }); 23 | d.render(true); 24 | } 25 | 26 | /** 27 | * @param {string} divContent 28 | */ 29 | static buildDivHtmlDialog(divContent) { 30 | return '
    ' + divContent + '
    '; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/components/dialog/templates/value-choice-dialog.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{! Modifier }} 4 |
    5 | 6 | 23 |
    24 | 25 |
    -------------------------------------------------------------------------------- /src/actor/templates/parts/slots/armor-slot.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 5 | {{detailedName}} 6 |
    7 |
    8 | {{#each system.location as | bool name |}} 9 | {{#if bool}} 10 | {{{lookup @root.config.Icons.armorLocationIcons name}}} 11 | {{/if}} 12 | {{/each}} 13 |
    14 |
    {{system.rating.value}}/{{system.rating.max}}
    15 |
    {{system.encumbrance}}
    16 | 17 |
    18 | {{> "systems/t2k4e/templates/actor/parts/slots/slot-buttons.hbs"}} 19 |
    20 | 21 |
    22 | -------------------------------------------------------------------------------- /src/less/symbols.less: -------------------------------------------------------------------------------- 1 | .symbol { 2 | display: inline-block; 3 | margin: 1px 1px -1px 1px; 4 | // -webkit-border-radius: 500px; 5 | // border-radius: 500px; 6 | // -webkit-box-shadow: -1px 1px 0 rgba(0,0,0,0.85); 7 | // box-shadow: -1px 1px 0 rgba(0,0,0,0.85); 8 | text-indent: -999em; 9 | overflow: hidden; 10 | width: 15px; 11 | height: 15px; 12 | -webkit-background-size: 100% 100%; 13 | background-size: 100% 100%; 14 | background-position: top left; 15 | -webkit-print-color-adjust: exact; 16 | color-adjust: exact; 17 | 18 | + .symbol { 19 | margin-left: 2px; 20 | } 21 | 22 | &.symbol-ammo { 23 | // margin: 0 2px -2px 0; 24 | margin: 0; 25 | width: 29px; // 287x59 26 | height: 6px; 27 | // -webkit-box-shadow: none; 28 | // box-shadow: none; 29 | // -webkit-border-radius: none; 30 | // border-radius: none; 31 | background-image: url(assets/icons/bullet3.svg); 32 | } 33 | } -------------------------------------------------------------------------------- /src/item/templates/parts/item-header.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 4 | 5 |
    6 |
    7 |

    {{localize (concat 'T2K4E.ItemTypes.' item.type)}}

    8 | {{#if item.isPhysical}} 9 |
    10 | 17 |
    ×
    18 |
    19 | {{/if}} 20 |
    21 |

    22 | 23 |

    24 |
    25 | 26 |
    -------------------------------------------------------------------------------- /src/actor/party/templates/party-sheet.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 8 | 9 |
    10 |
    11 | {{> systems/t2k4e/templates/actor/party/sheet-tabs/main-tab.hbs}} 12 |
    13 |
    14 | {{> systems/t2k4e/templates/actor/party/sheet-tabs/travel-tab.hbs}} 15 |
    16 |
    17 | {{> "systems/t2k4e/templates/actor/parts/actor-description.hbs"}} 18 |
    19 |
    20 |
    21 |
    22 | -------------------------------------------------------------------------------- /src/item/templates/specialty-sheet.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{!-- Item Sheet Header --}} 4 | {{> "systems/t2k4e/templates/item/parts/item-header.hbs"}} 5 | 6 | {{!-- Sheet Tab Navigation --}} 7 | 11 | 12 | {{!-- Sheet Body --}} 13 |
    14 | 15 | {{!-- Modifiers Tab --}} 16 |
    17 | {{> "systems/t2k4e/templates/item/parts/item-modifiers.hbs"}} 18 |
    19 | 20 | {{!-- Description Tab --}} 21 |
    22 | {{> "systems/t2k4e/templates/item/parts/item-description.hbs"}} 23 |
    24 | 25 |
    26 | 27 |
    28 | -------------------------------------------------------------------------------- /src/components/chat/templates/armor-chat.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 |
    5 |

    {{name}}

    6 |
    7 | 8 |
    9 | {{name}} 10 |
    11 | 12 |
    13 | {{{system.description}}} 14 |

    {{localize 'T2K4E.ItemSheet.FeaturesTab'}}

    15 |
    16 |
    {{localize 'T2K4E.ItemSheet.Armor'}}: {{system.rating.max}}
    17 |
    18 |
    19 | 20 | {{!--
    21 | 22 | {{#if system.mag.max}} 23 | 24 | {{/if}} 25 |
    --}} 26 | 27 |
    28 |
    -------------------------------------------------------------------------------- /src/actor/party/templates/sheet-tabs/main-tab.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | 5 |
    6 |
    7 |
    8 |
    9 |

    {{localize "FLPS.PARTY.NAME"}}

    10 | 11 |
    12 |
    13 |
    14 |
    15 |
    16 |

    {{localize "FLPS.PARTY.MEMBERS"}}

    17 |
    {{localize "FLPS.PARTY.HINT_ADD"}}
    18 |
    19 |
      20 | {{#each partyMembers as | partyMember |}} 21 | 22 | {{! prettier-ignore }} 23 | {{> systems/t2k4e/templates/actor/party/components/member-component.hbs partyMember=partyMember deleteButton=true}} 24 | {{/each}} 25 |
    26 |
    27 |
    28 |
    29 | -------------------------------------------------------------------------------- /esbuild.config.js: -------------------------------------------------------------------------------- 1 | import { build } from 'esbuild'; 2 | // import templatePaths from './tools/get-template-paths.js'; 3 | 4 | export default ({ watch = false, production = false } = {}) => 5 | build({ 6 | bundle: true, 7 | entryPoints: ['./src/t2k4e.js'], 8 | outdir: 'dist', 9 | format: 'esm', 10 | logLevel: 'info', 11 | sourcemap: !production ? 'inline' : false, 12 | ignoreAnnotations: !production, 13 | minifyWhitespace: true, 14 | minifySyntax: true, 15 | drop: production ? ['console', 'debugger'] : [], 16 | watch, 17 | // define: { 18 | // PATHS: JSON.stringify(templatePaths), 19 | // }, 20 | // plugins: [ 21 | // sassPlugin({ 22 | // logger: { 23 | // warn: () => '', 24 | // }, 25 | // }), 26 | // { 27 | // name: 'external-files', 28 | // setup(inBuild) { 29 | // inBuild.onResolve({ filter: /(\.\/assets|\.\/fonts|\/systems)/ }, () => { 30 | // return { external: true }; 31 | // }); 32 | // }, 33 | // }, 34 | // ], 35 | }); 36 | -------------------------------------------------------------------------------- /src/actor/templates/parts/slots/vehicle-weapon-slot.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 5 | {{detailedName}} 6 |
    7 |
    {{system.itemType}}
    8 |
    {{system.rof}}
    9 |
    {{system.damage}}
    10 |
    {{system.crit}}
    11 |
    {{#if (gte system.armorModifier 1)}}+{{/if}}{{system.armorModifier}}
    12 |
    {{system.range}}
    13 |
    {{system.mag.max}}
    14 |
    {{system.reliability.value}}
    15 |
    {{system.blast}}
    16 | 17 |
    18 | {{> "systems/t2k4e/templates/actor/parts/slots/slot-buttons.hbs"}} 19 |
    20 | 21 |
    22 | -------------------------------------------------------------------------------- /src/components/roll/templates/roll.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 | {{#if flavor}} 5 |
    {{flavor}}
    6 | {{/if}} 7 |
    8 |
    {{formula}}
    9 | {{{tooltip}}} 10 | {{#if (and (eq roll.game 't2k') (not isPrivate))}} 11 |

    {{roll.baseSuccessQty}}{{#if roll.ammoSpent}} ({{roll.hitCount}}){{/if}}

    12 | {{else}} 13 |

    {{total}}

    14 | {{/if}} 15 |
    16 |
    17 | 18 | {{! Extra info added for Year Zero rolls }} 19 | {{#if showInfos}} 20 | {{{infos}}} 21 | {{/if}} 22 | 23 | {{! Push button }} 24 | {{#if pushable}} 25 |
    26 | 27 | 28 |
    29 | {{/if}} 30 |
    31 |
    -------------------------------------------------------------------------------- /src/components/roll/templates/tooltip.hbs: -------------------------------------------------------------------------------- 1 |
    2 | {{#each parts}} 3 |
    4 |
    5 |
    6 | {{#unless this.isYearZeroDie}} 7 | {{this.formula}} 8 | {{else}} 9 | {{#if this.flavor}}{{this.flavor}}{{/if}} 10 | {{/unless}} 11 | {{this.total}} 12 |
    13 |
      14 | {{#if ../pushed}} 15 | {{#each this.rolls as | lineRolls |}} 16 |
      17 | {{#each lineRolls}} 18 | {{#if this}} 19 | {{{this.result}}} 20 | {{else}} 21 |   22 | {{/if}} 23 | {{/each}} 24 |
      25 | {{/each}} 26 | {{else}} 27 | {{#each this.rolls}} 28 |
    1. {{{this.result}}}
    2. 29 | {{/each}} 30 | {{/if}} 31 |
    32 |
    33 |
    34 | {{/each}} 35 |
    -------------------------------------------------------------------------------- /static/assets/icons/bullet.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/assets/icons/bullet3.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /static/assets/icons/bullet2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /patches/fs-extra-plus+0.6.0.patch: -------------------------------------------------------------------------------- 1 | # generated by patch-package 6.4.8 on 2022-03-21 22:23:04 2 | # 3 | # command: 4 | # npx patch-package fs-extra-plus 5 | # 6 | # declared package: 7 | # fs-extra-plus: 0.6.0 8 | # 9 | diff --git a/node_modules/fs-extra-plus/dist/index.js b/node_modules/fs-extra-plus/dist/index.js 10 | index e77bf27..7c25d16 100644 11 | --- a/node_modules/fs-extra-plus/dist/index.js 12 | +++ b/node_modules/fs-extra-plus/dist/index.js 13 | @@ -2,6 +2,10 @@ import FastGlob from 'fast-glob'; 14 | import { pathExists, remove } from 'fs-extra'; 15 | import { join as pathJoin, resolve as pathResolve } from 'path'; 16 | import { globCompare } from './util.js'; 17 | + 18 | +export * from 'fs-extra'; 19 | +export * from 'fs'; 20 | + 21 | /** 22 | * Simplified and sorted glob function (using fast-glob) for one or more pattern from current directory or a optional cwd one. 23 | * 24 | diff --git a/node_modules/fs-extra-plus/src/index.ts b/node_modules/fs-extra-plus/src/index.ts 25 | index 7b03c5f..c825de7 100644 26 | --- a/node_modules/fs-extra-plus/src/index.ts 27 | +++ b/node_modules/fs-extra-plus/src/index.ts 28 | @@ -3,8 +3,6 @@ import { pathExists, remove } from 'fs-extra'; 29 | import { join as pathJoin, resolve as pathResolve } from 'path'; 30 | import { globCompare } from './util.js'; 31 | 32 | - 33 | - 34 | /** 35 | * Simplified and sorted glob function (using fast-glob) for one or more pattern from current directory or a optional cwd one. 36 | * -------------------------------------------------------------------------------- /src/actor/party/components/helpers.js: -------------------------------------------------------------------------------- 1 | import { InfoDialog } from './info-dialog.js'; 2 | 3 | export class Helpers { 4 | static getCharacterDiceRoller(character) { 5 | character = character instanceof Actor ? character : game.user.character; 6 | if (!character) return; 7 | 8 | let charSheetClass = function () {}; 9 | for (const chName in CONFIG.Actor.sheetClasses.character) { 10 | if (chName === 't2k4e.ActorSheetT2KCharacter') { 11 | charSheetClass = CONFIG.Actor.sheetClasses.character[chName].cls; 12 | break; 13 | } 14 | } 15 | let charSheet; 16 | for (const key in character.apps) { 17 | if (character.apps[key] instanceof charSheetClass) { 18 | charSheet = character.apps[key]; 19 | break; 20 | } 21 | } 22 | if (!charSheet) { 23 | InfoDialog.show(game.i18n.localize('FLPS.UI.ATTENTION'), game.i18n.localize('FLPS.UI.ERROR.OPEN_SHEET')); 24 | return null; 25 | } 26 | 27 | return charSheet.diceRoller; 28 | } 29 | 30 | static getOwnedCharacters(characterIds) { 31 | characterIds = typeof characterIds !== 'object' && characterIds !== '' ? [characterIds] : characterIds; 32 | const characters = []; 33 | for (let i = 0; i < characterIds.length; i++) { 34 | const actor = game.actors.get(characterIds[i]); 35 | if (actor && actor.isOwner) characters.push(game.actors.get(characterIds[i])); 36 | } 37 | 38 | return characters; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/actor/templates/parts/slots/weapon-slot.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 |
    4 | 5 | {{detailedName}} 6 |
    7 |
    {{system.rof}}
    8 |
    {{system.damage}}
    9 |
    {{system.crit}}
    10 |
    {{#if (gte system.armorModifier 1)}}+{{/if}}{{system.armorModifier}}
    11 |
    {{system.range}}
    12 | {{#if system.mag.max}} 13 |
    {{system.mag.max}}
    14 | {{!-- --}} 15 | {{!--
    --}} 16 | {{else}} 17 |
    {{system.mag.value}}
    18 | {{/if}} 19 |
    {{system.reliability.value}}
    20 |
    {{system.blast}}
    21 |
    {{system.encumbrance}}
    22 | 23 |
    24 | {{> "systems/t2k4e/templates/actor/parts/slots/slot-buttons.hbs"}} 25 |
    26 | 27 | 28 | -------------------------------------------------------------------------------- /src/less/encumbrance.less: -------------------------------------------------------------------------------- 1 | @encumbranceBarHeight: 12px; 2 | 3 | .t2k4e.sheet.actor .encumbrance { 4 | flex: 0 0 @encumbranceBarHeight; 5 | background: @colorLightBrown; 6 | margin: 1px 6px 0 4px; 7 | border: 1px solid @colorDark; 8 | border-radius: 3px; 9 | position: relative; 10 | 11 | .encumbrance-bar { 12 | position: absolute; 13 | top: 1px; 14 | left: 1px; 15 | background: #6c8aa5; 16 | height: @encumbranceBarHeight - 4px; 17 | border: 1px solid @colorBeige; 18 | border-radius: 2px; 19 | } 20 | 21 | .encumbrance-label { 22 | height: @encumbranceBarHeight - 2px; 23 | padding: 0 5px; 24 | position: absolute; 25 | top: 0; 26 | right: 0; 27 | font-size: @encumbranceBarHeight; 28 | line-height: @encumbranceBarHeight - 1px; 29 | text-align: right; 30 | color: @colorBeige; 31 | text-shadow: 0 0 5px #000; 32 | } 33 | 34 | .encumbrance-breakpoint { 35 | display: block; 36 | position: absolute; 37 | 38 | &.encumbrance-33 { 39 | left: 33%; 40 | } 41 | &.encumbrance-66 { 42 | left: 66%; 43 | } 44 | } 45 | 46 | .arrow-up { 47 | bottom: 0; 48 | width: 0; 49 | height: 0; 50 | border-left: 4px solid transparent; 51 | border-right: 4px solid transparent; 52 | border-bottom: 4px solid @colorBrown; 53 | } 54 | 55 | .arrow-down { 56 | top: 0; 57 | width: 0; 58 | height: 0; 59 | border-left: 4px solid transparent; 60 | border-right: 4px solid transparent; 61 | border-top: 4px solid @colorBrown; 62 | } 63 | 64 | &.encumbered { 65 | .encumbrance-bar { 66 | background: @colorRed; 67 | border-color: lighten(@colorRed, 33%); 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /src/components/chat/templates/character-damage-chat.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {{#if (gt amount 0)}} 4 |

    5 | {{{localize 'T2K4E.Chat.Damage.DamageDealt' name=name amount=amount}}} 6 | {{#if incapacited}} 7 |
    {{{@root.config.Icons.buttons.lethal}}} {{localize 8 | 'T2K4E.Chat.Damage.Incapacited' 9 | }} 10 | {{/if}} 11 |

    12 | {{else}} 13 |

    {{{localize 'T2K4E.Chat.Damage.NoDamageDealt' name=name}}}

    14 | {{/if}} 15 | {{#if armors.length}} 16 |
    17 |

    18 | {{{localize 'T2K4E.Chat.Damage.InitialAmount' damage=initialAmount mod=signedArmorModifier}}} 19 | {{#each armors}} 20 |
    21 | {{label}}:  22 | {{#if damage}} 23 | {{#if penetrated}} 24 | {{localize 'T2K4E.Chat.Damage.DeflectedDamage' damage=damage}} 25 | {{else}} 26 | {{localize 'T2K4E.Chat.Damage.DeflectedAllDamage'}} 27 | {{/if}} 28 | {{else if penetrated}} 29 | {{localize 'T2K4E.Chat.Damage.NoEffect'}} 30 | {{else}} 31 | 32 | {{/if}} 33 | {{#if damaged}} — {{localize 'T2K4E.Chat.Damage.DamagedArmor'}}{{/if}} 34 | {{/each}} 35 |

    36 | {{/if}} 37 |
    38 |
    -------------------------------------------------------------------------------- /src/utils/semver-compare.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Takes up to three semver strings and an options object. 3 | * @param {String} min 4 | * @param {String} curr 5 | * @param {String} max 6 | * @param {Object} opt Properties: eqMin, eqMax, gEqMin, lEqMax 7 | * @returns {Boolean} Comparison result 8 | */ 9 | export default function semverComp(min, curr, max, opt = {}) { 10 | if ((!min && !max) || !curr) throw new Error(`Missing Comparators. min ${min}; curr ${curr}; max ${max}`); 11 | 12 | // Type converting from String to Number. 13 | min = min && coerceNum(min); 14 | curr = curr && coerceNum(curr); 15 | max = max && coerceNum(max); 16 | 17 | if (min && max && opt.eqMin && opt.eqMax) return min === curr && curr === max; 18 | if (min && opt.eqMin) return min === curr; 19 | if (max && opt.eqMax) return max === curr; 20 | 21 | // Type converting from Number to Boolean. 22 | if (min) { 23 | if (opt.gEqMin) min = min <= curr; 24 | else min = min < curr; 25 | } 26 | else { 27 | min = true; 28 | } 29 | 30 | if (max) { 31 | if (opt.lEqMax) max = curr <= max; 32 | else max = curr < max; 33 | } 34 | else { 35 | max = true; 36 | } 37 | 38 | if (min && max) return true; 39 | return false; 40 | } 41 | 42 | function coerceNum(string) { 43 | if (typeof string !== 'string') throw new Error(`Wrong term passed ${string}`); 44 | const array = Array.from(string.split('.'), v => parseInt(v)); 45 | if (array.some(v => isNaN(v)) || array.length !== 3) throw new Error(`Invalid SemVer string: ${string}`); 46 | array[0] = array[0] * 1000000; 47 | array[1] = array[1] * 1000; 48 | return array.reduce((sum, val) => (sum += val)); 49 | } 50 | -------------------------------------------------------------------------------- /src/less/tabs.less: -------------------------------------------------------------------------------- 1 | .t2k4e.sheet { 2 | nav.slanted-tabs { 3 | // flex: 0 0 @navHeight; 4 | // position: relative; 5 | white-space: nowrap; 6 | margin: 0; 7 | border: none; 8 | z-index: 1; 9 | 10 | /* Adjust this padding: 11 | * -> top+bottom: Y-axis position of the tab. 12 | * -> left+right: Navbar X-axis padding. 13 | */ 14 | padding: 8px 20px; 15 | 16 | a.item { 17 | display: inline-block; 18 | position: relative; 19 | // color: inherit; 20 | // text-decoration: none; 21 | overflow: hidden; 22 | text-overflow: ellipsis; 23 | 24 | text-align: center; 25 | z-index: 1; 26 | 27 | /* Adjust this padding: 28 | * -> top+bottom: Height of the tab. 29 | * -> left+right: Space for the text in the tab. 30 | */ 31 | padding: 0 20px; 32 | 33 | /* Adjust this margin to position the tab: 34 | * -> top+bottom: Y-axis positionment of the tab. 35 | * -> left+right: Width of the tab. 36 | */ 37 | margin: 0 -7px; 38 | 39 | &:before { 40 | border: 1px groove @colorKhaki;//#aaa; 41 | border-radius: 10px 10px 0 0; 42 | 43 | content: ''; /* To generate the box. */ 44 | position: absolute; 45 | top: 0; right: 0; bottom: .5em; left: 0; 46 | z-index: -1; 47 | border-bottom: none; 48 | background: #ddd; 49 | box-shadow: 0 2px hsla(0,0%,100%,.5) inset; 50 | transform: perspective(5px) rotateX(2deg); 51 | transform-origin: bottom; 52 | } 53 | 54 | &.active { 55 | z-index: 2; 56 | 57 | &:before { 58 | // background: #eee; 59 | background: @colorLightKhaki; 60 | 61 | margin-bottom: -1px; 62 | border-top-width: 1px; 63 | } 64 | } 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/utils/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Generates a random integer between [min, max] (included). 3 | * @param {number} min Minimum threshold 4 | * @param {number} max Maximum threshold 5 | * @returns {number} The randomized integer 6 | */ 7 | export function rand(min, max) { 8 | return Math.floor(Math.random() * (max - min + 1) + min); 9 | } 10 | 11 | /** 12 | * Creates a range of labels between two numbers. 13 | * @param {number} size Maximum 14 | * @param {number} [startAt=1] Minimum 15 | * @returns {string[]} 16 | */ 17 | export function range(size, startAt = 1) { 18 | return [...Array(size).keys()].map(i => `${i + startAt}`); 19 | } 20 | 21 | /** 22 | * Clamps a value to ensure it sits within a designated range. 23 | * 24 | * Called with no arguments, this function returns a value to fall 25 | * between 0 - 1, offering a useful shorthand for validating multipliers. 26 | * 27 | * @param {number} input Value to operate upon 28 | * @param {number} min Lower threshold; defaults to 0 29 | * @param {number} max Upper threshold; defaults to 1 30 | * @return {number} 31 | */ 32 | export function clamp(input, min, max) { 33 | return Math.min(Math.max(input, min || 0), undefined === max ? 1 : max); 34 | } 35 | 36 | export async function enrichTextFields(sheetData, fieldNames) { 37 | for (const fieldName of fieldNames) { 38 | if (foundry.utils.hasProperty(sheetData, fieldName)) { 39 | foundry.utils.setProperty( 40 | sheetData, 41 | fieldName, 42 | // eslint-disable-next-line max-len 43 | await foundry.applications.ux.TextEditor.implementation.enrichHTML(foundry.utils.getProperty(sheetData, fieldName), { async: true }), 44 | ); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: '✨ Feature request' 2 | description: Suggest an idea for this project 3 | labels: ['feature request'] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for your interest in the project and taking the time to fill out this feature request! 8 | - type: textarea 9 | id: feature-description 10 | attributes: 11 | label: Description 12 | description: 'Clear and concise description of the request. Please make the reason and usecases as detailed as possible. If you intend to submit a PR for this issue, tell us in the description. Thanks!' 13 | placeholder: When using the Twilight 2000 system I would like to see [whish]. 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: suggested-solution 18 | attributes: 19 | label: Suggested solution 20 | description: 'The solution could look something like this...' 21 | validations: 22 | required: true 23 | - type: textarea 24 | id: alternative 25 | attributes: 26 | label: Alternative 27 | description: Clear and concise description of any alternative solutions or features you've considered. 28 | - type: textarea 29 | id: additional-context 30 | attributes: 31 | label: Additional context 32 | description: Any other context or screenshots about the feature request here. 33 | - type: checkboxes 34 | id: checkboxes 35 | attributes: 36 | label: Validations 37 | description: Before submitting the issue, please make sure you do the following 38 | options: 39 | - label: Check that there isn't already an issue that request the same feature to avoid creating a duplicate. 40 | required: true 41 | -------------------------------------------------------------------------------- /src/actor/unit/unitSheet.js: -------------------------------------------------------------------------------- 1 | import ActorSheetT2K from '../actorSheet.js'; 2 | 3 | /** 4 | * Twilight 2000 Actor Sheet for Units. 5 | * @extends {ActorSheetT2K} Extends the T2K ActorSheet 6 | */ 7 | export default class ActorSheetT2KUnit extends ActorSheetT2K { 8 | /* ------------------------------------------- */ 9 | /* Sheet Properties */ 10 | /* ------------------------------------------- */ 11 | 12 | /** @override */ 13 | static get defaultOptions() { 14 | return foundry.utils.mergeObject(super.defaultOptions, { 15 | classes: ['t2k4e', 'sheet', 'item', 'unit'], 16 | width: 400, 17 | height: 550, 18 | tabs: [{ navSelector: '.sheet-tabs', contentSelector: '.sheet-body', initial: 'features' }], 19 | }); 20 | } 21 | 22 | /* ------------------------------------------- */ 23 | /* Sheet Data Preparation */ 24 | /* ------------------------------------------- */ 25 | 26 | // /** @override */ 27 | // getData() { 28 | // const sheetData = super.getData(); 29 | // return sheetData; 30 | // } 31 | 32 | /* ------------------------------------------- */ 33 | 34 | /* ------------------------------------------- */ 35 | /* Sheet Listeners */ 36 | /* ------------------------------------------- */ 37 | 38 | // /** @override */ 39 | // activateListeners(html) { 40 | // super.activateListeners(html); 41 | 42 | // // Everything below here is only needed if the sheet is editable. 43 | // if (!this.options.editable) return; 44 | // if (!this.isEditable) return; 45 | 46 | // // Owner-only listeners. 47 | // if (this.actor.isOwner) {} 48 | // } 49 | 50 | /* ------------------------------------------- */ 51 | } 52 | -------------------------------------------------------------------------------- /src/less/flex-layout.css: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------- */ 2 | /* Flexbox */ 3 | /* ------------------------------------------- */ 4 | .flex-center { 5 | justify-content: center; 6 | } 7 | .flex-left { 8 | justify-content: flex-start; 9 | } 10 | .flex-right { 11 | justify-content: flex-end; 12 | } 13 | .flex-between { 14 | justify-content: space-between; 15 | } 16 | .flex-around { 17 | justify-content: space-around; 18 | } 19 | .flex-top { 20 | align-items: flex-start; 21 | } 22 | .flex-bottom { 23 | align-items: flex-end; 24 | } 25 | .flex-middle { 26 | align-items: center; 27 | } 28 | .flex-grow { 29 | flex-grow: 1; 30 | } 31 | .t2k4e .full { 32 | width: 100%; 33 | height: 100%; 34 | } 35 | /* ------------------------------------------- */ 36 | /* Column Layout */ 37 | /* ------------------------------------------- */ 38 | /** 39 | * Creates a range of styles from .col-1 to .col-12 40 | * for placing flex elements like in a table. 41 | */ 42 | .col-12 { 43 | flex: 0 0 auto; 44 | width: 100%; 45 | } 46 | .col-11 { 47 | flex: 0 0 auto; 48 | width: 91.67%; 49 | } 50 | .col-10 { 51 | flex: 0 0 auto; 52 | width: 83.33%; 53 | } 54 | .col-9 { 55 | flex: 0 0 auto; 56 | width: 75%; 57 | } 58 | .col-8 { 59 | flex: 0 0 auto; 60 | width: 66.67%; 61 | } 62 | .col-7 { 63 | flex: 0 0 auto; 64 | width: 58.33%; 65 | } 66 | .col-6 { 67 | flex: 0 0 auto; 68 | width: 50%; 69 | } 70 | .col-5 { 71 | flex: 0 0 auto; 72 | width: 41.67%; 73 | } 74 | .col-4 { 75 | flex: 0 0 auto; 76 | width: 33.33%; 77 | } 78 | .col-3 { 79 | flex: 0 0 auto; 80 | width: 25%; 81 | } 82 | .col-2 { 83 | flex: 0 0 auto; 84 | width: 16.67%; 85 | } 86 | .col-1 { 87 | flex: 0 0 auto; 88 | width: 8.33%; 89 | } 90 | -------------------------------------------------------------------------------- /tools/link-project.js: -------------------------------------------------------------------------------- 1 | import { existsSync, readFileSync, mkdirSync, rmSync, symlinkSync } from 'node:fs'; 2 | import { join, resolve } from 'node:path'; 3 | 4 | import c from 'chalk'; 5 | 6 | const MODULEPATH = 'static/system.json'; 7 | const FILENAME = 'pathconfig'; 8 | const BASEPATH = 'Data/systems'; 9 | let DATAPATH; 10 | let PKG; 11 | 12 | try { 13 | DATAPATH = readFileSync(`./${FILENAME}`, 'utf-8').trim(); 14 | const temp = readFileSync(MODULEPATH); 15 | PKG = JSON.parse(temp); 16 | } 17 | catch (error) { 18 | console.error(`Could not read ${c.blue('package.json')}, or ${c.blue(FILENAME)}. See error for further details.`); 19 | throw error; 20 | } 21 | 22 | if (!existsSync(resolve(DATAPATH))) { 23 | console.error(c.red(`${c.bold('Error:')} ${c.gray(`The path ${c.blue(c.underline(DATAPATH))} does not exist`)}`)); 24 | process.exit(0); 25 | } 26 | 27 | try { 28 | const symlink = () => symlinkSync(resolve('./dist'), resolve(join(DATAPATH, `${BASEPATH}/${PKG.id}`))); 29 | const path = resolve(join(DATAPATH, `${BASEPATH}/${PKG.id}`)); 30 | if (!existsSync(resolve('./dist'))) mkdirSync(resolve('./dist')); 31 | if (existsSync(path)) { 32 | if (process.argv[2] !== '--force') { 33 | console.error( 34 | c.red( 35 | `${c.bold('Error:')} ${c.gray( 36 | `The path ${c.blue(path)} already exists.\nYou can force a symlink by using --force`, 37 | )}`, 38 | ), 39 | ); 40 | process.exit(0); 41 | } 42 | else rmSync(path, { recursive: true }); 43 | } 44 | symlink(); 45 | } 46 | catch (error) { 47 | console.error(error); 48 | process.exit(0); 49 | } 50 | 51 | console.info( 52 | c.green( 53 | `${c.bold('Success:')} ${c.gray( 54 | `Symlink created at ${c.blue(resolve(join(DATAPATH, `${BASEPATH}/${PKG.id}`)))}`, 55 | )}`, 56 | ), 57 | ); 58 | -------------------------------------------------------------------------------- /.vscode/i18n-ally-custom-framework.yml: -------------------------------------------------------------------------------- 1 | # Author: FloRad from SWADE game system 2 | # https://gitlab.com/peginc/swade 3 | 4 | # .vscode/i18n-ally-custom-framework.yml 5 | 6 | # An array of strings which contain Language Ids defined by VS Code 7 | # You can check avaliable language ids here: https://code.visualstudio.com/docs/languages/overview#_language-id 8 | languageIds: 9 | - javascript 10 | - typescript 11 | - handlebars 12 | 13 | # An array of RegExes to find the key usage. **The key should be captured in the first match group**. 14 | # You should unescape RegEx strings in order to fit in the YAML file 15 | # To help with this, you can use https://www.freeformatter.com/json-escape.html 16 | usageMatchRegex: 17 | # The following example shows how to detect `t("your.i18n.keys")` 18 | # the `{key}` will be placed by a proper keypath matching regex, 19 | # you can ignore it and use your own matching rules as well 20 | - "[^\\w\\d]game\\.i18n\\.localize\\(['\"`]({key})['\"`]\\)" 21 | - "[^\\w\\d]game\\.i18n\\.format\\(['\"`]({key})['\"`]" 22 | - "[^\\w\\d]ui\\.notifications\\.info\\(['\"`]({key})['\"`],\\s{\\s*.*\\slocalize: true\\s*.*}" 23 | - "[^\\w\\d]ui\\.notifications\\.warn\\(['\"`]({key})['\"`],\\s{\\s*.*\\slocalize: true\\s*.*}" 24 | - "[^\\w\\d]ui\\.notifications\\.error\\(['\"`]({key})['\"`],\\s{\\s*.*\\slocalize: true\\s*.*}" 25 | - "\\{\\{\\s*localize\\s+[\"']({key})['\"]\\}\\}" 26 | - "\\{\\{[\\w\\.\\s\\=]*\\(localize\\s+[\"']({key})['\"]\\)[\\w\\.\\s\\=]*\\}\\}" 27 | - "name:\\s+[\"'](SETTINGS.{key})[\"']" 28 | - "hint:\\s+[\"'](SETTINGS.{key})[\"']" 29 | 30 | # An array of strings containing refactor templates. 31 | # The "$1" will be replaced by the keypath specified. 32 | # Optional: uncomment the following two lines to use 33 | 34 | # refactorTemplates: 35 | # - "{{localize '$1'}}" 36 | # - '{{localize "$1"}}' 37 | 38 | # If set to true, only enables this custom framework (will disable all built-in frameworks) 39 | monopoly: true 40 | -------------------------------------------------------------------------------- /src/system/statusEffects.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Registers Status Effect Icons. 3 | * @see https://foundryvtt.wiki/en/development/guides/active-effects 4 | */ 5 | export function registerStatusEffects() { 6 | const path = 'systems/t2k4e/assets/icons/'; 7 | CONFIG.statusEffects = [ 8 | { 9 | id: 'fullCover', 10 | label: 'EFFECT.StatusFullCover', 11 | icon: `${path}token_full_cover.webp`, 12 | }, 13 | { 14 | id: 'partialCover', 15 | label: 'EFFECT.StatusPartialCover', 16 | icon: `${path}token_partial_cover.webp`, 17 | }, 18 | { 19 | id: 'overwatch', 20 | label: 'EFFECT.StatusOverwatch', 21 | icon: `${path}token_overwatch.webp`, 22 | }, 23 | { 24 | id: 'suppressed', 25 | label: 'EFFECT.StatusSuppressed', 26 | icon: `${path}token_suppressed.webp`, 27 | }, 28 | { 29 | id: 'stop', 30 | label: 'EFFECT.StatusStop', 31 | icon: `${path}token_stop.webp`, 32 | }, 33 | { 34 | id: 'smoke', 35 | label: 'EFFECT.StatusSmoke', 36 | icon: `${path}token_smoke.webp`, 37 | }, 38 | { 39 | id: 'fire', 40 | label: 'EFFECT.StatusFire', 41 | icon: `${path}token_fire.webp`, 42 | }, 43 | { 44 | icon: 'icons/svg/skull.svg', 45 | id: 'dead', 46 | label: 'EFFECT.StatusDead', 47 | }, 48 | { 49 | icon: 'icons/svg/sleep.svg', 50 | id: 'sleep', 51 | label: 'EFFECT.StatusAsleep', 52 | }, 53 | { 54 | icon: 'icons/svg/daze.svg', 55 | id: 'stun', 56 | label: 'EFFECT.StatusStunned', 57 | }, 58 | { 59 | icon: 'icons/svg/falling.svg', 60 | id: 'prone', 61 | label: 'EFFECT.StatusProne', 62 | }, 63 | { 64 | icon: 'icons/svg/net.svg', 65 | id: 'restrain', 66 | label: 'EFFECT.StatusRestrained', 67 | }, 68 | { 69 | icon: 'icons/svg/blind.svg', 70 | id: 'blind', 71 | label: 'EFFECT.StatusBlind', 72 | }, 73 | ]; 74 | } 75 | -------------------------------------------------------------------------------- /src/components/chat/templates/weapon-chat.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 |
    5 |

    {{name}}

    6 |
    7 | 8 |
    9 | {{name}} 10 |
    11 | 12 |
    13 | {{{system.description}}} 14 | {{!--

    {{localize "T2K4E.ItemSheet.FeaturesTab"}}

    --}} 15 |
    16 | {{#if system.rof}} 17 |
    {{localize "T2K4E.ItemSheet.RoF"}}: {{system.rof}}
    18 | {{/if}} 19 |
    {{localize "T2K4E.ItemSheet.Damage"}}: {{system.damage}}
    20 |
    {{localize "T2K4E.ItemSheet.Crit"}}: {{system.crit}}
    21 |
    {{localize "T2K4E.ItemSheet.Armor"}}: {{#if (gte system.armorModifier 1)}}+{{/if}}{{system.armorModifier}}
    22 | {{#if system.range}} 23 |
    {{localize "T2K4E.ItemSheet.Range"}}: {{system.range}}
    24 | {{/if}} 25 | {{#unless (eq system.blast "–")}} 26 |
    {{localize "T2K4E.ItemSheet.Blast"}}: {{system.blast}}
    27 | {{/unless}} 28 |
    29 |
    30 | 31 |
    32 | {{#unless system.isMounted}} 33 | 34 | {{!-- {{#if system.mag.max}} 35 | 36 | {{/if}} --}} 37 | {{/unless}} 38 |
    39 | 40 |
    41 |
    42 | -------------------------------------------------------------------------------- /src/components/armor.js: -------------------------------------------------------------------------------- 1 | import { YearZeroRoll } from 'yzur'; 2 | 3 | export default class Armor { 4 | // eslint-disable-next-line no-shadow 5 | constructor(rating, name, modifier = 0) { 6 | this.rating = rating; 7 | this.value = rating; 8 | this.name = name ?? 'Armor'; 9 | this.modifier = modifier; 10 | this.penetrated = false; 11 | this.damage = 0; 12 | } 13 | 14 | /* ------------------------------------------- */ 15 | /* Getters */ 16 | /* ------------------------------------------- */ 17 | 18 | get label() { 19 | return `${this.name} [${this.rating}]`; 20 | } 21 | 22 | get level() { 23 | return this.value > 0 ? Math.max(0, this.value + this.modifier) : 0; 24 | } 25 | 26 | get penetrationLimit() { 27 | return this.level - 2; 28 | } 29 | 30 | get damaged() { 31 | return this.value < this.rating; 32 | } 33 | 34 | /* ------------------------------------------- */ 35 | /* Methods */ 36 | /* ------------------------------------------- */ 37 | 38 | modify(n) { 39 | this._modifier = this.modifier; 40 | this.modifier = +n; 41 | } 42 | 43 | isPenetratedByDamage(baseDamage) { 44 | return baseDamage > this.penetrationLimit; 45 | } 46 | 47 | async penetration(amount, baseDamage, modifier) { 48 | const initialAmount = amount; 49 | if (modifier) this.modify(modifier); 50 | if (!this.isPenetratedByDamage(baseDamage)) amount = 0; 51 | else amount = Math.max(0, amount - this.level); 52 | this.damage += initialAmount - amount; 53 | if (amount > 0) { 54 | this.penetrated = true; 55 | await this.ablation(); 56 | } 57 | this.modify(this._modifier); 58 | return amount; 59 | } 60 | 61 | async ablation() { 62 | const roll = new YearZeroRoll('1d6np'); 63 | await roll.roll(); 64 | if (roll.total === 1) { 65 | this.value = Math.max(0, this.value - 1); 66 | return true; 67 | } 68 | return false; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/less/flex-layout.less: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------- */ 2 | /* Flexbox */ 3 | /* ------------------------------------------- */ 4 | 5 | // .flexrow { 6 | // display: flex; 7 | // flex-direction: row; 8 | // flex-wrap: wrap; 9 | // justify-content: flex-start; 10 | 11 | // > * { 12 | // flex: 1; 13 | // } 14 | 15 | // .flex0 { flex: 0; } 16 | // .flex1 { flex: 1; } 17 | // .flex2 { flex: 2; } 18 | // .flex3 { flex: 3; } 19 | // .flex4 { flex: 4; } 20 | // } 21 | 22 | // .flexcol { 23 | // display: flex; 24 | // flex-direction: column; 25 | // flex-wrap: nowrap; 26 | 27 | // > * { 28 | // flex: 1; 29 | // } 30 | 31 | // .flex0 { flex: 0; } 32 | // .flex1 { flex: 1; } 33 | // .flex2 { flex: 2; } 34 | // .flex3 { flex: 3; } 35 | // .flex4 { flex: 4; } 36 | // } 37 | 38 | .flex-center { 39 | justify-content: center; 40 | // text-align: center; 41 | } 42 | 43 | .flex-left { 44 | justify-content: flex-start; 45 | // text-align: left; 46 | } 47 | 48 | .flex-right { 49 | justify-content: flex-end; 50 | // text-align: right; 51 | } 52 | 53 | .flex-between { 54 | justify-content: space-between; 55 | } 56 | 57 | .flex-around { 58 | justify-content: space-around; 59 | } 60 | 61 | .flex-top { 62 | align-items: flex-start; 63 | } 64 | 65 | .flex-bottom { 66 | align-items: flex-end; 67 | } 68 | 69 | .flex-middle { 70 | align-items: center; 71 | } 72 | 73 | .flex-grow { 74 | flex-grow: 1; 75 | } 76 | 77 | .t2k4e .full { 78 | width: 100%; 79 | height: 100%; 80 | } 81 | 82 | /* ------------------------------------------- */ 83 | /* Column Layout */ 84 | /* ------------------------------------------- */ 85 | 86 | /** 87 | * Creates a range of styles from .col-1 to .col-12 88 | * for placing flex elements like in a table. 89 | */ 90 | .col-loop (@i) when (@i > 0) { 91 | .col-@{i} { 92 | flex: 0 0 auto; 93 | width: round((@i / 12 * 100%), 2); 94 | } 95 | .col-loop((@i - 1)); 96 | } 97 | .col-loop(12); -------------------------------------------------------------------------------- /src/components/dialog/templates/damage-choice-dialog.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{!-- INPUT VARIABLES (IN DATA): 4 | damage: number 5 | hitCount: number 6 | barrier: number 7 | location: string 8 | target: string 9 | isGM: boolean 10 | 11 | OUTPUT VARIABLES: 12 | damage: number 13 | hitCount: number 14 | barriers: string[] 15 | --}} 16 | 17 | {{#with data}} 18 | 19 | {{!-- ================================================== --}} 20 | 21 |

    22 | {{{localize "T2K4E.Dialog.Damage.Description" target=target}}} 23 | {{#if location}} 24 |
    {{localize "YZUR.CHAT.ROLL.HitLocation"}} {{localize (concat "T2K4E.ArmorLocationNames." location)}} 25 | {{/if}} 26 |

    27 | 28 | 29 | {{!-- BASE DAMAGE --}} 30 |
    31 | 32 | 33 |
    34 | 35 | {{!-- ================================================== --}} 36 | 37 | {{!-- EXTRA HITS --}} 38 | {{#if hitCount}} 39 |
    40 | 45 |
    46 |
    47 | {{/if}} 48 | 49 | {{!-- ================================================== --}} 50 | 51 | {{!-- BARRIER --}} 52 | {{#if barrier}} 53 |
    54 | 58 | 59 |
    60 | {{/if}} 61 | 62 | {{/with}} 63 | 64 | -------------------------------------------------------------------------------- /src/actor/party/components/character-picker-dialog.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | export class CharacterPickerDialog extends Dialog { 3 | /** 4 | * Show dialog that allows to pick a character from a list 5 | * 6 | */ 7 | static async show(title, characters = [], onSelect, onCancel) { 8 | onSelect = onSelect || function () {}; 9 | onCancel = onCancel || function () {}; 10 | 11 | const characterSelector = await this.buildCharacterSelector(characters); 12 | 13 | const d = new CharacterPickerDialog({ 14 | title: title, 15 | content: this.buildDivHtmlDialog(characterSelector), 16 | buttons: { 17 | cancel: { 18 | icon: '', 19 | label: 'Cancel', 20 | callback: onCancel, 21 | }, 22 | }, 23 | select: onSelect, 24 | default: 'cancel', 25 | close: onCancel, 26 | }); 27 | d.render(true); 28 | } 29 | 30 | /** 31 | * @param {string} html Dialog content 32 | */ 33 | activateListeners(html) { 34 | super.activateListeners(html); 35 | html.find('.party-member').click(this.handleCharacterSelect.bind(this)); 36 | } 37 | 38 | handleCharacterSelect(event) { 39 | this.data.select($(event.currentTarget).data('entity-id')); 40 | this.close(); 41 | } 42 | 43 | /** 44 | * @param {Array} characters Array with character IDs 45 | */ 46 | static async buildCharacterSelector(characters) { 47 | let html = ''; 48 | let actor; 49 | for (let i = 0; i < characters.length; i++) { 50 | actor = characters[i] instanceof Actor ? characters[i] : game.actors.get(characters[i]); 51 | html += await foundry.applications.handlebars.renderTemplate('systems/t2k4e/templates/actor/party/components/member-component.hbs', { 52 | partyMember: actor, 53 | noCharSheetLink: true, 54 | }); 55 | } 56 | return `
      ${html}
    `; 57 | } 58 | 59 | /** 60 | * @param {string} divContent 61 | */ 62 | static buildDivHtmlDialog(divContent) { 63 | return '
    ' + divContent + '
    '; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/utils/get-actor.js: -------------------------------------------------------------------------------- 1 | export async function getActiveActor() { 2 | let actor; 3 | if (game.user.isGM && canvas.ready && canvas.tokens.controlled.length > 1) { 4 | return chooseActor(canvas.tokens.controlled.map(t => t.actor), { 5 | title: game.i18n.localize('T2K4E.MACRO.GetActorTitle'), 6 | notes: game.i18n.localize('T2K4E.MACRO.GetActorHint'), 7 | }); 8 | } 9 | const speaker = ChatMessage.getSpeaker(); 10 | if (speaker.token) actor = game.actors.tokens[speaker.token]; 11 | if (!actor) actor = game.actors.get(speaker.actor); 12 | if (!actor) { 13 | ui.notifications.warn(game.i18n.format('T2K4E.MACRO.NoActor', { 14 | actor: speaker.alias, 15 | })); 16 | return; 17 | } 18 | return actor; 19 | } 20 | 21 | /** 22 | * Displays a dialog for requesting the choice of an Actor. 23 | * @see {@link Dialog} 24 | * @param {Actor[]} actors 25 | * @param {Object} [options] 26 | * @param {string} [options.title] 27 | * @param {string} [options.notes] 28 | * @returns {Promise} Selected Actor 29 | */ 30 | export async function chooseActor(actors = [], options = {}) { 31 | let content = '
    ' 32 | + ''; 42 | if (options.notes) content += `

    ${options.notes}

    `; 43 | content += '
    '; 44 | 45 | const actorId = await Dialog.prompt({ 46 | title: options.title ?? 'Choose an Actor', 47 | content, 48 | label: game.i18n.localize('T2K4E.Dialog.Actions.Ok'), 49 | callback: html => html[0].querySelector('form').actor.value, 50 | rejectClose: false, 51 | options: { 52 | width: 400, 53 | classes: ['t2k4e', 'dialog'], 54 | minimizable: false, 55 | }, 56 | }); 57 | 58 | return actors.find(a => a.id === actorId); 59 | } 60 | -------------------------------------------------------------------------------- /src/actor/templates/parts/slots/slot-buttons.hbs: -------------------------------------------------------------------------------- 1 | 56 | -------------------------------------------------------------------------------- /src/components/dialog/templates/cuf-dialog.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{! ================================================== }} 4 | 5 | {{! Unit Morale }} 6 |
    7 | 8 | 9 |
    10 | 11 |
    12 | 13 | {{! Modifier }} 14 |
    15 | 16 |
    17 | 25 | 32 | {{!-- --}} 33 |
    34 |
    35 | 36 | {{! Modifiers }} 37 |
    38 | {{#each data.modifiers}} 39 | 43 | {{/each}} 44 |
    45 | 46 | {{! ================================================== }} 47 | 48 |
    49 | 50 | {{! Max Pushes }} 51 |
    52 | 53 | 54 |
    55 | 56 | {{! ================================================== }} 57 | 58 |
    59 | 60 | {{! Roll Mode }} 61 |
    62 | 63 | 66 |
    67 | 68 |
    -------------------------------------------------------------------------------- /src/actor/templates/parts/vehicle-crew.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 | 5 |
    6 |
    7 | 8 | 9 |
    10 |
    11 | 12 | {{!-- ================================================== --}} 13 | 14 | {{!-- CREW OCCUPANTS --}} 15 |
    16 | {{#each crew}} 17 |
    18 | 19 | {{!-- Position --}} 20 |
    21 | 24 |
    25 | 26 | {{!-- Image --}} 27 | 28 | 29 | {{!-- Health Bar --}} 30 | 31 | 32 | {{!-- Name --}} 33 |
    {{actor.name}}
    34 | 35 | {{!-- Exposed checkbox --}} 36 |
    37 | 41 |
    42 | 43 | {{!-- Buttons --}} 44 |
    45 | {{#unless actor.isCrewDeleted}} 46 | 47 | {{{@root.config.Icons.buttons.edit}}} 48 | 49 | {{/unless}} 50 | 51 | {{{@root.config.Icons.buttons.remove}}} 52 | 53 |
    54 | 55 |
    56 | {{else}} 57 |
    {{localize "T2K4E.VehicleSheet.EmptyCrew"}}
    58 | {{/each}} 59 |
    60 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | // "$schema": "https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/eslintrc.json", 3 | "parserOptions": { 4 | "ecmaVersion": "latest", 5 | "sourceType": "module" 6 | }, 7 | "env": { 8 | "browser": true, 9 | "jquery": true, 10 | "node": true, 11 | "es6": true 12 | }, 13 | "extends": [ 14 | "eslint:recommended", 15 | "jquery", 16 | "@typhonjs-fvtt/eslint-config-foundry.js/0.8.0", 17 | "prettier" 18 | ], 19 | "plugins": [ 20 | "prettier" 21 | ], 22 | "rules": { 23 | // "prettier/prettier": ["error"], 24 | "arrow-parens": ["error", "as-needed"], 25 | "brace-style": ["error", "stroustrup", { "allowSingleLine": true }], 26 | "comma-dangle": ["error", "always-multiline"], 27 | "comma-spacing": "error", 28 | "comma-style": "error", 29 | "curly": ["error", "multi-line"], 30 | "dot-location": ["error", "property"], 31 | "eqeqeq": 0, // ["warn", "always", { "null": "ignore" }], 32 | "handle-callback-err": "off", 33 | "indent": ["error", 2, { "SwitchCase": 1 }], 34 | "linebreak-style": ["error", "unix"], 35 | "max-len": ["error", { "code": 120, "ignoreUrls": true }], 36 | "max-nested-callbacks": ["error", { "max": 4 }], 37 | "max-statements-per-line": ["error", { "max": 2 }], 38 | "no-console": "off", 39 | "no-empty-function": "warn", 40 | "no-floating-decimal": "error", 41 | "no-inline-comments": "off", 42 | "no-lonely-if": "error", 43 | "no-multi-spaces": "error", 44 | "no-multiple-empty-lines": ["error", { "max": 2, "maxEOF": 1, "maxBOF": 0 }], 45 | "no-prototype-builtins": "off", 46 | "no-shadow": ["error", { "builtinGlobals": true, "hoist": "all", "allow": ["event"] }], 47 | "no-trailing-spaces": ["error", { "ignoreComments": true }], 48 | "no-unreachable": "warn", 49 | "no-unused-labels": 0, 50 | "no-unused-vars": "warn", 51 | "no-var": "error", 52 | "object-curly-spacing": ["error", "always"], 53 | "prefer-const": "warn", 54 | "quotes": ["error", "single"], 55 | "semi": ["error", "always"], 56 | "space-before-blocks": "error", 57 | "space-before-function-paren": ["error", { 58 | "anonymous": "always", 59 | "named": "never", 60 | "asyncArrow": "always" 61 | }], 62 | "space-in-parens": ["error", "never"], 63 | "space-infix-ops": "error", 64 | "space-unary-ops": "error", 65 | "spaced-comment": "error", 66 | "yoda": "error" 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /static/system.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "t2k4e", 3 | "title": "Twilight: 2000 🪖 (4th Edition)", 4 | "description": "Twilight: 2000 is a roleplaying game about survival in mankind’s most desperate hour. Yet, in this bleak world, there is still hope. In the midst of utter destruction, you can start to build something new. Rally people to your ranks. Stake a claim and protect it. And maybe, if you live long enough, start turning the tide.", 5 | "version": "13.0.3", 6 | "compatibility": { 7 | "minimum": 13, 8 | "verified": "13.351", 9 | "maximum": 13 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Stefouch", 14 | "url": "https://stefouch.be", 15 | "discord": "@Stefouch" 16 | }, 17 | { 18 | "name": "Free League Developer Community", 19 | "url": "https://github.com/orgs/fvtt-fria-ligan" 20 | } 21 | ], 22 | "scripts": [], 23 | "esmodules": [ 24 | "t2k4e.js" 25 | ], 26 | "styles": [ 27 | "t2k4e.css" 28 | ], 29 | "languages": [ 30 | { 31 | "lang": "en", 32 | "name": "English", 33 | "path": "lang/en.json" 34 | }, 35 | { 36 | "lang": "fr", 37 | "name": "French (Français)", 38 | "path": "lang/fr.json" 39 | }, 40 | { 41 | "lang": "sv", 42 | "name": "Swedish (Svenska)", 43 | "path": "lang/sv.json" 44 | }, 45 | { 46 | "lang": "es", 47 | "name": "Spanish (Española)", 48 | "path": "lang/es.json" 49 | }, 50 | { 51 | "lang": "de", 52 | "name": "German (Deutsch)", 53 | "path": "lang/de.json" 54 | }, 55 | { 56 | "lang": "uk", 57 | "name": "Ukrainian (українська)", 58 | "path": "lang/uk.json" 59 | }, 60 | { 61 | "lang": "ru", 62 | "name": "Russian (Русский)", 63 | "path": "lang/ru.json" 64 | } 65 | ], 66 | "packs": [], 67 | "flags": {}, 68 | "socket": false, 69 | "protected": false, 70 | "background": "systems/t2k4e/assets/gear-intro_c.jpg", 71 | "grid": { 72 | "distance": 2, 73 | "units": "m" 74 | }, 75 | "primaryTokenAttribute": "health", 76 | "secondaryTokenAttribute": "sanity", 77 | "initiative": "1d10", 78 | "url": "https://github.com/fvtt-fria-ligan/twilight2000-foundry-vtt", 79 | "manifest": "https://github.com/fvtt-fria-ligan/twilight2000-foundry-vtt/releases/latest/download/system.json", 80 | "download": "https://github.com/fvtt-fria-ligan/twilight2000-foundry-vtt/releases/download/13.0.3/t2k4e-fvtt_v13.0.3.zip", 81 | "license": "GPL-3.0-or-later" 82 | } 83 | -------------------------------------------------------------------------------- /src/actor/party/templates/sheet-tabs/travel-tab.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    {{localize "FLPS.PARTY.HINT_ASSIGN"}}
    3 |
    4 | 5 |
    6 | 7 | 8 | 11 | 14 | 17 | 18 | 19 | 22 | 23 | 24 | 27 | 30 | 33 | 34 | 35 | 38 | 41 | 42 | 43 | 46 | 49 | 52 | 53 |
    9 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.march action=travelActions.march }} 10 | 12 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.rest action=travelActions.rest }} 13 | 15 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.sleep action=travelActions.sleep }} 16 |
    20 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.drive action=travelActions.drive }} 21 |
    25 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.watch action=travelActions.watch }} 26 | 28 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.camp action=travelActions.camp }} 29 | 31 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.other action=travelActions.other }} 32 |
    36 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.hunt action=travelActions.hunt }} 37 | 39 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.scrounge action=travelActions.scrounge }} 40 |
    44 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.forage action=travelActions.forage }} 45 | 47 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.fish action=travelActions.fish }} 48 | 50 | {{> systems/t2k4e/templates/actor/party/components/action-component.hbs assignedCharacters=travel.cook action=travelActions.cook }} 51 |
    54 |
    55 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "t2k4e", 3 | "version": "13.0.3", 4 | "description": "A Foundry VTT system for Twilight 2000 4E (Free League Publishing)", 5 | "type": "module", 6 | "author": "Stefouch", 7 | "license": "GPL-3.0-or-later", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/fvtt-fria-ligan/twilight2000-foundry-vtt.git" 11 | }, 12 | "bugs": { 13 | "url": "https://github.com/fvtt-fria-ligan/twilight2000-foundry-vtt/issues" 14 | }, 15 | "homepage": "https://github.com/fvtt-fria-ligan/twilight2000-foundry-vtt#readme", 16 | "keywords": [ 17 | "Foundry", 18 | "VTT", 19 | "T2K", 20 | "T2K4", 21 | "T2K4E", 22 | "Twilight 2000", 23 | "Free League", 24 | "Free League Publishing", 25 | "Fria Ligan", 26 | "RPG", 27 | "TTRPG", 28 | "Roleplaying Game", 29 | "Tabletop Roleplaying Game" 30 | ], 31 | "main": "src/t2k4e.js", 32 | "scripts": { 33 | "dev": "cross-env NODE_ENV=development gulp build", 34 | "dev:watch": "cross-env NODE_ENV=development gulp watch", 35 | "build": "cross-env NODE_ENV=production gulp build", 36 | "link": "node ./tools/link-project.js", 37 | "link:force": "node ./tools/link-project.js --force", 38 | "clean": "gulp clean", 39 | "bump": "cross-env NODE_ENV=production npm run lint:fix && gulp bump --r", 40 | "release": "gulp release", 41 | "lint": "eslint --ext .js .", 42 | "lint:fix": "eslint --ext .js --fix .", 43 | "format": "prettier-eslint \"**/*.js\" --write", 44 | "format:hbs": "prettier-eslint **/*.hbs --write --parser=glimmer", 45 | "postinstall": "npx husky install && npx patch-package", 46 | "upd": "npm list -g --depth=0 & npm outdated & npx npm-check -u", 47 | "test": "echo \"Error: no test specified\" && exit 1" 48 | }, 49 | "dependencies": { 50 | "yzur": "github:Stefouch/foundry-year-zero-roller#v6.0.0" 51 | }, 52 | "devDependencies": { 53 | "@league-of-foundry-developers/foundry-vtt-types": "^9.280.0", 54 | "@types/jquery": "^3.5.16", 55 | "@typhonjs-fvtt/eslint-config-foundry.js": "0.8.0", 56 | "chalk": "^5.3.0", 57 | "cross-env": "7.0.3", 58 | "devmoji": "2.3.0", 59 | "esbuild": "^0.15.18", 60 | "eslint": "^8.47.0", 61 | "eslint-config-jquery": "^3.0.1", 62 | "eslint-config-prettier": "^9.0.0", 63 | "eslint-plugin-prettier": "^5.0.0", 64 | "execa": "^6.1.0", 65 | "fs-extra-plus": "^0.6.0", 66 | "gulp": "^4.0.2", 67 | "gulp-clean-css": "^4.3.0", 68 | "gulp-less": "^5.0.0", 69 | "gulp-yaml": "2.0.4", 70 | "husky": "^8.0.3", 71 | "less": "^4.2.0", 72 | "prettier": "^3.0.1", 73 | "prettier-eslint-cli": "^7.1.0", 74 | "semver": "^7.5.4", 75 | "standard-version": "^9.3.2" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: '🐛 Bug report' 2 | description: Create a report to help us improve. 3 | labels: ['bug'] 4 | body: 5 | - type: markdown 6 | attributes: 7 | value: Thanks for your interest in the project and taking the time to fill out this bug report! 8 | - type: textarea 9 | id: bug-description 10 | attributes: 11 | label: Describe the bug 12 | description: A clear and concise description of what the bug is. If you intend to submit a PR for this issue, tell us in the description. Thanks! 13 | placeholder: I am doing ... What I expect is ... What actually happening is ... 14 | validations: 15 | required: true 16 | - type: textarea 17 | id: reproduction 18 | attributes: 19 | label: Reproduction 20 | description: Please provide a step by step guide to reproduce the issue. 21 | placeholder: Reproduction steps 22 | validations: 23 | required: true 24 | - type: textarea 25 | id: system-info 26 | attributes: 27 | label: System Info 28 | description: | 29 | Please provide a bullet list of your system information. 30 | - OS: [e.g. macOS] 31 | - Client [e.g. Foundry Desktop app, Chrome, Firefox] 32 | - Foundry Version [e.g. 9.269, 10] 33 | render: sh 34 | placeholder: System, OS, version, etc. 35 | validations: 36 | required: true 37 | - type: textarea 38 | id: logs 39 | attributes: 40 | label: Logs 41 | description: | 42 | You can find logs by pressing "f12" or "cmd+shift+i" in the browser-window/Foundry. Please try not to insert an image but copy paste the log text. 43 | - type: dropdown 44 | id: severity 45 | attributes: 46 | label: Priority this issue should have? 47 | description: Please be realistic. If you need to elaborate on your reasoning, please use the Issue description field above. 48 | multiple: false 49 | options: 50 | - Trivial (typos, etc) 51 | - Low (formatting issues, things that don't impact operation) 52 | - Medium (minor functional impact) 53 | - High (a broken feature, major functional impact) 54 | - Critical (extremely major functional impact) 55 | - type: checkboxes 56 | id: checkboxes 57 | attributes: 58 | label: Validations 59 | description: Before submitting the issue, please make sure you have done the following when troubleshooting the issue 60 | options: 61 | - label: Done a clean install of the system. 62 | required: true 63 | - label: Disabled all modules. 64 | required: true 65 | - label: Checked if the issue is present in a new world instance (create a new world in foundry using the Twilight 2000 system). 66 | required: true 67 | -------------------------------------------------------------------------------- /src/components/message-system.js: -------------------------------------------------------------------------------- 1 | /* -------------------------------------------- */ 2 | /* Author: @aMediocreDad */ 3 | /* -------------------------------------------- */ 4 | import semverComp from '@utils/semver-compare'; 5 | 6 | const SYSTEM_NAME = 't2k4e'; 7 | 8 | export default async function displayMessages() { 9 | const messages = await fetch(`systems/${SYSTEM_NAME}/assets/messages/messages.jsonc`) 10 | .then(resp => resp.text()) 11 | .then(jsonc => JSON.parse(stripJSON(jsonc))); 12 | 13 | messages.forEach(message => { 14 | handleDisplay(message); 15 | }); 16 | } 17 | 18 | const stripJSON = data => { 19 | return data.replace(/[^:]\/\/(.*)/g, ''); 20 | }; 21 | 22 | const handleDisplay = msg => { 23 | const { content, title, type } = msg; 24 | if (!isCurrent(msg)) return; 25 | if (type === 'prompt') return displayPrompt(title, content); 26 | if (type === 'chat') return sendToChat(title, content); 27 | }; 28 | 29 | const isCurrent = msg => { 30 | const isDisplayable = !msg.display === 'once' || !hasDisplayed(msg.title); 31 | const correctCoreVersion = 32 | foundry.utils.isNewerVersion(msg['max-core-version'] ?? '100.0.0', game.version) && 33 | foundry.utils.isNewerVersion(game.version, msg['min-core-version'] ?? '0.0.0'); 34 | const correctSysVersion = semverComp( 35 | msg['min-sys-version'] ?? '0.0.0', 36 | game.system.version, 37 | msg['max-sys-version'] ?? '100.0.0', 38 | { gEqMin: true }, 39 | ); 40 | return isDisplayable && correctCoreVersion && correctSysVersion; 41 | }; 42 | 43 | const hasDisplayed = identifier => { 44 | const settings = game.settings.get(SYSTEM_NAME, 'messages'); 45 | if (settings?.includes(identifier)) return true; 46 | else return false; 47 | }; 48 | 49 | const displayPrompt = (title, content) => { 50 | content = content.replace('{name}', game.user.name); 51 | return Dialog.prompt({ 52 | title: title, 53 | content: `${content}`, 54 | label: 'Understood!', 55 | options: { width: 400, classes: [SYSTEM_NAME, 'dialog'] }, 56 | callback: () => setDisplayed(title), 57 | }); 58 | }; 59 | 60 | const sendToChat = (title, content) => { 61 | content = content.replace('{name}', game.user.name); 62 | setDisplayed(title); 63 | const footer = `
    ${game.i18n.localize('NUE.FirstLaunchHint')}
    `; 64 | return ChatMessage.create({ 65 | whisper: [game.user.id], 66 | speaker: { alias: 'Twilight: 2000 4E' }, 67 | flags: { core: { canPopout: true } }, 68 | title: title, 69 | content: `

    ${title}

    ${content}${footer}
    `, 70 | }); 71 | }; 72 | 73 | const setDisplayed = async identifier => { 74 | const settings = game.settings.get(SYSTEM_NAME, 'messages'); 75 | settings.push(identifier); 76 | await game.settings.set(SYSTEM_NAME, 'messages', settings.flat()); 77 | }; 78 | -------------------------------------------------------------------------------- /src/system/enricher.js: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------ */ 2 | /* T2K SYMBOL */ 3 | /* Generates a T2K symbol */ 4 | /* ------------------------------------------ */ 5 | 6 | /** 7 | * - $1: Symbol 8 | * @example "[[S]] or [[F]] or [[B]] etc." 9 | */ 10 | const T2K_SYMBOL_PATTERN = /\[\[([SFBRTDNC]+)\]\]/gm; 11 | 12 | async function t2kSymbolEnricher(match) { 13 | const symbolDoc = document.createElement('span'); 14 | symbolDoc.className = 't2k-symbol'; 15 | symbolDoc.innerHTML = match[1]; 16 | return symbolDoc; 17 | } 18 | 19 | /* ------------------------------------------ */ 20 | /* FONT AWESOME ICON */ 21 | /* Generates a FontAwesome icon HTML text */ 22 | /* ------------------------------------------ */ 23 | 24 | /** 25 | * - $1: Icon classes 26 | * @example "@FontAwesomeIcon[fas fa-cog]" 27 | */ 28 | const FONT_AWESOME_ICON_PATTERN = /@FontAwesomeIcon\[(.+?)\]/gm; 29 | 30 | async function fontAwesomeIconEnricher(match) { 31 | const iconDoc = document.createElement('i'); 32 | // iconDoc.style.textIndent = 0; // Fix for inherited

    indent 33 | iconDoc.className = match[1]; 34 | return iconDoc; 35 | } 36 | 37 | /* ------------------------------------------ */ 38 | /* INLINE ICON IMAGE */ 39 | /* Generates a small inline icon */ 40 | /* from an image */ 41 | /* ------------------------------------------ */ 42 | 43 | /** 44 | * - $1: Path to the image 45 | * - $2: Tooltip text 46 | * @example "@IconImage[icons/svg/dice-target.svg]{Dice Target}" 47 | */ 48 | const INLINE_ICON_IMAGE = /@IconImage\[(.+?)\](?:{(.+?)})?/gm; 49 | 50 | async function iconImageEnricher(match) { 51 | const imgDoc = document.createElement('img'); 52 | imgDoc.setAttribute('src', match[1]); 53 | // imgDoc.setAttribute('width', 16); 54 | // imgDoc.setAttribute('height', 16); 55 | imgDoc.style.width = '1em'; 56 | imgDoc.style.height = '1em'; 57 | imgDoc.style.verticalAlign = 'middle'; 58 | // imgDoc.style.lineHeight = 0; 59 | imgDoc.className = 'nopopout'; 60 | 61 | if (match[2]) { 62 | imgDoc.setAttribute('data-tooltip', match[2]); 63 | } 64 | 65 | return imgDoc; 66 | } 67 | 68 | /* ------------------------------------------ */ 69 | 70 | // function _createBrokenLink(type, title) { 71 | // return `` 72 | // // + '' 73 | // + '' 74 | // + `${title}`; 75 | // } 76 | 77 | export function enrichTextEditors() { 78 | CONFIG.TextEditor.enrichers.push( 79 | { 80 | pattern: T2K_SYMBOL_PATTERN, 81 | enricher: t2kSymbolEnricher, 82 | }, 83 | { 84 | pattern: FONT_AWESOME_ICON_PATTERN, 85 | enricher: fontAwesomeIconEnricher, 86 | }, 87 | { 88 | pattern: INLINE_ICON_IMAGE, 89 | enricher: iconImageEnricher, 90 | }); 91 | } 92 | -------------------------------------------------------------------------------- /src/item/templates/parts/item-modifiers.hbs: -------------------------------------------------------------------------------- 1 |

    2 | 3 |
    4 |

    {{localize 'T2K4E.ItemSheet.RollModifiers'}}

    5 | 6 | {{{@root.config.Icons.buttons.plus}}} 7 | 8 |
    9 | 10 | {{#each system.rollModifiers as |modifier|}} 11 |
    12 |
    13 | 31 |
    32 | 40 |
    41 | {{else}} 42 |
    {{localize 'T2K4E.ItemSheet.NoRollModifier'}}
    43 | {{/each}} 44 | 45 | {{! TODO clean this code }} 46 | {{!--

    {{localize "T2K4E.Attributes"}}

    47 |
    48 | {{#each system.modifiers.attributes as |value name|}} 49 |
    50 | 51 | 53 |
    54 | {{/each}} 55 |
    56 |

    {{localize "T2K4E.Skills"}}

    57 |
    58 | {{#each system.modifiers.skills as |value name|}} 59 |
    60 | 61 | 63 |
    64 | {{/each}} 65 |
    --}} 66 |
    -------------------------------------------------------------------------------- /src/less/inventory.less: -------------------------------------------------------------------------------- 1 | @itemGap: 4px; 2 | 3 | .t2k4e.sheet .inventory { 4 | margin: 0; 5 | padding: 0; 6 | overflow-y: auto; 7 | height: 100%; 8 | 9 | .items-header { 10 | align-items: flex-end; 11 | text-align: center; 12 | padding: 2px @itemGap 0 @itemGap; 13 | background: @colorActorH2; 14 | border-top: @borderSheetBold; 15 | border-bottom: @borderSheetBold; 16 | 17 | > div h2 { 18 | padding: 0; 19 | border: 0 none; 20 | background: none; 21 | } 22 | 23 | > div h5 { 24 | border-left: @borderSheet; 25 | } 26 | } 27 | 28 | .item-list { 29 | .item { 30 | padding: 2px @itemGap; 31 | align-items: center; 32 | font-size: .8rem !important; 33 | 34 | &:not(:first-child) { 35 | border-top: @borderSheet; 36 | } 37 | 38 | &:hover { 39 | background-color: @colorBeige; 40 | } 41 | 42 | .item-name > img { 43 | cursor: pointer; 44 | } 45 | 46 | .item-name > a { 47 | // flex: 0; 48 | white-space: nowrap; 49 | overflow: hidden; 50 | text-overflow: ellipsis; 51 | max-width: min-content; 52 | min-height: 100%; 53 | } 54 | } 55 | } 56 | 57 | /* ------------------------------------------- */ 58 | 59 | .item-name { 60 | flex: 2; 61 | margin: 0; 62 | overflow: hidden; 63 | text-align: left; 64 | align-items: center; 65 | 66 | img { 67 | max-width: 24px; 68 | max-height: 24px; 69 | margin-right: 4px; 70 | } 71 | } 72 | 73 | .item-detail { 74 | text-align: center; 75 | word-break: break-all; 76 | white-space: nowrap; 77 | overflow: hidden; 78 | 79 | flex: 0 0 40px; 80 | } 81 | 82 | .item-controls { 83 | display: flex; 84 | flex-direction: row; 85 | flex: 0 0 80px; 86 | padding-bottom: 2px; 87 | text-align: right; 88 | font-size: .7rem; 89 | justify-content: flex-end; 90 | 91 | a.button { 92 | border: none; 93 | padding-bottom: 2px; 94 | text-align: right; 95 | font-size: .7rem; 96 | background: transparent; 97 | padding-inline: 2px; 98 | } 99 | 100 | 101 | .item-buttons { 102 | display: flex; 103 | 104 | a.button { 105 | border: none; 106 | padding-bottom: 2px; 107 | text-align: right; 108 | font-size: .7rem; 109 | background: transparent; 110 | padding-inline: 2px; 111 | } 112 | 113 | a.button + a.button { 114 | margin-left: 2px; 115 | } 116 | 117 | } 118 | 119 | 120 | .item-equip:not(.equipped), 121 | .item-backpack:not(.packed) { 122 | color: @colorTan; 123 | } 124 | } 125 | 126 | /* ------------------------------------------- */ 127 | /* Specific Entries */ 128 | /* ------------------------------------------- */ 129 | 130 | .item-cover { 131 | flex: 0 0 70px; 132 | text-align: right; 133 | padding-right: 2 * @itemGap; 134 | font-size: .7rem; 135 | } 136 | 137 | .item-quantity { 138 | flex: 0 0 70px; 139 | } 140 | 141 | .inventory-ammo .item-quantity { 142 | text-align: right; 143 | padding-right: 2 * @itemGap; 144 | } 145 | 146 | // .ammo-list { 147 | // padding: 2px @itemGap; 148 | // } 149 | } 150 | -------------------------------------------------------------------------------- /src/system/settings.js: -------------------------------------------------------------------------------- 1 | // config: true (visible) 2 | // scope: world (gm), client (player) 3 | 4 | /** 5 | * Registers system settings. 6 | */ 7 | export function registerSystemSettings() { 8 | // Tracks the system version. 9 | game.settings.register('t2k4e', 'systemMigrationVersion', { 10 | config: false, 11 | scope: 'world', 12 | name: 'System Migration Version', 13 | type: String, 14 | default: '', 15 | }); 16 | game.settings.register('t2k4e', 'messages', { 17 | name: 'Displayed Messages', 18 | hint: 'Used to track which messages have been displayed', 19 | scope: 'world', 20 | config: false, 21 | type: Array, 22 | default: [], 23 | }); 24 | 25 | game.settings.register('t2k4e', 'hideCapacitiesButtons', { 26 | config: true, 27 | scope: 'world', 28 | name: 'SETTINGS.hideCapacitiesButtons.name', 29 | hint: 'SETTINGS.hideCapacitiesButtons.label', 30 | type: Boolean, 31 | default: false, 32 | }); 33 | 34 | game.settings.register('t2k4e', 'hideWeaponProps', { 35 | config: true, 36 | scope: 'world', 37 | name: 'SETTINGS.hideWeaponProps.name', 38 | hint: 'SETTINGS.hideWeaponProps.label', 39 | type: Boolean, 40 | default: false, 41 | }); 42 | 43 | game.settings.register('t2k4e', 'trackPcAmmo', { 44 | config: true, 45 | scope: 'world', 46 | name: 'SETTINGS.trackPcAmmo.name', 47 | hint: 'SETTINGS.trackPcAmmo.label', 48 | type: Boolean, 49 | default: true, 50 | }); 51 | 52 | game.settings.register('t2k4e', 'trackNpcAmmo', { 53 | config: true, 54 | scope: 'world', 55 | name: 'SETTINGS.trackNpcAmmo.name', 56 | hint: 'SETTINGS.trackNpcAmmo.label', 57 | type: Boolean, 58 | default: false, 59 | }); 60 | 61 | game.settings.register('t2k4e', 'trackVehicleAmmo', { 62 | config: true, 63 | scope: 'world', 64 | name: 'SETTINGS.trackVehicleAmmo.name', 65 | hint: 'SETTINGS.trackVehicleAmmo.label', 66 | type: Boolean, 67 | default: true, 68 | }); 69 | 70 | game.settings.register('t2k4e', 'showTaskCheckOptions', { 71 | config: true, 72 | scope: 'client', 73 | name: 'SETTINGS.showTaskCheckOptions.name', 74 | hint: 'SETTINGS.showTaskCheckOptions.label', 75 | type: Boolean, 76 | default: true, 77 | }); 78 | 79 | game.settings.register('t2k4e', 'closeRollTooltipDelay', { 80 | config: true, 81 | scope: 'client', 82 | name: 'SETTINGS.closeRollTooltipDelay.name', 83 | hint: 'SETTINGS.closeRollTooltipDelay.label', 84 | type: Number, 85 | default: 60, 86 | }); 87 | 88 | game.settings.register('t2k4e', 'defaultCharTokenSize', { 89 | config: true, 90 | scope: 'world', 91 | name: 'SETTINGS.defaultCharTokenSize.name', 92 | hint: 'SETTINGS.defaultCharTokenSize.label', 93 | type: Number, 94 | default: 1, 95 | }); 96 | 97 | game.settings.register('t2k4e', 'travelRollAllowPush', { 98 | config: false, 99 | scope: 'world', 100 | name: 'FLPS.SETTINGS.ALLOW_PUSH', 101 | hint: 'FLPS.SETTINGS.ALLOW_PUSH_HINT', 102 | type: Boolean, 103 | default: false, 104 | }); 105 | } 106 | -------------------------------------------------------------------------------- /src/item/templates/injury-sheet.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{!-- Item Sheet Header --}} 4 | {{> "systems/t2k4e/templates/item/parts/item-header.hbs"}} 5 | 6 | {{!-- Sheet Tab Navigation --}} 7 | 12 | 13 | {{!-- Sheet Body --}} 14 |
    15 | 16 | {{!-- Features Tab --}} 17 |
    18 |
    19 |
    20 | 21 | 24 |
    25 |
    26 | 27 | 30 |
    31 |
    32 | 33 | 34 |
    35 |
    36 | 37 | {{!-- Other Parameters --}} 38 |
    39 |
    40 | {{!-- --}} 41 | 42 |
    43 | {{!--
    --}} 44 | {{!--
    --}} 45 |
    46 | 50 |
    51 | {{#if system.lethal}} 52 |
    53 | 54 |
    55 | {{/if}} 56 |
    57 |
    58 | 59 | {{!-- Modifiers Tab --}} 60 |
    61 | {{> "systems/t2k4e/templates/item/parts/item-modifiers.hbs"}} 62 |
    63 | 64 | {{!-- Description Tab --}} 65 | {{!--
    66 | {{> "systems/t2k4e/templates/item/parts/item-description.hbs"}} 67 |
    --}} 68 | 69 |
    70 | 71 |
    72 | -------------------------------------------------------------------------------- /src/components/roll/templates/infos.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{! MYZ & FBL — Attributes and Gear damage }} 4 | {{#if (or (eq roll.game 'myz') (eq roll.game 'fbl'))}} 5 | {{#if roll.pushed}} 6 | {{#if roll.attributeTrauma}} 7 |
    8 | {{localize 'YZUR.CHAT.ROLL.Trauma'}} 9 | {{roll.attributeTrauma}} 10 |
    11 | {{/if}} 12 | {{#if roll.gearDamage}} 13 |
    14 | {{localize 'YZUR.CHAT.ROLL.GearDamage'}} 15 | {{roll.gearDamage}} 16 |
    17 | {{/if}} 18 | {{/if}} 19 | {{/if}} 20 | 21 | {{! TWILIGHT 2000 4E }} 22 | {{#if (eq roll.game 't2k')}} 23 | {{! T2K: Hit Location }} 24 | {{#if roll.bestHitLocation}} 25 |
    26 | {{#if (gt (lookup roll.hitLocations 'length') 1)}} 27 | {{localize 'YZUR.CHAT.ROLL.HitLocations'}} 28 | {{else}} 29 | {{localize 'YZUR.CHAT.ROLL.HitLocation'}} 30 | {{/if}} 31 | {{#each roll.hitLocations as |loc|}} 32 | {{localize (concat 'YZUR.CHAT.ROLL.Locations.' loc)}} 33 | {{/each}} 34 |
    35 | {{/if}} 36 | 37 | {{! T2K: Extra Hits }} 38 | {{#if roll.hitCount}} 39 |
    40 | {{#if (gt roll.baseSuccessQty 0)}} 41 | {{#if (gt roll.hitCount 1)}}{{localize 'YZUR.CHAT.ROLL.ExtraHits'}}{{else}}{{localize 42 | 'YZUR.CHAT.ROLL.ExtraHit' 43 | }}{{/if}} 44 | {{else}} 45 | {{localize 'YZUR.CHAT.ROLL.Suppression'}} 46 | {{/if}} 47 | {{roll.hitCount}} 48 |
    49 | {{/if}} 50 | 51 | {{! T2K: Damage/Stress }} 52 | {{#if (and roll.pushed roll.attributeTrauma)}} 53 |
    54 | {{localize 'YZUR.CHAT.ROLL.DamageOrStress'}} 55 | {{roll.attributeTrauma}} 56 |
    57 | {{/if}} 58 | 59 | {{! T2K: Ammo Spent }} 60 | {{#if roll.ammoSpent}} 61 |
    62 | {{localize 'YZUR.CHAT.ROLL.AmmoSpent'}} 63 | {{add roll.ammoSpent 1}} 64 |
    65 | 66 | {{! T2K: Jamming }} 67 | {{#if (and roll.pushed roll.jamCount)}} 68 |
    69 | {{localize 'YZUR.CHAT.ROLL.JamCount'}} 70 | −{{roll.jamCount}} 71 |
    72 | {{/if}} 73 | {{#if roll.jammed}} 74 |
    75 | {{localize 'YZUR.CHAT.ROLL.Jammed'}} 76 |
    77 | {{/if}} 78 | {{/if}} 79 | 80 | {{/if}} 81 | 82 | {{! Mishap }} 83 | {{!-- {{#if roll.mishap}} --}} 84 | {{!--
    {{localize "YZUR.CHAT.ROLL.Mishap"}}
    --}} 85 | {{!-- {{/if}} --}} 86 | 87 |
    88 | -------------------------------------------------------------------------------- /src/less/grid-layout.less: -------------------------------------------------------------------------------- 1 | /* ------------------------------------------- */ 2 | /* Grid */ 3 | /* ------------------------------------------- */ 4 | 5 | .grid { 6 | display: grid; 7 | align-items: baseline; 8 | } 9 | 10 | .grid-2col { 11 | grid-column: span 2 / span 2; 12 | grid-template-columns: repeat(2, minmax(0, 1fr)); 13 | } 14 | 15 | .grid-3col { 16 | grid-column: span 3 / span 3; 17 | grid-template-columns: repeat(3, minmax(0, 1fr)); 18 | } 19 | 20 | .grid-4col { 21 | grid-column: span 4 / span 4; 22 | grid-template-columns: repeat(4, minmax(0, 1fr)); 23 | } 24 | 25 | .grid-5col { 26 | grid-column: span 5 / span 5; 27 | grid-template-columns: repeat(5, minmax(0, 1fr)); 28 | } 29 | 30 | .grid-6col { 31 | grid-column: span 6 / span 6; 32 | grid-template-columns: repeat(6, minmax(0, 1fr)); 33 | } 34 | 35 | .grid-7col { 36 | grid-column: span 7 / span 7; 37 | grid-template-columns: repeat(7, minmax(0, 1fr)); 38 | } 39 | 40 | .grid-8col { 41 | grid-column: span 8 / span 8; 42 | grid-template-columns: repeat(8, minmax(0, 1fr)); 43 | } 44 | 45 | .grid-9col { 46 | grid-column: span 9 / span 9; 47 | grid-template-columns: repeat(9, minmax(0, 1fr)); 48 | } 49 | 50 | .grid-10col { 51 | grid-column: span 10 / span 10; 52 | grid-template-columns: repeat(10, minmax(0, 1fr)); 53 | } 54 | 55 | .grid-11col { 56 | grid-column: span 11 / span 11; 57 | grid-template-columns: repeat(11, minmax(0, 1fr)); 58 | } 59 | 60 | .grid-12col { 61 | grid-column: span 12 / span 12; 62 | grid-template-columns: repeat(12, minmax(0, 1fr)); 63 | } 64 | 65 | /* ------------------------------------------- */ 66 | /* Specific Grid Layouts */ 67 | /* ------------------------------------------- */ 68 | 69 | .grid-actor-header { 70 | display: grid; 71 | // align-items: stretch; 72 | // justify-items: stretch; 73 | grid-column: span 7 / span 7; 74 | grid-template-columns: repeat(5, minmax(0, 1fr)) auto; 75 | grid-template-rows: auto 1fr 1fr; 76 | grid-template-areas: 77 | "name name name name img" 78 | "nation branch rank age img" 79 | "hit hit stress stress img"; 80 | 81 | .name { grid-area: name; } 82 | .img { grid-area: img; } 83 | .nation { grid-area: nation; } 84 | .branch { grid-area: branch; } 85 | .rank { grid-area: rank; } 86 | .age { grid-area: age; } 87 | .hit { grid-area: hit; } 88 | .stress { grid-area: stress; } 89 | .xp { grid-area: xp; } 90 | } 91 | 92 | .grid-vehicle-header { 93 | display: grid; 94 | align-items: center; 95 | grid-template-areas: 96 | "img info" 97 | "details details"; 98 | 99 | .vehicle-profile { grid-area: img; } 100 | .info { grid-area: info; } 101 | .header-details { grid-area: details; } 102 | } 103 | 104 | .grid-vehicle-details { 105 | display: grid; 106 | grid-template-columns: auto repeat(3, 140px); 107 | grid-template-rows: 1fr 1fr; 108 | grid-template-areas: 109 | "mt cs ts rel" 110 | "fuel cap cons price"; 111 | 112 | .combat-speed { grid-area: cs; } 113 | .travel-speed { grid-area: ts; } 114 | .movement-type { grid-area: mt; } 115 | .fuel-type { grid-area: fuel; } 116 | .fuel-cap { grid-area: cap; } 117 | .fuel-consumption { grid-area: cons;} 118 | .reliability { grid-area: rel; } 119 | .price { grid-area: price; } 120 | } 121 | -------------------------------------------------------------------------------- /src/lang/uk.yml: -------------------------------------------------------------------------------- 1 | T2K4E.Attribute: Атрибут 2 | T2K4E.Attributes: Атрибути 3 | T2K4E.AttributeNames.str: Сила 4 | T2K4E.AttributeNames.agl: Спритність 5 | T2K4E.AttributeNames.int: Інтелект 6 | T2K4E.AttributeNames.emp: Емпатія 7 | T2K4E.SheetClassCharacter: Лист персонажа 8 | T2K4E.SheetClassVehicle: Лист транспортного засобу 9 | T2K4E.SkillNames.recon: Розвідка 10 | T2K4E.SkillNames.survival: Виживання 11 | T2K4E.SkillNames.tech: Механіка 12 | T2K4E.SkillNames.command: Командування 13 | T2K4E.SkillNames.persuasion: Переконання 14 | T2K4E.SkillNames.medicalAid: Медична допомога 15 | T2K4E.Action: Дія 16 | T2K4E.Actions: Дії 17 | T2K4E.ActionNames.meleeAttack: Атака ближнього бою 18 | T2K4E.ActionNames.grapple: Захоплення 19 | T2K4E.ActionNames.breakFree: Вивільнення 20 | T2K4E.ActionNames.throwWeapon: Кинути зброю 21 | T2K4E.ItemTypes.weapon: Зброя 22 | T2K4E.ItemPropNames.twoHanded: Дворучний 23 | T2K4E.ItemPropNames.mounted: Встановлений 24 | T2K4E.ItemPropNames.disposable: Одноразовий 25 | T2K4E.ActorSheet.MainTab: Характеристики 26 | T2K4E.ActorSheet.CombatTab: Бій 27 | T2K4E.ActorSheet.EquipmentTab: Спорядження 28 | T2K4E.ActorSheet.BiographyTab: Біо 29 | T2K4E.ActorSheet.NoteTab: Нотатки 30 | T2K4E.ActorSheet.Branch: Відділення 31 | T2K4E.ActorSheet.MilitaryRank: Звання 32 | T2K4E.ActorSheet.ExperienceCurrent: ОД поточні 33 | T2K4E.ActorSheet.BigDream: Мрія 34 | T2K4E.ActorSheet.Current: Поточне 35 | T2K4E.ActorSheet.Max: Макс. 36 | T2K4E.ActorSheet.InjuryTimeLeft: '{time} залишилось' 37 | T2K4E.ActorSheet.Diseases: Хвороби 38 | T2K4E.ActorSheet.TemporaryRadiation: Тимчасове 39 | T2K4E.ActorSheet.Weapons: Зброя 40 | T2K4E.ActorSheet.AddWeapon: Додати зброю 41 | T2K4E.ActorSheet.Unarmed: Беззбройний 42 | T2K4E.ActorSheet.Delete: Видалити 43 | T2K4E.ActorSheet.NewItem.weapon: Нова зброя 44 | T2K4E.ActorSheet.NewItem.armor: Нова броня 45 | T2K4E.SkillNames.driving: Водіння 46 | T2K4E.ActorSheet.Nationality: Національність 47 | T2K4E.SkillNames.rangedCombat: Дальній бій 48 | T2K4E.ActorSheet.Name: Ім'я 49 | T2K4E.ActionNames.unarmedAttack: Беззбройна атака 50 | T2K4E.ActorSheet.Experience: Досвід 51 | T2K4E.ItemPropNames.ammoBelt: Пояс для боєприпасів 52 | T2K4E.ActorSheet.ExperienceTotal: ОД загальні 53 | T2K4E.ActionNames.run: Бігти 54 | T2K4E.ActorSheet.Appearance: Зовнішній вигляд 55 | T2K4E.ActorSheet.Actions: Дії 56 | T2K4E.ActorSheet.CriticalInjuries: Критичні травми 57 | T2K4E.ActorSheet.AddInjury: Додати нову травму 58 | T2K4E.ActorSheet.Radiation: Опромінення 59 | T2K4E.ActorSheet.PermanentRadiation: Постійне 60 | T2K4E.ActorSheet.Edit: Редагувати 61 | T2K4E.ActorSheet.Equip: Спорядити 62 | T2K4E.ActorSheet.Store: Зберігати в рюкзаку 63 | T2K4E.SkillNames.stamina: Витривалість 64 | T2K4E.Skill: Навичка 65 | T2K4E.Skills: Навички 66 | T2K4E.SkillNames.heavyWeapons: Важка зброя 67 | T2K4E.SkillNames.closeCombat: Ближній бій 68 | T2K4E.SkillNames.mobility: Мобільність 69 | T2K4E.ActionNames.crawl: Повзти 70 | T2K4E.ActionNames.seekCover: Знайти укриття 71 | T2K4E.ActionNames.shove: Штовхати 72 | T2K4E.ActionNames.disarm: Роззброїти 73 | T2K4E.ActionNames.retreat: Відступити 74 | T2K4E.ActionNames.prepareBow: Приготувати лук 75 | T2K4E.ActionNames.firstAid: Перша допомога 76 | T2K4E.ActionNames.aim: Прицілитись 77 | T2K4E.TravelTaskNames.hunting: Полювання 78 | T2K4E.ArmorLocationNames.head: Голова 79 | T2K4E.ArmorLocationNames.arms: Руки 80 | T2K4E.ArmorLocationNames.torso: Торс 81 | T2K4E.ArmorLocationNames.legs: Ноги 82 | T2K4E.ActorSheet.CapacityModifier: 'Модифікатор:' 83 | T2K4E.ActorSheet.Add: Додати 84 | -------------------------------------------------------------------------------- /src/actor/templates/parts/actor-stats.hbs: -------------------------------------------------------------------------------- 1 | {{!-- Attributes & Skills --}} 2 |
    3 |

    {{localize "T2K4E.ActorSheet.AttributesAndSkills"}}

    4 | 5 |
    6 | {{#each system.attributes as | attribute attr |}} 7 |
    8 |
    9 |
    10 |
    11 |
    {{localize "T2K4E.ActorSheet.Rating"}}
    12 |
    13 |
    14 |
    {{localize "T2K4E.ActorSheet.BaseDie"}}
    15 |
    16 |
    17 |
    18 | 21 |
    22 | {{selectBuilder (concat "system.attributes." attr ".score") @root.config.dieScores attribute.score }} 23 |
    24 |
    25 | {{#if (lte attribute.value 0)}}– 26 | {{else}} 27 |
    D{{attribute.value}}
    28 | {{/if}} 29 |
    30 |
    31 | {{!-- All skills for an attribute --}} 32 | {{#each @root.system.skills as | skill sk |}} 33 | {{#if (eq attr (lookup @root.config.skillsMap sk))}} 34 |
    35 | 38 |
    39 | {{selectBuilder (concat "system.skills." sk ".score") @root.config.dieScores skill.score}} 40 |
    41 |
    42 | {{#if (lte skill.value 0)}}– 43 | {{else}} 44 |
    D{{skill.value}}
    45 | {{/if}} 46 |
    47 |
    48 | {{/if}} 49 | {{/each}} 50 |
    51 | {{/each}} 52 |
    53 |
    54 | 55 | {{!-- Specialties --}} 56 |
    57 |

    {{localize "T2K4E.ActorSheet.Specialties"}}

    58 | 59 | 60 | 61 |
    62 | 63 |
    64 | {{#each actor.itemTypes.specialty as | specialty |}} 65 |
    66 | {{#with specialty}} 67 |
    68 | {{#if system.description}} 69 | {{name}}:  70 | {{{system.description}}} 71 | {{else}} 72 | {{#if hasModifier}} 73 | {{name}}:  74 | {{modifiersDescription}} 75 | {{else}} 76 | {{name}} 77 | {{/if}} 78 | {{/if}} 79 |
    80 | {{> "systems/t2k4e/templates/actor/parts/slots/slot-buttons.hbs"}} 81 | {{/with}} 82 |
    83 | {{else}} 84 |

    {{localize "T2K4E.ActorSheet.NoSpecialty"}}

    85 | {{/each}} 86 |
    87 | -------------------------------------------------------------------------------- /src/less/party.less: -------------------------------------------------------------------------------- 1 | .t2k4e.party { 2 | min-height: 540px; 3 | height: 100%; 4 | max-height: calc(100vh - 10%); 5 | .border { 6 | border: @borderSheetBold; 7 | border-radius: @gap; 8 | } 9 | } 10 | 11 | .t2k4e.party .party { 12 | height: 100%; 13 | min-height: 540px; 14 | width: 100%; 15 | } 16 | 17 | .party .avatar img { 18 | border: 2px solid @colorBrown; 19 | border-radius: 4px; 20 | margin: @gap 0 4px @gap; 21 | // width: 100px; 22 | // height: 100px; 23 | background-color: #fff; 24 | 25 | &:focus, 26 | &:hover { 27 | box-shadow: @hoverShadow; 28 | } 29 | } 30 | 31 | .party .tab-hint { 32 | font-style: italic; 33 | text-align: center; 34 | } 35 | 36 | .party-member:hover { 37 | background-color: @colorBeige; 38 | } 39 | 40 | .party-member .party-member-avatar { 41 | flex: 0 0 48px; 42 | width: 48px; 43 | height: 48px; 44 | border: 0px; 45 | cursor: pointer; 46 | } 47 | 48 | .party-member .party-member-name { 49 | line-height: 48px; 50 | } 51 | 52 | .party-member .button { 53 | flex: 0 0 24px; 54 | width: 24px; 55 | height: 48px; 56 | line-height: 48px; 57 | } 58 | 59 | .party-member .entity-link { 60 | padding: 0 6px; 61 | line-height: 44px; 62 | white-space: nowrap; 63 | overflow-x: hidden; 64 | text-overflow: ellipsis; 65 | 66 | border: 0px; 67 | background-color: inherit; 68 | } 69 | 70 | .party-member .plain-name { 71 | margin-right: 6px; 72 | line-height: 44px; 73 | 74 | white-space: nowrap; 75 | overflow-x: hidden; 76 | text-overflow: ellipsis; 77 | 78 | border: 0px; 79 | background-color: inherit; 80 | } 81 | 82 | .party-member-list { 83 | height: 100%; 84 | // min-height: 360px; 85 | 86 | .members-list { 87 | min-height: 100px; 88 | height: 100%; 89 | overflow-y: auto; 90 | } 91 | } 92 | 93 | table.travel-actions { 94 | border: 0px solid; 95 | // border-spacing: 6px; 96 | border-collapse: separate; 97 | background-color: transparent; 98 | margin-top: 0px; 99 | } 100 | 101 | table.travel-actions td { 102 | vertical-align: top; 103 | min-height: 1px; 104 | } 105 | 106 | .travel-action { 107 | min-width: 196px; 108 | min-height: 116px; 109 | height: 100%; 110 | // margin-bottom: 10px; 111 | flex-grow: 1; 112 | } 113 | 114 | .travel-action ol { 115 | padding-left: 4px; 116 | } 117 | 118 | .travel-action .travel-action-header { 119 | text-align: center; 120 | font-weight: bold; 121 | max-height: 20px; 122 | border-bottom: 1px solid @colorBrown; 123 | 124 | display: flex; 125 | flex-direction: row; 126 | justify-content: center; 127 | } 128 | 129 | .travel-action-header .entity-link { 130 | background-color: white; 131 | border: 0px solid; 132 | } 133 | 134 | .travel-action .travel-action-help { 135 | border: 1px solid; 136 | border-radius: 6px; 137 | background-color: cadetblue; 138 | display: flex; 139 | width: 20px; 140 | margin-left: 4px; 141 | justify-content: center; 142 | } 143 | .travel-action .travel-action-help:hover { 144 | background-color: cyan; 145 | } 146 | 147 | .travel-action button.travel-roll { 148 | font-size: var(--font-size--very-small); 149 | display: block; 150 | line-height: normal; 151 | height: 24px; 152 | width: 99%; 153 | border: none; 154 | border-bottom: 1px dashed @colorBrown; 155 | background-color: transparent; 156 | 157 | &:focus, 158 | &:hover { 159 | background-color: rgba(0, 0, 0, 0.1); 160 | } 161 | } -------------------------------------------------------------------------------- /src/components/dialog/templates/roll-dialog.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{! ================================================== }} 4 | 5 | {{#if (or data.attribute data.skill)}} 6 | {{! Roll Formula }} 7 |
    8 | 9 | 10 |
    11 | 12 | {{else}} 13 | {{! Attribute }} 14 |
    15 | 16 |
    17 |
    18 | 19 | {{! Skill }} 20 |
    21 | 22 |
    23 |
    24 | {{/if}} 25 | 26 | {{! ================================================== }} 27 | 28 | {{! Rate of Fire }} 29 | {{#if data.rof}} 30 |
    31 | 32 |
    33 |
    34 | {{/if}} 35 | 36 | {{! ================================================== }} 37 | 38 |
    39 | 40 | {{! Modifier }} 41 |
    42 | 43 | 60 |
    61 | 62 | {{! Modifiers }} 63 |
    64 | {{#each data.modifiers}} 65 | 69 | {{/each}} 70 |
    71 | 72 | {{! ================================================== }} 73 | 74 |
    75 | 76 | {{! Max Pushes }} 77 |
    78 | 79 | 80 |
    81 | 82 | {{! ================================================== }} 83 | 84 | {{! Location Die }} 85 |
    86 | 87 | 88 |
    89 | 90 | {{! ================================================== }} 91 | 92 |
    93 | 94 | {{! Roll Mode }} 95 |
    96 | 97 | 100 |
    101 | 102 |
    -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release CI 2 | 3 | on: 4 | release: 5 | types: 6 | - published 7 | 8 | env: 9 | # 'system' or 'module' 10 | TYPE: system 11 | 12 | jobs: 13 | release: 14 | name: Create & Publish Release 15 | # if: startsWith(github.ref, 'refs/tags/') 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: 📡 Checkout 20 | uses: actions/checkout@v3 21 | 22 | # Configures NodeJS. 23 | - name: ⚙️ Setup NodeJS 16 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: 16 27 | 28 | # Installs & builds. 29 | - name: 🔧 Install Dependencies 30 | run: npm ci 31 | - name: 🧱 Build Project 32 | run: npm run build 33 | 34 | # Gets the system/module name. 35 | - name: 📄 Get Name 36 | id: name 37 | uses: notiz-dev/github-action-json-property@release 38 | with: 39 | path: dist/${{ env.TYPE }}.json 40 | prop_path: id 41 | 42 | # Gets the version tag. 43 | - name: 📄 Get Version 44 | id: version 45 | uses: notiz-dev/github-action-json-property@release 46 | with: 47 | path: dist/${{ env.TYPE }}.json 48 | prop_path: version 49 | # - name: 🏷️ Get Version Tag 50 | # id: version 51 | # uses: ncipollo/semantic-version-action@v1.0.1 52 | # with: 53 | # tag: ${{ github.event.release.tag_name }} 54 | 55 | # Substitute the Manifest and Download URLs in the module.json 56 | - name: 📝 Substitute Manifest and Download Links For Versioned Ones 57 | id: manifest_link_version 58 | uses: microsoft/variable-substitution@v1 59 | with: 60 | files: dist/${{ env.TYPE }}.json 61 | env: 62 | # version: ${{ steps.version.outputs.prop }} 63 | manifest: https://github.com/${{ github.repository }}/releases/latest/download/${{ env.TYPE }}.json 64 | download: https://github.com/${{ github.repository }}/releases/download/${{ github.event.release.tag_name }}/${{ steps.name.outputs.prop }}-fvtt_v${{ steps.version.outputs.prop }}.zip 65 | 66 | # Generates the changelog. 67 | # - name: 📜 Generate Changelog 68 | # id: changelog 69 | # uses: mikepenz/release-changelog-builder-action@v3.3.1 70 | # env: 71 | # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 72 | 73 | # Creates the ZIP artifact. 74 | - name: 📦 Create ZIP Archive 75 | run: | 76 | cd dist/ 77 | zip -r ../${{ steps.name.outputs.prop }}-fvtt_v${{ steps.version.outputs.prop }}.zip * 78 | 79 | # Creates the release with its artifacts and description. 80 | - name: 🚀 Update Release with Artifacts 81 | uses: ncipollo/release-action@v1.10.0 82 | with: 83 | allowUpdates: true 84 | name: ${{ github.event.release.name }} 85 | draft: false 86 | prerelease: false 87 | tag: ${{ steps.version.outputs.tag }} 88 | body: ${{ github.event.release.body }} 89 | artifacts: './${{ steps.name.outputs.prop }}-fvtt_v${{ steps.version.outputs.prop }}.zip, ./dist/${{ env.TYPE }}.json' 90 | token: ${{ secrets.GITHUB_TOKEN }} 91 | 92 | # Publishes the release to the FoundryVTT's package repository. 93 | - name: 🚩 Publish Module to FoundryVTT Website 94 | uses: Varriount/fvtt-autopublish@v2.0.2 95 | with: 96 | username: ${{ secrets.FOUNDRY_ADMIN_USERNAME }} 97 | password: ${{ secrets.FOUNDRY_ADMIN_PASSWORD }} 98 | module-id: ${{ secrets.FOUNDRY_ADMIN_MODULE_NAME }} 99 | manifest-url: https://github.com/${{ github.repository }}/releases/download/${{ github.event.release.tag_name }}/${{ env.TYPE }}.json 100 | manifest-file: dist/${{ env.TYPE }}.json 101 | -------------------------------------------------------------------------------- /src/components/modifier.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-shadow */ 2 | /** 3 | * A class representing a roll modifier with many properties and automatic label. 4 | * @class 5 | */ 6 | export default class Modifier { 7 | /** 8 | * @param {string} key The key that will be parsed to identify the modifier. 9 | * @param {number|string} value The modification value of the modifier. (If a string, will be parsed) 10 | * @param {Item} [item] The item that is the source of the modifier. 11 | * @param {boolean} [active] Whether the modifier is active. 12 | * @param {string} [name] Alternative name for the modifier, if you don't want to use the item's name. 13 | * @param {string} [type] Alternative type for the modifier, if you don't want to use the item's type. 14 | * @param {string} [description] Alternative description for the modifier. 15 | */ 16 | constructor(key, value, item = {}, { active, name, type, description } = {}) { 17 | /** 18 | * The item that holds the modifier. 19 | * @type {Item} 20 | */ 21 | this.item = item; 22 | 23 | this._name = name ?? item.name; 24 | this._type = type ?? item.type; 25 | this._description = description ?? item.sytem?.description; 26 | 27 | /** 28 | * The key that will be parsed to identify the modifier. 29 | * @type {string} 30 | * @private 31 | */ 32 | this._key = key; 33 | 34 | /** 35 | * The modification value of the modifier. 36 | * @type {number} 37 | */ 38 | this.value = +value || 0; 39 | 40 | const keys = key.split('.'); 41 | if (keys.length !== 2) { 42 | throw new SyntaxError(`Modifier "${this.name}" | key#length not equal to 2: "${key}" | You must choose a name.`); 43 | } 44 | 45 | /** 46 | * The category of the target. Either "attribute", "skill", "action", "constant", or "travel". 47 | * @type {string} 48 | */ 49 | this.category = keys[0]; 50 | if (!this.constructor.ALLOWED_CATEGORIES.includes(this.category)) { 51 | throw new TypeError(`Modifier "${this.name}" | Illegal target category: "${this.category}"`); 52 | } 53 | 54 | /** 55 | * The target that is modified by the modifier. 56 | * @type {string} 57 | */ 58 | this.target = keys[1]; 59 | 60 | /** 61 | * Whether the modifier is active. 62 | * @type {boolean} 63 | */ 64 | this.active = active ?? this.value <= 0; 65 | } 66 | 67 | /* ------------------------------------------- */ 68 | /* Getters */ 69 | /* ------------------------------------------- */ 70 | 71 | /** 72 | * The item's name that is the source of the modifier. 73 | * @type {string} 74 | * @readonly 75 | */ 76 | get name() { 77 | return this._name ?? this.item?.name; 78 | } 79 | 80 | /** 81 | * The Item's type that was the source of the modifier. 82 | * Useful for sorting. 83 | * @type {string} 84 | * @readonly 85 | */ 86 | get type() { 87 | return this._type ?? this.item?.type; 88 | } 89 | 90 | /** 91 | * The value, with a sign. 92 | * @type {string|null} 93 | * @readonly 94 | */ 95 | get signedValue() { 96 | if (this.value !== 0 && !this.value) return null; 97 | return (this.value >= 0 ? '+' : '−') + Math.abs(this.value); 98 | } 99 | 100 | /** 101 | * The localized label of the modifier. 102 | * @type {string} 103 | * @readonly 104 | */ 105 | get label() { 106 | return this.name + (this.value ? ` ${this.signedValue}` : ''); 107 | } 108 | 109 | /** 110 | * The description of the item that is the source of the modifier. 111 | * @type {string} 112 | * @readonly 113 | */ 114 | get description() { 115 | const str = this._description ?? this.item.system?.description ?? ''; 116 | return str.replace(/<[^>]*>?/gm, ''); 117 | } 118 | } 119 | 120 | /* ------------------------------------------- */ 121 | 122 | Modifier.ALLOWED_CATEGORIES = ['attribute', 'skill', 'action', 'constant', 'travel']; 123 | -------------------------------------------------------------------------------- /static/fonts/Mukta.OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Girish Dalvi, Ek Type. All rights reserved. 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /static/fonts/Nunito.OFL.txt: -------------------------------------------------------------------------------- 1 | Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com), 2 | 3 | This Font Software is licensed under the SIL Open Font License, Version 1.1. 4 | This license is copied below, and is also available with a FAQ at: 5 | http://scripts.sil.org/OFL 6 | 7 | 8 | ----------------------------------------------------------- 9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 10 | ----------------------------------------------------------- 11 | 12 | PREAMBLE 13 | The goals of the Open Font License (OFL) are to stimulate worldwide 14 | development of collaborative font projects, to support the font creation 15 | efforts of academic and linguistic communities, and to provide a free and 16 | open framework in which fonts may be shared and improved in partnership 17 | with others. 18 | 19 | The OFL allows the licensed fonts to be used, studied, modified and 20 | redistributed freely as long as they are not sold by themselves. The 21 | fonts, including any derivative works, can be bundled, embedded, 22 | redistributed and/or sold with any software provided that any reserved 23 | names are not used by derivative works. The fonts and derivatives, 24 | however, cannot be released under any other type of license. The 25 | requirement for fonts to remain under this license does not apply 26 | to any document created using the fonts or their derivatives. 27 | 28 | DEFINITIONS 29 | "Font Software" refers to the set of files released by the Copyright 30 | Holder(s) under this license and clearly marked as such. This may 31 | include source files, build scripts and documentation. 32 | 33 | "Reserved Font Name" refers to any names specified as such after the 34 | copyright statement(s). 35 | 36 | "Original Version" refers to the collection of Font Software components as 37 | distributed by the Copyright Holder(s). 38 | 39 | "Modified Version" refers to any derivative made by adding to, deleting, 40 | or substituting -- in part or in whole -- any of the components of the 41 | Original Version, by changing formats or by porting the Font Software to a 42 | new environment. 43 | 44 | "Author" refers to any designer, engineer, programmer, technical 45 | writer or other person who contributed to the Font Software. 46 | 47 | PERMISSION & CONDITIONS 48 | Permission is hereby granted, free of charge, to any person obtaining 49 | a copy of the Font Software, to use, study, copy, merge, embed, modify, 50 | redistribute, and sell modified and unmodified copies of the Font 51 | Software, subject to the following conditions: 52 | 53 | 1) Neither the Font Software nor any of its individual components, 54 | in Original or Modified Versions, may be sold by itself. 55 | 56 | 2) Original or Modified Versions of the Font Software may be bundled, 57 | redistributed and/or sold with any software, provided that each copy 58 | contains the above copyright notice and this license. These can be 59 | included either as stand-alone text files, human-readable headers or 60 | in the appropriate machine-readable metadata fields within text or 61 | binary files as long as those fields can be easily viewed by the user. 62 | 63 | 3) No Modified Version of the Font Software may use the Reserved Font 64 | Name(s) unless explicit written permission is granted by the corresponding 65 | Copyright Holder. This restriction only applies to the primary font name as 66 | presented to the users. 67 | 68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font 69 | Software shall not be used to promote, endorse or advertise any 70 | Modified Version, except to acknowledge the contribution(s) of the 71 | Copyright Holder(s) and the Author(s) or with their explicit written 72 | permission. 73 | 74 | 5) The Font Software, modified or unmodified, in part or in whole, 75 | must be distributed entirely under this license, and must not be 76 | distributed under any other license. The requirement for fonts to 77 | remain under this license does not apply to any document created 78 | using the Font Software. 79 | 80 | TERMINATION 81 | This license becomes null and void if any of the above conditions are 82 | not met. 83 | 84 | DISCLAIMER 85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF 87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT 88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE 89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM 93 | OTHER DEALINGS IN THE FONT SOFTWARE. 94 | -------------------------------------------------------------------------------- /src/item/templates/gear-sheet.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{!-- Item Sheet Header --}} 4 | {{> "systems/t2k4e/templates/item/parts/item-header.hbs"}} 5 | 6 | {{!-- Sheet Tab Navigation --}} 7 | 12 | 13 | {{!-- Sheet Body --}} 14 |
    15 | 16 | {{!-- Features Tab --}} 17 |
    18 |
    19 |
    20 | 21 | 22 |
    23 |
    24 | 25 |
    26 | 27 | / 28 | 29 |
    30 |
    31 |
    32 | 33 | 34 |
    35 |
    36 | 37 | 38 |
    39 |
    40 | 41 | {{!-- Other Parameters --}} 42 |
    43 | 44 | {{!-- Used Skill --}} 45 | {{!--
    46 | 47 | 54 |
    --}} 55 | 56 | {{!-- Properties --}} 57 |
    58 | {{#each system.props as | prop name |}} 59 | 63 | {{/each}} 64 |
    65 | 66 |
    67 | 68 | {{!-- Inventory Options --}} 69 | {{#if inActor}} 70 |
    71 |
    72 | 76 |
    77 |
    78 | 82 |
    83 |
    84 | {{/if}} 85 | 86 |
    87 | 88 | {{!-- Modifiers Tab --}} 89 |
    90 | {{> "systems/t2k4e/templates/item/parts/item-modifiers.hbs"}} 91 |
    92 | 93 | {{!-- Description Tab --}} 94 |
    95 | {{> "systems/t2k4e/templates/item/parts/item-description.hbs"}} 96 |
    97 | 98 |
    99 | 100 |
    101 | -------------------------------------------------------------------------------- /src/less/journal.less: -------------------------------------------------------------------------------- 1 | .font-title() { 2 | font-family: 'GT Eesti Text Medium', 'Nunito Sans'; 3 | } 4 | .font-body() { 5 | font-family: 'TheSansB', 'Mukta'; 6 | } 7 | 8 | .app.window-app.sheet .window-content .editor .editor-content, 9 | .app.window-app.sheet .window-content .journal-entry-content { 10 | h1, h2, h3, h4 { 11 | .font-title(); 12 | text-transform: uppercase; 13 | text-indent: 0px; 14 | text-align: left; 15 | border-bottom: unset; 16 | background: none; 17 | // padding: 0; 18 | } 19 | h1 { 20 | color: @colorCoresetLightGreen; 21 | } 22 | h2 { 23 | color: @colorCoresetTeal; 24 | } 25 | h3 { 26 | font-weight: bold; 27 | color: @colorCoresetGreen; 28 | } 29 | h4 { 30 | font-family: 'Blue Highway'; 31 | font-weight: bold; 32 | color: @colorCoresetBrown; 33 | } 34 | 35 | img { 36 | border: none; 37 | } 38 | 39 | code { 40 | font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; 41 | background-color: rgba(27, 31, 35, 0.05); 42 | border-radius: 6px; 43 | font-size: 85%; 44 | margin: 0; 45 | padding: .2em .4em; 46 | } 47 | } 48 | 49 | .app.journal-sheet { 50 | // color: #000; 51 | // border: 9px solid red; 52 | // border-image-source: url('assets/textures/papper_outline.webp'); 53 | // border-image-slice: 38; 54 | // border-image-width: 3; 55 | // border-image-repeat: repeat; 56 | // border-image-outset: 1; 57 | // background-color: #fff; 58 | 59 | min-height: 260px; 60 | min-width: 560px; 61 | 62 | .window-header { 63 | // border: none; 64 | } 65 | 66 | .window-content { 67 | // background-image: url('assets/textures/background_texture.webp'); 68 | color: #000; 69 | 70 | // display: flex; 71 | // flex-direction: column; 72 | 73 | form input[name="name"] { 74 | .font-title(); 75 | color: @colorCoresetLightGreen; 76 | font-size: 3rem; 77 | text-transform: uppercase; 78 | text-align: center; 79 | line-height: 2; 80 | border: none; 81 | // padding: max(10px, 1%) min(14%, 130px) 0; 82 | text-overflow: ellipsis; 83 | width: min(100%, 900px); 84 | min-height: 70px; 85 | height: min(45%, 100px); 86 | margin: auto; 87 | background: none; 88 | } 89 | 90 | .editor { 91 | min-height: 200px; 92 | height: 100%; 93 | } 94 | 95 | .editor .editor-content, 96 | .journal-page-content { 97 | width: 100%; 98 | .font-body(); 99 | font-size: var(--font-size--default); 100 | line-height: 1.3; 101 | // text-shadow: 0 0 1px rgb(0 0 0 / 30%); 102 | color: #333; 103 | padding: 0 3em; 104 | display: flex; 105 | flex-direction: column; 106 | flex-wrap: initial; 107 | 108 | * { 109 | max-width: 90ch; 110 | } 111 | 112 | p { 113 | width: 100%; 114 | } 115 | 116 | p+p { 117 | text-indent: 25px; 118 | margin-top: -0.5em; 119 | } 120 | 121 | h1, h2, h3, h4 { 122 | margin: 1rem 0 -0.5rem 0; 123 | } 124 | 125 | table.t2k-table { 126 | color: @colorCoresetBrown; 127 | line-height: 1; 128 | // vertical-align: top; 129 | padding: 25px 0; 130 | max-width: 100%; 131 | border: none; 132 | border-collapse: collapse; 133 | // margin: auto; 134 | // margin-bottom: 15px; 135 | background: none; 136 | word-break: keep-all; 137 | 138 | tbody { 139 | vertical-align: top; 140 | } 141 | 142 | th, 143 | .t2k-th { 144 | font-size: .8rem; 145 | font-weight: bold; 146 | text-transform: uppercase; 147 | text-align: left; 148 | padding-top: 7px; 149 | padding-bottom: 5px; 150 | } 151 | 152 | th { 153 | background-color: @colorCoresetTableHeader; 154 | } 155 | 156 | tr:not(:last-child) { 157 | border-bottom: 1px solid @colorCoresetBrown; 158 | } 159 | 160 | // tr:not(:nth-child(1)) { 161 | // border-top: 1px solid @colorCoresetBrown; 162 | // } 163 | 164 | tr:nth-child(even) { 165 | background: none; 166 | } 167 | 168 | tr:nth-child(odd) { 169 | background-color: @colorCoresetTableLine; 170 | } 171 | 172 | td, th { 173 | padding-right: 10px; 174 | } 175 | 176 | th:nth-child(1), 177 | td:nth-child(1) { 178 | padding-left: 10px; 179 | } 180 | 181 | ul { 182 | list-style: '✓ '; 183 | margin: 0; 184 | padding: 0 0 0 1em; 185 | &>li::before { 186 | content: ''; 187 | margin: 0; 188 | } 189 | } 190 | } 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/actor/unit/unit-sheet.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{!-- ================================================== --}} 4 | {{!-- Actor Sheet Header --}} 5 | {{!-- ================================================== --}} 6 | 7 |
    8 | 9 | 10 |
    11 |
    12 | {{#if system.hq}} 13 |

    {{localize "T2K4E.UnitSheet.HQ"}}

    14 | {{else}} 15 |

    {{localize "TYPES.Actor.unit"}}

    16 | {{/if}} 17 |
    18 |

    19 | 20 | 21 |

    22 |
    23 |
    24 | 25 | {{!-- ================================================== --}} 26 | {{!-- Sheet Tab Navigation --}} 27 | {{!-- ================================================== --}} 28 | 29 | 33 | 34 | {{!-- ================================================== --}} 35 | {{!-- Sheet Body --}} 36 | {{!-- ================================================== --}} 37 | 38 |
    39 | 40 |
    41 | 42 |
    43 | 44 | {{!-- Faction --}} 45 |
    46 | 47 | 48 |
    49 | {{!-- Affiliation --}} 50 |
    51 | 52 | 56 |
    57 | {{!-- Type --}} 58 |
    59 | 60 | 61 |
    62 | {{!-- Size --}} 63 |
    64 | 65 | 69 |
    70 | {{!-- Counts --}} 71 |
    72 | 73 |
    74 | 75 | / 76 | 77 |
    78 |
    79 |
    80 | 81 |
    82 | 83 | / 84 | 85 |
    86 |
    87 | 88 |
    89 | 90 | {{!-- Modifiers --}} 91 |
    92 | {{#each system.unitModifiers as | mod name |}} 93 | 97 | {{/each}} 98 |
    99 | 100 | {{!-- HQ --}} 101 |
    102 | 106 |
    107 | 108 |
    109 | 110 | {{!-- Description Tab --}} 111 |
    112 | {{> "systems/t2k4e/templates/actor/parts/actor-description.hbs"}} 113 |
    114 | 115 |
    116 | 117 |
    118 | -------------------------------------------------------------------------------- /src/item/templates/armor-sheet.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{!-- Item Sheet Header --}} 4 | {{> "systems/t2k4e/templates/item/parts/item-header.hbs"}} 5 | 6 | {{!-- Sheet Tab Navigation --}} 7 | 12 | 13 | {{!-- Sheet Body --}} 14 |
    15 | 16 | {{!-- Features Tab --}} 17 |
    18 |
    19 |
    20 | 21 |
    22 | 23 | / 24 | 25 |
    26 |
    27 |
    28 | 29 | 30 |
    31 |
    32 | 33 | 34 |
    35 |
    36 | 37 | {{!-- Other Parameters --}} 38 |
    39 | 40 | {{!-- Used Skill --}} 41 | {{!--
    42 | 43 | 50 |
    --}} 51 | 52 | {{!-- Properties --}} 53 | 54 |
    55 | 59 | 63 | 67 | 71 |
    72 | 73 |
    74 | 75 | {{!-- Inventory Options --}} 76 | {{#if inActor}} 77 |
    78 |
    79 | 83 |
    84 |
    85 | 89 |
    90 |
    91 | {{/if}} 92 | 93 |
    94 | 95 | {{!-- Modifiers Tab --}} 96 |
    97 | {{> "systems/t2k4e/templates/item/parts/item-modifiers.hbs"}} 98 |
    99 | 100 | {{!-- Description Tab --}} 101 |
    102 | {{> "systems/t2k4e/templates/item/parts/item-description.hbs"}} 103 |
    104 | 105 |
    106 | 107 |
    108 | -------------------------------------------------------------------------------- /src/less/chat.less: -------------------------------------------------------------------------------- 1 | @import "./variables.less"; 2 | 3 | .chat-message { 4 | @dieSize: 32px; 5 | .actor-sheet-background(); 6 | .font-text-normal(); 7 | 8 | &.whisper { 9 | background-image: url('assets/textures/background_texture.webp'); 10 | } 11 | 12 | .message-content { 13 | p { 14 | line-height: 1.15; 15 | } 16 | // Custom Dice. 17 | // .basedied12, 18 | // .basedied10, 19 | // .basedied8, 20 | // .basedied6, 21 | .ammodie { 22 | // width: @dieSize; 23 | background-position: center; 24 | img { 25 | width: 16px; 26 | height: 16px; 27 | border: none; 28 | } 29 | } 30 | } 31 | 32 | .t2k4e.chat-card .card-content { 33 | img { 34 | border: none; 35 | } 36 | 37 | &>div { 38 | margin-bottom: @gap; 39 | } 40 | 41 | // .card-formula { 42 | // text-align: center; 43 | // padding: 2px; 44 | // color: @colorTan; 45 | // border: 1px solid #999; 46 | // border-radius: 3px; 47 | // background-color: rgba(0, 0, 0, 0.1); 48 | // word-break: break-all; 49 | // } 50 | 51 | .dice-flavor { 52 | font-family: 'DaisyWheel'; 53 | font-size: .9rem; 54 | text-transform: uppercase; 55 | text-align: center; 56 | color: @colorGreen; 57 | margin-bottom: 2px; 58 | } 59 | 60 | .dice-tooltip { 61 | // &> div + div { 62 | // margin-top: 2px; 63 | // } 64 | 65 | // .base-dice, 66 | // .ammo-dice { 67 | // display: flex; 68 | // flex-direction: row; 69 | // } 70 | display: flex; 71 | flex-direction: row; 72 | flex-wrap: wrap; 73 | margin-bottom: 3px; 74 | 75 | // .part-formula { 76 | // display: none; 77 | // } 78 | 79 | .tooltip-part { 80 | width: auto; 81 | min-width: 30%; 82 | margin: 0 2px 2px 0; 83 | border: 1px solid #999; 84 | border-radius: 3px; 85 | 86 | .part-header { 87 | justify-content: flex-end; 88 | background-color: @colorLightKhaki; 89 | 90 | .part-formula { 91 | margin-left: 4px; 92 | } 93 | 94 | .part-total { 95 | border-top: none; 96 | border-right: none; 97 | } 98 | } 99 | 100 | .dice-rolls { 101 | margin: 5px 2px; 102 | } 103 | 104 | // &.base .part-header { 105 | // color: #cfa826; 106 | // background-color: #262c23; 107 | // } 108 | 109 | // &.loc .part-header { 110 | // color: #000; 111 | // background-color: #fff; 112 | // } 113 | 114 | // &.ammo .part-header { 115 | // color: #000; 116 | // background-color: #726435; 117 | // } 118 | } 119 | 120 | .die { 121 | width: @dieSize; 122 | line-height: @dieSize; 123 | margin-right: 2px; 124 | background-image: url(../../../icons/svg/d6-grey.svg); 125 | background-repeat: no-repeat; 126 | background-size: @dieSize @dieSize; 127 | font-size: (@dieSize / 1.5); 128 | font-weight: bold; 129 | text-align: center; 130 | 131 | &.d100 { 132 | background-image: url(../../../icons/svg/d10-grey.svg); 133 | } 134 | 135 | &.d20 { 136 | background-image: url(../../../icons/svg/d20-grey.svg); 137 | } 138 | 139 | &.d12 { 140 | background-image: url(../../../icons/svg/d12-grey.svg); 141 | } 142 | 143 | &.d10 { 144 | background-image: url(../../../icons/svg/d10-grey.svg); 145 | } 146 | 147 | &.d8 { 148 | background-image: url(../../../icons/svg/d8-grey.svg); 149 | } 150 | 151 | &.d6 { 152 | background-image: url(../../../icons/svg/d6-grey.svg); 153 | } 154 | 155 | &.d4 { 156 | background-image: url(../../../icons/svg/d4-grey.svg); 157 | } 158 | 159 | // &.stunt { 160 | // color: @colorGreen; 161 | // filter: sepia(0.5) hue-rotate(60deg); 162 | // } 163 | 164 | // &.bane { 165 | // color: @colorRed; 166 | // filter: sepia(0.5) hue-rotate(-60deg); 167 | // } 168 | } 169 | } 170 | 171 | .dice-infos { 172 | .dice-info { 173 | display: flex; 174 | flex-direction: row; 175 | 176 | .label { 177 | flex: 0 0 150px; 178 | } 179 | .result { 180 | flex: 0 0 auto; 181 | font-weight: bold; 182 | } 183 | 184 | &.roll-jammed { 185 | .label { 186 | font-weight: bold; 187 | color: @colorRed; 188 | } 189 | } 190 | } 191 | } 192 | 193 | // .card-description { 194 | // .success.successful { 195 | // color: green; 196 | // } 197 | 198 | // .mishap { 199 | // color: @colorRed; 200 | // } 201 | // } 202 | 203 | // .card-description { 204 | // h4 { 205 | // border-top: 1px solid @colorBrown; 206 | // } 207 | // } 208 | 209 | .card-buttons, 210 | .dice-buttons { 211 | display: flex; 212 | flex-direction: row; 213 | flex-grow: 1; 214 | justify-content: space-around; 215 | align-items: stretch; 216 | gap: 3px; 217 | button { 218 | line-height: 1rem; 219 | flex-grow: 2; 220 | } 221 | } 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/less/items.less: -------------------------------------------------------------------------------- 1 | .t2k4e.sheet.item { 2 | min-width: 400px; 3 | min-height: 400px; 4 | 5 | .window-content { 6 | .item-sheet-background(); 7 | } 8 | 9 | /* ------------------------------------------- */ 10 | /* Sheet Header */ 11 | /* ------------------------------------------- */ 12 | 13 | .sheet-header { 14 | img.profile { 15 | border: 2px solid @colorBrown; 16 | border-radius: 4px; 17 | } 18 | 19 | h1 > input { 20 | font-size: 22px; 21 | color: @colorBrown; 22 | } 23 | 24 | .header-details { 25 | .font-header(); 26 | } 27 | 28 | .item-subtitle { 29 | color: @colorTan; 30 | .font-daisywheel(); 31 | 32 | h4.item-type { 33 | font-size: 16px; 34 | margin: 0; 35 | } 36 | 37 | .item-qty { 38 | font-size: 16px; 39 | padding-right: 10px; 40 | 41 | input { 42 | text-align: right; 43 | max-width: 70px; 44 | } 45 | } 46 | } 47 | } 48 | 49 | /* ------------------------------------------- */ 50 | /* Sheet Navigation */ 51 | /* ------------------------------------------- */ 52 | 53 | .sheet-tabs { 54 | // .font-bluehighway-bold(); 55 | .font-daisywheel(); 56 | text-transform: uppercase; 57 | font-size: 11pt; 58 | color: @colorBrown; 59 | 60 | // Fixes a tab bug. 61 | &.slanted-tabs { 62 | margin-bottom: 1px; 63 | } 64 | } 65 | 66 | /* ------------------------------------------- */ 67 | /* Sheet Body */ 68 | /* ------------------------------------------- */ 69 | 70 | .sheet-body { 71 | color: @colorDark; 72 | background: @colorLightKhaki; 73 | 74 | .item-features { 75 | text-align: center; 76 | 77 | label { 78 | width: 100%; 79 | background: @colorItemLabel; 80 | border-bottom: 1px solid @colorBrown; 81 | .font-text-bold(); 82 | color: @colorBrown; 83 | } 84 | 85 | input { 86 | color: @colorBrown; 87 | } 88 | 89 | input[list] { 90 | text-align: center; 91 | } 92 | 93 | select { 94 | min-height: 22px; 95 | border: 1px solid transparent; 96 | &:hover, 97 | &:focus { 98 | background: #fff; 99 | border: 1px solid @colorBrown; 100 | } 101 | 102 | &.score-selector { 103 | align-self: center; 104 | } 105 | } 106 | } 107 | 108 | .features-other { 109 | margin-top: 5px; 110 | padding-top: 10px; 111 | border-top: @borderGroove; 112 | } 113 | 114 | .item-properties { 115 | label.checkbox { 116 | flex: 0 0 98px; 117 | font-size: 11px; 118 | } 119 | } 120 | 121 | .roll-modifiers { 122 | .roll-modifiers-title { 123 | text-transform: uppercase; 124 | border-bottom: @borderGroove; 125 | .font-header(); 126 | font-size: 1rem; 127 | margin-bottom: (@gap / 2); 128 | } 129 | 130 | .no-modifier { 131 | margin: @gap; 132 | font-style: italic; 133 | } 134 | 135 | .roll-modifier { 136 | display: flex; 137 | flex-direction: row; 138 | margin: (@gap / 2) (@gap / 2) 0 (@gap / 2); 139 | padding: 3px (@gap / 2) 3px @gap; 140 | background-color: #e8e8e8; 141 | border: 1px solid #c7c7c7; 142 | border-radius: 10px; 143 | color: @colorBlue; 144 | 145 | .roll-modifier-value { 146 | input { 147 | flex: 1; 148 | margin: 0 10px; 149 | border: 1px solid @colorTan; 150 | } 151 | } 152 | 153 | .item-controls { 154 | flex: 0; 155 | 156 | .delete-modifier { 157 | color: transparent; 158 | } 159 | } 160 | 161 | &:hover, 162 | &:focus { 163 | // background-color: #c7c7c7; 164 | // border: 1px solid @colorDark; 165 | box-shadow: @hoverShadow; 166 | 167 | .delete-modifier { 168 | color: @colorDark; 169 | } 170 | } 171 | } 172 | } 173 | 174 | // .tab { 175 | // // TODO clean this code 176 | // // &.tab-modifiers { 177 | // // h4 { 178 | // // text-transform: uppercase; 179 | // // border-bottom: @borderGroove; 180 | // // .font-header(); 181 | // // font-size: 1rem; 182 | // // } 183 | 184 | // // .modifiers-list { 185 | // // margin-bottom: 10px; 186 | // // } 187 | 188 | // // .form-group { 189 | // // margin: 0 0 1px 0; 190 | // // padding: 0 4px; 191 | // // color: @colorTan; 192 | // // border: 1px solid transparent; 193 | // // border-radius: 4px 20px 20px 4px; 194 | 195 | // // input { 196 | // // flex: 0 0 40px; 197 | // // text-align: right; 198 | // // color: @colorTan; 199 | // // } 200 | 201 | // // &.modified { 202 | // // font-weight: bold; 203 | // // color: @colorBrown; 204 | // // background: darken(@colorLightKhaki, 10%); 205 | // // border-color: @colorBrown; 206 | 207 | // // input { 208 | // // color: @colorBrown; 209 | // // font-weight: bold; 210 | // // } 211 | // // } 212 | // // } 213 | // } 214 | // } 215 | } 216 | } -------------------------------------------------------------------------------- /src/system/handlebars.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable quotes */ 2 | /** 3 | * Defines a set of template paths to pre-load. 4 | * Pre-loaded templates are compiled and cached for fast access when rendering. 5 | * @return {Promise} 6 | */ 7 | export async function preloadHandlebarsTemplates() { 8 | // /* Esbuild defines the paths for us at build time. */ 9 | // // eslint-disable-next-line no-undef 10 | // const paths = PATHS; 11 | // console.log('T2K4E | Loading Handlebars templates:', paths); 12 | // return loadTemplates(paths); 13 | return foundry.applications.handlebars.loadTemplates([ 14 | // Shared Partials 15 | // 'templates/dice/roll.html', 16 | 17 | // Actor Sheet Partials 18 | 'systems/t2k4e/templates/actor/parts/actor-stats.hbs', 19 | 'systems/t2k4e/templates/actor/parts/actor-combat.hbs', 20 | 'systems/t2k4e/templates/actor/parts/actor-equipment.hbs', 21 | 'systems/t2k4e/templates/actor/parts/actor-description.hbs', 22 | 'systems/t2k4e/templates/actor/parts/capacity-boxes.hbs', 23 | 'systems/t2k4e/templates/actor/parts/radiation-boxes.hbs', 24 | 'systems/t2k4e/templates/actor/parts/slots/slot-buttons.hbs', 25 | 'systems/t2k4e/templates/actor/parts/slots/weapon-slot.hbs', 26 | 'systems/t2k4e/templates/actor/parts/slots/armor-slot.hbs', 27 | 'systems/t2k4e/templates/actor/parts/slots/gear-slot.hbs', 28 | 'systems/t2k4e/templates/actor/parts/slots/ammo-slot.hbs', 29 | 30 | // Vehicle Sheet Partials 31 | 'systems/t2k4e/templates/actor/parts/vehicle-crew.hbs', 32 | 'systems/t2k4e/templates/actor/parts/vehicle-combat.hbs', 33 | 'systems/t2k4e/templates/actor/parts/vehicle-cargo.hbs', 34 | 'systems/t2k4e/templates/actor/parts/vehicle-components.hbs', 35 | 'systems/t2k4e/templates/actor/parts/slots/vehicle-weapon-slot.hbs', 36 | 37 | // Party Sheet Partials 38 | 'systems/t2k4e/templates/actor/party/sheet-tabs/main-tab.hbs', 39 | 'systems/t2k4e/templates/actor/party/sheet-tabs/travel-tab.hbs', 40 | 'systems/t2k4e/templates/actor/party/components/action-component.hbs', 41 | 'systems/t2k4e/templates/actor/party/components/member-component.hbs', 42 | 43 | // Item Sheet Partials 44 | 'systems/t2k4e/templates/item/parts/item-header.hbs', 45 | 'systems/t2k4e/templates/item/parts/item-modifiers.hbs', 46 | 'systems/t2k4e/templates/item/parts/item-description.hbs', 47 | 48 | // Chat Partials 49 | ]); 50 | } 51 | 52 | /* -------------------------------------------- */ 53 | /* HandlebarsJS Custom Helpers */ 54 | /* -------------------------------------------- */ 55 | 56 | /** 57 | * Defines Handlebars custom Helpers and Partials. 58 | */ 59 | export function registerHandlebars() { 60 | Handlebars.registerHelper('concat', function () { 61 | let str = ''; 62 | for (const arg in arguments) { 63 | if (typeof arguments[arg] !== 'object') { 64 | str += arguments[arg]; 65 | } 66 | } 67 | return str; 68 | }); 69 | 70 | Handlebars.registerHelper('capitalize', function (val) { 71 | return typeof val === 'string' && val.length > 0 ? val[0].toUpperCase() + val.slice(1) : val; 72 | }); 73 | 74 | Handlebars.registerHelper('toLowerCase', function (str) { 75 | return str.toLowerCase(); 76 | }); 77 | 78 | Handlebars.registerHelper('toUpperCase', function (str) { 79 | return str.toUpperCase(); 80 | }); 81 | 82 | // Handlebars.registerHelper('flps_enrich', function (content) { 83 | // // Enriches content. 84 | // content = TextEditor.enrichHTML(content, { documents: true, async: true }); 85 | // return new Handlebars.SafeString(content); 86 | // }); 87 | 88 | Handlebars.registerHelper('times', function (n, content) { 89 | let str = ''; 90 | for (let i = 0; i < n; i++) { 91 | content.data.max = n; 92 | content.data.index = i + 1; 93 | str += content.fn(i); 94 | } 95 | return str; 96 | }); 97 | 98 | Handlebars.registerHelper('mathMin', function (a, b) { 99 | return Math.min(a, b); 100 | }); 101 | 102 | Handlebars.registerHelper('mathMax', function (a, b) { 103 | return Math.max(a, b); 104 | }); 105 | 106 | Handlebars.registerHelper('add', function (a, b) { 107 | return a + b; 108 | }); 109 | 110 | Handlebars.registerHelper('divide', function (a, b) { 111 | return a / b; 112 | }); 113 | 114 | Handlebars.registerHelper('multiply', function (a, b) { 115 | return a * b; 116 | }); 117 | 118 | Handlebars.registerHelper('ratio', function (a, b) { 119 | return (a / b) * 100; 120 | }); 121 | 122 | Handlebars.registerHelper('selectBuilder', function (selectionName, list, selection) { 123 | const selectOptions = []; 124 | list.forEach(option => { 125 | const isSelected = option === selection; 126 | const opt = ``; 127 | selectOptions.push(opt); 128 | }); 129 | return new Handlebars.SafeString(``); 132 | }); 133 | 134 | /** 135 | * Templates for a die Score selector. 136 | * Parameters: 137 | * * `name` - The name of the affected variable. 138 | * * `selected` - The current selected value. 139 | */ 140 | Handlebars.registerPartial( 141 | 'scoreSelector', 142 | ``, 149 | ); 150 | } 151 | -------------------------------------------------------------------------------- /src/item/templates/grenade-sheet.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | {{!-- Item Sheet Header --}} 4 | {{> "systems/t2k4e/templates/item/parts/item-header.hbs"}} 5 | 6 | {{!-- Sheet Tab Navigation --}} 7 | 11 | 12 | {{!-- Sheet Body --}} 13 |
    14 | 15 | {{!-- Features Tab --}} 16 |
    17 |
    18 |
    19 | 20 | 21 |
    22 | {{!--
    23 | 24 | 25 |
    --}} 26 | {{!--
    27 | 28 |
    29 | {{selectBuilder "system.reliability.score" @root.config.dieScores system.reliability.score}} 30 | / 31 | {{selectBuilder "system.reliability.max" @root.config.dieScores system.reliability.max}} 32 |
    33 |
    --}} 34 | {{!--
    35 | 36 | 37 |
    --}} 38 |
    39 | 40 | 41 |
    42 |
    43 | 44 | 45 |
    46 |
    47 | 48 | {{selectBuilder "system.blast" @root.config.dieScores system.blast}} 49 |
    50 |
    51 | 52 | 53 |
    54 | {{!--
    55 | 56 |
    57 | 58 | / 59 | 60 |
    61 |
    --}} 62 |
    63 | 64 | 65 |
    66 |
    67 | 68 | 69 |
    70 |
    71 | 72 | 73 |
    74 |
    75 | 76 | {{!-- Other Parameters --}} 77 |
    78 | 79 | {{!-- Used Attribute --}} 80 |
    81 | 82 | 85 |
    86 | 87 | {{!-- Used Skill --}} 88 |
    89 | 90 | 93 |
    94 | 95 | {{!-- Properties --}} 96 |
    97 | 101 |
    102 | 103 |
    104 | 105 | {{!-- Inventory Options --}} 106 | {{#if inActor}} 107 |
    108 |
    109 | 113 |
    114 |
    115 | 119 |
    120 |
    121 | {{/if}} 122 | 123 |
    124 | 125 | {{!-- Description Tab --}} 126 |
    127 | {{> "systems/t2k4e/templates/item/parts/item-description.hbs"}} 128 |
    129 | 130 |
    131 | 132 |
    133 | --------------------------------------------------------------------------------