mirror of
https://github.com/morbalint/kemkas.git
synced 2026-07-18 03:13:46 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c1399eea56 | |||
| 39df5bd53d | |||
| 87e267d790 | |||
| 8ebd5170fd | |||
| 3709a29a57 | |||
| e8ab39c23e | |||
| 426ce608e6 | |||
| 8815e6d1b1 | |||
| 5fce1d591f |
+16
-18
@@ -15,7 +15,7 @@ jobs:
|
||||
unit-test-and-lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: actions/checkout@v4
|
||||
- name: Setup Node.js 24.x
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
@@ -52,10 +52,10 @@ jobs:
|
||||
outputs:
|
||||
image_sha_tag: ${{ steps.image-tag.outputs.image_sha_tag }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
- uses: actions/checkout@v4
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -78,7 +78,7 @@ jobs:
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
- name: Build and push frontend image
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ./frontend/
|
||||
file: ./frontend/Dockerfile
|
||||
@@ -98,10 +98,10 @@ jobs:
|
||||
outputs:
|
||||
image_sha_tag: ${{ steps.image-tag.outputs.image_sha_tag }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
- uses: actions/checkout@v4
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -124,7 +124,7 @@ jobs:
|
||||
echo "EOF"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
- name: Build and push e2e image
|
||||
uses: docker/build-push-action@v7
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ./e2e/
|
||||
file: ./e2e/Dockerfile
|
||||
@@ -147,33 +147,31 @@ jobs:
|
||||
FRONTEND_IMAGE: ${{ needs.build-fe.outputs.image_sha_tag }}
|
||||
E2E_IMAGE: ${{ needs.build-e2e.outputs.image_sha_tag }}
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
- name: Setup docker compose
|
||||
uses: docker/setup-compose-action@v2
|
||||
- uses: actions/checkout@v4
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@v4
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Pull images for test run
|
||||
run: docker compose -f e2e.docker-compose.yaml pull
|
||||
run: docker compose -f docker-compose.e2e.yaml pull
|
||||
- name: Run Docker Compose E2E tests
|
||||
run: docker compose -f e2e.docker-compose.yaml up --no-build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
run: docker compose -f docker-compose.e2e.yaml up --no-build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
- name: Upload Playwright HTML report
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-report
|
||||
path: e2e/playwright-report
|
||||
if-no-files-found: ignore
|
||||
- name: Upload Playwright test results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-test-results
|
||||
path: e2e/test-results
|
||||
if-no-files-found: ignore
|
||||
- name: Tear down Docker Compose stack
|
||||
if: always()
|
||||
run: docker compose -f e2e.docker-compose.yaml down -v --remove-orphans
|
||||
run: docker compose -f docker-compose.e2e.yaml down -v --remove-orphans
|
||||
|
||||
@@ -31,7 +31,7 @@ Later start the docker compose first and the project launch settings after the D
|
||||
For a fully containerized end-to-end run (tagged backend image + freshly built frontend/e2e images):
|
||||
|
||||
```shell
|
||||
docker compose -f e2e.docker-compose.yaml up --build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
docker compose -f docker-compose.e2e.yaml up --build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
```
|
||||
|
||||
Use `BACKEND_IMAGE` to select a specific backend tag, and note this compose stack auto-generates TLS certificates for the nginx proxy.
|
||||
|
||||
@@ -41,7 +41,7 @@ services:
|
||||
ports:
|
||||
- "8000:8000"
|
||||
volumes:
|
||||
- ./e2e.nginx.conf:/etc/nginx/nginx.conf:ro
|
||||
- ./nginx.e2e.conf:/etc/nginx/nginx.conf:ro
|
||||
- tls-certs:/etc/nginx/certs:ro
|
||||
depends_on:
|
||||
certs:
|
||||
+2
-2
@@ -43,14 +43,14 @@ Prerequisites:
|
||||
Run:
|
||||
|
||||
```shell
|
||||
docker compose -f e2e.docker-compose.yaml up --build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
docker compose -f docker-compose.e2e.yaml up --build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
```
|
||||
|
||||
Run with a different backend tag:
|
||||
|
||||
```shell
|
||||
BACKEND_IMAGE=ghcr.io/morbalint/kemkas-backend:<tag> \
|
||||
docker compose -f e2e.docker-compose.yaml up --build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
docker compose -f docker-compose.e2e.yaml up --build --abort-on-container-exit --exit-code-from e2e e2e
|
||||
```
|
||||
|
||||
The `certs` service generates a local CA and nginx server certificate in a shared volume.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"node": ">=24"
|
||||
},
|
||||
"dependencies": {
|
||||
"@grafana/faro-web-sdk": "^2.3.1",
|
||||
"@grafana/faro-web-sdk": "^1.4.2",
|
||||
"@pdf-lib/fontkit": "^1.1.1",
|
||||
"@reduxjs/toolkit": "^2.2.2",
|
||||
"@testing-library/jest-dom": "^6.4.2",
|
||||
|
||||
@@ -8,23 +8,21 @@ import {AppDispatch, RootState} from "../../store";
|
||||
import {characterSelector, setHarcosSpecialization} from "../domain-models/characterSlice";
|
||||
|
||||
function HarcosFegyverSpecializacio(props: {
|
||||
harcosSzint: number,
|
||||
karakterSzint: number,
|
||||
szint: number
|
||||
}) {
|
||||
const {
|
||||
harcosSzint,
|
||||
karakterSzint,
|
||||
szint
|
||||
} = props
|
||||
|
||||
const dispatch = useDispatch.withTypes<AppDispatch>()()
|
||||
const character = useSelector.withTypes<RootState>()(characterSelector)
|
||||
const specialization = character.szintlepesek[karakterSzint-1]?.harcosFegyver || 'kard_hosszu'
|
||||
const specialization = character.szintlepesek[szint-1].harcosFegyver || 'kard_hosszu'
|
||||
const existingSpecializations = character.szintlepesek.filter(x => x.harcosFegyver != null).map(x => x.harcosFegyver! as string)
|
||||
const changeSpecialization = (specialization: string) => dispatch(setHarcosSpecialization({szint: karakterSzint, fegyver: specialization}))
|
||||
const changeSpecialization = (specialization: string) => dispatch(setHarcosSpecialization({szint, fegyver: specialization}))
|
||||
|
||||
const fegyver = GetFegyver(specialization)
|
||||
const availableFegyverek = AllowedFegyver(Osztaly2E.Harcos)
|
||||
const pickableFegyverek = availableFegyverek.filter(f => f.Id === specialization || existingSpecializations.filter(x => x === f.Id).length < (harcosSzint < 9 ? 1 : 2))
|
||||
const pickableFegyverek = availableFegyverek.filter(f => f.Id === specialization || existingSpecializations.filter(x => x === f.Id).length < (szint < 9 ? 1 : 2))
|
||||
|
||||
|
||||
return <>
|
||||
@@ -34,7 +32,7 @@ function HarcosFegyverSpecializacio(props: {
|
||||
fegyverek={pickableFegyverek}
|
||||
selectedId={specialization}
|
||||
onChange={changeSpecialization}
|
||||
dataTestId={"harcos-specialization-" + karakterSzint}
|
||||
dataTestId={"harcos-specialization-" + szint}
|
||||
/>
|
||||
{fegyver == null && <span className='form-field-error'>Ismeretlen fegyver: {specialization}</span>}
|
||||
</div>
|
||||
|
||||
@@ -1,126 +0,0 @@
|
||||
import React from "react";
|
||||
import {render} from "@testing-library/react";
|
||||
import {configureStore} from "@reduxjs/toolkit";
|
||||
import {Provider} from "react-redux";
|
||||
import KarakterKepzettsegek from "./Kepzettsegek2E";
|
||||
import userReducer from "../../shared/domain-models/userSlice";
|
||||
import characterReducer, {setCharacter} from "../domain-models/characterSlice";
|
||||
import {DefaultKarakter, Karakter2E} from "../domain-models/karakter2E";
|
||||
import {Osztaly2E} from "../domain-models/osztaly2E";
|
||||
import {Tulajdonsag2E} from "../domain-models/tulajdonsag2E";
|
||||
|
||||
function createStore() {
|
||||
return configureStore({
|
||||
reducer: {
|
||||
user: userReducer,
|
||||
character2E: characterReducer,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
describe("KarakterKepzettsegek", () => {
|
||||
it("shows one more kepzettseg selector when INT modifier increases from level-up", () => {
|
||||
const karakter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 4,
|
||||
tulajdonsagok: {
|
||||
...DefaultKarakter.tulajdonsagok,
|
||||
t_int: 17,
|
||||
},
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 10 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 7 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 8, tulajdonsagNoveles: Tulajdonsag2E.Intelligencia },
|
||||
],
|
||||
tolvajKepzettsegek: [],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const store = createStore();
|
||||
store.dispatch(setCharacter(karakter));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<KarakterKepzettsegek />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const selectors = sut.container.querySelectorAll('[data-testid^="kepzettseg-"]');
|
||||
expect(selectors).toHaveLength(7);
|
||||
});
|
||||
|
||||
it("shows one more kepzettseg selector when INT modifier increases at level 8", () => {
|
||||
const karakter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 8,
|
||||
tulajdonsagok: {
|
||||
...DefaultKarakter.tulajdonsagok,
|
||||
t_int: 14,
|
||||
},
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 10 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 7 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 8, tulajdonsagNoveles: Tulajdonsag2E.Ero },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 9 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 6, tulajdonsagNoveles: Tulajdonsag2E.Intelligencia },
|
||||
],
|
||||
tolvajKepzettsegek: [],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const store = createStore();
|
||||
store.dispatch(setCharacter(karakter));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<KarakterKepzettsegek />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const selectors = sut.container.querySelectorAll('[data-testid^="kepzettseg-"]');
|
||||
expect(selectors).toHaveLength(6);
|
||||
});
|
||||
|
||||
it("shows one more kepzettseg selector when INT modifier increases at level 12", () => {
|
||||
const karakter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 12,
|
||||
tulajdonsagok: {
|
||||
...DefaultKarakter.tulajdonsagok,
|
||||
t_int: 17,
|
||||
},
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 10 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 7 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 8, tulajdonsagNoveles: Tulajdonsag2E.Ero },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 9 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 6, tulajdonsagNoveles: Tulajdonsag2E.Egeszseg },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 3 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 7 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 4, tulajdonsagNoveles: Tulajdonsag2E.Intelligencia },
|
||||
],
|
||||
tolvajKepzettsegek: [],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const store = createStore();
|
||||
store.dispatch(setCharacter(karakter));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<KarakterKepzettsegek />
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const selectors = sut.container.querySelectorAll('[data-testid^="kepzettseg-"]');
|
||||
expect(selectors).toHaveLength(7);
|
||||
});
|
||||
});
|
||||
@@ -13,7 +13,7 @@ import {arraySetN} from "../../util";
|
||||
import {useDispatch, useSelector} from "react-redux";
|
||||
import {AppDispatch, RootState} from "../../store";
|
||||
import {characterSelector, setKepzettsegek, setTolvajKepzettsegek} from "../domain-models/characterSlice";
|
||||
import {TulajdonsagokTotal} from "../domain-models/tulajdonsag2E";
|
||||
import {TulajdonsagokFajjal} from "../domain-models/faj2E";
|
||||
|
||||
function InternalKepzettsegekSelector(props: {
|
||||
title: string,
|
||||
@@ -70,8 +70,8 @@ function KarakterKepzettsegek () {
|
||||
const karakter = useSelector.withTypes<RootState>()(characterSelector);
|
||||
const dispatch = useDispatch.withTypes<AppDispatch>()();
|
||||
|
||||
const tulajdonsagokTotal = TulajdonsagokTotal(karakter)
|
||||
const numberOfKepzettsegek = GetNumberOfKepzettsegek(tulajdonsagokTotal.t_int, karakter.faj)
|
||||
const tulajdonsagokFajjal = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
|
||||
const numberOfKepzettsegek = GetNumberOfKepzettsegek(tulajdonsagokFajjal.t_int, karakter.faj)
|
||||
const kepzettsegek = karakter.kepzettsegek
|
||||
const fajError = karakter.kepzettsegFajError
|
||||
const osztalyError = karakter.kepzettsegOsztalyError
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
import React from "react";
|
||||
import {fireEvent, render} from "@testing-library/react";
|
||||
import {configureStore} from "@reduxjs/toolkit";
|
||||
import {Provider} from "react-redux";
|
||||
import LevelUps from "./LevelUps";
|
||||
import userReducer from "../../shared/domain-models/userSlice";
|
||||
import characterReducer, {setCharacter} from "../domain-models/characterSlice";
|
||||
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
||||
import {Osztaly2E} from "../domain-models/osztaly2E";
|
||||
import {ChangeOsztalyAtSzint, DefaultKarakter, Karakter2E} from "../domain-models/karakter2E";
|
||||
import {LevelUp} from "../domain-models/szintlepes";
|
||||
import {GetAvailableKepzettsegek} from "../domain-models/kepzettsegek2E";
|
||||
|
||||
function applyLevelUp(karakter: Karakter2E): Karakter2E {
|
||||
let next: Karakter2E | undefined;
|
||||
LevelUp(karakter, updated => {
|
||||
next = updated;
|
||||
});
|
||||
expect(next).toBeDefined();
|
||||
return next as Karakter2E;
|
||||
}
|
||||
|
||||
describe("LevelUps Harcos specialization indexing", () => {
|
||||
it("updates specialization on the selected character level for multiclass", async () => {
|
||||
const level1Tolvaj: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 1,
|
||||
szintlepesek: [{
|
||||
osztaly: Osztaly2E.Tolvaj,
|
||||
HProll: 6,
|
||||
}],
|
||||
tolvajKepzettsegek: [],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const level2Auto = applyLevelUp(level1Tolvaj);
|
||||
const karakter = ChangeOsztalyAtSzint(level2Auto, Osztaly2E.Harcos, 2);
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
user: userReducer,
|
||||
character2E: characterReducer,
|
||||
},
|
||||
});
|
||||
store.dispatch(setCharacter(karakter));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<LevelUps
|
||||
karakter={store.getState().character2E}
|
||||
changeKarakter={(updated) => store.dispatch(setCharacter(updated))}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const selector = await sut.findByTestId("harcos-specialization-2");
|
||||
|
||||
const currentSpec = karakter.szintlepesek[1]?.harcosFegyver;
|
||||
const nextSpec = AllowedFegyver(Osztaly2E.Harcos)
|
||||
.map(x => x.Id)
|
||||
.find(id => id !== currentSpec);
|
||||
|
||||
expect(nextSpec).toBeDefined();
|
||||
fireEvent.change(selector, {target: {value: nextSpec as string}});
|
||||
|
||||
const stateAfter = store.getState().character2E;
|
||||
expect(stateAfter.szintlepesek[0]?.harcosFegyver).toBeUndefined();
|
||||
expect(stateAfter.szintlepesek[1]?.harcosFegyver).toBe(nextSpec);
|
||||
});
|
||||
|
||||
it("does not render tulajdonsag selector at level 4 when all abilities are maxed", () => {
|
||||
const maxedCharacter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 1,
|
||||
tulajdonsagok: {
|
||||
t_ero: 18,
|
||||
t_ugy: 18,
|
||||
t_egs: 18,
|
||||
t_int: 18,
|
||||
t_bol: 18,
|
||||
t_kar: 18,
|
||||
},
|
||||
szintlepesek: [{
|
||||
osztaly: Osztaly2E.Pap,
|
||||
HProll: 8,
|
||||
}],
|
||||
tolvajKepzettsegek: [],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const level2 = applyLevelUp(maxedCharacter);
|
||||
const level3 = applyLevelUp(level2);
|
||||
const level4 = applyLevelUp(level3);
|
||||
|
||||
expect(level4.szintlepesek[3]?.tulajdonsagNoveles).toBeUndefined();
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
user: userReducer,
|
||||
character2E: characterReducer,
|
||||
},
|
||||
});
|
||||
store.dispatch(setCharacter(level4));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<LevelUps
|
||||
karakter={store.getState().character2E}
|
||||
changeKarakter={(updated) => store.dispatch(setCharacter(updated))}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(sut.queryByTestId("tulajdonsag-4")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render kaloz krit selector when tengeresz milestone exists but krit is missing", () => {
|
||||
const inconsistentTengeresz: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 3,
|
||||
szintlepesek: [
|
||||
{
|
||||
osztaly: Osztaly2E.Tengeresz,
|
||||
HProll: 10,
|
||||
},
|
||||
{
|
||||
osztaly: Osztaly2E.Tengeresz,
|
||||
HProll: 5,
|
||||
},
|
||||
{
|
||||
osztaly: Osztaly2E.Tengeresz,
|
||||
HProll: 7,
|
||||
}
|
||||
],
|
||||
tolvajKepzettsegek: [],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
user: userReducer,
|
||||
character2E: characterReducer,
|
||||
},
|
||||
});
|
||||
store.dispatch(setCharacter(inconsistentTengeresz));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<LevelUps
|
||||
karakter={store.getState().character2E}
|
||||
changeKarakter={(updated) => store.dispatch(setCharacter(updated))}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
expect(sut.queryByTestId("kaloz-krit-3")).toBeNull();
|
||||
});
|
||||
|
||||
it("shows and updates Tolvaj extra skill on multiclass Tolvaj level 5", async () => {
|
||||
const multiclassTolvaj: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 6,
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 10 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3, tolvajExtraKepzettseg: "k_meregkeveres" },
|
||||
],
|
||||
tolvajKepzettsegek: ["k_alcazas", "k_csapdak", "k_egyensulyozas", "k_hamisitas"],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
user: userReducer,
|
||||
character2E: characterReducer,
|
||||
},
|
||||
});
|
||||
store.dispatch(setCharacter(multiclassTolvaj));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<LevelUps
|
||||
karakter={store.getState().character2E}
|
||||
changeKarakter={(updated) => store.dispatch(setCharacter(updated))}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const selector = await sut.findByTestId("tolvaj-extra-kepzettseg-6");
|
||||
const nextKepzettseg = GetAvailableKepzettsegek(multiclassTolvaj)
|
||||
.map(x => x.Id)
|
||||
.find(id => id !== multiclassTolvaj.szintlepesek[5]?.tolvajExtraKepzettseg);
|
||||
|
||||
expect(nextKepzettseg).toBeDefined();
|
||||
fireEvent.change(selector, {target: {value: nextKepzettseg as string}});
|
||||
|
||||
const stateAfter = store.getState().character2E;
|
||||
expect(stateAfter.szintlepesek[5]?.tolvajExtraKepzettseg).toBe(nextKepzettseg);
|
||||
expect(stateAfter.szintlepesek[4]?.tolvajExtraKepzettseg).toBeUndefined();
|
||||
});
|
||||
|
||||
it("at Tolvaj level 9 selector includes class-restricted non-Tolvaj skills", async () => {
|
||||
const tolvajLevel9: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 9,
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 2, tolvajExtraKepzettseg: "k_meregkeveres" },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, tolvajExtraKepzettseg: "k_alkimia" },
|
||||
],
|
||||
tolvajKepzettsegek: ["k_alcazas", "k_csapdak", "k_egyensulyozas", "k_hamisitas"],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const store = configureStore({
|
||||
reducer: {
|
||||
user: userReducer,
|
||||
character2E: characterReducer,
|
||||
},
|
||||
});
|
||||
store.dispatch(setCharacter(tolvajLevel9));
|
||||
|
||||
const sut = render(
|
||||
<Provider store={store}>
|
||||
<LevelUps
|
||||
karakter={store.getState().character2E}
|
||||
changeKarakter={(updated) => store.dispatch(setCharacter(updated))}
|
||||
/>
|
||||
</Provider>
|
||||
);
|
||||
|
||||
const selector = await sut.findByTestId("tolvaj-extra-kepzettseg-9");
|
||||
const arcaneOption = selector.querySelector('option[value="k_csillagjoslas"]');
|
||||
expect(arcaneOption).not.toBeNull();
|
||||
|
||||
fireEvent.change(selector, {target: {value: "k_csillagjoslas"}});
|
||||
expect(store.getState().character2E.szintlepesek[8]?.tolvajExtraKepzettseg).toBe("k_csillagjoslas");
|
||||
});
|
||||
});
|
||||
@@ -41,8 +41,6 @@ function LevelUp(props: {
|
||||
const kalozSzint = classLevels[Osztaly2E.Tengeresz]
|
||||
const tolvajSzint = classLevels[Osztaly2E.Tolvaj]
|
||||
const szintlepes = karakter.szintlepesek[szint-1];
|
||||
const tulajdonsagNoveles = szintlepes?.tulajdonsagNoveles;
|
||||
const kalozKritikus = szintlepes?.kalozKritikus;
|
||||
|
||||
return <div>
|
||||
<div className='row mt-3'>
|
||||
@@ -56,10 +54,10 @@ function LevelUp(props: {
|
||||
osztalySzint={classLevels[osztaly]}
|
||||
dataTestId={`osztaly-${szint}`}
|
||||
/>}
|
||||
{szint % 4 === 0 && tulajdonsagNoveles != null &&
|
||||
{szint % 4 === 0 &&
|
||||
<TulajdonsagNoveles
|
||||
tulajdonsagok={karakter.tulajdonsagok}
|
||||
tulajdonsagNoveles={tulajdonsagNoveles}
|
||||
tulajdonsagNoveles={karakter.szintlepesek[szint-1].tulajdonsagNoveles!}
|
||||
changeTulajdonsagNoveles={changeTulajdonsagNoveles}
|
||||
dataTestId={`tulajdonsag-${szint}`}
|
||||
/>}
|
||||
@@ -71,13 +69,12 @@ function LevelUp(props: {
|
||||
/>
|
||||
{osztaly === Osztaly2E.Harcos && harcosSzint % 2 === 1 &&
|
||||
<HarcosFegyverSpecializacio
|
||||
harcosSzint={harcosSzint}
|
||||
karakterSzint={szint}
|
||||
szint={harcosSzint}
|
||||
/>
|
||||
}
|
||||
{osztaly === Osztaly2E.Tengeresz && kalozSzint % 3 === 0 && kalozKritikus != null &&
|
||||
{osztaly === Osztaly2E.Tengeresz && kalozSzint % 3 === 0 &&
|
||||
<KalozKritikus
|
||||
kritFegyverId={kalozKritikus}
|
||||
kritFegyverId={szintlepes.kalozKritikus!}
|
||||
existingKrits={karakter.szintlepesek.map(x => x.kalozKritikus)}
|
||||
changeKrit={changeKalozKritikus}
|
||||
szint={kalozSzint}
|
||||
@@ -85,17 +82,12 @@ function LevelUp(props: {
|
||||
}
|
||||
{osztaly === Osztaly2E.Tolvaj
|
||||
&& (tolvajSzint === 5 || tolvajSzint === 9)
|
||||
&& szintlepes?.tolvajExtraKepzettseg != null &&
|
||||
&& szintlepes.tolvajExtraKepzettseg != null &&
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Extra képzettség</label>
|
||||
<KepzettsegSelector
|
||||
selected={Kepzettsegek[szintlepes!.tolvajExtraKepzettseg]}
|
||||
kepzettsegek={[
|
||||
Kepzettsegek[szintlepes!.tolvajExtraKepzettseg],
|
||||
...GetAvailableKepzettsegek(karakter, {
|
||||
ignoreClassRestrictions: tolvajSzint === 9,
|
||||
})
|
||||
]}
|
||||
selected={Kepzettsegek[szintlepes.tolvajExtraKepzettseg]}
|
||||
kepzettsegek={[Kepzettsegek[szintlepes.tolvajExtraKepzettseg], ...GetAvailableKepzettsegek(karakter)]}
|
||||
dataTestId={`tolvaj-extra-kepzettseg-${szint}`}
|
||||
changeKepzettseg={changeExtraTolvajKepzettseg}
|
||||
/>
|
||||
@@ -108,19 +100,16 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
|
||||
const {karakter, changeKarakter} = props;
|
||||
|
||||
const tulajdonsagokAtSzint = (szint: number) => TulajdonsagokTotal({...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint)})
|
||||
const szintlepesAt = (szint: number) => karakter.szintlepesek[szint-1]!
|
||||
|
||||
const changeRolledHPAtSzint = (szint: number) => (newHProll: number) => {
|
||||
const szintlepes = szintlepesAt(szint)
|
||||
changeKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {...szintlepes, HProll: newHProll})})
|
||||
changeKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {...karakter.szintlepesek[szint-1], HProll: newHProll})})
|
||||
console.log(karakter)
|
||||
}
|
||||
const changeTulajdonsagNovelesAtSzint = (szint: number) => {
|
||||
return (t: Tulajdonsag2E) => {
|
||||
const szintlepes = szintlepesAt(szint)
|
||||
changeKarakter({...karakter,
|
||||
szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {
|
||||
...szintlepes,
|
||||
...karakter.szintlepesek[szint-1],
|
||||
tulajdonsagNoveles: t
|
||||
})
|
||||
})
|
||||
@@ -129,11 +118,10 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
|
||||
|
||||
const changeKalozKritikusAtSzint = (szint: number) => {
|
||||
return (krit: string) => {
|
||||
const szintlepes = szintlepesAt(szint)
|
||||
changeKarakter({
|
||||
...karakter,
|
||||
szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {
|
||||
...szintlepes,
|
||||
...karakter.szintlepesek[szint-1],
|
||||
kalozKritikus: krit
|
||||
})
|
||||
})
|
||||
@@ -142,11 +130,10 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
|
||||
|
||||
const changeExtraTolvajKepzettseg = (szint: number) => {
|
||||
return (k: KepzettsegId) => {
|
||||
const szintlepes = szintlepesAt(szint)
|
||||
changeKarakter({
|
||||
...karakter,
|
||||
szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {
|
||||
...szintlepes,
|
||||
...karakter.szintlepesek[szint-1],
|
||||
tolvajExtraKepzettseg: k,
|
||||
})
|
||||
})
|
||||
@@ -157,13 +144,10 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
|
||||
|
||||
return <>
|
||||
{levels.slice(1).map(szint =>
|
||||
{
|
||||
const szintlepes = szintlepesAt(szint)
|
||||
return (
|
||||
<LevelUp
|
||||
key={`level-up-${szint}`}
|
||||
szint={szint}
|
||||
osztaly={szintlepes.osztaly}
|
||||
osztaly={karakter.szintlepesek[szint-1].osztaly}
|
||||
karakter={{...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint) ,tulajdonsagok: tulajdonsagokAtSzint(szint)}}
|
||||
changeTulajdonsagNoveles={changeTulajdonsagNovelesAtSzint(szint)}
|
||||
changeRolledHP={changeRolledHPAtSzint(szint)}
|
||||
@@ -171,8 +155,6 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
|
||||
changeOsztaly={(o) => changeKarakter(ChangeOsztalyAtSzint(karakter, o, szint))}
|
||||
changeExtraTolvajKepzettseg={changeExtraTolvajKepzettseg(szint)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)}
|
||||
</>
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import {AllowedFegyver} from "./allowed-fegyver";
|
||||
import {BaseHP} from "./masodlagos_ertekek";
|
||||
import {dAny} from "../../shared/domain-models/kockak";
|
||||
import {KarakterVarazslat} from "./varazslat";
|
||||
import {GetAvailableKepzettsegek} from "./kepzettsegek2E";
|
||||
|
||||
export interface Karakter2E {
|
||||
id?: string,
|
||||
@@ -52,15 +51,13 @@ export const DefaultKarakter: Karakter2E = {
|
||||
varazslatok: [],
|
||||
}
|
||||
|
||||
function setOsztalyForSzintLepes(karakter: Karakter2E, osztaly: Osztaly2E, szint: number): Szintlepes[] {
|
||||
const szintlepesek = karakter.szintlepesek
|
||||
function setOsztalyForSzintLepes(szintlepesek: Szintlepes[], osztaly: Osztaly2E, szint: number): Szintlepes[] {
|
||||
const prev = szintlepesek.slice(0, szint-1)
|
||||
const current : Szintlepes = {
|
||||
...szintlepesek[szint-1],
|
||||
osztaly,
|
||||
harcosFegyver: undefined,
|
||||
kalozKritikus: undefined,
|
||||
tolvajExtraKepzettseg: undefined,
|
||||
kalozKritikus: undefined
|
||||
}
|
||||
const tail = szintlepesek.slice(szint).map(x => {return {...x}})
|
||||
|
||||
@@ -120,39 +117,6 @@ function setOsztalyForSzintLepes(karakter: Karakter2E, osztaly: Osztaly2E, szint
|
||||
tail[i].kalozKritikus = kalozKritAtSzint(kalozSzint)
|
||||
}
|
||||
}
|
||||
|
||||
let tolvajSzint = prev.filter(x => x.osztaly === Osztaly2E.Tolvaj).length
|
||||
const existingTolvajExtraKepzettsegek = szintlepesek
|
||||
.map(x => x.tolvajExtraKepzettseg)
|
||||
.filter(x => x != null) as KepzettsegId[]
|
||||
const tolvajExtraKepzettsegAtSzint = (tSzint: number, atLevelSzintlepesek: Szintlepes[]): (KepzettsegId | undefined) => {
|
||||
if (tSzint !== 5 && tSzint !== 9) {
|
||||
return undefined
|
||||
}
|
||||
const extraIndex = tSzint === 5 ? 0 : 1
|
||||
if (existingTolvajExtraKepzettsegek.length > extraIndex) {
|
||||
return existingTolvajExtraKepzettsegek[extraIndex]
|
||||
}
|
||||
return GetAvailableKepzettsegek({
|
||||
szintlepesek: atLevelSzintlepesek,
|
||||
faj: karakter.faj,
|
||||
kepzettsegek: karakter.kepzettsegek,
|
||||
tolvajKepzettsegek: karakter.tolvajKepzettsegek,
|
||||
}, {
|
||||
ignoreClassRestrictions: tSzint === 9,
|
||||
})[0]?.Id
|
||||
}
|
||||
|
||||
if (osztaly === Osztaly2E.Tolvaj) {
|
||||
tolvajSzint++
|
||||
current.tolvajExtraKepzettseg = tolvajExtraKepzettsegAtSzint(tolvajSzint, [...prev, current])
|
||||
}
|
||||
for (let i = 0; i < tail.length; i++) {
|
||||
if (tail[i].osztaly === Osztaly2E.Tolvaj) {
|
||||
tolvajSzint++
|
||||
tail[i].tolvajExtraKepzettseg = tolvajExtraKepzettsegAtSzint(tolvajSzint, [...prev, current, ...tail.slice(0, i+1)])
|
||||
}
|
||||
}
|
||||
|
||||
const HD = BaseHP(osztaly)
|
||||
if (szint === 1) {
|
||||
@@ -174,6 +138,6 @@ export function ChangeLvl1Osztaly(karakter: Karakter2E, osztaly: Osztaly2E): Kar
|
||||
export function ChangeOsztalyAtSzint(karakter: Karakter2E, osztaly: Osztaly2E, szint: number): Karakter2E {
|
||||
return {
|
||||
...karakter,
|
||||
szintlepesek: setOsztalyForSzintLepes(karakter, osztaly, szint)
|
||||
szintlepesek: setOsztalyForSzintLepes(karakter.szintlepesek, osztaly, szint)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,28 +106,6 @@ describe("Kepzettsegek 2E", () => {
|
||||
const actual = GetAvailableKepzettsegek(karakter)
|
||||
expect(actual).not.toContain(Kepzettsegek.k_meregkeveres)
|
||||
})
|
||||
|
||||
test("at Tolvaj level 9 extra skill can include class-restricted non-Tolvaj skills", () => {
|
||||
const karakter = {
|
||||
...DefaultKarakter,
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, tulajdonsagNoveles: Tulajdonsag2E.Ugyesseg },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, tolvajExtraKepzettseg: Kepzettsegek.k_meregkeveres.Id },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, },
|
||||
]
|
||||
}
|
||||
|
||||
const restricted = GetAvailableKepzettsegek(karakter)
|
||||
expect(restricted).not.toContain(Kepzettsegek.k_csillagjoslas)
|
||||
|
||||
const unrestricted = GetAvailableKepzettsegek(karakter, { ignoreClassRestrictions: true })
|
||||
expect(unrestricted).toContain(Kepzettsegek.k_csillagjoslas)
|
||||
})
|
||||
})
|
||||
test("multiclass characters get access to kepzettsegek from all classes", () => {
|
||||
const karakter = {
|
||||
|
||||
@@ -13,8 +13,7 @@ function availableKezpettsegListFajjal(faj: Faj2E, ...osztalyok: Osztaly2E[]): K
|
||||
}
|
||||
|
||||
export function GetNumberOfKepzettsegek(t_int: number, faj: Faj2E, max: number = 11) {
|
||||
// Default cap is 11. Base calculation is 3 + 1 (human) + 3 (max ability modifier) = 7;
|
||||
// thief-specific extra selections are handled elsewhere and are not part of this default max.
|
||||
//max = 3 + 1 + 3 + 5 = 12 // 3 base, 1 human, 3 from max ability modifier, 4 from Thief +1 at 9th level
|
||||
let numberOfKepzettseg = 3 + Modifier(t_int) + (faj === Faj2E.Ember ? 1 : 0)
|
||||
|
||||
if (numberOfKepzettseg < 1) {
|
||||
@@ -28,15 +27,9 @@ export function GetNumberOfKepzettsegek(t_int: number, faj: Faj2E, max: number =
|
||||
return numberOfKepzettseg;
|
||||
}
|
||||
|
||||
export function GetAvailableKepzettsegek(
|
||||
karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>,
|
||||
options?: { ignoreClassRestrictions?: boolean }
|
||||
): Kepzettseg[] {
|
||||
export function GetAvailableKepzettsegek(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>): Kepzettseg[] {
|
||||
const osztalyok = new Set(karakter.szintlepesek.map(x => x.osztaly))
|
||||
const baseKepzettsegList = options?.ignoreClassRestrictions
|
||||
? KepzettsegLista
|
||||
: availableKezpettsegListFajjal(karakter.faj, ...osztalyok)
|
||||
const availableKepzettsegek = baseKepzettsegList
|
||||
const availableKepzettsegek = availableKezpettsegListFajjal(karakter.faj, ...osztalyok)
|
||||
.filter(k => !karakter.kepzettsegek.includes(k.Id))
|
||||
|
||||
if (!osztalyok.has(Osztaly2E.Tolvaj)) {
|
||||
|
||||
@@ -1,151 +0,0 @@
|
||||
import {ChangeOsztalyAtSzint, DefaultKarakter, Karakter2E} from "./karakter2E";
|
||||
import {Osztaly2E} from "./osztaly2E";
|
||||
import {LevelUp} from "./szintlepes";
|
||||
|
||||
function applyLevelUp(karakter: Karakter2E): Karakter2E {
|
||||
let next: Karakter2E | undefined;
|
||||
LevelUp(karakter, updated => {
|
||||
next = updated;
|
||||
});
|
||||
expect(next).toBeDefined();
|
||||
return next as Karakter2E;
|
||||
}
|
||||
|
||||
function level1Tolvaj(): Karakter2E {
|
||||
return {
|
||||
...DefaultKarakter,
|
||||
szint: 1,
|
||||
szintlepesek: [{
|
||||
osztaly: Osztaly2E.Tolvaj,
|
||||
HProll: 6,
|
||||
}],
|
||||
tolvajKepzettsegek: [],
|
||||
varazslatok: [],
|
||||
};
|
||||
}
|
||||
|
||||
describe("Harcos specialization in multiclass level-ups", () => {
|
||||
it("adds a specialization when first Harcos level is gained at character level 2", () => {
|
||||
const afterLevel2 = applyLevelUp(level1Tolvaj());
|
||||
const multiclassed = ChangeOsztalyAtSzint(afterLevel2, Osztaly2E.Harcos, 2);
|
||||
|
||||
const secondLevel = multiclassed.szintlepesek[1];
|
||||
expect(secondLevel?.osztaly).toBe(Osztaly2E.Harcos);
|
||||
expect(secondLevel?.harcosFegyver).toBeDefined();
|
||||
});
|
||||
|
||||
it("does not add a specialization on even Harcos class level", () => {
|
||||
const afterLevel2 = applyLevelUp(level1Tolvaj());
|
||||
const multiclassed = ChangeOsztalyAtSzint(afterLevel2, Osztaly2E.Harcos, 2);
|
||||
const afterLevel3 = applyLevelUp(multiclassed);
|
||||
|
||||
const thirdLevel = afterLevel3.szintlepesek[2];
|
||||
expect(thirdLevel?.osztaly).toBe(Osztaly2E.Harcos);
|
||||
expect(thirdLevel?.harcosFegyver).toBeUndefined();
|
||||
});
|
||||
|
||||
it("adds the next specialization on odd Harcos class level after multiclass", () => {
|
||||
const afterLevel2 = applyLevelUp(level1Tolvaj());
|
||||
const multiclassed = ChangeOsztalyAtSzint(afterLevel2, Osztaly2E.Harcos, 2);
|
||||
const afterLevel3 = applyLevelUp(multiclassed);
|
||||
const afterLevel4 = applyLevelUp(afterLevel3);
|
||||
|
||||
const firstHarcosSpec = multiclassed.szintlepesek[1]?.harcosFegyver;
|
||||
const thirdHarcosLevelSpec = afterLevel4.szintlepesek[3]?.harcosFegyver;
|
||||
|
||||
expect(firstHarcosSpec).toBeDefined();
|
||||
expect(thirdHarcosLevelSpec).toBeDefined();
|
||||
expect(thirdHarcosLevelSpec).not.toBe(firstHarcosSpec);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Tolvaj extra skill in multiclass level-ups", () => {
|
||||
it("adds extra skill when Tolvaj class reaches level 5 at higher character level", () => {
|
||||
const karakter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 5,
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 10 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
],
|
||||
tolvajKepzettsegek: ["k_alcazas", "k_csapdak", "k_egyensulyozas", "k_hamisitas"],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const afterLevel6 = applyLevelUp(karakter);
|
||||
const sixthLevel = afterLevel6.szintlepesek[5];
|
||||
|
||||
expect(sixthLevel?.osztaly).toBe(Osztaly2E.Tolvaj);
|
||||
expect(sixthLevel?.tolvajExtraKepzettseg).toBeDefined();
|
||||
});
|
||||
|
||||
it("recomputes missing extra skill when class change makes current level Tolvaj level 5", () => {
|
||||
const karakter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 5,
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 8 },
|
||||
],
|
||||
tolvajKepzettsegek: ["k_alcazas", "k_csapdak", "k_egyensulyozas", "k_hamisitas"],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const changed = ChangeOsztalyAtSzint(karakter, Osztaly2E.Tolvaj, 5);
|
||||
const fifthLevel = changed.szintlepesek[4];
|
||||
|
||||
expect(fifthLevel?.osztaly).toBe(Osztaly2E.Tolvaj);
|
||||
expect(fifthLevel?.tolvajExtraKepzettseg).toBeDefined();
|
||||
});
|
||||
|
||||
it("at Tolvaj class level 9 LevelUp can auto-pick a class-restricted non-Tolvaj skill", () => {
|
||||
const karakter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 8,
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 2, tolvajExtraKepzettseg: "k_meregkeveres" },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
],
|
||||
tolvajKepzettsegek: ["k_alcazas", "k_csapdak", "k_egyensulyozas", "k_hamisitas"],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const afterLevel9 = applyLevelUp(karakter);
|
||||
expect(afterLevel9.szintlepesek[8]?.tolvajExtraKepzettseg).toBe("k_alkimia");
|
||||
});
|
||||
|
||||
it("at Tolvaj class level 9 class-change recomputation can set non-Tolvaj restricted skill", () => {
|
||||
const karakter: Karakter2E = {
|
||||
...DefaultKarakter,
|
||||
szint: 9,
|
||||
szintlepesek: [
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 6 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 2, tolvajExtraKepzettseg: "k_meregkeveres" },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 4 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 5 },
|
||||
{ osztaly: Osztaly2E.Tolvaj, HProll: 3 },
|
||||
{ osztaly: Osztaly2E.Harcos, HProll: 8 },
|
||||
],
|
||||
tolvajKepzettsegek: ["k_alcazas", "k_csapdak", "k_egyensulyozas", "k_hamisitas"],
|
||||
varazslatok: [],
|
||||
};
|
||||
|
||||
const changed = ChangeOsztalyAtSzint(karakter, Osztaly2E.Tolvaj, 9);
|
||||
expect(changed.szintlepesek[8]?.tolvajExtraKepzettseg).toBe("k_alkimia");
|
||||
});
|
||||
});
|
||||
@@ -67,9 +67,7 @@ export function LevelUp(karakter: Karakter2E, changeKarakter: (input: Karakter2E
|
||||
if (autoPickedOsztaly === Osztaly2E.Tolvaj){
|
||||
const tolvajSzint = 1 + karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Tolvaj).length
|
||||
if (tolvajSzint === 5 || tolvajSzint === 9) {
|
||||
const availableKepzettsegek = GetAvailableKepzettsegek(karakter, {
|
||||
ignoreClassRestrictions: tolvajSzint === 9,
|
||||
})
|
||||
const availableKepzettsegek = GetAvailableKepzettsegek(karakter)
|
||||
szintlepes.tolvajExtraKepzettseg = availableKepzettsegek[0].Id;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ function CreateCharacter2E(props: {
|
||||
<h4 className='col align-self-center'>Tanult</h4>
|
||||
</div>
|
||||
<OsztalySelector2E />
|
||||
{karakter.szintlepesek[0].osztaly === Osztaly2E.Harcos && <HarcosFegyverSpecializacio harcosSzint={1} karakterSzint={1}/>}
|
||||
{karakter.szintlepesek[0].osztaly === Osztaly2E.Harcos && <HarcosFegyverSpecializacio szint={1}/>}
|
||||
<KarakterKepzettsegek />
|
||||
<hr/>
|
||||
{/* 1. szinten */}
|
||||
|
||||
+77
-82
@@ -434,22 +434,22 @@
|
||||
"@eslint/core" "^0.17.0"
|
||||
levn "^0.4.1"
|
||||
|
||||
"@grafana/faro-core@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-2.3.1.tgz#4392673454e76c788aab9a5558985d2fb7368678"
|
||||
integrity sha512-htDKO0YFKr0tfntrPoM151vOPSZzmP6oE0+0MDvbI1WDaBW4erXmYi3feGJLWDXt5/vZBg9iQRmZoRzTLTTcOA==
|
||||
"@grafana/faro-core@^1.8.2":
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.8.2.tgz#f3c374b5267e74e2bad991fd00a1a0a15cbb5a01"
|
||||
integrity sha512-STj5KqGN4R4Zmul+bRLDBxFTszjBozbvFdtLSVPavhfJUHeuTLE6y9EIDAnz8c3yT2FBO2t8WkJKZfAu+uPH5w==
|
||||
dependencies:
|
||||
"@opentelemetry/api" "^1.9.0"
|
||||
"@opentelemetry/otlp-transformer" "^0.213.0"
|
||||
"@opentelemetry/otlp-transformer" "^0.52.0"
|
||||
|
||||
"@grafana/faro-web-sdk@^2.3.1":
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-2.3.1.tgz#bdfe9d821e9d3f0e2a9ba7a7aeb5dcd0e32dc1da"
|
||||
integrity sha512-WMfErl2YSP+CcfcobMpCdK6apX86hc8bymMXsvYLQpBBkQ0KJjIilEQS/YXd+g/cg6F1kwbeweisBKluNNy5sA==
|
||||
"@grafana/faro-web-sdk@^1.4.2":
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.8.2.tgz#becda21cb8a6366b824ac9c1ea33de77ac74a1ad"
|
||||
integrity sha512-626pJ+UI/xWGyMbkNzOQ+NiEZkGxIa7AomakqrMXyBJpN6t2bKv8FP1ztSTZyRVzETyIdfCgfDPnZm9S+Nk+UQ==
|
||||
dependencies:
|
||||
"@grafana/faro-core" "^2.3.1"
|
||||
ua-parser-js "1.0.41"
|
||||
web-vitals "^5.1.0"
|
||||
"@grafana/faro-core" "^1.8.2"
|
||||
ua-parser-js "^1.0.32"
|
||||
web-vitals "^4.0.1"
|
||||
|
||||
"@humanfs/core@^0.19.1":
|
||||
version "0.19.1"
|
||||
@@ -535,82 +535,77 @@
|
||||
"@jridgewell/resolve-uri" "^3.1.0"
|
||||
"@jridgewell/sourcemap-codec" "^1.4.14"
|
||||
|
||||
"@opentelemetry/api-logs@0.213.0":
|
||||
version "0.213.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.213.0.tgz#c7abc7d3c4586cfbfd737c0a2fcfb2323a9def75"
|
||||
integrity sha512-zRM5/Qj6G84Ej3F1yt33xBVY/3tnMxtL1fiDIxYbDWYaZ/eudVw3/PBiZ8G7JwUxXxjW8gU4g6LnOyfGKYHYgw==
|
||||
"@opentelemetry/api-logs@0.52.1":
|
||||
version "0.52.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.52.1.tgz#52906375da4d64c206b0c4cb8ffa209214654ecc"
|
||||
integrity sha512-qnSqB2DQ9TPP96dl8cDubDvrUyWc0/sK81xHTK8eSUspzDM3bsewX903qclQFvVhgStjRWdC5bLb3kQqMkfV5A==
|
||||
dependencies:
|
||||
"@opentelemetry/api" "^1.3.0"
|
||||
"@opentelemetry/api" "^1.0.0"
|
||||
|
||||
"@opentelemetry/api@^1.3.0":
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.1.tgz#c1b0346de336ba55af2d5a7970882037baedec05"
|
||||
integrity sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==
|
||||
|
||||
"@opentelemetry/api@^1.9.0":
|
||||
"@opentelemetry/api@^1.0.0", "@opentelemetry/api@^1.9.0":
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.9.0.tgz#d03eba68273dc0f7509e2a3d5cba21eae10379fe"
|
||||
integrity sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==
|
||||
|
||||
"@opentelemetry/core@2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-2.6.0.tgz#719c829ed98bd7af808a2d2c83374df1fd1f3c66"
|
||||
integrity sha512-HLM1v2cbZ4TgYN6KEOj+Bbj8rAKriOdkF9Ed3tG25FoprSiQl7kYc+RRT6fUZGOvx0oMi5U67GoFdT+XUn8zEg==
|
||||
"@opentelemetry/core@1.25.1":
|
||||
version "1.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.25.1.tgz#ff667d939d128adfc7c793edae2f6bca177f829d"
|
||||
integrity sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==
|
||||
dependencies:
|
||||
"@opentelemetry/semantic-conventions" "^1.29.0"
|
||||
"@opentelemetry/semantic-conventions" "1.25.1"
|
||||
|
||||
"@opentelemetry/otlp-transformer@^0.213.0":
|
||||
version "0.213.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.213.0.tgz#e830244d21817805b8967963ffc4651b8f5c96ee"
|
||||
integrity sha512-RSuAlxFFPjeK4d5Y6ps8L2WhaQI6CXWllIjvo5nkAlBpmq2XdYWEBGiAbOF4nDs8CX4QblJDv5BbMUft3sEfDw==
|
||||
"@opentelemetry/otlp-transformer@^0.52.0":
|
||||
version "0.52.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.52.1.tgz#779b7ebf0e3791eebeaa64caff06914fe3577948"
|
||||
integrity sha512-I88uCZSZZtVa0XniRqQWKbjAUm73I8tpEy/uJYPPYw5d7BRdVk0RfTBQw8kSUl01oVWEuqxLDa802222MYyWHg==
|
||||
dependencies:
|
||||
"@opentelemetry/api-logs" "0.213.0"
|
||||
"@opentelemetry/core" "2.6.0"
|
||||
"@opentelemetry/resources" "2.6.0"
|
||||
"@opentelemetry/sdk-logs" "0.213.0"
|
||||
"@opentelemetry/sdk-metrics" "2.6.0"
|
||||
"@opentelemetry/sdk-trace-base" "2.6.0"
|
||||
protobufjs "^7.0.0"
|
||||
"@opentelemetry/api-logs" "0.52.1"
|
||||
"@opentelemetry/core" "1.25.1"
|
||||
"@opentelemetry/resources" "1.25.1"
|
||||
"@opentelemetry/sdk-logs" "0.52.1"
|
||||
"@opentelemetry/sdk-metrics" "1.25.1"
|
||||
"@opentelemetry/sdk-trace-base" "1.25.1"
|
||||
protobufjs "^7.3.0"
|
||||
|
||||
"@opentelemetry/resources@2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-2.6.0.tgz#1a945dbb8986043d8b593c358d5d8e3de6becf5a"
|
||||
integrity sha512-D4y/+OGe3JSuYUCBxtH5T9DSAWNcvCb/nQWIga8HNtXTVPQn59j0nTBAgaAXxUVBDl40mG3Tc76b46wPlZaiJQ==
|
||||
"@opentelemetry/resources@1.25.1":
|
||||
version "1.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.25.1.tgz#bb9a674af25a1a6c30840b755bc69da2796fefbb"
|
||||
integrity sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "2.6.0"
|
||||
"@opentelemetry/semantic-conventions" "^1.29.0"
|
||||
"@opentelemetry/core" "1.25.1"
|
||||
"@opentelemetry/semantic-conventions" "1.25.1"
|
||||
|
||||
"@opentelemetry/sdk-logs@0.213.0":
|
||||
version "0.213.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.213.0.tgz#babf51dfd3e2bc882a41a0de2a13a2077d6df764"
|
||||
integrity sha512-00xlU3GZXo3kXKve4DLdrAL0NAFUaZ9appU/mn00S/5kSUdAvyYsORaDUfR04Mp2CLagAOhrzfUvYozY/EZX2g==
|
||||
"@opentelemetry/sdk-logs@0.52.1":
|
||||
version "0.52.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.52.1.tgz#5653faa2d81cae574729bdeb4298b95dc10ae736"
|
||||
integrity sha512-MBYh+WcPPsN8YpRHRmK1Hsca9pVlyyKd4BxOC4SsgHACnl/bPp4Cri9hWhVm5+2tiQ9Zf4qSc1Jshw9tOLGWQA==
|
||||
dependencies:
|
||||
"@opentelemetry/api-logs" "0.213.0"
|
||||
"@opentelemetry/core" "2.6.0"
|
||||
"@opentelemetry/resources" "2.6.0"
|
||||
"@opentelemetry/semantic-conventions" "^1.29.0"
|
||||
"@opentelemetry/api-logs" "0.52.1"
|
||||
"@opentelemetry/core" "1.25.1"
|
||||
"@opentelemetry/resources" "1.25.1"
|
||||
|
||||
"@opentelemetry/sdk-metrics@2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.6.0.tgz#c9f63eb68a5c7600a4ffc84bdce3ef59c9b1af47"
|
||||
integrity sha512-CicxWZxX6z35HR83jl+PLgtFgUrKRQ9LCXyxgenMnz5A1lgYWfAog7VtdOvGkJYyQgMNPhXQwkYrDLujk7z1Iw==
|
||||
"@opentelemetry/sdk-metrics@1.25.1":
|
||||
version "1.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.1.tgz#50c985ec15557a9654334e7fa1018dc47a8a56b7"
|
||||
integrity sha512-9Mb7q5ioFL4E4dDrc4wC/A3NTHDat44v4I3p2pLPSxRvqUbDIQyMVr9uK+EU69+HWhlET1VaSrRzwdckWqY15Q==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "2.6.0"
|
||||
"@opentelemetry/resources" "2.6.0"
|
||||
"@opentelemetry/core" "1.25.1"
|
||||
"@opentelemetry/resources" "1.25.1"
|
||||
lodash.merge "^4.6.2"
|
||||
|
||||
"@opentelemetry/sdk-trace-base@2.6.0":
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.6.0.tgz#d7e752a0906f2bcae3c1261e224aef3e3b3746f9"
|
||||
integrity sha512-g/OZVkqlxllgFM7qMKqbPV9c1DUPhQ7d4n3pgZFcrnrNft9eJXZM2TNHTPYREJBrtNdRytYyvwjgL5geDKl3EQ==
|
||||
"@opentelemetry/sdk-trace-base@1.25.1":
|
||||
version "1.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.25.1.tgz#cbc1e60af255655d2020aa14cde17b37bd13df37"
|
||||
integrity sha512-C8k4hnEbc5FamuZQ92nTOp8X/diCY56XUTnMiv9UTuJitCzaNNHAVsdm5+HLCdI8SLQsLWIrG38tddMxLVoftw==
|
||||
dependencies:
|
||||
"@opentelemetry/core" "2.6.0"
|
||||
"@opentelemetry/resources" "2.6.0"
|
||||
"@opentelemetry/semantic-conventions" "^1.29.0"
|
||||
"@opentelemetry/core" "1.25.1"
|
||||
"@opentelemetry/resources" "1.25.1"
|
||||
"@opentelemetry/semantic-conventions" "1.25.1"
|
||||
|
||||
"@opentelemetry/semantic-conventions@^1.29.0":
|
||||
version "1.40.0"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.40.0.tgz#10b2944ca559386590683392022a897eefd011d3"
|
||||
integrity sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==
|
||||
"@opentelemetry/semantic-conventions@1.25.1":
|
||||
version "1.25.1"
|
||||
resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz#0deecb386197c5e9c2c28f2f89f51fb8ae9f145e"
|
||||
integrity sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==
|
||||
|
||||
"@pdf-lib/fontkit@^1.1.1":
|
||||
version "1.1.1"
|
||||
@@ -2347,10 +2342,10 @@ prop-types@^15.6.2, prop-types@^15.8.1:
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
protobufjs@^7.0.0:
|
||||
version "7.5.4"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.5.4.tgz#885d31fe9c4b37f25d1bb600da30b1c5b37d286a"
|
||||
integrity sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==
|
||||
protobufjs@^7.3.0:
|
||||
version "7.3.2"
|
||||
resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.3.2.tgz#60f3b7624968868f6f739430cfbc8c9370e26df4"
|
||||
integrity sha512-RXyHaACeqXeqAKGLDl68rQKbmObRsTIn4TYVUUug1KfS47YWCo5MacGITEryugIgZqORCvJWEk4l449POg5Txg==
|
||||
dependencies:
|
||||
"@protobufjs/aspromise" "^1.1.2"
|
||||
"@protobufjs/base64" "^1.1.2"
|
||||
@@ -2736,10 +2731,10 @@ typescript@^5.2.2:
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.5.3.tgz#e1b0a3c394190838a0b168e771b0ad56a0af0faa"
|
||||
integrity sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==
|
||||
|
||||
ua-parser-js@1.0.41:
|
||||
version "1.0.41"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.41.tgz#bd04dc9ec830fcf9e4fad35cf22dcedd2e3b4e9c"
|
||||
integrity sha512-LbBDqdIC5s8iROCUjMbW1f5dJQTEFB1+KO9ogbvlb3nm9n4YHa5p4KTvFPWvh2Hs8gZMBuiB1/8+pdfe/tDPug==
|
||||
ua-parser-js@^1.0.32:
|
||||
version "1.0.38"
|
||||
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-1.0.38.tgz#66bb0c4c0e322fe48edfe6d446df6042e62f25e2"
|
||||
integrity sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==
|
||||
|
||||
uncontrollable@^7.2.1:
|
||||
version "7.2.1"
|
||||
@@ -2848,10 +2843,10 @@ warning@^4.0.0, warning@^4.0.3:
|
||||
dependencies:
|
||||
loose-envify "^1.0.0"
|
||||
|
||||
web-vitals@^5.1.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-5.2.0.tgz#5de39106a652228bb5c40021d62b669d213e6e17"
|
||||
integrity sha512-i2z98bEmaCqSDiHEDu+gHl/dmR4Q+TxFmG3/13KkMO+o8UxQzCqWaDRCiLgEa41nlO4VpXSI0ASa1xWmO9sBlA==
|
||||
web-vitals@^4.0.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.1.tgz#67eec387ddd0ef4c25574a01ab9dae723eee2b97"
|
||||
integrity sha512-U6bAxeudnhDqcXNl50JC4hLlqox9DZnngxfISZm3DMZnonW35xtJOVUc091L+DOY+6hVZVpKXoiCP0RiT6339Q==
|
||||
|
||||
webidl-conversions@^7.0.0:
|
||||
version "7.0.0"
|
||||
|
||||
Reference in New Issue
Block a user