61 Commits

Author SHA1 Message Date
f2fb0eb804 Merge pull request 'Configure Renovate' (#1) from renovate/configure into master
Some checks failed
Codacy Security Scan / Codacy Security Scan (push) Failing after 3m31s
Node.js CI / test (15.x) (push) Failing after 3m33s
Node.js CI / deploy (push) Has been skipped
CodeQL / Analyze (javascript) (push) Failing after 2m24s
Reviewed-on: #1
2025-07-19 12:54:23 +02:00
31b11e7c2b Add renovate.json 2025-07-19 06:32:07 +00:00
17fcf4ec52 Bump nedb-promises from 5.0.3 to 6.0.3 (#158)
Bumps [nedb-promises](https://github.com/bajankristof/nedb-promises) from 5.0.3 to 6.0.3.
- [Release notes](https://github.com/bajankristof/nedb-promises/releases)
- [Changelog](https://github.com/bajankristof/nedb-promises/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bajankristof/nedb-promises/commits)

---
updated-dependencies:
- dependency-name: nedb-promises
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 08:40:48 +00:00
99b95714fb Bump @types/jest from 27.4.0 to 27.4.1 (#157)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 27.4.0 to 27.4.1.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 08:38:39 +00:00
53c30cee50 Bump eslint-config-prettier from 8.3.0 to 8.5.0 (#155)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 8.3.0 to 8.5.0.
- [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v8.3.0...v8.5.0)

---
updated-dependencies:
- dependency-name: eslint-config-prettier
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 10:36:50 +02:00
2935714cde Bump eslint from 8.6.0 to 8.13.0 (#154)
Bumps [eslint](https://github.com/eslint/eslint) from 8.6.0 to 8.13.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.6.0...v8.13.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 08:36:22 +00:00
5f18f32bcf Bump babel-jest from 27.4.6 to 27.5.1 (#146)
Bumps [babel-jest](https://github.com/facebook/jest/tree/HEAD/packages/babel-jest) from 27.4.6 to 27.5.1.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v27.5.1/packages/babel-jest)

---
updated-dependencies:
- dependency-name: babel-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 08:34:28 +00:00
a592002172 Bump dotenv from 10.0.0 to 16.0.0 (#143)
Bumps [dotenv](https://github.com/motdotla/dotenv) from 10.0.0 to 16.0.0.
- [Release notes](https://github.com/motdotla/dotenv/releases)
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v10.0.0...v16.0.0)

---
updated-dependencies:
- dependency-name: dotenv
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 10:34:16 +02:00
255723ff8c Bump jest from 27.4.7 to 27.5.1 (#147)
Bumps [jest](https://github.com/facebook/jest) from 27.4.7 to 27.5.1.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v27.4.7...v27.5.1)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 10:33:59 +02:00
91d299e70b Bump minimist from 1.2.5 to 1.2.6 (#153)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-04-10 10:31:24 +02:00
05674703bf replace got with working version 11.8 (#149) 2022-02-22 17:10:53 +00:00
19d9ac4c22 Bump jest from 27.4.5 to 27.4.7 (#131)
Bumps [jest](https://github.com/facebook/jest) from 27.4.5 to 27.4.7.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v27.4.5...v27.4.7)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-09 13:30:48 +00:00
c2ccabe0f1 Bump babel-jest from 27.4.5 to 27.4.6 (#130)
Bumps [babel-jest](https://github.com/facebook/jest/tree/HEAD/packages/babel-jest) from 27.4.5 to 27.4.6.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v27.4.6/packages/babel-jest)

---
updated-dependencies:
- dependency-name: babel-jest
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-09 14:28:04 +01:00
d59b897e15 Bump eslint from 8.5.0 to 8.6.0 (#129)
Bumps [eslint](https://github.com/eslint/eslint) from 8.5.0 to 8.6.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v8.5.0...v8.6.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-09 14:27:55 +01:00
ead6baab83 Bump nedb-promises from 5.0.1 to 5.0.3 (#126)
Bumps [nedb-promises](https://github.com/bajankristof/nedb-promises) from 5.0.1 to 5.0.3.
- [Release notes](https://github.com/bajankristof/nedb-promises/releases)
- [Changelog](https://github.com/bajankristof/nedb-promises/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bajankristof/nedb-promises/commits)

---
updated-dependencies:
- dependency-name: nedb-promises
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-31 12:56:17 +01:00
96f0ed8401 Bump @types/jest from 27.0.3 to 27.4.0 (#128)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 27.0.3 to 27.4.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-31 12:56:01 +01:00
aa89a0458e security audit (#123)
Co-authored-by: Marcus Netz <marcus.netz@godyo.com>
2021-12-23 09:06:36 +00:00
8531755426 Bump eslint from 7.32.0 to 8.5.0 (#121)
Bumps [eslint](https://github.com/eslint/eslint) from 7.32.0 to 8.5.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.32.0...v8.5.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-23 07:57:59 +00:00
05c64549e4 Bump jest from 27.2.4 to 27.4.5 (#120)
Bumps [jest](https://github.com/facebook/jest) from 27.2.4 to 27.4.5.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v27.2.4...v27.4.5)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-23 07:55:32 +00:00
ca373dcb73 Bump @types/jest from 27.0.2 to 27.0.3 (#122)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 27.0.2 to 27.0.3.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-23 07:55:04 +00:00
ae7443c0cc Bump eslint-config-airbnb from 18.2.1 to 19.0.2 (#114)
Bumps [eslint-config-airbnb](https://github.com/airbnb/javascript) from 18.2.1 to 19.0.2.
- [Release notes](https://github.com/airbnb/javascript/releases)
- [Commits](https://github.com/airbnb/javascript/compare/eslint-config-airbnb-v18.2.1...eslint-config-airbnb-v19.0.2)

---
updated-dependencies:
- dependency-name: eslint-config-airbnb
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-12-23 08:52:38 +01:00
6683056a1c Bump nedb-promises from 4.1.5 to 5.0.1 (#86)
Bumps [nedb-promises](https://github.com/bajankristof/nedb-promises) from 4.1.5 to 5.0.1.
- [Release notes](https://github.com/bajankristof/nedb-promises/releases)
- [Changelog](https://github.com/bajankristof/nedb-promises/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bajankristof/nedb-promises/commits)

---
updated-dependencies:
- dependency-name: nedb-promises
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-07 20:15:16 +02:00
610868b885 Bump eslint-plugin-prettier from 3.4.0 to 4.0.0 (#83)
Bumps [eslint-plugin-prettier](https://github.com/prettier/eslint-plugin-prettier) from 3.4.0 to 4.0.0.
- [Release notes](https://github.com/prettier/eslint-plugin-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-plugin-prettier/blob/master/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-plugin-prettier/commits/v4.0.0)

---
updated-dependencies:
- dependency-name: eslint-plugin-prettier
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-07 20:12:40 +02:00
36eaec155c Bump jest from 27.0.6 to 27.2.4 (#93)
Bumps [jest](https://github.com/facebook/jest) from 27.0.6 to 27.2.4.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v27.0.6...v27.2.4)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-07 18:05:43 +00:00
44324d7bf5 Bump @types/jest from 26.0.24 to 27.0.2 (#88)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.24 to 27.0.2.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-07 18:02:01 +00:00
8ac2eca437 Bump babel-jest from 27.0.6 to 27.2.4 (#91)
Bumps [babel-jest](https://github.com/facebook/jest/tree/HEAD/packages/babel-jest) from 27.0.6 to 27.2.4.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/main/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v27.2.4/packages/babel-jest)

---
updated-dependencies:
- dependency-name: babel-jest
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-10-07 19:58:48 +02:00
f1066f8ac3 Bump eslint from 7.30.0 to 7.32.0 (#75)
Bumps [eslint](https://github.com/eslint/eslint) from 7.30.0 to 7.32.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.30.0...v7.32.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-08-08 20:13:29 +02:00
23b999c198 Bump @types/jest from 26.0.23 to 26.0.24 (#73)
Bumps [@types/jest](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/jest) from 26.0.23 to 26.0.24.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/jest)

---
updated-dependencies:
- dependency-name: "@types/jest"
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-09 08:10:59 +00:00
8f1c4b3e8c Bump babel-jest from 26.6.3 to 27.0.6 (#71)
Bumps [babel-jest](https://github.com/facebook/jest/tree/HEAD/packages/babel-jest) from 26.6.3 to 27.0.6.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/commits/v27.0.6/packages/babel-jest)

---
updated-dependencies:
- dependency-name: babel-jest
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-09 08:06:03 +00:00
8609a807e9 Bump jest from 26.6.3 to 27.0.6 (#70)
Bumps [jest](https://github.com/facebook/jest) from 26.6.3 to 27.0.6.
- [Release notes](https://github.com/facebook/jest/releases)
- [Changelog](https://github.com/facebook/jest/blob/master/CHANGELOG.md)
- [Commits](https://github.com/facebook/jest/compare/v26.6.3...v27.0.6)

---
updated-dependencies:
- dependency-name: jest
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-09 10:03:24 +02:00
21a7b043b4 Bump eslint from 7.26.0 to 7.30.0 (#72)
Bumps [eslint](https://github.com/eslint/eslint) from 7.26.0 to 7.30.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.26.0...v7.30.0)

---
updated-dependencies:
- dependency-name: eslint
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-09 09:53:47 +02:00
7c6c0f37d0 Bump dotenv from 9.0.2 to 10.0.0 (#58)
Bumps [dotenv](https://github.com/motdotla/dotenv) from 9.0.2 to 10.0.0.
- [Release notes](https://github.com/motdotla/dotenv/releases)
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v9.0.2...v10.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-07-09 09:48:52 +02:00
aa58f13444 Bump nedb-promises from 4.1.3 to 4.1.5 (#57)
Bumps [nedb-promises](https://github.com/bajankristof/nedb-promises) from 4.1.3 to 4.1.5.
- [Release notes](https://github.com/bajankristof/nedb-promises/releases)
- [Changelog](https://github.com/bajankristof/nedb-promises/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bajankristof/nedb-promises/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-21 14:00:59 +02:00
5f59372253 Bump dotenv from 9.0.0 to 9.0.2 (#55)
Bumps [dotenv](https://github.com/motdotla/dotenv) from 9.0.0 to 9.0.2.
- [Release notes](https://github.com/motdotla/dotenv/releases)
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v9.0.0...v9.0.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-12 17:20:10 +02:00
cb47266772 Update node.js.yml (#56) 2021-05-12 15:16:31 +00:00
14df5e64d9 Bump eslint from 7.25.0 to 7.26.0 (#54)
Bumps [eslint](https://github.com/eslint/eslint) from 7.25.0 to 7.26.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v7.25.0...v7.26.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-12 10:44:55 +02:00
d0e4384479 Update node.js.yml 2021-05-09 10:51:25 +02:00
f6dc7d5b19 Update node.js.yml 2021-05-09 10:45:04 +02:00
ba3e5a9824 Delete bump-version.yml 2021-05-09 10:44:15 +02:00
2c092af970 bump version (#51) 2021-05-08 11:32:43 +00:00
7bf77284dd Update readme (#49)
* removed dependency to Random

* removed dependency to node-fetch

* remove node-fetch, add got

* updated README

* bump version
2021-05-07 21:02:47 +00:00
8b3d9b4c78 Remove dependency Random, node-fetch (#48)
* removed dependency to Random

* removed dependency to node-fetch

* remove node-fetch, add got

* unstringify json
2021-05-07 22:51:03 +02:00
ba63be64dd merge dev branch (more tests) (#47)
* more tests and bugfixes on spells

* linting
2021-05-06 19:35:58 +00:00
25ad8ad160 removed string concatenation (#46) 2021-05-06 19:29:16 +00:00
d85d12e2d1 Bump dotenv from 8.2.0 to 9.0.0 (#43)
Bumps [dotenv](https://github.com/motdotla/dotenv) from 8.2.0 to 9.0.0.
- [Release notes](https://github.com/motdotla/dotenv/releases)
- [Changelog](https://github.com/motdotla/dotenv/blob/master/CHANGELOG.md)
- [Commits](https://github.com/motdotla/dotenv/compare/v8.2.0...v9.0.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 19:06:19 +00:00
6a52df3f28 Bump nedb-promises from 4.1.2 to 4.1.3 (#42)
Bumps [nedb-promises](https://github.com/bajankristof/nedb-promises) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/bajankristof/nedb-promises/releases)
- [Changelog](https://github.com/bajankristof/nedb-promises/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bajankristof/nedb-promises/commits)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 18:55:38 +00:00
807ccb1cd0 Bump eslint-config-prettier from 6.8.0 to 8.3.0 (#45)
Bumps [eslint-config-prettier](https://github.com/prettier/eslint-config-prettier) from 6.8.0 to 8.3.0.
- [Release notes](https://github.com/prettier/eslint-config-prettier/releases)
- [Changelog](https://github.com/prettier/eslint-config-prettier/blob/main/CHANGELOG.md)
- [Commits](https://github.com/prettier/eslint-config-prettier/compare/v6.8.0...v8.3.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:12:42 +02:00
87e469407c Bump eslint from 6.8.0 to 7.25.0 (#35)
Bumps [eslint](https://github.com/eslint/eslint) from 6.8.0 to 7.25.0.
- [Release notes](https://github.com/eslint/eslint/releases)
- [Changelog](https://github.com/eslint/eslint/blob/master/CHANGELOG.md)
- [Commits](https://github.com/eslint/eslint/compare/v6.8.0...v7.25.0)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-05-06 13:07:58 +02:00
79c95cea97 (dev) remove rewire, add babel-plugin-rewire. (#44)
* removed rewire. now using babel-rewire instead

* implemented more tests

* changed some eslint params

* linting

* linting

* coverage on getChant

Co-authored-by: Marcus Netz <marcus.netz@godyo.com>
2021-05-06 10:52:33 +00:00
4fa2dc7ab7 (fix) !spells and !chants returned null value (#40) 2021-05-04 20:39:59 +00:00
895f47847e Tweak: Add --all to !List command (#39)
* tweaked on list command

* added more tests
2021-05-03 19:44:05 +00:00
9bcd195afd removed eslint-import-resolver-module-alias (#38) 2021-05-03 16:50:43 +00:00
c6cacdae5e switched nedb to nedb-promises (#37)
* breaking change: switched to nedb-promises
* Linting
* some dev dependencies
* more tests
* updated package version
* bug fixing
* changed isNaN to isString
* (fix) args[0]
2021-05-03 18:39:33 +02:00
dc746276ab fix attribute checks (#34) 2021-05-01 21:21:33 +00:00
d45e4faad6 Security fixes (#32)
* Generic Object Injection Sink

* (fix) "Character" is not defined.

* added eslint

* improve code quality, use refactored function

* (fix) eslint jest

* "Character" is not defined

* removed unused file Compare.js

* (fix) PointsUsed is not defined

* (fix) eslint moans jsconfig

* turn off "no-prototype-builtins"

* push code coverage
2021-05-01 20:13:15 +02:00
63bd06e92f Create codacy-analysis.yml (#31) 2021-05-01 18:06:15 +00:00
351c90577f (fix) attack handler, more tests. (#30) 2021-05-01 07:12:07 +00:00
f22df0dec1 Refactoring (#29)
* refactor Attack command

* add test to Attack functions

* changed README.md

* install dev dependency rewire

* stop autoloading due to ci errors
2021-04-30 23:14:27 +02:00
edcfba3d7b Delete data directory (#28) 2021-04-30 20:51:10 +00:00
924fca5b90 add more tests (#26)
* added more tests

* (fix) no cpu profile.
2021-04-29 19:42:51 +00:00
23418bbc60 Add Skillchecks for Magical Talents (#25)
* initial implementation of spells

* added return list of spells. Moved them into seperate json

* added _some_ chants, restructuring data from spells

* added more chants, added command for getting info

* added related messages, added skillcheck for spells (cast)

* better error handling, added chant command

* (fix) Chants were referring to spells

* cleanup testing variables and code

* updated README

* fixed storage location issues and minor bugs

* removed db storage location

* rc1

* (fix) chants_title

* (fix) Uncaught ReferenceError: Discord is not defined

* (fix) more reference errors

Co-authored-by: Marcus Netz <marcus.netz@godyo.com>
2021-04-28 19:33:30 +02:00
70 changed files with 17437 additions and 12202 deletions

83
.eslintrc Normal file
View File

@ -0,0 +1,83 @@
{
"parserOptions": {
"ecmaVersion": 10,
"sourceType": "script",
"ecmaFeatures": {
"jsx": true
}
},
"rules": {
"constructor-super": 2,
"for-direction": 2,
"getter-return": 2,
"no-async-promise-executor": 2,
"no-case-declarations": 2,
"no-class-assign": 2,
"no-compare-neg-zero": 2,
"no-cond-assign": 2,
"no-const-assign": 2,
"no-constant-condition": 2,
"no-control-regex": 2,
"no-debugger": 2,
"no-delete-var": 2,
"no-dupe-args": 2,
"no-dupe-class-members": 2,
"no-dupe-else-if": 2,
"no-dupe-keys": 2,
"no-duplicate-case": 2,
"no-empty": 2,
"no-empty-character-class": 2,
"no-empty-pattern": 2,
"no-ex-assign": 2,
"no-extra-boolean-cast": 2,
"no-extra-semi": 2,
"no-fallthrough": 2,
"no-func-assign": 2,
"no-global-assign": 2,
"no-import-assign": 2,
"no-inner-declarations": 2,
"no-invalid-regexp": 2,
"no-irregular-whitespace": 2,
"no-misleading-character-class": 2,
"no-mixed-spaces-and-tabs": 2,
"no-new-symbol": 2,
"no-obj-calls": 2,
"no-octal": 2,
"no-prototype-builtins": 0,
"no-redeclare": 2,
"no-regex-spaces": 2,
"no-self-assign": 2,
"no-setter-return": 2,
"no-shadow-restricted-names": 2,
"no-sparse-arrays": 2,
"no-this-before-super": 2,
"no-undef": 2,
"no-unexpected-multiline": 2,
"no-unreachable": 2,
"no-unsafe-finally": 2,
"no-unsafe-negation": 2,
"no-unused-labels": 2,
"no-unused-vars": 2,
"no-useless-catch": 2,
"no-useless-escape": 2,
"no-with": 2,
"require-yield": 2,
"use-isnan": 2,
"valid-typeof": 2,
"no-underscore-dangle": 0,
"spaced-comment": 0,
"no-console": 0,
"no-unneeded-ternary": 0,
"object-shorthand": 0,
"no-useless-rename": 0,
"arrow-body-style": ["error", "as-needed", { "requireReturnForObjectLiteral": true }]
},
"env": {
"node": true,
"jest": true,
"commonjs": true,
"es2017": true
},
"plugins": ["prettier"],
"extends": ["airbnb", "prettier"]
}

49
.github/workflows/codacy-analysis.yml vendored Normal file
View File

@ -0,0 +1,49 @@
# This workflow checks out code, performs a Codacy security scan
# and integrates the results with the
# GitHub Advanced Security code scanning feature. For more information on
# the Codacy security scan action usage and parameters, see
# https://github.com/codacy/codacy-analysis-cli-action.
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.
name: Codacy Security Scan
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '33 2 * * 6'
jobs:
codacy-security-scan:
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v2
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@1.1.0
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 2147483647
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: results.sarif

View File

@ -13,16 +13,31 @@ on:
- 'Dockerfile'
pull_request:
branches: [ master ]
pull_request_target:
branches: [ master ]
jobs:
build:
test:
runs-on: ubuntu-latest
# If the PR is coming from a fork (pull_request_target), ensure it's opened by "dependabot[bot]".
# Otherwise, clone it normally.
if: |
(github.event_name == 'pull_request_target' && github.actor == 'dependabot[bot]') ||
(github.event_name != 'pull_request_target' && github.actor != 'dependabot[bot]')
strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 15.x]
node-version: [15.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v2
- name: Checkout
if: ${{ github.event_name != 'pull_request_target' }}
uses: actions/checkout@v2
- name: Checkout PR
if: ${{ github.event_name == 'pull_request_target' }}
uses: actions/checkout@v2
with:
ref: ${{ github.event.pull_request.head.sha }}
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
@ -30,10 +45,13 @@ jobs:
- run: npm ci
- run: npm run build --if-present
- run: npm test
- name: Run codacy-coverage-reporter
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
deploy:
needs: build
needs: test
if: ${{github.event_name == 'push'}}
runs-on: ubuntu-latest
steps:

19
.gitignore vendored
View File

@ -1,10 +1,15 @@
node_modules
/node_modules/
.env
.eslintrc.js
.eslintrc.json
.vscode
.github
data/dsabot.db
data/dsabot.db~
data
.jshint
.prettierrc
/.vscode/
/.github/
.DS_Store
Thumbs.db
/data/dsabot.db
!/data/*.js
!/data/*.json
/private
coverage

3
.jshintrc Normal file
View File

@ -0,0 +1,3 @@
{
"esversion": 9
}

19
.prettierrc Normal file
View File

@ -0,0 +1,19 @@
{
"arrowParens": "avoid",
"bracketSpacing": true,
"embeddedLanguageFormatting": "auto",
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"jsxBracketSameLine": true,
"jsxSingleQuote": true,
"printWidth": 100,
"proseWrap": "preserve",
"quoteProps": "as-needed",
"requirePragma": false,
"semi": true,
"singleQuote": true,
"tabWidth": 4,
"trailingComma": "es5",
"useTabs": false,
"vueIndentScriptAndStyle": false
}

View File

@ -1,6 +1,7 @@
[![CodeQL](https://github.com/TobenderZephyr/dsabot/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/TobenderZephyr/dsabot/actions/workflows/codeql-analysis.yml)
# DSA Discord Bot
![GitHub package.json version](https://img.shields.io/github/package-json/v/TobenderZephyr/dsabot?style=flat-square) ![node-current](https://img.shields.io/node/v/discord.js?style=flat-square) ![GitHub last commit](https://img.shields.io/github/last-commit/TobenderZephyr/dsabot?style=flat-square) ![GitHub Workflow Status (branch)](https://img.shields.io/github/workflow/status/TobenderZephyr/dsabot-docker/Build%20Image%20on%20Push/main?label=docker%20image&style=flat-square) ![Docker Pulls](https://img.shields.io/docker/pulls/tobenderzephyr/dsabot) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/e7dfc961c9eb481185468cc59b22fdfa)](https://www.codacy.com/gh/TobenderZephyr/dsabot/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=TobenderZephyr/dsabot&amp;utm_campaign=Badge_Grade) [![Codacy Badge](https://app.codacy.com/project/badge/Coverage/e7dfc961c9eb481185468cc59b22fdfa)](https://www.codacy.com/gh/TobenderZephyr/dsabot/dashboard?utm_source=github.com&utm_medium=referral&utm_content=TobenderZephyr/dsabot&utm_campaign=Badge_Coverage)
This Project is a fork of LucaSchwan/dsa-bot.
It is a Discord.js Bot written in JavaScript to support playing the German Pen & Paper RPG "Das Schwarze Auge" (The Dark Eye). The Bot has a built-in Database based on Endb and can handle character sheets from [The Dark Aid](https://www.ulisses-ebooks.de/product/212543/The-Dark-Aid-alpha).
@ -10,37 +11,44 @@ It can roll dice and even compare results with your characters attributes.
# Commands
### !help
Send the user a simple command list with things to do.
## Dice Rolling
### !roll *x* W/D *y*
### !roll _x_ W/D _y_
This command can be used to roll dice. To use it one has to put in the number of dice to use as the *x* and the number of sides as the *y* in between those Numbers stands W/D which simply means dice(D) or the german word "Würfel" (W). Theoretically it doesn't matter what Letter is in between but for roleplay gamers this should feel natural.
This command can be used to roll dice. To use it one has to put in the number of dice to use as the _x_ and the number of sides as the _y_ in between those Numbers stands W/D which simply means dice(D) or the german word "Würfel" (W). Theoretically it doesn't matter what Letter is in between but for roleplay gamers this should feel natural.
ie `!roll 3w20`
### !heads
Throw a coin. Heads or Tails?
## Tracking System
As this Bot should help with tracking your character, simply attach your .tdc file in a private message.
### !ep / !ap [Value]
Probes on your attributes.
Rolls 1 die and compares it with the given value. Rolls another, if returned number is 1 or 20.
ie `!ep 11`
### !ep / !ap [Attribute or Abbreviation]
Does the same as above. You don't need to remember your stats (if you sent a `tdc`-File, that is.)
ie. `!ep Mut` or `!ep KK`
### !skill [skillname]
Returns the current level of the desired skill.
### !attack [weaponname] ([-Disadvantages/+Advantages])
Rolls an attack by using the weapon based skillset. Calculates your combat technique value and takes into account for `MU` or `FF`.
`caution`: It does not yet make use of any benefits or disadvantages your character possesses.
@ -49,19 +57,24 @@ ie. `!attack Waqqif`
For a list of weapons to chose from, use `!weapons`
### !talent [skillname] ([-Disadvantages/+Advantages])
Rolls 3 dice and compares the results of each with your current level of character attributes including your bonus on that particular skill.
`caution`: It does not yet make use of any benefits or disadvantages your character has (at the moment).
ie. `!talent klettern -2`
```
@TobenderZephyr, Du würfelst auf das Talent Klettern.
Deine Werte für MU, GE, KK sind 12, 13, 12. (Bonus: 6)
Das waren deine 🎲: 1, 16, 2. Damit hast du 3/3 Proben bestanden. Dein Bonus: 3/6.
```
### !talents
Sends the User a list of talents to use on the `!talent` command.
### !tp [attribute1] [attribute2] [attribute3] ([bonus] [-Disadvantage/+Advantages])
This command also rolls 3 dice and compares their values with entered arguments.
This one is better suited for people, who did not provide a `.tdc`-File or if one of the other numerous Advantages and/or Disadvantages need to be taken into account.
@ -74,9 +87,35 @@ Roll with a set Bonus of 4:
Roll with a Benefit given by the GM:
`!tp 11 10 11 0 +2`
### !spells [spell]
This command returns a list of spells known to you. This differs from `!talents` because there would be many more additions to certain
spells through rule books.
If you define a spell by not leaving arguments empty, it will display your current level and checks on your stats.
### !chants [chant]
See `!spells`. This uses karma point talents.
### !cast [spell] ([-Disadvantages/+Advantages])
Rolls 3 dice and compares the results of each with your current level of character attributes including your bonus on that particular spell.
`caution`: It does not yet make use of any benefits or disadvantages your character has (at the moment).
ie. `!cast fulminictus +1`
### !chant [chant] ([-Disadvantages/+Advantages])
See `!cast`. This uses karma point talents.
ie. `!chant Lautlos +1`
# How to use
To connect the script to a Bot, you need to create a Bot using the Discord Developer Portal. To do this you can follow a guide like [this](https://discordpy.readthedocs.io/en/latest/discord.html).
## Docker
Just pull the docker image and you are good to go.
`docker pull tobenderzephyr/dsabot:latest`
@ -85,12 +124,14 @@ The container needs at least the following Environment variables:
`BOT_TOKEN`: The token which you retrieve for your bot Discord Developer Portal
`CMDPREFIX`: Instead of using `!` as your prefix, you may want to use your own.
You may run the container with `docker run -rm -v ./data:/usr/src/app/data -e BOT_TOKEN=[token] -e CMDPREFIX=! tobenderzephyr/dsabot:latest`
You may run the container with `docker run -rm -v ./data:/usr/src/app/data/ -e BOT_TOKEN=[token] -e CMDPREFIX=! tobenderzephyr/dsabot:latest`
The database is stored under `./data`, so you are good to just mount this as a volume as seen in the example above.
### docker-compose
You may aswell use a simple `docker-compose.yml` and use docker-compose for easy running the app:
```
version: "3"
services:
@ -102,7 +143,7 @@ services:
BOT_TOKEN: <YOUR TOKEN>
CMDPREFIX: !
volumes:
- ./data:/usr/src/app/data
- ./data/:/usr/src/app/data/
```
## manual setup
@ -114,12 +155,10 @@ Then you need to run the following code inside of a terminal while beeing in the
`npm install`
Rename `.sample.env` file to `.env`
Enter the token you received on the Discord Developer Portal into the variable BOT_TOKEN inside `.env`.
Enter the token you received on the Discord Developer Portal into the variable BOT_TOKEN inside `.env`.
When you joined your Bot to your desired channel all you need to enter inside the bots directory:
`npm start`
Then your Bot should run and be working in your channel.

View File

@ -0,0 +1,231 @@
require('module-alias/register');
require('babel-plugin-rewire');
const Attack = require('@Commands/Attack');
const getWeapon = Attack.__get__('getWeapon');
const getAttributeLevel = Attack.__get__('getAttributeLevel');
const getCombatTechniqueLevel = Attack.__get__('getCombatTechniqueLevel');
const isMeleeWeapon = Attack.__get__('isMeleeWeapon');
const getAttribute = Attack.__get__('getAttribute');
const CompareAttackResult = Attack.__get__('CompareAttackResult');
const getCombatTechnique = Attack.__get__('getCombatTechnique');
describe('getCombatTechnique', () => {
it('should be undefined without value', () => {
expect(getCombatTechnique({})).toBeUndefined();
});
it('should be undefined without value', () => {
expect(getCombatTechnique({ combattechnique: 'made-up' })).toBeUndefined();
});
it('should be null without any params.', () => {
expect(getCombatTechnique()).toBeNull();
});
it('should return defined object', () => {
expect(getCombatTechnique({ combattechnique: 'dolche' })).toEqual(
expect.objectContaining({
id: expect.any(String),
name: expect.any(String),
Leiteigenschaft: expect.anything(),
})
);
});
});
describe('getAttribute', () => {
test('should return Object', () => {
const obj = { id: 'mut', kuerzel: 'MU', name: 'Mut' };
expect(getAttribute('KK')).toBeInstanceOf(Object);
expect(getAttribute('KK')).toEqual(
expect.objectContaining({
id: expect.any(String),
kuerzel: expect.any(String),
name: expect.any(String),
})
);
expect(getAttribute('MU')).toEqual(obj);
});
});
describe('CompareAttackResults', () => {
test('CompareAttackResults', () => {
expect(CompareAttackResult()).toEqual(
expect.objectContaining({
Ok: expect.any(Boolean),
Patzer: expect.any(Boolean),
CriticalHit: expect.any(Boolean),
DoubleDamage: expect.any(Boolean),
Dice: expect.anything(),
})
);
});
it('should return object with fumble', () => {
const obj = {
Ok: false,
Patzer: true,
CriticalHit: false,
DoubleDamage: false,
Dice: [20, 14],
};
expect(CompareAttackResult([20, 14], 8)).toEqual(obj);
});
it('should return object with crit', () => {
const obj = {
Ok: true,
Patzer: false,
CriticalHit: true,
DoubleDamage: false,
Dice: [1, 14],
};
expect(CompareAttackResult([1, 14], 8)).toEqual(obj);
});
it('should return object with double damage', () => {
const obj = {
Ok: true,
Patzer: false,
CriticalHit: true,
DoubleDamage: true,
Dice: [1, 4],
};
expect(CompareAttackResult([1, 4], 8)).toEqual(obj);
});
it('should return object without passing', () => {
const obj = {
Ok: false,
Patzer: false,
CriticalHit: false,
DoubleDamage: false,
Dice: [10],
};
expect(CompareAttackResult([10, 14], 8)).toEqual(obj);
});
});
describe('getAttributeLevel', () => {
it('returns a number ', () => {
expect(getAttributeLevel({ attributes: [{ id: 'mut', level: 8 }] }, 'mut')).toBe(8);
});
});
describe('getCombatTechniqueLevel', () => {
it('returnsa defined object ', () => {
const Player = { combattechniques: [{ id: 'dolche', level: 9 }] };
const CombatTechnique = { name: 'Dolche', id: 'dolche', Leiteigenschaft: ['GE'] };
expect(getCombatTechniqueLevel(Player, CombatTechnique)).toEqual(
expect.objectContaining({
id: expect.any(String),
name: expect.any(String),
level: expect.any(Number),
Leiteigenschaft: expect.any(Array),
})
);
});
});
describe('getWeapon', () => {
it('returns an object', () => {
expect(getWeapon('waqqif')).toBeInstanceOf(Object);
});
it('returns a defined object ', () => {
expect(getWeapon('waqqif')).toEqual(
expect.objectContaining({
id: expect.any(String),
name: expect.any(String),
dice: expect.any(Number),
diemodificator: expect.any(Number),
at_mod: expect.any(Number),
pa_mod: expect.any(Number),
article: expect.any(Number),
DmgThreshold: expect.any(Number),
combattechnique: expect.any(String),
})
);
});
});
describe('isMeleeWeapon', () => {
it('returns true ', () => {
expect(isMeleeWeapon({ id: 'waqqif' })).toBeTruthy();
});
it('returns false ', () => {
expect(isMeleeWeapon({ id: 'bogen' })).toBeFalsy();
});
});
describe('main Function', () => {
it('should abort with a message: no entry found', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
};
const handleAttack = Attack.__get__('handleAttack');
//expect(handleAttack(err)).toThrowError();
expect(handleAttack({}, { message: message })).toEqual(
'Sorry, für dich habe ich leider keinen Eintrag 😥'
);
});
it('should abort with a message: No such weapon', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
};
const handleAttack = Attack.__get__('handleAttack');
const args = [''];
expect(handleAttack([{ character: {} }], { message: message, args: args })).toEqual(
'Diese Waffe gibt es nicht.'
);
});
it('complete run with melee weapon', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
};
const character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'fingerfertigkeit', level: 10 },
{ id: 'klugheit', level: 10 },
{ id: 'intuition', level: 10 },
{ id: 'charisma', level: 10 },
{ id: 'gewandtheit', level: 16 },
{ id: 'konstitution', level: 10 },
{ id: 'koerperkraft', level: 10 },
],
combattechniques: [{ id: 'dolche', level: 8 }],
};
const handleAttack = Attack.__get__('handleAttack');
const args = ['messer'];
expect(handleAttack({ character: character }, { message: message, args: args })).toEqual(
expect.any(String)
);
});
it('complete run with ranged weapon', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
};
const character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'fingerfertigkeit', level: 14 },
{ id: 'klugheit', level: 10 },
{ id: 'intuition', level: 10 },
{ id: 'charisma', level: 10 },
{ id: 'gewandtheit', level: 16 },
{ id: 'konstitution', level: 10 },
{ id: 'koerperkraft', level: 10 },
],
combattechniques: [{ id: 'boegen', level: 8 }],
};
const handleAttack = Attack.__get__('handleAttack');
const args = ['langbogen'];
expect(handleAttack({ character: character }, { message: message, args: args })).toEqual(
expect.any(String)
);
});
});

View File

@ -0,0 +1,123 @@
require('module-alias/register');
require('babel-plugin-rewire');
const Attribute = require('@Commands/Attribute');
const HandleNamedAttributes = Attribute.__get__('HandleNamedAttributes');
const getAttributeLevel = Attribute.__get__('getAttributeLevel');
const getAttribute = Attribute.__get__('getAttribute');
const handleAttributeCheck = Attribute.__get__('handleAttributeCheck');
describe('getAttribute', () => {
test('getAttribute should return Object', () => {
const obj = { id: 'mut', kuerzel: 'MU', name: 'Mut' };
expect(getAttribute('KK')).toEqual(
expect.objectContaining({
id: expect.any(String),
kuerzel: expect.any(String),
name: expect.any(String),
})
);
expect(getAttribute('MU')).toEqual(obj);
expect(getAttribute('mut')).toEqual(obj);
});
it('should return undefined', () => {
expect(getAttribute()).toBeUndefined();
});
});
describe('getAttributeLevel', () => {
it('returns a number ', () => {
expect(getAttributeLevel({ attributes: [{ id: 'mut', level: 8 }] }, { id: 'mut' })).toBe(8);
});
});
describe('HandleNamedAttribute', () => {
it('should return an object', () => {
const Character = {
attributes: [{ id: 'mut', level: 8 }],
};
expect(HandleNamedAttributes({ Character: Character, args: ['mut'] })).toEqual({
Name: 'Mut',
Level: 8,
});
});
});
it('should return with no errors', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
author: {
tag: 'test',
},
};
const doc = { character: { attributes: [{ id: 'mut', level: 8 }] } };
const args = ['mut'];
expect(handleAttributeCheck(doc, { message, args })).toEqual(expect.any(String));
});
it('should return with no errors', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
author: {
tag: 'test',
},
};
const docs = { character: { attributes: [{ id: 'mut', level: 8 }] } };
const args = ['MU'];
expect(handleAttributeCheck(docs, { message, args })).toEqual(expect.any(String));
});
it('should return with no errors', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
author: {
tag: 'test',
},
};
const docs = [{ character: { attributes: [{ id: 'mut', level: 8 }] } }];
const args = [8];
for (let i = 0; i < 30; i += 1) {
expect(handleAttributeCheck(docs, { message, args })).toEqual(expect.any(String));
}
});
it('should return with no errors', () => {
const reply = jest.fn(str => str);
const message = {
reply: reply,
author: {
tag: 'test',
},
};
const docs = [{ character: { attributes: [{ id: 'mut', level: 8 }] } }];
const args = [8, '+2'];
for (let i = 0; i < 30; i += 1) {
expect(handleAttributeCheck(docs, { message, args })).toEqual(expect.any(String));
}
});
it('should return empty', () => {
const message = { author: { tag: 'test' }, reply: jest.fn(str => str) };
const args = ['MU'];
expect(Attribute.exec(message, args)).toBeInstanceOf(Promise);
//expect(Attribute.exec(message, args)).resolves.toBeUndefined();
});
/*
const reply = jest.fn(str => str);
const message = {
reply: reply,
author: {
tag: 'test',
},
};
const docs = [{ character: { attributes: [{ id: 'mut', level: 8 }] } }];
const args = ['MU'];
const run = [];
for (let i = 1; i < 100; i++) {
run.push(i);
}
test.each(run)('run multiple times (%s)', () => {
expect(handleAttributeCheck(docs, { message, args })).toEqual(expect.any(String));
});
*/

View File

@ -0,0 +1,76 @@
require('module-alias/register');
require('babel-plugin-rewire');
const Chants = require('@Commands/Chants');
const createChantList = Chants.__get__('createChantList');
const TestValue = {
Name: 'Test',
Level: 10,
Attributes: [
{ Name: 'Klugheit', Level: 10 },
{ Name: 'Charisma', Level: 11 },
{ Name: 'Mut', Level: 12 },
],
};
describe('createChantList', () => {
it('should return an array with expected object(s)', () => {
const Test = { chants: [{ id: 'test', level: 10 }] };
const expected = {
Name: 'Test',
Level: 10,
Attributes: [
{ Name: 'Klugheit', Level: 10 },
{ Name: 'Charisma', Level: 11 },
{ Name: 'Mut', Level: 12 },
],
};
Chants.__Rewire__('getChant', () => expected);
expect(createChantList(Test)).toEqual(expect.arrayContaining([expected]));
Chants.__ResetDependency__('getChant');
});
it('should abort if character has no chants', () => {
expect(createChantList({ attributes: [] })).toBeNull();
expect(createChantList()).toBeNull();
expect(createChantList({})).toBeNull();
});
});
describe('ReplyChant', () => {
const ReplyChant = Chants.__get__('ReplyChant');
it('should return null if no param given.', () => {
expect(ReplyChant()).toBeNull();
});
it('should return a string', () => {
// toBeInstanceOf(String) is not working :(
expect(
ReplyChant({
Name: 'Test',
Level: 9,
Attributes: [
{ Name: 'Klugheit', Level: 10 },
{ Name: 'Charisma', Level: 11 },
{ Name: 'Mut', Level: 12 },
],
})
).toMatch(/.*Test.*(9)?.*/);
});
Chants.__ResetDependency__('ReplyChant');
});
describe('ReplyChantList', () => {
const ReplyChantList = Chants.__get__('ReplyChantList');
it('should return null if params are empty', () => {
expect(ReplyChantList('')).toBeNull();
expect(ReplyChantList([])).toBeNull();
expect(ReplyChantList()).toBeNull();
});
it('should return Name and Level', () => {
const input = [TestValue];
expect(ReplyChantList(input)).toMatch('Test (10)');
});
});

134
__tests__/commands/List.js Normal file
View File

@ -0,0 +1,134 @@
require('module-alias/register');
require('babel-plugin-rewire');
const List = require('@Commands/List');
// const getStats = reWireUtils.__get__('getStats');
const getAttribute = List.__get__('getAttribute');
const printHeader = List.__get__('printHeader');
const listStats = List.__get__('listStats');
describe('getAttributes', () => {
it('should return an attribute object', () => {
expect(getAttribute({ id: 'mut', level: 9 })).toEqual(
expect.objectContaining({
id: 'mut',
Name: 'Mut',
Level: 9,
})
);
expect(getAttribute()).toEqual(
expect.objectContaining({
id: expect.any(String),
Name: expect.any(String),
Level: expect.any(Number),
})
);
});
});
describe('printHeader', () => {
it('should return null with no params', () => {
expect(printHeader()).toBeNull();
});
it('should return a string', () => {
const attributes = [{ Short: 'AA' }, { Short: 'BB' }, { Short: 'CC' }];
expect(printHeader(attributes)).toMatch(/\s+AA\s+[|]\s+BB\s+[|]\s+CC\s+/g);
});
});
describe('listStats', () => {
it('should return a string', () => {
expect(listStats([{ Level: 8 }, { Level: 9 }, { Level: 10 }])).toMatch(
/\s+8\s+[|]\s+9\s+[|]\s+10\s+/
);
});
});
describe('findUser', () => {
const expected = {
user: 'Test',
character: {
name: 'test',
},
};
List.__Rewire__('db', {
findOne: () => Promise.resolve(expected),
});
const findUser = List.__get__('findUser');
expect(findUser()).toBeInstanceOf(Promise);
expect(findUser()).resolves.toEqual(expected);
});
/*
describe('findUsers', () => {
const expected = {
user: 'Test',
character: {
name: 'test',
attributes: [{ id: 'mut', level: 9 }],
},
};
List.__Rewire__('db', {
findOne: () => {
return Promise.resolve(expected);
},
});
const findUsers = List.__get__('findUsers');
expect(findUser()).toBeInstanceOf(Promise);
expect(findUser()).resolves.toEqual(expected);
});*/
describe('getStats', () => {
it('should give name, id and level in order', () => {
const getStats = List.__get__('getStats');
const user = {
character: {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
],
},
};
expect(getStats(user)).toEqual(
expect.arrayContaining([
{
Name: expect.any(String),
Level: expect.any(Number),
Short: expect.any(String),
id: expect.any(String),
},
])
);
});
});
describe('returnResult', () => {
const returnResult = List.__get__('returnResult');
const message = { reply: str => str };
const characters = [
{
Name: 'Zulu',
Attributes: [
{ id: 'charisma', Level: 7, Short: 'CH' },
{ id: 'mut', Level: 14, Short: 'MU' },
],
},
{
Name: 'Alfa',
Attributes: [
{ id: 'mut', Level: 10, Short: 'MU' },
{ id: 'charisma', Level: 11, Short: 'CH' },
],
},
];
it('returns if no characters were found', () => {
expect(returnResult(message, [])).toBe('Keine Benutzer auf dieser Liste gefunden.');
expect(returnResult(message)).toBe('Keine Benutzer auf dieser Liste gefunden.');
});
it('returns a string ', () => {
expect(returnResult(message, characters)).toMatch(/.*/);
});
});

View File

@ -0,0 +1,14 @@
require('module-alias/register');
require('babel-plugin-rewire');
const command = require('@Commands/Roll');
//const exec = command.__get__('exec');
describe('roll command', () => {
const reply = jest.fn(str => str);
const message = { author: { tag: 'test' }, reply: reply };
it('should not return anything without correct arguments', () => {
const args = ['1w6'];
expect(command.exec(message, args)).resolves.toBeUndefined();
expect(reply).toHaveBeenCalled();
});
});

View File

@ -0,0 +1,76 @@
require('module-alias/register');
require('babel-plugin-rewire');
const Spells = require('@Commands/Spells');
const createSpellList = Spells.__get__('createSpellList');
const TestValue = {
Name: 'Test',
Level: 10,
Attributes: [
{ Name: 'Klugheit', Level: 10 },
{ Name: 'Charisma', Level: 11 },
{ Name: 'Mut', Level: 12 },
],
};
describe('createSpellList', () => {
it('should return an array with expected object(s)', () => {
const Test = { spells: [{ id: 'test', level: 10 }] };
const expected = {
Name: 'Test',
Level: 10,
Attributes: [
{ Name: 'Klugheit', Level: 10 },
{ Name: 'Charisma', Level: 11 },
{ Name: 'Mut', Level: 12 },
],
};
Spells.__Rewire__('getSpell', () => expected);
expect(createSpellList(Test)).toEqual(expect.arrayContaining([expected]));
Spells.__ResetDependency__('getSpell');
});
it('should abort if character has no chants', () => {
expect(createSpellList({ attributes: [] })).toBeNull();
expect(createSpellList()).toBeNull();
expect(createSpellList({})).toBeNull();
});
});
describe('ReplySpell', () => {
const ReplySpell = Spells.__get__('ReplySpell');
it('should return null if no param given.', () => {
expect(ReplySpell()).toBeNull();
});
it('should return a string', () => {
// toBeInstanceOf(String) is not working :(
expect(
ReplySpell({
Name: 'Test',
Level: 9,
Attributes: [
{ Name: 'Klugheit', Level: 10 },
{ Name: 'Charisma', Level: 11 },
{ Name: 'Mut', Level: 12 },
],
})
).toMatch(/.*Test.*(9)?.*/);
});
Spells.__ResetDependency__('ReplySpell');
});
describe('ReplySpellList', () => {
const ReplySpellList = Spells.__get__('ReplySpellList');
it('should return null if params are empty', () => {
expect(ReplySpellList('')).toBe('Du kennst keine Zaubersprüche.');
expect(ReplySpellList([])).toBe('Du kennst keine Zaubersprüche.');
expect(ReplySpellList()).toBe('Du kennst keine Zaubersprüche.');
});
it('should return Name and Level', () => {
const input = [TestValue];
expect(ReplySpellList(input)).toMatch('Test (10)');
});
});

View File

@ -1,12 +1,33 @@
const {CalculateQuality} = require('@dsabot/CalculateQuality');
require('module-alias/register');
const { CalculateQuality } = require('@dsabot/CalculateQuality');
const TestValues = [
[1,1], [2,1], [3,1],
[4,2], [5,2], [6,2],
[7,3], [8,3], [9,3],
[10,4],[11,4],[12,4],
[13,5],[14,5],[15,5]
[1, 1],
[2, 1],
[3, 1],
[4, 2],
[5, 2],
[6, 2],
[7, 3],
[8, 3],
[9, 3],
[10, 4],
[11, 4],
[12, 4],
[13, 5],
[14, 5],
[15, 5],
[16, 6],
[17, 6],
[18, 6],
[19, 6],
[20, 6],
];
test.each(TestValues)('Retrieving Quality for %s', (input, output) => {
expect(CalculateQuality(input)).toBe(output);
});
});
it('should return 1 without input', () => {
expect(CalculateQuality()).toBe(1);
});

View File

@ -0,0 +1,10 @@
require('module-alias/register');
const { Capitalize } = require('@dsabot/Capitalize');
it('should capitalize the first letter.', () => {
expect(Capitalize('mother')).toBe('Mother');
});
it('should capitalize without any word given', () => {
expect(Capitalize()).toBe('None');
});

View File

@ -0,0 +1,60 @@
require('module-alias/register');
const { CompareResults } = require('@dsabot/CompareResults');
it('should return an object', () => {
const Obj = {
Passed: 0,
CriticalHit: 0,
Fumbles: 0,
PointsUsed: [],
PointsRemaining: 0,
};
expect(CompareResults).toBeInstanceOf(Object);
expect(CompareResults()).toMatchObject(Obj);
});
it('should match No. of Fumbles', () => {
const Obj = {
Passed: 0,
CriticalHit: 0,
Fumbles: 2,
PointsUsed: [0, 0, 0],
PointsRemaining: 0,
};
expect(CompareResults([9, 20, 20])).toMatchObject(Obj);
});
it('should match No. of Passed', () => {
const Obj = {
Passed: 3,
CriticalHit: 0,
Fumbles: 0,
PointsUsed: [0, 0, 0],
PointsRemaining: 0,
};
expect(CompareResults([7, 7, 7])).toMatchObject(Obj);
});
it('should match No. of Critical Hits', () => {
const Obj = {
Passed: 3,
CriticalHit: 2,
Fumbles: 0,
PointsUsed: [0, 0, 0],
PointsRemaining: 0,
};
expect(CompareResults([8, 1, 1])).toMatchObject(Obj);
});
it('should decrease Points remaining', () => {
const Obj = {
Passed: 3,
CriticalHit: 0,
Fumbles: 0,
PointsUsed: [0, 0, 3],
PointsRemaining: 3,
};
expect(CompareResults([11, 9, 15], [12, 12, 12], 0, 6)).toMatchObject(Obj);
});

View File

@ -1,6 +1,4 @@
const {
CountOccurences
} = require('../../functions/CountOccurences');
const { CountOccurences } = require('../../functions/CountOccurences');
test('Counting Occurences', () => {
expect(CountOccurences([1, 2, 3, 4, 1], 1)).toBe(2);
});
expect(CountOccurences([1, 2, 3, 4, 1], 1)).toBe(2);
});

View File

@ -0,0 +1,19 @@
require('module-alias/register');
const { CreateResultTable, f } = require('@dsabot/CreateResultTable');
it('turn any number into a string', () => {
expect(f(2)).toBe('+2');
expect(f(0)).toBe('0');
expect(f(-1)).toBe('-1');
});
it('should return a string', () => {
const obj = {
Attributes: [8, 8, 8],
Throws: [7, 7, 7],
PointsUsed: [0, 0, 0],
Bonus: 0,
};
expect(CreateResultTable(obj)).toEqual(expect.any(String));
});

View File

@ -0,0 +1,19 @@
require('module-alias/register');
const { Random } = require('@dsabot/Random');
it('should return with no min or max value', () => {
expect(Random.int()).toBeUndefined();
});
it('call for use should return true', () => {
expect(Random.use(null)).toBeTruthy();
});
it('should return between 1 and 2', () => {
expect(Random.int(1, 2)).toBeGreaterThanOrEqual(1);
});
it('should return between 1 and 2', () => {
expect(Random.int(1, 2)).toBeLessThanOrEqual(2);
});
it('should return exactly 1', () => {
expect(Random.int(1, 1)).toBe(1);
});

View File

@ -1,8 +1,15 @@
const { roll } = require('@dsabot/Roll');
describe('rolling dice', () => {
const expected = [1, 2, 3, 4, 5, 6];
test.each(expected)('contains only numbers from 1 to 6', (value) => {
expect(roll(200, 6).dice).toContain(value);
});
});
const expected = [1, 2, 3, 4, 5, 6];
test.each(expected)('contains only numbers from 1 to 6', value => {
expect(roll(200, 6).dice).toContain(value);
});
});
describe('rolling dice', () => {
const expected = [1, 2, 3, 4, 5, 6];
test.each(expected)('contains only numbers from 1 to 6', value => {
expect(roll(200, 6, 'test').dice).toContain(value);
});
});

View File

@ -0,0 +1,6 @@
require('module-alias/register');
const { findMessage } = require('@dsabot/findMessage');
it('should capitalize the first letter.', () => {
expect(findMessage('ERROR')).toBe('Irgendwas ist schief gelaufen. 🤔');
});

View File

@ -0,0 +1,23 @@
require('module-alias/register');
const { getAttributeLevels } = require('@dsabot/getAttributeLevels');
const Character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
{ id: 'intuition', level: 12 },
{ id: 'charisma', level: 13 },
{ id: 'fingerfertigkeit', level: 14 },
{ id: 'gewandtheit', level: 15 },
{ id: 'konstitution', level: 16 },
{ id: 'koerperkraft', level: 17 },
],
};
it('should return an array', () => {
expect(getAttributeLevels(['MU', 'IN', 'KO'], Character)).toBeInstanceOf(Array);
});
it('should have 3 items in it.', () => {
expect(getAttributeLevels(['MU', 'IN', 'KO'], Character)).toHaveLength(3);
});

View File

@ -0,0 +1,103 @@
require('module-alias/register');
require('babel-plugin-rewire');
const command = require('@dsabot/getChant');
describe('getChant integration test', () => {
it('should not find an entry for a chant', () => {
const getChant = command.__get__('getChant');
expect(getChant({ Character: { name: '' }, chant_name: 'test' })).toBeNull();
});
it('should return null if char has no chants.', () => {
const Character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
{ id: 'charisma', level: 12 },
],
};
command.__set__('Chants', [{ id: 'test', name: 'Test', attributes: ['MU', 'KL', 'CH'] }]);
const getChant = command.__get__('getChant');
expect(getChant({ Character: Character, chant_name: 'test' })).toBeNull();
});
it('should return a correct chant result.', () => {
const Character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
{ id: 'charisma', level: 12 },
],
chants: [{ id: 'test', level: 7 }, { id: 'no-level' }],
};
const Chants = [
{
id: 'test',
name: 'Testchant',
attributes: ['MU', 'KL', 'CH'],
},
{ id: 'no-level', name: 'No Level', attributes: ['MU', 'KL', 'CH'] },
];
command.__set__('Chants', Chants);
const getChant = command.__get__('getChant');
expect(getChant({ Character: Character, chant_name: 'test' })).toEqual(
expect.objectContaining({
Name: 'Testchant',
Level: 7,
Attributes: [
{ Level: 10, Name: 'MU' },
{ Level: 11, Name: 'KL' },
{ Level: 12, Name: 'CH' },
],
})
);
expect(getChant({ Character: Character, chant_name: 'Testchant' })).toEqual(
expect.objectContaining({
Name: 'Testchant',
Level: 7,
Attributes: [
{ Level: 10, Name: 'MU' },
{ Level: 11, Name: 'KL' },
{ Level: 12, Name: 'CH' },
],
})
);
expect(getChant({ Character: Character, chant_name: 'no-level' })).toEqual(
expect.objectContaining({
Name: 'No Level',
Level: 0,
Attributes: [
{ Level: 10, Name: 'MU' },
{ Level: 11, Name: 'KL' },
{ Level: 12, Name: 'CH' },
],
})
);
});
it('should not find the chant.', () => {
const Character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
{ id: 'charisma', level: 12 },
],
chants: [{ id: 'test', level: 7 }],
};
const Chants = [{ id: 'test', name: 'Testchant', attributes: ['MU', 'KL', 'CH'] }];
command.__set__('Chants', Chants);
const getChant = command.__get__('getChant');
expect(getChant({ Character: Character, chant_name: 'well-hidden' })).toBeNull();
});
});

View File

@ -0,0 +1,109 @@
require('module-alias/register');
require('babel-plugin-rewire');
const command = require('@dsabot/getSpell');
describe('getSpell integration test', () => {
it('should not find an entry for a spell', () => {
const getSpell = command.__get__('getSpell');
expect(getSpell({ Character: { name: '' }, spell_name: 'test' })).toBeNull();
});
it('should return null if char has no spells.', () => {
const Character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
{ id: 'charisma', level: 12 },
],
};
command.__set__('Spells', [
{ id: 'test', name: 'Test', attributes: ['MU', 'KL', 'CH'], modified_by: ['SK'] },
]);
const getSpell = command.__get__('getSpell');
expect(getSpell({ Character: Character, spell_name: 'test' })).toBeNull();
});
it('should return a correct spell result.', () => {
const Character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
{ id: 'charisma', level: 12 },
],
spells: [{ id: 'test', level: 7 }, { id: 'no-level' }],
};
const Spells = [
{
id: 'test',
name: 'Testspell',
attributes: ['MU', 'KL', 'CH'],
modified_by: ['SK'],
},
{ id: 'no-level', name: 'No Level', attributes: ['MU', 'KL', 'CH'], modified_by: [] },
];
command.__set__('Spells', Spells);
const getSpell = command.__get__('getSpell');
expect(getSpell({ Character: Character, spell_name: 'test' })).toEqual(
expect.objectContaining({
Name: 'Testspell',
Level: 7,
Attributes: [
{ Level: 10, Name: 'MU' },
{ Level: 11, Name: 'KL' },
{ Level: 12, Name: 'CH' },
],
ModifiedBy: ['SK'],
})
);
expect(getSpell({ Character: Character, spell_name: 'Testspell' })).toEqual(
expect.objectContaining({
Name: 'Testspell',
Level: 7,
Attributes: [
{ Level: 10, Name: 'MU' },
{ Level: 11, Name: 'KL' },
{ Level: 12, Name: 'CH' },
],
ModifiedBy: ['SK'],
})
);
expect(getSpell({ Character: Character, spell_name: 'no-level' })).toEqual(
expect.objectContaining({
Name: 'No Level',
Level: 0,
Attributes: [
{ Level: 10, Name: 'MU' },
{ Level: 11, Name: 'KL' },
{ Level: 12, Name: 'CH' },
],
ModifiedBy: [],
})
);
});
it('should not find the spell.', () => {
const Character = {
attributes: [
{ id: 'mut', level: 10 },
{ id: 'klugheit', level: 11 },
{ id: 'charisma', level: 12 },
],
spells: [{ id: 'test', level: 7 }],
};
const Spells = [{ id: 'test', name: 'Testspell', attributes: ['MU', 'KL', 'CH'] }];
command.__set__('Spells', Spells);
const getSpell = command.__get__('getSpell');
expect(getSpell({ Character: Character, spell_name: 'well-hidden' })).toBeNull();
});
});

View File

@ -0,0 +1,12 @@
require('module-alias/register');
const { isEmpty } = require('@dsabot/isEmpty');
it('should return true statements', () => {
expect(isEmpty({})).toBeTruthy();
expect(isEmpty()).toBeTruthy();
expect(isEmpty('')).toBeTruthy();
expect(isEmpty([])).toBeTruthy();
expect(isEmpty({ key: 'value' })).toBeFalsy();
expect(isEmpty([null])).toBeFalsy();
expect(isEmpty([''])).toBeFalsy();
});

View File

@ -0,0 +1,12 @@
require('module-alias/register');
const { isString } = require('@dsabot/isString');
it('should return true statements', () => {
expect(isString({})).toBeFalsy();
expect(isString()).toBeFalsy();
expect(isString('')).toBeTruthy();
expect(isString([])).toBeFalsy();
expect(isString({ key: 'value' })).toBeFalsy();
expect(isString([null])).toBeFalsy();
expect(isString([''])).toBeFalsy();
});

16
babel.config.js Normal file
View File

@ -0,0 +1,16 @@
module.exports = {
plugins: [
'babel-plugin-rewire',
[
'module-resolver',
{
root: ['.'],
alias: {
'@Lib': './lib',
'@dsabot': './functions',
'@Commands': './commands',
},
},
],
],
};

View File

@ -1,124 +1,162 @@
const globals = require('../globals');
const db = globals.db;
const Random = require('random');
//const { roll } = require('@dsabot/Roll');
const { findMessage }= require('@dsabot/findMessage');
require('module-alias/register');
const { roll } = require('@dsabot/Roll');
const { findMessage } = require('@dsabot/findMessage');
const { isEmpty } = require('@dsabot/isEmpty');
const { db } = require('../globals');
const { CombatTechniques } = require('../globals');
const { Werte } = require('../globals');
const { Weapons } = require('../globals');
const { MeleeWeapons } = require('../globals');
function getCombatTechnique(Weapon) {
if (Weapon) return CombatTechniques.find(technique => technique.id === Weapon.combattechnique);
return null;
}
function getAttribute(abbr) {
return Werte.find(attribute => attribute.kuerzel === abbr);
}
function CompareAttackResult(dice = [8, 8], Comparison = 6) {
let ok = false;
let crit = false;
let dd = false;
let fumble = false;
dice.forEach((val, index) => {
if (index === 0) {
ok = val <= Comparison ? true : false;
crit = val === 1 ? true : false;
fumble = val === 20 ? true : false;
if ((ok && !crit) || (!ok && !fumble)) {
dice.pop();
}
}
if (index === 1) {
dd = crit && val < Comparison ? true : false;
fumble = !crit && val > Comparison ? true : false;
}
});
return {
Ok: ok,
Patzer: fumble,
CriticalHit: crit,
DoubleDamage: dd,
Dice: dice,
};
}
function getAttributeLevel(Player = {}, Attribute = '') {
return Player.attributes.find(a => a.id === Attribute).level;
}
function getCombatTechniqueLevel(Player = {}, CombatTechnique = {}) {
if (Player && CombatTechnique) {
const p = Player.combattechniques.find(technique => technique.id === CombatTechnique.id);
return {
id: CombatTechnique.id,
name: CombatTechnique.name,
level: p ? p.level : 6,
Leiteigenschaft: CombatTechnique.Leiteigenschaft,
};
}
return null;
}
function getWeapon(Weapon = '') {
return Weapons.find(
w => w.id === Weapon.toLowerCase() || w.name.toLowerCase() === Weapon.toLowerCase()
);
}
function isMeleeWeapon(Weapon) {
if (MeleeWeapons.find(MeleeWeapon => MeleeWeapon.id === Weapon.id)) return true;
return false;
}
function handleAttack(doc, { message, args }) {
if (isEmpty(doc)) {
return message.reply(findMessage('NOENTRY'));
}
const Player = doc.character;
const Weapon = getWeapon(args[0]);
if (!Weapon) {
return message.reply(findMessage('NO_SUCH_WEAPON'));
}
// Determining Both Attack and Ranged Attack Values.
const CombatTechnique = getCombatTechniqueLevel(Player, getCombatTechnique(Weapon)); //?+
const Attribute = isMeleeWeapon(Weapon)
? getAttributeLevel(Player, 'mut')
: getAttributeLevel(Player, 'fingerfertigkeit');
let AttackValue = isMeleeWeapon(Weapon)
? CombatTechnique.level + Weapon.at_mod
: CombatTechnique.level;
AttackValue += Math.floor((Attribute - 8) / 3);
const { dice } = roll(2, 20);
const Bonus = parseInt(args[1], 10) || 0;
const Comparison = Math.floor(AttackValue + Bonus);
const AttackResult = CompareAttackResult(dice, Comparison);
let Reply = `Du greifst mit ${Weapon.name} an.\n Dein Angriffswert für ${CombatTechnique.name} ist ${AttackValue} (KtW: ${CombatTechnique.level})\n`;
Reply += `Deine 🎲: \` ${AttackResult.Dice.join(', ')} \`\n\n`;
Reply += !AttackResult.Ok ? findMessage('COMBAT_FAIL') : findMessage('COMBAT_SUCCESS');
Reply += AttackResult.Patzer ? findMessage('COMBAT_CRIT_FAIL') : '';
Reply += AttackResult.CriticalHit ? findMessage('COMBAT_CRIT_SUCCESS') : '';
Reply += AttackResult.DoubleDamage ? findMessage('COMBAT_DOUBLEDAMAGE') : '';
if (AttackResult.Ok) {
// adding 1 to damage for every point above weapon's "Leiteigenschaft"
// applies only to Melee Weapons.
let AttackBonus = 0;
if (isMeleeWeapon(Weapon) && Weapon.DmgThreshold) {
CombatTechnique.Leiteigenschaft.forEach(abbr => {
const attrib = getAttribute(abbr);
const AttributeValue = getAttributeLevel(Player, attrib.id);
if (Weapon.DmgThreshold < AttributeValue) {
AttackBonus += Math.floor(AttributeValue - Weapon.DmgThreshold);
}
});
}
const DamageDice = roll(1, 6).dice;
let Damage = Weapon.diemodificator + AttackBonus + DamageDice.reduce((p, v) => p + v);
Damage = AttackResult.DoubleDamage ? (Damage *= 2) : Damage;
Reply += '\n\nHier aufklappen, wenn der Gegner nicht parieren/Ausweichen konnte:\n';
Reply += `||\n`;
Reply += ` ${Weapon.name} (${Weapon.dice}W6+${
Weapon.diemodificator
}) richtet ${Damage} schaden an. ${
AttackBonus ? `(+${AttackBonus} Bonus auf Leiteigenschaft)` : ''
}`;
Reply += `\nDeine 🎲: ${DamageDice.join(', ')}\n||\n`;
}
return message.reply(Reply);
}
module.exports = {
name: 'attack',
description: 'Würfelt den Attackewert auf eine Nahkampfwaffe.',
aliases: ['angriff','attacke'],
usage: '<Waffe>',
needs_args: true,
name: 'attack',
description: 'Würfelt den Attackewert auf eine Nahkampfwaffe.',
aliases: ['angriff', 'attacke'],
usage: '<Waffe>',
needs_args: true,
async exec(message, args) {
try {
db.find({
user: message.author.tag,
}, function(err, docs) {
if (docs.length === 0) {
return message.reply(findMessage('NOENTRY'));
}
else {
Random.use(message.author.tag);
const Player = docs[0].character;
const Weapon = globals.Weapons.find(w => w.id === args[0].toLowerCase());
if(!Weapon) { return message.reply(globals.Replies.find(r => r.id === 'NO_SUCH_WEAPON').string); }
// Determining Both Attack and Ranged Attack Values.
const CombatTechnique = globals.CombatTechniques.find(technique => technique.id === Weapon.combattechnique);
let PlayerCombatTechnique = Player.combattechniques.find(technique => technique.id === CombatTechnique.id);
let CombatTechniqueValue = null;
if (PlayerCombatTechnique) { CombatTechniqueValue = PlayerCombatTechnique.level; }
if(!CombatTechniqueValue) { CombatTechniqueValue = 6; }
let Attribute;
let AttackValue = CombatTechniqueValue;
if (globals.MeleeWeapons.find(MeleeWeapon => MeleeWeapon.id === Weapon.id)) {
// For melee combat, MU is used for determining the Attack Value. Also, any weapon-based attack modifiers apply.
Attribute = Player.attributes.find(a => a.id === 'mut').level;
AttackValue += Weapon.at_mod;
}
else {
// For ranged combat, FF is used for determining Attack Value
Attribute = Player.attributes.find(a => a.id === 'fingerfertigkeit').level;
}
AttackValue += Math.floor((Attribute - 8)/3);
let dice = [];
let Bonus = 0;
if(args[1] && !isNaN(parseInt(args[1]))) { Bonus = parseInt(args[1]); }
let Comparison = Math.floor(AttackValue + Bonus);
let CriticalHit = false;
let Patzer = false;
let Ok = false;
let DoubleDamage = false;
for (let i = 0; i < 2; i++) {
dice.push(Random.int(1,20));
}
// If there is a cleaner way to do these checks, I'm all into it.
if((dice[0] == 1) && dice[1] <= Comparison) { CriticalHit = true; DoubleDamage = true; Ok = true; }
else if((dice[0] == 1) && dice[1] > Comparison) { CriticalHit = true; Ok = true; }
else if((dice[0] == 20) && dice[1] > Comparison) { Patzer = true; }
else if(dice[0] <= Comparison && !CriticalHit) { Ok = true; dice.pop(); }
else if(dice[0] > Comparison ) { dice.pop(); }
let Reply = 'Du greifst mit ' + globals.Declination[Weapon.article] + ' ' + Weapon.name + ' an.\n';
Reply += 'Dein Angriffswert für ' + CombatTechnique.name + ' ist ' + Math.floor(((Attribute - 8)/3) + CombatTechniqueValue) + '. (KtW: ' + CombatTechniqueValue + ')\n';
Reply += 'Deine 🎲: ` ' + dice.join(', ') + ' `.\n\n';
if(!Ok) {
Reply += globals.Replies.find(reply => reply.id === 'COMBAT_FAIL').string;
if(Patzer) { Reply += globals.Replies.find(reply => reply.id === 'COMBAT_CRIT_FAIL').string; }
}
else {
if(CriticalHit) { Reply += globals.Replies.find(reply => reply.id === 'COMBAT_CRIT_SUCCESS').string; }
if(DoubleDamage) { Reply += globals.Replies.find(reply => reply.id === 'COMBAT_DOUBLEDAMAGE').string; }
if(!CriticalHit) { Reply += globals.Replies.find(reply => reply.id === 'COMBAT_SUCCESS').string; }
// adding 1 to damage for every point above weapon's "Leiteigenschaft"
// applies only to Melee Weapons.
let AttackBonus = 0;
if (globals.MeleeWeapons.find(MeleeWeapon => MeleeWeapon.id === Weapon.id))
{
if(Weapon.DmgThreshold) {
CombatTechnique.Leiteigenschaft.forEach(LEKuerzel => {
let Leiteigenschaft = globals.Werte.find(attribute => attribute.kuerzel === LEKuerzel);
let DmgThreshold = Weapon.DmgThreshold;
let AttributeValue = Player.attributes.find(attribute => attribute.id === Leiteigenschaft.id).level;
if(DmgThreshold<AttributeValue) {
AttackBonus += Math.floor(AttributeValue - DmgThreshold);
}
});
}
}
const DieModificator = Weapon.diemodificator;
let Damage = DieModificator + AttackBonus;
let DamageDice = [];
for (let i = 0; i < Weapon.dice; i++) {
DamageDice.push(Random.int(1,6));
}
DamageDice.forEach(result => {
Damage += result;
});
if(DoubleDamage) { Damage *= 2; }
Reply += '\n\nHier aufklappen, wenn der Gegner nicht parieren/Ausweichen konnte:\n';
Reply += '||' + globals.Articles[Weapon.article] + ' ' + Weapon.name + ' (' + Weapon.dice + 'W6+' + Weapon.diemodificator +') erzielt ` ' + Damage + ' ` Schaden.';
Reply += '\nDeine 🎲: ` ' + DamageDice.join(',') + ' `.||\n';
}
return message.reply( Reply );
}
});
}
catch (e) {
throw e;
}
},
};
async exec(message, args) {
db.findOne({ user: message.author.tag })
.then(doc => {
handleAttack(doc, { message, args });
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

View File

@ -1,96 +1,89 @@
const globals = require('../globals');
const { CountOccurences } = require('@dsabot/CountOccurences');
const { findMessage } = require('@dsabot/findMessage');
const Random = require('random');
const db = globals.db;
module.exports = {
name: 'attribute',
description: '',
aliases: ['ap', 'ep'],
usage: '<Eigenschaft> / <Eigenschaftswert>',
needs_args: true,
async exec(message, args) {
try {
let Attribute;
let AttributeName;
let Level = 8;
await db.find({
user: message.author.tag,
}, async (err, docs) => {
// user calls with text, let's look him up in the database.
if (isNaN(args[0])) {
Attribute = HandleNamedAttributes({
Character: docs[0].character,
args: args
});
AttributeName = Attribute.Name;
Level = Attribute.Level;
} else {
Level = args[0];
}
Random.use(message.author.tag);
const dice = [];
dice.push(Random.int(1, 20));
if (dice[0] == 1 || dice[0] == 20) {
dice.push(Random.int(1, 20));
}
// handle crits
if (CountOccurences(dice, 1) == 2) {
message.reply('Du hast einen kritischen Erfolg erzielt (' + dice.join(', ') + ')! 🎉🥳🎆');
return;
} else if (CountOccurences(dice, 20) == 2) {
message.reply('Du hast einen Patzer (' + dice.join(', ') + ')! 😭 Viel Erfolg beim nächsten mal!');
return;
}
if ((dice.length == 2 && dice[0] != 20 && dice[1] <= Level) || (dice.length == 1 && dice[0] <= Level)) {
if (AttributeName) {
message.reply('Du hast die Probe auf ' + AttributeName + ' (Stufe ' + Level + ') bestanden.\n' +
'Deine 🎲: ' + dice.join(', '));
} else {
message.reply('Du hast die Probe (Stufe ' + Level + ') bestanden.\n' +
'Deine 🎲: ' + dice.join(', '));
}
} else if (AttributeName) {
message.reply('Du hast die Probe auf ' + AttributeName + ' (Stufe ' + Level + ') leider nicht bestanden 😢.\n' +
'Deine 🎲: ' + dice.join(', '));
} else {
message.reply('Du hast die Probe (Stufe ' + Level + ') leider nicht bestanden 😢.\n' +
'Deine 🎲: ' + dice.join(', '));
}
});
} catch (e) {
throw e;
}
},
};
const HandleCrits = (dice) => {
};
const HandleNamedAttributes = ({Character: Character = [], args: args = []} = {}) => {
let Attributes = globals.Werte;
let Level = 8; // This is the minimum attributes value.
let AttributeName;
let AttributeId;
if (args[0].length == 2) {
AttributeId = Attributes.find(attribute => attribute.kuerzel === args[0].toUpperCase()).id;
} else {
AttributeId = args[0].toLowerCase() ||
Attributes.find(attribute => attribute.name.toLowerCase() === args[0].toLowerCase()).id;
}
Level = Character.attributes.find(attribute => attribute.id === AttributeId).level;
AttributeName = Attributes.find(attribute => attribute.id === AttributeId).name;
return {
Name: AttributeName,
Level: Level
};
};
require('module-alias/register');
const { roll } = require('@dsabot/Roll');
const { findMessage } = require('@dsabot/findMessage');
const { CompareResults } = require('@dsabot/CompareResults');
const { isEmpty } = require('@dsabot/isEmpty');
const { isString } = require('@dsabot/isString');
const { db } = require('../globals');
const { Werte } = require('../globals');
function getAttributeLevel(Character = {}, Attribute = {}) {
return Character.attributes.find(attribute => attribute.id === Attribute.id).level;
}
function getAttribute(attribute = '') {
return attribute.length === 2
? Werte.find(a => a.kuerzel === attribute.toUpperCase())
: Werte.find(a => a.name.toLowerCase() === attribute.toLowerCase());
}
function HandleNamedAttributes({ Character = {}, args = [] } = {}) {
const Attribute = getAttribute(args[0]);
const Level = getAttributeLevel(Character, Attribute) || 8;
return {
Name: Attribute.name,
Level,
};
}
function handleAttributeCheck(doc, { message, args }) {
if (isEmpty(doc)) {
return message.reply(findMessage('NOENTRY'));
}
const Attribute = isString(args[0])
? HandleNamedAttributes({ Character: doc.character, args: args })
: null;
const Level = Attribute ? Attribute.Level : args[0] || 8;
const Bonus = parseInt(args[1], 10) || 0;
const { dice } = roll(2, 20, message.author.tag);
const Result = CompareResults(dice, [Level, Level], Bonus);
// handle crits
if (Result.CriticalHit === 2) {
return message.reply(
`${findMessage('TITLE_CRIT_SUCCESS')}\n${findMessage('MSG_CRIT_SUCCESS')}`
);
}
if (Result.Fumbles === 2) {
return message.reply(
`${findMessage('TITLE_CRIT_FAILURE')}\n${findMessage('MSG_CRIT_FAILURE')}`
);
}
// every
if (dice[0] + Bonus > Level) {
return message.reply(
`Du hast die Probe (Stufe ${Level}) leider nicht bestanden 😢.\nDeine 🎲: ${dice[0]} ${
Bonus ? `+${Bonus}` : ''
}`
);
}
if (Attribute) {
return message.reply(
`Du hast die Probe auf ${Attribute.Name} (Stufe ${
Attribute.Level
}) bestanden. Deine 🎲: ${dice[0]} ${Bonus ? `+${Bonus}` : ''}`
);
}
return message.reply(
`Du hast die Probe (Stufe ${Level}) bestanden. Deine 🎲: ${dice[0]} ${
Bonus ? `+${Bonus}` : ''
}`
);
}
module.exports = {
name: 'attribute',
description: '',
aliases: ['ap', 'ep'],
usage: '<Eigenschaft> / <Eigenschaftswert>',
needs_args: true,
async exec(message, args) {
db.findOne({ user: message.author.tag })
.then(doc => handleAttributeCheck(doc, { message, args }))
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

108
commands/Cast.js Normal file
View File

@ -0,0 +1,108 @@
const Discord = require('discord.js');
const { roll } = require('@dsabot/Roll');
const { findMessage } = require('@dsabot/findMessage');
const { getSpell } = require('@dsabot/getSpell');
const { CalculateQuality } = require('@dsabot/CalculateQuality');
const { CompareResults } = require('@dsabot/CompareResults');
const { CreateResultTable, f } = require('@dsabot/CreateResultTable');
const { isEmpty } = require('@dsabot/isEmpty');
const { isString } = require('@dsabot/isString');
const { db } = require('../globals');
module.exports = {
name: 'cast',
description:
' Du machst eine Fertigkeitsprobe auf Magietalente.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Deine Boni werden in' +
' die Berechnung einbezogen.',
aliases: ['zaubern'],
usage: '<Zaubern> [<-Erschwernis> / <+Erleichterung>]',
needs_args: false,
async exec(message, args) {
db.findOne({ user: message.author.tag })
.then(doc => {
if (isEmpty(doc)) {
return message.reply(findMessage('NOENTRY'));
}
if (!doc.character.hasOwnProperty('spells'))
return message.reply(findMessage('NO_SPELLS'));
if (!isString(args[0])) {
return message.reply(findMessage('WRONG_ARGUMENTS'));
}
const Spell = getSpell({ Character: doc.character, spell_name: args[0] });
if (!Spell) {
return message.reply(findMessage('SPELL_UNKNOWN'));
}
if (!Spell.Level || !Spell.Attributes) {
return null;
}
const { Attributes } = Spell;
const DiceThrow = roll(3, 20, message.author.tag).dice;
const Bonus = parseInt(args[1], 10) || 0;
const {
Passed,
CriticalHit,
Fumbles,
PointsUsed,
PointsRemaining,
} = CompareResults(
DiceThrow,
Attributes.map(attr => attr.Level),
Bonus,
Spell.Level
);
const Reply = new Discord.MessageEmbed();
Reply.addFields({
name: `Du würfelst auf den Zauber **${Spell.Name}** ( Stufe ${Spell.Level} ${
Bonus ? `${f(Bonus)} ` : ''
})`,
value: CreateResultTable({
Attributes: Attributes,
Throws: DiceThrow,
PointsUsed: PointsUsed,
Bonus: Bonus,
}),
inline: false,
});
if (Fumbles >= 2) {
Reply.setColor('#900c3f');
Reply.addFields({
name: findMessage('TITLE_CRIT_FAILURE'),
value: findMessage('MSG_CRIT_FAILURE'),
inline: false,
});
} else if (CriticalHit >= 2) {
Reply.setColor('#1E8449');
Reply.addFields({
name: findMessage('TITLE_CRIT_SUCCESS'),
value: findMessage('MSG_CRIT_SUCCESS'),
inline: false,
});
} else if (Passed < 3) {
Reply.addFields({
name: findMessage('TITLE_FAILURE'),
value: `${
Passed === 0 ? 'Keine Probe' : `nur ${Passed}/3 Proben`
} erfolgreich. 😪`,
inline: false,
});
} else {
Reply.addFields({
name: findMessage('TITLE_SUCCESS'),
value: `Dein verbleibender Bonus: ${PointsRemaining}/${
Spell.Level
} (QS${CalculateQuality(PointsRemaining)})`,
inline: false,
});
}
return message.reply(Reply);
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

106
commands/Chant.js Normal file
View File

@ -0,0 +1,106 @@
const Discord = require('discord.js');
const { roll } = require('@dsabot/Roll');
const { findMessage } = require('@dsabot/findMessage');
const { getChant } = require('@dsabot/getChant');
const { CalculateQuality } = require('@dsabot/CalculateQuality');
const { CompareResults } = require('@dsabot/CompareResults');
const { CreateResultTable, f } = require('@dsabot/CreateResultTable');
const { isEmpty } = require('@dsabot/isEmpty');
const { isString } = require('@dsabot/isString');
const { db } = require('../globals');
module.exports = {
name: 'chant',
description:
' Du machst eine Fertigkeitsprobe auf Magietalente.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Deine Boni werden in' +
' die Berechnung einbezogen.',
aliases: [''],
usage: '<Liturgie/Zeremonie> [<-Erschwernis> / <+Erleichterung>]',
needs_args: false,
async exec(message, args) {
db.findOne({ user: message.author.tag })
.then(doc => {
if (isEmpty(doc)) {
return message.reply(findMessage('NOENTRY'));
}
if (!doc.character.hasOwnProperty('chants'))
return message.reply(findMessage('NO_CHANTS'));
if (!isString(args[0])) {
return message.reply(findMessage('WRONG_ARGUMENTS'));
}
const Chant = getChant({ Character: doc.character, chant_name: args[0] });
if (!Chant) {
return message.reply(findMessage('CHANT_UNKNOWN'));
}
if (!Chant.Level || !Chant.Attributes) {
return null;
}
const { Attributes } = Chant;
const DiceThrow = roll(3, 20, message.author.tag).dice;
const Bonus = parseInt(args[1], 10) || 0;
const {
Passed,
CriticalHit,
Fumbles,
PointsUsed,
PointsRemaining,
} = CompareResults(
DiceThrow,
Attributes.map(attr => attr.Level),
Bonus,
Chant.Level
);
const Reply = new Discord.MessageEmbed();
Reply.addFields({
name: `Du würfelst auf die Liturgie **${Chant.Name}** ( Stufe ${Chant.Level} ${
Bonus ? `${f(Bonus)} ` : ''
})`,
value: CreateResultTable({
Attributes: Attributes,
Throws: DiceThrow,
PointsUsed: PointsUsed,
Bonus: Bonus,
}),
inline: false,
});
if (Fumbles >= 2) {
Reply.setColor('#900c3f');
Reply.addFields({
name: findMessage('TITLE_CRIT_FAILURE'),
value: findMessage('MSG_CRIT_FAILURE'),
inline: false,
});
} else if (CriticalHit >= 2) {
Reply.setColor('#1E8449');
Reply.addFields({
name: findMessage('TITLE_CRIT_SUCCESS'),
value: findMessage('MSG_CRIT_SUCCESS'),
inline: false,
});
} else if (Passed < 3) {
Reply.addFields({
name: findMessage('TITLE_FAILURE'),
value: `${
Passed === 0 ? 'Keine Probe' : `nur ${Passed}/3 Proben`
} erfolgreich. 😪`,
inline: false,
});
} else {
Reply.addFields({
name: findMessage('TITLE_SUCCESS'),
value: `Dein verbleibender Bonus: ${PointsRemaining}/${
Chant.Level
} (QS${CalculateQuality(PointsRemaining)})`,
inline: false,
});
}
return message.reply(Reply);
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

72
commands/Chants.js Normal file
View File

@ -0,0 +1,72 @@
require('module-alias/register');
const Discord = require('discord.js');
const { findMessage } = require('@dsabot/findMessage');
const { getChant } = require('@dsabot/getChant');
const { isEmpty } = require('@dsabot/isEmpty');
const { db } = require('../globals');
const createChantList = (Character = {}) => {
if (!Character || !Character.hasOwnProperty('chants')) return null;
const ChantList = [];
Character.chants.forEach(chant =>
ChantList.push(getChant({ Character: Character, chant_name: chant.id }))
);
return ChantList.filter(value => value !== undefined && value !== null);
};
const ReplyChantList = (ChantList = []) => {
if (!ChantList || ChantList.length === 0) return null;
return `${ChantList.map(chant => `${chant.Name} ${chant.Level ? `(${chant.Level})` : ''}`).join(
'\n'
)}`;
};
const ReplyChant = (Chant = {}) => {
if (!Chant || Object.keys(Chant).length === 0) return null;
return `Deine Werte für ${Chant.Name} ${Chant.Level ? `(${Chant.Level})` : ''} sind:
${Chant.Attributes.map(attribute => `${attribute.Name}: ${attribute.Level}`).join(' ')}
`;
};
module.exports = {
name: 'chants',
description: 'Zeigt dir deinen Fertigkeitswert im jeweiligen Magietalent (Götterwirken).',
aliases: ['segen', 'liturgie', 'liturgien', 'zeremonien'],
usage: '[<Liturgie / Zeremonie>]',
needs_args: false,
async exec(message, args) {
db.findOne({ user: message.author.tag })
.then(doc => {
if (isEmpty(doc)) {
return message.reply(findMessage('NOENTRY'));
}
console.log(doc.character);
const Character = doc.character;
if (!Character.hasOwnProperty('chants'))
return message.reply(findMessage('NO_CHANTS'));
if (args.length === 0) {
const Embed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle(findMessage('CHANTS_TITLE'))
.setDescription(findMessage('CHANTS_DESCRIPTION'))
.addField(ReplyChantList(createChantList(Character)), '\u200B', true);
return message.reply(Embed);
}
const Chant = getChant({
Character: Character,
chant_name: args[0],
});
if (!Chant) {
return message.reply(findMessage('SPELL_UNKNOWN'));
}
return message.reply(ReplyChant(Chant));
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

View File

@ -1,16 +1,16 @@
const globals = require('../globals');
const { roll } = require('@dsabot/Roll');
const { findMessage }= require('@dsabot/findMessage');
const { findMessage } = require('@dsabot/findMessage');
const { Coin } = require('../globals');
module.exports = {
name: 'kopf',
description: 'Wirf eine Münze. Kopf oder Zahl?',
aliases: ['zahl', 'heads', 'tails'],
usage: '',
needs_args: false,
name: 'kopf',
description: 'Wirf eine Münze. Kopf oder Zahl?',
aliases: ['zahl', 'heads', 'tails'],
usage: '',
needs_args: false,
async exec(message, args) {
const coin = roll(1,2,message.author.tag).dice;
message.reply(`${findMessage('HEADS_OR_TAILS')} **${globals.Coin[(coin-1)]}**.`);
},
};
async exec(message) {
const { dice } = roll(1, 2, message.author.tag);
message.reply(`${findMessage('HEADS_OR_TAILS')} **${Coin[dice - 1]}**.`);
},
};

View File

@ -1,81 +1,97 @@
const Discord = require('discord.js');
const cmdprefix = process.env.CMDPREFIX || '!';
const prfx = process.env.CMDPREFIX || '!';
module.exports = {
name: 'help',
description: '',
aliases: ['hilfe'],
usage: '',
needs_args: false,
async exec(message, args) {
const Help = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('Hilfe')
.setDescription('Das sind die Befehle, die du verwenden kannst.\n' +
'Werte in Klammern müssen nicht mit angegeben werden.')
name: 'help',
description: '',
aliases: ['hilfe'],
usage: '',
needs_args: false,
async exec(message) {
const Help = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('Hilfe')
.setDescription(
'Das sind die Befehle, die du verwenden kannst.\n' +
'Werte in Klammern müssen nicht mit angegeben werden.'
)
.addFields({
name: cmdprefix + 'kopf',
value: 'Wirf eine Münze. Kopf oder Zahl?',
inline: false,
}, {
name: cmdprefix + 'roll <Anzahl> W <Augenzahl>',
value: 'Lass die Würfel rollen. Benötigt wird die Anzahl sowie die Augenzahl auf den Würfeln.',
inline: false,
}, {
name: cmdprefix + 'ep/ap <Eigenschaftswert>',
value: ' Du machst eine Eigenschaftsprobe / Attributprobe.\n' +
' Du würfelst mit einem W20 auf deinen Eigenschaftswert.\n' +
' Bei einer 1 oder 20 wird der Bestätigungswurf ausgeführt.',
inline: false,
}, {
name: cmdprefix + 'tp/fp <Eigenschaftswert1> <Eigenschaftswert2> <Eigenschaftswert3> (Fertigkeitswert) (+Erleichtert/-Erschwert)',
value: ' Du machst eine Fertigkeitsprobe.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder' +
' ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.',
inline: false,
}, {
name: cmdprefix + 'talents',
value: ' Du erhälst eine Liste mit den Talentnamen, die du für ' +
cmdprefix + 'talent/' + cmdprefix + 'skill nutzen kannst.',
inline: false,
}, {
name: cmdprefix + 'weapons',
value: ' Du erhälst eine Liste mit den Waffen, die du für ' +
cmdprefix + 'attack/' + cmdprefix + 'angriff nutzen kannst.',
inline: false,
}, {
name: '\u200B',
value: '\u200B',
}, {
name: '\u200B',
value: 'Wenn du mir deine .tdc Datei zusendest, kannst du folgendes nutzen:',
}, {
name: cmdprefix + 'attack [Waffe] (+Erleichtert/-Erschwert)',
value: 'Du greifst mit deiner Waffe an. Es wird gleichzeitig Schaden gewürfelt, sofern dein Gegner den Schaden nicht abwenden kann.',
inline: false,
}, {
name: cmdprefix + 'parry [Waffe] (+Erleichtert/-Erschwert)',
value: 'Du versuchst, mit der gewählten Waffe zu parieren.',
inline: false,
},{
name: cmdprefix + 'ep/ap [Klugheit] oder ' + cmdprefix + 'ep/ap [FF]',
value: 'siehe oben. Du brauchst deinen Wert nicht wissen.',
inline: false,
}, {
name: cmdprefix + 'talent <Talentname> (+Erleichtert/-Erschwert)',
value: 'siehe tp. Allerdings musst du deine Werte nicht wissen.',
inline: false,
}, {
name: cmdprefix + 'skill <Talentname>',
value: 'Zeigt dir deinen Fertigkeitswert im jeweiligen Talent.',
inline: false,
}, {
name: cmdprefix + 'remove',
value: 'Löscht deinen Charakter aus der Datenbank. Sinnvoll, wenn du mir eine neue zusenden möchtest.',
inline: false,
});
message.author.send(Help);
},
};
.addFields(
{
name: `${prfx}kopf`,
value: `Wirf eine Münze. Kopf oder Zahl?`,
inline: false,
},
{
name: `${prfx}roll <Anzahl> W <Augenzahl>`,
value: `Lass die Würfel rollen. Benötigt wird die Anzahl sowie die Augenzahl auf den Würfeln.`,
inline: false,
},
{
name: `${prfx}ep/ap <Eigenschaftswert>`,
value:
`Du machst eine Eigenschaftsprobe / Attributprobe.\n` +
` Du würfelst mit einem W20 auf deinen Eigenschaftswert.\n` +
` Bei einer 1 oder 20 wird der Bestätigungswurf ausgeführt.`,
inline: false,
},
{
name: `${prfx}tp/fp <Eigenschaftswert1> <Eigenschaftswert2> <Eigenschaftswert3> (Fertigkeitswert) (+Erleichtert/-Erschwert)`,
value:
` Du machst eine Fertigkeitsprobe.\n` +
` Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder` +
` ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.`,
inline: false,
},
{
name: `${prfx}talents`,
value: `Du erhälst eine Liste mit den Talentnamen, die du für ${prfx}talent/${prfx}skill nutzen kannst.`,
inline: false,
},
{
name: `${prfx}weapons`,
value: `Du erhälst eine Liste mit den Waffen, die du für ${prfx}attack/${prfx}angriff nutzen kannst.`,
inline: false,
},
{
name: '\u200B',
value: '\u200B',
},
{
name: '\u200B',
value: 'Wenn du mir deine .tdc Datei zusendest, kannst du folgendes nutzen:',
},
{
name: `${prfx}attack [Waffe] (+Erleichtert/-Erschwert)`,
value: `Du greifst mit deiner Waffe an. Es wird gleichzeitig Schaden gewürfelt, sofern dein Gegner den Schaden nicht abwenden kann.`,
inline: false,
},
{
name: `${prfx}parry [Waffe] (+Erleichtert/-Erschwert)`,
value: `Du versuchst, mit der gewählten Waffe zu parieren.`,
inline: false,
},
{
name: `${prfx}ep/ap [Klugheit] oder ${prfx}ep/ap [FF]`,
value: `siehe oben. Du brauchst deinen Wert nicht wissen.`,
inline: false,
},
{
name: `${prfx}talent <Talentname> (+Erleichtert/-Erschwert)`,
value: `siehe tp. Allerdings musst du deine Werte nicht wissen.`,
inline: false,
},
{
name: `${prfx}skill <Talentname>`,
value: `Zeigt dir deinen Fertigkeitswert im jeweiligen Talent.`,
inline: false,
},
{
name: `${prfx}remove`,
value: `Löscht deinen Charakter aus der Datenbank. Sinnvoll, wenn du mir eine neue zusenden möchtest.`,
inline: false,
}
);
message.author.send(Help);
},
};

114
commands/List.js Normal file
View File

@ -0,0 +1,114 @@
require('module-alias/register');
const { findMessage } = require('@dsabot/findMessage');
const { isEmpty } = require('@dsabot/isEmpty');
const { db } = require('../globals');
const { Werte } = require('../globals');
function printHeader(attributes) {
if (!attributes) return null;
return `${''.padStart(31)}${attributes
.map(a => `${a.Short}`.padEnd(4).padStart(6))
.join('|')}\n`.toString();
}
function listStats(attributes) {
return `${attributes.map(a => `${a.Level}`.padEnd(4).padStart(6)).join('|')}\n`;
}
function getAttribute(attribute_request = { id: 'mut', level: 9 }) {
const Attribute = Werte.find(a => a.id === attribute_request.id);
return {
id: Attribute.id,
Name: Attribute.name,
Short: Attribute.kuerzel,
Level: attribute_request.level,
};
}
function getStats(user) {
const Attributes = [];
user.character.attributes.forEach(attribute => {
Attributes.push(getAttribute(attribute));
});
Attributes.sort((a, b) => (a.id > b.id ? 1 : -1));
return Attributes;
}
function returnResult(message, Characters) {
if (isEmpty(Characters)) return message.reply(findMessage('NO_CHARACTERS'));
Characters.sort((a, b) => (a.Name > b.Name ? 1 : -1));
let Reply = `\`\`\`\n${printHeader(Characters[0].Attributes)}`;
Characters.forEach(c => {
Reply += `${c.Name.toString().padEnd(30)} ${listStats(c.Attributes)}`;
});
Reply += `\`\`\``;
return message.reply(Reply);
}
async function findUser(request = '') {
return db
.findOne({
$or: [
{ user: request.replace('@', '') },
{ uid: request.replaceAll(/[<>!@]/gi, '') },
{ character: { name: request } },
],
})
.then(doc => doc);
}
async function findUsers(message) {
const Characters = [];
db.find({})
.limit(10)
.then(users => {
users.forEach(user => {
Characters.push({
Name: user.character.name,
Attributes: getStats(user),
});
});
})
.then(() => returnResult(message, Characters));
}
module.exports = {
name: 'list',
description: 'Gibt eine Liste von Mitspielern aus.',
aliases: ['liste'],
usage: '[@Mention / Benutzername]',
needs_args: false,
exec: async (message, args) => {
if (!args) return null;
if (args[0] === '--all') {
return findUsers(message);
}
const Characters = []; //?+
Promise.all(
args
.map(arg => findUser(arg))
.then(user => {
if (!isEmpty(user)) {
Characters.push({
Name: user.character.name,
Attributes: getStats(user),
});
}
})
).then(() => returnResult(message, Characters));
return null;
},
};
/*
(async () => {
db.loadDatabase();
const l = require('./List');
const msg = { author: { tag: 'tagged!' }, reply: e => console.log(e) };
l.exec(msg, ['tobenderzephyr#2509', 'ElManu#8438']);
})();
*/

View File

@ -1,85 +1,104 @@
const globals = require('../globals');
const db = globals.db;
const Random = require('random');
const { findMessage } = require('@dsabot/findMessage');
const { isEmpty } = require('@dsabot/isEmpty');
const { Random } = require('@dsabot/Random');
const { db } = require('../globals');
const { Werte } = require('../globals');
const { Weapons } = require('../globals');
const { CombatTechniques } = require('../globals');
const { MeleeWeapons } = require('../globals');
module.exports = {
name: 'parry',
description: 'Würfelt den Paradewert auf eine Nahkampfwaffe.',
aliases: ['parieren','parade'],
usage: '<Waffe>',
needs_args: true,
name: 'parry',
description: 'Würfelt den Paradewert auf eine Nahkampfwaffe.',
aliases: ['parieren', 'parade'],
usage: '<Waffe>',
needs_args: true,
async exec(message, args) {
try {
db.find({
user: message.author.tag,
}, function(err, docs) {
if (docs.length === 0) {
return message.reply(globals.Replies.find(r => r.id === 'NOENTRY').string);
}
else {
async exec(message, args) {
db.find({ user: message.author.tag }).then(docs => {
if (isEmpty(docs)) {
return message.reply(findMessage('NOENTRY'));
}
Random.use(message.author.tag);
const Player = docs[0].character;
const Weapon = Weapons.find(w => w.id === args[0].toLowerCase());
if (!Weapon) {
return message.reply(findMessage('NO_SUCH_WEAPON'));
}
const Player = docs[0].character;
const Weapon = globals.Weapons.find(w => w.id === args[0].toLowerCase());
if(!Weapon) { return message.reply(globals.Replies.find(r => r.id === 'NO_SUCH_WEAPON').string);}
if (!MeleeWeapons.find(MeleeWeapon => MeleeWeapon.id === Weapon.id)) {
return message.reply(findMessage('PARRY_WRONG_WEAPON'));
}
const CombatTechnique = CombatTechniques.find(
technique => technique.id === Weapon.combattechnique
);
const PlayerCombatTechnique = Player.combattechniques.find(
technique => technique.id === CombatTechnique.id
);
let CombatTechniqueValue = null;
if (PlayerCombatTechnique) {
CombatTechniqueValue = PlayerCombatTechnique.level;
}
if (!CombatTechniqueValue) {
CombatTechniqueValue = 6;
}
if(!globals.MeleeWeapons.find(MeleeWeapon => MeleeWeapon.id === Weapon.id)) {
return message.reply(globals.Replies.find(r => r.id === 'PARRY_WRONG_WEAPON').string);
}
const CombatTechnique = globals.CombatTechniques.find(technique => technique.id === Weapon.combattechnique);
let PlayerCombatTechnique = Player.combattechniques.find(technique => technique.id === CombatTechnique.id);
let CombatTechniqueValue = null;
if (PlayerCombatTechnique) { CombatTechniqueValue = PlayerCombatTechnique.level; }
if(!CombatTechniqueValue) { CombatTechniqueValue = 6; }
let ParryValue = Math.ceil(CombatTechniqueValue / 2);
CombatTechniqueValue.Leiteigenschaft.forEach(Property => {
const Attribute = Werte.find(a => a.kuerzel === Property.id);
ParryValue += Math.floor(
(Player.attributes.find(a => a.id === Attribute).level - 8) / 3
);
});
ParryValue += Weapon.pa_mod;
let ParryValue = Math.ceil(CombatTechniqueValue/2);
CombatTechniqueValue.Leiteigenschaft.forEach( Property => {
let Attribute = globals.Werte.find(a => a.kuerzel === Property.id);
ParryValue += Math.floor((Player.attributes.find(a => a.id === Attribute).level - 8)/3);
});
ParryValue += Weapon.pa_mod;
const dice = [];
let dice = [];
let Bonus = 0;
if(args[1] && !isNaN(parseInt(args[1]))) { Bonus = parseInt(args[1]); }
let Comparison = Math.floor(ParryValue + Bonus);
let Patzer = false;
let Critical = false;
let Ok = false;
const Bonus = parseInt(args[1], 10) || 0;
for (let i = 0; i < 2; i++) {
dice.push(Random.int(1,20));
}
const Comparison = Math.floor(ParryValue + Bonus);
let Patzer = false;
let Critical = false;
let Ok = false;
// If there is a cleaner way to do these checks, I'm all into it.
if((dice[0] == 1) && dice[1] <= Comparison) { Critical = true; Ok = true; }
else if(dice[0] <= Comparison && !Critical) { Ok = true; dice.pop(); }
else if((dice[0] == 20) && dice[1] > Comparison) { Patzer = true; }
else if(dice[0] > Comparison ) { dice.pop(); }
for (let i = 0; i < 2; i += 1) {
dice.push(Random.int(1, 20));
}
// If there is a cleaner way to do these checks, I'm all into it.
if (dice[0] === 1 && dice[1] <= Comparison) {
Critical = true;
Ok = true;
} else if (dice[0] <= Comparison && !Critical) {
Ok = true;
dice.pop();
} else if (dice[0] === 20 && dice[1] > Comparison) {
Patzer = true;
} else if (dice[0] > Comparison) {
dice.pop();
}
let Reply = 'Du versuchst, mit ' + globals.Declination[Weapon.article] + ' ' + Weapon.name + ' zu parieren.\n';
Reply += 'Dein Paradewert für ' + CombatTechnique.name + ' ist ' + Math.floor(ParryValue - Weapon.pa_mod) + '. (Waffe: ' + Weapon.pa_mod + ')\n';
Reply += 'Deine 🎲: ` ' + dice.join(', ') + ' `.\n\n';
let Reply = `Du versuchst, mit ${Weapon.name} zu parieren.\n`;
Reply += `Dein Paradewert für ${CombatTechnique.name} ist ${Math.floor(
ParryValue - Weapon.pa_mod
)}. (Waffe ${Weapon.pa_mod})\n`;
Reply += `Deine 🎲: ${dice.join(', ')}\n\n`;
if(!Ok) {
Reply += globals.Replies.find(reply => reply.id === 'PARRY_FAIL').string;
if(Patzer) { Reply += globals.Replies.find(reply => reply.id === 'PARRY_CRIT_FAIL').string; }
}
else {
if(Critical) { Reply += globals.Replies.find(reply => reply.id === 'PARRY_CRIT_SUCCESS').string; }
if(!Critical) { Reply += globals.Replies.find(reply => reply.id === 'PARRY_SUCCESS').string; }
}
if (!Ok) {
Reply += findMessage('PARRY_FAIL');
if (Patzer) {
Reply += findMessage('PARRY_CRIT_FAIL');
}
} else {
if (Critical) {
Reply += findMessage('PARRY_CRIT_SUCCESS');
}
if (!Critical) {
Reply += findMessage('PARRY_SUCCESS');
}
}
return message.reply( Reply );
}
});
}
catch (e) {
throw e;
}
},
};
return message.reply(Reply);
});
},
};

View File

@ -1,17 +1,20 @@
const { findMessage }= require('@dsabot/findMessage');
const globals = require('../globals');
const db = globals.db;
const { findMessage } = require('@dsabot/findMessage');
const { db } = require('../globals');
module.exports = {
name: 'remove',
description: 'Löscht deinen Charakter aus der Datenbank. Sinnvoll, wenn du mir eine neue zusenden möchtest.',
aliases: [],
usage: '',
needs_args: false,
async exec(message, args) {
db.remove({
user: message.author.tag,
}, {}, function(err, numRemoved) {
return message.reply(findMessage('DELETED_DATA'));
});
},
};
name: 'remove',
description:
'Löscht deinen Charakter aus der Datenbank. Sinnvoll, wenn du mir eine neue zusenden möchtest.',
aliases: [],
usage: '',
needs_args: false,
// eslint-disable-next-line no-unused-vars
async exec(message) {
db.remove({ user: message.author.tag })
.then(() => message.reply(findMessage('DELETED_DATA')))
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

View File

@ -1,24 +1,28 @@
// eslint-disable-next-line no-unused-vars
const globals = require('../globals');
const { roll } = require('@dsabot/Roll');
const { findMessage }= require('@dsabot/findMessage');
const { findMessage } = require('@dsabot/findMessage');
const { DiceRegex } = require('../globals');
module.exports = {
name: 'roll',
description: 'Lass die Würfel rollen. Benötigt wird die Anzahl sowie die Augenzahl auf den Würfeln.',
aliases: ['r'],
usage: '<Anzahl> w <Augenzahl>',
needs_args: true,
async exec(message, args) {
let params = args.join('').split(globals.DiceRegex);
if ( params.length >= 2 ) {
const Bonus = parseInt(params[2]) || 0;
const numberOfDice = parseInt( params[0] );
const diceValues = parseInt( params[1] );
const result = roll( numberOfDice, diceValues, message.author.tag );
let total = (Bonus ? Bonus + result.sum : result.sum)
message.reply(`${findMessage('ROLL')} ${result.dice.join(', ')} `+
`(Gesamt: ${result.sum}${Bonus ? `+${Bonus}=${total}` : ``})` );
}
},
name: 'roll',
description:
'Lass die Würfel rollen. Benötigt wird die Anzahl sowie die Augenzahl auf den Würfeln.',
aliases: ['r'],
usage: '<Anzahl> w <Augenzahl>',
needs_args: true,
async exec(message, args) {
const params = args.join('').split(DiceRegex);
if (params.length >= 2) {
const Bonus = parseInt(params[2], 10) || 0;
const numberOfDice = parseInt(params[0], 10);
const diceValues = parseInt(params[1], 10);
const result = roll(numberOfDice, diceValues, message.author.tag);
const total = Bonus ? Bonus + result.sum : result.sum;
message.reply(
`${findMessage('ROLL')} \` ${result.dice.join(' `, ` ')} \`` +
` (Gesamt: ${result.sum}${Bonus ? `+${Bonus}=${total}` : ``})`
);
}
},
};

View File

@ -1,41 +1,39 @@
// eslint-disable-next-line no-unused-vars
const globals = require('../globals');
const Discord = require('discord.js');
const db = globals.db;
const { findMessage }= require('@dsabot/findMessage');
const { findMessage } = require('@dsabot/findMessage');
const { isEmpty } = require('@dsabot/isEmpty');
const { db } = require('../globals');
module.exports = {
name: 'show',
description: '',
aliases: [],
usage: '',
needs_args: false,
name: 'show',
description: '',
aliases: [],
usage: '',
needs_args: false,
async exec(message, args) {
try {
db.find({
user: message.author.tag,
}, function(err, docs) {
if (docs.length === 0) {
return message.reply(findMessage('NOENTRY'));
}
else {
const Character = docs[0].character;
let Gender;
if (Character.sex == 'female') { Gender = '♀️'; }
else { Gender = '♂️'; }
const Reply = new Discord.MessageEmbed();
Reply.setColor('#0099ff');
Reply.setTitle(`${Gender} ${Character.name}`);
Reply.setDescription(`${Character.age} Jahre, ${Character.race}/${Character.culture}`);
Reply.addField(Character.professionname, Character.xp.startinglevel);
message.reply( Reply );
}
});
}
catch (e) {
throw e;
}
},
};
async exec(message) {
db.find({ user: message.author.tag })
.then(docs => {
if (isEmpty(docs)) {
return message.reply(findMessage('NOENTRY'));
}
const Character = docs[0].character;
const Gender = Character.sex === 'female' ? '♀️' : '♂️';
const Reply = new Discord.MessageEmbed();
Reply.setColor('#0099ff');
Reply.setTitle(`${Gender} ${Character.name}`);
Reply.setDescription(
`${Character.age} Jahre, ${Character.race}/${Character.culture}`
);
Reply.addField(Character.professionname, Character.xp.startinglevel);
return message.reply(Reply);
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

View File

@ -1,31 +1,30 @@
const globals = require('../globals');
const db = globals.db;
const { findMessage }= require('@dsabot/findMessage');
const { findMessage } = require('@dsabot/findMessage');
const { getSkill } = require('@dsabot/getSkill');
module.exports = {
name: 'skill',
description: 'Zeigt dir deinen Fertigkeitswert im jeweiligen Talent.',
aliases: [],
usage: '<Fertigkeit>',
needs_args: true,
const { isEmpty } = require('@dsabot/isEmpty');
const { db } = require('../globals');
async exec(message, args) {
try {
db.find({
user: message.author.tag,
}, function(err, docs) {
if (docs.length === 0) {
return message.reply(findMessage('NOENTRY'));
}
else {
const Skill = getSkill({Character: docs[0].character, args: args});
if(!Skill) { return message.reply(findMessage('TALENT_UNKNOWN'));}
return message.reply(`Du hast folgenden Wert in **${Skill.Name}**: ${Skill.Level}`)
}
});
}
catch (e) {
throw e;
}
},
};
module.exports = {
name: 'skill',
description: 'Zeigt dir deinen Fertigkeitswert im jeweiligen Talent.',
aliases: [],
usage: '<Fertigkeit>',
needs_args: true,
async exec(message, args) {
db.find({ user: message.author.tag })
.then(docs => {
if (isEmpty(docs)) {
return message.reply(findMessage('NOENTRY'));
}
const Skill = getSkill({ Character: docs[0].character, args: args });
if (!Skill) {
return message.reply(findMessage('TALENT_UNKNOWN'));
}
return message.reply(`Du hast folgenden Wert in **${Skill.Name}**: ${Skill.Level}`);
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

65
commands/Spells.js Normal file
View File

@ -0,0 +1,65 @@
const Discord = require('discord.js');
const { findMessage } = require('@dsabot/findMessage');
const { getSpell } = require('@dsabot/getSpell');
const { db } = require('../globals');
const { isEmpty } = require('@dsabot/isEmpty');
const ReplySpellList = (SpellList = []) => {
if (isEmpty(SpellList)) return findMessage('NO_SPELLS');
return `${SpellList.map(s => `${s.Name} (${s.Level})`).join('\n')}`;
};
const ReplySpell = (Spell = {}) => {
if (isEmpty(Spell)) return null;
return `Deine Werte für ${Spell.Name} (${Spell.Level}) sind:
${Spell.Attributes.map(attribute => `${attribute.Name}: ${attribute.Level}`).join(' ')}
`;
};
const createSpellList = (Character = {}) => {
if (!Character || !Character.hasOwnProperty('spells')) return null;
const SpellList = [];
Character.spells.forEach(spell =>
SpellList.push(getSpell({ Character: Character, spell_name: spell.id }))
);
return SpellList.filter(value => value !== undefined && value !== null); //?+
};
module.exports = {
name: 'spells',
description: 'Zeigt dir deinen Fertigkeitswert im jeweiligen Magietalent.',
aliases: ['spell', 'zauber'],
usage: '<Zauber>',
needs_args: false,
async exec(message, args) {
db.find({ user: message.author.tag })
.then(docs => {
if (docs.length === 0) {
return message.reply(findMessage('NOENTRY'));
}
const Character = docs[0].character;
if (!Character.hasOwnProperty('spells'))
return message.reply(findMessage('NO_SPELLS'));
if (args.length === 0) {
const Embed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle(findMessage('SPELLS_TITLE'))
.setDescription(findMessage('SPELLS_DESCRIPTION'))
.addField(ReplySpellList(createSpellList(Character)), '\u200B', true);
return message.reply(Embed);
}
const Spell = getSpell({
Character: Character,
spell_name: args[0],
});
if (!Spell) return message.reply(findMessage('SPELL_UNKNOWN'));
return message.reply(ReplySpell(Spell));
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};

View File

@ -1,101 +1,99 @@
const globals = require('../globals');
const Discord = require('discord.js');
const db = globals.db;
const { roll } = require('@dsabot/Roll');
const { findMessage } = require('@dsabot/findMessage');
const { roll } = require('@dsabot/Roll');
const { findMessage } = require('@dsabot/findMessage');
const { getSkill } = require('@dsabot/getSkill');
const { CalculateQuality } = require('@dsabot/CalculateQuality');
const { CompareResults } = require('@dsabot/CompareResults');
const { CreateResultTable } = require('@dsabot/CreateResultTable');
const { isString } = require('@dsabot/isString');
const { db } = require('../globals');
module.exports = {
name: 'talent',
description: ' Du machst eine Fertigkeitsprobe.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder' +
' ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.',
aliases: ['t'],
usage: '<Talent> [<-Erschwernis> / <+Erleichterung>]',
needs_args: true,
async exec(message, args) {
try {
db.find({
user: message.author.tag,
}, function (err, docs) {
if (docs.length === 0) {
return message.reply(findMessage('NOENTRY'));
}
if (!isNaN(args[0])) {
return message.reply(findMessage('WRONG_ARGUMENTS'));
} else {
const Skill = getSkill({Character: docs[0].character, args: args});
if(!Skill) { return message.reply(findMessage('TALENT_UNKNOWN'));}
const Attributes = Skill.Attributes;
const DiceThrow = roll(3, 20, message.author.tag).dice;
const Bonus = parseInt(args[1]) || 0;
let { Passed,
CriticalHit,
Fumbles,
PointsUsed,
PointsRemaining } = CompareResults(
DiceThrow,
Attributes.map(attr => attr.Level),
Bonus,
Skill.Level);
const Reply = new Discord.MessageEmbed();
Reply.addFields({
name: `Du würfelst auf das Talent **${Skill.Name}** (Stufe ${Skill.Level} + ${Bonus})`,
value: CreateTable({Attributes: Attributes, Throws: DiceThrow, PointsUsed: PointsUsed}),
inline: false
});
if (Fumbles >= 2) {
Reply.setColor('#900c3f');
Reply.addFields({
name: findMessage('TITLE_CRIT_FAILURE'),
value: findMessage('MSG_CRIT_FAILURE'),
inline: false
});
} else if (CriticalHit >= 2) {
Reply.setColor('#1E8449');
Reply.addFields({
name: findMessage('TITLE_CRIT_SUCCESS'),
value: findMessage('MSG_CRIT_SUCCESS'),
inline: false
});
} else if (Passed < 3) {
Reply.addFields({
name: findMessage('TITLE_FAILURE'),
value: `${(Passed === 0) ? 'Keine Probe' : `nur ${Passed}/3 Proben`} erfolgreich. 😪`,
inline: false
});
} else {
Reply.addFields({
name: findMessage('TITLE_SUCCESS'),
value: `Dein verbleibender Bonus: ${PointsRemaining}/${Skill.Level} (QS${CalculateQuality(PointsRemaining)})`,
inline: false
});
}
message.reply(Reply);
}
});
} catch (e) {
throw e;
}
},
name: 'talent',
description:
' Du machst eine Fertigkeitsprobe.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder' +
' ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.',
aliases: ['t'],
usage: '<Talent> [<-Erschwernis> / <+Erleichterung>]',
needs_args: true,
async exec(message, args) {
db.find({ user: message.author.tag })
.then(docs => {
if (docs.length === 0) {
return message.reply(findMessage('NOENTRY'));
}
if (!isString(args[0])) {
return message.reply(findMessage('WRONG_ARGUMENTS'));
}
const Skill = getSkill({ Character: docs[0].character, args: args });
if (!Skill) {
return message.reply(findMessage('TALENT_UNKNOWN'));
}
const { Attributes } = Skill;
const DiceThrow = roll(3, 20, message.author.tag).dice;
const Bonus = parseInt(args[1], 10) || 0;
const {
Passed,
CriticalHit,
Fumbles,
PointsUsed,
PointsRemaining,
} = CompareResults(
DiceThrow,
Attributes.map(attr => attr.Level),
Bonus,
Skill.Level
);
const Reply = new Discord.MessageEmbed();
Reply.addFields({
name: `Du würfelst auf das Talent **${Skill.Name}** (Stufe ${Skill.Level} + ${Bonus})`,
value: CreateResultTable({
Attributes: Attributes,
Throws: DiceThrow,
PointsUsed: PointsUsed,
Bonus: Bonus,
}),
inline: false,
});
if (Fumbles >= 2) {
Reply.setColor('#900c3f');
Reply.addFields({
name: findMessage('TITLE_CRIT_FAILURE'),
value: findMessage('MSG_CRIT_FAILURE'),
inline: false,
});
} else if (CriticalHit >= 2) {
Reply.setColor('#1E8449');
Reply.addFields({
name: findMessage('TITLE_CRIT_SUCCESS'),
value: findMessage('MSG_CRIT_SUCCESS'),
inline: false,
});
} else if (Passed < 3) {
Reply.addFields({
name: findMessage('TITLE_FAILURE'),
value: `${
Passed === 0 ? 'Keine Probe' : `nur ${Passed}/3 Proben`
} erfolgreich. 😪`,
inline: false,
});
} else {
Reply.addFields({
name: findMessage('TITLE_SUCCESS'),
value: `Dein verbleibender Bonus: ${PointsRemaining}/${
Skill.Level
} (QS${CalculateQuality(PointsRemaining)})`,
inline: false,
});
}
return message.reply(Reply);
})
.catch(err => {
message.reply(findMessage('ERROR'));
throw new Error(err);
});
},
};
function Pad(Number = 0) {
return Number.toString().padStart(1, ' ');
}
const CreateTable = ({Attributes: Attributes, Throws: Throws, PointsUsed: PointsUsed}) => {
return `
\`\`\`
${' '.padEnd(15)} ${Attributes.map(attr => `${attr.Name}`.padStart(5)).join('\t|\t')}\t|
${'Dein Wert'.padEnd(15)} ${Attributes.map(attr => `${attr.Level}`.padStart(5)).join('\t|\t')}\t|
${'Dein Wurf'.padEnd(15)} ${Throws.map(Throw => `${Throw}`.padStart(5)).join('\t|\t')}\t|
${'Abzüge'.padEnd(15)} ${PointsUsed.map(Points => `${Points}`.replace(0,'--').padStart(5)).join('\t|\t')}\t|
${'Gesamt'.padEnd(15)} ${PointsUsed.reduce((acc,cur) => acc+cur).toString().padStart(5)}
\`\`\`
`;
};

View File

@ -1,42 +1,42 @@
const globals = require('../globals');
const Discord = require('discord.js');
const { Capitalize } = require('@dsabot/Capitalize');
module.exports = {
name: 'talents',
description: '',
aliases: [],
usage: '',
needs_args: false,
async exec(message, args) {
const Embed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('Talentübersicht')
.setDescription('Das sind die Talente, die ich kenne:');
for (let Talent of GenerateTalentList()) {
Embed.addField(Talent.Category, Talent.Talents.join('\n'), true);
}
message.author.send(
Embed,
);
},
};
const { TalentKategorien } = require('../globals');
const { Talente } = require('../globals');
const GenerateTalentList = () => {
const Categories = globals.TalentKategorien;
const Talents = globals.Talente;
const TalentList = [];
const TalentList = [];
TalentKategorien.forEach(Category => {
TalentList.push({
Category: Category,
Talents: Talente.filter(
Talent => Talent.categoryid === TalentKategorien.indexOf(Category)
)
.map(Talent => Capitalize(Talent.id))
.sort(),
});
});
Categories.forEach(Category => {
TalentList.push({
Category: Category,
Talents: Talents.filter(Talent => Talent.categoryid === Categories.indexOf(Category))
.map(Talent => Capitalize(Talent.id))
.sort()
});
});
return TalentList.sort();
};
return TalentList.sort();
};
module.exports = {
name: 'talents',
description: '',
aliases: [],
usage: '',
needs_args: false,
async exec(message) {
const Embed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('Talentübersicht')
.setDescription('Das sind die Talente, die ich kenne:');
const TalentList = GenerateTalentList();
TalentList.forEach(Talent => {
Embed.addField(Talent.Category, Talent.Talents.join('\n'), true);
});
return message.author.send(Embed);
},
};

View File

@ -1,85 +1,66 @@
// eslint-disable-next-line no-unused-vars
const Random = require('random');
const globals = require('../globals');
const Discord = require('discord.js');
const { roll } = require('@dsabot/Roll');
const { findMessage }= require('@dsabot/findMessage');
const { findMessage } = require('@dsabot/findMessage');
const { CompareResults } = require('@dsabot/CompareResults');
module.exports = {
name: 'tp',
description: 'Du machst eine Fertigkeitsprobe.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder' +
' ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.',
aliases: ['talentprobe'],
usage: '<Eigenschaftswert1> <Eigenschaftswert2> <Eigenschaftswert3> [<Fertigkeitswert>] [<-Erschwernis> / <+Erleichterung>]',
needs_args: true,
name: 'tp',
description:
'Du machst eine Fertigkeitsprobe.\n' +
' Es werden drei Würfel auf deine Eigenschaftswerte geworfen. Hast du Boni auf dein Talent und/oder' +
' ist der Wurf erleichtert oder erschwert, wird dies in die Berechnung einbezogen.',
aliases: ['talentprobe'],
usage:
'<Eigenschaftswert1> <Eigenschaftswert2> <Eigenschaftswert3> [<Fertigkeitswert>] [<-Erschwernis> / <+Erleichterung>]',
needs_args: true,
async exec(message, args) {
async exec(message, args) {
if (Number.isNaN(args[0])) {
return message.reply(findMessage('WRONG_ARGUMENTS'));
}
if(isNaN(args[0])) {
return message.reply(findMessage('WRONG_ARGUMENTS'));
}
const Bonus = parseInt(args[3], 10) || 0;
const Erschwernis = parseInt(args[4], 10) || 0;
//Random.use(message.author.tag);
//const dice = [];
let bonus = 0;
let bonus_orig = 0;
let erschwernis = 0;
if (args[3]) {
bonus_orig = parseInt(args[3]);
bonus = bonus_orig;
}
if (args[4]) {
erschwernis = parseInt(args[4]);
}
/*for (let i = 1; i <= 3; i++) {
roll.push(Random.int(1, 20));
}*/
const dice = roll(3,20,message.author.tag).dice;
const { dice } = roll(3, 20, message.author.tag);
let ok = 0;
let patzer = 0;
let crit = 0;
for (let i = 0; i < 3; i++) {
if (Math.floor(parseInt(args[i]) + parseInt(erschwernis)) >= dice[i]) {
ok++;
} else if (
Math.floor(parseInt(args[i]) + parseInt(bonus) + parseInt(erschwernis)) >= dice[i]) {
ok++;
bonus = bonus - (dice[i] - parseInt(erschwernis) - parseInt(args[i]));
}
if (dice[i] == 1) {crit++;}
if (dice[i] == 20) {patzer++;}
}
const { Passed, CriticalHit, Fumbles, PointsRemaining } = CompareResults(
dice,
[parseInt(args[0], 10), parseInt(args[1], 10), parseInt(args[2], 10)],
Bonus,
Erschwernis
);
const Reply = new Discord.MessageEmbed();
Reply.setTitle(`${findMessage('ROLL')} ${dice.join(', ')}.`);
if (patzer >= 2) {
Reply.setColor('#900c3f');
Reply.addFields({
name: findMessage('TITLE_CRIT_FAILURE'),
value: findMessage('MSG_CRIT_FAILURE'),
inline: false
});
} else if (crit >= 2) {
Reply.setColor('#1E8449');
Reply.addFields({
name: findMessage('TITLE_CRIT_SUCCESS'),
value: findMessage('MSG_CRIT_SUCCESS'),
inline: false
});
} else if (ok < 3) {
Reply.addFields({
name: findMessage('TITLE_FAILURE'),
value: 'Nur ' + ok + '/3 Proben erfolgreich. 😪',
inline: false
});
} else {
Reply.addFields({
name: findMessage('TITLE_SUCCESS'),
value: ok + '/3 Proben erfolgreich. Dein Bonus: ' + bonus + '/' + bonus_orig + '.',
inline: false
});
}
message.reply(Reply);
}
};
const Reply = new Discord.MessageEmbed();
Reply.setTitle(`${findMessage('ROLL')} \` ${dice.join(' ` ` ')} \``);
if (Fumbles >= 2) {
Reply.setColor('#900c3f');
Reply.addFields({
name: findMessage('TITLE_CRIT_FAILURE'),
value: findMessage('MSG_CRIT_FAILURE'),
inline: false,
});
} else if (CriticalHit >= 2) {
Reply.setColor('#1E8449');
Reply.addFields({
name: findMessage('TITLE_CRIT_SUCCESS'),
value: findMessage('MSG_CRIT_SUCCESS'),
inline: false,
});
} else if (Passed < 3) {
Reply.addFields({
name: findMessage('TITLE_FAILURE'),
value: `${Passed ? `Nur ${Passed}/3 Proben` : `Keine Probe`} erfolgreich. 😪`,
inline: false,
});
} else {
Reply.addFields({
name: findMessage('TITLE_SUCCESS'),
value: `${Passed}/3 Proben erfolgreich. Dein Bonus: ${PointsRemaining}/${Bonus}`,
inline: false,
});
}
return message.reply(Reply);
},
};

View File

@ -1,41 +1,38 @@
const globals = require('../globals');
const Discord = require('discord.js');
const { Capitalize } = require('@dsabot/Capitalize');
module.exports = {
name: 'weapons',
description: 'Listet eine Übersicht, welche für einen Angriff genutzt werden können.',
aliases: ['waffen'],
usage: '',
needs_args: false,
async exec(message, args) {
const Embed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('Waffenübersicht')
.setDescription('Folgende Waffen können für einen Angriff genutzt werden:');
for (let Technique of GenerateWeaponList()) {
Embed.addField(Technique.Technique_Name, Technique.Weapons.join('\n'), true);
}
message.author.send(
Embed,
);
},
};
const { CombatTechniques } = require('../globals');
const { Weapons } = require('../globals');
const GenerateWeaponList = () => {
let WeaponList = [];
const Techniques = globals.CombatTechniques;
const Weapons = globals.Weapons;
Techniques.forEach(Technique => {
WeaponList.push({
Technique_Name: Technique.name,
Weapons: Weapons.filter(Weapon => Weapon.combattechnique === Technique.id)
.map(Weapon => Capitalize(Weapon.id))
});
});
return WeaponList.sort();
const WeaponList = [];
CombatTechniques.forEach(Technique => {
WeaponList.push({
Technique_Name: Technique.name,
Weapons: Weapons.filter(Weapon => Weapon.combattechnique === Technique.id).map(Weapon =>
Capitalize(Weapon.id)
),
});
});
return WeaponList.sort();
};
module.exports = {
name: 'weapons',
description: 'Listet eine Übersicht, welche für einen Angriff genutzt werden können.',
aliases: ['waffen'],
usage: '',
needs_args: false,
async exec(message) {
const Embed = new Discord.MessageEmbed()
.setColor('#0099ff')
.setTitle('Waffenübersicht')
.setDescription('Folgende Waffen können für einen Angriff genutzt werden:');
const WeaponList = GenerateWeaponList();
WeaponList.forEach(Technique => {
Embed.addField(Technique.Technique_Name, Technique.Weapons.join('\n'), true);
});
return message.author.send(Embed);
},
};

View File

@ -1 +0,0 @@

View File

@ -1,15 +1,9 @@
const CalculateQuality = (PointsAvailable = 0) => {
if (PointsAvailable <= 3)
return 1;
else if (PointsAvailable > 3 && PointsAvailable <= 6)
return 2;
else if (PointsAvailable > 6 && PointsAvailable <= 9)
return 3;
else if (PointsAvailable > 9 && PointsAvailable <= 12)
return 4;
else if (PointsAvailable > 12 && PointsAvailable <= 15)
return 5;
else if (PointsAvailable > 15)
return 6;
if (PointsAvailable <= 3) return 1;
if (PointsAvailable > 3 && PointsAvailable <= 6) return 2;
if (PointsAvailable > 6 && PointsAvailable <= 9) return 3;
if (PointsAvailable > 9 && PointsAvailable <= 12) return 4;
if (PointsAvailable > 12 && PointsAvailable <= 15) return 5;
return 6;
};
module.exports = { CalculateQuality };

View File

@ -1,5 +1,3 @@
const Capitalize = (Word = 'none') => {
return Word[0].toUpperCase() + Word.substring(1);
};
const Capitalize = (Word = 'none') => `${Word[0].toUpperCase() + Word.substring(1)}`;
module.exports = { Capitalize };

View File

@ -1,6 +0,0 @@
const Compare = () => {
return { result };
};
module.exports = { Compare };

View File

@ -1,35 +1,47 @@
const CompareResults = (Throws = [], AttributeLevels = [8, 8, 8], Bonus = 0, PointsRemaining = 0) => {
/**
* Compares each item inside an array Throws
* with corresponding AttributeLevels (With added bonus)
*
* @param {Array} Throws=[]
* @param {Array} AttributeLevels=[8,8,8]
* @param {BigInt} Bonus=0
* @param {BigInt} PointsRemaining=0
*/
const CompareResults = (Throws = [], AttributeLevels = [8, 8, 8], Bonus = 0, Points = 0) => {
let Passed = 0;
let Fumbles = 0;
let CriticalHit = 0;
let PointsRemaining = Points;
const AllPointsUsed = [];
let Passed = 0;
let Fumbles = 0;
let CriticalHit = 0;
let AllPointsUsed = [];
Throws.forEach((Throw, key) => {
let PointsUsed = 0;
const AttributeLevel = AttributeLevels.find((v, k) => key === k);
if (Math.floor(AttributeLevel + Bonus) >= Throw) {
Passed += 1;
} else if (Math.floor(AttributeLevel + PointsRemaining + Bonus) >= Throw) {
Passed += 1;
PointsUsed = Throw - Bonus - AttributeLevel;
PointsRemaining -= PointsUsed;
} else {
PointsUsed = PointsRemaining;
PointsRemaining -= PointsUsed;
}
if (Throw === 1) {
CriticalHit += 1;
}
if (Throw === 20) {
Fumbles += 1;
}
AllPointsUsed.push(PointsUsed);
});
for (let i = 0; i < Throws.length; i++) {
let PointsUsed = 0;
if (Math.floor(AttributeLevels[i] + Bonus) >= Throws[i]) {
Passed++;
} else if (Math.floor(AttributeLevels[i] + PointsRemaining + Bonus) >= Throws[i]) {
Passed++;
PointsUsed = (Throws[i] - Bonus - AttributeLevels[i]);
PointsRemaining -= PointsUsed;
}
else {
// We need to use all our points, so that next die/dice
// would not return a 'Passed'.
PointsUsed = PointsRemaining;
PointsRemaining -= PointsUsed;
}
if (Throws[i] == 1) { CriticalHit++; }
if (Throws[i] == 20) { Fumbles++; }
AllPointsUsed.push(PointsUsed);
}
return {
Passed: Passed,
CriticalHit: CriticalHit,
Fumbles: Fumbles,
PointsUsed: AllPointsUsed,
PointsRemaining: PointsRemaining
};
return {
Passed: Passed,
CriticalHit: CriticalHit,
Fumbles: Fumbles,
PointsUsed: AllPointsUsed,
PointsRemaining: PointsRemaining,
};
};
module.exports = { CompareResults };

View File

@ -1,5 +1,3 @@
const CountOccurences = (arr, value) => {
return arr.filter((v) => (v === value)).length;
};
const CountOccurences = (arr, value) => arr.filter(v => v === value).length;
module.exports = { CountOccurences };
module.exports = { CountOccurences };

View File

@ -0,0 +1,26 @@
function f(n) {
return (n > 0 ? '+' : '') + n;
}
const CreateResultTable = ({
Attributes: Attributes,
Throws: Throws,
PointsUsed: PointsUsed,
Bonus: Bonus = 0,
}) => `
\`\`\`
${''.padEnd(15)} ${Attributes.map(attr => `${attr.Name}`.padStart(6)).join('\t|\t')}\t|
${'Dein Wert'.padEnd(15)} ${Attributes.map(attr =>
`${attr.Level}${Bonus ? `(${f(Bonus)})` : ``}`.padStart(6)
).join('\t|\t')}\t|
${'Dein Wurf'.padEnd(15)} ${Throws.map(Throw => `${Throw}`.padStart(6)).join('\t|\t')}\t|
${'Abzüge'.padEnd(15)} ${PointsUsed.map(Points => `${Points}`.replace(0, '--').padStart(6)).join(
'\t|\t'
)}\t|
${'Gesamt'.padEnd(15)} ${PointsUsed.reduce((acc, cur) => acc + cur)
.toString()
.padStart(6)}
\`\`\`
`;
module.exports = { CreateResultTable, f };

View File

@ -1,13 +1,12 @@
const Random = {int, use};
function int (min, max) {
if (!min || !max) { return; }
//return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min))) + min;
return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min) + 1)) + min;
function int(min, max) {
if (!min || !max) {
return undefined;
}
function use (str) {
return true;
return Math.floor(Math.random() * (Math.floor(max) - Math.ceil(min) + 1)) + min;
}
module.exports = { Random };
function use() {
return true;
}
const Random = { int, use };
module.exports = { Random };

View File

@ -1,18 +1,17 @@
const { Random } = require("@dsabot/Random");
const { Random } = require('@dsabot/Random');
//const Random = require('random');
const roll = (numberOfDice, numberOfEyes, tag) => {
let dice = [];
const dice = [];
let sum = 0;
if(tag) {
if (tag) {
Random.use(tag);
}
for (let i = 0; i<numberOfDice; i++ ) {
let result = Random.int(1,numberOfEyes);
for (let i = 0; i < numberOfDice; i += 1) {
const result = Random.int(1, numberOfEyes);
dice.push(result);
sum += result;
}
return { dice, sum };
};
module.exports = { roll };

View File

@ -1,7 +1,5 @@
const globals = require('../globals');
const { Replies } = require('../globals');
const findMessage = (value) => {
return globals.Replies.find(r => r.id === value).string;
};
const findMessage = value => Replies.find(r => r.id === value).string;
module.exports = { findMessage };
module.exports = { findMessage };

View File

@ -1,14 +1,13 @@
const globals = require('../globals');
const { Werte } = require('../globals');
const getAttributeLevels = (Attributes = [], Character = {}) => {
let AttributeId;
let AttributeLevel;
let AttributeList = [];
for (let Attribute of Attributes) {
AttributeId = globals.Werte.find((attribute) => attribute.kuerzel === Attribute).id;
AttributeLevel = Character.attributes.find((att) => att.id === AttributeId).level;
AttributeList.push({ Name: Attribute, Level: AttributeLevel });
}
return AttributeList;
const AttributeList = [];
Attributes.forEach(Attribute => {
const { id } = Werte.find(att => att.kuerzel === Attribute);
const { level } = Character.attributes.find(att => att.id === id);
AttributeList.push({ Name: Attribute, Level: level });
});
return AttributeList;
};
module.exports = { getAttributeLevels};
module.exports = { getAttributeLevels };

20
functions/getChant.js Normal file
View File

@ -0,0 +1,20 @@
require('module-alias/register');
const { getAttributeLevels } = require('@dsabot/getAttributeLevels');
const Chants = require('@Lib/Chants.json');
const { isEmpty } = require('@dsabot/isEmpty');
const getChant = ({ Character: Character = [], chant_name: chantName = '' } = {}) => {
if (!Character.hasOwnProperty('chants')) return null;
const chantEntry =
Chants.find(chant => chant.id.toLowerCase() === chantName.toLowerCase()) ||
Chants.find(chant => chant.name.toLowerCase() === chantName.toLowerCase());
// let us filter out blessings.
if (isEmpty(chantEntry)) return null;
const Chant = Character.chants.find(chant => chant.id === chantEntry.id); // || null;
const Level = Chant.hasOwnProperty('level') ? Chant.level : 0;
const Attributes = getAttributeLevels(chantEntry.attributes, Character);
return { Name: chantEntry.name, Level: Level, Attributes: Attributes };
};
module.exports = { getChant };

View File

@ -1,24 +1,27 @@
const globals = require('../globals');
const { getAttributeLevels } = require("@dsabot/getAttributeLevels");
const { getAttributeLevels } = require('@dsabot/getAttributeLevels');
const { Talente } = require('../globals');
const getSkill = ({ Character: Character = [], args: args = [] } = {}) => {
let skill_entry = globals.Talente.find(skill => skill.id.toLowerCase() === args[0].toLowerCase()) ||
globals.Talente.find(skill => skill.name.toLowerCase() === args[0].toLowerCase());
const skillEntry =
Talente.find(skill => skill.id.toLowerCase() === args[0].toLowerCase()) ||
Talente.find(skill => skill.name.toLowerCase() === args[0].toLowerCase());
if (!skill_entry) { return; }
if (!skillEntry) {
return null;
}
let Level = 0; // This is the minimum attributes value.
let cSkill = Character.skills.find(skill => skill.id === skill_entry.id) || {};
if (cSkill) {
Level = cSkill.level || 0;
}
let Name = globals.Talente.find(skill => skill.id === skill_entry.id).name;
let Attributes = getAttributeLevels(skill_entry.values, Character);
let Level = 0; // This is the minimum attributes value.
const cSkill = Character.skills.find(skill => skill.id === skillEntry.id) || null;
if (cSkill) {
Level = cSkill.level || 0;
}
const Name = Talente.find(skill => skill.id === skillEntry.id).name;
const Attributes = getAttributeLevels(skillEntry.values, Character);
return {
Name: Name,
Level: Level,
Attributes: Attributes
};
return {
Name: Name,
Level: Level,
Attributes: Attributes,
};
};
module.exports = { getSkill };

21
functions/getSpell.js Normal file
View File

@ -0,0 +1,21 @@
const { getAttributeLevels } = require('@dsabot/getAttributeLevels');
const Spells = require('@Lib/Spells.json');
const { isEmpty } = require('@dsabot/isEmpty');
const getSpell = ({ Character: Character = [], spell_name: spellName = '' } = {}) => {
if (!Character.hasOwnProperty('spells')) return null;
const spellEntry =
Spells.find(spell => spell.id.toLowerCase() === spellName.toLowerCase()) ||
Spells.find(spell => spell.name.toLowerCase() === spellName.toLowerCase());
if (isEmpty(spellEntry)) return null;
const Spell = Character.spells.find(spell => spell.id === spellEntry.id); //?+
const Level = Spell.hasOwnProperty('level') ? Spell.level : 0;
const ModifiedBy = spellEntry.modified_by;
const Attributes = getAttributeLevels(spellEntry.attributes, Character);
return { Name: spellEntry.name, Level: Level, Attributes: Attributes, ModifiedBy: ModifiedBy };
};
module.exports = { getSpell };

6
functions/isEmpty.js Normal file
View File

@ -0,0 +1,6 @@
function isEmpty(document = {}) {
if (!document) return true;
if (document.length === 0) return true;
return Object.keys(document).length === 0 ? true : false;
}
module.exports = { isEmpty };

4
functions/isString.js Normal file
View File

@ -0,0 +1,4 @@
function isString(str) {
return typeof str === 'string' || str instanceof String ? true : false;
}
module.exports = { isString };

View File

@ -1,15 +1,12 @@
const Discord = require('discord.js');
const Datastore = require('nedb'),
db = new Datastore({
const Datastore = require('nedb-promises')
const db = Datastore.create({
filename: 'data/dsabot.db',
autoload: true,
autoload: false,
});
const MessageEmbed = new Discord.MessageEmbed();
const money = [{
'GD': 'Golddukaten',
'ST': 'Silbertaler',
}];
const DiceRegex = /\s?[DdWw]\s?|(?=\-|\+)/;
const DiceRegex = /\s?[DdWw]\s?|(?=-|\+)/;
const Coin = ['Kopf', 'Zahl'];
const Werte = [
{ id: 'mut', kuerzel: 'MU', name: 'Mut' },
@ -139,7 +136,16 @@ const Replies = [
{ id: 'PARRY_SUCCESS', string: 'Parade erfolgreich.'},
{ id: 'PARRY_CRIT_SUCCESS', string: 'Kritischer Erfolg! Du darfst einen Passierschlag ausführen!'},
{ id: 'ROLL', string: 'Du würfelst:'},
{ id: 'HEADS_OR_TAILS', string: 'Die Münze landet auf '}
{ id: 'HEADS_OR_TAILS', string: 'Die Münze landet auf ' },
{ id: 'SPELL_UNKNOWN', string: 'Diesen Zauber kenne ich nicht.' },
{ id: 'NO_SPELLS', string: 'Du kennst keine Zaubersprüche.' },
{ id: 'SPELLS_TITLE', string: 'Zaubersprüche'},
{ id: 'SPELLS_DESCRIPTION', string: 'Folgende Zaubersprüche beherrschst du:'},
{ id: 'NO_CHANTS', string: 'Du kennst keine Liturgien.' },
{ id: 'CHANTS_TITLE', string: 'Liturgien'},
{ id: 'CHANTS_DESCRIPTION', string: 'Folgende Liturgien beherrschst du:' },
{ id: 'CHANT_UNKNOWN', string: 'Diese Liturgie kenne ich nicht.' },
{ id: 'NO_CHARACTERS', string: 'Keine Benutzer auf dieser Liste gefunden.'}
];
const Declination = ['dem', 'der', 'dem', '']; // Maskulinum, Feminimum, Neutrum, None
const Articles = ['Der','Die','Das',''];
@ -225,11 +231,4 @@ const RangedWeapons = [
];
const Weapons = MeleeWeapons.concat(RangedWeapons);
const Advantages = [
{}
];
const Disadvantages = [
{}
];
module.exports = { Werte, Talente, Coin, TalentKategorien, DiceRegex, Discord, MessageEmbed, db, Replies, MeleeWeapons, Weapons, RangedWeapons, CombatTechniques, Articles, Declination };

127
index.js
View File

@ -1,85 +1,66 @@
require('module-alias/register');
require('dotenv').config();
const fs = require('fs');
const fetch = require('node-fetch');
const globals = require('./globals');
const db = globals.db;
const cmdprefix = process.env.CMDPREFIX || '!';
const got = require('got');
const Discord = require('discord.js');
const { findMessage } = require('@dsabot/findMessage');
const { db } = require('./globals');
db.load();
const cmdprefix = process.env.CMDPREFIX || '!';
const client = new Discord.Client();
async function CreateFromFile(message, data) {
db.find({
user: message.author.tag,
}).then(docs => {
if (docs.length === 0) {
db.insert({ uid: `${message.author.id}`, user: message.author.tag, character: data })
.then(() => message.reply(findMessage('SAVED_DATA')))
.catch(e => {
console.log(e);
message.reply(findMessage('ERROR'));
});
}
});
}
async function commandHandler(message) {
if (message.attachments.size > 0 && message.channel.type === 'dm' && !message.author.bot) {
try {
got(message.attachments.first().url).then(data => CreateFromFile(message, data.body));
} catch (e) {
console.log(e);
return message.reply(findMessage('ERROR'));
}
} else {
if (!message.content.startsWith(cmdprefix) || message.author.bot) {
return null;
}
const args = message.content.slice(cmdprefix.length).split(' ');
const commandName = args.shift().toLowerCase();
const command =
client.commands.get(commandName) ||
client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
if (!command) return null;
if (command.needs_args && !args.length) {
return message.reply(
`${findMessage('TOO_FEW_ARGS')}\n${cmdprefix}${commandName} ${command.usage}`
);
}
command.exec(message, args);
}
return null;
}
client.commands = new Discord.Collection();
client.on('message', commandHandler);
client.login(process.env.BOT_TOKEN);
client.once('ready', () => {
console.log('Ready!');
console.log('Ready!');
});
const commandFiles = fs.readdirSync('./commands/').filter(file => file.endsWith('.js'));
for (const file of commandFiles) {
const command = require(`./commands/${file}`);
client.commands.set(command.name, command);
}
async function commandHandler(message) {
//console.log(`${new Date().toUTCString()} ${message.author.tag} (size: ${message.attachments.size})`);
if ((message.attachments.size > 0) && message.channel.type == 'dm' && !message.author.bot) {
try {
const response = await fetch(message.attachments.first().url);
const data = await validateJSON(response);
if (data) await CreateFromFile(message, data);
} catch (e) {
console.log(e);
return message.reply(globals.Replies.find(x => x.id === 'ERROR').string);
}
} else {
if (!message.content.startsWith(cmdprefix) || message.author.bot) {
return;
}
const args = message.content.slice(cmdprefix.length).split(' ');
const commandName = args.shift().toLowerCase();
//if (!client.commands.has(commandName)) return;
try {
const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
if (!command) return;
if (command.needs_args && !args.length) {
return message.reply(
globals.Replies.find(x => x.id === 'TOO_FEW_ARGS').string +
cmdprefix + commandName + ' ' + command.usage
);
} else {
command.exec(message, args);
}
} catch (e) {
message.reply(globals.Replies.find(x => x.id === 'ERROR').string);
}
}
}
function validateJSON(body) {
try {
const data = body.json();
return data;
} catch (e) {
return null;
}
}
async function CreateFromFile(message, data) {
try {
db.find({
user: message.author.tag,
}, function (err, docs) {
if (docs.length === 0) {
db.insert({
user: message.author.tag,
character: data,
}, function (err, docs) {
message.reply(globals.Replies.find(r => r.id === 'SAVED_DATA').string);
});
}
});
} catch (e) {
throw e;
}
}
commandFiles.forEach(file => {
const command = require(`./commands/${file}`); // eslint-disable-line global-require, import/no-dynamic-require
client.commands.set(command.name, command);
});

View File

@ -1,8 +1,10 @@
module.exports = {
testEnvironment: 'node',
moduleNameMapper: {
"@dsabot/(.*)": "<rootDir>/functions/$1",
"@Commands/(.*)": "<rootDir>/commands/$1",
"@Root/(.*)": "<rootDir>/$1",
}
};
testEnvironment: 'node',
moduleNameMapper: {
'@dsabot/(.*)': '<rootDir>/functions/$1',
'@Commands/(.*)': '<rootDir>/commands/$1',
'@Root/(.*)': '<rootDir>/$1',
'@data/(.*)': '<rootDir>/data/$i',
'@Lib/(.*)': '<rootDir>/lib/$i',
},
};

View File

@ -3,11 +3,14 @@
"baseUrl": ".",
"paths": {
"@dsabot/*": ["./functions/*"],
"@globals": ["./globals"]
},
"@globals": ["./globals"],
"@data/*": ["./data/*"],
"@Commands/*": ["./commands/*"],
"@Lib/*": ["./lib/*"]
}
},
"exclude": ["node_modules"],
"typeAcquisition": {
"exclude": [ "dotenv" ]
},
}
"exclude": ["dotenv", "source-map"]
}
}

1226
lib/Chants.json Normal file

File diff suppressed because it is too large Load Diff

2529
lib/Spells.json Normal file

File diff suppressed because it is too large Load Diff

22016
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,27 +1,61 @@
{
"name": "dsabot",
"version": "1.1.0",
"description": "",
"main": "index.js",
"scripts": {
"lint": "eslint commands/",
"start": "node index.js",
"test": "jest"
},
"_moduleAliases": {
"@dsabot": "functions"
},
"author": "",
"license": "ISC",
"dependencies": {
"discord.js": "^12.5.3",
"dotenv": "^8.2.0",
"module-alias": "^2.2.2",
"nedb": "^1.8.0",
"node-fetch": "^2.6.1",
"random": "^3.0.6"
},
"devDependencies": {
"jest": "^26.6.3"
}
"name": "dsabot",
"version": "1.6.6",
"description": "",
"main": "index.js",
"scripts": {
"lint": "eslint commands/",
"preinstall": "npx npm-force-resolutions",
"start": "node index.js",
"test": "jest --collectCoverage"
},
"_moduleAliases": {
"@dsabot": "functions",
"@data": "data",
"@Commands": "commands",
"@Lib": "lib"
},
"author": "",
"license": "ISC",
"dependencies": {
"discord.js": "^12.5.3",
"dotenv": "^16.0.0",
"got": "^11.8.3",
"module-alias": "^2.2.2",
"nedb-promises": "^6.0.3"
},
"devDependencies": {
"@types/jest": "^27.4.1",
"babel-jest": "^27.5.1",
"babel-plugin-module-resolver": "^4.1.0",
"babel-plugin-rewire": "^1.2.0",
"eslint": "^8.13.0",
"eslint-config-airbnb": "^19.0.2",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^27.5.1"
},
"jest": {
"collectCoverage": true,
"collectCoverageFrom": [
"**/*.{js,jsx}",
"!**/node_modules/**",
"!**/vendor/**",
"!**/.github/**",
"!**/__tests__/**",
"!**/__mocks__/**"
],
"coveragePathIgnorePatterns": [
"/node_modules/",
"<rootDir>/__tests__/",
"<rootDir>/.github/",
"<rootDir>/coverage/",
"<rootDir>/__mocks__/"
],
"coverageDirectory": "coverage"
},
"resolutions": {
"normalize-url": ">=4.5.1",
"path-parse": ">=1.0.7"
}
}

3
renovate.json Normal file
View File

@ -0,0 +1,3 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json"
}