├── .browserslistrc
├── src
├── database
│ ├── role_skills.js
│ ├── motivation.json
│ ├── roles.json
│ ├── enemies.json
│ ├── friends.json
│ ├── personality.json
│ ├── romance.json
│ ├── goals.json
│ ├── armor.json
│ ├── weapons.js
│ ├── background.json
│ ├── index.js
│ ├── cyberware.json
│ ├── appearance.json
│ ├── skills.js
│ ├── role_stats.js
│ └── gear.js
├── assets
│ ├── cyberpunk-cp.png
│ ├── sass
│ │ ├── app.scss
│ │ ├── components
│ │ │ ├── _index.scss
│ │ │ ├── _charsheet-header.scss
│ │ │ ├── _header.scss
│ │ │ ├── _select-input.scss
│ │ │ ├── _options-modal.scss
│ │ │ ├── _footer.scss
│ │ │ ├── _button.scss
│ │ │ ├── _lifepath-gen.scss
│ │ │ └── _charsheet.scss
│ │ ├── _base.scss
│ │ ├── _variables.scss
│ │ └── _utils.scss
│ └── fonts
│ │ ├── TwCenMTStd-Bold.woff
│ │ ├── TwCenMTStd-Bold.woff2
│ │ ├── TwCenMTStd-MediumCond.woff
│ │ ├── TwCenMTStd-SemiMedium.woff
│ │ ├── TwCenMTStd-MediumCond.woff2
│ │ └── TwCenMTStd-SemiMedium.woff2
├── store.js
├── main.js
├── router.js
├── App.vue
├── components
│ ├── CharArmor.vue
│ ├── CharSkills.vue
│ ├── CharWeapons.vue
│ ├── CharItems.vue
│ ├── CharHealth.vue
│ ├── CharStyle.vue
│ ├── CharBaseInfo.vue
│ └── CharLifepath.vue
├── views
│ ├── CharGen.vue
│ └── 2020Lifepath.vue
└── character.js
├── babel.config.js
├── postcss.config.js
├── public
├── favicon.ico
└── index.html
├── .gitignore
├── .editorconfig
├── README.md
└── package.json
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 |
--------------------------------------------------------------------------------
/src/database/role_skills.js:
--------------------------------------------------------------------------------
1 | export default {
2 |
3 | }
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/app"]
3 | };
4 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {}
4 | }
5 | };
6 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/assets/cyberpunk-cp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/src/assets/cyberpunk-cp.png
--------------------------------------------------------------------------------
/src/assets/sass/app.scss:
--------------------------------------------------------------------------------
1 | @import "~sass-rem";
2 | @import 'variables';
3 | @import 'utils';
4 | @import 'base';
5 |
6 | @import 'components/index';
7 |
--------------------------------------------------------------------------------
/src/assets/fonts/TwCenMTStd-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/src/assets/fonts/TwCenMTStd-Bold.woff
--------------------------------------------------------------------------------
/src/assets/fonts/TwCenMTStd-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/src/assets/fonts/TwCenMTStd-Bold.woff2
--------------------------------------------------------------------------------
/src/assets/fonts/TwCenMTStd-MediumCond.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/src/assets/fonts/TwCenMTStd-MediumCond.woff
--------------------------------------------------------------------------------
/src/assets/fonts/TwCenMTStd-SemiMedium.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/src/assets/fonts/TwCenMTStd-SemiMedium.woff
--------------------------------------------------------------------------------
/src/assets/fonts/TwCenMTStd-MediumCond.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/src/assets/fonts/TwCenMTStd-MediumCond.woff2
--------------------------------------------------------------------------------
/src/assets/fonts/TwCenMTStd-SemiMedium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benserrette/cyberpunk-red-character-generator/HEAD/src/assets/fonts/TwCenMTStd-SemiMedium.woff2
--------------------------------------------------------------------------------
/src/store.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Vuex from "vuex";
3 |
4 | Vue.use(Vuex);
5 |
6 | export default new Vuex.Store({
7 | state: {},
8 | mutations: {},
9 | actions: {}
10 | });
11 |
--------------------------------------------------------------------------------
/src/assets/sass/components/_index.scss:
--------------------------------------------------------------------------------
1 | @import 'header';
2 | @import 'footer';
3 | @import 'button';
4 | @import 'select-input';
5 | @import 'charsheet';
6 | @import 'charsheet-header';
7 | @import 'lifepath-gen';
8 | @import 'options-modal';
9 |
--------------------------------------------------------------------------------
/src/database/motivation.json:
--------------------------------------------------------------------------------
1 | [
2 | "Money ",
3 | "Honor",
4 | "Your word",
5 | "Honesty ",
6 | "Knowledge ",
7 | "Vengeance ",
8 | "Love",
9 | "Power",
10 | "Having a good time",
11 | "Friendship"
12 | ]
13 |
--------------------------------------------------------------------------------
/src/database/roles.json:
--------------------------------------------------------------------------------
1 | [
2 | "None",
3 | "Rockerboy",
4 | "Solo",
5 | "Netrunner",
6 | "Tech",
7 | "Media",
8 | "Lawman",
9 | "Exec",
10 | "Fixer",
11 | "Nomad",
12 | "Street Scum",
13 | "Booster",
14 | "Private Security"
15 | ]
16 |
--------------------------------------------------------------------------------
/src/assets/sass/components/_charsheet-header.scss:
--------------------------------------------------------------------------------
1 | .charsheet-header {
2 | @extend %cut-corners-box;
3 | @extend %print-remove;
4 |
5 | display: flex;
6 | flex-direction: column;
7 | justify-content: space-between;
8 |
9 | @include breakpoint(tablet) {
10 | flex-direction: row;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
--------------------------------------------------------------------------------
/src/database/enemies.json:
--------------------------------------------------------------------------------
1 | [
2 | "Ex–friend",
3 | "Ex–lover",
4 | "Relative",
5 | "Childhood enemy ",
6 | "Person working for you",
7 | "Person you work for",
8 | "Partner or coworker ",
9 | "Booster gang member ",
10 | "Corporate Exec",
11 | "Government official"
12 | ]
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 |
7 | [*.{js,py}]
8 | charset = utf-8
9 |
10 | [Makefile]
11 | indent_style = tab
12 |
13 | [src/**.{js,vue,scss,json}]
14 | indent_style = space
15 | indent_size = 2
16 |
17 | [package.json]
18 | indent_style = space
19 | indent_size = 2
20 |
--------------------------------------------------------------------------------
/src/database/friends.json:
--------------------------------------------------------------------------------
1 | [
2 | "Like an older sibling to you ",
3 | "Like a younger sibling to you ",
4 | "A teacher or mentor",
5 | "A partner or coworker ",
6 | "A former lover ",
7 | "An old enemy ",
8 | "Like a parent to you ",
9 | "An old childhood friend ",
10 | "A relative ",
11 | "Someone with a common interest"
12 |
13 | ]
--------------------------------------------------------------------------------
/src/assets/sass/components/_header.scss:
--------------------------------------------------------------------------------
1 | .header {
2 | @extend %print-remove;
3 |
4 | background-color: $gray;
5 | text-align: center;
6 | padding: rem(20px) 0;
7 | margin-bottom: rem(20px);
8 |
9 | &__link {
10 | font-family: $font-cond;
11 | font-size: rem(35px);
12 | font-weight: bold;
13 | text-decoration: none;
14 | color: $prime-red;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/database/personality.json:
--------------------------------------------------------------------------------
1 | [
2 | "Shy and secretive ",
3 | "Rebellious, antisocial, violent ",
4 | "Arrogant, proud and aloof ",
5 | "Moody, rash and headstrong ",
6 | "Picky, fussy, and nervous ",
7 | "Stable and serious ",
8 | "Silly and fluff–headed",
9 | "Sneaky and deceptive ",
10 | "Intellectual and detached ",
11 | "Friendly and outgoing"
12 | ]
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VModal from 'vue-js-modal'
3 | import App from "./App.vue";
4 | import router from "./router";
5 | import store from "./store";
6 | // App custom styles
7 | import "./assets/sass/app.scss";
8 |
9 | Vue.config.productionTip = false;
10 |
11 | Vue.use(VModal);
12 |
13 | new Vue({
14 | router,
15 | store,
16 | render: h => h(App)
17 | }).$mount("#app");
18 |
--------------------------------------------------------------------------------
/src/database/romance.json:
--------------------------------------------------------------------------------
1 | [
2 | "Your lover died in an accident. ",
3 | "Your lover mysteriously vanished. ",
4 | "It just didn’t work out. ",
5 | "A personal goal or vendetta came between you and your lover. ",
6 | "Your lover was kidnapped. ",
7 | "Your lover went insane. ",
8 | "Your lover committed suicide.",
9 | "Your lover was killed in a fight.",
10 | "A rival cut you out of the action. ",
11 | "Your lover is imprisoned or exiled"
12 | ]
--------------------------------------------------------------------------------
/src/router.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Router from "vue-router";
3 | import CharGen from "./views/CharGen";
4 | import LifePath from "./views/2020Lifepath";
5 |
6 | Vue.use(Router);
7 |
8 | export default new Router({
9 | mode: "hash",
10 | base: process.env.BASE_URL,
11 | routes: [
12 | {
13 | path: "/lifepath",
14 | name: "lifepath",
15 | component: LifePath
16 | },
17 | {
18 | path: "/:base64?",
19 | name: "home-base64",
20 | component: CharGen
21 | },
22 | ]
23 | });
24 |
--------------------------------------------------------------------------------
/src/database/goals.json:
--------------------------------------------------------------------------------
1 | [
2 | "Get rid of a bad reputation. ",
3 | "Gain power and control.",
4 | "Get off the street no matter what it takes.",
5 | "Cause pain and suffering to anyone who crosses you. ",
6 | "Live down your past life and try to forget it. ",
7 | "Hunt down those responsible for your life and make them pay. ",
8 | "Get what’s rightfully yours. ",
9 | "Save, if possible, anyone else involved in your background. ",
10 | "Gain fame and recognition. ",
11 | "Become feared and respected."
12 | ]
--------------------------------------------------------------------------------
/src/assets/sass/components/_select-input.scss:
--------------------------------------------------------------------------------
1 | .select-input {
2 | appearance: none;
3 | background-color: $medium-red;
4 | border: 2px solid $dark-red;
5 | border-radius: 0;
6 | cursor: pointer;
7 | color: $white;
8 | font-weight: bold;
9 | margin: rem(5px);
10 | // Top padding different to fix for weird font baseline
11 | padding: rem(13px 30px 10px 15px);
12 |
13 | background-image: url($down-caret-icon);
14 | background-size: rem(18px);
15 | background-repeat: no-repeat;
16 | background-position: right rem(10px) top 48%;
17 | }
18 |
--------------------------------------------------------------------------------
/src/assets/sass/components/_options-modal.scss:
--------------------------------------------------------------------------------
1 | .options-modal {
2 | .v--modal-box {
3 | padding: rem(25px 20px 20px);
4 | }
5 |
6 | &__close {
7 | background: none;
8 | border: none;
9 | padding: rem(5px);
10 | position: absolute;
11 | top: rem(5px);
12 | right: rem(5px);
13 | font-weight: bold;
14 | font-size: rem(20px);
15 | color: $prime-red;
16 | }
17 |
18 | &__title {
19 | text-transform: uppercase;
20 | font-size: rem(20px);
21 | }
22 |
23 | &__option {
24 | display: block;
25 | margin: rem(15px) 0;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # cyberpunk_char_gen
2 |
3 | ## Database
4 |
5 | All data is contained in the `/src/database` folder as `json` or `js` files. Names are generated using the [Node Random Name npm package](https://www.npmjs.com/package/node-random-name)
6 |
7 |
8 | ## Project setup
9 | ```
10 | npm install
11 | ```
12 |
13 | ### Compiles and hot-reloads for development
14 | ```
15 | npm run serve
16 | ```
17 |
18 | ### Compiles and minifies for production
19 | ```
20 | npm run build
21 | ```
22 |
23 | ### Customize configuration
24 | See [Configuration Reference](https://cli.vuejs.org/config/).
25 |
--------------------------------------------------------------------------------
/src/database/armor.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "name": "Leathers",
4 | "sp": 4
5 | },
6 | {
7 | "name": "Kevlar",
8 | "sp": 7
9 | },
10 | {
11 | "name": "Bodyweight Suit",
12 | "sp": 11
13 | },
14 | {
15 | "name": "Light Armorjack",
16 | "sp": 11
17 | },
18 | {
19 | "name": "Heavy Armorjack",
20 | "sp": 15
21 | },
22 | {
23 | "name": "MetalGear",
24 | "sp": 25
25 | },
26 | {
27 | "name": "Cloth",
28 | "sp": 0
29 | }
30 | ]
31 |
--------------------------------------------------------------------------------
/src/assets/sass/components/_footer.scss:
--------------------------------------------------------------------------------
1 | .footer {
2 | @extend %print-remove;
3 |
4 | display: flex;
5 | padding: rem(40px) 0 rem(20px);
6 | flex-direction: column;
7 | justify-content: space-between;
8 | align-items: center;
9 | text-align: center;
10 |
11 | &__content {
12 | padding: rem(10px) 0;
13 |
14 | * {
15 | font-family: $font-cond;
16 | }
17 |
18 | p {
19 | color: $dark-gray;
20 | }
21 | }
22 |
23 | @include breakpoint(desktop) {
24 | flex-direction: row;
25 | text-align: left;
26 |
27 | &__content {
28 | padding: 0;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | Cyberpunk Red Character Generator
9 |
10 |
11 |
12 | We're sorry but cyberpunk_char_gen doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cyberpunk_char_gen",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build"
8 | },
9 | "dependencies": {
10 | "core-js": "^2.6.5",
11 | "crypto-js": "^3.1.9-1",
12 | "node-random-name": "^1.0.1",
13 | "vue": "^2.6.10",
14 | "vue-js-modal": "^1.3.33",
15 | "vue-router": "^3.0.3",
16 | "vuex": "^3.0.1"
17 | },
18 | "devDependencies": {
19 | "@vue/cli-plugin-babel": "^3.11.0",
20 | "@vue/cli-service": "^4.2.2",
21 | "sass": "^1.25.0",
22 | "sass-loader": "^7.3.1",
23 | "sass-rem": "^2.0.1",
24 | "vue-template-compiler": "^2.6.10"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/assets/sass/components/_button.scss:
--------------------------------------------------------------------------------
1 | .button {
2 | display: inline-block;
3 | background-color: $medium-red;
4 | border: 2px solid $dark-red;
5 | border-radius: 0;
6 | cursor: pointer;
7 | color: $white;
8 | font-weight: bold;
9 | margin: rem(5px);
10 | // Top padding different to fix for weird font baseline
11 | padding: rem(13px 15px 10px);
12 | transition: background .3s ease,
13 | color .3s ease,
14 | border .3s ease;
15 |
16 | &:hover {
17 | background-color: $dark-red;
18 | }
19 |
20 | &--white {
21 | background-color: $white;
22 | border-color: $gray;
23 | color: $prime-red;
24 |
25 | &:hover {
26 | background-color: $gray;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/components/CharArmor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Armor
4 |
5 |
6 |
7 | Head
8 |
9 |
10 |
11 |
12 | Body
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
--------------------------------------------------------------------------------
/src/assets/sass/components/_lifepath-gen.scss:
--------------------------------------------------------------------------------
1 | .lifepath-gen {
2 | @extend %cut-corners-box;
3 |
4 | &__title {
5 | @extend %box-side-title;
6 | margin-bottom: rem(10px);
7 | }
8 |
9 | &__content {
10 | background-color: $white;
11 | padding: rem(15px);
12 | line-height: 1.2;
13 | }
14 |
15 | &__persons {
16 | break-inside: avoid;
17 | margin-top: rem(15px);
18 | }
19 |
20 | &__persons-title {
21 | color: $white;
22 | font-size: rem(18px);
23 | padding-bottom: rem(5px);
24 | }
25 |
26 | &__persons-list {
27 | background-color: $white;
28 | margin: 0;
29 | padding: rem(15px);
30 |
31 | dt {
32 | font-weight: bold;
33 | }
34 |
35 | dd {
36 | margin-bottom: rem(10px);
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/components/CharSkills.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Skills
4 |
5 |
6 |
{{ skill.name }}
7 |
8 | {{skill.stat}} + {{skill.modifier}}
9 | ({{(parseInt(stats[skill.stat.toLowerCase()]) || 0) + skill.modifier}})
10 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
--------------------------------------------------------------------------------
/src/database/weapons.js:
--------------------------------------------------------------------------------
1 | export default {
2 | "Cyberarm": { special: "Melee", damage: "1d6", cyber: true },
3 | Kinfe: { special: "Melee", damage: "1d6" },
4 | "Big Knucks": { special: "Melee", damage: "1d6", cyber: true},
5 | "Medium Pistol": { damage: "2d6" },
6 | "Medium SMG": { special: "Burst", damage: "2d6" },
7 | Rippers: { special: "Melee", damage: "2d6", cyber: true},
8 | "Slice & Dice": { special: "Melee", damage: "2d6", cyber: true},
9 | "Heavy Pistol": { damage: "3d6" },
10 | "Very Heavy Pistol": { damage: "4d6" },
11 | "Assault Rifle": { special: "Burst", damage: "5d6" },
12 | Shotgun: { damage: "5d6" },
13 | "Missile Launcher": { special: "Explosive", damage: "7d6" },
14 | "C9 Explosive Pack": { special: "Explosive", damage: "8d6" }
15 | };
16 |
--------------------------------------------------------------------------------
/src/components/CharWeapons.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Weapons
4 |
5 |
6 |
7 |
8 | {{ weapon.name }}
9 | {{ weapon.special && ` [${weapon.special}]` }}
10 |
11 |
12 |
13 |
14 | No Weapons.
15 |
16 |
17 |
18 |
19 |
20 |
21 |
27 |
--------------------------------------------------------------------------------
/src/database/background.json:
--------------------------------------------------------------------------------
1 | [
2 | "Your family lost everything through betrayal.",
3 | "Your family lost everything through bad management.",
4 | "Your family was exiled or otherwise driven from their original home/nation/Corporation.",
5 | "Your family is imprisoned and you alone escaped.",
6 | "Your family vanished. You are the only remaining member.",
7 | "Your family was killed and you were the only survivor.",
8 | "Your family is involved in a long–term conspiracy, organization, or association, such as a crime family or revolutionary group.",
9 | "Your family was scattered to the winds due to misfortune.",
10 | "Your family is cursed with a hereditary feud that has lasted for generations.",
11 | " You are the inheritor of a family debt; you must honor this debt before moving on with your life"
12 | ]
--------------------------------------------------------------------------------
/src/components/CharItems.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
27 |
--------------------------------------------------------------------------------
/src/database/index.js:
--------------------------------------------------------------------------------
1 | import armor from "./armor";
2 | import background from "./background";
3 | import cyberware from "./cyberware";
4 | import enemies from "./enemies";
5 | import friends from "./friends";
6 | import goals from "./goals";
7 | import index from "./index";
8 | import motivation from "./motivation";
9 | import personality from "./personality";
10 | import romance from "./romance";
11 | import skills from "./skills";
12 | import weapons from "./weapons";
13 | import role_stats from "./role_stats";
14 | import role_skills from "./role_skills";
15 | import roles from "./roles";
16 | import gear from "./gear";
17 | import appearance from "./appearance";
18 |
19 | export default {
20 | armor,
21 | background,
22 | cyberware,
23 | enemies,
24 | friends,
25 | goals,
26 | index,
27 | motivation,
28 | personality,
29 | romance,
30 | skills,
31 | weapons,
32 | role_stats,
33 | role_skills,
34 | roles,
35 | gear,
36 | appearance
37 | };
38 |
--------------------------------------------------------------------------------
/src/components/CharHealth.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Starting Hit Points
5 |
6 |
7 |
8 |
9 | Seriously Wounded
10 |
11 |
12 |
13 |
14 | Death Save
15 |
16 |
17 |
18 |
19 |
20 |
26 |
--------------------------------------------------------------------------------
/src/assets/sass/_base.scss:
--------------------------------------------------------------------------------
1 | @include font-face('TwCent', 'TwCenMTStd-SemiMedium');
2 | @include font-face('TwCent', 'TwCenMTStd-Bold', 700);
3 | @include font-face('TwCent-Cond', 'TwCenMTStd-MediumCond');
4 |
5 | // Resets
6 | html, * {
7 | font-family: $font;
8 | font-size: 16px; // rem base
9 | -webkit-print-color-adjust: exact;
10 | box-sizing: border-box;
11 | }
12 |
13 | body {
14 | background-color: $white;
15 | margin: 0;
16 | }
17 |
18 | h1,
19 | h2,
20 | h3,
21 | h4,
22 | h5,
23 | h6,
24 | p {
25 | margin: 0
26 | }
27 |
28 | a {
29 | text-decoration: none;
30 | color: $dark-red;
31 | }
32 |
33 | // App container
34 | .container {
35 | width: 100%;
36 | padding-right: 15px;
37 | padding-left: 15px;
38 | margin-right: auto;
39 | margin-left: auto;
40 |
41 | @each $breakpoint, $container-max-width in $max-widths {
42 | @include breakpoint($breakpoint) {
43 | max-width: $container-max-width;
44 | }
45 | }
46 |
47 | @include breakpoint(print) {
48 | max-width: unset;
49 | width: 100% !important;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/components/CharStyle.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Clothes
5 |
6 | {{ !emptyStyle ? appearance.clothes : '' }}
7 |
8 |
9 |
10 |
11 |
Hair
12 |
13 | {{ !emptyStyle ? appearance.hair : '' }}
14 |
15 |
16 |
17 |
18 |
Affectations
19 |
20 | {{ !emptyStyle ? appearance.affectations : '' }}
21 |
22 |
23 |
24 |
25 |
Origin and Lang
26 |
27 | {{ !emptyStyle ? appearance.origin : '' }}
28 |
29 |
30 |
31 |
32 |
33 |
39 |
--------------------------------------------------------------------------------
/src/components/CharBaseInfo.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 | {{character.name}}, {{character && character.role}}
12 | (Reputation: {{ character.reputation }})
13 |
14 |
15 |
16 |
17 | {{ type }}
18 | {{ stat }}
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
32 |
--------------------------------------------------------------------------------
/src/assets/sass/_variables.scss:
--------------------------------------------------------------------------------
1 | // VIEWPORT
2 | $breakpoints: (
3 | base: 0,
4 | mobile: 576px,
5 | tablet: 768px,
6 | desktop: 992px,
7 | wide: 1200px
8 | );
9 |
10 | $max-widths: (
11 | mobile: 540px,
12 | tablet: 720px,
13 | desktop: 960px,
14 | wide: 1140px
15 | );
16 |
17 | // COLORS
18 | $white: rgb(255, 255, 255);
19 | $gray: rgb(230, 230, 230);
20 | $dark-gray: rgb(59, 59, 59);
21 | $black: rgb(0, 0, 0);
22 | $prime-red: rgb(219, 68, 53);
23 | $medium-red: rgb(173, 49, 38);
24 | $dark-red: rgb(150, 28, 17);
25 |
26 |
27 | // FONTS
28 | $font: 'TwCent', 'Arial', sans-serif;
29 | $font-cond: 'TwCent-Cond', 'Arial', sans-serif;
30 |
31 | $down-caret-icon: 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/PjwhRE9DVFlQRSBzdmcgIFBVQkxJQyAnLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4nICAnaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkJz48c3ZnIGhlaWdodD0iNTEycHgiIGlkPSJMYXllcl8xIiB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCA1MTIgNTEyIiB3aWR0aD0iNTEycHgiIHhtbDpzcGFjZT0icHJlc2VydmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik05OC45LDE4NC43bDEuOCwyLjFsMTM2LDE1Ni41YzQuNiw1LjMsMTEuNSw4LjYsMTkuMiw4LjZjNy43LDAsMTQuNi0zLjQsMTkuMi04LjZMNDExLDE4Ny4xbDIuMy0yLjYgIGMxLjctMi41LDIuNy01LjUsMi43LTguN2MwLTguNy03LjQtMTUuOC0xNi42LTE1Ljh2MEgxMTIuNnYwYy05LjIsMC0xNi42LDcuMS0xNi42LDE1LjhDOTYsMTc5LjEsOTcuMSwxODIuMiw5OC45LDE4NC43eiIvPjwvc3ZnPg==';
32 |
--------------------------------------------------------------------------------
/src/database/cyberware.json:
--------------------------------------------------------------------------------
1 | {
2 | "Cyberarm": {
3 | "description": "A Cyberweapon concealed in a cyberarm."
4 | },
5 | "Cyberleg (Paired Jump Boosters)": {
6 | "description": "You can leap 6 m/yds straight up or make a running jump of up to 8 m/yds."
7 | },
8 | "Cyberaudio (Amped Hearing)": {
9 | "description": "Adds +1 to any sound–related Task Check."
10 | },
11 | "Cyberaudio (Radio Link)": {
12 | "description": "Micro radio implant gives you the ability to talk to any receiver on the same band frequency for up to 1 mile/1.6km."
13 | },
14 | "Cyberoptic (Camera)": {
15 | "description": "Images can be recorded on the built–in chip and downloaded to a recorder or Agent."
16 | },
17 | "Cyberoptic (Low Light)": {
18 | "description": "You can see clearly in dim light (faint moonlight, distant street lamps)."
19 | },
20 | "Cyberoptic (Targeting)": {
21 | "description": "A built–in targeting sight allows you to add +1 to Marksmanship."
22 | },
23 | "Interface Plugs": {
24 | "description": "Sockets that allow user to interface with machines and cybertech."
25 | },
26 | "Reflex Boost (Speedware)": {
27 | "description": "You are boosted for five full Turns (+3 to Initiative Checks) before the boost cuts out. You must then wait 2 Turns before reboosting."
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/database/appearance.json:
--------------------------------------------------------------------------------
1 | {
2 | "Clothes": [
3 | "Biker leathers",
4 | "Blue jeans",
5 | "Corporate Suits",
6 | "Jumpsuits",
7 | "Miniskirts",
8 | "High Fashion",
9 | "Cammos",
10 | "Normal clothes",
11 | "Nude",
12 | "Bag Lady chic"
13 | ],
14 | "Hairstyle": [
15 | "Mohawk",
16 | "Long & Ratty",
17 | "Short & Spiked",
18 | "Wild & all over",
19 | "Bald",
20 | "Striped",
21 | "Tinted",
22 | "Neat, short",
23 | "Short, curly",
24 | "Long, straight"
25 | ],
26 | "Affectations": [
27 | "Tatoos",
28 | "Mirrorshades",
29 | "Ritual Scars",
30 | "Spiked gloves",
31 | "Nose Rings",
32 | "Earrings",
33 | "Long fingernails",
34 | "Spike heeled boots",
35 | "Weird Contact Lenses",
36 | "Fingerless gloves"
37 | ],
38 | "Origins": [
39 | "Anglo-American (English)",
40 | "African (Bantu, Fante, Kongo, Ashanti, Zulu, Swahili)",
41 | "Japanese/Korean (Japanese or Korean)",
42 | "Central European/Soviet (Bulgarian, Russian, Czech, Polish, Ukranian, Slovak)",
43 | "Pacific Islander (Microneasian, Tagalog, Polynesian, Malayan, Sudanese, Indonesian, Hawaiian)",
44 | "Chinese/Southeast Asian (Burmese, Cantonese, Mandarin, Thai, Tibetan, Vietnamese)",
45 | "Black American (English, Blackfolk)",
46 | "Hispanic American (Spanish, English)",
47 | "Central /SouthAmerican (Spanish, Portuguese)",
48 | "European (French, German, English, Spanish, Italian, Greek, Danish, Dutch, Norwegian, Swedish, Finnish)"
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/src/assets/sass/_utils.scss:
--------------------------------------------------------------------------------
1 | // Mixin for custom fonts
2 | @mixin font-face($font-family, $font-file, $weight: normal, $style: normal) {
3 | @font-face {
4 | font-family: '#{$font-family}';
5 | src: url('~@/assets/fonts/#{$font-file}.woff') format('woff2'),
6 | url('~@/assets/fonts/#{$font-file}.woff2') format('woff');
7 | font-weight: $weight;
8 | font-style: $style;
9 | }
10 | }
11 |
12 | // Mobile first breakpoint inclusion
13 | @mixin breakpoint($breakpoint) {
14 | @if map-has-key($max-widths, $breakpoint) {
15 | @media (min-width: map-get($max-widths, $breakpoint)) {
16 | @content;
17 | }
18 | } @else if $breakpoint == print {
19 | @media print {
20 | @content;
21 | }
22 | } @else {
23 | @error '`breakpoints()` breakpoint `#{$breakpoint}` not found.';
24 | }
25 | }
26 |
27 | // Placeholder to remove element on print
28 | %print-remove {
29 | @include breakpoint(print) {
30 | display: none !important;
31 | }
32 | }
33 |
34 |
35 | $corner-width: rem(20px);
36 |
37 | // Path for upper right and lower left corners
38 | %cut-path-1 {
39 | clip-path:
40 | polygon(
41 | 0% 0%,
42 | $corner-width 0%,
43 | calc(100% - #{$corner-width}) 0%,
44 | 100% $corner-width,
45 | 100% 100%,
46 | calc(100% - #{$corner-width}) 100%,
47 | $corner-width 100%,
48 | 0% calc(100% - #{$corner-width})
49 | );
50 | }
51 |
52 | // Path for upper left and lower right corners
53 | %cut-path-2 {
54 | clip-path:
55 | polygon(
56 | $corner-width 0%,
57 | 0% $corner-width,
58 | 0% 100%,
59 | calc(100% - #{$corner-width}) 100%,
60 | 100% calc(100% - #{$corner-width}),
61 | 100% 0,
62 | 0 0,
63 | $corner-width 0%
64 | );
65 | }
66 |
67 | // Placeholder for red boxes with cut corners
68 | %cut-corners-box {
69 | @extend %cut-path-1;
70 | position: relative;
71 | background-color: $prime-red;
72 | padding: rem(20px) $corner-width;
73 | margin-bottom: rem(15px);
74 | }
75 |
76 | %box-side-title {
77 | color: $white;
78 | font-weight: bold;
79 | text-transform: uppercase;
80 | font-size: rem(20px);
81 | }
82 |
--------------------------------------------------------------------------------
/src/components/CharLifepath.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
Background
5 |
6 | {{ !emptyLifePath ? lifepath.background : '' }}
7 |
8 |
9 |
10 |
11 |
Motivation
12 |
13 | {{ !emptyLifePath ? lifepath.motivation : '' }}
14 |
15 |
16 |
17 |
18 |
Goals
19 |
20 | {{ !emptyLifePath ? lifepath.goals : '' }}
21 |
22 |
23 |
24 |
25 |
Friends
26 |
27 |
28 |
29 |
33 |
34 | -
35 |
36 |
37 |
38 |
39 |
40 |
Enemies
41 |
42 |
43 |
44 |
48 |
49 | -
50 |
51 |
52 |
53 |
54 |
55 |
Romance
56 |
57 | {{ !emptyLifePath ? lifepath.romance : '' }}
58 |
59 |
60 |
61 |
62 |
Personality
63 |
64 | {{ !emptyLifePath ? lifepath.personality : '' }}
65 |
66 |
67 |
68 |
69 |
70 | Want a more extensive Lifepath?
71 | Check out the 2020 Lifepath Generator
72 |
73 |
74 |
75 |
76 |
77 |
83 |
--------------------------------------------------------------------------------
/src/database/skills.js:
--------------------------------------------------------------------------------
1 | export default {
2 | Perception: {
3 | stat: "INT",
4 | name: "Perception",
5 | description: "Search for the Hidden; Detect Lies, Emotions"
6 | },
7 | Tracking: {
8 | stat: "INT",
9 | name: "Tracking",
10 | description: "Follow a Trail Left Behind"
11 | },
12 | Education: {
13 | stat: "INT",
14 | name: "Education",
15 | description: "Know Sciences, History, Trivia, Current Events"
16 | },
17 | "Local Expert": {
18 | stat: "INT",
19 | name: "Local Expert",
20 | description: "Know Local Area, Local Factions, Agendas —"
21 | },
22 | Interface: {
23 | stat: "NET",
24 | name: "Interface",
25 | description: "Special “hacker” Skill available only to Netrunners"
26 | },
27 | Marksmanship: {
28 | stat: "REF",
29 | name: "Marksmanship",
30 | description: "Fire Ranged Weapons Accurately"
31 | },
32 | Driving: {
33 | stat: "REF",
34 | name: "Driving",
35 | description: "Drive Vehicles Skillfully"
36 | },
37 | Evasion: {
38 | stat: "DEX",
39 | name: "Evasion",
40 | description: "Dodge Attacks You See Coming"
41 | },
42 | Athletics: {
43 | stat: "DEX",
44 | name: "Athletics",
45 | description: "Feats of Strength, General Athleticism."
46 | },
47 | Stealth: {
48 | stat: "DEX",
49 | name: "Stealth",
50 | description: "Hiding and Moving Silently"
51 | },
52 | Brawling: {
53 | stat: "DEX",
54 | name: "Brawling",
55 | description: "Martial Fighting Using The Whole Body"
56 | },
57 | Melee: {
58 | stat: "DEX",
59 | name: "Melee",
60 | description: "Weapon Fighting With Melee Weapons"
61 | },
62 | "Basic Tech": {
63 | stat: "TECH",
64 | name: "Basic Tech",
65 | description: "Identify, Understand, and Repair Electronics"
66 | },
67 | Cybertech: {
68 | stat: "TECH",
69 | name: "Cybertech",
70 | description: "Identify, Understand, and Repair Cybernetics"
71 | },
72 | "First Aid": {
73 | stat: "TECH",
74 | name: "First Aid",
75 | description: "Patch Up Others and Yourself"
76 | },
77 | Bribery: {
78 | stat: "COOL",
79 | name: "Bribery",
80 | description: "Know When, Who and How Much to Bribe"
81 | },
82 | Interrogation: {
83 | stat: "COOL",
84 | name: "Interrogation",
85 | description: "Forcibly Extract Info from People"
86 | },
87 | Persuasion: {
88 | stat: "COOL",
89 | name: "Persuasion",
90 | description: "Convince, Persuade or Influence People"
91 | },
92 | Concentration: {
93 | stat: "WILL",
94 | name: "Concentration",
95 | description: "Focus, Memory, Mental Toughness"
96 | },
97 | Conversation: {
98 | stat: "EMP",
99 | name: "Conversation",
100 | description: "Extract Info Through Careful Conversation"
101 | },
102 | "Human Perception": {
103 | stat: "EMP",
104 | name: "Human Perception",
105 | description: "Read Faces, Bodies to Detect Lies, Emotions"
106 | },
107 | "Play Instrument": {
108 | stat: "EMP",
109 | name: "Play Instrument",
110 | description: "Playing an Instrument and Writing Music"
111 | }
112 | };
113 |
--------------------------------------------------------------------------------
/src/assets/sass/components/_charsheet.scss:
--------------------------------------------------------------------------------
1 | .charsheet {
2 | &-stats {
3 | @extend %cut-corners-box;
4 |
5 | &__name {
6 | color: $white;
7 | font-size: rem(28px);
8 | font-weight: bold;
9 | margin-bottom: rem(10px);
10 | }
11 |
12 | &__top-info {
13 | display: flex;
14 | justify-content: space-between;
15 | }
16 |
17 | &__stats-row,
18 | &__health-row {
19 | display: flex;
20 | justify-content: space-between;
21 | margin-bottom: rem(10px);
22 | }
23 |
24 | &__char-photo {
25 | @extend %cut-path-2;
26 | width: 90px;
27 | background-size: cover;
28 | background-position: center;
29 | margin-right: rem(15px);
30 | margin-bottom: rem(10px);
31 | }
32 |
33 | &__base-info {
34 | flex-grow: 1;
35 | }
36 |
37 | &__data-block {
38 | flex-basis: 100%;
39 | &+& {
40 | margin-left: rem(5px);
41 | }
42 | }
43 |
44 | &__data-info {
45 | appearance: none;
46 | display: block;
47 | width: 100%;
48 | background-color: $white;
49 | color: $black;
50 | text-transform: uppercase;
51 | text-align: center;
52 | padding: rem(8px 0 5px);
53 | border: 3px solid transparent;
54 |
55 | // Fix for input mode
56 | -moz-appearance:textfield;
57 | &::-webkit-outer-spin-button,
58 | &::-webkit-inner-spin-button {
59 | -webkit-appearance: none;
60 | margin: 0;
61 | }
62 |
63 | &--edit {
64 | border-color: $dark-red;
65 | }
66 |
67 | &--type {
68 | font-weight: bold;
69 | }
70 |
71 | &+& {
72 | margin-top: rem(5px);
73 | }
74 | }
75 | }
76 |
77 | &-bottom {
78 | display: flex;
79 | flex: 0 0 auto;
80 | justify-content: space-between;
81 |
82 | @include breakpoint(tablet) {
83 | &__column {
84 | width: calc(50% - #{rem(7.5px)});
85 | }
86 | }
87 |
88 | @include breakpoint(print) {
89 | &__column {
90 | width: calc(50% - #{rem(7.5px)});
91 | }
92 | }
93 | }
94 |
95 | &-skills,
96 | &-lifepath,
97 | &-style,
98 | &-armor,
99 | &-weapons,
100 | &-items {
101 | @extend %cut-corners-box;
102 |
103 | &__title {
104 | @extend %box-side-title;
105 | }
106 | }
107 |
108 | &-skills {
109 | &__skill-block {
110 | flex-basis: calc(33% - #{rem(10px)});
111 | background-color: $white;
112 | margin: rem(5px);
113 | padding: rem(10px) rem(5px);
114 | text-align: center;
115 | cursor: help;
116 | display: flex;
117 | flex-direction: column;
118 | justify-content: space-between;
119 | flex-grow: 0;
120 | }
121 |
122 | &__skill-name {
123 | margin-bottom: rem(5px);
124 | }
125 |
126 | &__content {
127 | display: flex;
128 | flex-wrap: wrap;
129 | margin: 0 rem(-5px);
130 | }
131 | }
132 |
133 | &-lifepath,
134 | &-style {
135 | &__block {
136 | display: flex;
137 | justify-content: space-between;
138 | align-items: center;
139 | margin-bottom: rem(10px);
140 | break-inside: avoid;
141 |
142 | &--hide-print {
143 | @extend %print-remove;
144 | }
145 |
146 | &:last-child {
147 | margin-bottom: 0;
148 | }
149 | }
150 |
151 | &__title {
152 | width: rem(150px);
153 | margin: 0;
154 | }
155 |
156 | &__content {
157 | display: flex;
158 | align-items: center;
159 | flex-grow: 1;
160 | padding: rem(5px);
161 | background-color: $white;
162 | flex-basis: calc(100% - #{rem(175px)});
163 | min-height: rem(60px);
164 |
165 | ol {
166 | padding-left: rem(13px);
167 | }
168 | }
169 |
170 | &__more {
171 | color: $white;
172 | text-align: center;
173 | width: 100%;
174 | padding-top: rem(10px);
175 |
176 | a {
177 | color: $gray;
178 | text-decoration: underline;
179 | }
180 | }
181 | }
182 |
183 | &-armor,
184 | &-weapons {
185 | $block: &;
186 |
187 | display: flex;
188 | justify-content: space-between;
189 | align-items: center;
190 |
191 | &__table {
192 | width: 100%;
193 | margin-left: rem(10px);
194 | border: 5px solid transparent;
195 |
196 | th,
197 | td {
198 | text-align: left;
199 | background-color: $white;
200 | padding: rem(10px 5px 7px);
201 | }
202 |
203 | th {
204 | width: rem(70px);
205 | }
206 |
207 | #{$block}__info-number {
208 | text-align: center;
209 | width: rem(60px);
210 | }
211 | }
212 | }
213 |
214 | &-items {
215 | display: flex;
216 | justify-content: space-between;
217 | align-items: flex-start;
218 |
219 | &__title {
220 | text-align: center;
221 | margin-bottom: rem(15px);
222 | }
223 |
224 | &__column {
225 | width: calc(50% - #{rem(2.5px)});
226 | }
227 |
228 | &__item {
229 | background-color: $white;
230 | text-align: center;
231 | padding: rem(20px 15px);
232 | min-height: rem(90px);
233 | display: flex;
234 | flex-direction: column;
235 | justify-content: center;
236 | break-inside: avoid;
237 |
238 | &+& {
239 | margin-top: rem(5px);
240 | }
241 |
242 | h4 {
243 | font-size: rem(18px);
244 | margin-bottom: rem(5px);
245 | }
246 |
247 | p {
248 | font-size: rem(14px);
249 | }
250 | }
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/src/views/CharGen.vue:
--------------------------------------------------------------------------------
1 |
2 |
103 |
104 |
105 |
193 |
--------------------------------------------------------------------------------
/src/character.js:
--------------------------------------------------------------------------------
1 | import Database from "@/database";
2 | import CryptoJS from "crypto-js";
3 | import RandomName from "node-random-name";
4 | // console.debug(Database);
5 |
6 | function random(max, min) {
7 | max = max || 1;
8 | min = min || 0;
9 | return Math.floor(Math.random() * max + min);
10 | }
11 |
12 | function getRandom(database, sub) {
13 | let item = undefined;
14 | try {
15 | let d = Database[database] || Database[database + "s"];
16 | if(sub)
17 | {
18 | d = d[sub];
19 | }
20 | if (d.length) {
21 | let index = random(d.length);
22 | item = d[index];
23 | } else if (typeof d == "object") {
24 | let keys = Object.keys(d);
25 | let key = keys[random(keys.length)];
26 | item = {
27 | name: key,
28 | ...d[key]
29 | };
30 | }
31 | } catch (e) {
32 | console.error(e);
33 | }
34 | // console.debug(item);
35 | return item;
36 | }
37 |
38 | function setHas(set, name) {
39 | for (let item in set) {
40 | if (item.name == name) {
41 | return true;
42 | }
43 | }
44 | return false;
45 | }
46 |
47 | function Character(settings) {
48 | let return_obj = {};
49 | if (typeof settings == "string") {
50 | return_obj = this.decode64(settings);
51 | } else {
52 | settings = settings || {};
53 | let role = settings.role || getRandom("roles");
54 |
55 | let name = RandomName();
56 |
57 | let stats = {};
58 | // console.debug(Database.role_stats[role]);
59 | if (role == "None" || Database.role_stats[role].length == 0) {
60 | stats = {
61 | int: random(10, 1),
62 | ref: random(10, 1),
63 | dex: random(10, 1),
64 | tech: random(10, 1),
65 | cool: random(10, 1),
66 | will: random(10, 1),
67 | luck: random(10, 1),
68 | move: random(10, 1),
69 | body: random(10, 1),
70 | emp: random(10, 1)
71 | };
72 | } else {
73 | let role_stats = Database.role_stats[role];
74 | let roll = random(role_stats.length - 1);
75 | // console.debug(roll);
76 | stats = role_stats[roll];
77 | }
78 |
79 | let weapon_count = random(3);
80 | let skill_count = random(12);
81 | let cyberware_count = random(3);
82 | let gear_count = random(6,1);
83 | // console.debug(role, cyberware_count);
84 |
85 | let starting_hits = Math.ceil(stats.body * 5);
86 | let seriously_wounded = Math.ceil(stats.body * 2.5);
87 | let death_save = stats.body;
88 | let reputation = random(10, 1);
89 |
90 | let skills_set = new Set();
91 | let skill_names = Object.keys(Database.skills);
92 | if (role == "Netrunner") {
93 | skills_set.add("Interface");
94 | }
95 | while (skills_set.size < skill_count) {
96 | let skill_name = skill_names[random(skill_names.length - 1)];
97 | if (skill_name == "Interface") {
98 | continue;
99 | }
100 | skills_set.add(skill_name);
101 | }
102 | let skills = [...skills_set].map(skill_name => {
103 | let skill = Database.skills[skill_name];
104 | skill.modifier = random(10, 1);
105 | return skill;
106 | });
107 | skills = skills.sort((a, b) =>
108 | a.name > b.name ? 1 : b.name > a.name ? -1 : 0
109 | );
110 |
111 | // let gear_set = new Set();
112 | // let gear_names = Object.keys(Database.gear);
113 | // // if (role == "Netrunner") {
114 | // // gear_set.add("Interface");
115 | // // }
116 | // while (gear_set.size < gear_count) {
117 | // let gear_name = gear_names[random(gear_names.length - 1)];
118 | // // if (gear_name == "Interface") {
119 | // // continue;
120 | // // }
121 | // gear_set.add(gear_name);
122 | // }
123 | // let gear = [...gear_set].map(gear_name => {
124 | // let item = Database.gear[gear_name];
125 | // // item.modifier = random(10, 1);
126 | // return item;
127 | // });
128 | // gear = gear.sort((a, b) =>
129 | // a.name > b.name ? 1 : b.name > a.name ? -1 : 0
130 | // );
131 |
132 |
133 | let cyberware_set = new Set();
134 | let cyberware_names = Object.keys(Database.cyberware);
135 | if (role == "Netrunner") {
136 | cyberware_set.add("Interface Plugs");
137 | }
138 | if (role == "Solo") {
139 | cyberware_count += 1;
140 | }
141 | while (cyberware_set.size < cyberware_count) {
142 | let cyberware_name =
143 | cyberware_names[random(cyberware_names.length - 1)];
144 | if (cyberware_name == "Interface Plugs") {
145 | continue;
146 | }
147 | cyberware_set.add(cyberware_name);
148 | }
149 |
150 | let armor = {
151 | head: getRandom("armor"),
152 | body: getRandom("armor")
153 | };
154 |
155 | // let weapons_set = new Set();
156 | let weapons = [];
157 | for (let i = 0; i < weapon_count; i++) {
158 | weapons.push(getRandom("weapons"));
159 |
160 | if (weapons[i].cyber) {
161 | cyberware_set.add("Cyberarm");
162 | }
163 |
164 | // weapons_set.add(weapons[i].name);
165 | }
166 |
167 | if (cyberware_set.has("Cyberarm")) {
168 | if (!setHas(weapons, "Cyberarm")) {
169 | let ca = Database.weapons["Cyberarm"];
170 | ca.name = "Cyberarm";
171 | weapons.push(ca);
172 | }
173 | }
174 |
175 | let cyberware = [...cyberware_set].map(cyberware_name => {
176 | let cyberware = Database.cyberware[cyberware_name];
177 | cyberware.name = cyberware_name;
178 | return cyberware;
179 | });
180 |
181 | cyberware = cyberware.sort((a, b) =>
182 | a.name > b.name ? 1 : b.name > a.name ? -1 : 0
183 | );
184 | weapons = weapons.sort((a, b) =>
185 | a.name > b.name ? 1 : b.name > a.name ? -1 : 0
186 | );
187 |
188 |
189 | // let gear = [];
190 | let gear_set = new Set();
191 | gear_set.add("Agent");
192 | if(role == "Netrunner")
193 | {
194 | gear_set.add("Cyberdeck & Cables");
195 | gear_set.add("Programs");
196 | gear_set.add("Black ICE");
197 | // gear.push({...Database.gear["Cyberdeck & Cables"], name: "Cyberdeck & Cables"});
198 | // gear.push({... Database.gear["Programs"], name: "Programs"});
199 | // gear.push({... Database.gear["Black ICE"], name: "Black ICE"});
200 | }
201 | while(gear_set.size < gear_count)
202 | {
203 | let item = (getRandom("gear"));
204 | if(item.role && item.role != role)
205 | {
206 | continue;
207 | }
208 | gear_set.add(item.name);
209 | }
210 | let gear = [...gear_set].map(gear_name => {
211 | let gear = Database.gear[gear_name];
212 | gear.name = gear_name;
213 | return gear;
214 | });
215 | gear = gear.sort((a, b) =>
216 | a.name > b.name ? 1 : b.name > a.name ? -1 : 0
217 | );
218 |
219 |
220 |
221 | let number_of_friends = random(10, 1) - 7;
222 | let number_of_enemies = random(10, 1) - 5;
223 |
224 | let lifepath = {
225 | background: getRandom("background"),
226 | motivation: getRandom("motivation"),
227 | goals: getRandom("goals"),
228 | friends: [],
229 | enemies: [],
230 | romance: getRandom("romance"),
231 | personality: getRandom("personality")
232 | };
233 |
234 | for (let i = 0; i < number_of_friends; i++) {
235 | lifepath.friends.push(getRandom("friends"));
236 | }
237 | for (let i = 0; i < number_of_enemies; i++) {
238 | lifepath.enemies.push(getRandom("enemies"));
239 | }
240 |
241 | let appearance = {
242 | clothes: getRandom("appearance", "Clothes"),
243 | hair: getRandom("appearance", "Hairstyle"),
244 | affectations: getRandom("appearance", "Affectations"),
245 | origin: getRandom("appearance", "Origins")
246 | };
247 |
248 | return_obj = {
249 | name,
250 | role,
251 | stats,
252 | starting_hits,
253 | seriously_wounded,
254 | death_save,
255 | skills,
256 | armor,
257 | weapons,
258 | cyberware,
259 | gear,
260 | lifepath,
261 | reputation,
262 | appearance
263 | };
264 | }
265 | console.debug(return_obj);
266 | for (let attr in return_obj) {
267 | this[attr] = return_obj[attr];
268 | }
269 |
270 | // console.debug(this);
271 | // console.debug(return_obj);
272 | // return return_obj;
273 | }
274 | Character.prototype.recalculate = function(){
275 | this.starting_hits = Math.ceil(this.stats.body * 5);
276 | this.seriously_wounded = Math.ceil(this.stats.body * 2.5);
277 | this.death_save = this.stats.body;
278 | };
279 | Character.prototype.toString = function() {
280 | return JSON.stringify(this);
281 | };
282 | Character.prototype.encode64 = function() {
283 | //encrypt
284 | let rawStr = JSON.stringify(this);
285 | let wordArray = CryptoJS.enc.Utf8.parse(rawStr);
286 | let base64 = CryptoJS.enc.Base64.stringify(wordArray);
287 | return base64;
288 | };
289 | Character.prototype.decode64 = function(base64) {
290 | //decrypt
291 | try {
292 | let parsedWordArray = CryptoJS.enc.Base64.parse(base64);
293 | let parsedStr = parsedWordArray.toString(CryptoJS.enc.Utf8);
294 | return JSON.parse(parsedStr);
295 | } catch (err) {
296 | console.error(err);
297 | return {};
298 | }
299 | };
300 |
301 | export default Character;
302 |
--------------------------------------------------------------------------------
/src/database/role_stats.js:
--------------------------------------------------------------------------------
1 | export default {
2 | Rockerboy: [
3 | {
4 | int: 5,
5 | ref: 8,
6 | dex: 5,
7 | tech: 4,
8 | cool: 9,
9 | will: 8,
10 | luck: 6,
11 | move: 6,
12 | body: 10,
13 | emp: 6
14 | },
15 | {
16 | int: 5,
17 | ref: 10,
18 | dex: 6,
19 | tech: 3,
20 | cool: 9,
21 | will: 10,
22 | luck: 6,
23 | move: 6,
24 | body: 10,
25 | emp: 4
26 | },
27 | {
28 | int: 6,
29 | ref: 10,
30 | dex: 5,
31 | tech: 3,
32 | cool: 9,
33 | will: 10,
34 | luck: 7,
35 | move: 5,
36 | body: 8,
37 | emp: 5
38 | },
39 | {
40 | int: 6,
41 | ref: 9,
42 | dex: 5,
43 | tech: 6,
44 | cool: 9,
45 | will: 9,
46 | luck: 5,
47 | move: 6,
48 | body: 8,
49 | emp: 4
50 | },
51 | {
52 | int: 5,
53 | ref: 10,
54 | dex: 6,
55 | tech: 3,
56 | cool: 10,
57 | will: 10,
58 | luck: 6,
59 | move: 6,
60 | body: 8,
61 | emp: 4
62 | },
63 | {
64 | int: 6,
65 | ref: 10,
66 | dex: 7,
67 | tech: 4,
68 | cool: 8,
69 | will: 10,
70 | luck: 5,
71 | move: 7,
72 | body: 9,
73 | emp: 5
74 | }
75 | ],
76 | Solo: [
77 | {
78 | int: 5,
79 | ref: 8,
80 | dex: 5,
81 | tech: 4,
82 | cool: 9,
83 | will: 8,
84 | luck: 6,
85 | move: 6,
86 | body: 10,
87 | emp: 6
88 | },
89 | {
90 | int: 5,
91 | ref: 10,
92 | dex: 6,
93 | tech: 3,
94 | cool: 9,
95 | will: 10,
96 | luck: 6,
97 | move: 6,
98 | body: 10,
99 | emp: 4
100 | },
101 | {
102 | int: 6,
103 | ref: 10,
104 | dex: 5,
105 | tech: 3,
106 | cool: 9,
107 | will: 10,
108 | luck: 7,
109 | move: 5,
110 | body: 8,
111 | emp: 5
112 | },
113 | {
114 | int: 6,
115 | ref: 9,
116 | dex: 5,
117 | tech: 6,
118 | cool: 9,
119 | will: 9,
120 | luck: 5,
121 | move: 6,
122 | body: 8,
123 | emp: 4
124 | },
125 | {
126 | int: 5,
127 | ref: 10,
128 | dex: 6,
129 | tech: 3,
130 | cool: 10,
131 | will: 10,
132 | luck: 6,
133 | move: 6,
134 | body: 8,
135 | emp: 4
136 | },
137 | {
138 | int: 6,
139 | ref: 10,
140 | dex: 7,
141 | tech: 4,
142 | cool: 8,
143 | will: 10,
144 | luck: 5,
145 | move: 7,
146 | body: 9,
147 | emp: 5
148 | }
149 | ],
150 | Netrunner: [
151 | {
152 | int: 6,
153 | ref: 7,
154 | dex: 10,
155 | tech: 7,
156 | cool: 8,
157 | will: 4,
158 | luck: 10,
159 | move: 5,
160 | body: 5,
161 | emp: 3
162 | },
163 | {
164 | int: 7,
165 | ref: 10,
166 | dex: 8,
167 | tech: 6,
168 | cool: 10,
169 | will: 3,
170 | luck: 10,
171 | move: 7,
172 | body: 6,
173 | emp: 4
174 | },
175 | {
176 | int: 7,
177 | ref: 9,
178 | dex: 10,
179 | tech: 7,
180 | cool: 8,
181 | will: 6,
182 | luck: 8,
183 | move: 7,
184 | body: 7,
185 | emp: 5
186 | },
187 | {
188 | int: 5,
189 | ref: 10,
190 | dex: 7,
191 | tech: 7,
192 | cool: 10,
193 | will: 4,
194 | luck: 7,
195 | move: 7,
196 | body: 5,
197 | emp: 3
198 | },
199 | {
200 | int: 6,
201 | ref: 9,
202 | dex: 8,
203 | tech: 6,
204 | cool: 8,
205 | will: 5,
206 | luck: 8,
207 | move: 6,
208 | body: 5,
209 | emp: 6
210 | },
211 | {
212 | int: 5,
213 | ref: 9,
214 | dex: 7,
215 | tech: 7,
216 | cool: 8,
217 | will: 6,
218 | luck: 7,
219 | move: 6,
220 | body: 5,
221 | emp: 4
222 | }
223 | ],
224 | Tech: [
225 | {
226 | int: 10,
227 | ref: 10,
228 | dex: 5,
229 | tech: 9,
230 | cool: 3,
231 | will: 5,
232 | luck: 7,
233 | move: 6,
234 | body: 5,
235 | emp: 6
236 | },
237 | {
238 | int: 10,
239 | ref: 7,
240 | dex: 6,
241 | tech: 9,
242 | cool: 3,
243 | will: 5,
244 | luck: 5,
245 | move: 5,
246 | body: 6,
247 | emp: 6
248 | },
249 | {
250 | int: 10,
251 | ref: 7,
252 | dex: 5,
253 | tech: 10,
254 | cool: 4,
255 | will: 3,
256 | luck: 7,
257 | move: 5,
258 | body: 7,
259 | emp: 6
260 | },
261 | {
262 | int: 8,
263 | ref: 8,
264 | dex: 5,
265 | tech: 10,
266 | cool: 4,
267 | will: 4,
268 | luck: 7,
269 | move: 6,
270 | body: 5,
271 | emp: 5
272 | },
273 | {
274 | int: 7,
275 | ref: 7,
276 | dex: 7,
277 | tech: 9,
278 | cool: 4,
279 | will: 3,
280 | luck: 6,
281 | move: 6,
282 | body: 6,
283 | emp: 7
284 | },
285 | {
286 | int: 10,
287 | ref: 10,
288 | dex: 7,
289 | tech: 8,
290 | cool: 4,
291 | will: 5,
292 | luck: 6,
293 | move: 6,
294 | body: 7,
295 | emp: 6
296 | }
297 | ],
298 | Media: [],
299 | Lawman: [],
300 | Exec: [],
301 | Fixer: [
302 | {
303 | int: 7,
304 | ref: 6,
305 | dex: 6,
306 | tech: 3,
307 | cool: 6,
308 | will: 6,
309 | luck: 7,
310 | move: 5,
311 | body: 6,
312 | emp: 10
313 | },
314 | {
315 | int: 9,
316 | ref: 5,
317 | dex: 5,
318 | tech: 5,
319 | cool: 6,
320 | will: 6,
321 | luck: 8,
322 | move: 5,
323 | body: 5,
324 | emp: 10
325 | },
326 | {
327 | int: 7,
328 | ref: 5,
329 | dex: 5,
330 | tech: 5,
331 | cool: 6,
332 | will: 6,
333 | luck: 10,
334 | move: 5,
335 | body: 5,
336 | emp: 9
337 | },
338 | {
339 | int: 7,
340 | ref: 6,
341 | dex: 7,
342 | tech: 7,
343 | cool: 7,
344 | will: 7,
345 | luck: 7,
346 | move: 7,
347 | body: 6,
348 | emp: 8
349 | },
350 | {
351 | int: 10,
352 | ref: 5,
353 | dex: 5,
354 | tech: 5,
355 | cool: 5,
356 | will: 5,
357 | luck: 10,
358 | move: 6,
359 | body: 5,
360 | emp: 9
361 | },
362 | {
363 | int: 9,
364 | ref: 5,
365 | dex: 5,
366 | tech: 5,
367 | cool: 7,
368 | will: 7,
369 | luck: 10,
370 | move: 7,
371 | body: 5,
372 | emp: 9
373 | }
374 | ],
375 | Nomad: [
376 | {
377 | int: 6,
378 | ref: 0,
379 | dex: 9,
380 | tech: 4,
381 | cool: 7,
382 | will: 9,
383 | luck: 7,
384 | move: 7,
385 | body: 5,
386 | emp: 6
387 | },
388 | {
389 | int: 5,
390 | ref: 9,
391 | dex: 7,
392 | tech: 5,
393 | cool: 9,
394 | will: 9,
395 | luck: 9,
396 | move: 7,
397 | body: 7,
398 | emp: 3
399 | },
400 | {
401 | int: 6,
402 | ref: 8,
403 | dex: 8,
404 | tech: 4,
405 | cool: 7,
406 | will: 8,
407 | luck: 8,
408 | move: 5,
409 | body: 7,
410 | emp: 4
411 | },
412 | {
413 | int: 7,
414 | ref: 9,
415 | dex: 7,
416 | tech: 5,
417 | cool: 8,
418 | will: 8,
419 | luck: 8,
420 | move: 7,
421 | body: 7,
422 | emp: 4
423 | },
424 | {
425 | int: 7,
426 | ref: 10,
427 | dex: 9,
428 | tech: 5,
429 | cool: 7,
430 | will: 10,
431 | luck: 10,
432 | move: 7,
433 | body: 7,
434 | emp: 4
435 | },
436 | {
437 | int: 6,
438 | ref: 8,
439 | dex: 9,
440 | tech: 6,
441 | cool: 8,
442 | will: 7,
443 | luck: 8,
444 | move: 7,
445 | body: 5,
446 | emp: 3
447 | }
448 | ],
449 | "Street Scum": [
450 | {
451 | int: 3,
452 | ref: 4,
453 | dex: 7,
454 | tech: 3,
455 | cool: 2,
456 | will: 4,
457 | luck: 0,
458 | move: 4,
459 | body: 4,
460 | emp: 2
461 | }
462 | ],
463 | Booster: [
464 | {
465 | int: 4,
466 | ref: 6,
467 | dex: 8,
468 | tech: 3,
469 | cool: 4,
470 | will: 4,
471 | luck: 0,
472 | move: 4,
473 | body: 6,
474 | emp: 3
475 | }
476 | ],
477 | "Private Security": [
478 | {
479 | int: 5,
480 | ref: 6,
481 | dex: 8,
482 | tech: 3,
483 | cool: 5,
484 | will: 4,
485 | luck: 0,
486 | move: 4,
487 | body: 5,
488 | emp: 3
489 | }
490 | ]
491 | };
492 |
--------------------------------------------------------------------------------
/src/database/gear.js:
--------------------------------------------------------------------------------
1 | export default {
2 | Agent: {
3 | description:
4 | "A pocket-sized machine which functions as a computer and a phone."
5 | },
6 | Guitar: {
7 | description: "Forty’s instrument of choice and most prized possession.",
8 | role: "Rockerboy"
9 | },
10 | "100 Eurobucks": {
11 | description: "A stack of unmarked bills."
12 | },
13 | "Agent w/ Pseudo AI Secretary": {
14 | description:
15 | "A pocket sized machine which functions as a computer and a phone. This Agent has a secretary program."
16 | },
17 | Groundcar: {
18 | description:
19 | "A sedan-style ground card with enough room to hold 6 people."
20 | },
21 | "Cyberdeck & Cables": {
22 | description: "A pocket sized machien used for Netrunning.",
23 | role: "Netrunner"
24 | },
25 | Programs: {
26 | description: "A set of programs for use with a cyberdeck",
27 | role: "Netrunner"
28 | },
29 | "Black ICE": {
30 | description: "A program used with a cyberdeck.",
31 | role: "Netrunner"
32 | },
33 | "Technical Toolbox & Tools": {
34 | description:
35 | "A large box filled with a number of tools to allow you to make repairs on basic tech & cybertech."
36 | },
37 | Motorcycle: {
38 | description: "A street bike with enough room to fit seat two people."
39 | },
40 |
41 | // The clothing styles of 2020 break into five basic fashion statements:
42 | // Generic Chic:
43 | // This is the standard Streetwear, made up of colorful modular components in many colors. Belts, coats, sashes, boots predominate.
44 | // lelsurewear:
45 | // This is the equivalent of 21st century athletic wear. Padded fleece, corporate and athletic logos.
46 | // Buslnesswear:
47 | // This is the equivalent of the standard business suit; understated colors, pinstripes, real leather shoes etc. Wool and other natural fabrics are considered the proper outfitting for the up and coming Corp.
48 | // High Fashion:
49 | // Sophisticated and expensive dressing for the upper class. Designer labels like Miyake, SJ.fui Van, and Anne Calvin.
50 | // Urban Flash:
51 | // Video jackets, colorshift fabrics, cammo, leathers, metal spikes, Logowear, jeans, leather skirts, boots. The wildest and most \ltterly chilled in cyberfashion.
52 |
53 | // Tools
54 |
55 | "Tech scanner": {
56 | description:
57 | "A small handheld microcomp with various 1/0 connecters and probes. Techscanners run diagnostic programs, Identify and examine malfunctioning components, and display internal schematics on a small screen. "
58 | },
59 | "Cutting Torch": {
60 | description:
61 | "Common oxy/acetalyne type out of a bottle. Hand held, about a foot long. More powerful models are available, up to thermite lances at 5x-15x cost. "
62 | },
63 | "Tech Tool Kit": {
64 | description:
65 | "Mixed kit of tools for repair of mechanical items, usually in a 4'x16'x2' case. "
66 | },
67 | "Electronics Kit": {
68 | description:
69 | "Mixed kit of tools for repair of electronic items, usually in a 4'x16'x2' case."
70 | },
71 | "Protective Goggles": {
72 | description:
73 | "Protective eyewear for welding, metal machining work, chemical mixing, etc. "
74 | },
75 | Flashlight: {
76 | description:
77 | "You all know what this is. Beam range 100'-120' Can buy smaller pocket lights (1 /4 range) for half the normal price. "
78 | },
79 | Glowstik: {
80 | description:
81 | "Chemlight in a 6' plastic tube. Shake or break to activate. Soft light lasts up to 6 hours. Comes in green, blue, red. "
82 | },
83 | Flashpaint: {
84 | description:
85 | "Fluorescent paint gives off soft light equal to Glowstik, lasts up to 4 hours. "
86 | },
87 | Flashtape: {
88 | description:
89 | "Flourescent paint gives off soft light equal to Glowstik. Lasts 6 hours, comes in variety of widths. "
90 | },
91 | Rope: {
92 | description:
93 | "Braided synthetics in a variety of thicknesses and weights. Can hold up to 1,000 lbs. "
94 | },
95 | "Breathing Mask": {
96 | description:
97 | "A common painter's style mask; nose and mouth coverage, with two replacable filters (1 eb per 1 0 pack) on the sides. Good for keeping out the smog. "
98 | },
99 | "Personal Electronics Holo Generator": {
100 | description:
101 | "Small box (approx. 4 'x2'x6' inches) projects a holographic picture from a replacable chip. Generator is compatible with chips fcom most digital cameras. Can be linked with a digital Recorder/Player. "
102 | },
103 | // "Video Board": {
104 | // description:
105 | // "monitor using flat-LCD technology. No thicker than an Inch, most video boards are built Into TVs, but all types have Input plugs for use as a readout monitor for other electronic products. large ones (20'x100') are used as advertising signs. Videoboards are bought by the square foot. "
106 | // },
107 | Datachip: {
108 | description:
109 | "The storage medium of the future for holding digital information. Usually plastic-cased, chips come in the shape of buttons, flat squares, and triangular slivers. All shapes can be read by all types of recording media by use of adapter plugs. "
110 | },
111 | Logcompass: {
112 | description:
113 | "A form of programmable inertial compassthat keeps track of your changes in direction from a fixed bearing or point. "
114 | },
115 | "Digital Recorder": {
116 | description:
117 | "Audio recording device using datachip technology, most are the size of two paperback books stacked flat. Some are smaller that a pack of cards. "
118 | },
119 | "Digital Camera": {
120 | description:
121 | "Still images are 'digitized' onto a chip cartridge. About the size of a pack of cigarettes. "
122 | },
123 | VldeoCam: {
124 | description:
125 | "Can be mounted on a headset, a shoulder clamp, or hand-held depending on size (This affects price, size of recorded image, duration of recording time,etc. The price given is for the most inexpensive shoulder-carried model.) Sound and image are usually recorded on a tape·pak that is the size of a card deck or smaller, but you can direct-feed to a transmission device with a set of cables. "
126 | },
127 | "Video/audio Tape Player": {
128 | description:
129 | "This device plays the videocam tape·paks, along with many older-style audio tapes. "
130 | },
131 | "Video Tape": {
132 | description:
133 | "The video tape of 2020 is a high density digital media capable of handling both audio and visual images. "
134 | },
135 | "Pocket TV": {
136 | description:
137 | "Uses a flat-scan screen in a package 5'x5'x3/4\" or smaller. Picks up the majority of VHF, UHF stations. "
138 | },
139 | "Digital Chip Player": {
140 | description:
141 | "This plays audio- and video-recorded chips. You must plug into a video board to play the video track of a digital chip. "
142 | },
143 | "Digital Music Chip": {
144 | description:
145 | "1 to 6 pop album favorites (or any other music) slapped into semiconductors and plastic. These chip are also available in a read-write format as well. "
146 | },
147 | "Electric Guitar": {
148 | description:
149 | 'No longer the classic "axe", it\'s now lighter, more flexible in its applications, and sometimes not even in a recognizable shape. It may have even replaced the strings and frets with a series of key banks! '
150 | },
151 | "Electronic Keyboard": {
152 | description:
153 | "Little changed from the present, except in size and power. "
154 | },
155 | "Drum Synthesizers": {
156 | description:
157 | "Common 'new-wave'music equipment; a series of percussion pads and a sound box. It will fit In a couple of suitcases and can be arranged anyway the drummer plea.ses. "
158 | },
159 | Amplifier: {
160 | description:
161 | "Little changed from the present, except in size and power "
162 | },
163 |
164 | "Laptop Computer": {
165 | description:
166 | "The common portable, with internal hard drive, video board (detachable), and slots for data/ programming chips. These units do not have the advanced CPUs and memory spaces available in a regular computer system; they cannot be used for Netrunning. "
167 | },
168 | "Pocket Computer": {
169 | description:
170 | "The classic 6'x3'x1 /2' programmable calculator with keyboard and chip slots, up to 100 pages of alphanumeric memory."
171 | },
172 |
173 | Cybermodem: { description: "see Netrunning section. Cellular Cybermodem" },
174 | "Interface Cables": {
175 | description:
176 | "Typical plug ended splicing cables going from a cyber-operated machine to a person's interface sockets. "
177 | },
178 | "Low Impedance Cables": {
179 | description:
180 | "Special low-resistance/interferance cables for improved data transfer; they confer a + 1 bonus on any interfacing tasks, such as controlling cybervehicles or Netrunning."
181 | },
182 | "Trode Set": {
183 | description:
184 | "A low efficency headset for 'piggybacking' in the Net. -2 to Interface skill."
185 | },
186 | Keyboard: {
187 | description:
188 | "Can be accessorized to your cybermodem or other electronic equipment."
189 | },
190 | Terminal: {
191 | description:
192 | 'A computer workstation including keyboard, video board, and 1/0 connectors. A terminal can be used to Netrun (making the runner immune to most Black software), but is very, very slow (-5 to Interface Skills). Terminal operators are commonly known as "net-tortoises"'
193 | },
194 |
195 | "Communications Mastoid Commo": {
196 | description:
197 | "All commos are radio transceivers. This one is glued to the jaw and temple; you send via subvocalization and receive with soundless vibrations. Range 10 miles. "
198 | },
199 | "Pocket Commo": {
200 | description: "A typical small walkie-talkie. Range 10 miles. "
201 | },
202 | Blnoculars: { description: "'Nuff said." },
203 | Binoglasses: {
204 | description:
205 | "These high-tech . vision aids combine binocular effects with a laser rangefinder, and sometimes IR lenses. More expensive versions will have a digital camera built in. "
206 | },
207 | "LB Goggles": {
208 | description:
209 | "Light intensification goggles boost ambient light for night vision via 'Starlite' technology. Goggles can be overwhelmed by sudden light level increase. With tuning (DIFFICULT task), they can also detect active IR beams. "
210 | },
211 | "IR Goggles": {
212 | description:
213 | "These pick up hazy, background Infrared sources. Normally used with an active IR source for invisible illumination. "
214 | },
215 | "IR Flashlight": {
216 | description:
217 | "These pick up hazy, background Infrared sources. UV flash is similar; also useable with the proper cyberoptic. "
218 | },
219 |
220 | "Cardlock Decryptor": {
221 | description:
222 | "The probe of this device is inserted into a card lock instead of the normal card. A Decrypt or operates by adding +5 to your bas· TECH+Eiectronic Security+ 1d10 skill check against the lock. "
223 | },
224 | VocDecryptor: {
225 | description:
226 | "A vocal modulator for penetrating vocolocks. See above. A Decrypt or operates by adding +5 to your bas· TECH+Eiectronic Security+ 1d10 skill check against the lock. "
227 | },
228 | "Security Scanner": {
229 | description:
230 | "This device searches out electromagnetic fields generated by various alarm systems (75% chance of location). A TECH or INT roll may be needed to identify the style of alarm encountered. "
231 | },
232 | "Polson Sniffer": {
233 | description:
234 | "Can be set to check air or liquid for a specific poison(s). Otherwise, it will simply alert you to foreign substances. 85% accuracy. "
235 | },
236 | "Jamming Transmitter": {
237 | description:
238 | "Usually comes in 2 or 3 large cases, but can fill an entire van. jams electromagetic transmissions in a 1 000 foot area (that includes cellular phones and some cyberware). "
239 | },
240 | "Scanner Plate": {
241 | description:
242 | "A reading device for palmprint locks. Can be attached to any type of Card or Voclock to add an extra layer of security. "
243 | },
244 | "Movement Sensor": {
245 | description:
246 | "A typical alarm system. Covers seismic, sonar, and fixed IR or visible light networks. Detects movement in a defined area, with a 95% reliability. The sensory processro is about the size of a pack of cigarettes. "
247 | },
248 | Passcard: {
249 | description: "The most common unlocking device for a cardlock. "
250 | },
251 | "Tracking Device": {
252 | description:
253 | "Hand held or suitcased equipment for detecting/following tracer buttons. Range is 1 mile. "
254 | },
255 | "Tracer Buttons": {
256 | description:
257 | "Can be any size from a matchbook to a pin. Uses radioactivity or constant/pulsed radio transmission to pinpoint who or what it's attached to. Some can be turned on/off remotely. Usually bought in sets of 6. "
258 | },
259 | Handcuffs: {
260 | description:
261 | "Just what it says. Probably a little stronger (a NEARLY IMPOSSIBLE task to break) due to new alloys. Often (50%) opened with a form of cardlock. "
262 | },
263 | "Striptape Binders": {
264 | description:
265 | "Great for riot control. One-use-only plastic locking strips for temporary handcuffs and leg ties (VERY DIFFICULT to break). With ceramic fibers to resist cutting, and guaranteed fireproof. Come in boxes of 12. "
266 | },
267 |
268 | "Dermal Stapler": {
269 | description:
270 | "This automatically pulls the sides of a wound together and sutures it with staples of a compressed organic material that dissolves after an elapsed time. "
271 | },
272 | "Spray Skin": {
273 | description:
274 | "A putty-like spray gel for treatment of severe abrasions. Antiseptic and sterile, it's also air permeable and flakes off in about two weeks. "
275 | },
276 |
277 | Cryotank: {
278 | description:
279 | "An advanced refrigeration tank; the cryotank will cool a body down to preservation levels while life-support machines maintain the blood/oxygen flow. Designed to keep a dying body In relative stasis. "
280 | },
281 | Medkit: {
282 | description:
283 | "Standard doctor's or military corpsman's bag. It contains antidotes, dressings, drugs, applicators, medicines, and examining Instruments (probes, depressors, ocular light, stethoscope). "
284 | },
285 | "Surgical Set": {
286 | description:
287 | "A full set of surgeon's tools (scalpel, retractor, probe, damp, tweezer, etc.}, and chemicals or equipment for maintaining a sterile operating field. "
288 | },
289 | "First Aid Kit": {
290 | description:
291 | "The common household medic's box. It has bandages, antiseptics, and a simple painkiller. "
292 | },
293 | "Slap Patch": {
294 | description:
295 | "A small plutic pad containing a measured amount of medicine. The pad Is applied to the skin and the mediclne Is absorbed in steady doses. See the Trouma Team section for drugs and prices. "
296 | },
297 | Airhypo: {
298 | description:
299 | "The 'Bones McCoy' uses a quick burst of compressed air to force a liquid drug through the skin. See the Trauma Team section for drugs and prices. "
300 | },
301 | Medscanner: {
302 | description:
303 | "Readouts for body temperature, heartrate, blood pressure, respiration, and blood sugar levels. A small chipped database adds a +2 to your Diagnose Skill. "
304 | },
305 | "Drug Analyser": {
306 | description:
307 | "Ranging in size from a book to a briefcase, this gaget operates in a manner simular to the chemical sniffer. It will determine the purity of a drug with a known composition, or ldentfy the molecular makeup and possible effects of an unknown substance that is simular to a drug already programmed into its library. "
308 | },
309 |
310 | Scooter: {
311 | description:
312 | "This is an updated, electrically powered version of the old Riva and Vespa motorscooters of the 1990's. Top speed about 50 mph, scooters can get about 6 hours of travel per fastcharge (about 5 minutes at any service station). "
313 | },
314 |
315 | CityCar: {
316 | description:
317 | "One man (two In a pinch), three wheelers common in the Corporate Zones. Top speed about 40mph, with 4 hours travel per fastcharge. CityCars can also be rented (2· .. eb per mile) from convenient kiosks located around most corporate areas; you use your debit card to rent from the vendor, drive where you want, and drop the car off at the nearest vendor."
318 | },
319 | "Small Subcompact": {
320 | description:
321 | "Usually methanol or CHOOH2 powered, these vehicles have a top speed of around 90mph, a ten gallon tank and seat four in relative comfort."
322 | },
323 | "Medium Sedan": {
324 | description:
325 | "Methanol or CHOOH2 powered, these vehicles have a top speed of around 90mph, a fifteen gallon tank and seat four."
326 | },
327 | Sportscar: {
328 | description:
329 | "Almost always CHOOH2 powered (electrics /ust don't have the speed). Top speed about21 0, with a ten ga ion tank. Seats 2."
330 | },
331 | "Luxury Sedan": {
332 | description:
333 | "MethanolorCHOOH2 powered, these vehicles have a top speed of around 90mph, a twenty gallon tank and seat six."
334 | },
335 | Fastcharge: {
336 | description:
337 | "Rapid (S minutes) battery-recharge for electric vehicles. Available at most service stations for 20 eb per charge."
338 | },
339 | CHOOH2: {
340 | description:
341 | "Synthetic meta-alcohol fuel. About 1 D6/3+ 1 euro per gallon (the cost fluctuates wildly due to supply, demand and ceo-terrorist activities)."
342 | },
343 |
344 | Kibble: {
345 | description:
346 | "A mass-produced nutrient that satisfies most requirements for sustenance, but tends to look, smell, and tute like the dry pet food it takes its name from."
347 | },
348 | "Generic Prepack": {
349 | description:
350 | "A step up from the common TV dinner, thesemealpac.kscanbemkrowavedorrelrigerateddepending on What's inside. Many come with their own chemtabs for heating or cooling. The cuisine isn't inspired, but it beats kibble."
351 | },
352 | "Good Prepack": {
353 | description:
354 | "Good restaurant meals in a package. The best quality pre·made meals you're going to find. For anything better, eat out, or prep It yourself (and who really knows how to do that anymore?)."
355 | },
356 | Fresh: {
357 | description:
358 | "You know what that Is. Well, at least you've met someone who's eaten it."
359 | }
360 | };
361 |
--------------------------------------------------------------------------------
/src/views/2020Lifepath.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | Cyberpunk 2020 Lifepath Generator
4 |
5 |
6 |
7 |
Friends
8 |
9 |
10 |
11 |
12 |
13 |
14 |
No friends
15 |
16 |
17 |
18 |
Enemies
19 |
20 |
21 |
22 |
23 |
24 |
25 |
No enemies
26 |
27 |
28 |
29 |
Lovers
30 |
31 |
32 |
33 |
34 |
35 |
36 |
No lovers
37 |
38 |
39 |
40 |
41 |
42 |
748 |
--------------------------------------------------------------------------------