fix tolvajkepzettseg

This commit is contained in:
2024-05-17 19:36:31 +02:00
parent a5019a85cb
commit 0ea7853437
6 changed files with 224 additions and 88 deletions
@@ -2,11 +2,10 @@ import React from "react";
import KepzettsegSelector from "../display-components/KepzettsegSelector2E";
import {
GetKepzettsegListaN,
GetNumberOfKepzettsegek,
GetNumberOfKepzettsegek, GetTolvajKepzettsegListaN,
Kepzettseg,
Kepzettsegek,
KepzettsegId,
TolvajKepzettsegList,
} from "../domain-models/kepzettsegek2E";
import {arraySetN} from "../../util";
import {useDispatch, useSelector} from "react-redux";
@@ -79,13 +78,6 @@ function KarakterKepzettsegek () {
const changeKepzettsegek = (k: KepzettsegId[]) => dispatch(setKepzettsegek(k))
const changeTolvajKepzettsegek = (k: KepzettsegId[]) => dispatch(setTolvajKepzettsegek(k))
// TODO: Birodalmi tolvajnal az Alikmia, vagy Meregkeveres kezelese
const getTolvajKepzettsegListaN = (n: number) : Kepzettseg[] => {
const tolvajKepzettsegekWithoutN = [...tolvajKepzettsegek.slice(0, n), ...tolvajKepzettsegek.slice(n+1)]
return TolvajKepzettsegList.filter(x => !kepzettsegek.includes(x.Id) && !tolvajKepzettsegekWithoutN.includes(x.Id))
}
return <>
<InternalKepzettsegekSelector
title="Képzettségek"
@@ -102,7 +94,7 @@ function KarakterKepzettsegek () {
{tolvajKepzettsegek.length > 0 && <InternalKepzettsegekSelector
title="Tolvaj képzettségek"
numberOfKepzettseg={4}
getKepzettsegListaN={getTolvajKepzettsegListaN}
getKepzettsegListaN={GetTolvajKepzettsegListaN(karakter)}
changeKepzettsegek={changeTolvajKepzettsegek}
kepzettsegek={tolvajKepzettsegek}
dataTestId={"tolvaj-kepzettseg"}
@@ -10,6 +10,8 @@ import HarcosFegyverSpecializacio from "./HarcosFegyverSpec";
import MultiClassOsztalySelector2E from "./MultiClassOsztalySelector2E";
import {getClassLevels} from "../domain-models/szintlepes";
import KepzettsegSelector from "../display-components/KepzettsegSelector2E";
import {GetAvailableKepzettsegek, Kepzettsegek, KepzettsegId} from "../domain-models/kepzettsegek2E";
function LevelUp(props: {
szint: number,
@@ -18,7 +20,8 @@ function LevelUp(props: {
changeTulajdonsagNoveles: (t: Tulajdonsag2E) => void,
changeRolledHP: (rolledHP: number) => void,
changeKalozKritikus: (krit: string) => void,
changeOsztaly: (osztaly: Osztaly2E) => void
changeOsztaly: (osztaly: Osztaly2E) => void,
changeExtraTolvajKepzettseg: (kepzettseg: KepzettsegId) => void,
}) {
const {
szint,
@@ -27,14 +30,16 @@ function LevelUp(props: {
changeTulajdonsagNoveles,
changeRolledHP,
changeKalozKritikus,
changeOsztaly
changeOsztaly,
changeExtraTolvajKepzettseg
} = props
const classLevels = getClassLevels(karakter.szintlepesek)
const harcosSzint = classLevels[Osztaly2E.Harcos]
const kalozSzint = classLevels[Osztaly2E.Tengeresz]
const krit = karakter.szintlepesek[szint-1].kalozKritikus
const tolvajSzint = classLevels[Osztaly2E.Tolvaj]
const szintlepes = karakter.szintlepesek[szint-1];
return <div>
<div className='row mt-3'>
@@ -68,12 +73,25 @@ function LevelUp(props: {
}
{osztaly === Osztaly2E.Tengeresz && kalozSzint % 3 === 0 &&
<KalozKritikus
kritFegyverId={krit!}
kritFegyverId={szintlepes.kalozKritikus!}
existingKrits={karakter.szintlepesek.map(x => x.kalozKritikus)}
changeKrit={changeKalozKritikus}
szint={kalozSzint}
/>
}
{osztaly === Osztaly2E.Tolvaj
&& (tolvajSzint === 5 || tolvajSzint === 9)
&& 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)]}
dataTestId={`tolvaj-extra-kepzettseg-${szint}`}
changeKepzettseg={changeExtraTolvajKepzettseg}
/>
</div>
}
</div>
}
@@ -109,6 +127,18 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
};
}
const changeExtraTolvajKepzettseg = (szint: number) => {
return (k: KepzettsegId) => {
changeKarakter({
...karakter,
szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {
...karakter.szintlepesek[szint-1],
tolvajExtraKepzettseg: k,
})
})
}
}
const levels = karakter.szintlepesek.map((_, i) => i+1);
return <>
@@ -122,6 +152,7 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
changeRolledHP={changeRolledHPAtSzint(szint)}
changeKalozKritikus={changeKalozKritikusAtSzint(szint)}
changeOsztaly={(o) => changeKarakter(ChangeOsztalyAtSzint(karakter, o, szint))}
changeExtraTolvajKepzettseg={changeExtraTolvajKepzettseg(szint)}
/>
)}
</>
@@ -0,0 +1,123 @@
import {GetAvailableKepzettsegek, GetNumberOfKepzettsegek, Kepzettsegek, KepzettsegLista} from "./kepzettsegek2E";
import {Faj2E} from "./faj2E";
import {DefaultKarakter} from "./karakter2E";
import {Osztaly2E} from "./osztaly2E";
import {Tulajdonsag2E} from "./tulajdonsag2E";
describe("Kepzettsegek 2E", () => {
describe("GetNumberOfKepzettsegek", () => {
test("Add extra kepzettseg for Ember", () => {
const actual = GetNumberOfKepzettsegek(18, Faj2E.Ember)
expect(actual).toEqual(7)
})
test("should be min for extra stupid", () => {
const actual = GetNumberOfKepzettsegek(3, Faj2E.Osember)
expect(actual).toEqual(1)
})
test("never less than 1", () => {
const actual = GetNumberOfKepzettsegek(-999, Faj2E.Osember)
expect(actual).toEqual(1)
})
test("never more than 11", () => {
const actual = GetNumberOfKepzettsegek(999, Faj2E.Elf)
expect(actual).toEqual(11)
})
})
describe("GetAvailableKepzettsegek", () => {
test("excludes existing karakter kepzettsegek", () => {
const karakter = {
...DefaultKarakter,
kepzettsegek: KepzettsegLista.map(x => x.Id),
}
const actual = GetAvailableKepzettsegek(karakter)
expect(actual).toHaveLength(0)
})
test("includes Birodalmi kepzettsegek for a Birodalmi", () => {
const karakter = {
...DefaultKarakter,
faj: Faj2E.Birodalmi,
}
const actual = GetAvailableKepzettsegek(karakter)
expect(actual).toContain(Kepzettsegek.k_meregkeveres)
expect(actual).toContain(Kepzettsegek.k_alkimia)
expect(actual).toContain(Kepzettsegek.k_okkultizmus)
})
test.each([
[Osztaly2E.Varazslo],
[Osztaly2E.Illuzionista],
[Osztaly2E.Pap],
[Osztaly2E.Druida],
[Osztaly2E.Vandor],
])("includes arcane kepzettsegek for %s", (osztaly) => {
const karakter = {
...DefaultKarakter,
szintlepesek: [
{ osztaly, HProll: 4, },
]
}
const actual = GetAvailableKepzettsegek(karakter)
expect(actual).toContain(Kepzettsegek.k_csillagjoslas)
})
describe("when Tolvaj", () => {
test("includes unpicked Tolvaj kepzettsegek", () => {
const karakter = {
...DefaultKarakter,
szintlepesek: [
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, }
]
}
const actual = GetAvailableKepzettsegek(karakter)
expect(actual).toContain(Kepzettsegek.k_meregkeveres)
})
test.each([
[Kepzettsegek.k_meregkeveres],
[Kepzettsegek.k_alcazas],
[Kepzettsegek.k_csapdak],
[Kepzettsegek.k_szabadulomuveszet],
[Kepzettsegek.k_hamisitas],
])("excludes already picked Tolvaj kepzettsegek", (kepzettseg) => {
const karakter = {
...DefaultKarakter,
szintlepesek: [
{ osztaly: Osztaly2E.Tolvaj, HProll: 6, }
],
tolvajKepzettsegek: [kepzettseg.Id]
}
const actual = GetAvailableKepzettsegek(karakter)
expect(actual).not.toContain(kepzettseg)
})
test("excludes extra high level Tolvaj kepzettsegek", () => {
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
},
]
}
const actual = GetAvailableKepzettsegek(karakter)
expect(actual).not.toContain(Kepzettsegek.k_meregkeveres)
})
})
test("multiclass characters get access to kepzettsegek from all classes", () => {
const karakter = {
...DefaultKarakter,
szintlepesek: [
{ osztaly: Osztaly2E.Illuzionista, HProll: 4, },
{ osztaly: Osztaly2E.Tolvaj, HProll: 4, },
]
}
const actual = GetAvailableKepzettsegek(karakter)
expect(actual).toContain(Kepzettsegek.k_csillagjoslas)
expect(actual).toContain(Kepzettsegek.k_meregkeveres)
})
})
})
@@ -1,7 +1,7 @@
import {Osztaly2E} from "./osztaly2E";
import {Faj2E, TulajdonsagokFajjal} from "./faj2E";
import {Faj2E} from "./faj2E";
import {Karakter2E} from "./karakter2E";
import {Modifier, Tulajdonsag2E} from "./tulajdonsag2E";
import {Modifier, Tulajdonsag2E, TulajdonsagokTotal} from "./tulajdonsag2E";
export type KepzettsegId = 'k_alkimia' | 'k_alcazas' | 'k_allatidomitas' | 'k_csapdak' | 'k_csillagjoslas' | 'k_egyensulyozas' | 'k_eloadas' | 'k_ertekbecsles' | 'k_gyogyitas' | 'k_hajozas' | 'k_hallgatozas' | 'k_hamisitas' | 'k_herbalizmus' | 'k_historia' | 'k_jelek_olvasasa' | 'k_lovaglas' | 'k_maszas' | 'k_megfigyeles' | 'k_meregkeveres' | 'k_mesterseg' | 'k_nyomkereses' | 'k_okkultizmus' | 'k_osonas' | 'k_szabadulomuveszet' | 'k_ugras' | 'k_uszas' | 'k_vadonjaras' | 'k_zarnyitas' | 'k_zsebmetszes'
@@ -209,11 +209,7 @@ export const Kepzettsegek: Record<KepzettsegId, Kepzettseg> =
(acc: Record<KepzettsegId, Kepzettseg>, k) => { acc[k.Id] = k; return acc; },
{} as Record<KepzettsegId, Kepzettseg>);
export function AvailableKezpettsegList(...osztalyok: Osztaly2E[]): Kepzettseg[] {
return KepzettsegLista.filter(k => k.Osztalyok == null || k.Osztalyok.some(o => osztalyok.includes(o)))
}
export function AvailableKezpettsegListFajjal(faj: Faj2E, ...osztalyok: Osztaly2E[]): Kepzettseg[] {
function availableKezpettsegListFajjal(faj: Faj2E, ...osztalyok: Osztaly2E[]): Kepzettseg[] {
const birodalmiKepzettsegek : KepzettsegId[] = ["k_alkimia", "k_meregkeveres", "k_okkultizmus"]
return KepzettsegLista.filter(k =>
k.Osztalyok == null || k.Osztalyok.some(o => osztalyok.includes(o))
@@ -222,7 +218,7 @@ export function AvailableKezpettsegListFajjal(faj: Faj2E, ...osztalyok: Osztaly2
}
export function GetNumberOfKepzettsegek(t_int: number, faj: Faj2E, max: number = 11) {
//max = 3 + 1 + 3 + 5 = 12 // 3 base, 1 human, 3 from max ability modifier, 5 from Thief at 9th level
//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) {
@@ -236,6 +232,21 @@ export function GetNumberOfKepzettsegek(t_int: number, faj: Faj2E, max: number =
return numberOfKepzettseg;
}
export function GetAvailableKepzettsegek(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>): Kepzettseg[] {
const osztalyok = new Set(karakter.szintlepesek.map(x => x.osztaly))
const availableKepzettsegek = availableKezpettsegListFajjal(karakter.faj, ...osztalyok)
.filter(k => !karakter.kepzettsegek.includes(k.Id))
if (!osztalyok.has(Osztaly2E.Tolvaj)) {
return availableKepzettsegek;
}
return availableKepzettsegek.filter(k =>
!karakter.tolvajKepzettsegek?.includes(k.Id)
&& !karakter.szintlepesek.some(sz =>
sz.tolvajExtraKepzettseg === k.Id && sz.osztaly === Osztaly2E.Tolvaj))
}
export function SetDefaultTolvajKepzettsegek(karakter: Pick<Karakter2E, 'szintlepesek' | 'tolvajKepzettsegek'>, changeTolvajKepzettsegek: (tolvajKepzettsegek?: KepzettsegId[]) => void) {
const hasTolvajSzint = karakter.szintlepesek.some(szint => szint.osztaly === Osztaly2E.Tolvaj)
if (!hasTolvajSzint && karakter.tolvajKepzettsegek != null) {
@@ -247,79 +258,47 @@ export function SetDefaultTolvajKepzettsegek(karakter: Pick<Karakter2E, 'szintle
}
}
export function GetKepzettsegAtN(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>, n: number): Kepzettseg | undefined {
const osztalyok = new Set(karakter.szintlepesek.map(x => x.osztaly))
let availableKepzettsegList = AvailableKezpettsegListFajjal(karakter.faj, ...osztalyok)
const kepzettsegekWithoutN = [...karakter.kepzettsegek.slice(0, n), ...karakter.kepzettsegek.slice(n + 1)]
return availableKepzettsegList.find(x => !kepzettsegekWithoutN.includes(x.Id) && !karakter.tolvajKepzettsegek?.includes(x.Id))
export function GetKepzettsegListaN(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>) {
return (n: number): Kepzettseg[] => {
if (karakter.kepzettsegek.length > n){
return [Kepzettsegek[karakter.kepzettsegek[n]], ...GetAvailableKepzettsegek(karakter)]
}
else {
return GetAvailableKepzettsegek(karakter);
}
}
}
export function GetKepzettsegListaN(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>) {
const osztalyok = new Set(karakter.szintlepesek.map(x => x.osztaly))
let availableKepzettsegList = AvailableKezpettsegListFajjal(karakter.faj, ...osztalyok)
export function GetTolvajKepzettsegListaN(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>) {
return (n: number): Kepzettseg[] => {
let available = [...availableKepzettsegList]
// if (n === 0) {
// if (karakter.faj === Faj2E.Eszaki) {
// return [Kepzettsegek.k_hajozas]
// }
// if (karakter.faj === Faj2E.Nomad) {
// return [Kepzettsegek.k_lovaglas]
// }
// // TODO birodalmi tolvaj, tolvajképzettségek!
// if (karakter.faj === Faj2E.Birodalmi) {
// return [Kepzettsegek.k_alkimia, Kepzettsegek.k_meregkeveres, Kepzettsegek.k_okkultizmus]
// }
// if (karakter.faj === Faj2E.Torpe) {
// return [Kepzettsegek.k_ertekbecsles]
// }
// if (karakter.faj === Faj2E.Elf || karakter.faj === Faj2E.Felelf) {
// return [Kepzettsegek.k_vadonjaras]
// }
// if (osztalyok.has(Osztaly2E.Druida) || osztalyok.has(Osztaly2E.Vandor)) {
// return [Kepzettsegek.k_vadonjaras]
// }
// if (osztalyok.has(Osztaly2E.Dalnok)) {
// return [Kepzettsegek.k_eloadas]
// }
// }
// if (n === 1) {
// if ((osztalyok.has(Osztaly2E.Vandor) || osztalyok.has(Osztaly2E.Druida))
// && karakter.kepzettsegek[0] !== Kepzettsegek.k_vadonjaras.Id) {
// return [Kepzettsegek.k_vadonjaras]
// }
// if (osztalyok.has(Osztaly2E.Dalnok)
// && karakter.kepzettsegek[0] !== Kepzettsegek.k_eloadas.Id) {
// return [Kepzettsegek.k_eloadas]
// }
// }
// if (n === 2) { // maybe write a better abstraction?
// if (osztalyok.has(Osztaly2E.Dalnok)
// && karakter.kepzettsegek[0] !== Kepzettsegek.k_eloadas.Id
// && karakter.kepzettsegek[1] !== Kepzettsegek.k_eloadas.Id) {
// return [Kepzettsegek.k_eloadas]
// }
// }
const kepzettsegekWithoutN = [...karakter.kepzettsegek.slice(0, n), ...karakter.kepzettsegek.slice(n + 1)]
return available.filter(x => !kepzettsegekWithoutN.includes(x.Id) && !karakter.tolvajKepzettsegek?.includes(x.Id))
if (karakter.tolvajKepzettsegek != null && karakter.tolvajKepzettsegek.length > n){
return [Kepzettsegek[karakter.tolvajKepzettsegek[n]], ...GetAvailableKepzettsegek(karakter)]
}
else {
return GetAvailableKepzettsegek(karakter);
}
}
}
export function AdjustKepzettsegek(karakter: Pick<Karakter2E, 'faj' | 'tulajdonsagok' | 'szintlepesek' | 'kepzettsegek' | 'tolvajKepzettsegek'>): KepzettsegId[] {
const tulajdonsagokFajjal = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
const numberOfKepzettsegek = GetNumberOfKepzettsegek(tulajdonsagokFajjal.t_int, karakter.faj)
const tul = TulajdonsagokTotal(karakter)
const numberOfKepzettsegek = GetNumberOfKepzettsegek(tul.t_int, karakter.faj)
const diff = numberOfKepzettsegek - karakter.kepzettsegek.length
if (diff > 0) {
const kepzettsegek = [...karakter.kepzettsegek]
for (let i = 0; i < diff; i++) {
const next = GetKepzettsegAtN({
const next = GetAvailableKepzettsegek({
...karakter,
kepzettsegek,
}, kepzettsegek.length + 1)!.Id;
})[0].Id;
kepzettsegek.push(next)
}
return kepzettsegek;
} else {
}
else if (diff === 0) {
return karakter.kepzettsegek
}
else {
return karakter.kepzettsegek.slice(0, numberOfKepzettsegek);
}
}
@@ -2,7 +2,7 @@ import {ElsodlegesMento, MasodlagosMento, MentokTotal, MultiClassMentokAlap} fro
import {Osztaly2E} from "./osztaly2E";
import {Szintlepes} from "./szintlepes";
describe("mentok", () => {
describe("mentok 2E", () => {
test.each([
[1, 2],
[2, 3],
@@ -1,5 +1,5 @@
import {Tulajdonsag2E, TulajdonsagIDs, TulajdonsagokTotal} from "./tulajdonsag2E";
import {KepzettsegId} from "./kepzettsegek2E";
import {GetAvailableKepzettsegek, KepzettsegId} from "./kepzettsegek2E";
import {Osztaly2E} from "./osztaly2E";
import {Karakter2E} from "./karakter2E";
import {BaseHP} from "./masodlagos_ertekek";
@@ -23,15 +23,15 @@ export function PickableSpecializationFilter(existingSpecilizations: (string | u
}
export function LevelUp(karakter: Karakter2E, changeKarakter: (input: Karakter2E) => void) {
const osztaly = karakter.szintlepesek[0].osztaly
const autoPickedOsztaly = karakter.szintlepesek[karakter.szintlepesek.length - 1].osztaly
const tulajdonsagokTotal = TulajdonsagokTotal(karakter)
const szint = karakter.szint + 1
const dice = BaseHP(osztaly)
const dice = BaseHP(autoPickedOsztaly)
const roll = dAny(dice)
console.log(`Level ${szint} HP roll on d${dice} is: ${roll}`)
const szintlepes: Szintlepes = {
osztaly: osztaly,
osztaly: autoPickedOsztaly,
HProll: roll
}
@@ -43,16 +43,19 @@ export function LevelUp(karakter: Karakter2E, changeKarakter: (input: Karakter2E
}
}
}
if(osztaly === Osztaly2E.Harcos) {
const harcosSzint = karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Harcos).length + 1
if (autoPickedOsztaly === Osztaly2E.Harcos){
const harcosSzint = 1 + karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Harcos).length
if (harcosSzint % 2 === 1) {
const harcosSpecializaciok = karakter.szintlepesek.map(x => x.harcosFegyver)
let specializationFilter = PickableSpecializationFilter(harcosSpecializaciok, harcosSzint)
szintlepes.harcosFegyver = AllowedFegyver(Osztaly2E.Harcos).filter(specializationFilter)[0].Id
}
}
if(osztaly === Osztaly2E.Tengeresz) {
const kalozSzint = karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Tengeresz).length + 1
if(autoPickedOsztaly === Osztaly2E.Tengeresz)
{
const kalozSzint = 1 + karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Tengeresz).length
if (kalozSzint % 3 === 0) {
let kalozKritikus = karakter.szintlepesek.map(x => x.kalozKritikus)
let specializationFilter = PickableSpecializationFilter(kalozKritikus, kalozSzint)
@@ -60,6 +63,14 @@ 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)
szintlepes.tolvajExtraKepzettseg = availableKepzettsegek[0].Id;
}
}
changeKarakter({...karakter, szint, szintlepesek: [...karakter.szintlepesek, szintlepes]})
}