diff --git a/.github/workflows/rpgsaga.yml b/.github/workflows/rpgsaga.yml index a415e8886..48ead9af6 100644 --- a/.github/workflows/rpgsaga.yml +++ b/.github/workflows/rpgsaga.yml @@ -18,7 +18,7 @@ jobs: run: | cd ./rpgsaga/saga yarn install --immutable --immutable-cache --check-cache - yarn run lint + yarn run lint --fix - name: Test Saga run: | cd ./rpgsaga/saga diff --git a/rpgsaga/.vscode/launch.json b/rpgsaga/.vscode/launch.json index 9d13d41b9..b84fb7a7f 100644 --- a/rpgsaga/.vscode/launch.json +++ b/rpgsaga/.vscode/launch.json @@ -4,6 +4,7 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { "type": "node", "request": "launch", @@ -11,7 +12,7 @@ "skipFiles": [ "/**" ], - "program": "${workspaceFolder}/saga/src/index.ts", + "program": "${workspaceFolder}\\src\\index.ts", "outFiles": [ "${workspaceFolder}/**/*.js" ] @@ -20,17 +21,13 @@ "type": "node", "request": "launch", "name": "Tests debug", - "program": "${workspaceRoot}/saga/node_modules/jest/bin/jest.js", + "program": "${workspaceRoot}/node_modules/jest/bin/jest.js", "args": [ - "--config", - "${workspaceFolder}/saga/package.json", + "-i" ], "skipFiles": [ "/**/*.js", "node_modules", - "${workspaceFolder}/out/**/*.js" - ], - "console": "integratedTerminal" + ] } - ] } \ No newline at end of file diff --git a/rpgsaga/saga/.eslintrc.js b/rpgsaga/saga/.eslintrc.js new file mode 100644 index 000000000..6b2fbc16b --- /dev/null +++ b/rpgsaga/saga/.eslintrc.js @@ -0,0 +1,130 @@ +module.exports = { + env: { + browser: true, + es2021: true, + }, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:import/errors', + 'plugin:import/warnings', + 'plugin:import/typescript', + 'plugin:prettier/recommended', + ], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + ecmaVersion: 12, + sourceType: 'module', + }, + plugins: ['@typescript-eslint', 'prettier', 'import'], + ignorePatterns: ['.eslintrc.js', 'react-app-env.d.ts'], + rules: { + 'no-param-reassign': ['error'], + 'prettier/prettier': ['error', { endOfLine: 'auto' }], + 'linebreak-style': 0, + 'arrow-body-style': [ + 'error', + 'as-needed', + { + requireReturnForObjectLiteral: false, + }, + ], + curly: ['error', 'all'], + 'no-implicit-coercion': ['error'], + 'spaced-comment': ['error', 'always'], + eqeqeq: ['error', 'always'], + 'prefer-template': 'error', + 'no-useless-concat': 'error', + 'prefer-destructuring': [ + 'error', + { + VariableDeclarator: { + array: false, + object: true, + }, + AssignmentExpression: { + array: false, + object: true, + }, + }, + { + enforceForRenamedProperties: false, + }, + ], + 'import/extensions': [ + 'error', + 'ignorePackages', + { + ts: 'never', + tsx: 'never', + }, + ], + 'import/no-extraneous-dependencies': ['error', { devDependencies: true }], + 'import/order': [ + 'error', + { + 'newlines-between': 'always', + groups: ['builtin', 'external', 'parent', 'sibling', 'index'], + pathGroups: [ + { + pattern: 'src/**', + group: 'parent', + position: 'after', + }, + ], + }, + ], + 'import/newline-after-import': 'error', + '@typescript-eslint/no-explicit-any': 'error', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/ban-types': ['error'], + '@typescript-eslint/no-shadow': ['error'], + '@typescript-eslint/naming-convention': [ + 'error', + { + selector: 'default', + format: ['camelCase'], + }, + { + selector: ['enumMember', 'variable'], + format: ['camelCase', 'PascalCase', 'UPPER_CASE'], + }, + { + selector: 'parameter', + format: ['camelCase'], + leadingUnderscore: 'allow', + modifiers: ['unused'], + }, + { + selector: 'objectLiteralProperty', + filter: { + // Regular expression for BEM classnames + // Source: https://medium.com/takeaway-tech/the-search-for-a-regex-to-match-hyphenated-bem-css-class-names-5f8b66cc2bd9 + regex: '^[a-z]([a-z0-9-]+)?(__([a-z0-9]+-?)+)?(--([a-z0-9]+-?)+){0,2}$', + match: true, + }, + format: null, + }, + { + selector: 'typeLike', + format: ['PascalCase'], + }, + { + selector: 'typeProperty', + format: ['snake_case', 'camelCase'], + }, + ], + }, + settings: { + 'import/resolver': { + node: { + extensions: ['.js', '.jsx', '.ts', '.tsx'], + moduleDirectory: ['node_modules', '.'], + }, + }, + }, +}; diff --git a/rpgsaga/saga/computer/src/computer.ts b/rpgsaga/saga/computer/src/computer.ts new file mode 100644 index 000000000..f59f0aaaf --- /dev/null +++ b/rpgsaga/saga/computer/src/computer.ts @@ -0,0 +1,24 @@ +import { Gadget } from "./gadget"; + +export class Computer extends Gadget { + hard_disk_size: number; + + constructor(brand: string, model: string, hard_disk_size: number = 500) { + super(brand, model); + this.hard_disk_size = hard_disk_size; + } + + setHardDiskSize(size: number): void { + this.hard_disk_size = size; + console.log(`Hard disk size set to ${this.hard_disk_size} GB.`); + } + + getHardDiskSize(): number { + return this.hard_disk_size; + } + + getStatus(): string { + const status = this.isOn ? "ON" : "OFF"; + return `${this.brand} ${this.model} is ${status} with ${this.hard_disk_size} GB hard disk.`; + } +} \ No newline at end of file diff --git a/rpgsaga/saga/computer/src/gadget.ts b/rpgsaga/saga/computer/src/gadget.ts new file mode 100644 index 000000000..bbff1d3b7 --- /dev/null +++ b/rpgsaga/saga/computer/src/gadget.ts @@ -0,0 +1,34 @@ +export class Gadget { + brand: string; + model: string; + isOn: boolean; + + constructor(brand: string, model: string) { + this.brand = brand; + this.model = model; + this.isOn = false; + } + + turnOn(): void { + if (!this.isOn) { + this.isOn = true; + console.log(`${this.brand} ${this.model} is now ON.`); + } else { + console.log(`${this.brand} ${this.model} is already ON.`); + } + } + + turnOff(): void { + if (this.isOn) { + this.isOn = false; + console.log(`${this.brand} ${this.model} is now OFF.`); + } else { + console.log(`${this.brand} ${this.model} is already OFF.`); + } + } + + getStatus(): string { + const status = this.isOn ? "ON" : "OFF"; + return `${this.brand} ${this.model} is ${status}.`; + } +} \ No newline at end of file diff --git a/rpgsaga/saga/computer/src/phone.ts b/rpgsaga/saga/computer/src/phone.ts new file mode 100644 index 000000000..003d63451 --- /dev/null +++ b/rpgsaga/saga/computer/src/phone.ts @@ -0,0 +1,27 @@ +import { Gadget } from "./gadget"; + +export class Phone extends Gadget { + battery_level: number; + + constructor(brand: string, model: string, battery_level: number = 100) { + super(brand, model); + this.battery_level = battery_level; + } + + charge(percentage: number): void { + this.battery_level += percentage; + if (this.battery_level > 100) { + this.battery_level = 100; + } + console.log(`Battery level is now ${this.battery_level}%.`); + } + + getBatteryLevel(): number { + return this.battery_level; + } + + getStatus(): string { + const status = this.isOn ? "ON" : "OFF"; + return `${this.brand} ${this.model} is ${status} with ${this.battery_level}% battery.`; + } +} \ No newline at end of file diff --git a/rpgsaga/saga/computer/tests/computer.test.ts b/rpgsaga/saga/computer/tests/computer.test.ts new file mode 100644 index 000000000..e30f871dd --- /dev/null +++ b/rpgsaga/saga/computer/tests/computer.test.ts @@ -0,0 +1,63 @@ +import { Computer } from "../src/computer"; + +describe('Computer', () => { + let computer: Computer; + + beforeEach(() => { + computer = new Computer('Dell', 'XPS 13', 1000); + }); + + test('should initialize with correct brand and model', () => { + expect(computer.brand).toBe('Dell'); + expect(computer.model).toBe('XPS 13'); + }); + + test('should initialize with correct hard disk size', () => { + expect(computer.getHardDiskSize()).toBe(1000); + }); + + test('should turn on the computer', () => { + computer.turnOn(); + expect(computer.isOn).toBe(true); + }); + + test('should not turn on the computer if it is already on', () => { + computer.turnOn(); + const consoleSpy = jest.spyOn(console, 'log'); + computer.turnOn(); + expect(consoleSpy).toHaveBeenCalledWith('Dell XPS 13 is already ON.'); + expect(computer.isOn).toBe(true); + }); + + test('should turn off the computer', () => { + computer.turnOn(); + computer.turnOff(); + expect(computer.isOn).toBe(false); + }); + + test('should not turn off the computer if it is already off', () => { + const consoleSpy = jest.spyOn(console, 'log'); + computer.turnOff(); + expect(consoleSpy).toHaveBeenCalledWith('Dell XPS 13 is already OFF.'); + expect(computer.isOn).toBe(false); + }); + + test('should set hard disk size', () => { + computer.setHardDiskSize(2000); + expect(computer.getHardDiskSize()).toBe(2000); + }); + + test('should get correct status when computer is on', () => { + computer.turnOn(); + expect(computer.getStatus()).toBe('Dell XPS 13 is ON with 1000 GB hard disk.'); + }); + + test('should get correct status when computer is off', () => { + expect(computer.getStatus()).toBe('Dell XPS 13 is OFF with 1000 GB hard disk.'); + }); + + test('should initialize with default hard disk size if not provided', () => { + const defaultComputer = new Computer('Apple', 'MacBook Pro'); + expect(defaultComputer.getHardDiskSize()).toBe(500); + }); +}); \ No newline at end of file diff --git a/rpgsaga/saga/computer/tests/phone.test.ts b/rpgsaga/saga/computer/tests/phone.test.ts new file mode 100644 index 000000000..cee66b15f --- /dev/null +++ b/rpgsaga/saga/computer/tests/phone.test.ts @@ -0,0 +1,69 @@ +// src/Phone.test.ts +import { Phone } from "../src/phone"; + +describe('Phone', () => { + let phone: Phone; + + beforeEach(() => { + phone = new Phone('Apple', 'iPhone 13', 50); + }); + + test('should initialize with correct brand and model', () => { + expect(phone.brand).toBe('Apple'); + expect(phone.model).toBe('iPhone 13'); + }); + + test('should initialize with correct battery level', () => { + expect(phone.getBatteryLevel()).toBe(50); + }); + + test('should turn on the phone', () => { + phone.turnOn(); + expect(phone.isOn).toBe(true); + }); + + test('should not turn on the phone if it is already on', () => { + phone.turnOn(); + const consoleSpy = jest.spyOn(console, 'log'); + phone.turnOn(); + expect(consoleSpy).toHaveBeenCalledWith('Apple iPhone 13 is already ON.'); + expect(phone.isOn).toBe(true); + }); + + test('should turn off the phone', () => { + phone.turnOn(); + phone.turnOff(); + expect(phone.isOn).toBe(false); + }); + + test('should not turn off the phone if it is already off', () => { + const consoleSpy = jest.spyOn(console, 'log'); + phone.turnOff(); + expect(consoleSpy).toHaveBeenCalledWith('Apple iPhone 13 is already OFF.'); + expect(phone.isOn).toBe(false); + }); + + test('should charge the phone', () => { + phone.charge(30); + expect(phone.getBatteryLevel()).toBe(80); + }); + + test('should not charge the phone above 100%', () => { + phone.charge(60); + expect(phone.getBatteryLevel()).toBe(100); + }); + + test('should get correct status when phone is on', () => { + phone.turnOn(); + expect(phone.getStatus()).toBe('Apple iPhone 13 is ON with 50% battery.'); + }); + + test('should get correct status when phone is off', () => { + expect(phone.getStatus()).toBe('Apple iPhone 13 is OFF with 50% battery.'); + }); + + test('should initialize with default battery level if not provided', () => { + const defaultPhone = new Phone('Samsung', 'Galaxy S21'); + expect(defaultPhone.getBatteryLevel()).toBe(100); + }); +}); \ No newline at end of file diff --git a/rpgsaga/saga/mathexpression/src/index.ts b/rpgsaga/saga/mathexpression/src/index.ts new file mode 100644 index 000000000..2276e7c9b --- /dev/null +++ b/rpgsaga/saga/mathexpression/src/index.ts @@ -0,0 +1,7 @@ +import { taskA, taskB } from "./mathFunction"; + +const x: number[][] = taskA(1, 2, 3, 4, 0.5); +const y: number[] = taskB([1, 2, 3], 2, 3); + +console.log(x); +console.log(y); \ No newline at end of file diff --git a/rpgsaga/saga/mathexpression/src/mathFunction.ts b/rpgsaga/saga/mathexpression/src/mathFunction.ts new file mode 100644 index 000000000..e4d1e1498 --- /dev/null +++ b/rpgsaga/saga/mathexpression/src/mathFunction.ts @@ -0,0 +1,31 @@ +export function toRadians(deg: number): number { + return deg * (Math.PI / 180.0); +} + +export function calculate(a: number, b: number, x: number): number { + let exp: number; + if (x < 5) { + exp = Math.pow(Math.log10(Math.pow(a, 2) + x), 2) / Math.pow(a + x, 2); + } else { + exp = Math.pow(a + b * x, 2.5) / (1.8 + Math.pow(Math.cos(toRadians(a * x)), 3)); + } + return exp; +} + +export function taskA(a: number, b: number, begX: number, endX: number, detX: number): [number[], number[]] { + const ylist: number[] = []; + const xlist: number[] = []; + for (let x = begX; x <= endX; x += detX) { + ylist.push(calculate(a, b, x)); + xlist.push(x); + } + return [ylist, xlist]; +} + +export function taskB(xlist: number[], a: number, b: number): number[] { + const ylist: number[] = []; + for (const v of xlist) { + ylist.push(calculate(a, b, v)); + } + return ylist; +} \ No newline at end of file diff --git a/rpgsaga/saga/mathexpression/tests/mathFunction.test.ts b/rpgsaga/saga/mathexpression/tests/mathFunction.test.ts new file mode 100644 index 000000000..67ee72d7f --- /dev/null +++ b/rpgsaga/saga/mathexpression/tests/mathFunction.test.ts @@ -0,0 +1,53 @@ +import { calculate, toRadians } from '../src/mathFunction'; + +describe('calculate', () => { + it('должна правильно вычислять для x < 5', () => { + const a = 2; + const b = 3; + const x = 4; + const expected = Math.pow(Math.log10(Math.pow(a, 2) + x), 2) / Math.pow(a + x, 2); + expect(calculate(a, b, x)).toBeCloseTo(expected, 4); + }); + + it('должна правильно вычислять для x >= 5', () => { + const a = 2; + const b = 3; + const x = 5; + const numerator = Math.pow(a + b * x, 2.5); + const denominator = 1.8 + Math.pow(Math.cos(toRadians(a * x)), 3); + const expected = numerator / denominator; + expect(calculate(a, b, x)).toBeCloseTo(expected, 4); + }); + + it('должна обрабатывать случай x = 5', () => { + const a = 1; + const b = 1; + const x = 5; + const result = calculate(a, b, x); + expect(result).not.toBeNaN(); + }); + + it('должна обрабатывать случай x = 0', () => { + const a = 1; + const b = 1; + const x = 0; + const result = calculate(a, b, x); + expect(result).not.toBeNaN(); + }); + + it('должна обрабатывать случай x = -1', () => { + const a = 1; + const b = 1; + const x = -1; + const result = calculate(a, b, x); + expect(result).not.toBeNaN(); + }); + + it('должна обрабатывать случай x = 10', () => { + const a = 1; + const b = 1; + const x = 10; + const result = calculate(a, b, x); + expect(result).not.toBeNaN(); + }); +}); \ No newline at end of file diff --git a/rpgsaga/saga/package.json b/rpgsaga/saga/package.json index 48455ab0e..1bb32af56 100644 --- a/rpgsaga/saga/package.json +++ b/rpgsaga/saga/package.json @@ -6,27 +6,26 @@ "scripts": { "dev": "ts-node --script-mode src/index.ts", "test": "jest", - "lint": "eslint \"{src,apps,libs,test}/**/*.ts\"", - "lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix" + "lint": "eslint src --ext .js --ext .jsx --ext .ts --ext .tsx", + "lint:fix": "npm run lint -- --fix" }, "author": "", "license": "ISC", "dependencies": {}, "devDependencies": { - "@eslint/compat": "^1.2.0", - "@types/jest": "^29.5.13", - "@types/node": "^22.7.4", - "@typescript-eslint/eslint-plugin": "^8.8.0", - "@typescript-eslint/parser": "^8.8.0", - "eslint": "^9.12.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-prettier": "^5.2.1", - "jest": "^29.7.0", - "prettier": "^3.3.3", - "ts-jest": "^29.2.5", - "ts-node": "^10.9.2", - "typescript": "^5.6.2" + "@types/jest": "^27.0.3", + "@types/node": "^16.11.0", + "@typescript-eslint/eslint-plugin": "^5.0.0", + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^7.28.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-import": "^2.23.4", + "eslint-plugin-prettier": "^3.4.0", + "jest": "^27.2.5", + "prettier": "^2.4.1", + "ts-node": "^10.3.0", + "typescript": "^4.4.4", + "ts-jest": "^27.1.2" }, "jest": { "preset": "ts-jest" diff --git a/rpgsaga/saga/src.ts b/rpgsaga/saga/src.ts new file mode 100644 index 000000000..e69de29bb diff --git a/rpgsaga/saga/src/abilities/abilities.ts b/rpgsaga/saga/src/abilities/abilities.ts new file mode 100644 index 000000000..8ffa9a0d8 --- /dev/null +++ b/rpgsaga/saga/src/abilities/abilities.ts @@ -0,0 +1,9 @@ +import { Hero } from '../heroes/hero'; +import { Effect } from '../effects/effects'; + +export abstract class Ability { + damage: number; + effect: Effect; + + abstract use(target: Hero): void; +} \ No newline at end of file diff --git a/rpgsaga/saga/src/abilities/backfire.ts b/rpgsaga/saga/src/abilities/backfire.ts new file mode 100644 index 000000000..363f83ebb --- /dev/null +++ b/rpgsaga/saga/src/abilities/backfire.ts @@ -0,0 +1,13 @@ +import { Ability } from './abilities'; +import { Hero } from '../heroes/hero'; +import { BackfireEffect } from '../effects/backfireEffect'; + +export class Backfire extends Ability { + damage = 0; + effect = new BackfireEffect; + + use(target: Hero) { + console.log(`${target.constructor.name} подвергается Ворожению!`); + this.effect.apply(target); + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/abilities/fireArrow.ts b/rpgsaga/saga/src/abilities/fireArrow.ts new file mode 100644 index 000000000..f0936d7b4 --- /dev/null +++ b/rpgsaga/saga/src/abilities/fireArrow.ts @@ -0,0 +1,14 @@ +import { Ability } from './abilities'; +import { Hero } from '../heroes/hero'; +import { BurnEffect } from '../effects/burnEffect'; + +export class FireArrows extends Ability { + damage = 5; + effect = new BurnEffect; + + use(target: Hero) { + console.log(`${target.constructor.name} поражен Огненной Стрелой!`); + target.takeDamage(this.damage); + this.effect.apply(target); + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/abilities/retributionStrike.ts b/rpgsaga/saga/src/abilities/retributionStrike.ts new file mode 100644 index 000000000..bee4c984f --- /dev/null +++ b/rpgsaga/saga/src/abilities/retributionStrike.ts @@ -0,0 +1,13 @@ +import { Ability } from './abilities'; +import { Hero } from '../heroes/hero'; +import { ExecutionEffect } from '../effects/executionEffect'; + +export class RetributionStrike extends Ability { + damage = 0; + effect = new ExecutionEffect; + + use(target: Hero) { + console.log(`${target.constructor.name} подвергается Удару Возмездия!`); + this.effect.apply(target); + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/effects/backfireEffect.ts b/rpgsaga/saga/src/effects/backfireEffect.ts new file mode 100644 index 000000000..28394c359 --- /dev/null +++ b/rpgsaga/saga/src/effects/backfireEffect.ts @@ -0,0 +1,9 @@ +import { Effect } from "./effects"; +import { Hero } from "../heroes/hero"; + +export class BackfireEffect extends Effect { + apply(target: Hero) { + console.log(`${target.constructor.name} будет использовать следующую способность на самом себе!`); + target.nextAbilitySelf = true; + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/effects/burnEffect.ts b/rpgsaga/saga/src/effects/burnEffect.ts new file mode 100644 index 000000000..ce6e1f01a --- /dev/null +++ b/rpgsaga/saga/src/effects/burnEffect.ts @@ -0,0 +1,9 @@ +import { Effect } from "./effects"; +import { Hero } from "../heroes/hero"; + +export class BurnEffect extends Effect { + apply(target: Hero) { + console.log(`${target.constructor.name} поджигается!`); + target.takeDamage(5); + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/effects/effects.ts b/rpgsaga/saga/src/effects/effects.ts new file mode 100644 index 000000000..4bc7daa80 --- /dev/null +++ b/rpgsaga/saga/src/effects/effects.ts @@ -0,0 +1,5 @@ +import { Hero } from "../heroes/hero"; + +export abstract class Effect { + abstract apply(target: Hero): void; +} \ No newline at end of file diff --git a/rpgsaga/saga/src/effects/executionEffect.ts b/rpgsaga/saga/src/effects/executionEffect.ts new file mode 100644 index 000000000..3e6aca9ee --- /dev/null +++ b/rpgsaga/saga/src/effects/executionEffect.ts @@ -0,0 +1,13 @@ +import { Effect } from "./effects"; +import { Hero } from "../heroes/hero"; + +export class ExecutionEffect extends Effect { + apply(target: Hero) { + if (target.health <= target.health * 0.25) { + console.log(`${target.constructor.name} казнен!`); + target.health = 0; + } else { + console.log(`${target.constructor.name} не подлежит казни.`); + } + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/game.ts b/rpgsaga/saga/src/game.ts new file mode 100644 index 000000000..75f3c65bd --- /dev/null +++ b/rpgsaga/saga/src/game.ts @@ -0,0 +1,34 @@ +import { Hero } from "./heroes/hero"; + +export class Game { + player1: Hero; + player2: Hero; + + constructor(player1: Hero, player2: Hero) { + this.player1 = player1; + this.player2 = player2; + } + + start() { + console.log('Игра началась!'); + let currentPlayer = this.player1; + let opponent = this.player2; + + while (this.player1.health > 0 && this.player2.health > 0) { + console.log(`\nХод игрока: ${currentPlayer.constructor.name}`); + this.makeMove(currentPlayer, opponent); + + [currentPlayer, opponent] = [opponent, currentPlayer]; + } + + console.log(`\nИгра окончена! Победитель: ${this.player1.health > 0 ? this.player1.constructor.name : this.player2.constructor.name}`); + } + + makeMove(currentPlayer: Hero, opponent: Hero) { + if (Math.random() < 0.5) { + currentPlayer.attack(opponent); + } else { + currentPlayer.useAbility(opponent); + } + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/heroes/archer.ts b/rpgsaga/saga/src/heroes/archer.ts new file mode 100644 index 000000000..612733cfd --- /dev/null +++ b/rpgsaga/saga/src/heroes/archer.ts @@ -0,0 +1,8 @@ +import { FireArrows } from "../abilities/fireArrow"; +import { Hero } from "./hero"; + +export class Archer extends Hero { + health = 30; + attackPower = 15; + ability = new FireArrows(); +} \ No newline at end of file diff --git a/rpgsaga/saga/src/heroes/hero.ts b/rpgsaga/saga/src/heroes/hero.ts new file mode 100644 index 000000000..1cfd8967a --- /dev/null +++ b/rpgsaga/saga/src/heroes/hero.ts @@ -0,0 +1,28 @@ +import { Ability } from "../abilities/abilities"; + +export abstract class Hero { + health: number; + attackPower: number; + ability: Ability; + nextAbilitySelf: boolean; + + attack(target: Hero) { + console.log(`${this.constructor.name} атакует ${target.constructor.name}!`); + target.takeDamage(this.attackPower); + } + + takeDamage(damage: number) { + this.health -= damage; + console.log(`${this.constructor.name} получает ${damage} урона. Здоровье: ${this.health}`); + } + + useAbility(target: Hero) { + if (this.nextAbilitySelf) { + console.log(`${this.constructor.name} использует способность на самом себе!`); + this.ability.use(this); + this.nextAbilitySelf = false; + } else { + this.ability.use(target); + } + } +} \ No newline at end of file diff --git a/rpgsaga/saga/src/heroes/knight.ts b/rpgsaga/saga/src/heroes/knight.ts new file mode 100644 index 000000000..6ecd8cd77 --- /dev/null +++ b/rpgsaga/saga/src/heroes/knight.ts @@ -0,0 +1,8 @@ +import { Hero } from './hero'; +import { RetributionStrike } from '../abilities/retributionStrike'; + +export class Knight extends Hero { + health = 70; + attackPower = 5; + ability = new RetributionStrike(); +} \ No newline at end of file diff --git a/rpgsaga/saga/src/heroes/mage.ts b/rpgsaga/saga/src/heroes/mage.ts new file mode 100644 index 000000000..8e2f00ed8 --- /dev/null +++ b/rpgsaga/saga/src/heroes/mage.ts @@ -0,0 +1,8 @@ +import { Hero } from "./hero"; +import { Backfire } from "../abilities/backfire"; + +export class Mage extends Hero { + health = 70; + attackPower = 5; + ability = new Backfire(); +} \ No newline at end of file diff --git a/rpgsaga/saga/src/index.ts b/rpgsaga/saga/src/index.ts deleted file mode 100644 index 7bc4a71de..000000000 --- a/rpgsaga/saga/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -console.log('Hello world'); diff --git a/rpgsaga/saga/tests/example.spec.ts b/rpgsaga/saga/tests/example.spec.ts deleted file mode 100644 index a86cfde79..000000000 --- a/rpgsaga/saga/tests/example.spec.ts +++ /dev/null @@ -1,7 +0,0 @@ -describe('Example', () => { - it('should return 5 as result of 2 and 3 sum', () => { - const a = 3; - const b = 2; - expect(a + b).toEqual(5); - }); -});