├── .editorconfig ├── .eslintrc ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── babel.config.json ├── firebase.json ├── firestore.indexes.json ├── firestore.rules ├── jest.config.js ├── nx.json ├── package-lock.json ├── package.json ├── packages ├── emporium-e2e │ ├── .eslintrc │ ├── cypress.json │ ├── src │ │ ├── fixtures │ │ │ └── example.json │ │ ├── integration │ │ │ └── app.spec.ts │ │ ├── plugins │ │ │ └── index.js │ │ └── support │ │ │ ├── app.po.ts │ │ │ ├── commands.ts │ │ │ └── index.ts │ ├── tsconfig.e2e.json │ └── tsconfig.json ├── emporium │ ├── .babelrc │ ├── .browserslistrc │ ├── .eslintrc │ ├── babel-jest.config.json │ ├── database.rules.json │ ├── emporium-changelog.md │ ├── jest.config.js │ ├── src │ │ ├── app │ │ │ ├── app.scss │ │ │ ├── app.spec.tsx │ │ │ ├── app.tsx │ │ │ ├── components │ │ │ │ ├── About.tsx │ │ │ │ ├── Archetype.tsx │ │ │ │ ├── ArchetypeSkills.tsx │ │ │ │ ├── ArchetypeStats.tsx │ │ │ │ ├── Attributes.tsx │ │ │ │ ├── Buttons.tsx │ │ │ │ ├── Career.tsx │ │ │ │ ├── CharacterDescription.tsx │ │ │ │ ├── CharacterImage.tsx │ │ │ │ ├── CharacterSelect.tsx │ │ │ │ ├── Characteristics.tsx │ │ │ │ ├── CustomData │ │ │ │ │ ├── CustomArchetypeTalents.tsx │ │ │ │ │ ├── CustomArchetypes.tsx │ │ │ │ │ ├── CustomCareers.tsx │ │ │ │ │ ├── CustomData.tsx │ │ │ │ │ ├── CustomEquipment.tsx │ │ │ │ │ ├── CustomMotivations.tsx │ │ │ │ │ ├── CustomSettings.tsx │ │ │ │ │ ├── CustomSkills.tsx │ │ │ │ │ ├── CustomTalents.tsx │ │ │ │ │ ├── CustomVehicles.tsx │ │ │ │ │ ├── Fragments.tsx │ │ │ │ │ ├── SettingBuilder.tsx │ │ │ │ │ └── index.ts │ │ │ │ ├── DataPage.tsx │ │ │ │ ├── Description.tsx │ │ │ │ ├── Equipment.tsx │ │ │ │ ├── ErrorBoundary.tsx │ │ │ │ ├── ImportExport.tsx │ │ │ │ ├── Loading.tsx │ │ │ │ ├── MainPage.tsx │ │ │ │ ├── ModalDeleteConfirm.tsx │ │ │ │ ├── Motivation.tsx │ │ │ │ ├── MotivationBlock.tsx │ │ │ │ ├── Notes.tsx │ │ │ │ ├── ShowCharacteristics.tsx │ │ │ │ ├── Skill.tsx │ │ │ │ ├── SkillBlock.tsx │ │ │ │ ├── SkillRow.tsx │ │ │ │ ├── TalentBlock.tsx │ │ │ │ ├── TalentDedication.tsx │ │ │ │ ├── TalentList.tsx │ │ │ │ ├── TalentSelection.tsx │ │ │ │ ├── Talents.tsx │ │ │ │ ├── User.tsx │ │ │ │ ├── UserButton.tsx │ │ │ │ ├── VehicleSelect.tsx │ │ │ │ ├── XPBoxes.tsx │ │ │ │ ├── XPPopup.tsx │ │ │ │ ├── critical │ │ │ │ │ ├── critical.scss │ │ │ │ │ └── critical.tsx │ │ │ │ ├── gear │ │ │ │ │ ├── gear.scss │ │ │ │ │ └── gear.tsx │ │ │ │ ├── index.ts │ │ │ │ └── printLayout │ │ │ │ │ ├── Attributes.tsx │ │ │ │ │ ├── Character.tsx │ │ │ │ │ ├── CharacterDescription.tsx │ │ │ │ │ ├── CharacterImage.tsx │ │ │ │ │ ├── Characteristics.tsx │ │ │ │ │ ├── Critical.tsx │ │ │ │ │ ├── Equipment.tsx │ │ │ │ │ ├── Motivations.tsx │ │ │ │ │ ├── Notes.tsx │ │ │ │ │ ├── PrintLayout.tsx │ │ │ │ │ ├── Skill.tsx │ │ │ │ │ ├── SkillBlock.tsx │ │ │ │ │ ├── SkillRow.tsx │ │ │ │ │ ├── TalentPyramid.tsx │ │ │ │ │ ├── XP.tsx │ │ │ │ │ └── index.ts │ │ │ └── firestoreDB.js │ │ ├── assets │ │ │ ├── data │ │ │ │ ├── archetypeTalents │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ ├── archetypes │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ ├── armor │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ ├── careers │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ ├── craftsmanship │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ ├── gear │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ ├── index.js │ │ │ │ ├── lists.js │ │ │ │ ├── motivations.json │ │ │ │ ├── qualities.json │ │ │ │ ├── settings.json │ │ │ │ ├── skills.json │ │ │ │ ├── talents │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── EPG.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ ├── vehicles │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ │ └── weapons │ │ │ │ │ ├── CRB.json │ │ │ │ │ ├── KF.json │ │ │ │ │ ├── ROT.json │ │ │ │ │ └── SOTB.json │ │ │ ├── images │ │ │ │ ├── CRB │ │ │ │ │ ├── Agility.svg │ │ │ │ │ ├── AvailableXp.svg │ │ │ │ │ ├── BlankStat.svg │ │ │ │ │ ├── Brawn.svg │ │ │ │ │ ├── Cunning.svg │ │ │ │ │ ├── Defense.svg │ │ │ │ │ ├── Intellect.svg │ │ │ │ │ ├── Logo.svg │ │ │ │ │ ├── Presence.svg │ │ │ │ │ ├── Soak.svg │ │ │ │ │ ├── Strain.svg │ │ │ │ │ ├── StrainThreshold.svg │ │ │ │ │ ├── TotalXp.svg │ │ │ │ │ ├── VehicleStatBlock.svg │ │ │ │ │ ├── Willpower.svg │ │ │ │ │ ├── Wounds.svg │ │ │ │ │ ├── WoundsThreshold.svg │ │ │ │ │ ├── background.png │ │ │ │ │ └── index.ts │ │ │ │ ├── Crest.png │ │ │ │ ├── KF │ │ │ │ │ ├── Agility.svg │ │ │ │ │ ├── AvailableXp.svg │ │ │ │ │ ├── BlankStat.svg │ │ │ │ │ ├── Brawn.svg │ │ │ │ │ ├── Cunning.svg │ │ │ │ │ ├── Defense.svg │ │ │ │ │ ├── Intellect.svg │ │ │ │ │ ├── Logo.svg │ │ │ │ │ ├── Presence.svg │ │ │ │ │ ├── Soak.svg │ │ │ │ │ ├── Strain.svg │ │ │ │ │ ├── StrainThreshold.svg │ │ │ │ │ ├── TotalXp.svg │ │ │ │ │ ├── VehicleStatBlock.svg │ │ │ │ │ ├── Willpower.svg │ │ │ │ │ ├── Wounds.svg │ │ │ │ │ ├── WoundsThreshold.svg │ │ │ │ │ ├── background.png │ │ │ │ │ ├── index.ts │ │ │ │ │ └── kf-vehicle-statblocks.svg │ │ │ │ ├── ROT │ │ │ │ │ ├── Agility.svg │ │ │ │ │ ├── AvailableXp.svg │ │ │ │ │ ├── BlankStat.svg │ │ │ │ │ ├── Brawn.svg │ │ │ │ │ ├── Cunning.svg │ │ │ │ │ ├── Defense.svg │ │ │ │ │ ├── Intellect.svg │ │ │ │ │ ├── Logo.svg │ │ │ │ │ ├── Presence.svg │ │ │ │ │ ├── Soak.svg │ │ │ │ │ ├── Strain.svg │ │ │ │ │ ├── StrainThreshold.svg │ │ │ │ │ ├── TotalXp.svg │ │ │ │ │ ├── VehicleStatBlock.svg │ │ │ │ │ ├── Willpower.svg │ │ │ │ │ ├── Wounds.svg │ │ │ │ │ ├── WoundsThreshold.svg │ │ │ │ │ ├── background.png │ │ │ │ │ └── index.ts │ │ │ │ ├── SOTB │ │ │ │ │ ├── Agility.svg │ │ │ │ │ ├── AvailableXp.svg │ │ │ │ │ ├── BlankCharacteristic.svg │ │ │ │ │ ├── BlankStat.svg │ │ │ │ │ ├── Brawn.svg │ │ │ │ │ ├── Cunning.svg │ │ │ │ │ ├── Defense.svg │ │ │ │ │ ├── Intellect.svg │ │ │ │ │ ├── Logo.png │ │ │ │ │ ├── Presence.svg │ │ │ │ │ ├── Soak.svg │ │ │ │ │ ├── Strain.svg │ │ │ │ │ ├── StrainThreshold.svg │ │ │ │ │ ├── TotalXp.svg │ │ │ │ │ ├── VehicleStatBlock.svg │ │ │ │ │ ├── Willpower.svg │ │ │ │ │ ├── Wounds.svg │ │ │ │ │ ├── WoundsThreshold.svg │ │ │ │ │ ├── background.png │ │ │ │ │ └── index.ts │ │ │ │ ├── emporium.png │ │ │ │ ├── gm.png │ │ │ │ ├── index.ts │ │ │ │ ├── pc.png │ │ │ │ └── user.svg │ │ │ ├── manifest.json │ │ │ └── service-worker.js │ │ ├── index.html │ │ ├── main.tsx │ │ ├── polyfills.ts │ │ ├── redux │ │ │ ├── actions.tsx │ │ │ ├── changeState.tsx │ │ │ ├── initialState.tsx │ │ │ ├── reducers.tsx │ │ │ └── selectors │ │ │ │ ├── archetypeSkillRank.tsx │ │ │ │ ├── careerCheck.tsx │ │ │ │ ├── characteristics.tsx │ │ │ │ ├── criticals.tsx │ │ │ │ ├── encumbranceLimit.tsx │ │ │ │ ├── equipmentStats.tsx │ │ │ │ ├── gearDice.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── maxCareerSkills.tsx │ │ │ │ ├── skillDice.tsx │ │ │ │ ├── skillRanks.tsx │ │ │ │ ├── strainThreshold.tsx │ │ │ │ ├── talentCount.tsx │ │ │ │ ├── totalDefense.tsx │ │ │ │ ├── totalEncumbrance.tsx │ │ │ │ ├── totalSoak.tsx │ │ │ │ ├── totalXP.tsx │ │ │ │ ├── usedXP.tsx │ │ │ │ └── woundThreshold.tsx │ │ ├── styles.scss │ │ └── styles │ │ │ ├── fonts │ │ │ ├── AGaramondPro-Bold.woff │ │ │ ├── AGaramondPro-Bold.woff2 │ │ │ ├── AGaramondPro-BoldItalic.woff │ │ │ ├── AGaramondPro-BoldItalic.woff2 │ │ │ ├── AGaramondPro-Italic.woff │ │ │ ├── AGaramondPro-Italic.woff2 │ │ │ ├── AGaramondPro-Regular.woff │ │ │ ├── AGaramondPro-Regular.woff2 │ │ │ ├── AvenirNextLTPro-Bold.woff │ │ │ ├── AvenirNextLTPro-Bold.woff2 │ │ │ ├── AvenirNextLTPro-Regular.woff │ │ │ ├── AvenirNextLTPro-Regular.woff2 │ │ │ ├── BebasNeueBold.woff │ │ │ ├── BebasNeueBold.woff2 │ │ │ ├── BebasNeueRegular.woff │ │ │ ├── BebasNeueRegular.woff2 │ │ │ ├── Bolton.woff │ │ │ ├── Bolton.woff2 │ │ │ ├── BoltonBold.woff │ │ │ ├── BoltonBold.woff2 │ │ │ ├── BoltonBoldItalic.woff │ │ │ ├── BoltonBoldItalic.woff2 │ │ │ ├── BoltonItalic.woff │ │ │ ├── BoltonItalic.woff2 │ │ │ ├── CharisSIL-Bold.woff │ │ │ ├── CharisSIL-Bold.woff2 │ │ │ ├── CharisSIL.woff │ │ │ ├── CharisSIL.woff2 │ │ │ ├── MinionPro-Bold.woff │ │ │ ├── MinionPro-Bold.woff2 │ │ │ ├── MinionPro-Regular.woff │ │ │ ├── MinionPro-Regular.woff2 │ │ │ ├── american-captain-webfont.woff │ │ │ ├── american-captain-webfont.woff2 │ │ │ ├── archistico_bold.woff │ │ │ ├── archistico_bold.woff2 │ │ │ ├── archistico_simple.woff │ │ │ ├── archistico_simple.woff2 │ │ │ ├── index.scss │ │ │ ├── khand-bold-webfont.woff │ │ │ ├── khand-bold-webfont.woff2 │ │ │ ├── khand-light-webfont.woff │ │ │ ├── khand-light-webfont.woff2 │ │ │ ├── khand-medium-webfont.woff │ │ │ ├── khand-medium-webfont.woff2 │ │ │ ├── khand-regular-webfont.woff │ │ │ ├── khand-regular-webfont.woff2 │ │ │ ├── khand-semibold-webfont.woff │ │ │ └── khand-semibold-webfont.woff2 │ │ │ ├── index.scss │ │ │ ├── main.scss │ │ │ ├── tabs.scss │ │ │ ├── themes │ │ │ └── kf.scss │ │ │ └── vehicle.scss │ ├── tsconfig.app.json │ ├── tsconfig.json │ └── tsconfig.spec.json └── ui │ ├── .babelrc │ ├── .eslintrc │ ├── README.md │ ├── babel-jest.config.json │ ├── jest.config.js │ ├── src │ ├── index.ts │ └── lib │ │ ├── control-button-set │ │ ├── control-button-set.scss │ │ ├── control-button-set.spec.tsx │ │ └── control-button-set.tsx │ │ └── delete-button │ │ ├── delete-button.scss │ │ ├── delete-button.spec.tsx │ │ └── delete-button.tsx │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── tools ├── schematics │ └── .gitkeep └── tsconfig.tools.json ├── tsconfig.json └── workspace.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 2018, 6 | "sourceType": "module", 7 | "project": "./tsconfig.json" 8 | }, 9 | "ignorePatterns": ["**/*"], 10 | "plugins": ["@typescript-eslint", "@nrwl/nx"], 11 | "extends": [ 12 | "eslint:recommended", 13 | "plugin:@typescript-eslint/eslint-recommended", 14 | "plugin:@typescript-eslint/recommended", 15 | "prettier", 16 | "prettier/@typescript-eslint" 17 | ], 18 | "rules": { 19 | "curly": "error", 20 | "TS2525": "off", 21 | "no-case-declarations": "off", 22 | "no-async-promise-executor": "off", 23 | "@typescript-eslint/no-explicit-any": "off", 24 | "@typescript-eslint/ban-ts-ignore": "off", 25 | "@typescript-eslint/no-empty-function": "off", 26 | "@typescript-eslint/explicit-member-accessibility": "error", 27 | "@typescript-eslint/explicit-function-return-type": "warn", 28 | "@typescript-eslint/no-parameter-properties": "off", 29 | "lines-between-class-members": ["error", "always"], 30 | "padding-line-between-statements": [ 31 | "error", 32 | { 33 | "blankLine": "always", 34 | "prev": [ 35 | "block-like", 36 | "multiline-const", 37 | "multiline-var", 38 | "multiline-expression", 39 | "multiline-let", 40 | "function" 41 | ], 42 | "next": "*" 43 | } 44 | ], 45 | "@nrwl/nx/enforce-module-boundaries": [ 46 | "error", 47 | { 48 | "enforceBuildableLibDependency": true, 49 | "allow": [], 50 | "depConstraints": [ 51 | { "sourceTag": "*", "onlyDependOnLibsWithTags": ["*"] } 52 | ] 53 | } 54 | ] 55 | }, 56 | "overrides": [ 57 | { 58 | "files": ["*.tsx"], 59 | "rules": { 60 | "@typescript-eslint/no-unused-vars": "off" 61 | } 62 | } 63 | ] 64 | } 65 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Env file 4 | .env 5 | 6 | # Compiled output 7 | /dist 8 | /tmp 9 | /out-tsc 10 | 11 | # Dependencies 12 | /node_modules 13 | 14 | # IDEs and editors 15 | /.idea 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # IDE - VSCode 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | 30 | # System Files 31 | .DS_Store 32 | Thumbs.db 33 | 34 | # Firebase 35 | .firebase 36 | .firebaserc 37 | 38 | # Misc 39 | /.sass-cache 40 | /connect.lock 41 | /coverage 42 | /libpeerconnection.log 43 | npm-debug.log 44 | yarn-error.log 45 | testem.log 46 | /typings 47 | yarn-debug.log* 48 | *.iml 49 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | 3 | /dist 4 | /coverage 5 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "tabWidth": 4, 3 | "singleQuote": true, 4 | "bracketSpacing": true, 5 | "arrowParens": "avoid", 6 | "trailingComma": "none", 7 | "semi": true, 8 | "printWidth": 80 9 | } 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Genesys Emporium 2 | 3 | ## Current Production Build 4 | 5 | [The Genesys Emporium](https://genesysemporium.com) 6 | 7 | ## Community 8 | 9 | [Support/Unbound Legends Discord](https://discord.gg/wc7BGW5) 10 | [Genesys Community Discord](https://discord.gg/XphjJxM) 11 | 12 | ## Misc 13 | 14 | Genesys was created by [Fantasy Flight Games, Genesys](https://www.fantasyflightgames.com/en/products/genesys). 15 | 16 | Genesys Emporium was originally created by [SkyJedi](https://twitter.com/SkyJedi). 17 | Go check him out, he's an awesome guy who has made many major contributions to the Genesys community. 18 | 19 | ## Building & Running 20 | - create a firebase project with authentication (google) and firestore, configure firestore permissions with rules from firestore.rules 21 | 22 | - create packages/emporium/.env 23 | ``` 24 | NX_apiKey=> 25 | NX_authDomain=.firebaseapp.com 26 | NX_databaseURL=https://.firebaseio.com 27 | NX_projectId= 28 | NX_storageBucket=.appspot.com 29 | NX_messagingSenderId=SENDER_ID 30 | ``` 31 | 32 | install and run 33 | ``` 34 | npm install 35 | npm run start 36 | ``` 37 | If you get an error message like 38 | `Error: Cannot find module '@nrwl/workspace/src/utilities/output'` 39 | go to `node_modules/@nrwl/workspace/src` and create a symlink utilities->utils 40 | 41 | -------------------------------------------------------------------------------- /babel.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@nrwl/web/babel"], 3 | "babelrcRoots": ["*"] 4 | } 5 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "database": { 3 | "rules": "database.rules.json" 4 | }, 5 | "hosting": { 6 | "public": "dist/packages/emporium", 7 | "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], 8 | "rewrites": [ 9 | { 10 | "source": "**", 11 | "destination": "/index.html" 12 | } 13 | ] 14 | }, 15 | "firestore": { 16 | "rules": "firestore.rules", 17 | "indexes": "firestore.indexes.json" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /firestore.indexes.json: -------------------------------------------------------------------------------- 1 | { 2 | // Example: 3 | // 4 | // "indexes": [ 5 | // { 6 | // "collectionId": "widgets", 7 | // "fields": [ 8 | // { "fieldPath": "foo", "mode": "ASCENDING" }, 9 | // { "fieldPath": "bar", "mode": "DESCENDING" } 10 | // ] 11 | // } 12 | // ] 13 | "indexes": [] 14 | } -------------------------------------------------------------------------------- /firestore.rules: -------------------------------------------------------------------------------- 1 | service cloud.firestore { 2 | match /databases/{database}/documents { 3 | 4 | function dbData(type, document) { 5 | return get(/databases/$(database)/documents/$(type)/$(document)).data 6 | } 7 | 8 | match /users/{userId}/data/{document=**} { 9 | allow read, write: if request.auth.uid == userId; 10 | } 11 | 12 | match /users/{userId}/customData/{document=**} { 13 | allow read, write: if request.auth.uid == userId; 14 | } 15 | 16 | match /{db}/{document} { 17 | allow create: if request.auth.uid != null; 18 | allow read: if request.auth.uid != null; 19 | allow write, delete: if request.auth.uid in dbData(db, document).write; 20 | 21 | match /data/{type} { 22 | allow read: if request.auth.uid != null; 23 | allow write, delete: if request.auth.uid in dbData(db, document).write; 24 | } 25 | } 26 | 27 | match /userDB/{document} { 28 | allow write: if request.resource.data.uid == request.auth.uid; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testMatch: ['**/+(*.)+(spec|test).+(ts|js)?(x)'], 3 | transform: { 4 | '^.+\\.(ts|js|html)$': 'ts-jest', 5 | }, 6 | resolver: '@nrwl/jest/plugins/resolver', 7 | moduleFileExtensions: ['ts', 'js', 'html'], 8 | coverageReporters: ['html'], 9 | }; 10 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "npmScope": "genesys-emporium", 3 | "affected": { 4 | "defaultBase": "master" 5 | }, 6 | "implicitDependencies": { 7 | "workspace.json": "*", 8 | "package.json": { 9 | "dependencies": "*", 10 | "devDependencies": "*" 11 | }, 12 | "tsconfig.json": "*", 13 | "tslint.json": "*", 14 | "nx.json": "*" 15 | }, 16 | "tasksRunnerOptions": { 17 | "default": { 18 | "runner": "@nrwl/nx-cloud", 19 | "options": { 20 | "accessToken": "ZGY2MGRjMmQtMGVhOC00YjU3LWIzM2QtZjNlY2UzNTc4YjBlfHJlYWQtd3JpdGU=", 21 | "cacheableOperations": ["build", "test", "lint", "e2e"], 22 | "canTrackAnalytics": false, 23 | "showUsageWarnings": true 24 | } 25 | } 26 | }, 27 | "projects": { 28 | "emporium": { 29 | "tags": [] 30 | }, 31 | "emporium-e2e": { 32 | "tags": [], 33 | "implicitDependencies": ["emporium"] 34 | }, 35 | "ui": { 36 | "tags": [] 37 | } 38 | }, 39 | "workspaceLayout": { 40 | "appsDir": "packages", 41 | "libsDir": "packages" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/emporium-e2e/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": {}, 3 | "overrides": [ 4 | { 5 | "files": ["src/plugins/index.js"], 6 | "rules": { 7 | "@typescript-eslint/no-var-requires": "off", 8 | "no-undef": "off" 9 | } 10 | } 11 | ], 12 | "extends": ["plugin:cypress/recommended", "../../.eslintrc"], 13 | "ignorePatterns": ["!**/*"] 14 | } 15 | -------------------------------------------------------------------------------- /packages/emporium-e2e/cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileServerFolder": ".", 3 | "fixturesFolder": "./src/fixtures", 4 | "integrationFolder": "./src/integration", 5 | "modifyObstructiveCode": false, 6 | "pluginsFile": "./src/plugins/index", 7 | "supportFile": "./src/support/index.ts", 8 | "video": true, 9 | "videosFolder": "../../dist/cypress/packages/emporium-e2e/videos", 10 | "screenshotsFolder": "../../dist/cypress/packages/emporium-e2e/screenshots", 11 | "chromeWebSecurity": false 12 | } 13 | -------------------------------------------------------------------------------- /packages/emporium-e2e/src/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io" 4 | } 5 | -------------------------------------------------------------------------------- /packages/emporium-e2e/src/integration/app.spec.ts: -------------------------------------------------------------------------------- 1 | import { getGreeting } from '../support/app.po'; 2 | 3 | describe('emporium', () => { 4 | beforeEach(() => cy.visit('/')); 5 | 6 | it('should display welcome message', () => { 7 | // Custom command example, see `../support/commands.ts` file 8 | cy.login('my-email@something.com', 'myPassword'); 9 | 10 | // Function helper example, see `../support/app.po.ts` file 11 | getGreeting().contains('Welcome to emporium!'); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /packages/emporium-e2e/src/plugins/index.js: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example plugins/index.js can be used to load plugins 3 | // 4 | // You can change the location of this file or turn off loading 5 | // the plugins file with the 'pluginsFile' configuration option. 6 | // 7 | // You can read more here: 8 | // https://on.cypress.io/plugins-guide 9 | // *********************************************************** 10 | 11 | // This function is called when a project is opened or re-opened (e.g. due to 12 | // the project's config changing) 13 | 14 | const { preprocessTypescript } = require('@nrwl/cypress/plugins/preprocessor'); 15 | 16 | module.exports = (on, config) => { 17 | // `on` is used to hook into various events Cypress emits 18 | // `config` is the resolved Cypress config 19 | 20 | // Preprocess Typescript file using Nx helper 21 | on('file:preprocessor', preprocessTypescript(config)); 22 | }; 23 | -------------------------------------------------------------------------------- /packages/emporium-e2e/src/support/app.po.ts: -------------------------------------------------------------------------------- 1 | export const getGreeting = () => cy.get('h1'); 2 | -------------------------------------------------------------------------------- /packages/emporium-e2e/src/support/commands.ts: -------------------------------------------------------------------------------- 1 | // *********************************************** 2 | // This example commands.js shows you how to 3 | // create various custom commands and overwrite 4 | // existing commands. 5 | // 6 | // For more comprehensive examples of custom 7 | // commands please read more here: 8 | // https://on.cypress.io/custom-commands 9 | // *********************************************** 10 | // eslint-disable-next-line @typescript-eslint/no-namespace 11 | declare namespace Cypress { 12 | interface Chainable { 13 | login(email: string, password: string): void; 14 | } 15 | } 16 | // 17 | // -- This is a parent command -- 18 | Cypress.Commands.add('login', (email, password) => { 19 | console.log('Custom command example: Login', email, password); 20 | }); 21 | // 22 | // -- This is a child command -- 23 | // Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) 24 | // 25 | // 26 | // -- This is a dual command -- 27 | // Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) 28 | // 29 | // 30 | // -- This will overwrite an existing command -- 31 | // Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) 32 | -------------------------------------------------------------------------------- /packages/emporium-e2e/src/support/index.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/index.js is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands'; 18 | -------------------------------------------------------------------------------- /packages/emporium-e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "sourceMap": false, 5 | "outDir": "../../dist/out-tsc", 6 | "allowJs": true 7 | }, 8 | "include": ["src/**/*.ts", "src/**/*.js"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/emporium-e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "types": ["cypress", "node"] 5 | }, 6 | "include": ["**/*.ts", "**/*.js"] 7 | } 8 | -------------------------------------------------------------------------------- /packages/emporium/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@nrwl/react/babel"], 3 | "plugins": [] 4 | } 5 | -------------------------------------------------------------------------------- /packages/emporium/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is used by: 2 | # 1. autoprefixer to adjust CSS to support the below specified browsers 3 | # 2. babel preset-env to adjust included polyfills 4 | # 5 | # For additional information regarding the format and rule options, please see: 6 | # https://github.com/browserslist/browserslist#queries 7 | # 8 | # If you need to support different browsers in production, you may tweak the list below. 9 | 10 | > 0.2% 11 | not dead 12 | not op_mini all 13 | -------------------------------------------------------------------------------- /packages/emporium/babel-jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ], 11 | "@babel/preset-typescript", 12 | "@babel/preset-react" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/emporium/database.rules.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | ".read": "true", 4 | ".write": "true" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/emporium/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'emporium', 3 | preset: '../../jest.config.js', 4 | transform: { 5 | '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': '@nrwl/react/plugins/jest', 6 | '^.+\\.[tj]sx?$': [ 7 | 'babel-jest', 8 | { cwd: __dirname, configFile: './babel-jest.config.json' }, 9 | ], 10 | }, 11 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], 12 | coverageDirectory: '../../coverage/packages/emporium', 13 | }; 14 | -------------------------------------------------------------------------------- /packages/emporium/src/app/app.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/app/app.scss -------------------------------------------------------------------------------- /packages/emporium/src/app/app.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import { BrowserRouter } from 'react-router-dom'; 5 | 6 | import App from './app'; 7 | 8 | describe('App', () => { 9 | it('should render successfully', () => { 10 | const { baseElement } = render( 11 | 12 | 13 | 14 | ); 15 | 16 | expect(baseElement).toBeTruthy(); 17 | }); 18 | 19 | it('should have a greeting as the title', () => { 20 | const { getByText } = render( 21 | 22 | 23 | 24 | ); 25 | 26 | expect(getByText('Welcome to emporium!')).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/About.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, Row } from 'reactstrap'; 3 | 4 | export const About = () => { 5 | return ( 6 |
7 | 8 | Created by  9 | 14 | SkyJedi 15 | 16 | . Maintained by  17 | 22 | Unbound Legends 23 | 24 | . 25 | 26 | 27 | 35 | 43 | 51 | 59 | 60 | 61 | Contributions by Nick Holmstead. 62 | 63 | 64 | Images by  65 | 70 | DrainSmith 71 | 72 | .   73 | 74 | 75 | A Character Creator for  76 | 81 | Fantasy Flight Games' 82 | 83 | ,  84 | 89 | Genesys 90 | 91 | . 92 | 93 | 94 | 99 | Source Code 100 | 101 | {/* TODO: Add dynamic version support that doesn't use package.json */} 102 |  v0.2.1.5 103 | 104 |
105 | ); 106 | }; 107 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/Archetype.tsx: -------------------------------------------------------------------------------- 1 | import { changeData } from '@emporium/actions'; 2 | import { omit } from 'lodash-es'; 3 | import React from 'react'; 4 | import { connect } from 'react-redux'; 5 | import { Button, Input, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; 6 | import { bindActionCreators } from 'redux'; 7 | import { ArchetypeStats } from './ArchetypeStats'; 8 | 9 | class ArchetypeComponent extends React.Component { 10 | public handleSelect = event => { 11 | const value = event.target.value === '' ? null : event.target.value; 12 | this.props.changeData(value, 'archetype'); 13 | this.props.changeData('', 'archetypeSpecialSkills'); 14 | this.props.changeData( 15 | omit(this.props.misc, 'archetypeTalents'), 16 | 'misc', 17 | false 18 | ); 19 | }; 20 | 21 | public render() { 22 | const { archetype, archetypes, handleClose, modal, theme } = this.props; 23 | return ( 24 | 30 | 31 | Select Archetype 32 | 33 | 34 | 40 | 47 | ))} 48 | 49 | 50 | 51 | 52 | 55 | 56 | 57 | ); 58 | } 59 | } 60 | 61 | const mapStateToProps = state => { 62 | return { 63 | archetypes: state.archetypes, 64 | archetype: state.archetype, 65 | misc: state.misc, 66 | theme: state.theme 67 | }; 68 | }; 69 | 70 | const matchDispatchToProps = dispatch => 71 | bindActionCreators({ changeData }, dispatch); 72 | 73 | export const Archetype = connect( 74 | mapStateToProps, 75 | matchDispatchToProps 76 | )(ArchetypeComponent); 77 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/Buttons.tsx: -------------------------------------------------------------------------------- 1 | import { changeData, changePrintContent } from '@emporium/actions'; 2 | import React from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { Button, ButtonGroup, Col, Input, Label, Row } from 'reactstrap'; 5 | import { bindActionCreators } from 'redux'; 6 | import { UserButton } from './UserButton'; 7 | import { PrintLayout } from './printLayout'; 8 | 9 | class ButtonsComponent extends React.Component { 10 | public render(): React.ReactNode { 11 | const { changePrintContent, theme, themes, changeData } = this.props; 12 | return ( 13 | 14 | 19 | 22 | 28 | changeData(event.target.value, 'theme') 29 | } 30 | > 31 | {Object.keys(themes) 32 | .sort() 33 | .map(key => ( 34 | 37 | ))} 38 | 39 | 40 |
41 | 42 | 48 | 49 | 50 |
51 |
52 | ); 53 | } 54 | } 55 | 56 | const mapStateToProps = state => { 57 | return { 58 | theme: state.theme, 59 | themes: state.themes 60 | }; 61 | }; 62 | 63 | const matchDispatchToProps = dispatch => 64 | bindActionCreators({ changePrintContent, changeData }, dispatch); 65 | 66 | export const Buttons = connect( 67 | mapStateToProps, 68 | matchDispatchToProps 69 | )(ButtonsComponent); 70 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/CharacterImage.tsx: -------------------------------------------------------------------------------- 1 | import { changeData } from '@emporium/actions'; 2 | import * as images from '@emporium/images'; 3 | import React from 'react'; 4 | import { connect } from 'react-redux'; 5 | import { Button, Input, Modal, ModalBody, ModalFooter, ModalHeader, Row } from 'reactstrap'; 6 | import { bindActionCreators } from 'redux'; 7 | 8 | class CharacterImageComponent extends React.Component { 9 | public state = { modal: false, text: this.props.description.image }; 10 | public img: any = null; 11 | 12 | public handleBlur = event => { 13 | const { changeData, description } = this.props; 14 | const obj = { ...description }; 15 | obj.image = this.state.text; 16 | changeData(obj, 'description'); 17 | event.preventDefault(); 18 | }; 19 | 20 | public render() { 21 | const { description, theme } = this.props; 22 | const { modal, text } = this.state; 23 | return ( 24 |
25 | 26 |
27 | CHARACTER IMAGE 28 |
29 | 36 |
37 |
38 | 39 | not found (this.img = img)} 44 | onError={() => (this.img.src = images.user)} 45 | /> 46 | 47 | this.setState({ modal: false })} 51 | > 52 | this.setState({ modal: false })}> 53 | Edit Character Image 54 | 55 | 56 |
57 | CHARACTER IMAGE URL: 58 | 63 | this.setState({ text: event.target.value }) 64 | } 65 | /> 66 |
67 |
68 | 69 | 72 | 73 |
74 |
75 | ); 76 | } 77 | } 78 | 79 | const mapStateToProps = state => { 80 | return { 81 | description: state.description, 82 | theme: state.theme 83 | }; 84 | }; 85 | 86 | const matchDispatchToProps = dispatch => 87 | bindActionCreators({ changeData }, dispatch); 88 | 89 | export const CharacterImage = connect( 90 | mapStateToProps, 91 | matchDispatchToProps 92 | )(CharacterImageComponent); 93 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/CustomData/CustomData.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Tab, TabList, TabPanel, Tabs } from 'react-tabs'; 3 | import { ErrorBoundary } from '../ErrorBoundary'; 4 | import { CustomArchetypes } from './CustomArchetypes'; 5 | import { CustomArchetypeTalents } from './CustomArchetypeTalents'; 6 | import { CustomCareers } from './CustomCareers'; 7 | import { CustomEquipment } from './CustomEquipment'; 8 | import { CustomMotivations } from './CustomMotivations'; 9 | import { CustomSettings } from './CustomSettings'; 10 | import { CustomSkills } from './CustomSkills'; 11 | import { CustomTalents } from './CustomTalents'; 12 | import { CustomVehicles } from './CustomVehicles'; 13 | 14 | export const CustomData = () => { 15 | return ( 16 |
17 | 18 | 19 | Archetypes 20 | Archetype Talents 21 | Armor 22 | Careers 23 | Gear 24 | Motivations 25 | Settings 26 | Skills 27 | Talents 28 | Weapons 29 | Vehicles 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 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 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 |
88 | ); 89 | }; 90 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/CustomData/CustomSettings.tsx: -------------------------------------------------------------------------------- 1 | import { DeleteButton } from '@emporium/ui'; 2 | import React from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { Button, Col, Row, Table } from 'reactstrap'; 5 | import { bindActionCreators } from 'redux'; 6 | import { Fragment } from './Fragments'; 7 | 8 | class CustomSettingsComponent extends React.Component { 9 | public state: any = {}; 10 | 11 | public initState(): void {} 12 | 13 | public UNSAFE_componentWillMount = () => this.initState(); 14 | 15 | public handleSubmit = event => { 16 | this.initState(); 17 | event.preventDefault(); 18 | }; 19 | 20 | public handleDelete = event => { 21 | event.preventDefault(); 22 | }; 23 | 24 | public render() { 25 | const { customSettings } = this.props; 26 | const { name } = this.state; 27 | return ( 28 |
29 | 33 | this.setState({ name: event.target.value }) 34 | } 35 | /> 36 | 37 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 49 | 50 | 51 | {Object.keys(customSettings).map(key => ( 52 | 53 | 54 | 60 | 61 | ))} 62 | 63 |
CUSTOM SETTINGS 48 |
{customSettings[key]} 55 | 59 |
64 | 65 |
66 |
67 | ); 68 | } 69 | } 70 | 71 | const mapStateToProps = state => { 72 | return { 73 | customSettings: state.customSettings 74 | }; 75 | }; 76 | 77 | const matchDispatchToProps = dispatch => bindActionCreators({}, dispatch); 78 | 79 | export const CustomSettings = connect( 80 | mapStateToProps, 81 | matchDispatchToProps 82 | )(CustomSettingsComponent); 83 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/CustomData/index.ts: -------------------------------------------------------------------------------- 1 | export {CustomData} from './CustomData'; 2 | export {CustomSettings} from './CustomSettings'; 3 | export {CustomArchetypes} from './CustomArchetypes'; 4 | export {CustomArchetypeTalents} from './CustomArchetypeTalents'; 5 | export {CustomCareers} from './CustomCareers'; 6 | export {CustomEquipment} from './CustomEquipment'; 7 | export {CustomMotivations} from './CustomMotivations'; 8 | export {CustomSkills} from './CustomSkills'; 9 | export {CustomTalents} from './CustomTalents'; 10 | export {CustomVehicles} from './CustomVehicles'; 11 | export {Fragment} from './Fragments'; 12 | export {SettingBuilder} from './SettingBuilder'; 13 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/DataPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Col, Container, Row } from 'reactstrap'; 3 | import { ImportExport } from './ImportExport'; 4 | 5 | export const DataPage = () => { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | ); 15 | }; 16 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Button, Col, Row } from 'reactstrap'; 4 | 5 | class ErrorBoundaryComponent extends React.Component { 6 | public state = { 7 | hasError: false, 8 | error: null, 9 | info: null 10 | }; 11 | 12 | public componentDidCatch(error, info) { 13 | this.setState({ 14 | hasError: true, 15 | error: error, 16 | info: info 17 | }); 18 | } 19 | 20 | public buildMessage = () => { 21 | const text = `Component: ${this.props.component}%0D%0A User: ${ 22 | this.props.user 23 | }%0D%0A Character: ${ 24 | this.props.character 25 | }%0D%0A Error: ${this.state.error.toString()}%0D%0A`; 26 | const error = this.state.info.componentStack 27 | .split('\n') 28 | .filter(Boolean) 29 | .map(line => `${line.replace('\n', '').trim()}%0D%0A`) 30 | .join(''); 31 | return text + error; 32 | }; 33 | 34 | public render() { 35 | if (this.state.hasError) { 36 | return ( 37 |
38 | 39 | 40 | Oops!!! Something went wrong 41 | 42 | 43 | 44 | 45 | 46 | Click button to send an error report to the man. 47 | 48 | 49 | 50 | 60 |
61 | ); 62 | } else { 63 | return this.props.children; 64 | } 65 | } 66 | } 67 | 68 | const mapStateToProps = state => { 69 | return { 70 | user: state.user, 71 | character: state.character 72 | }; 73 | }; 74 | 75 | export const ErrorBoundary = connect(mapStateToProps)(ErrorBoundaryComponent); 76 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/Loading.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Progress } from 'reactstrap'; 3 | 4 | export class Loading extends React.Component { 5 | public state = { time: 0 }; 6 | public timer: any = null; 7 | 8 | public componentWillUnmount() { 9 | clearInterval(this.timer); 10 | this.setState({ time: 100 }); 11 | } 12 | 13 | public componentDidMount() { 14 | this.timer = setInterval( 15 | () => this.setState({ time: this.state.time + 4 }), 16 | 100 17 | ); 18 | } 19 | 20 | public render() { 21 | return ( 22 |
23 |

LOADING

24 | 29 |
30 | Comments? Questions? Concerns?
31 | Join our Discord! 32 |
33 |
34 | ); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/MainPage.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Col, Row } from 'reactstrap'; 3 | import { Buttons } from './Buttons'; 4 | import { About } from './About'; 5 | import { Attributes } from './Attributes'; 6 | import { CharacterDescription } from './CharacterDescription'; 7 | import { CharacterImage } from './CharacterImage'; 8 | import { CharacterSelect } from './CharacterSelect'; 9 | import { Critical } from './critical/critical'; 10 | import { Equipment } from './Equipment'; 11 | import { ErrorBoundary } from './ErrorBoundary'; 12 | import { Motivation } from './Motivation'; 13 | import { Notes } from './Notes'; 14 | import { ShowCharacteristics } from './ShowCharacteristics'; 15 | import { Skill } from './Skill'; 16 | import { TalentList } from './TalentList'; 17 | import { Talents } from './Talents'; 18 | import { XPBoxes } from './XPBoxes'; 19 | 20 | export const MainPage = (): any => { 21 | return ( 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 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 | 77 | 78 | 79 | 80 |
81 | ); 82 | }; 83 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/ModalDeleteConfirm.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Button, ButtonGroup, Modal, ModalBody, ModalFooter, ModalHeader } from 'reactstrap'; 4 | 5 | class ModalDeleteConfirmComponent extends React.Component { 6 | public render() { 7 | const { 8 | deleteModal, 9 | confirmedDelete, 10 | handleClose, 11 | type, 12 | theme 13 | } = this.props; 14 | return ( 15 | 20 | BALETEED WARNING 21 | 22 | Are you super serious? This cannot be undone! 23 | 24 | 25 | 26 | 27 | 32 | 33 | 34 | 35 | ); 36 | } 37 | } 38 | 39 | const mapStateToProps = state => { 40 | return { 41 | theme: state.theme 42 | }; 43 | }; 44 | 45 | export const ModalDeleteConfirm = connect(mapStateToProps)( 46 | ModalDeleteConfirmComponent 47 | ); 48 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/Motivation.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Row } from 'reactstrap'; 4 | import { MotivationBlock } from './MotivationBlock'; 5 | 6 | class MotivationComponent extends React.Component { 7 | public render() { 8 | const { theme } = this.props; 9 | return ( 10 |
11 | 12 |
MOTIVATIONS
13 |
14 |
15 | 16 | {['Strength', 'Flaw', 'Desire', 'Fear'].map(type => ( 17 | 18 | ))} 19 | 20 |
21 | ); 22 | } 23 | } 24 | 25 | const mapStateToProps = state => { 26 | return { 27 | theme: state.theme 28 | }; 29 | }; 30 | 31 | export const Motivation = connect(mapStateToProps)(MotivationComponent); 32 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/Notes.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Input, Row } from 'reactstrap'; 4 | import { bindActionCreators } from 'redux'; 5 | import { changeData } from '@emporium/actions'; 6 | 7 | class NotesComponent extends React.Component { 8 | public constructor(props) { 9 | super(props); 10 | this.state = { 11 | notes: props.description.notes 12 | }; 13 | } 14 | 15 | public render() { 16 | const { notes } = this.state; 17 | const { changeData, description, theme } = this.props; 18 | return ( 19 |
20 | 21 |
NOTES
22 |
23 |
24 | 25 | 27 | changeData({ ...description, notes }, 'description') 28 | } 29 | onChange={event => 30 | this.setState({ notes: event.target.value }) 31 | } 32 | type="textarea" 33 | className="w-100" 34 | rows="31" 35 | maxLength="5000" 36 | value={notes} 37 | /> 38 | 39 |
40 | ); 41 | } 42 | } 43 | 44 | const mapStateToProps = state => { 45 | return { 46 | description: state.description, 47 | theme: state.theme 48 | }; 49 | }; 50 | 51 | const matchDispatchToProps = dispatch => 52 | bindActionCreators({ changeData }, dispatch); 53 | 54 | export const Notes = connect( 55 | mapStateToProps, 56 | matchDispatchToProps 57 | )(NotesComponent); 58 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/ShowCharacteristics.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Button, Row } from 'reactstrap'; 4 | import { chars } from '@emporium/data'; 5 | import * as images from '@emporium/images'; 6 | import { characteristics } from '@emporium/selectors'; 7 | import { Characteristics } from './Characteristics'; 8 | 9 | class ShowCharacteristicsComponent extends React.Component { 10 | public state = { modal: false }; 11 | 12 | public render() { 13 | const { characteristics, theme } = this.props; 14 | return ( 15 |
16 | 17 |
18 | CHARACTERISTICS 19 |
20 | 27 |
28 |
29 | 30 | {chars.map(stat => ( 31 |
32 | 37 | 40 | {characteristics[stat]} 41 | 42 |
43 | ))} 44 |
45 | this.setState({ modal: false })} 48 | /> 49 |
50 | ); 51 | } 52 | } 53 | 54 | const mapStateToProps = state => { 55 | return { 56 | characteristics: characteristics(state), 57 | theme: state.theme 58 | }; 59 | }; 60 | 61 | export const ShowCharacteristics = connect(mapStateToProps)( 62 | ShowCharacteristicsComponent 63 | ); 64 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/Skill.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Col, Row } from 'reactstrap'; 4 | import { SkillBlock } from './SkillBlock'; 5 | 6 | class SkillComponent extends React.Component { 7 | public render() { 8 | const { theme } = this.props; 9 | return ( 10 |
11 | 12 |
SKILLS
13 |
14 |
15 | 16 | 17 | {['General', 'Magic'].map(type => ( 18 | 19 | ))} 20 | 21 | 22 | {['Combat', 'Social', 'Knowledge'].map(type => ( 23 | 24 | ))} 25 | 26 | 27 |
28 | ); 29 | } 30 | } 31 | 32 | const mapStateToProps = state => { 33 | return { 34 | theme: state.theme 35 | }; 36 | }; 37 | 38 | export const Skill = connect(mapStateToProps)(SkillComponent); 39 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/TalentBlock.tsx: -------------------------------------------------------------------------------- 1 | import { talentCount } from '@emporium/selectors'; 2 | import React from 'react'; 3 | import DynamicFont from 'react-dynamic-font'; 4 | import { connect } from 'react-redux'; 5 | import { Card, CardBody, CardHeader } from 'reactstrap'; 6 | import { Description } from './Description'; 7 | import { TalentSelection } from './TalentSelection'; 8 | 9 | class TalentBlockComponent extends React.Component { 10 | public state = { modal: false }; 11 | 12 | public activation = () => { 13 | const { talents, talentKey } = this.props; 14 | if (talentKey === '') { 15 | return 'var(--light)'; 16 | } 17 | 18 | if (!talents[talentKey]) { 19 | return 'var(--red)'; 20 | } 21 | 22 | if (talents[talentKey].activation) { 23 | return 'var(--orange)'; 24 | } else { 25 | return 'var(--lightblue)'; 26 | } 27 | }; 28 | 29 | public render() { 30 | const { talents, talentKey, row, tier } = this.props; 31 | const talent = talents[talentKey]; 32 | const color = this.activation(); 33 | return ( 34 |
35 | this.setState({ modal: false })} 38 | row={row} 39 | tier={tier} 40 | talentKey={talentKey} 41 | /> 42 | this.setState({ modal: true })} 44 | className="m-1 talentCard" 45 | > 46 | 50 | 59 | 60 | 61 | 74 | 75 | 76 |
77 | ); 78 | } 79 | } 80 | 81 | const mapStateToProps = state => { 82 | return { 83 | masterTalents: state.masterTalents, 84 | talents: state.talents, 85 | talentCount: talentCount(state) 86 | }; 87 | }; 88 | 89 | export const TalentBlock = connect(mapStateToProps)(TalentBlockComponent); 90 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/TalentDedication.tsx: -------------------------------------------------------------------------------- 1 | import { changeData } from '@emporium/actions'; 2 | import { characteristics } from '@emporium/selectors'; 3 | import React from 'react'; 4 | import { connect } from 'react-redux'; 5 | import { Input, Row } from 'reactstrap'; 6 | import { bindActionCreators } from 'redux'; 7 | 8 | class TalentDedicationComponent extends React.Component { 9 | public state = { options: [] }; 10 | 11 | public UNSAFE_componentWillMount() { 12 | const { characteristics, talentModifiers, row } = this.props; 13 | const options = []; 14 | Object.keys(characteristics).forEach(characteristic => { 15 | if ( 16 | 5 > characteristics[characteristic] && 17 | !Object.values(talentModifiers.Dedication).includes( 18 | characteristic 19 | ) 20 | ) { 21 | options.push(characteristic); 22 | } 23 | }); 24 | talentModifiers.Dedication[row] && 25 | options.push(talentModifiers.Dedication[row]); 26 | options.sort(); 27 | this.setState({ options: options }); 28 | } 29 | 30 | public componentWillUnmount() { 31 | this.props.handleDedicationChange(''); 32 | } 33 | 34 | public handleChange = event => { 35 | this.props.handleDedicationChange(event.target.value); 36 | event.preventDefault(); 37 | }; 38 | 39 | public render() { 40 | const { options } = this.state; 41 | const { selection } = this.props; 42 | return ( 43 | 44 | Select a characteristic to increase: 45 | 50 | 55 | ))} 56 | 57 | 58 | ); 59 | } 60 | } 61 | 62 | const mapStateToProps = state => { 63 | return { 64 | characteristics: characteristics(state), 65 | talentModifiers: state.talentModifiers 66 | }; 67 | }; 68 | 69 | const matchDispatchToProps = dispatch => 70 | bindActionCreators({ changeData }, dispatch); 71 | 72 | export const TalentDedication = connect( 73 | mapStateToProps, 74 | matchDispatchToProps 75 | )(TalentDedicationComponent); 76 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/Talents.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Row } from 'reactstrap'; 4 | import { talentCount } from '@emporium/selectors'; 5 | import { TalentBlock } from './TalentBlock'; 6 | 7 | class TalentsComponent extends React.Component { 8 | public render() { 9 | const { masterTalents, theme } = this.props; 10 | return ( 11 |
12 | 13 |
TALENTS
14 |
15 |
16 | {Object.keys(masterTalents).map(row => ( 17 | 18 | {Object.keys(masterTalents[row]).map(tier => ( 19 | 25 | ))} 26 | 27 | ))} 28 |
29 | ); 30 | } 31 | } 32 | 33 | const mapStateToProps = state => { 34 | return { 35 | masterTalents: state.masterTalents, 36 | talents: state.talents, 37 | talentCount: talentCount(state), 38 | theme: state.theme 39 | }; 40 | }; 41 | 42 | export const Talents = connect(mapStateToProps)(TalentsComponent); 43 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/User.tsx: -------------------------------------------------------------------------------- 1 | import { firebase } from '@firebase/app'; 2 | import '@firebase/auth'; 3 | import * as firebaseui from "firebaseui"; 4 | import React, { Component } from 'react'; 5 | import StyledFirebaseAuth from 'react-firebaseui/StyledFirebaseAuth'; 6 | import { Container, Row } from 'reactstrap'; 7 | import * as images from '@emporium/images'; 8 | import { About } from './About'; 9 | 10 | export class User extends Component { 11 | public uiConfig: any = { 12 | signInFlow: 'popup', 13 | autoUpgradeAnonymousUsers: true, 14 | callbacks: { 15 | signInFailure: console.error, 16 | onAuthStateChanged: console.log 17 | }, 18 | signInOptions: [ 19 | firebase.auth.GoogleAuthProvider.PROVIDER_ID, 20 | { 21 | provider: firebase.auth.PhoneAuthProvider.PROVIDER_ID, 22 | // Invisible reCAPTCHA with image challenge and bottom left badge. 23 | recaptchaParameters: { 24 | type: 'image', 25 | size: 'invisible', 26 | badge: 'bottomleft' 27 | } 28 | }, 29 | firebase.auth.EmailAuthProvider.PROVIDER_ID, 30 | firebaseui.auth.AnonymousAuthProvider.PROVIDER_ID 31 | ] 32 | }; 33 | 34 | public render() { 35 | return ( 36 |
37 | 38 |
39 | 40 |

Genesys Emporium

41 |
42 | 43 |

Genesys Character Creator

44 |
45 | 46 | 51 | 52 | 53 | 57 | 58 | 59 | 60 | 61 | 62 |
63 | ); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/UserButton.tsx: -------------------------------------------------------------------------------- 1 | import { changeUser } from '@emporium/actions'; 2 | import firebase from '@firebase/app'; 3 | import '@firebase/auth'; 4 | import React from 'react'; 5 | import { connect } from 'react-redux'; 6 | import { DropdownItem, DropdownMenu, DropdownToggle, UncontrolledButtonDropdown } from 'reactstrap'; 7 | import { bindActionCreators } from 'redux'; 8 | 9 | class UserButtonComponent extends React.Component { 10 | public getName = () => { 11 | const user = firebase.auth().currentUser; 12 | let name = 'Rando Calrissian'; 13 | if (user) { 14 | if (user.email) { 15 | name = user.email; 16 | } else if (user.phoneNumber) { 17 | name = user.phoneNumber; 18 | } 19 | } 20 | return name; 21 | }; 22 | 23 | public handleClick = async () => { 24 | firebase 25 | .auth() 26 | .signOut() 27 | .then(() => this.props.changeUser(null)) 28 | .catch(console.error); 29 | }; 30 | 31 | public render() { 32 | return ( 33 | 34 | 35 | {this.getName()} 36 | 37 | 38 | 39 | Sign Out 40 | 41 | 42 | 43 | ); 44 | } 45 | } 46 | 47 | const mapStateToProps = state => { 48 | return { 49 | user: state.user 50 | }; 51 | }; 52 | 53 | const matchDispatchToProps = dispatch => 54 | bindActionCreators({ changeUser }, dispatch); 55 | 56 | export const UserButton = connect( 57 | mapStateToProps, 58 | matchDispatchToProps 59 | )(UserButtonComponent); 60 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/XPBoxes.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Row } from 'reactstrap'; 4 | import { bindActionCreators } from 'redux'; 5 | import * as images from '@emporium/images'; 6 | import { changeData } from '@emporium/actions'; 7 | import { totalXP, usedXP } from '@emporium/selectors'; 8 | import { XPPopup } from './XPPopup'; 9 | 10 | class XPBoxesComponent extends React.Component { 11 | public state = { modal: false }; 12 | 13 | public render() { 14 | const { totalXP, usedXP, theme } = this.props; 15 | return ( 16 |
17 |
this.setState({ modal: true })} 20 | > 21 | 22 | {totalXP} 23 |
24 | 25 |
this.setState({ modal: true })} 28 | > 29 | 34 | 35 | 36 | {totalXP - usedXP} 37 | 38 |
39 | this.setState({ modal: false })} 42 | /> 43 |
44 | ); 45 | } 46 | } 47 | 48 | const mapStateToProps = state => { 49 | return { 50 | totalXP: totalXP(state), 51 | usedXP: usedXP(state), 52 | theme: state.theme 53 | }; 54 | }; 55 | 56 | const matchDispatchToProps = dispatch => 57 | bindActionCreators({ changeData }, dispatch); 58 | 59 | export const XPBoxes = connect( 60 | mapStateToProps, 61 | matchDispatchToProps 62 | )(XPBoxesComponent); 63 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/XPPopup.tsx: -------------------------------------------------------------------------------- 1 | import { changeData } from '@emporium/actions'; 2 | import React from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { Button, ButtonGroup, Modal, ModalBody, ModalHeader, Row } from 'reactstrap'; 5 | import { bindActionCreators } from 'redux'; 6 | 7 | class XPPopupComponent extends React.Component { 8 | public constructor(props) { 9 | super(props); 10 | this.state = { 11 | earnedXP: props.earnedXP 12 | }; 13 | } 14 | 15 | public handleChange = event => { 16 | let xp = event.target.value; 17 | if (xp > 9999) { 18 | return; 19 | } 20 | if (xp.includes('+')) { 21 | xp = +xp.replace(/\D+/g, '') + +this.state.earnedXP; 22 | } 23 | this.setState({ earnedXP: +xp }); 24 | event.preventDefault(); 25 | }; 26 | 27 | public handleSubmit = event => { 28 | const { earnedXP } = this.state; 29 | this.props.changeData(earnedXP, 'earnedXP'); 30 | this.props.handleClose(); 31 | event.preventDefault(); 32 | }; 33 | 34 | public render() { 35 | const { earnedXP } = this.state; 36 | const { handleClose, modal, theme } = this.props; 37 | return ( 38 | 43 | {`Earned XP: ${earnedXP}`} 46 | 47 | 48 | 0 ? earnedXP : ''} 51 | onChange={this.handleChange} 52 | /> 53 | 54 | 55 | 56 | 59 | 62 | 63 | 64 | 65 | 66 | 67 | ); 68 | } 69 | } 70 | 71 | const mapStateToProps = state => { 72 | return { 73 | earnedXP: state.earnedXP, 74 | theme: state.theme 75 | }; 76 | }; 77 | 78 | const matchDispatchToProps = dispatch => 79 | bindActionCreators({ changeData }, dispatch); 80 | 81 | export const XPPopup = connect( 82 | mapStateToProps, 83 | matchDispatchToProps 84 | )(XPPopupComponent); 85 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/critical/critical.scss: -------------------------------------------------------------------------------- 1 | .critical-container { 2 | table td:last-child { 3 | text-align: right; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/gear/gear.scss: -------------------------------------------------------------------------------- 1 | .gear-modal { 2 | max-width: 600px; 3 | 4 | .item-filter { 5 | width: 30%; 6 | display: inline-block; 7 | border-radius: 4px; 8 | padding: 7px 0 5px 11px; 9 | border: 1px solid rgb(206, 212, 218); 10 | margin: -15px 5px 5px; 11 | vertical-align: top; 12 | } 13 | 14 | .table-container { 15 | clear: right; 16 | } 17 | 18 | .rbt { 19 | position: relative; 20 | width: calc(70% - 10px); 21 | display: inline-block; 22 | margin-top: -15px; 23 | margin-bottom: 5px; 24 | 25 | .rbt-aux .rbt-close { 26 | margin-top: 3px; 27 | } 28 | } 29 | 30 | table { 31 | td { 32 | &:first-child { 33 | text-align: center; 34 | 35 | button { 36 | width: 27px; 37 | height: 27px; 38 | text-align: center; 39 | padding: 0; 40 | } 41 | } 42 | 43 | &:last-child { 44 | text-align: center; 45 | } 46 | } 47 | } 48 | 49 | .settings-restriction { 50 | margin-top: 4px; 51 | position: absolute; 52 | left: 16px; 53 | 54 | input { 55 | width: 20px; 56 | height: 20px; 57 | vertical-align: middle; 58 | } 59 | 60 | label { 61 | margin-right: 5px; 62 | font-size: 1.2em; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/index.ts: -------------------------------------------------------------------------------- 1 | export { About } from './About'; 2 | export { ArchetypeSkills } from './ArchetypeSkills'; 3 | export { ArchetypeStats } from './ArchetypeStats'; 4 | export { Archetype } from './Archetype'; 5 | export { Attributes } from './Attributes'; 6 | export { Career } from './Career'; 7 | export { CharacterDescription } from './CharacterDescription'; 8 | export { CharacterImage } from './CharacterImage'; 9 | export { Characteristics } from './Characteristics'; 10 | export { CharacterSelect } from './CharacterSelect'; 11 | export { Critical } from './critical/critical'; 12 | export { DataPage } from './DataPage'; 13 | export { Description } from './Description'; 14 | export { ErrorBoundary } from './ErrorBoundary'; 15 | export { Equipment } from './Equipment'; 16 | export { Gear } from './gear/gear'; 17 | export { ImportExport } from './ImportExport'; 18 | export { Loading } from './Loading'; 19 | export { MainPage } from './MainPage'; 20 | export { MotivationBlock } from './MotivationBlock'; 21 | export { Motivation } from './Motivation'; 22 | export { Notes } from './Notes'; 23 | export { ShowCharacteristics } from './ShowCharacteristics'; 24 | export { SkillBlock } from './SkillBlock'; 25 | export { SkillRow } from './SkillRow'; 26 | export { Skill } from './Skill'; 27 | export { TalentBlock } from './TalentBlock'; 28 | export { TalentDedication } from './TalentDedication'; 29 | export { TalentList } from './TalentList'; 30 | export { TalentSelection } from './TalentSelection'; 31 | export { Talents } from './Talents'; 32 | export { User } from './User'; 33 | export { UserButton } from './UserButton'; 34 | export { XPBoxes } from './XPBoxes'; 35 | export { XPPopup } from './XPPopup'; 36 | export { VehicleSelect } from './VehicleSelect'; 37 | export { ModalDeleteConfirm } from './ModalDeleteConfirm'; 38 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/Character.tsx: -------------------------------------------------------------------------------- 1 | import * as images from '@emporium/images'; 2 | import React from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { Col, Row } from 'reactstrap'; 5 | 6 | class Component extends React.Component { 7 | public render(): React.ReactNode { 8 | const { 9 | archetype, 10 | archetypes, 11 | careers, 12 | career, 13 | characterList, 14 | character, 15 | description, 16 | setting, 17 | theme 18 | } = this.props; 19 | return ( 20 |
21 | 22 | 23 | 24 |
25 | CHARACTER 26 |
27 |
28 |
29 | 30 | 31 | CHARACTER: 32 | {characterList[character]} 33 | 34 | 35 |
36 | 37 | 38 | ARCHETYPE: 39 | {archetype === null 40 | ? '' 41 | : archetypes[archetype] 42 | ? archetypes[archetype].name 43 | : 'Missing Archetype Data'} 44 | 45 | 46 | CAREER: 47 | {career === null 48 | ? '' 49 | : careers[career] 50 | ? careers[career].name 51 | : 'Missing Career Data'} 52 | 53 | 54 |
55 | 56 | 57 | SETTING: 58 | {setting.join(', ')} 59 | 60 | 61 | PLAYER: 62 | {description.playerName} 63 | 64 | 65 | 66 | 67 | 72 | 73 |
74 |
75 | ); 76 | } 77 | } 78 | 79 | const mapStateToProps = state => { 80 | return { 81 | archetype: state.archetype, 82 | archetypes: state.archetypes, 83 | career: state.career, 84 | careers: state.careers, 85 | description: state.description, 86 | user: state.user, 87 | characterList: state.characterList, 88 | character: state.character, 89 | setting: state.setting, 90 | theme: state.theme 91 | }; 92 | }; 93 | 94 | export const Character = connect(mapStateToProps)(Component); 95 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/CharacterDescription.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Col, Row } from 'reactstrap'; 4 | 5 | class Component extends React.Component { 6 | public render(): React.ReactNode { 7 | const { description, theme } = this.props; 8 | return ( 9 |
10 | 11 |
12 | CHARACTER DESCRIPTION 13 |
14 |
15 |
16 | {['gender', 'age', 'height', 'build', 'hair', 'eyes'].map( 17 | aspect => ( 18 | 19 | 20 | {aspect.toLocaleUpperCase()}: 21 | 22 | {description[aspect]} 23 |
24 |
25 | ) 26 | )} 27 | 28 | 29 | NOTABLE FEATURES: 30 | 31 | 32 | {description.features ? description.features : ''} 33 | 34 | 35 |
36 | ); 37 | } 38 | } 39 | 40 | const mapStateToProps = state => { 41 | return { 42 | description: state.description, 43 | theme: state.theme 44 | }; 45 | }; 46 | 47 | export const CharacterDescription = connect(mapStateToProps)(Component); 48 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/CharacterImage.tsx: -------------------------------------------------------------------------------- 1 | import * as images from '@emporium/images'; 2 | import React from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { Row } from 'reactstrap'; 5 | 6 | class Component extends React.Component { 7 | public img: { src: string } = null; 8 | 9 | public render(): React.ReactNode { 10 | const { description, theme } = this.props; 11 | return ( 12 |
13 | 14 |
15 | CHARACTER IMAGE 16 |
17 |
18 |
19 | not found (this.img = img)} 24 | onError={() => (this.img.src = images.user)} 25 | /> 26 |
27 | ); 28 | } 29 | } 30 | 31 | const mapStateToProps = state => { 32 | return { 33 | description: state.description, 34 | theme: state.theme 35 | }; 36 | }; 37 | 38 | export const CharacterImage = connect(mapStateToProps)(Component); 39 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/Characteristics.tsx: -------------------------------------------------------------------------------- 1 | import { chars } from '@emporium/data-lists'; 2 | import * as images from '@emporium/images'; 3 | import { characteristics } from '@emporium/selectors'; 4 | import React from 'react'; 5 | import { connect } from 'react-redux'; 6 | import { Row } from 'reactstrap'; 7 | 8 | class Component extends React.Component { 9 | public render(): React.ReactNode { 10 | const { characteristics, theme } = this.props; 11 | return ( 12 |
13 | 14 |
15 | CHARACTERISTICS 16 |
17 |
18 |
19 | 20 | {chars.map(stat => ( 21 |
25 | 30 | 33 | {characteristics[stat]} 34 | 35 |
36 | ))} 37 |
38 |
39 | ); 40 | } 41 | } 42 | 43 | const mapStateToProps = state => { 44 | return { 45 | characteristics: characteristics(state), 46 | theme: state.theme 47 | }; 48 | }; 49 | 50 | export const Characteristics = connect(mapStateToProps)(Component); 51 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/Critical.tsx: -------------------------------------------------------------------------------- 1 | import { criticalText } from '@emporium/selectors'; 2 | import React from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { Row, Table } from 'reactstrap'; 5 | import { Description } from '../Description'; 6 | 7 | class Component extends React.Component { 8 | public render(): React.ReactNode { 9 | const { critical, theme } = this.props; 10 | return ( 11 |
12 | 13 |
14 | CRITICAL INJURES 15 |
16 |
17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | {critical.map((critRoll, index) => ( 27 | 28 | 31 | 36 | 37 | ))} 38 | 39 |
CRITICALDESCRIPTION
29 | {critRoll}: 30 | 32 | 35 |
40 |
41 | ); 42 | } 43 | } 44 | 45 | const mapStateToProps = state => { 46 | return { 47 | critical: state.critical, 48 | theme: state.theme 49 | }; 50 | }; 51 | 52 | export const Critical = connect(mapStateToProps)(Component); 53 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/Motivations.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Row } from 'reactstrap'; 4 | 5 | class Component extends React.Component { 6 | public render(): React.ReactNode { 7 | const { masterMotivations, theme } = this.props; 8 | return ( 9 |
10 | 11 |
MOTIVATIONS
12 |
13 |
14 | {['Strength', 'Flaw', 'Desire', 'Fear'].map(type => ( 15 | 16 | {type.toUpperCase()} 17 | {masterMotivations[type] && ( 18 |

19 | {masterMotivations[type].key}:{' '} 20 | {masterMotivations[type].description} 21 |

22 | )} 23 |
24 | ))} 25 |
26 | ); 27 | } 28 | } 29 | 30 | const mapStateToProps = state => { 31 | return { 32 | masterMotivations: state.masterMotivations, 33 | motivations: state.motivations, 34 | theme: state.theme 35 | }; 36 | }; 37 | 38 | export const Motivations = connect(mapStateToProps)(Component); 39 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/Notes.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Row } from 'reactstrap'; 4 | import { Description } from '../Description'; 5 | 6 | class Component extends React.Component { 7 | public render(): React.ReactNode { 8 | const { description, theme } = this.props; 9 | return ( 10 |
11 | 12 |
NOTES
13 |
14 |
15 | 16 | 19 | 20 |
21 | ); 22 | } 23 | } 24 | 25 | const mapStateToProps = state => { 26 | return { 27 | description: state.description, 28 | theme: state.theme 29 | }; 30 | }; 31 | 32 | export const Notes = connect(mapStateToProps)(Component); 33 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/PrintLayout.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Col, Container, Row } from 'reactstrap'; 3 | import { TalentList } from '../TalentList'; 4 | import { Attributes } from './Attributes'; 5 | import { Character } from './Character'; 6 | import { CharacterDescription } from './CharacterDescription'; 7 | import { CharacterImage } from './CharacterImage'; 8 | import { Characteristics } from './Characteristics'; 9 | import { Critical } from './Critical'; 10 | import { Equipment } from './Equipment'; 11 | import { Motivations } from './Motivations'; 12 | import { Notes } from './Notes'; 13 | import { Skill } from './Skill'; 14 | import { TalentPyramid } from './TalentPyramid'; 15 | import { XP } from './XP'; 16 | 17 | export const PrintLayout = (): any => { 18 | return ( 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | ); 41 | }; 42 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/Skill.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Col, Row } from 'reactstrap'; 4 | import { SkillBlock } from './SkillBlock'; 5 | 6 | class Component extends React.Component { 7 | public render(): React.ReactNode { 8 | const { theme } = this.props; 9 | return ( 10 |
11 | 12 |
SKILLS
13 |
14 |
15 | 16 | 17 | {['General', 'Magic'].map((type, index) => ( 18 | 19 | ))} 20 | 21 | 22 | {['Combat', 'Social', 'Knowledge'].map( 23 | (type, index) => ( 24 | 29 | ) 30 | )} 31 | 32 | 33 |
34 | ); 35 | } 36 | } 37 | 38 | const mapStateToProps = state => { 39 | return { 40 | theme: state.theme 41 | }; 42 | }; 43 | 44 | export const Skill = connect(mapStateToProps)(Component); 45 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/SkillBlock.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { Row, Table } from 'reactstrap'; 4 | import { SkillRow } from './SkillRow'; 5 | 6 | class Component extends React.Component { 7 | public render(): React.ReactNode { 8 | const { type, skills, index } = this.props; 9 | return ( 10 |
11 | 12 | {type} 13 | 14 | 15 | {0 >= index && ( 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | )} 25 | 26 | {Object.keys(skills) 27 | .sort() 28 | .map( 29 | skillKey => 30 | skills[skillKey].type === type && ( 31 | 35 | ) 36 | )} 37 | 38 |
SkillCareerRankDice Pool
39 |
40 | ); 41 | } 42 | } 43 | 44 | const mapStateToProps = state => { 45 | return { 46 | skills: state.skills, 47 | masterSkills: state.masterSkills 48 | }; 49 | }; 50 | 51 | export const SkillBlock = connect(mapStateToProps)(Component); 52 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/SkillRow.tsx: -------------------------------------------------------------------------------- 1 | import { archetypeSkillRank, careerCheck, skillDice, skillRanks } from '@emporium/selectors'; 2 | import React from 'react'; 3 | import { connect } from 'react-redux'; 4 | import { Description } from '../Description'; 5 | 6 | class Component extends React.Component { 7 | public shortCharacteristics = (): string => { 8 | const { skillKey, skills } = this.props; 9 | switch (skills[skillKey].characteristic) { 10 | case 'Agility': 11 | return 'AG'; 12 | case 'Brawn': 13 | return 'BR'; 14 | case 'Intellect': 15 | return 'INT'; 16 | case 'Cunning': 17 | return 'CUN'; 18 | case 'Willpower': 19 | return 'WILL'; 20 | case 'Presence': 21 | return 'PR'; 22 | default: 23 | return ''; 24 | } 25 | }; 26 | 27 | public render(): React.ReactNode { 28 | const { 29 | masterSkills, 30 | skills, 31 | skillKey, 32 | careerSkillsRank, 33 | skillDice, 34 | skillRanks, 35 | archetypeSkillRank, 36 | careerCheck 37 | } = this.props; 38 | const skill = skills[skillKey]; 39 | const ranks = [0, 1, 2, 3, 4, 5]; 40 | if (careerSkillsRank.includes(skillKey)) { 41 | ranks.shift(); 42 | } 43 | if (archetypeSkillRank[skillKey]) { 44 | for (let i = 0; archetypeSkillRank[skillKey].rank > i; i++) { 45 | ranks.shift(); 46 | } 47 | } 48 | return ( 49 | 58 | 59 | {`${skill.name} (${this.shortCharacteristics()})`} 60 | 61 | 62 | {careerCheck[skillKey] ? '✓' : ''} 63 | 64 | 65 | {skillRanks[skillKey] ? skillRanks[skillKey] : ''} 66 | 67 | 68 | 69 | 70 | 71 | ); 72 | } 73 | } 74 | 75 | const mapStateToProps = state => { 76 | return { 77 | masterSkills: state.masterSkills, 78 | skills: state.skills, 79 | careerSkillsRank: state.careerSkillsRank, 80 | career: state.career, 81 | careers: state.careers, 82 | skillDice: skillDice(state), 83 | skillRanks: skillRanks(state), 84 | archetypeSkillRank: archetypeSkillRank(state), 85 | careerCheck: careerCheck(state) 86 | }; 87 | }; 88 | 89 | export const SkillRow = connect(mapStateToProps)(Component); 90 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/TalentPyramid.tsx: -------------------------------------------------------------------------------- 1 | import { talentCount } from '@emporium/selectors'; 2 | import React from 'react'; 3 | import DynamicFont from 'react-dynamic-font'; 4 | import { connect } from 'react-redux'; 5 | import { Card, CardBody, Row } from 'reactstrap'; 6 | 7 | class Component extends React.Component { 8 | public activation = (talentKey): string => { 9 | const { talents } = this.props; 10 | if (talentKey === '') { 11 | return 'var(--light)'; 12 | } 13 | 14 | if (!talents[talentKey]) { 15 | return 'var(--red)'; 16 | } 17 | 18 | if (talents[talentKey].activation) { 19 | return 'var(--orange)'; 20 | } else { 21 | return 'var(--lightblue)'; 22 | } 23 | }; 24 | 25 | public render(): React.ReactNode { 26 | const { masterTalents, talents, theme } = this.props; 27 | return ( 28 |
29 | 30 |
TALENTS
31 |
32 |
33 | {Object.keys(masterTalents).map(row => ( 34 | 35 | {Object.keys(masterTalents[row]).map(tier => { 36 | const talent = talents[masterTalents[row][tier]]; 37 | return ( 38 | 42 | 50 | 59 | 60 | 61 | ); 62 | })} 63 | 64 | ))} 65 |
66 | ); 67 | } 68 | } 69 | 70 | const mapStateToProps = state => { 71 | return { 72 | masterTalents: state.masterTalents, 73 | talents: state.talents, 74 | talentCount: talentCount(state), 75 | theme: state.theme 76 | }; 77 | }; 78 | 79 | export const TalentPyramid = connect(mapStateToProps)(Component); 80 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/XP.tsx: -------------------------------------------------------------------------------- 1 | import * as images from '@emporium/images'; 2 | import { totalXP, usedXP } from '@emporium/selectors'; 3 | import React from 'react'; 4 | import { connect } from 'react-redux'; 5 | import { Row } from 'reactstrap'; 6 | 7 | class Component extends React.Component { 8 | public render(): React.ReactNode { 9 | const { totalXP, usedXP, theme } = this.props; 10 | return ( 11 |
12 | 13 |
14 | 19 | 20 | {totalXP} 21 | 22 |
23 | 24 |
25 | 30 | 31 | {totalXP - usedXP} 32 | 33 |
34 |
35 |
36 | ); 37 | } 38 | } 39 | 40 | const mapStateToProps = state => { 41 | return { 42 | totalXP: totalXP(state), 43 | usedXP: usedXP(state), 44 | theme: state.theme 45 | }; 46 | }; 47 | 48 | export const XP = connect(mapStateToProps)(Component); 49 | -------------------------------------------------------------------------------- /packages/emporium/src/app/components/printLayout/index.ts: -------------------------------------------------------------------------------- 1 | export {Attributes} from './Attributes'; 2 | export {CharacterDescription} from './CharacterDescription'; 3 | export {CharacterImage} from './CharacterImage'; 4 | export {Characteristics} from './Characteristics'; 5 | export {Character} from './Character'; 6 | export {Critical} from './Critical'; 7 | export {Equipment} from './Equipment'; 8 | export {Motivations} from './Motivations'; 9 | export {Notes} from './Notes'; 10 | export {SkillBlock} from './SkillBlock'; 11 | export {SkillRow} from './SkillRow'; 12 | export {Skill} from './Skill'; 13 | export {TalentPyramid} from './TalentPyramid'; 14 | export {XP} from './XP'; 15 | 16 | export {PrintLayout} from './PrintLayout'; -------------------------------------------------------------------------------- /packages/emporium/src/app/firestoreDB.js: -------------------------------------------------------------------------------- 1 | import firebase from '@firebase/app'; 2 | import '@firebase/firestore'; 3 | 4 | const config = { 5 | apiKey: process.env.NX_apiKey, 6 | authDomain: process.env.NX_authDomain, 7 | databaseURL: process.env.NX_databaseURL, 8 | projectId: process.env.NX_projectId, 9 | storageBucket: process.env.NX_storageBucket, 10 | messagingSenderId: process.env.NX_messagingSenderId 11 | }; 12 | 13 | firebase.initializeApp(config); 14 | const firestore = firebase.firestore(); 15 | const settings = {}; 16 | firestore.settings(settings); 17 | firestore.enablePersistence().catch(console.error); 18 | 19 | export const db = firebase.firestore(); 20 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/archetypeTalents/ROT.json: -------------------------------------------------------------------------------- 1 | { 2 | "YnfernaelLore": { 3 | "name": "Ynfernael Lore", 4 | "activation": false, 5 | "turn": false, 6 | "book": "ROT", 7 | "page": "63", 8 | "description": "See ROT, page 63, for more details.", 9 | "modifier": { 10 | "careerSkills": [ 11 | "KnowledgeForbidden" 12 | ], 13 | "KnowledgeForbidden": 2 14 | }, 15 | "setting": [ 16 | "All" 17 | ] 18 | }, 19 | "EmpyreanMagic": { 20 | "name": "Empyrean Magic", 21 | "activation": false, 22 | "turn": false, 23 | "book": "ROT", 24 | "page": "63", 25 | "description": "See ROT, page 63, for more details.", 26 | "modifier": { 27 | "careerSkills": [ 28 | "Divine" 29 | ], 30 | "Divine": 1 31 | }, 32 | "setting": [ 33 | "All" 34 | ] 35 | }, 36 | "Stubborn": { 37 | "name": "Stubborn", 38 | "activation": false, 39 | "turn": false, 40 | "book": "ROT", 41 | "page": "65", 42 | "description": "See ROT, page 65, for more details.", 43 | "setting": [ 44 | "All" 45 | ] 46 | }, 47 | "HotTempered": { 48 | "name": "Hot Tempered", 49 | "activation": false, 50 | "turn": false, 51 | "book": "ROT", 52 | "page": "67", 53 | "description": "See ROT, page 67, for more details.", 54 | "setting": [ 55 | "All" 56 | ] 57 | }, 58 | "Tenacious": { 59 | "name": "Tenacious", 60 | "activation": false, 61 | "turn": false, 62 | "book": "ROT", 63 | "page": "67", 64 | "description": "See ROT, page 67, for more details.", 65 | "setting": [ 66 | "All" 67 | ] 68 | }, 69 | "Claws": { 70 | "name": "Claws", 71 | "activation": false, 72 | "turn": false, 73 | "book": "ROT", 74 | "page": "68", 75 | "description": "See ROT, page 68, for more details.", 76 | "setting": [ 77 | "All" 78 | ] 79 | }, 80 | "FleetOfPaw": { 81 | "name": "Fleet of Paw", 82 | "activation": false, 83 | "turn": false, 84 | "book": "ROT", 85 | "page": "68", 86 | "description": "See ROT, page 68, for more details.", 87 | "setting": [ 88 | "All" 89 | ] 90 | }, 91 | "CatAncestry": { 92 | "name": "Cat Ancestry", 93 | "activation": false, 94 | "turn": false, 95 | "book": "ROT", 96 | "page": "68", 97 | "modifier": { 98 | "archetypeTalents": [ 99 | "FleetOfPaw", 100 | "Claws" 101 | ] 102 | }, 103 | "description": "See ROT, page 68, for more details.", 104 | "setting": [ 105 | "All" 106 | ] 107 | }, 108 | "Small": { 109 | "name": "Small", 110 | "activation": false, 111 | "turn": false, 112 | "book": "ROT", 113 | "page": "69", 114 | "description": "See ROT, page 69, for more details.", 115 | "setting": [ 116 | "All" 117 | ] 118 | }, 119 | "MilitiaTraining": { 120 | "name": "Militia Training", 121 | "activation": false, 122 | "turn": false, 123 | "book": "ROT", 124 | "page": "69", 125 | "description": "See ROT, page 69, for more details.", 126 | "setting": [ 127 | "All" 128 | ] 129 | }, 130 | "Tricksy": { 131 | "name": "Tricksy", 132 | "activation": false, 133 | "turn": false, 134 | "book": "ROT", 135 | "page": "69", 136 | "description": "See ROT, page 69, for more details.", 137 | "setting": [ 138 | "All" 139 | ] 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/archetypeTalents/SOTB.json: -------------------------------------------------------------------------------- 1 | { 2 | "Underestimated": { 3 | "name": "Underestimated", 4 | "activation": false, 5 | "turn": false, 6 | "book": "SOTB", 7 | "page": 27, 8 | "description": "See SOTB, page 27, for more details.", 9 | "setting": [ 10 | "Shadow Of The Beanstalk" 11 | ] 12 | }, 13 | "AdjustedToCybernetics": { 14 | "name": "Adjusted To Cybernetics", 15 | "activation": false, 16 | "turn": false, 17 | "book": "SOTB", 18 | "page": 28, 19 | "description": "See SOTB, page 28, for more details.", 20 | "setting": [ 21 | "Shadow Of The Beanstalk" 22 | ] 23 | }, 24 | "Cyborg": { 25 | "name": "Cyborg", 26 | "activation": false, 27 | "turn": false, 28 | "book": "SOTB", 29 | "page": 28, 30 | "description": "See SOTB, page 28, for more details.", 31 | "setting": [ 32 | "Shadow Of The Beanstalk" 33 | ] 34 | }, 35 | "EnhancedGeneticModifications": { 36 | "name": "Enhanced Genetic Modifications", 37 | "activation": true, 38 | "turn": "Incidental", 39 | "book": "SOTB", 40 | "page": 29, 41 | "description": "See SOTB, page 29, for more details.", 42 | "setting": [ 43 | "Shadow Of The Beanstalk" 44 | ] 45 | }, 46 | "G-Mod": { 47 | "name": "G-Mod", 48 | "activation": false, 49 | "turn": false, 50 | "book": "SOTB", 51 | "page": 29, 52 | "description": "See SOTB, page 29, for more details.", 53 | "setting": [ 54 | "Shadow Of The Beanstalk" 55 | ] 56 | }, 57 | "Zero-GAdept": { 58 | "name": "Zero-G Adept", 59 | "activation": false, 60 | "turn": false, 61 | "book": "SOTB", 62 | "page": 30, 63 | "description": "See SOTB, page 30, for more details.", 64 | "setting": [ 65 | "Shadow Of The Beanstalk" 66 | ] 67 | }, 68 | "Resourceful": { 69 | "name": "Resourceful", 70 | "activation": true, 71 | "turn": "Incidental", 72 | "book": "SOTB", 73 | "page": 30, 74 | "description": "See SOTB, page 30, for more details.", 75 | "setting": [ 76 | "Shadow Of The Beanstalk" 77 | ] 78 | } 79 | } -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/archetypes/SOTB.json: -------------------------------------------------------------------------------- 1 | { 2 | "Natural": { 3 | "name": "Natural", 4 | "book": "SOTB", 5 | "page": 25, 6 | "description": "See SOTB, page 25, for more details.", 7 | "setting": [ 8 | "Shadow Of The Beanstalk" 9 | ], 10 | "woundThreshold": 10, 11 | "strainThreshold": 10, 12 | "experience": 120, 13 | "skills": { 14 | "choice": 2, 15 | "any": 1 16 | }, 17 | "talents": [ 18 | "ReadyForAnything" 19 | ], 20 | "Brawn": 2, 21 | "Agility": 2, 22 | "Intellect": 2, 23 | "Cunning": 2, 24 | "Willpower": 2, 25 | "Presence": 2 26 | }, 27 | "BioroidSOTB": { 28 | "name": "Bioroid (SotB)", 29 | "book": "SOTB", 30 | "page": 26, 31 | "description": "See SOTB, page 26, for more details.", 32 | "setting": [ 33 | "Shadow Of The Beanstalk" 34 | ], 35 | "woundThreshold": 11, 36 | "strainThreshold": 8, 37 | "experience": 170, 38 | "skills": {}, 39 | "talents": [ 40 | "Inorganic" 41 | ], 42 | "Brawn": 3, 43 | "Agility": 1, 44 | "Intellect": 1, 45 | "Cunning": 1, 46 | "Willpower": 1, 47 | "Presence": 1 48 | }, 49 | "CloneSOTB": { 50 | "name": "Clone (SotB)", 51 | "book": "SOTB", 52 | "page": 27, 53 | "description": "See SOTB, page 27, for more details.", 54 | "setting": [ 55 | "Shadow Of The Beanstalk" 56 | ], 57 | "woundThreshold": 9, 58 | "strainThreshold": 9, 59 | "experience": 85, 60 | "skills": { 61 | "choice": 2, 62 | "any": 2 63 | }, 64 | "talents": [ 65 | "Underestimated" 66 | ], 67 | "Brawn": 2, 68 | "Agility": 2, 69 | "Intellect": 2, 70 | "Cunning": 2, 71 | "Willpower": 2, 72 | "Presence": 2 73 | }, 74 | "Cyborg": { 75 | "name": "Cyborg", 76 | "book": "SOTB", 77 | "page": 28, 78 | "description": "See SOTB, page 28, for more details.", 79 | "setting": [ 80 | "Shadow Of The Beanstalk" 81 | ], 82 | "woundThreshold": 11, 83 | "strainThreshold": 8, 84 | "experience": 100, 85 | "skills": { 86 | "Mechanics": 1 87 | }, 88 | "talents": [ 89 | "AdjustedToCybernetics", 90 | "Cyborg" 91 | ], 92 | "Brawn": 3, 93 | "Agility": 2, 94 | "Intellect": 2, 95 | "Cunning": 2, 96 | "Willpower": 2, 97 | "Presence": 1 98 | }, 99 | "G-Mod": { 100 | "name": "G-Mod", 101 | "book": "SOTB", 102 | "page": 29, 103 | "description": "See SOTB, page 29, for more details.", 104 | "setting": [ 105 | "Shadow Of The Beanstalk" 106 | ], 107 | "woundThreshold": 11, 108 | "strainThreshold": 11, 109 | "experience": 90, 110 | "skills": { 111 | "Resilience": 1 112 | }, 113 | "talents": [ 114 | "EnhancedGeneticModifications", 115 | "G-Mod" 116 | ], 117 | "Brawn": 2, 118 | "Agility": 2, 119 | "Intellect": 3, 120 | "Cunning": 2, 121 | "Willpower": 1, 122 | "Presence": 2 123 | }, 124 | "Loonie": { 125 | "name": "Loonie", 126 | "book": "SOTB", 127 | "page": 30, 128 | "description": "See SOTB, page 29, for more details.", 129 | "setting": [ 130 | "Shadow Of The Beanstalk" 131 | ], 132 | "woundThreshold": 9, 133 | "strainThreshold": 11, 134 | "experience": 100, 135 | "skills": { 136 | "Coordination": 1 137 | }, 138 | "talents": [ 139 | "Zero-GAdept", 140 | "Resourceful" 141 | ], 142 | "Brawn": 1, 143 | "Agility": 3, 144 | "Intellect": 2, 145 | "Cunning": 2, 146 | "Willpower": 2, 147 | "Presence": 2 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/armor/CRB.json: -------------------------------------------------------------------------------- 1 | { 2 | "heavyJacket": { 3 | "name": "Heavy Jacket", 4 | "defense": 0, 5 | "soak": "+1", 6 | "encumbrance": 1, 7 | "price": 50, 8 | "rarity": 1, 9 | "book": "CRB", 10 | "page": 92, 11 | "setting": [ 12 | "All" 13 | ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/armor/KF.json: -------------------------------------------------------------------------------- 1 | { 2 | "StandardClothing": { 3 | "name": "Standard Clothing", 4 | "defense": 0, 5 | "soak": "+0", 6 | "encumbrance": 1, 7 | "price": 10, 8 | "rarity": 0, 9 | "book": "SotC", 10 | "page": 143, 11 | "setting": ["scienceFantasy", "Keyforge"] 12 | }, 13 | "DurableClothing": { 14 | "name": "Durable Clothing", 15 | "defense": 0, 16 | "soak": "+1", 17 | "encumbrance": 1, 18 | "price": 50, 19 | "rarity": 1, 20 | "book": "SotC", 21 | "page": 143, 22 | "setting": ["scienceFantasy", "Keyforge"] 23 | }, 24 | "LightArmor": { 25 | "name": "Light Armor", 26 | "defense": 0, 27 | "soak": "+2", 28 | "encumbrance": 2, 29 | "price": 500, 30 | "rarity": 2, 31 | "book": "SotC", 32 | "page": 143, 33 | "setting": ["scienceFantasy", "Keyforge"] 34 | }, 35 | "HeavyArmor": { 36 | "name": "Heavy Armor", 37 | "defense": 1, 38 | "soak": "+3", 39 | "encumbrance": 3, 40 | "price": 1200, 41 | "rarity": 4, 42 | "book": "SotC", 43 | "page": 143, 44 | "setting": ["scienceFantasy", "Keyforge"] 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/armor/ROT.json: -------------------------------------------------------------------------------- 1 | { 2 | "brigandine": { 3 | "name": "Brigandine", 4 | "defense": 1, 5 | "soak": "+1", 6 | "encumbrance": 2, 7 | "price": 400, 8 | "rarity": 5, 9 | "book": "ROT", 10 | "page": 96, 11 | "setting": [ 12 | "Fantasy" 13 | ] 14 | }, 15 | "chainmail": { 16 | "name": "Chainmail", 17 | "defense": 0, 18 | "soak": "+2", 19 | "encumbrance": 3, 20 | "price": 550, 21 | "rarity": 4, 22 | "book": "ROT", 23 | "page": 96, 24 | "setting": [ 25 | "Fantasy" 26 | ], 27 | "modifier": { 28 | "Stealth": [ 29 | "[black]" 30 | ] 31 | } 32 | }, 33 | "heavyRobes": { 34 | "name": "Heavy Robes", 35 | "defense": 1, 36 | "soak": "0", 37 | "encumbrance": 1, 38 | "price": 45, 39 | "rarity": 0, 40 | "book": "ROT", 41 | "page": 96, 42 | "setting": [ 43 | "Fantasy" 44 | ] 45 | }, 46 | "leather": { 47 | "name": "Leather", 48 | "defense": 0, 49 | "soak": "+1", 50 | "encumbrance": 2, 51 | "price": 50, 52 | "rarity": 3, 53 | "book": "ROT", 54 | "page": 96, 55 | "setting": [ 56 | "Fantasy" 57 | ] 58 | }, 59 | "padded": { 60 | "name": "Padded", 61 | "defense": 0, 62 | "soak": "+1", 63 | "encumbrance": 2, 64 | "price": 35, 65 | "rarity": 2, 66 | "book": "ROT", 67 | "page": 96, 68 | "setting": [ 69 | "Fantasy" 70 | ] 71 | }, 72 | "plate": { 73 | "name": "Plate", 74 | "defense": 1, 75 | "soak": "+2", 76 | "encumbrance": 4, 77 | "price": 1000, 78 | "rarity": 6, 79 | "book": "ROT", 80 | "page": 97, 81 | "setting": [ 82 | "Fantasy" 83 | ], 84 | "modifier": { 85 | "Stealth": [ 86 | "[black]", 87 | "[black]" 88 | ] 89 | } 90 | }, 91 | "scale": { 92 | "name": "Scale", 93 | "defense": 0, 94 | "soak": "+2", 95 | "encumbrance": 4, 96 | "price": 410, 97 | "rarity": 4, 98 | "book": "ROT", 99 | "page": 97, 100 | "setting": [ 101 | "Fantasy" 102 | ], 103 | "modifier": { 104 | "Stealth": [ 105 | "[black]" 106 | ] 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/armor/SOTB.json: -------------------------------------------------------------------------------- 1 | { 2 | "durableClothing": { 3 | "name": "Durable Clothing", 4 | "defense": 0, 5 | "soak": "+1", 6 | "encumbrance": 1, 7 | "hardPoints": 1, 8 | "price": 50, 9 | "restricted": false, 10 | "rarity": 1, 11 | "book": "SOTB", 12 | "page": 93 13 | }, 14 | "concealedBuckyweave": { 15 | "name": "Concealed Buckyweave", 16 | "defense": 1, 17 | "soak": "+1", 18 | "encumbrance": 1, 19 | "hardPoints": 2, 20 | "price": 320, 21 | "restricted": false, 22 | "rarity": 4, 23 | "book": "SOTB", 24 | "page": 93 25 | }, 26 | "environmentalHardsuit": { 27 | "name": "Environmental Hardsuit", 28 | "defense": 0, 29 | "soak": "+1", 30 | "encumbrance": 4, 31 | "hardPoints": 2, 32 | "price": 260, 33 | "restricted": false, 34 | "rarity": 4, 35 | "book": "SOTB", 36 | "page": 93, 37 | "modifier": { 38 | "Resilience": [ 39 | "[success]" 40 | ] 41 | } 42 | }, 43 | "opticalCamouflageSuit": { 44 | "name": "Optical Camouflage Suit", 45 | "defense": 2, 46 | "soak": "+0", 47 | "encumbrance": 2, 48 | "hardPoints": 1, 49 | "price": 580, 50 | "restricted": true, 51 | "rarity": 7, 52 | "book": "SOTB", 53 | "page": 93 54 | }, 55 | "lightBodyArmor": { 56 | "name": "Light Body Armor", 57 | "defense": 0, 58 | "soak": "+2", 59 | "encumbrance": 2, 60 | "hardPoints": 1, 61 | "price": 500, 62 | "restricted": false, 63 | "rarity": 5, 64 | "book": "SOTB", 65 | "page": 94 66 | }, 67 | "personalExosuit": { 68 | "name": "Personal Exosuit", 69 | "defense": 0, 70 | "soak": "+3", 71 | "encumbrance": 5, 72 | "hardPoints": 4, 73 | "price": 5000, 74 | "restricted": true, 75 | "rarity": 6, 76 | "book": "SOTB", 77 | "page": 94, 78 | "modifier": { 79 | "Brawn": 1, 80 | "Perception": [ 81 | "[rmblackblack]" 82 | ], 83 | "Vigilance": [ 84 | "[rmblackblack]" 85 | ], 86 | "Brawl": [ 87 | "[rmblackblack]" 88 | ], 89 | "Melee": [ 90 | "[rmblackblack]" 91 | ], 92 | "RangedLight": [ 93 | "[rmblackblack]" 94 | ], 95 | "RangedHeavy": [ 96 | "[rmblackblack]" 97 | ], 98 | "Gunnery": [ 99 | "[rmblackblack]" 100 | ] 101 | } 102 | }, 103 | "plasteelCarapace": { 104 | "name": "Plasteel Carapace", 105 | "defense": 1, 106 | "soak": "+2", 107 | "encumbrance": 4, 108 | "hardPoints": 3, 109 | "price": 750, 110 | "restricted": true, 111 | "rarity": 5, 112 | "book": "SOTB", 113 | "page": 95 114 | }, 115 | "riotArmor": { 116 | "name": "Riot Armor", 117 | "defense": 0, 118 | "soak": "+2", 119 | "encumbrance": 3, 120 | "hardPoints": 2, 121 | "price": 550, 122 | "restricted": false, 123 | "rarity": 5, 124 | "book": "SOTB", 125 | "page": 95, 126 | "modifier": { 127 | "Resilience": [ 128 | "[blue]" 129 | ] 130 | } 131 | } 132 | } -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/careers/ROT.json: -------------------------------------------------------------------------------- 1 | { 2 | "Disciple": { 3 | "name": "Disciple", 4 | "setting": [ 5 | "Fantasy" 6 | ], 7 | "book": "ROT", 8 | "page": "70", 9 | "description": "See ROT, page 70, for more details.", 10 | "skills": [ 11 | "Athletics", 12 | "Charm", 13 | "Discipline", 14 | "Divine", 15 | "KnowledgeLore", 16 | "Leadership", 17 | "MeleeLight", 18 | "Melee", 19 | "Resilience" 20 | ] 21 | }, 22 | "Envoy": { 23 | "name": "Envoy", 24 | "setting": [ 25 | "Fantasy" 26 | ], 27 | "book": "ROT", 28 | "page": "70", 29 | "description": "See ROT, page 70, for more details.", 30 | "skills": [ 31 | "Charm", 32 | "Cool", 33 | "Deception", 34 | "KnowledgeGeography", 35 | "Leadership", 36 | "MeleeLight", 37 | "Negotiation", 38 | "Melee", 39 | "Vigilance" 40 | ] 41 | }, 42 | "Mage": { 43 | "name": "Mage", 44 | "setting": [ 45 | "Fantasy" 46 | ], 47 | "book": "ROT", 48 | "page": "71", 49 | "description": "See ROT, page 71, for more details.", 50 | "skills": [ 51 | "Alchemy", 52 | "Cool", 53 | "Arcana", 54 | "Discipline", 55 | "KnowledgeAdventuring", 56 | "KnowledgeForbidden", 57 | "KnowledgeLore", 58 | "Perception" 59 | ] 60 | }, 61 | "Primalist": { 62 | "name": "Primalist", 63 | "setting": [ 64 | "Fantasy" 65 | ], 66 | "book": "ROT", 67 | "page": "71", 68 | "description": "See ROT, page 71, for more details.", 69 | "skills": [ 70 | "Alchemy", 71 | "Brawl", 72 | "Discipline", 73 | "KnowledgeLore", 74 | "Medicine", 75 | "MeleeHeavy", 76 | "Primal", 77 | "Survival" 78 | ] 79 | }, 80 | "Scholar": { 81 | "name": "Scholar", 82 | "setting": [ 83 | "Fantasy" 84 | ], 85 | "book": "ROT", 86 | "page": "72", 87 | "description": "See ROT, page 72, for more details.", 88 | "skills": [ 89 | "Alchemy", 90 | "KnowledgeForbidden", 91 | "KnowledgeGeography", 92 | "KnowledgeLore", 93 | "Mechanics", 94 | "Medicine", 95 | "Perception", 96 | "Runes" 97 | ] 98 | }, 99 | "Scout": { 100 | "name": "Scout", 101 | "setting": [ 102 | "Fantasy" 103 | ], 104 | "book": "ROT", 105 | "page": "73", 106 | "description": "See ROT, page 73, for more details.", 107 | "skills": [ 108 | "KnowledgeAdventuring", 109 | "KnowledgeGeography", 110 | "Perception", 111 | "Ranged", 112 | "Riding", 113 | "Stealth", 114 | "Survival", 115 | "Vigilance" 116 | ] 117 | }, 118 | "Warrior": { 119 | "name": "Warrior", 120 | "setting": [ 121 | "Fantasy" 122 | ], 123 | "book": "ROT", 124 | "page": "73", 125 | "description": "See ROT, page 73, for more details.", 126 | "skills": [ 127 | "Brawl", 128 | "Coercion", 129 | "Leadership", 130 | "MeleeHeavy", 131 | "MeleeLight", 132 | "Resilience", 133 | "Riding", 134 | "Vigilance" 135 | ] 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/craftsmanship/CRB.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/craftsmanship/ROT.json: -------------------------------------------------------------------------------- 1 | { 2 | "Ancient": { 3 | "name": "Ancient", 4 | "armor": { 5 | "soak": 1, 6 | "defense": 1, 7 | "qualities": { 8 | "Reinforced": 1 9 | } 10 | }, 11 | "weapons": { 12 | "hardPoint": -1, 13 | "damage": 1, 14 | "critical": -1, 15 | "qualities": { 16 | "Reinforced": 1 17 | } 18 | }, 19 | "price": 20, 20 | "rarity": 10 21 | }, 22 | "Dwarven": { 23 | "name": "Dwarven", 24 | "armor": { 25 | "encumbrance": 1, 26 | "hardPoint": 1 27 | }, 28 | "weapons": { 29 | "damage": 1, 30 | "encumbrance": 1 31 | }, 32 | "price": 2, 33 | "rarity": 2 34 | }, 35 | "Elven": { 36 | "name": "Elven", 37 | "armor": { 38 | "encumbrance": -2, 39 | "modifier": { 40 | "Stealth": [ 41 | "[rmblack]" 42 | ] 43 | } 44 | }, 45 | "weapons": { 46 | "damage": -1, 47 | "critical": -1 48 | }, 49 | "price": 2, 50 | "rarity": 3 51 | }, 52 | "Iron": { 53 | "name": "Iron", 54 | "armor": { 55 | "encumbrance": 2, 56 | "modifier": { 57 | "Athletics": [ 58 | "[black]" 59 | ], 60 | "Coordination": [ 61 | "[black]" 62 | ], 63 | "Riding": [ 64 | "[black]" 65 | ], 66 | "Stealth": [ 67 | "[black]" 68 | ] 69 | } 70 | }, 71 | "weapons": { 72 | "critical": 1 73 | }, 74 | "price": 0.5, 75 | "rarity": -1 76 | }, 77 | "Steel": { 78 | "name": "Steel", 79 | "armor": {}, 80 | "weapons": {}, 81 | "price": 1, 82 | "rarity": 0 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/craftsmanship/SOTB.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/gear/CRB.json: -------------------------------------------------------------------------------- 1 | { 2 | "backpack": { 3 | "name": "Backpack", 4 | "encumbrance": 0, 5 | "price": 50, 6 | "rarity": 3, 7 | "book": "CRB", 8 | "page": 94, 9 | "setting": [ 10 | "All" 11 | ], 12 | "modifier": { 13 | "maxEncumbrance": 4 14 | } 15 | }, 16 | "painkiller": { 17 | "name": "Painkiller", 18 | "encumbrance": 0, 19 | "price": 25, 20 | "rarity": 2, 21 | "book": "CRB", 22 | "page": 94, 23 | "setting": [ 24 | "All" 25 | ] 26 | }, 27 | "rope": { 28 | "name": "Rope", 29 | "encumbrance": 1, 30 | "price": 5, 31 | "rarity": 1, 32 | "book": "CRB", 33 | "page": 94, 34 | "setting": [ 35 | "All" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/index.js: -------------------------------------------------------------------------------- 1 | import * as merge from 'deepmerge'; 2 | import { default as archetypesCRB } from './archetypes/CRB.json'; 3 | import { default as archetypesROT } from './archetypes/ROT.json'; 4 | import { default as archetypesSOTB } from './archetypes/SOTB.json'; 5 | import { default as archetypesKF } from './archetypes/KF.json'; 6 | import { default as archetypeTalentsCRB } from './archetypeTalents/CRB.json'; 7 | import { default as archetypeTalentsROT } from './archetypeTalents/ROT.json'; 8 | import { default as archetypeTalentsSOTB } from './archetypeTalents/SOTB.json'; 9 | import { default as archetypeTalentsKF } from './archetypeTalents/KF.json'; 10 | import { default as armorCRB } from './armor/CRB.json'; 11 | import { default as armorROT } from './armor/ROT.json'; 12 | import { default as armorSOTB } from './armor/SOTB.json'; 13 | import { default as armorKF } from './armor/KF.json'; 14 | import { default as careersCRB } from './careers/CRB.json'; 15 | import { default as careersROT } from './careers/ROT.json'; 16 | import { default as careersSOTB } from './careers/SOTB.json'; 17 | import { default as careersKF } from './careers/KF.json'; 18 | import { default as craftsmanshipCRB } from './craftsmanship/CRB.json'; 19 | import { default as craftsmanshipROT } from './craftsmanship/ROT.json'; 20 | import { default as craftsmanshipSOTB } from './craftsmanship/SOTB.json'; 21 | import { default as gearCRB } from './gear/CRB.json'; 22 | import { default as gearROT } from './gear/ROT.json'; 23 | import { default as gearSOTB } from './gear/SOTB.json'; 24 | import { default as gearKF } from './gear/KF.json'; 25 | import { default as talentsCRB } from './talents/CRB.json'; 26 | import { default as talentsEPG } from './talents/EPG.json'; 27 | import { default as talentsROT } from './talents/ROT.json'; 28 | import { default as talentsSOTB } from './talents/SOTB.json'; 29 | import { default as talentsKF } from './talents/KF.json'; 30 | import { default as vehiclesCRB } from './vehicles/CRB.json'; 31 | import { default as vehiclesROT } from './vehicles/ROT.json'; 32 | import { default as vehiclesSOTB } from './vehicles/SOTB.json'; 33 | import { default as vehiclesKF } from './vehicles/KF.json'; 34 | import { default as weaponsCRB } from './weapons/CRB.json'; 35 | import { default as weaponsROT } from './weapons/ROT.json'; 36 | import { default as weaponsSOTB } from './weapons/SOTB.json'; 37 | import { default as weaponsKF } from './weapons/KF.json'; 38 | 39 | export const archetypes = merge.all([ 40 | archetypesCRB, 41 | archetypesROT, 42 | archetypesSOTB, 43 | archetypesKF 44 | ]); 45 | export const archetypeTalents = merge.all([ 46 | archetypeTalentsCRB, 47 | archetypeTalentsROT, 48 | archetypeTalentsSOTB, 49 | archetypeTalentsKF 50 | ]); 51 | export const armor = merge.all([armorCRB, armorROT, armorSOTB, armorKF]); 52 | export const careers = merge.all([ 53 | careersCRB, 54 | careersROT, 55 | careersSOTB, 56 | careersKF 57 | ]); 58 | export const craftsmanship = merge.all([ 59 | craftsmanshipCRB, 60 | craftsmanshipROT, 61 | craftsmanshipSOTB 62 | ]); 63 | export const gear = merge.all([gearCRB, gearROT, gearSOTB, gearKF]); 64 | export const talents = merge.all([ 65 | talentsCRB, 66 | talentsEPG, 67 | talentsROT, 68 | talentsSOTB, 69 | talentsKF 70 | ]); 71 | export const weapons = merge.all([ 72 | weaponsCRB, 73 | weaponsROT, 74 | weaponsSOTB, 75 | weaponsKF 76 | ]); 77 | export const vehicles = merge.all([ 78 | vehiclesCRB, 79 | vehiclesROT, 80 | vehiclesSOTB, 81 | vehiclesKF 82 | ]); 83 | 84 | export { default as motivations } from './motivations.json'; 85 | export { default as qualities } from './qualities.json'; 86 | export { default as skills } from './skills.json'; 87 | export { default as settings } from './settings.json'; 88 | export { 89 | dataTypes, 90 | customDataTypes, 91 | vehicleDataTypes, 92 | chars, 93 | diceOrder, 94 | diceNames, 95 | modifiableAttributes 96 | } from './lists'; 97 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/lists.js: -------------------------------------------------------------------------------- 1 | export const dataTypes = [ 2 | 'archetype', 3 | 'archetypeSpecialSkills', 4 | 'career', 5 | 'careerSkillsRank', 6 | 'creationCharacteristics', 7 | 'critical', 8 | 'currentStrain', 9 | 'currentWound', 10 | 'description', 11 | 'earnedXP', 12 | 'equipmentArmor', 13 | 'equipmentGear', 14 | 'equipmentWeapons', 15 | 'masterMotivations', 16 | 'masterSkills', 17 | 'masterTalents', 18 | 'misc', 19 | 'money', 20 | 'aember', 21 | 'setting', 22 | 'talentModifiers', 23 | 'theme', 24 | 'themes' 25 | ]; 26 | 27 | export const vehicleDataTypes = [ 28 | 'vehicleType', 29 | 'currentHullTrauma', 30 | 'currentSystemStrain', 31 | 'vehicleNotes' 32 | ]; 33 | 34 | export const chars = [ 35 | 'Brawn', 36 | 'Agility', 37 | 'Intellect', 38 | 'Cunning', 39 | 'Willpower', 40 | 'Presence' 41 | ]; 42 | 43 | export const diceOrder = [ 44 | '[yellow]', 45 | '[green]', 46 | '[blue]', 47 | '[red]', 48 | '[purple]', 49 | '[black]', 50 | '[rmblack]', 51 | '[rmblackblack]' 52 | ]; 53 | 54 | export const diceNames = { 55 | '[blue]': { name: 'Boost Die' }, 56 | '[black]': { name: 'Setback Die' }, 57 | '[rmblack]': { name: 'Remove Setback Die' }, 58 | '[rmblackblack]': { name: 'Remove 2 Setback Die' }, 59 | '[success]': { name: 'Success' }, 60 | '[advantage]': { name: 'Advantage' }, 61 | '[failure]': { name: 'Failure' }, 62 | '[threat]': { name: 'Threat' } 63 | }; 64 | 65 | export const customDataTypes = [ 66 | 'customArchetypes', 67 | 'customArchetypeTalents', 68 | 'customArmor', 69 | 'customCareers', 70 | 'customGear', 71 | 'customMotivations', 72 | 'customSettings', 73 | 'customSkills', 74 | 'customTalents', 75 | 'customVehicles', 76 | 'customWeapons' 77 | ]; 78 | 79 | export const modifiableAttributes = [ 80 | 'woundThreshold', 81 | 'strainThreshold', 82 | 'soak', 83 | 'meleeDefense', 84 | 'rangedDefense', 85 | 'defense', 86 | 'careerSkills' 87 | ].sort(); 88 | 89 | export const books = ['CRB', 'RoT', 'SotB', 'SotC']; 90 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "All": "All", 3 | "Fantasy": "Fantasy", 4 | "hacking": "Hacking", 5 | "Keyforge": "Keyforge", 6 | "magic": "Magic", 7 | "modernDay": "Modern Day", 8 | "scienceFiction": "Science Fiction", 9 | "scienceFantasy": "Science Fantasy", 10 | "spaceOpera": "Space Opera", 11 | "steampunk": "Steampunk", 12 | "taco": "Taco", 13 | "vehicle": "Vehicle", 14 | "weirdWar": "Weird War" 15 | } 16 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/vehicles/CRB.json: -------------------------------------------------------------------------------- 1 | { 2 | "threeMastedFrigate": { 3 | "name": "Three-Masted Frigate", 4 | "silhouette": 5, 5 | "maxSpeed": 3, 6 | "handling": -3, 7 | "defense": 0, 8 | "armor": 3, 9 | "hullTraumaThreshold": 60, 10 | "systemStrainThreshold": 45, 11 | "skill": "Operating,", 12 | "complement": "225 crew", 13 | "passengerCapacity": 60, 14 | "price": 300000, 15 | "rarity": 8, 16 | "consumables": "3 months", 17 | "encumbranceCapacity": 200, 18 | "weapons": "15 starboard and 15 port 24-pounder cannons (Fire Arc Starboard and Fire Arc Port; Damage 6; Critical 3; Range [Long]).\n4 starboard and 4 port 9-pounder cannons (Fire Arc Starboard and Fire Arc Port; Damage 4; Critical 5; Range [Medium]).\n2 forward “long nines” (Fire Arc Forward; Damage 4; Critical 5; Range [Long]; Accurate 1)." 19 | }, 20 | "fourDoorAutomobile": { 21 | "name": "Four Door Automobile", 22 | "silhouette": 2, 23 | "maxSpeed": 4, 24 | "handling": 0, 25 | "defense": 0, 26 | "armor": 0, 27 | "hullTraumaThreshold": 4, 28 | "systemStrainThreshold": 5, 29 | "skill": "Driving,", 30 | "complement": "1 driver", 31 | "passengerCapacity": "3 (5 uncomfortably)", 32 | "price": 2000, 33 | "rarity": 3, 34 | "consumables": "none", 35 | "encumbranceCapacity": 20, 36 | "weapons": "none" 37 | }, 38 | "aerospaceSuperiorityFighter": { 39 | "name": "Aerospace Superiority Fighter", 40 | "silhouette": 3, 41 | "maxSpeed": 5, 42 | "handling": 2, 43 | "defense": 0, 44 | "armor": 2, 45 | "hullTraumaThreshold": 10, 46 | "systemStrainThreshold": 10, 47 | "skill": "Piloting,", 48 | "complement": "1 pilot, 1 copilot", 49 | "passengerCapacity": 0, 50 | "price": 1000000000, 51 | "rarity": 9, 52 | "consumables": "1 day", 53 | "encumbranceCapacity": 5, 54 | "weapons": "Rotary cannon (Fire Arc Forward; Damage 2; Critical 5; Range [Long]; Auto-fire).\nAir-to-air missiles (Fire Arc Forward; Damage 5; Critical 3; Range [Extreme]; Guided 3, Limited Ammo 6).\nAnti-ship missile (Fire Arc Forward; Damage 8; Critical 1; Range [Strategic]; Blast 5, Breach 2, Limited Ammo 1)." 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/vehicles/ROT.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /packages/emporium/src/assets/data/weapons/KF.json: -------------------------------------------------------------------------------- 1 | { 2 | "BrawlWeapon": { 3 | "name": "Brawl Weapon", 4 | "skill": "Brawl", 5 | "damage": "+0", 6 | "critical": 5, 7 | "range": "Engaged", 8 | "encumbrance": 1, 9 | "price": 25, 10 | "rarity": 1, 11 | "book": "SotC", 12 | "page": 138, 13 | "setting": ["scienceFantasy", "Keyforge"] 14 | }, 15 | "OneHandedMeleeWeapon": { 16 | "name": "One-Handed Melee Weapon", 17 | "skill": "Melee", 18 | "damage": "+1", 19 | "critical": 4, 20 | "range": "Engaged", 21 | "encumbrance": 1, 22 | "price": 50, 23 | "rarity": 2, 24 | "book": "SotC", 25 | "page": 138, 26 | "setting": ["scienceFantasy", "Keyforge"] 27 | }, 28 | "OneHandedRangedWeapon": { 29 | "name": "One-Handed Ranged Weapon", 30 | "skill": "Ranged", 31 | "damage": "5", 32 | "critical": 4, 33 | "range": "Short", 34 | "encumbrance": 2, 35 | "price": 150, 36 | "rarity": 3, 37 | "book": "SotC", 38 | "page": 138, 39 | "setting": ["scienceFantasy", "Keyforge"] 40 | }, 41 | "TwoHandedRangedWeapon": { 42 | "name": "Two-Handed Ranged Weapon", 43 | "skill": "Ranged", 44 | "damage": "6", 45 | "critical": 4, 46 | "range": "Medium", 47 | "encumbrance": 3, 48 | "price": 500, 49 | "rarity": 3, 50 | "book": "SotC", 51 | "page": 138, 52 | "setting": ["scienceFantasy", "Keyforge"] 53 | }, 54 | "GunneryWeapon": { 55 | "name": "Gunnery Weapon", 56 | "skill": "Ranged", 57 | "damage": "10", 58 | "critical": 3, 59 | "range": "Long", 60 | "encumbrance": 5, 61 | "price": 1400, 62 | "rarity": 5, 63 | "book": "SotC", 64 | "page": 138, 65 | "setting": ["scienceFantasy", "Keyforge"] 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/CRB/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/CRB/background.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/CRB/index.ts: -------------------------------------------------------------------------------- 1 | export {default as Agility} from './Agility.svg'; 2 | export {default as AvailableXp} from './AvailableXp.svg'; 3 | export {default as Brawn} from './Brawn.svg'; 4 | export {default as background} from './background.png'; 5 | export {default as Cunning} from './Cunning.svg'; 6 | export {default as Defense} from './Defense.svg'; 7 | export {default as Intellect} from './Intellect.svg'; 8 | export {default as Logo} from './Logo.svg'; 9 | export {default as Presence} from './Presence.svg'; 10 | export {default as Soak} from './Soak.svg'; 11 | export {default as Strain} from './Strain.svg'; 12 | export {default as StrainThreshold} from './StrainThreshold.svg'; 13 | export {default as TotalXp} from './TotalXp.svg'; 14 | export {default as VehicleStatBlock} from './VehicleStatBlock.svg'; 15 | export {default as Willpower} from './Willpower.svg'; 16 | export {default as Wounds} from './Wounds.svg'; 17 | export {default as WoundsThreshold} from './WoundsThreshold.svg'; 18 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/Crest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/Crest.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/KF/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/KF/background.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/KF/index.ts: -------------------------------------------------------------------------------- 1 | const characteristicUrl = 'https://unbound-legends.imgix.net/character2/charstat-kf.svg?auto=format'; 2 | 3 | export const Brawn = characteristicUrl; 4 | export const Agility = characteristicUrl; 5 | export const Intellect = characteristicUrl; 6 | export const Cunning = characteristicUrl; 7 | export const Willpower = characteristicUrl; 8 | export const Presence = characteristicUrl; 9 | 10 | const doubleValueUrl = 'https://unbound-legends.imgix.net/character2/statblock02-kf.svg?auto=format'; 11 | 12 | export const Wounds = doubleValueUrl; 13 | export const Strain = doubleValueUrl; 14 | export const Defense = doubleValueUrl; 15 | 16 | export const Soak = 'https://unbound-legends.imgix.net/character2/statblock01-kf.svg?auto=format'; 17 | export const Logo = 'https://ul-emporium.imgix.net/logos/keyforge-logo-bigger.png'; 18 | export const AvailableXp = 'https://ul-emporium.imgix.net/attributes/emp-kf-avaxp.svg'; 19 | export const TotalXp = 'https://ul-emporium.imgix.net/attributes/emp-kf-totxp.svg'; 20 | export const StrainThreshold = Soak; 21 | export const WoundsThreshold = Soak; 22 | 23 | export const VehicleStatBlock = '/assets/images/KF/kf-vehicle-statblocks.svg'; 24 | 25 | export { default as background } from './background.png'; 26 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/ROT/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/ROT/background.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/ROT/index.ts: -------------------------------------------------------------------------------- 1 | export {default as Agility} from './Agility.svg'; 2 | export {default as AvailableXp} from './AvailableXp.svg'; 3 | export {default as Brawn} from './Brawn.svg'; 4 | export {default as background} from './background.png'; 5 | export {default as Cunning} from './Cunning.svg'; 6 | export {default as Defense} from './Defense.svg'; 7 | export {default as Intellect} from './Intellect.svg'; 8 | export {default as Logo} from './Logo.svg'; 9 | export {default as Presence} from './Presence.svg'; 10 | export {default as Soak} from './Soak.svg'; 11 | export {default as Strain} from './Strain.svg'; 12 | export {default as StrainThreshold} from './StrainThreshold.svg'; 13 | export {default as TotalXp} from './TotalXp.svg'; 14 | export {default as VehicleStatBlock} from './VehicleStatBlock.svg'; 15 | export {default as Willpower} from './Willpower.svg'; 16 | export {default as Wounds} from './Wounds.svg'; 17 | export {default as WoundsThreshold} from './WoundsThreshold.svg'; 18 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/SOTB/Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/SOTB/Logo.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/SOTB/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/SOTB/background.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/SOTB/index.ts: -------------------------------------------------------------------------------- 1 | export {default as Agility} from './Agility.svg'; 2 | export {default as AvailableXp} from './AvailableXp.svg'; 3 | export {default as Brawn} from './Brawn.svg'; 4 | export {default as background} from './background.png'; 5 | export {default as Cunning} from './Cunning.svg'; 6 | export {default as Defense} from './Defense.svg'; 7 | export {default as Intellect} from './Intellect.svg'; 8 | export {default as Logo} from './Logo.png'; 9 | export {default as Presence} from './Presence.svg'; 10 | export {default as Soak} from './Soak.svg'; 11 | export {default as Strain} from './Strain.svg'; 12 | export {default as StrainThreshold} from './StrainThreshold.svg'; 13 | export {default as TotalXp} from './TotalXp.svg'; 14 | export {default as VehicleStatBlock} from './VehicleStatBlock.svg'; 15 | export {default as Willpower} from './Willpower.svg'; 16 | export {default as Wounds} from './Wounds.svg'; 17 | export {default as WoundsThreshold} from './WoundsThreshold.svg'; 18 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/emporium.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/emporium.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/gm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/gm.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/index.ts: -------------------------------------------------------------------------------- 1 | //import * as CCC from './CCC' 2 | import * as CRB from './CRB'; 3 | import * as ROT from './ROT'; 4 | import * as SOTB from './SOTB'; 5 | import * as KF from './KF'; 6 | 7 | export { CRB }; 8 | export { ROT }; 9 | export { SOTB }; 10 | export { KF }; 11 | //export {CCC}; 12 | export { default as Crest } from './Crest.png'; 13 | export { default as gm } from './gm.png'; 14 | export { default as pc } from './pc.png'; 15 | export { default as user } from './user.svg'; 16 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/pc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/assets/images/pc.png -------------------------------------------------------------------------------- /packages/emporium/src/assets/images/user.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Emporium", 3 | "name": "Genesys Emporium", 4 | "icons": [ 5 | { 6 | "src": "/assets/images/emporium.png", 7 | "sizes": "512x512", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/assets/images/emporium.png", 12 | "sizes": "192x192", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": "/", 17 | "background_color": "#f7f4f2", 18 | "theme_color": "#f7f4f2", 19 | "display": "standalone" 20 | } 21 | -------------------------------------------------------------------------------- /packages/emporium/src/assets/service-worker.js: -------------------------------------------------------------------------------- 1 | self.addEventListener('activate', event => { 2 | // Delete all of our old caches 3 | const cacheWhitelist = []; 4 | event.waitUntil( 5 | caches.keys().then(keyList => 6 | Promise.all( 7 | keyList.map(key => { 8 | if (!cacheWhitelist.includes(key)) { 9 | console.log('Deleting cache: ' + key); 10 | return caches.delete(key); 11 | } 12 | 13 | return null; 14 | }) 15 | ) 16 | ) 17 | ); 18 | }); 19 | -------------------------------------------------------------------------------- /packages/emporium/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | Genesys Emporium 18 | 19 | 20 |
21 | 22 | 23 | -------------------------------------------------------------------------------- /packages/emporium/src/main.tsx: -------------------------------------------------------------------------------- 1 | import 'bootstrap/dist/css/bootstrap.css'; 2 | import 'core-js/features/array'; 3 | import 'core-js/features/object/values'; 4 | import 'core-js/features/string/includes'; 5 | import React from 'react'; 6 | import 'react-bootstrap-typeahead/css/Typeahead.css'; 7 | import ReactDOM from 'react-dom'; 8 | import { Provider } from 'react-redux'; 9 | import { BrowserRouter, Route } from 'react-router-dom'; 10 | import { applyMiddleware, createStore } from 'redux'; 11 | import thunk from 'redux-thunk'; 12 | import 'sw-rpg-icons/css/sw-rpg-colors.min.css'; 13 | import 'sw-rpg-icons/css/sw-rpg-icons.min.css'; 14 | import { App } from './app/app'; 15 | import allReducers from './redux/reducers'; 16 | import './styles/index.scss'; 17 | 18 | export const store = createStore(allReducers, {}, applyMiddleware(thunk)); 19 | 20 | ReactDOM.render( 21 | 22 | 23 | 24 | 25 | 26 | 27 | , 28 | document.getElementById('root') 29 | ); 30 | -------------------------------------------------------------------------------- /packages/emporium/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Polyfill stable language features. These imports will be optimized by `@babel/preset-env`. 3 | * 4 | * See: https://github.com/zloirock/core-js#babel 5 | */ 6 | import 'core-js/stable'; 7 | import 'regenerator-runtime/runtime'; 8 | 9 | 10 | // Ultra hacky bootstrap support (?) 11 | // https://stackoverflow.com/questions/50264344/aws-sdk-crash-after-updating-from-angular5-to-angular6 12 | (window as any).global = window; 13 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/initialState.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | export const archetype = null; 4 | export const archetypeSpecialSkills = {}; 5 | export const career = null; 6 | export const careerSkillsRank = []; 7 | export const creationCharacteristics = { 8 | Brawn: 0, 9 | Agility: 0, 10 | Intellect: 0, 11 | Cunning: 0, 12 | Willpower: 0, 13 | Presence: 0 14 | }; 15 | export const critical = []; 16 | export const currentHullTrauma = 0; 17 | export const currentSystemStrain = 0; 18 | export const currentWound = 0; 19 | export const currentStrain = 0; 20 | export const description = { 21 | name: 'New Character', 22 | playerName: 'Enter Player Name' 23 | }; 24 | export const earnedXP = 0; 25 | export const equipmentArmor = {}; 26 | export const equipmentGear = {}; 27 | export const equipmentWeapons = {}; 28 | export const masterMotivations = { 29 | Desire: {}, 30 | Fear: {}, 31 | Strength: {}, 32 | Flaw: {} 33 | }; 34 | export const masterSkills = {}; 35 | export const masterTalents = { 1: { 1: '' } }; 36 | export const misc = null; 37 | export const money = 0; 38 | export const aember = 0; 39 | export const setting = ['All']; 40 | export const talentModifiers = { Dedication: {} }; 41 | export const theme = 'CRB'; 42 | export const themes = { 43 | CRB: 'Core Rule Book', 44 | KF: 'Keyforge', 45 | ROT: 'Realms of Terrinoth', 46 | SOTB: 'Shadow of the Beanstalk' 47 | }; 48 | export const vehicle = ''; 49 | export const vehicleType = ''; 50 | export const vehicleNotes = ''; 51 | export const vehicleWrite = false; 52 | 53 | export const printContent = ( 54 |

55 | {`You savage. I made print button and you dare to use the print function in the browser?!?!\n 56 | For better results use the aforementioned print button. It's located on the top-right of the characters tab.\n 57 | Can't I just hijack the print function and do it automatically, you ask?\n 58 | PROBABLY!\n\n 59 | -Sky`} 60 |

61 | ); 62 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/reducers.tsx: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import * as changeState from './changeState'; 3 | 4 | const allReducers = combineReducers({ 5 | archetype: changeState.archetype, 6 | archetypes: changeState.archetypes, 7 | archetypeSpecialSkills: changeState.archetypeSpecialSkills, 8 | archetypeTalents: changeState.archetypeTalents, 9 | armor: changeState.armor, 10 | career: changeState.career, 11 | careers: changeState.careers, 12 | careerSkillsRank: changeState.careerSkillsRank, 13 | character: changeState.character, 14 | characterList: changeState.characterList, 15 | craftsmanship: changeState.craftsmanship, 16 | creationCharacteristics: changeState.creationCharacteristics, 17 | critical: changeState.critical, 18 | currentHullTrauma: changeState.currentHullTrauma, 19 | currentSystemStrain: changeState.currentSystemStrain, 20 | currentStrain: changeState.currentStrain, 21 | currentWound: changeState.currentWound, 22 | customArchetypes: changeState.customArchetypes, 23 | customArchetypeTalents: changeState.customArchetypeTalents, 24 | customArmor: changeState.customArmor, 25 | customCareers: changeState.customCareers, 26 | customGear: changeState.customGear, 27 | customMotivations: changeState.customMotivations, 28 | customSkills: changeState.customSkills, 29 | customSettings: changeState.customSettings, 30 | customTalents: changeState.customTalents, 31 | customWeapons: changeState.customWeapons, 32 | customVehicles: changeState.customVehicles, 33 | description: changeState.description, 34 | earnedXP: changeState.earnedXP, 35 | equipmentArmor: changeState.equipmentArmor, 36 | equipmentGear: changeState.equipmentGear, 37 | equipmentWeapons: changeState.equipmentWeapons, 38 | gear: changeState.gear, 39 | loadingData: changeState.loadingData, 40 | masterMotivations: changeState.masterMotivations, 41 | masterSkills: changeState.masterSkills, 42 | masterTalents: changeState.masterTalents, 43 | misc: changeState.misc, 44 | money: changeState.money, 45 | aember: changeState.aember, 46 | motivations: changeState.motivations, 47 | printContent: changeState.printContent, 48 | qualities: changeState.qualities, 49 | setting: changeState.setting, 50 | settings: changeState.settings, 51 | skills: changeState.skills, 52 | talentModifiers: changeState.talentModifiers, 53 | talents: changeState.talents, 54 | theme: changeState.theme, 55 | themes: changeState.themes, 56 | user: changeState.user, 57 | weapons: changeState.weapons, 58 | vehicle: changeState.vehicle, 59 | vehicles: changeState.vehicles, 60 | vehicleDataSet: changeState.vehicleDataSet, 61 | vehicleNotes: changeState.vehicleNotes, 62 | vehicleType: changeState.vehicleType 63 | }); 64 | 65 | export default allReducers; 66 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/archetypeSkillRank.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | 4 | const archetype = state => state.archetype; 5 | const archetypes = state => state.archetypes; 6 | const archetypeSpecialSkills = state => state.archetypeSpecialSkills; 7 | const archetypeTalents = state => state.archetypeTalents; 8 | const skills = state => state.skills; 9 | 10 | export const archetypeSkillRank = state => calcArchetypeSkillRank(state); 11 | 12 | const calcArchetypeSkillRank = createSelector( 13 | archetype, 14 | archetypes, 15 | archetypeTalents, 16 | skills, 17 | archetypeSpecialSkills, 18 | ( 19 | archetype, 20 | archetypes, 21 | archetypeTalents, 22 | skills, 23 | archetypeSpecialSkills 24 | ) => { 25 | const archSkills = get(archetypes, `${archetype}.skills`, {}), 26 | talents = get(archetypes, `${archetype}.talents`, []); 27 | //add any starting skills based on archetype skills 28 | if (!Object.keys(archSkills).includes('choice')) { 29 | Object.keys(archSkills).forEach(key => { 30 | if (Object.keys(skills).includes(key)) { 31 | archetypeSpecialSkills[key] = { rank: archSkills[key] }; 32 | } 33 | }); 34 | } 35 | //add any starting skills based on archetype talents 36 | for (const talent of talents) { 37 | const modifier = get(archetypeTalents, `${talent}.modifier`, {}); 38 | Object.keys(modifier).forEach(key => { 39 | if ( 40 | Object.keys(skills).includes(key) && 41 | Number.isInteger(modifier[key]) 42 | ) { 43 | archetypeSpecialSkills[key] = { rank: modifier[key] }; 44 | } 45 | }); 46 | } 47 | return archetypeSpecialSkills; 48 | } 49 | ); 50 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/careerCheck.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { talentCount } from './talentCount'; 4 | 5 | const archetype = state => state.archetype; 6 | const archetypes = state => state.archetypes; 7 | const archetypeTalents = state => state.archetypeTalents; 8 | const career = state => state.career; 9 | const careers = state => state.careers; 10 | const skills = state => state.skills; 11 | const talents = state => state.talents; 12 | 13 | export const careerCheck = state => calcCareerCheck(state); 14 | 15 | const calcCareerCheck = createSelector( 16 | archetype, 17 | archetypes, 18 | archetypeTalents, 19 | skills, 20 | career, 21 | careers, 22 | talents, 23 | talentCount, 24 | ( 25 | archetype, 26 | archetypes, 27 | archetypeTalents, 28 | skills, 29 | career, 30 | careers, 31 | talents, 32 | talentCount 33 | ) => { 34 | const careerSkillsList = {}; 35 | //get careerSkills from career 36 | Object.keys(skills).forEach(skill => { 37 | careerSkillsList[skill] = false; 38 | const list = get(careers, `${career}.skills`, []); 39 | if (list.includes(skill)) { 40 | careerSkillsList[skill] = true; 41 | } 42 | 43 | //get careerSkills from archetype 44 | const archTalents = get(archetypes, `${archetype}.talents`, []); 45 | archTalents.forEach(talent => { 46 | const careerSkills = get( 47 | archetypeTalents, 48 | `${talent}.modifier.careerSkills`, 49 | [] 50 | ); 51 | if (careerSkills.includes(skill)) { 52 | careerSkillsList[skill] = true; 53 | } 54 | }); 55 | 56 | //get careerSkills from talents 57 | Object.keys(talentCount).forEach(talent => { 58 | const careerSkills = get( 59 | talents, 60 | `${talent}.modifier.careerSkills`, 61 | [] 62 | ); 63 | if (careerSkills.includes(skill)) { 64 | careerSkillsList[skill] = true; 65 | } 66 | }); 67 | }); 68 | return careerSkillsList; 69 | } 70 | ); 71 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/characteristics.tsx: -------------------------------------------------------------------------------- 1 | import { chars } from '@emporium/data-lists'; 2 | import { get } from 'lodash-es'; 3 | import { createSelector } from 'reselect'; 4 | import * as initialState from '../initialState'; 5 | import { equipmentStats } from './equipmentStats'; 6 | import { talentCount } from './talentCount'; 7 | 8 | const archetype = state => state.archetype; 9 | const archetypes = state => state.archetypes; 10 | const creationCharacteristics = state => state.creationCharacteristics; 11 | const talentModifiers = state => state.talentModifiers; 12 | const talents = state => state.talents; 13 | 14 | export const characteristics = state => calcCharacteristics(state); 15 | 16 | const calcCharacteristics = createSelector( 17 | archetype, 18 | archetypes, 19 | creationCharacteristics, 20 | talentModifiers, 21 | equipmentStats, 22 | talents, 23 | talentCount, 24 | ( 25 | archetype, 26 | archetypes, 27 | creationCharacteristics, 28 | talentModifiers, 29 | equipmentStats, 30 | talents, 31 | talentCount 32 | ) => { 33 | //get the starting characteristics 34 | const characteristics = { ...creationCharacteristics }; 35 | 36 | //add the arch characteristics 37 | const arch = get( 38 | archetypes, 39 | `${archetype}`, 40 | initialState.creationCharacteristics 41 | ); 42 | Object.keys(characteristics).forEach( 43 | key => (characteristics[key] += arch[key]) 44 | ); 45 | 46 | //add dedications talents 47 | const dedication = get(talentModifiers, 'Dedication', {}); 48 | Object.keys(dedication).forEach( 49 | key => characteristics[dedication[key]]++ 50 | ); 51 | 52 | //add other talents 53 | Object.entries(talentCount).forEach(([talent, count]) => { 54 | const modifier = get(talents, `${talent}.modifier`, {}); 55 | chars.forEach(key => { 56 | if (key in modifier) { 57 | characteristics[key] += count; 58 | } 59 | }); 60 | }); 61 | //add equipment modifier 62 | Object.keys(equipmentStats).forEach(key => { 63 | const modifier = get(equipmentStats, `${key}.modifier`, {}), 64 | carried = get(equipmentStats, `${key}.carried`, false), 65 | equipped = get(equipmentStats, `${key}.equipped`, false), 66 | type = get(equipmentStats, `${key}.type`, ''); 67 | 68 | if (carried && modifier && (equipped || type !== 'armor')) { 69 | Object.keys(modifier).forEach(key => { 70 | if (chars.includes(key)) { 71 | characteristics[key] += 1; 72 | } 73 | }); 74 | } 75 | }); 76 | 77 | //Hard cap of 6 78 | Object.keys(characteristics).forEach(key => { 79 | if (characteristics[key] > 6) { 80 | characteristics[key] = 6; 81 | } 82 | }); 83 | 84 | return characteristics; 85 | } 86 | ); 87 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/encumbranceLimit.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { characteristics } from './characteristics'; 4 | import { talentCount } from './talentCount'; 5 | 6 | const equipmentGear = state => state.equipmentGear; 7 | const talents = state => state.talents; 8 | const archetypeTalents = state => state.archetypeTalents; 9 | const gear = state => state.gear; 10 | const archetype = state => state.archetype; 11 | const archetypes = state => state.archetypes; 12 | 13 | export const encumbranceLimit = state => calcEncumbranceLimit(state); 14 | const calcEncumbranceLimit = createSelector( 15 | characteristics, 16 | equipmentGear, 17 | gear, 18 | talents, 19 | archetypeTalents, 20 | talentCount, 21 | archetypes, 22 | archetype, 23 | ( 24 | characteristics, 25 | equipmentGear, 26 | gear, 27 | talents, 28 | archetypeTalents, 29 | talentCount, 30 | archetypes, 31 | archetype 32 | ) => { 33 | const Brawn = characteristics.Brawn; 34 | 35 | //get gear modifier 36 | const gearModifier = Object.keys(equipmentGear) 37 | .map(item => { 38 | const id = equipmentGear[item].id, 39 | maxEncumbrance = get( 40 | gear, 41 | `${id}.modifier.maxEncumbrance`, 42 | 0 43 | ); 44 | if (equipmentGear[item].carried) { 45 | return maxEncumbrance; 46 | } else { 47 | return 0; 48 | } 49 | }) 50 | .reduce((acc, val) => acc + val, 0); 51 | 52 | // Add archetype talents 53 | let archetypeTalentModifier = 0; 54 | if (archetype && archetypes?.[archetype]?.talents) { 55 | const selectedArchetypeTalents = archetypes?.[archetype]?.talents; 56 | archetypeTalentModifier = selectedArchetypeTalents 57 | .map(talent => { 58 | return get( 59 | archetypeTalents, 60 | `${talent}.modifier.maxEncumbrance`, 61 | 0 62 | ); 63 | }) 64 | .reduce((acc, val) => acc + val, 0); 65 | } 66 | 67 | // Add other talents 68 | const talentsModifier = Object.entries(talentCount) 69 | .map(([talent, count]) => { 70 | return ( 71 | get(talents, `${talent}.modifier.maxEncumbrance`, 0) * 72 | +count 73 | ); 74 | }) 75 | .reduce((acc, val) => acc + val, 0); 76 | 77 | return ( 78 | Brawn + gearModifier + talentsModifier + archetypeTalentModifier + 5 79 | ); 80 | } 81 | ); 82 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/gearDice.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { equipmentStats } from './equipmentStats'; 4 | import { skillDice } from './skillDice'; 5 | 6 | const qualities = state => state.qualities; 7 | 8 | export const gearDice = state => calcGearDice(state); 9 | 10 | const calcGearDice = createSelector( 11 | skillDice, 12 | equipmentStats, 13 | qualities, 14 | (skillDice, equipmentStats, qualities) => { 15 | const gearDice = {}; 16 | Object.keys(equipmentStats).forEach(key => { 17 | const item = equipmentStats[key], 18 | { type, skill } = item, 19 | list = get(item, 'qualities', []), 20 | qualityDice = Object.keys(list) 21 | .map(quality => { 22 | const rank = list[quality] === '' ? 1 : list[quality]; 23 | const check = get( 24 | qualities, 25 | `${quality}.modifier.check`, 26 | '' 27 | ); 28 | return [...Array(rank)].map(() => check).join(' '); 29 | }) 30 | .join(' '); 31 | 32 | gearDice[type] = { 33 | ...gearDice[type], 34 | [key]: skillDice[skill] + ' ' + qualityDice 35 | }; 36 | }); 37 | return gearDice; 38 | } 39 | ); 40 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/index.ts: -------------------------------------------------------------------------------- 1 | //naked selectors 2 | export { archetypeSkillRank } from './archetypeSkillRank'; 3 | export { criticalText } from './criticals'; 4 | export { talentCount } from './talentCount'; 5 | export { equipmentStats } from './equipmentStats'; 6 | export { maxCareerSkills } from './maxCareerSkills'; 7 | export { totalXP } from './totalXP'; 8 | 9 | //compound selectors 10 | 11 | //1st level selectors (only need naked selectors) 12 | export { characteristics } from './characteristics'; 13 | export { careerCheck } from './careerCheck'; 14 | export { totalDefense } from './totalDefense'; 15 | export { totalEncumbrance } from './totalEncumbrance'; 16 | export { skillRanks } from './skillRanks'; 17 | 18 | //2nd level selectors (needs naked and 1st level selectors) 19 | export { strainThreshold } from './strainThreshold'; 20 | export { encumbranceLimit } from './encumbranceLimit'; 21 | export { totalSoak } from './totalSoak'; 22 | export { usedXP } from './usedXP'; 23 | export { woundThreshold } from './woundThreshold'; 24 | 25 | //3rd level selectors (needs naked, 1st and 2nd level selectors) 26 | export { skillDice } from './skillDice'; 27 | 28 | //4th level selectors (needs naked, 1st, 2nd, 3rd level selectors) 29 | export { gearDice } from './gearDice'; 30 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/maxCareerSkills.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | 4 | const archetype = state => state.archetype; 5 | const archetypes = state => state.archetypes; 6 | 7 | export const maxCareerSkills = state => calcMaxCareerSkills(state); 8 | 9 | const calcMaxCareerSkills = createSelector( 10 | archetype, 11 | archetypes, 12 | (archetype, archetypes) => 13 | get(archetypes, `${archetype}.skills.careerSkills`, 4) 14 | ); 15 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/skillRanks.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import {archetypeSkillRank} from './archetypeSkillRank'; 4 | 5 | const careerSkillsRank = state => state.careerSkillsRank; 6 | const masterSkills = state => state.masterSkills; 7 | const skills = state => state.skills; 8 | 9 | export const skillRanks = state => calcSkillRanks(state); 10 | 11 | const calcSkillRanks = createSelector( 12 | masterSkills, 13 | skills, 14 | careerSkillsRank, 15 | archetypeSkillRank, 16 | (masterSkills, skills, careerSkillsRank, archetypeSkillRank) => { 17 | const skillRanks = {}; 18 | Object.keys(skills).forEach(key => { 19 | const ranks = get(masterSkills, `${key}.rank`, 0), 20 | careerRanks = get(masterSkills, `${key}.careerRank`, 0), 21 | freeCareerSkillsRank = careerSkillsRank.includes(key) ? 1 : 0, 22 | freeArchetypeSkillRank = get( 23 | archetypeSkillRank, 24 | `${key}.rank`, 25 | 0 26 | ); 27 | 28 | skillRanks[key] = 29 | ranks + 30 | careerRanks + 31 | freeCareerSkillsRank + 32 | freeArchetypeSkillRank; 33 | }); 34 | 35 | return skillRanks; 36 | } 37 | ); 38 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/strainThreshold.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { talentCount } from './talentCount'; 4 | import { equipmentStats } from './equipmentStats'; 5 | 6 | const archetype = state => state.archetype; 7 | const archetypes = state => state.archetypes; 8 | const creationCharacteristics = state => state.creationCharacteristics; 9 | const talents = state => state.talents; 10 | 11 | export const strainThreshold = state => calcStrain(state); 12 | 13 | const calcStrain = createSelector( 14 | archetype, 15 | archetypes, 16 | talents, 17 | creationCharacteristics, 18 | talentCount, 19 | equipmentStats, 20 | ( 21 | archetype, 22 | archetypes, 23 | talents, 24 | creationCharacteristics, 25 | talentCount, 26 | equipmentStats 27 | ) => { 28 | const startingThreshold = get( 29 | archetypes, 30 | `${archetype}.strainThreshold`, 31 | 0 32 | ), 33 | startingWillpower = get(archetypes, `${archetype}.Willpower`, 0), 34 | creationWillpower = get(creationCharacteristics, 'Willpower', 0); 35 | 36 | //get all talents that modify strain 37 | const talentModifier = Object.keys(talentCount).reduce( 38 | (acc, talent) => { 39 | return ( 40 | acc + 41 | +get(talents, `${talent}.modifier.strainThreshold`, 0) * 42 | talentCount[talent] 43 | ); 44 | }, 45 | 0 46 | ); 47 | 48 | // see if character has "Inorganic" talent 49 | const inorganic = get(archetypes, `${archetype}.talents`, []).includes('Inorganic'); 50 | 51 | //check for Gear 52 | const Gear = Object.keys(equipmentStats) 53 | .map(key => { 54 | const modifier = get( 55 | equipmentStats, 56 | `${key}.modifier.strainThreshold`, 57 | 0 58 | ), 59 | carried = get(equipmentStats, `${key}.carried`, false), 60 | equipped = get(equipmentStats, `${key}.equipped`, false), 61 | cybernetics = get(equipmentStats, `${key}.cybernetics`, false), 62 | kind = get(equipmentStats, `${key}.type`, ''); 63 | 64 | if ((carried && kind !== 'armor') || equipped) { 65 | if (inorganic && cybernetics) { 66 | return 0; 67 | } 68 | return +modifier; 69 | } else { 70 | return 0; 71 | } 72 | }) 73 | .reduce((acc, num) => acc + num, 0); 74 | return ( 75 | startingThreshold + 76 | startingWillpower + 77 | creationWillpower + 78 | talentModifier + 79 | Gear 80 | ); 81 | } 82 | ); 83 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/talentCount.tsx: -------------------------------------------------------------------------------- 1 | import { createSelector } from 'reselect'; 2 | 3 | const masterTalents = state => state.masterTalents; 4 | export const talentCount = state => calcTalentCount(state); 5 | 6 | const calcTalentCount = createSelector(masterTalents, masterTalents => { 7 | const count = {}; 8 | Object.keys(masterTalents).forEach(row => { 9 | Object.keys(masterTalents[row]).forEach(tier => { 10 | const talent = masterTalents[row][tier]; 11 | if (talent !== '') { 12 | count[talent] = count[talent] ? count[talent] + 1 : 1; 13 | } 14 | }); 15 | }); 16 | return count; 17 | }); 18 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/totalEncumbrance.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { equipmentStats } from './equipmentStats'; 4 | 5 | export const totalEncumbrance = state => calcTotalEncumbrance(state); 6 | 7 | const calcTotalEncumbrance = createSelector(equipmentStats, equipmentStats => { 8 | let encumbrance = 0; 9 | Object.keys(equipmentStats).forEach(key => { 10 | const carried = get(equipmentStats, `${key}.carried`, false), 11 | equipped = get(equipmentStats, `${key}.equipped`, false), 12 | type = get(equipmentStats, `${key}.type`, ''), 13 | itemEncumbrance = get(equipmentStats, `${key}.encumbrance`, 0); 14 | if (carried) { 15 | encumbrance += itemEncumbrance; 16 | if (type === 'armor' && equipped) { 17 | encumbrance -= itemEncumbrance < 3 ? itemEncumbrance : 3; 18 | } 19 | } 20 | }); 21 | return encumbrance; 22 | }); 23 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/totalSoak.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { characteristics } from './characteristics'; 4 | import { equipmentStats } from './equipmentStats'; 5 | import { talentCount } from './talentCount'; 6 | 7 | const archetype = state => state.archetype; 8 | const archetypes = state => state.archetypes; 9 | const archetypeTalents = state => state.archetypeTalents; 10 | const talents = state => state.talents; 11 | const armor = state => state.armor; 12 | 13 | export const totalSoak = state => calcTotalSoak(state); 14 | 15 | const calcTotalSoak = createSelector( 16 | archetype, 17 | archetypes, 18 | talents, 19 | armor, 20 | archetypeTalents, 21 | equipmentStats, 22 | characteristics, 23 | talentCount, 24 | ( 25 | archetype, 26 | archetypes, 27 | talents, 28 | armor, 29 | archetypeTalents, 30 | equipmentStats, 31 | characteristics, 32 | talentCount 33 | ) => { 34 | const Brawn = get(characteristics, 'Brawn', 0); 35 | 36 | //get soak from armor and gear 37 | let Armor = 0; 38 | Object.keys(equipmentStats).forEach(key => { 39 | const carried = get(equipmentStats, `${key}.carried`, false), 40 | equipped = get(equipmentStats, `${key}.equipped`, false), 41 | type = get(equipmentStats, `${key}.type`, ''), 42 | soak = +get(equipmentStats, `${key}.soak`, 0), 43 | modifierSoak = +get(equipmentStats, `${key}.modifier.soak`, 0); 44 | 45 | if (type === 'armor' && equipped) { 46 | Armor += soak; 47 | } 48 | if (type === 'gear' && carried) { 49 | Armor += modifierSoak; 50 | } 51 | }); 52 | 53 | //get soak from Enduring Talent 54 | let talentModifier = 0; 55 | Object.keys(talentCount).forEach( 56 | talent => 57 | (talentModifier += 58 | +get(talents, `${talent}.modifier.soak`, 0) * 59 | talentCount[talent]) 60 | ); 61 | 62 | //get soak from archetype 63 | let archetypeModifier = 0; 64 | const archTalents = get(archetypes, `${archetype}.talents`, []); 65 | archTalents.forEach( 66 | key => 67 | (archetypeModifier += +get( 68 | archetypeTalents, 69 | `${key}.modifier.soak`, 70 | 0 71 | )) 72 | ); 73 | 74 | return Brawn + Armor + talentModifier + archetypeModifier; 75 | } 76 | ); 77 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/totalXP.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | 4 | const archetype = state => state.archetype; 5 | const archetypes = state => state.archetypes; 6 | const earnedXP = state => state.earnedXP; 7 | 8 | export const totalXP = state => calcTotalXP(state); 9 | 10 | const calcTotalXP = createSelector( 11 | archetype, 12 | archetypes, 13 | earnedXP, 14 | (archetype, archetypes, earnedXP) => 15 | +get(archetypes, `${archetype}.experience`, 0) + +earnedXP 16 | ); 17 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/usedXP.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { archetypeSkillRank } from './archetypeSkillRank'; 4 | import { skillRanks } from './skillRanks'; 5 | 6 | const archetype = state => state.archetype; 7 | const archetypes = state => state.archetypes; 8 | const career = state => state.career; 9 | const careers = state => state.careers; 10 | const careerSkillsRank = state => state.careerSkillsRank; 11 | const creationCharacteristics = state => state.creationCharacteristics; 12 | const masterSkills = state => state.masterSkills; 13 | const masterTalents = state => state.masterTalents; 14 | 15 | export const usedXP = state => calcUsedXP(state); 16 | 17 | const calcUsedXP = createSelector( 18 | masterTalents, 19 | creationCharacteristics, 20 | archetype, 21 | archetypes, 22 | masterSkills, 23 | career, 24 | careers, 25 | careerSkillsRank, 26 | archetypeSkillRank, 27 | skillRanks, 28 | ( 29 | masterTalents, 30 | creationCharacteristics, 31 | archetype, 32 | archetypes, 33 | masterSkills, 34 | career, 35 | careers, 36 | careerSkillsRank, 37 | archetypeSkillRank, 38 | skillRanks 39 | ) => { 40 | //talent XP 41 | let talentXP = 0; 42 | Object.keys(masterTalents).forEach(row => { 43 | Object.keys(masterTalents[row]).forEach(tier => { 44 | if (masterTalents[row][tier] !== '') { 45 | talentXP = talentXP + 5 * +tier; 46 | } 47 | }); 48 | }); 49 | 50 | //skillXP 51 | let skillXP = 0; 52 | Object.keys(masterSkills).forEach(skill => { 53 | const rank = skillRanks[skill], 54 | archSkillRank = get(archetypeSkillRank, `${skill}.rank`, 0); 55 | 56 | for ( 57 | let i = 58 | (careerSkillsRank.includes(skill) ? 1 : 0) + archSkillRank; 59 | rank > i; 60 | i++ 61 | ) { 62 | skillXP += (i + 1) * 5; 63 | } 64 | 65 | skillXP += get(masterSkills, `${skill}.rank`, 0) * 5; 66 | }); 67 | 68 | //characteristicXP 69 | let characteristicXP = 0; 70 | Object.keys(creationCharacteristics).forEach(characteristic => { 71 | const points = get(creationCharacteristics, characteristic, 0), 72 | archCharacteristic = get( 73 | archetypes, 74 | `${archetype}.${characteristic}` 75 | ); 76 | 77 | [...Array(points)].forEach((_, i) => { 78 | characteristicXP += (archCharacteristic + i + 1) * 10; 79 | }); 80 | }); 81 | 82 | return talentXP + skillXP + characteristicXP; 83 | } 84 | ); 85 | -------------------------------------------------------------------------------- /packages/emporium/src/redux/selectors/woundThreshold.tsx: -------------------------------------------------------------------------------- 1 | import { get } from 'lodash-es'; 2 | import { createSelector } from 'reselect'; 3 | import { equipmentStats } from './equipmentStats'; 4 | import { talentCount } from './talentCount'; 5 | 6 | const archetype = state => state.archetype; 7 | const archetypes = state => state.archetypes; 8 | const creationCharacteristics = state => state.creationCharacteristics; 9 | const talents = state => state.talents; 10 | 11 | export const woundThreshold = state => calcWounds(state); 12 | 13 | const calcWounds = createSelector( 14 | archetype, 15 | archetypes, 16 | talents, 17 | creationCharacteristics, 18 | talentCount, 19 | equipmentStats, 20 | ( 21 | archetype, 22 | archetypes, 23 | talents, 24 | creationCharacteristics, 25 | talentCount, 26 | equipmentStats 27 | ) => { 28 | const startingThreshold = get( 29 | archetypes, 30 | `${archetype}.woundThreshold`, 31 | 0 32 | ), 33 | startingBrawn = get(archetypes, `${archetype}.Brawn`, 0), 34 | creationBrawn = get(creationCharacteristics, 'Brawn', 0); 35 | 36 | //get wound modifier from talentModifier 37 | let talentModifier = 0; 38 | Object.keys(talentCount).forEach( 39 | talent => 40 | (talentModifier += 41 | get(talents, `${talent}.modifier.woundThreshold`, 0) * 42 | talentCount[talent]) 43 | ); 44 | 45 | let Gear = 0; 46 | Object.keys(equipmentStats).forEach(key => { 47 | const carried = get(equipmentStats, `${key}.carried`, false), 48 | type = get(equipmentStats, `${key}.type`, ''), 49 | woundThreshold = +get( 50 | equipmentStats, 51 | `${key}.modifier.woundThreshold`, 52 | 0 53 | ); 54 | 55 | if (type === 'gear' && carried) { 56 | Gear += woundThreshold; 57 | } 58 | }); 59 | 60 | return ( 61 | startingThreshold + 62 | startingBrawn + 63 | creationBrawn + 64 | talentModifier + 65 | Gear 66 | ); 67 | } 68 | ); 69 | -------------------------------------------------------------------------------- /packages/emporium/src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-Bold.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-Bold.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-BoldItalic.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-BoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-BoldItalic.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-Italic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-Italic.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-Italic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-Italic.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-Regular.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AGaramondPro-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AGaramondPro-Regular.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AvenirNextLTPro-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AvenirNextLTPro-Bold.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AvenirNextLTPro-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AvenirNextLTPro-Bold.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AvenirNextLTPro-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AvenirNextLTPro-Regular.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/AvenirNextLTPro-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/AvenirNextLTPro-Regular.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BebasNeueBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BebasNeueBold.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BebasNeueBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BebasNeueBold.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BebasNeueRegular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BebasNeueRegular.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BebasNeueRegular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BebasNeueRegular.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/Bolton.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/Bolton.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/Bolton.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/Bolton.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BoltonBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BoltonBold.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BoltonBold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BoltonBold.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BoltonBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BoltonBoldItalic.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BoltonBoldItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BoltonBoldItalic.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BoltonItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BoltonItalic.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/BoltonItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/BoltonItalic.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/CharisSIL-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/CharisSIL-Bold.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/CharisSIL-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/CharisSIL-Bold.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/CharisSIL.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/CharisSIL.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/CharisSIL.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/CharisSIL.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/MinionPro-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/MinionPro-Bold.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/MinionPro-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/MinionPro-Bold.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/MinionPro-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/MinionPro-Regular.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/MinionPro-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/MinionPro-Regular.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/american-captain-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/american-captain-webfont.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/american-captain-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/american-captain-webfont.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/archistico_bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/archistico_bold.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/archistico_bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/archistico_bold.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/archistico_simple.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/archistico_simple.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/archistico_simple.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/archistico_simple.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-bold-webfont.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-bold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-bold-webfont.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-light-webfont.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-light-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-light-webfont.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-medium-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-medium-webfont.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-medium-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-medium-webfont.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-regular-webfont.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-regular-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-regular-webfont.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-semibold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-semibold-webfont.woff -------------------------------------------------------------------------------- /packages/emporium/src/styles/fonts/khand-semibold-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/emporium/src/styles/fonts/khand-semibold-webfont.woff2 -------------------------------------------------------------------------------- /packages/emporium/src/styles/main.scss: -------------------------------------------------------------------------------- 1 | body { 2 | --orange: rgb(255, 122, 22); 3 | --lightblue: rgb(89, 163, 217); 4 | --darkblue: rgb(19, 100, 185); 5 | --gray: rgb(247, 245, 242); 6 | --brown: rgb(179, 151, 123); 7 | --red: rgb(148, 45, 37); 8 | --difficulty: rgb(82, 40, 126); 9 | --challenge: rgb(117, 19, 23); 10 | --boost: rgb(118, 205, 219); 11 | --ability: rgb(70, 172, 78); 12 | --proficiency: rgb(254, 240, 53); 13 | --orangeFade: rgba(255, 122, 22, 0.2); 14 | --lightblueFade: rgba(89, 163, 217, 0.2); 15 | } 16 | 17 | hr { 18 | margin-top: 0.25rem; 19 | margin-bottom: 0.25rem; 20 | border: 0; 21 | border-top: 2px solid rgba(0, 0, 0, 0.1); 22 | } 23 | 24 | table { 25 | vertical-align: middle; 26 | } 27 | 28 | thead { 29 | font-weight: 600; 30 | } 31 | 32 | label { 33 | padding-bottom: 0 !important; 34 | padding-top: 0 !important; 35 | padding-right: 0 !important; 36 | } 37 | 38 | .table th { 39 | padding: 0.4rem; 40 | } 41 | 42 | .table td { 43 | padding: 0.4rem; 44 | } 45 | 46 | .table-dice { 47 | } 48 | 49 | .table-career { 50 | text-align: center; 51 | } 52 | 53 | .table-rank { 54 | text-align: center; 55 | } 56 | 57 | .table-name { 58 | text-align: left; 59 | } 60 | 61 | input[type="number"]::-webkit-outer-spin-button, 62 | input[type="number"]::-webkit-inner-spin-button { 63 | -webkit-appearance: none; 64 | margin: 0; 65 | } 66 | 67 | input[type="number"] { 68 | -moz-appearance: textfield; 69 | } 70 | 71 | .text-pre { 72 | white-space: pre-line; 73 | } 74 | 75 | .w-10 { 76 | width: 10%; 77 | } 78 | 79 | .w-20 { 80 | width: 20%; 81 | } 82 | 83 | .w-30 { 84 | width: 30%; 85 | } 86 | 87 | .w-40 { 88 | width: 40%; 89 | } 90 | 91 | .w-60 { 92 | width: 60%; 93 | } 94 | 95 | .w-70 { 96 | width: 70%; 97 | } 98 | 99 | .w-80 { 100 | width: 80%; 101 | } 102 | 103 | .w-90 { 104 | width: 90%; 105 | } -------------------------------------------------------------------------------- /packages/emporium/src/styles/tabs.scss: -------------------------------------------------------------------------------- 1 | .react-tabs__tab-list { 2 | width: 100%; 3 | text-align: left; 4 | border-bottom: 1px solid #aaa; 5 | margin: 0 0 10px; 6 | padding: 0; 7 | } 8 | 9 | .react-tabs__tab { 10 | display: inline-block; 11 | border: 1px solid transparent; 12 | border-bottom: none; 13 | bottom: -1px; 14 | position: relative; 15 | list-style: none; 16 | padding: 6px 12px; 17 | cursor: pointer; 18 | font-size: 0.8rem; 19 | } 20 | 21 | .react-tabs__tab--selected { 22 | background: var(--gray); 23 | border-color: #aaa; 24 | color: black; 25 | border-radius: 5px 5px 0 0; 26 | } 27 | 28 | .react-tabs__tab--disabled { 29 | color: GrayText; 30 | cursor: default; 31 | } 32 | 33 | .react-tabs__tab:focus { 34 | box-shadow: 0 0 5px hsl(208, 99%, 50%); 35 | border-color: hsl(208, 99%, 50%); 36 | outline: none; 37 | } 38 | 39 | .react-tabs__tab:focus:after { 40 | content: ""; 41 | position: absolute; 42 | height: 5px; 43 | left: -4px; 44 | right: -4px; 45 | bottom: -5px; 46 | background: #fff; 47 | } 48 | 49 | .react-tabs__tab-panel { 50 | display: none; 51 | } 52 | 53 | .react-tabs__tab-panel--selected { 54 | display: block; 55 | } 56 | -------------------------------------------------------------------------------- /packages/emporium/src/styles/themes/kf.scss: -------------------------------------------------------------------------------- 1 | .body-KF { 2 | .vehicleStat-silhouette { 3 | left: 8%; 4 | } 5 | 6 | .vehicleStat-maxSpeed { 7 | left: 24.8%; 8 | } 9 | 10 | .vehicleStat-handling { 11 | left: 41.3%; 12 | } 13 | 14 | .vehicleStat-defense { 15 | top: 32%; 16 | left: 62.5%; 17 | } 18 | 19 | .vehicleStat-armor { 20 | top: 32%; 21 | left: 88%; 22 | } 23 | 24 | .vehicleStat-hullTraumaThreshold { 25 | top: 88%; 26 | left: 58%; 27 | } 28 | 29 | .vehicleStat-currentHullTrauma { 30 | top: 87.3%; 31 | left: 67%; 32 | width: 2.2rem; 33 | font-size: 1.2rem; 34 | height: 29px; 35 | } 36 | 37 | .vehicleStat-systemStrainThreshold { 38 | top: 88%; 39 | left: 84%; 40 | } 41 | 42 | .vehicleStat-currentSystemStrain { 43 | top: 87.3%; 44 | left: 92%; 45 | width: 2.2rem; 46 | font-size: 1.2rem; 47 | height: 29px; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /packages/emporium/src/styles/vehicle.scss: -------------------------------------------------------------------------------- 1 | .VehicleStatBlock { 2 | position: relative; 3 | text-align: center; 4 | color: black; 5 | padding: 0; 6 | margin: 0.15rem; 7 | width: 40rem; 8 | } 9 | 10 | .vehicleStat { 11 | position: absolute; 12 | display: inline-flex; 13 | align-items: center; 14 | transform: translate(-50%, -50%); 15 | flex: unset; 16 | padding: 0 0; 17 | font-weight: bold; 18 | font-size: 1.5rem; 19 | } 20 | 21 | .vehicleStat-silhouette { 22 | top: 27%; 23 | left: 8.5%; 24 | font-size: 2.5rem; 25 | } 26 | 27 | .vehicleStat-maxSpeed { 28 | top: 27%; 29 | left: 24.5%; 30 | font-size: 2.5rem; 31 | } 32 | 33 | .vehicleStat-handling { 34 | top: 27%; 35 | left: 40.9%; 36 | font-size: 2.5rem; 37 | } 38 | 39 | .vehicleStat-defense { 40 | top: 27%; 41 | left: 61.5%; 42 | } 43 | 44 | .vehicleStat-armor { 45 | top: 27%; 46 | left: 85%; 47 | } 48 | 49 | .vehicleStat-hullTraumaThreshold { 50 | top: 78.5%; 51 | left: 57%; 52 | } 53 | 54 | .vehicleStat-systemStrainThreshold { 55 | top: 78.5%; 56 | left: 81%; 57 | } 58 | 59 | .vehicleStat-currentHullTrauma { 60 | top: 77.5%; 61 | left: 65%; 62 | width: 2.2rem; 63 | font-size: 1.2rem; 64 | } 65 | 66 | .vehicleStat-currentSystemStrain { 67 | top: 77.5%; 68 | left: 89%; 69 | width: 2.2rem; 70 | font-size: 1.2rem; 71 | } 72 | 73 | @media only screen 74 | and (max-width: 480px) { 75 | 76 | .VehicleStatBlock { 77 | max-width: 100vw 78 | } 79 | 80 | .vehicleStat-silhouette, 81 | .vehicleStat-maxSpeed, 82 | .vehicleStat-handling { 83 | font-size: 1.5rem; 84 | } 85 | 86 | .vehicleStat-defense, 87 | .vehicleStat-armor, 88 | .vehicleStat-hullTraumaThreshold, 89 | .vehicleStat-systemStrainThreshold { 90 | font-size: 1.0rem; 91 | } 92 | 93 | .vehicleStat-currentHullTrauma, 94 | .vehicleStat-currentSystemStrain { 95 | height: 1rem; 96 | width: 1.8rem; 97 | font-size: 0.8rem; 98 | } 99 | } -------------------------------------------------------------------------------- /packages/emporium/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], 8 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/emporium/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "types": ["node", "jest"] 9 | }, 10 | "files": [ 11 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 12 | "../../node_modules/@nrwl/react/typings/image.d.ts" 13 | ], 14 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/emporium/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.spec.ts", 10 | "**/*.spec.tsx", 11 | "**/*.spec.js", 12 | "**/*.spec.jsx", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/ui/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@nrwl/react/babel"], 3 | "plugins": [] 4 | } 5 | -------------------------------------------------------------------------------- /packages/ui/README.md: -------------------------------------------------------------------------------- 1 | # ui 2 | 3 | This library was generated with [Nx](https://nx.dev). 4 | 5 | ## Running unit tests 6 | 7 | Run `nx test ui` to execute the unit tests via [Jest](https://jestjs.io). 8 | -------------------------------------------------------------------------------- /packages/ui/babel-jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ], 11 | "@babel/preset-typescript", 12 | "@babel/preset-react" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /packages/ui/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | name: 'ui', 3 | preset: '../../jest.config.js', 4 | transform: { 5 | '^.+\\.[tj]sx?$': [ 6 | 'babel-jest', 7 | { cwd: __dirname, configFile: './babel-jest.config.json' }, 8 | ], 9 | }, 10 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'], 11 | coverageDirectory: '../../coverage/packages/ui', 12 | }; 13 | -------------------------------------------------------------------------------- /packages/ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './lib/delete-button/delete-button'; 2 | export * from './lib/control-button-set/control-button-set'; 3 | -------------------------------------------------------------------------------- /packages/ui/src/lib/control-button-set/control-button-set.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/ui/src/lib/control-button-set/control-button-set.scss -------------------------------------------------------------------------------- /packages/ui/src/lib/control-button-set/control-button-set.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import ControlButtonSet from './control-button-set'; 5 | 6 | describe(' ControlButtonSet', () => { 7 | it('should render successfully', () => { 8 | const { baseElement } = render(); 9 | expect(baseElement).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/ui/src/lib/control-button-set/control-button-set.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button, ButtonGroup, Row } from 'reactstrap'; 3 | import './control-button-set.scss'; 4 | 5 | export const ControlButtonSet = ({ 6 | mode, 7 | type, 8 | handleSubmit, 9 | onEditSubmit, 10 | onEditCancel, 11 | disabled 12 | }: { 13 | mode: string; 14 | type: string; 15 | handleSubmit?: any; 16 | onEditSubmit?: any; 17 | onEditCancel?: any; 18 | disabled?: boolean; 19 | }) => { 20 | switch (mode) { 21 | case 'add': 22 | return ( 23 | 24 | 25 | 26 | 29 | 30 | 31 | ); 32 | case 'edit': 33 | return ( 34 | 35 | 36 | 42 | 48 | 49 | 50 | ); 51 | default: 52 | throw new Error('Did not send valid mode to ControlButtonSet.js'); 53 | } 54 | }; 55 | 56 | export default ControlButtonSet; 57 | -------------------------------------------------------------------------------- /packages/ui/src/lib/delete-button/delete-button.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/packages/ui/src/lib/delete-button/delete-button.scss -------------------------------------------------------------------------------- /packages/ui/src/lib/delete-button/delete-button.spec.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from '@testing-library/react'; 3 | 4 | import DeleteButton from './delete-button'; 5 | 6 | describe(' DeleteButton', () => { 7 | it('should render successfully', () => { 8 | const { baseElement } = render(); 9 | expect(baseElement).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/ui/src/lib/delete-button/delete-button.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Button } from 'reactstrap'; 3 | import './delete-button.scss'; 4 | 5 | export class DeleteButton extends React.Component { 6 | public state = { confirmation: false }; 7 | private timer: any = null; 8 | 9 | public confirmDelete = () => { 10 | this.setState({ confirmation: true }); 11 | this.timer = setTimeout( 12 | () => this.setState({ confirmation: false }), 13 | 2000 14 | ); 15 | }; 16 | 17 | public componentWillUnmount() { 18 | clearTimeout(this.timer); 19 | } 20 | 21 | public render() { 22 | if (this.state.confirmation) { 23 | return ( 24 | 27 | ); 28 | } 29 | return ( 30 | 38 | ); 39 | } 40 | } 41 | 42 | export default DeleteButton; 43 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "jsx": "react", 5 | "allowJs": true, 6 | "esModuleInterop": true, 7 | "allowSyntheticDefaultImports": true, 8 | "types": ["node", "jest"] 9 | }, 10 | "files": [ 11 | "../../node_modules/@nrwl/react/typings/cssmodule.d.ts", 12 | "../../node_modules/@nrwl/react/typings/image.d.ts" 13 | ], 14 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 15 | } 16 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "types": ["node"] 6 | }, 7 | "exclude": ["**/*.spec.ts", "**/*.spec.tsx"], 8 | "include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/ui/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "**/*.spec.ts", 10 | "**/*.spec.tsx", 11 | "**/*.spec.js", 12 | "**/*.spec.jsx", 13 | "**/*.d.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /tools/schematics/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Unbound-Legends/RPG-Web-Character-Creator/755e7662f3aebbf8f51eac9a801007096fc259cf/tools/schematics/.gitkeep -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"] 9 | }, 10 | "include": ["**/*.ts"] 11 | } 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "typeRoots": ["node_modules/@types"], 14 | "lib": ["es2017", "dom"], 15 | "skipLibCheck": true, 16 | "skipDefaultLibCheck": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@emporium/ui": ["packages/ui/src/index.ts"], 20 | "@emporium/data": ["packages/emporium/src/assets/data/index.js"], 21 | "@emporium/data-lists": ["packages/emporium/src/assets/data/lists.js"], 22 | "@emporium/images": ["packages/emporium/src/assets/images/index.ts"], 23 | "@emporium/actions": ["packages/emporium/src/redux/actions.tsx"], 24 | "@emporium/reducers": ["packages/emporium/src/redux/reducers.tsx"], 25 | "@emporium/selectors": ["packages/emporium/src/redux/selectors/index.ts"], 26 | "@emporium/firestoreDb": ["packages/emporium/src/app/firestoreDB.js"] 27 | } 28 | }, 29 | "exclude": ["node_modules", "tmp"] 30 | } 31 | --------------------------------------------------------------------------------