initial import
This commit is contained in:
commit
22c16c8146
0
.agents/skills/.gitkeep
Normal file
0
.agents/skills/.gitkeep
Normal file
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
coverage/
|
||||||
|
*.log
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
**/*.iml
|
||||||
|
**/.idea
|
||||||
|
**/*.received.*
|
||||||
|
**/DS_Store/*
|
||||||
|
**/.DS_Store
|
||||||
4
.prettierignore
Normal file
4
.prettierignore
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
coverage/
|
||||||
|
package-lock.json
|
||||||
7
.prettierrc.json
Normal file
7
.prettierrc.json
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": true,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"printWidth": 100,
|
||||||
|
"tabWidth": 2
|
||||||
|
}
|
||||||
13
AGENTS.md
Normal file
13
AGENTS.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
**ALWAYS** start replies with ⚔️.
|
||||||
|
|
||||||
|
## What this project is
|
||||||
|
|
||||||
|
An implementation of the RPG Combat rules engine. There are six user stories described in [user-stories.md](user-stories.md)
|
||||||
|
|
||||||
|
## Build and Test Scripts
|
||||||
|
|
||||||
|
- `npm test`: runs unit tests using vitest
|
||||||
|
- `npm run lint:fix`: runs eslint with autofix
|
||||||
|
- `npm run format:fix`: runs prettier with autofix
|
||||||
|
- `npm run typecheck`: runs tsc without emit
|
||||||
|
- `npm run checks`: runs the pre-commit gate (format:fix, lint:fix, typecheck, test)
|
||||||
8
README.md
Normal file
8
README.md
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# RPG Combat
|
||||||
|
|
||||||
|
Use this starting template for your implementation of the game rules. Requires Node.js and npm. Install dependencies, then run the tests:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm test
|
||||||
|
```
|
||||||
78
eslint.config.js
Normal file
78
eslint.config.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import js from '@eslint/js';
|
||||||
|
import tseslint from 'typescript-eslint';
|
||||||
|
import prettier from 'eslint-config-prettier';
|
||||||
|
|
||||||
|
export default tseslint.config(
|
||||||
|
{ ignores: ['dist', 'node_modules', 'coverage'] },
|
||||||
|
|
||||||
|
js.configs.recommended,
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
|
||||||
|
{
|
||||||
|
files: ['src/**/*.ts'],
|
||||||
|
extends: [...tseslint.configs.recommendedTypeChecked],
|
||||||
|
languageOptions: {
|
||||||
|
parserOptions: {
|
||||||
|
projectService: true,
|
||||||
|
tsconfigRootDir: import.meta.dirname,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/switch-exhaustiveness-check': 'warn',
|
||||||
|
'@typescript-eslint/no-unnecessary-condition': 'warn',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
rules: {
|
||||||
|
complexity: ['warn', 12],
|
||||||
|
'max-depth': ['warn', 4],
|
||||||
|
'max-params': ['warn', 4],
|
||||||
|
'max-lines-per-function': [
|
||||||
|
'warn',
|
||||||
|
{ max: 60, skipBlankLines: true, skipComments: true, IIFEs: true },
|
||||||
|
],
|
||||||
|
|
||||||
|
'no-else-return': ['warn', { allowElseIf: false }],
|
||||||
|
'no-lonely-if': 'warn',
|
||||||
|
'no-param-reassign': ['warn', { props: false }],
|
||||||
|
eqeqeq: ['warn', 'always', { null: 'ignore' }],
|
||||||
|
|
||||||
|
'prefer-const': 'warn',
|
||||||
|
'prefer-template': 'warn',
|
||||||
|
'object-shorthand': 'warn',
|
||||||
|
'no-console': 'warn',
|
||||||
|
|
||||||
|
'@typescript-eslint/explicit-function-return-type': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
allowExpressions: true,
|
||||||
|
allowTypedFunctionExpressions: true,
|
||||||
|
allowHigherOrderFunctions: true,
|
||||||
|
allowDirectConstAssertionInArrowFunctions: true,
|
||||||
|
allowIIFEs: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
'@typescript-eslint/consistent-type-imports': 'warn',
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'warn',
|
||||||
|
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' },
|
||||||
|
],
|
||||||
|
'@typescript-eslint/no-explicit-any': 'warn',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'warn',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
files: ['**/*.test.ts', '**/*.spec.ts'],
|
||||||
|
rules: {
|
||||||
|
'max-lines-per-function': 'off',
|
||||||
|
'max-params': 'off',
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-non-null-assertion': 'off',
|
||||||
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
prettier,
|
||||||
|
);
|
||||||
21
license.txt
Normal file
21
license.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2026 Samman Technical Coaching Society
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
2489
package-lock.json
generated
Normal file
2489
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
package.json
Normal file
31
package.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"name": "rpg-combat",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"typecheck": "tsc --noEmit",
|
||||||
|
"test": "vitest run",
|
||||||
|
"lint": "eslint .",
|
||||||
|
"lint:fix": "eslint . --fix",
|
||||||
|
"format": "prettier --check .",
|
||||||
|
"format:fix": "prettier --write .",
|
||||||
|
"checks": "npm run format:fix && npm run lint:fix && npm run typecheck && npm test"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"kata"
|
||||||
|
],
|
||||||
|
"author": "<put your name here>",
|
||||||
|
"license": "MIT",
|
||||||
|
"description": "A TypeScript implementation of RPG Combat",
|
||||||
|
"devDependencies": {
|
||||||
|
"@eslint/js": "^10.0.1",
|
||||||
|
"@types/node": "^25.9.1",
|
||||||
|
"eslint": "^10.4.1",
|
||||||
|
"eslint-config-prettier": "^10.1.8",
|
||||||
|
"prettier": "^3.8.3",
|
||||||
|
"typescript": "^6.0.3",
|
||||||
|
"typescript-eslint": "^8.60.0",
|
||||||
|
"vitest": "^4.1.7"
|
||||||
|
}
|
||||||
|
}
|
||||||
22
tsconfig.json
Normal file
22
tsconfig.json
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"target": "es2022",
|
||||||
|
"types": [],
|
||||||
|
"strict": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noUncheckedSideEffectImports": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"allowImportingTsExtensions": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*"]
|
||||||
|
}
|
||||||
70
user-stories.md
Normal file
70
user-stories.md
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
# RPG Combat
|
||||||
|
|
||||||
|
This is a description of the business rules we should support in the game engine.
|
||||||
|
|
||||||
|
|
||||||
|
## Damage and Health
|
||||||
|
|
||||||
|
1. All Characters, when created, have:
|
||||||
|
- Health, starting at 1000
|
||||||
|
- May be Alive or Dead, starting Alive
|
||||||
|
|
||||||
|
2. Characters can Deal Damage to Characters.
|
||||||
|
- Damage is subtracted from Health
|
||||||
|
- When damage received exceeds current Health, Health becomes 0 and the character dies
|
||||||
|
- A Character cannot Deal Damage to itself
|
||||||
|
|
||||||
|
3. A Character can Heal themselves.
|
||||||
|
- Dead characters cannot heal
|
||||||
|
|
||||||
|
## Levels
|
||||||
|
|
||||||
|
1. All characters have a Level, starting at 1
|
||||||
|
- A Character cannot have a health above 1000 until they reach level 6, when the maximum increases to 1500
|
||||||
|
|
||||||
|
2. When dealing damage:
|
||||||
|
- If the target is 5 or more Levels above the attacker, Damage is reduced by 50%
|
||||||
|
- If the target is 5 or more Levels below the attacker, Damage is increased by 50%
|
||||||
|
|
||||||
|
## Factions
|
||||||
|
|
||||||
|
1. Characters may belong to one or more Factions.
|
||||||
|
- Newly created Characters belong to no Faction.
|
||||||
|
|
||||||
|
2. A Character may Join or Leave one or more Factions.
|
||||||
|
|
||||||
|
3. Players belonging to the same Faction are considered Allies.
|
||||||
|
- Allies cannot Deal Damage to one another.
|
||||||
|
- Allies can Heal one another and non-allies cannot.
|
||||||
|
|
||||||
|
## Magical objects
|
||||||
|
|
||||||
|
1. As well as Characters there are also Magical Objects
|
||||||
|
- Magical Objects have Health
|
||||||
|
- The maximum amount of Health is fixed at the time the object is created
|
||||||
|
- When reduced to 0 Health, Magical Objects are *Destroyed*
|
||||||
|
- Magical Objects cannot be Healed by Characters
|
||||||
|
- Magical Objects do not belong to Factions; they are neutral
|
||||||
|
|
||||||
|
2. Characters can gain health from a Healing Magical Object.
|
||||||
|
- Characters can gain any amount of health from the Object, up to its maximum and theirs
|
||||||
|
- Healing Magical Objects cannot deal Damage
|
||||||
|
|
||||||
|
3. Characters can deal Damage by using a Magical Weapon.
|
||||||
|
- These Magical Objects deal a fixed amount of damage when they are used
|
||||||
|
- The amount of damage is fixed at the time the weapon is created
|
||||||
|
- Every time the weapon is used, the Health is reduced by 1
|
||||||
|
- Magical Weapons cannot give Health to a Character
|
||||||
|
|
||||||
|
## Changing level
|
||||||
|
|
||||||
|
1. Level 1 Characters that survive 1000 damage points gain a level, (this may be counted over several battles)
|
||||||
|
- a character cannot gain a level while receiving damage, it happens directly afterwards (if the player is still alive)
|
||||||
|
- Level 2 Characters need to survive an additional 2000 damage points to gain a level, Level 3 Characters need to survive an additional 3000, and so on.
|
||||||
|
|
||||||
|
2. Level 1 Characters that have ever been part of 3 distinct factions gain a level
|
||||||
|
- Level 2 Characters need to join an additional 3 distinct factions to gain a level, Level 3 Characters need to join an additional 3, and so on.
|
||||||
|
|
||||||
|
3. The maximum Level for Characters is 10
|
||||||
|
- Characters cannot lose a level they have gained
|
||||||
|
|
||||||
7
vitest.config.ts
Normal file
7
vitest.config.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { defineConfig } from 'vitest/config';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
test: {
|
||||||
|
include: ['src/**/*.{test,spec}.ts'],
|
||||||
|
},
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user