Compare commits

..

1 Commits

Author SHA1 Message Date
morbalint 532a9651b9 explore the concept 2024-01-25 19:29:04 +01:00
78 changed files with 683 additions and 3340 deletions
+11 -101
View File
@@ -9,14 +9,16 @@ on:
jobs:
ci-fe:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Setup Node.js 18.x
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18.x
- name: Cache NPM packages
uses: actions/cache@v4
uses: actions/cache@v3
with:
key: npm-${{ hashFiles('./Kemkas.Web/frontend/yarn.lock') }}
path: |
@@ -38,7 +40,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- uses: docker/setup-buildx-action@v3
- name: Install doctl
uses: digitalocean/action-doctl@v2
@@ -66,93 +68,6 @@ jobs:
docker push registry.digitalocean.com/kemkas/kemkas:${GITHUB_SHA::8}
docker push ghcr.io/${{ github.repository_owner }}/kemkas:${GITHUB_SHA::8}
docker-fe-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DO_ACCESS_TOKEN }}
- name: Log in to DigitalOcean Container Registry with short-lived credentials
run: doctl registry login --expiry-seconds 1200
- name: Log in to GitHub Container Registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- uses: docker/build-push-action@v5
with:
context: ./Kemkas.Web/frontend/
file: ./Kemkas.Web/frontend/Dockerfile
cache-from: type=gha
cache-to: type=gha,mode=max
push: false
load: true
tags: kemkas/kemkas-fe:edge
- name: Tag container image
run: |
docker tag kemkas/kemkas-fe:edge registry.digitalocean.com/kemkas/kemkas-fe:${GITHUB_SHA::8}
docker tag kemkas/kemkas-fe:edge ghcr.io/${{ github.repository_owner }}/kemkas-fe:${GITHUB_SHA::8}
- name: Push image to Container Registry
run: |
docker push registry.digitalocean.com/kemkas/kemkas-fe:${GITHUB_SHA::8}
docker push ghcr.io/${{ github.repository_owner }}/kemkas-fe:${GITHUB_SHA::8}
docker-be-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DO_ACCESS_TOKEN }}
- name: Log in to DigitalOcean Container Registry with short-lived credentials
run: doctl registry login --expiry-seconds 1200
- name: Log in to GitHub Container Registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- uses: docker/build-push-action@v5
with:
context: .
file: Kemkas.Web/Backend.Dockerfile
cache-from: type=gha
cache-to: type=gha,mode=max
push: false
load: true
tags: kemkas/kemkas-be:edge
- name: Tag container image
run: |
docker tag kemkas/kemkas-be:edge registry.digitalocean.com/kemkas/kemkas-be:${GITHUB_SHA::8}
docker tag kemkas/kemkas-be:edge ghcr.io/${{ github.repository_owner }}/kemkas-be:${GITHUB_SHA::8}
- name: Push image to Container Registry
run: |
docker push registry.digitalocean.com/kemkas/kemkas-be:${GITHUB_SHA::8}
docker push ghcr.io/${{ github.repository_owner }}/kemkas-be:${GITHUB_SHA::8}
docker-composit-build:
runs-on: ubuntu-latest
needs:
- docker-be-build
- docker-fe-build
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- uses: docker/build-push-action@v5
with:
context: .
file: Kemkas.Web/Composite.Dockerfile
args: FE_TAG=${GITHUB_SHA::8},BE_TAG=${GITHUB_SHA::8}
cache-from: type=gha
cache-to: type=gha,mode=max
push: false
load: true
tags: ghcr.io/${{ github.repository_owner }}/kemkas/kemkas-composite:${GITHUB_SHA::8}
deploy:
runs-on: ubuntu-latest
needs:
@@ -160,7 +75,7 @@ jobs:
- docker-build
if: ${{ github.event_name == 'push' || ( github.event_name == 'pull_request' && github.event.action == 'closed' && github.event.pull_request.merged ) }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
- name: Install doctl
uses: digitalocean/action-doctl@v2
with:
@@ -185,13 +100,8 @@ jobs:
export DOCKER_IMAGE_ID=$(docker images ghcr.io/${{ github.repository_owner }}/kemkas:${GITHUB_SHA::8} --format "{{.ID}}")
export DOCKER_IMAGE_ID=GHCR-$DOCKER_IMAGE_ID
echo "DOCKER_IMAGE_ID=$DOCKER_IMAGE_ID" >> $GITHUB_ENV
- name: Tag commit with docker image ID
uses: actions/github-script@v5
- name: Tag commit
uses: tvdias/github-tagger@v0.0.1
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: "refs/tags/${{ env.DOCKER_IMAGE_ID }}",
sha: context.sha
})
repo-token: "${{ github.token }}"
tag: "${{ env.DOCKER_IMAGE_ID }}"
-20
View File
@@ -1,20 +0,0 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY ["Kemkas.Web/Kemkas.Web.csproj", "Kemkas.Web/"]
RUN dotnet restore "Kemkas.Web/Kemkas.Web.csproj"
COPY . .
WORKDIR "/src/Kemkas.Web"
RUN dotnet build "Kemkas.Web.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "Kemkas.Web.csproj" -c Release -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Kemkas.Web.dll"]
-15
View File
@@ -1,15 +0,0 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
ARG FE_TAG=latest
ARG BE_TAG=latest
FROM ghcr.io/morbalint/kemkas-fe:${FE_TAG} as frontend
FROM ghcr.io/morbalint/kemkas-be:${BE_TAG} as backend
FROM base AS final
COPY --from=backend /app .
COPY --from=frontend /usr/share/nginx/html ./wwwroot
ENTRYPOINT ["dotnet", "Kemkas.Web.dll"]
@@ -1,90 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Kemkas.Web.Db.Models;
using Kemkas.Web.Services.FirstEdition.Character;
using Kemkas.Web.Services.Shared;
using Kemkas.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace Kemkas.Web.Controllers;
/// <summary>
/// First edition character endpoints
/// </summary>
/// <param name="validationService"></param>
/// <param name="dtoToDbModelService"></param>
/// <param name="dbModelToDto1EService"></param>
/// <param name="persistenceService"></param>
[ApiController]
[Route("[controller]")]
public class Character1EController(
ICharacterValidationService validationService,
ICharacter1EDtoToDbModelService dtoToDbModelService,
ICharacterDbModelToDto1EService dbModelToDto1EService,
ICharacterPersistenceService persistenceService)
: ControllerBase
{
[HttpPost]
public async Task<ActionResult<Guid>> StoreNewCharacter([FromBody] Character1eDto dto, [FromQuery]bool isPublic = true)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var errors = validationService.Validate(dto);
if (errors != null)
{
return BadRequest(errors);
}
V1Karakter model;
try
{
model = dtoToDbModelService.Convert(dto);
}
catch (ValidationException ex)
{
return BadRequest(ex.Message);
}
var id = await persistenceService.StoreNewCharacter1E(model, isPublic);
return id;
}
[HttpGet("{id:guid}")]
public async Task<ActionResult<Character1eDto>> GetCharacterById([FromRoute] Guid id)
{
var entity = await persistenceService.GetCharacter1EById(id);
if (entity is null)
{
return NotFound();
}
return dbModelToDto1EService.Convert(entity);
}
[HttpPost("{id:guid}")]
public async Task<ActionResult<Guid>> UpdateCharacter([FromRoute] Guid id, [FromBody] Character1eDto dto, [FromQuery]bool isPublic = true)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var errors = validationService.Validate(dto);
if (errors != null)
{
return BadRequest(errors);
}
var original = await persistenceService.GetCharacter1EById(id, tracking: true);
if (original is null)
{
return NotFound();
}
dtoToDbModelService.Update(original, dto);
await persistenceService.UpdateCharacter1E(original, isPublic);
return id;
}
}
@@ -1,89 +0,0 @@
using System.ComponentModel.DataAnnotations;
using Kemkas.Web.Db.Models;
using Kemkas.Web.Services.SecondEdition.Character;
using Kemkas.Web.Services.Shared;
using Kemkas.Web.ViewModels;
using Microsoft.AspNetCore.Mvc;
namespace Kemkas.Web.Controllers;
[ApiController]
[Route("[controller]")]
public class Character2EController(
ICharacter2EDtoToDbModelService dtoToDbModelService,
ICharacterPersistenceService persistenceService,
ICharacterDbModelToDto2EService dbModelToDtoService
) : ControllerBase
{
[HttpPost]
public async Task<ActionResult<Guid>> StoreNewCharacter([FromBody] Character2eDto dto, [FromQuery]bool isPublic = true)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// var errors = validationService.Validate(dto);
// if (errors != null)
// {
// return BadRequest(errors);
// }
V2Karakter model;
try
{
model = dtoToDbModelService.Convert(dto);
}
catch (ValidationException ex)
{
return BadRequest(ex.Message);
}
var id = await persistenceService.StoreNewCharacter2E(model, isPublic);
return id;
}
[HttpGet("{id:guid}")]
public async Task<ActionResult<Character2eDto>> GetCharacterById([FromRoute] Guid id)
{
var entity = await persistenceService.GetCharacter2EById(id);
if (entity is null)
{
return NotFound();
}
return dbModelToDtoService.Convert(entity);
}
[HttpPost("{id:guid}")]
public async Task<ActionResult<Guid>> UpdateCharacter([FromRoute] Guid id, [FromBody] Character2eDto dto, [FromQuery]bool isPublic = true)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
// var errors = validationService.Validate(dto);
// if (errors != null)
// {
// return BadRequest(errors);
// }
var original = await persistenceService.GetCharacter2EById(id, tracking: true);
if (original is null)
{
return NotFound();
}
try
{
dtoToDbModelService.Update(original, dto);
}
catch (ValidationException ex)
{
return BadRequest(ex.Message);
}
await persistenceService.UpdateCharacter2E(original, isPublic);
return id;
}
}
+73 -7
View File
@@ -1,19 +1,85 @@
using Kemkas.Web.Services.FirstEdition.Character;
using Kemkas.Web.Services.Shared;
using System.ComponentModel.DataAnnotations;
using Kemkas.Web.Db.Models;
using Kemkas.Web.Services.Character;
using Kemkas.Web.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Kemkas.Web.Controllers;
/// <summary>
/// Shared first and second edition character endpoints
/// </summary>
/// <param name="persistenceService"></param>
[ApiController]
[Route("[controller]")]
public class CharacterController(ICharacterPersistenceService persistenceService) : ControllerBase
public class CharacterController(
ICharacterValidationService validationService,
ICharacterDtoToDbModelService dtoToDbModelService,
ICharacterDbModelToDtoService dbModelToDtoService,
ICharacterPersistenceService persistenceService)
: ControllerBase
{
[HttpPost]
public async Task<ActionResult<Guid>> StoreNewCharacter([FromBody] CharacterDto dto, [FromQuery]bool isPublic = true)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var errors = validationService.Validate(dto);
if (errors != null)
{
return BadRequest(errors);
}
V1Karakter model;
try
{
model = dtoToDbModelService.Convert(dto);
}
catch (ValidationException ex)
{
return BadRequest(ex.Message);
}
var id = await persistenceService.StoreNewCharacter(model, isPublic);
return id;
}
[HttpGet("{id:guid}")]
public async Task<ActionResult<CharacterDto>> GetCharacterById([FromRoute] Guid id)
{
var entity = await persistenceService.GetCharacterById(id);
if (entity is null)
{
return NotFound();
}
return dbModelToDtoService.Convert(entity);
}
[HttpPost("{id:guid}")]
public async Task<ActionResult<Guid>> UpdateCharacter([FromRoute] Guid id, [FromBody] CharacterDto dto, [FromQuery]bool isPublic = true)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var errors = validationService.Validate(dto);
if (errors != null)
{
return BadRequest(errors);
}
var original = await persistenceService.GetCharacterById(id, tracking: true);
if (original is null)
{
return NotFound();
}
dtoToDbModelService.Update(original, dto);
await persistenceService.UpdateCharacter(original, isPublic);
return id;
}
[HttpGet]
[Authorize]
public async Task<List<CharacterListItemDto>> GetAllCharacters()
@@ -0,0 +1,35 @@
using Kemkas.Web.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Kemkas.Web.Controllers;
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
return Enumerable.Range(1, 5).Select(
index => new WeatherForecast
{
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
-11
View File
@@ -13,8 +13,6 @@ public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Applicati
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
// 1st edition character
public DbSet<V1Karakter> Karakterek { get; set; }
public DbSet<V1KarakterKepzettseg> KarakterKepzettsegek { get; set; }
@@ -23,13 +21,4 @@ public class ApplicationDbContext : IdentityDbContext<ApplicationUser, Applicati
public DbSet<V1Felszereles> Felszerelesek { get; set; }
// 2nd edition character
public DbSet<V2Karakter> Karakterek2E { get; set; }
public DbSet<V2KarakterKepzettseg> KarakterKepzettsegek2E { get; set; }
public DbSet<V2Szintlepes> Szintlepesek2E { get; set; }
public DbSet<V2Felszereles> Felszerelesek2E { get; set; }
}
+1 -18
View File
@@ -1,6 +1,6 @@
namespace Kemkas.Web.Db.Enums;
public enum Faj1E
public enum Faj
{
Ember = 0,
Amazon = 1,
@@ -15,20 +15,3 @@ public enum Faj1E
Gnom = 10,
Torpe = 11,
}
public enum Faj2E
{
Ember = 0,
Amazon = 1,
Birodalmi = 2,
Nomad = 3,
Eszaki = 4,
Osember = 5,
Elf = 6,
Felelf = 7,
Felork = 8,
Felszerzet = 9,
Gnom = 10,
Torpe = 11,
}
+26 -66
View File
@@ -2,82 +2,42 @@ namespace Kemkas.Web.Db.Enums;
public static class FajExtensions
{
public static Faj1E Convert1E(string faj)
public static Faj Convert(string faj)
{
return faj switch
{
"f_ember" => Faj1E.Ember,
"f_amazon" => Faj1E.Amazon,
"f_birodalmi" => Faj1E.Birodalmi,
"f_etuniai" => Faj1E.Etuniai,
"f_eszaki" => Faj1E.Eszaki,
"f_osember" => Faj1E.Osember,
"f_elf" => Faj1E.Elf,
"f_felelf" => Faj1E.Felelf,
"f_felork" => Faj1E.Felork,
"f_felszerzet" => Faj1E.Felszerzet,
"f_gnom" => Faj1E.Gnom,
"f_torpe" => Faj1E.Torpe,
"f_ember" => Faj.Ember,
"f_amazon" => Faj.Amazon,
"f_birodalmi" => Faj.Birodalmi,
"f_etuniai" => Faj.Etuniai,
"f_eszaki" => Faj.Eszaki,
"f_osember" => Faj.Osember,
"f_elf" => Faj.Elf,
"f_felelf" => Faj.Felelf,
"f_felork" => Faj.Felork,
"f_felszerzet" => Faj.Felszerzet,
"f_gnom" => Faj.Gnom,
"f_torpe" => Faj.Torpe,
_ => throw new Exception("invalid faj: " + faj)
};
}
public static Faj2E Convert2E(string faj)
public static string Convert(this Faj faj)
{
return faj switch
{
"f_2e_ember" => Faj2E.Ember,
"f_2e_amazon" => Faj2E.Amazon,
"f_2e_birodalmi" => Faj2E.Birodalmi,
"f_2e_nomad" => Faj2E.Nomad,
"f_2e_eszaki" => Faj2E.Eszaki,
"f_2e_osember" => Faj2E.Osember,
"f_2e_elf" => Faj2E.Elf,
"f_2e_felelf" => Faj2E.Felelf,
"f_2e_felork" => Faj2E.Felork,
"f_2e_felszerzet" => Faj2E.Felszerzet,
"f_2e_gnom" => Faj2E.Gnom,
"f_2e_torpe" => Faj2E.Torpe,
_ => throw new Exception("invalid faj: " + faj)
};
}
public static string Convert(this Faj1E faj)
{
return faj switch
{
Faj1E.Ember => "f_ember",
Faj1E.Amazon => "f_amazon",
Faj1E.Birodalmi => "f_birodalmi",
Faj1E.Etuniai => "f_etuniai",
Faj1E.Eszaki => "f_eszaki",
Faj1E.Osember => "f_osember",
Faj1E.Elf => "f_elf",
Faj1E.Felelf => "f_felelf",
Faj1E.Felork => "f_felork",
Faj1E.Felszerzet => "f_felszerzet",
Faj1E.Gnom => "f_gnom",
Faj1E.Torpe => "f_torpe",
_ => throw new Exception("invalid faj: " + faj)
};
}
public static string Convert(this Faj2E faj)
{
return faj switch
{
Faj2E.Ember => "f_2e_ember",
Faj2E.Amazon => "f_2e_amazon",
Faj2E.Birodalmi => "f_2e_birodalmi",
Faj2E.Nomad => "f_2e_nomad",
Faj2E.Eszaki => "f_2e_eszaki",
Faj2E.Osember => "f_2e_osember",
Faj2E.Elf => "f_2e_elf",
Faj2E.Felelf => "f_2e_felelf",
Faj2E.Felork => "f_2e_felork",
Faj2E.Felszerzet => "f_2e_felszerzet",
Faj2E.Gnom => "f_2e_gnom",
Faj2E.Torpe => "f_2e_torpe",
Faj.Ember => "f_ember",
Faj.Amazon => "f_amazon",
Faj.Birodalmi => "f_birodalmi",
Faj.Etuniai => "f_etuniai",
Faj.Eszaki => "f_eszaki",
Faj.Osember => "f_osember",
Faj.Elf => "f_elf",
Faj.Felelf => "f_felelf",
Faj.Felork => "f_felork",
Faj.Felszerzet => "f_felszerzet",
Faj.Gnom => "f_gnom",
Faj.Torpe => "f_torpe",
_ => throw new Exception("invalid faj: " + faj)
};
}
+1 -37
View File
@@ -1,6 +1,6 @@
namespace Kemkas.Web.Db.Enums;
public enum Kepzettseg1E
public enum Kepzettseg
{
Alkimia = 1,
Alcazas = 2,
@@ -32,39 +32,3 @@ public enum Kepzettseg1E
Zarnyitas = 28,
Zsebmetszes = 29,
}
// offset by 200 to make it more different from 1e karakter kepzettsegek
// I don't plan to mix them, but let's make it obvious which one is which.
// But it could be useful in one-time character conversions in the future.
public enum Kepzettseg2E
{
Alkimia = 201,
Alcazas = 202,
Allatidomitas = 203,
Csapdak = 204,
Csillagjoslas = 205,
Egyensulyozas = 206,
Eloadas = 207,
Ertekbecsles = 208,
Gyogyitas = 209,
Hajozas = 210,
Hallgatozas = 211,
Hamisitas = 212,
JelekOlvasasa = 213,
Herbalizmus = 601,
Historia = 602,
Lovaglas = 215,
Maszas = 216,
Megfigyeles = 217,
Meregkeveres = 218,
Mesterseg = 219,
Nyomkereses = 220,
Okkultizmus = 666, // inside joke
Osonas = 221,
Szabadulomuveszet = 223,
Ugras = 225,
Uszas = 226,
Vadonjaras = 603,
Zarnyitas = 228,
Zsebmetszes = 229,
}
+60 -134
View File
@@ -4,150 +4,76 @@ namespace Kemkas.Web.Db.Enums;
public static class KepzettsegExtensions
{
public static Kepzettseg1E Convert1E(string kepzettseg)
public static Kepzettseg Convert(string kepzettseg)
{
return kepzettseg switch
{
"k_alkimia" => Kepzettseg1E.Alkimia,
"k_alcazas" => Kepzettseg1E.Alcazas,
"k_allatidomitas" => Kepzettseg1E.Allatidomitas,
"k_csapdak" => Kepzettseg1E.Csapdak,
"k_csillagjoslas" => Kepzettseg1E.Csillagjoslas,
"k_egyensulyozas" => Kepzettseg1E.Egyensulyozas,
"k_eloadas" => Kepzettseg1E.Eloadas,
"k_ertekbecsles" => Kepzettseg1E.Ertekbecsles,
"k_gyogyitas" => Kepzettseg1E.Gyogyitas,
"k_hajozas" => Kepzettseg1E.Hajozas,
"k_hallgatozas" => Kepzettseg1E.Hallgatozas,
"k_hamisitas" => Kepzettseg1E.Hamisitas,
"k_jelek_olvasasa" => Kepzettseg1E.JelekOlvasasa,
"k_koncentracio" => Kepzettseg1E.Koncentracio,
"k_lovaglas" => Kepzettseg1E.Lovaglas,
"k_maszas" => Kepzettseg1E.Maszas,
"k_megfigyeles" => Kepzettseg1E.Megfigyeles,
"k_meregkeveres" => Kepzettseg1E.Meregkeveres,
"k_mesterseg" => Kepzettseg1E.Mesterseg,
"k_nyomkereses" => Kepzettseg1E.Nyomkereses,
"k_osonas" => Kepzettseg1E.Osonas,
"k_rejtozes" => Kepzettseg1E.Rejtozes,
"k_szabadulomuveszet" => Kepzettseg1E.Szabadulomuveszet,
"k_tudas" => Kepzettseg1E.Tudas,
"k_ugras" => Kepzettseg1E.Ugras,
"k_uszas" => Kepzettseg1E.Uszas,
"k_varazslatismeret" => Kepzettseg1E.Varazslatismeret,
"k_zarnyitas" => Kepzettseg1E.Zarnyitas,
"k_zsebmetszes" => Kepzettseg1E.Zsebmetszes,
"k_alkimia" => Kepzettseg.Alkimia,
"k_alcazas" => Kepzettseg.Alcazas,
"k_allatidomitas" => Kepzettseg.Allatidomitas,
"k_csapdak" => Kepzettseg.Csapdak,
"k_csillagjoslas" => Kepzettseg.Csillagjoslas,
"k_egyensulyozas" => Kepzettseg.Egyensulyozas,
"k_eloadas" => Kepzettseg.Eloadas,
"k_ertekbecsles" => Kepzettseg.Ertekbecsles,
"k_gyogyitas" => Kepzettseg.Gyogyitas,
"k_hajozas" => Kepzettseg.Hajozas,
"k_hallgatozas" => Kepzettseg.Hallgatozas,
"k_hamisitas" => Kepzettseg.Hamisitas,
"k_jelek_olvasasa" => Kepzettseg.JelekOlvasasa,
"k_koncentracio" => Kepzettseg.Koncentracio,
"k_lovaglas" => Kepzettseg.Lovaglas,
"k_maszas" => Kepzettseg.Maszas,
"k_megfigyeles" => Kepzettseg.Megfigyeles,
"k_meregkeveres" => Kepzettseg.Meregkeveres,
"k_mesterseg" => Kepzettseg.Mesterseg,
"k_nyomkereses" => Kepzettseg.Nyomkereses,
"k_osonas" => Kepzettseg.Osonas,
"k_rejtozes" => Kepzettseg.Rejtozes,
"k_szabadulomuveszet" => Kepzettseg.Szabadulomuveszet,
"k_tudas" => Kepzettseg.Tudas,
"k_ugras" => Kepzettseg.Ugras,
"k_uszas" => Kepzettseg.Uszas,
"k_varazslatismeret" => Kepzettseg.Varazslatismeret,
"k_zarnyitas" => Kepzettseg.Zarnyitas,
"k_zsebmetszes" => Kepzettseg.Zsebmetszes,
_ => throw new ValidationException("invalid kepzettseg: " + kepzettseg),
};
}
public static Kepzettseg2E Convert2E(string kepzettseg)
public static string Convert(this Kepzettseg kepzettseg)
{
return kepzettseg switch
{
"k_alkimia" => Kepzettseg2E.Alkimia,
"k_alcazas" => Kepzettseg2E.Alcazas,
"k_allatidomitas" => Kepzettseg2E.Allatidomitas,
"k_csapdak" => Kepzettseg2E.Csapdak,
"k_csillagjoslas" => Kepzettseg2E.Csillagjoslas,
"k_egyensulyozas" => Kepzettseg2E.Egyensulyozas,
"k_eloadas" => Kepzettseg2E.Eloadas,
"k_ertekbecsles" => Kepzettseg2E.Ertekbecsles,
"k_gyogyitas" => Kepzettseg2E.Gyogyitas,
"k_hajozas" => Kepzettseg2E.Hajozas,
"k_hallgatozas" => Kepzettseg2E.Hallgatozas,
"k_hamisitas" => Kepzettseg2E.Hamisitas,
"k_herbalizmus" => Kepzettseg2E.Herbalizmus,
"k_historia" => Kepzettseg2E.Historia,
"k_jelek_olvasasa" => Kepzettseg2E.JelekOlvasasa,
"k_lovaglas" => Kepzettseg2E.Lovaglas,
"k_maszas" => Kepzettseg2E.Maszas,
"k_megfigyeles" => Kepzettseg2E.Megfigyeles,
"k_meregkeveres" => Kepzettseg2E.Meregkeveres,
"k_mesterseg" => Kepzettseg2E.Mesterseg,
"k_nyomkereses" => Kepzettseg2E.Nyomkereses,
"k_okkultizmus" => Kepzettseg2E.Okkultizmus,
"k_osonas" => Kepzettseg2E.Osonas,
"k_szabadulomuveszet" => Kepzettseg2E.Szabadulomuveszet,
"k_ugras" => Kepzettseg2E.Ugras,
"k_uszas" => Kepzettseg2E.Uszas,
"k_vadonjaras" => Kepzettseg2E.Vadonjaras,
"k_zarnyitas" => Kepzettseg2E.Zarnyitas,
"k_zsebmetszes" => Kepzettseg2E.Zsebmetszes,
_ => throw new ValidationException("invalid kepzettseg: " + kepzettseg),
};
}
public static string Convert(this Kepzettseg1E kepzettseg)
{
return kepzettseg switch
{
Kepzettseg1E.Alkimia => "k_alkimia",
Kepzettseg1E.Alcazas => "k_alcazas",
Kepzettseg1E.Allatidomitas => "k_allatidomitas",
Kepzettseg1E.Csapdak => "k_csapdak",
Kepzettseg1E.Csillagjoslas => "k_csillagjoslas",
Kepzettseg1E.Egyensulyozas => "k_egyensulyozas",
Kepzettseg1E.Eloadas => "k_eloadas",
Kepzettseg1E.Ertekbecsles => "k_ertekbecsles",
Kepzettseg1E.Gyogyitas => "k_gyogyitas",
Kepzettseg1E.Hajozas => "k_hajozas",
Kepzettseg1E.Hallgatozas => "k_hallgatozas",
Kepzettseg1E.Hamisitas => "k_hamisitas",
Kepzettseg1E.JelekOlvasasa => "k_jelek_olvasasa",
Kepzettseg1E.Koncentracio => "k_koncentracio",
Kepzettseg1E.Lovaglas => "k_lovaglas",
Kepzettseg1E.Maszas => "k_maszas",
Kepzettseg1E.Megfigyeles => "k_megfigyeles",
Kepzettseg1E.Meregkeveres => "k_meregkeveres",
Kepzettseg1E.Mesterseg => "k_mesterseg",
Kepzettseg1E.Nyomkereses => "k_nyomkereses",
Kepzettseg1E.Osonas => "k_osonas",
Kepzettseg1E.Rejtozes => "k_rejtozes",
Kepzettseg1E.Szabadulomuveszet => "k_szabadulomuveszet",
Kepzettseg1E.Tudas => "k_tudas",
Kepzettseg1E.Ugras => "k_ugras",
Kepzettseg1E.Uszas => "k_uszas",
Kepzettseg1E.Varazslatismeret => "k_varazslatismeret",
Kepzettseg1E.Zarnyitas => "k_zarnyitas",
Kepzettseg1E.Zsebmetszes => "k_zsebmetszes",
_ => throw new ValidationException("invalid kepzettseg: " + kepzettseg),
};
}
public static string Convert(this Kepzettseg2E kepzettseg)
{
return kepzettseg switch
{
Kepzettseg2E.Alkimia => "k_alkimia",
Kepzettseg2E.Alcazas => "k_alcazas",
Kepzettseg2E.Allatidomitas => "k_allatidomitas",
Kepzettseg2E.Csapdak => "k_csapdak",
Kepzettseg2E.Csillagjoslas => "k_csillagjoslas",
Kepzettseg2E.Egyensulyozas => "k_egyensulyozas",
Kepzettseg2E.Eloadas => "k_eloadas",
Kepzettseg2E.Ertekbecsles => "k_ertekbecsles",
Kepzettseg2E.Gyogyitas => "k_gyogyitas",
Kepzettseg2E.Hajozas => "k_hajozas",
Kepzettseg2E.Hallgatozas => "k_hallgatozas",
Kepzettseg2E.Hamisitas => "k_hamisitas",
Kepzettseg2E.Herbalizmus => "k_herbalizmus",
Kepzettseg2E.Historia => "k_historia",
Kepzettseg2E.JelekOlvasasa => "k_jelek_olvasasa",
Kepzettseg2E.Lovaglas => "k_lovaglas",
Kepzettseg2E.Maszas => "k_maszas",
Kepzettseg2E.Megfigyeles => "k_megfigyeles",
Kepzettseg2E.Meregkeveres => "k_meregkeveres",
Kepzettseg2E.Mesterseg => "k_mesterseg",
Kepzettseg2E.Nyomkereses => "k_nyomkereses",
Kepzettseg2E.Okkultizmus => "k_okkultizmus",
Kepzettseg2E.Osonas => "k_osonas",
Kepzettseg2E.Szabadulomuveszet => "k_szabadulomuveszet",
Kepzettseg2E.Ugras => "k_ugras",
Kepzettseg2E.Uszas => "k_uszas",
Kepzettseg2E.Vadonjaras => "k_vadonjaras",
Kepzettseg2E.Zarnyitas => "k_zarnyitas",
Kepzettseg2E.Zsebmetszes => "k_zsebmetszes",
Kepzettseg.Alkimia => "k_alkimia",
Kepzettseg.Alcazas => "k_alcazas",
Kepzettseg.Allatidomitas => "k_allatidomitas",
Kepzettseg.Csapdak => "k_csapdak",
Kepzettseg.Csillagjoslas => "k_csillagjoslas",
Kepzettseg.Egyensulyozas => "k_egyensulyozas",
Kepzettseg.Eloadas => "k_eloadas",
Kepzettseg.Ertekbecsles => "k_ertekbecsles",
Kepzettseg.Gyogyitas => "k_gyogyitas",
Kepzettseg.Hajozas => "k_hajozas",
Kepzettseg.Hallgatozas => "k_hallgatozas",
Kepzettseg.Hamisitas => "k_hamisitas",
Kepzettseg.JelekOlvasasa => "k_jelek_olvasasa",
Kepzettseg.Koncentracio => "k_koncentracio",
Kepzettseg.Lovaglas => "k_lovaglas",
Kepzettseg.Maszas => "k_maszas",
Kepzettseg.Megfigyeles => "k_megfigyeles",
Kepzettseg.Meregkeveres => "k_meregkeveres",
Kepzettseg.Mesterseg => "k_mesterseg",
Kepzettseg.Nyomkereses => "k_nyomkereses",
Kepzettseg.Osonas => "k_osonas",
Kepzettseg.Rejtozes => "k_rejtozes",
Kepzettseg.Szabadulomuveszet => "k_szabadulomuveszet",
Kepzettseg.Tudas => "k_tudas",
Kepzettseg.Ugras => "k_ugras",
Kepzettseg.Uszas => "k_uszas",
Kepzettseg.Varazslatismeret => "k_varazslatismeret",
Kepzettseg.Zarnyitas => "k_zarnyitas",
Kepzettseg.Zsebmetszes => "k_zsebmetszes",
_ => throw new ValidationException("invalid kepzettseg: " + kepzettseg),
};
}
+1 -18
View File
@@ -1,6 +1,6 @@
namespace Kemkas.Web.Db.Enums;
public enum Osztaly1E
public enum Osztaly
{
Error = 0, // for unset enum value mapping
Harcos = 1,
@@ -13,20 +13,3 @@ public enum Osztaly1E
Varazslo = 8,
Illuzionista = 9,
}
public enum Osztaly2E
{
Error = 0, // for unset enum value mapping
Harcos = 1,
Ijasz = 2,
Amazon = 3,
Tengeresz = 4,
Barbar = 5,
Pap = 6,
Tolvaj = 7,
Varazslo = 8,
Illuzionista = 9,
Dalnok = 10,
Druida = 11,
Vandor = 12,
}
+20 -60
View File
@@ -4,76 +4,36 @@ namespace Kemkas.Web.Db.Enums;
public static class OsztalyExtensions
{
public static Osztaly1E Convert1E(string osztaly)
public static Osztaly Convert(string osztaly)
{
return osztaly switch
{
"o_harcos" => Osztaly1E.Harcos,
"o_ijasz" => Osztaly1E.Ijasz,
"o_amazon" => Osztaly1E.Amazon,
"o_kaloz" => Osztaly1E.Kaloz,
"o_barbar" => Osztaly1E.Barbar,
"o_pap" => Osztaly1E.Pap,
"o_tolvaj" => Osztaly1E.Tolvaj,
"o_varazslo" => Osztaly1E.Varazslo,
"o_illuzionista" => Osztaly1E.Illuzionista,
"o_harcos" => Osztaly.Harcos,
"o_ijasz" => Osztaly.Ijasz,
"o_amazon" => Osztaly.Amazon,
"o_kaloz" => Osztaly.Kaloz,
"o_barbar" => Osztaly.Barbar,
"o_pap" => Osztaly.Pap,
"o_tolvaj" => Osztaly.Tolvaj,
"o_varazslo" => Osztaly.Varazslo,
"o_illuzionista" => Osztaly.Illuzionista,
_ => throw new ValidationException("unknown osztaly: " + osztaly)
};
}
public static Osztaly2E Convert2E(string osztaly)
public static string Convert(this Osztaly osztaly)
{
return osztaly switch
{
"o_2e_harcos" => Osztaly2E.Harcos,
"o_2e_ijasz" => Osztaly2E.Ijasz,
"o_2e_amazon" => Osztaly2E.Amazon,
"o_2e_tengeresz" => Osztaly2E.Tengeresz,
"o_2e_barbar" => Osztaly2E.Barbar,
"o_2e_pap" => Osztaly2E.Pap,
"o_2e_tolvaj" => Osztaly2E.Tolvaj,
"o_2e_varazslo" => Osztaly2E.Varazslo,
"o_2e_illuzionista" => Osztaly2E.Illuzionista,
"o_2e_dalnok" => Osztaly2E.Dalnok,
"o_2e_druida" => Osztaly2E.Druida,
"o_2e_vandor" => Osztaly2E.Vandor,
_ => throw new ValidationException("unknown osztaly: " + osztaly)
};
}
public static string Convert(this Osztaly1E osztaly)
{
return osztaly switch
{
Osztaly1E.Harcos => "o_harcos",
Osztaly1E.Ijasz => "o_ijasz",
Osztaly1E.Amazon => "o_amazon",
Osztaly1E.Kaloz => "o_kaloz",
Osztaly1E.Barbar => "o_barbar",
Osztaly1E.Pap => "o_pap",
Osztaly1E.Tolvaj => "o_tolvaj",
Osztaly1E.Varazslo => "o_varazslo",
Osztaly1E.Illuzionista => "o_illuzionista",
_ => throw new ValidationException("invalid osztaly!")
};
}
public static string Convert(this Osztaly2E osztaly)
{
return osztaly switch
{
Osztaly2E.Harcos => "o_2e_harcos",
Osztaly2E.Ijasz => "o_2e_ijasz",
Osztaly2E.Amazon => "o_2e_amazon",
Osztaly2E.Tengeresz => "o_2e_tengeresz",
Osztaly2E.Barbar => "o_2e_barbar",
Osztaly2E.Pap => "o_2e_pap",
Osztaly2E.Tolvaj => "o_2e_tolvaj",
Osztaly2E.Varazslo => "o_2e_varazslo",
Osztaly2E.Illuzionista => "o_2e_illuzionista",
Osztaly2E.Dalnok => "o_2e_dalnok",
Osztaly2E.Druida => "o_2e_druida",
Osztaly2E.Vandor => "o_2e_vandor",
Osztaly.Harcos => "o_harcos",
Osztaly.Ijasz => "o_ijasz",
Osztaly.Amazon => "o_amazon",
Osztaly.Kaloz => "o_kaloz",
Osztaly.Barbar => "o_barbar",
Osztaly.Pap => "o_pap",
Osztaly.Tolvaj => "o_tolvaj",
Osztaly.Varazslo => "o_varazslo",
Osztaly.Illuzionista => "o_illuzionista",
_ => throw new ValidationException("invalid osztaly!")
};
}
@@ -1,690 +0,0 @@
// <auto-generated />
using System;
using Kemkas.Web.Db;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
#nullable disable
namespace Kemkas.Web.Db.Migrations
{
[DbContext(typeof(ApplicationDbContext))]
[Migration("20240214163223_AddSecondEditionModels")]
partial class AddSecondEditionModels
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "8.0.0")
.HasAnnotation("Relational:MaxIdentifierLength", 63);
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Kemkas.Web.Db.Models.ApplicationRole", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("AspNetRoles", (string)null);
});
modelBuilder.Entity("Kemkas.Web.Db.Models.ApplicationUser", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<int>("AccessFailedCount")
.HasColumnType("integer");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text");
b.Property<string>("Email")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<bool>("EmailConfirmed")
.HasColumnType("boolean");
b.Property<bool>("LockoutEnabled")
.HasColumnType("boolean");
b.Property<DateTimeOffset?>("LockoutEnd")
.HasColumnType("timestamp with time zone");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("NormalizedUserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.Property<string>("PasswordHash")
.HasColumnType("text");
b.Property<string>("PhoneNumber")
.HasColumnType("text");
b.Property<bool>("PhoneNumberConfirmed")
.HasColumnType("boolean");
b.Property<string>("SecurityStamp")
.HasColumnType("text");
b.Property<bool>("TwoFactorEnabled")
.HasColumnType("boolean");
b.Property<string>("UserName")
.HasMaxLength(256)
.HasColumnType("character varying(256)");
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasDatabaseName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasDatabaseName("UserNameIndex");
b.ToTable("AspNetUsers", (string)null);
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1Felszereles", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsFegyver")
.HasColumnType("boolean");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("Felszerelesek");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1Karakter", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("Bolcsesseg")
.HasColumnType("smallint");
b.Property<byte>("Egeszseg")
.HasColumnType("smallint");
b.Property<byte>("Ero")
.HasColumnType("smallint");
b.Property<int>("Faj")
.HasColumnType("integer");
b.Property<byte>("Intelligencia")
.HasColumnType("smallint");
b.Property<bool>("IsPublic")
.HasColumnType("boolean");
b.Property<string>("Isten")
.HasColumnType("text");
b.Property<byte>("Jellem")
.HasColumnType("smallint");
b.Property<byte>("Karizma")
.HasColumnType("smallint");
b.Property<double?>("Kor")
.HasColumnType("double precision");
b.Property<string>("Nem")
.HasColumnType("text");
b.Property<string>("Nev")
.IsRequired()
.HasColumnType("text");
b.Property<int>("Osztaly")
.HasColumnType("integer");
b.Property<int?>("OwnerUserId")
.HasColumnType("integer");
b.Property<string>("Pajzs")
.HasColumnType("text");
b.Property<string>("Pancel")
.HasColumnType("text");
b.Property<byte>("Szint")
.HasColumnType("smallint");
b.Property<byte>("Ugyesseg")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("OwnerUserId");
b.ToTable("Karakterek");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1KarakterKepzettseg", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsTolvajKepzettseg")
.HasColumnType("boolean");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<int>("Kepzettseg")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("KarakterKepzettsegek");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1Szintlepes", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("FegyverSpecializacio")
.HasColumnType("text");
b.Property<byte>("HpRoll")
.HasColumnType("smallint");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<byte>("KarakterSzint")
.HasColumnType("smallint");
b.Property<byte?>("TulajdonsagNoveles")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("Szintlepesek");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Felszereles", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsFegyver")
.HasColumnType("boolean");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<string>("TargyId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("Felszerelesek2E");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Karakter", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("Bolcsesseg")
.HasColumnType("smallint");
b.Property<byte>("Egeszseg")
.HasColumnType("smallint");
b.Property<byte>("Ero")
.HasColumnType("smallint");
b.Property<int>("Faj")
.HasColumnType("integer");
b.Property<byte>("Intelligencia")
.HasColumnType("smallint");
b.Property<bool>("IsPublic")
.HasColumnType("boolean");
b.Property<string>("Isten")
.HasColumnType("text");
b.Property<byte>("Jellem")
.HasColumnType("smallint");
b.Property<byte>("Karizma")
.HasColumnType("smallint");
b.Property<double?>("Kor")
.HasColumnType("double precision");
b.Property<string>("Nem")
.HasColumnType("text");
b.Property<string>("Nev")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("OwnerUserId")
.HasColumnType("integer");
b.Property<string>("Pajzs")
.HasColumnType("text");
b.Property<string>("Pancel")
.HasColumnType("text");
b.Property<byte>("Szint")
.HasColumnType("smallint");
b.Property<byte>("Ugyesseg")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("OwnerUserId");
b.ToTable("Karakterek2E");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2KarakterKepzettseg", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsTolvajKepzettseg")
.HasColumnType("boolean");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<int>("Kepzettseg")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("KarakterKepzettsegek2E");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Szintlepes", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("FegyverSpecializacio")
.HasColumnType("text");
b.Property<byte>("HpRoll")
.HasColumnType("smallint");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<byte>("KarakterSzint")
.HasColumnType("smallint");
b.Property<int>("Osztaly")
.HasColumnType("integer");
b.Property<int?>("TolvajExtraKepzettseg")
.HasColumnType("integer");
b.Property<byte?>("TulajdonsagNoveles")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("Szintlepesek2E");
});
modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("FriendlyName")
.HasColumnType("text");
b.Property<string>("Xml")
.HasColumnType("text");
b.HasKey("Id");
b.ToTable("DataProtectionKeys");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text");
b.Property<string>("ClaimValue")
.HasColumnType("text");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ProviderKey")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("ProviderDisplayName")
.HasColumnType("text");
b.Property<int>("UserId")
.HasColumnType("integer");
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer");
b.Property<int>("RoleId")
.HasColumnType("integer");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
{
b.Property<int>("UserId")
.HasColumnType("integer");
b.Property<string>("LoginProvider")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("Name")
.HasMaxLength(128)
.HasColumnType("character varying(128)");
b.Property<string>("Value")
.HasColumnType("text");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens", (string)null);
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1Felszereles", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V1Karakter", "Karakter")
.WithMany("Felszereles")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1Karakter", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationUser", "OwnerUser")
.WithMany()
.HasForeignKey("OwnerUserId");
b.Navigation("OwnerUser");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1KarakterKepzettseg", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V1Karakter", "Karakter")
.WithMany("KarakterKepzettsegek")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1Szintlepes", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V1Karakter", "Karakter")
.WithMany("Szintlepesek")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Felszereles", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V2Karakter", "Karakter")
.WithMany("Felszereles")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Karakter", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationUser", "OwnerUser")
.WithMany()
.HasForeignKey("OwnerUserId");
b.Navigation("OwnerUser");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2KarakterKepzettseg", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V2Karakter", "Karakter")
.WithMany("KarakterKepzettsegek")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Szintlepes", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V2Karakter", "Karakter")
.WithMany("Szintlepesek")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<int>", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<int>", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<int>", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationRole", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Kemkas.Web.Db.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<int>", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationUser", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V1Karakter", b =>
{
b.Navigation("Felszereles");
b.Navigation("KarakterKepzettsegek");
b.Navigation("Szintlepesek");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Karakter", b =>
{
b.Navigation("Felszereles");
b.Navigation("KarakterKepzettsegek");
b.Navigation("Szintlepesek");
});
#pragma warning restore 612, 618
}
}
}
@@ -1,148 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Kemkas.Web.Db.Migrations
{
/// <inheritdoc />
public partial class AddSecondEditionModels : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Karakterek2E",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
IsPublic = table.Column<bool>(type: "boolean", nullable: false),
OwnerUserId = table.Column<int>(type: "integer", nullable: true),
Nev = table.Column<string>(type: "text", nullable: false),
Nem = table.Column<string>(type: "text", nullable: true),
Kor = table.Column<double>(type: "double precision", nullable: true),
Jellem = table.Column<byte>(type: "smallint", nullable: false),
Isten = table.Column<string>(type: "text", nullable: true),
Faj = table.Column<int>(type: "integer", nullable: false),
Ero = table.Column<byte>(type: "smallint", nullable: false),
Ugyesseg = table.Column<byte>(type: "smallint", nullable: false),
Egeszseg = table.Column<byte>(type: "smallint", nullable: false),
Intelligencia = table.Column<byte>(type: "smallint", nullable: false),
Bolcsesseg = table.Column<byte>(type: "smallint", nullable: false),
Karizma = table.Column<byte>(type: "smallint", nullable: false),
Szint = table.Column<byte>(type: "smallint", nullable: false),
Pancel = table.Column<string>(type: "text", nullable: true),
Pajzs = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Karakterek2E", x => x.Id);
table.ForeignKey(
name: "FK_Karakterek2E_AspNetUsers_OwnerUserId",
column: x => x.OwnerUserId,
principalTable: "AspNetUsers",
principalColumn: "Id");
});
migrationBuilder.CreateTable(
name: "Felszerelesek2E",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
KarakterId = table.Column<Guid>(type: "uuid", nullable: false),
TargyId = table.Column<string>(type: "text", nullable: false),
IsFegyver = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Felszerelesek2E", x => x.Id);
table.ForeignKey(
name: "FK_Felszerelesek2E_Karakterek2E_KarakterId",
column: x => x.KarakterId,
principalTable: "Karakterek2E",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "KarakterKepzettsegek2E",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
KarakterId = table.Column<Guid>(type: "uuid", nullable: false),
Kepzettseg = table.Column<int>(type: "integer", nullable: false),
IsTolvajKepzettseg = table.Column<bool>(type: "boolean", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_KarakterKepzettsegek2E", x => x.Id);
table.ForeignKey(
name: "FK_KarakterKepzettsegek2E_Karakterek2E_KarakterId",
column: x => x.KarakterId,
principalTable: "Karakterek2E",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "Szintlepesek2E",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
KarakterId = table.Column<Guid>(type: "uuid", nullable: false),
KarakterSzint = table.Column<byte>(type: "smallint", nullable: false),
Osztaly = table.Column<int>(type: "integer", nullable: false),
HpRoll = table.Column<byte>(type: "smallint", nullable: false),
TulajdonsagNoveles = table.Column<byte>(type: "smallint", nullable: true),
FegyverSpecializacio = table.Column<string>(type: "text", nullable: true),
TolvajExtraKepzettseg = table.Column<int>(type: "integer", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_Szintlepesek2E", x => x.Id);
table.ForeignKey(
name: "FK_Szintlepesek2E_Karakterek2E_KarakterId",
column: x => x.KarakterId,
principalTable: "Karakterek2E",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_Felszerelesek2E_KarakterId",
table: "Felszerelesek2E",
column: "KarakterId");
migrationBuilder.CreateIndex(
name: "IX_Karakterek2E_OwnerUserId",
table: "Karakterek2E",
column: "OwnerUserId");
migrationBuilder.CreateIndex(
name: "IX_KarakterKepzettsegek2E_KarakterId",
table: "KarakterKepzettsegek2E",
column: "KarakterId");
migrationBuilder.CreateIndex(
name: "IX_Szintlepesek2E_KarakterId",
table: "Szintlepesek2E",
column: "KarakterId");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "Felszerelesek2E");
migrationBuilder.DropTable(
name: "KarakterKepzettsegek2E");
migrationBuilder.DropTable(
name: "Szintlepesek2E");
migrationBuilder.DropTable(
name: "Karakterek2E");
}
}
}
@@ -259,150 +259,6 @@ namespace Kemkas.Web.Db.Migrations
b.ToTable("Szintlepesek");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Felszereles", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsFegyver")
.HasColumnType("boolean");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<string>("TargyId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("Felszerelesek2E");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Karakter", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<byte>("Bolcsesseg")
.HasColumnType("smallint");
b.Property<byte>("Egeszseg")
.HasColumnType("smallint");
b.Property<byte>("Ero")
.HasColumnType("smallint");
b.Property<int>("Faj")
.HasColumnType("integer");
b.Property<byte>("Intelligencia")
.HasColumnType("smallint");
b.Property<bool>("IsPublic")
.HasColumnType("boolean");
b.Property<string>("Isten")
.HasColumnType("text");
b.Property<byte>("Jellem")
.HasColumnType("smallint");
b.Property<byte>("Karizma")
.HasColumnType("smallint");
b.Property<double?>("Kor")
.HasColumnType("double precision");
b.Property<string>("Nem")
.HasColumnType("text");
b.Property<string>("Nev")
.IsRequired()
.HasColumnType("text");
b.Property<int?>("OwnerUserId")
.HasColumnType("integer");
b.Property<string>("Pajzs")
.HasColumnType("text");
b.Property<string>("Pancel")
.HasColumnType("text");
b.Property<byte>("Szint")
.HasColumnType("smallint");
b.Property<byte>("Ugyesseg")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("OwnerUserId");
b.ToTable("Karakterek2E");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2KarakterKepzettseg", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<bool>("IsTolvajKepzettseg")
.HasColumnType("boolean");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<int>("Kepzettseg")
.HasColumnType("integer");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("KarakterKepzettsegek2E");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Szintlepes", b =>
{
b.Property<Guid>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("uuid");
b.Property<string>("FegyverSpecializacio")
.HasColumnType("text");
b.Property<byte>("HpRoll")
.HasColumnType("smallint");
b.Property<Guid>("KarakterId")
.HasColumnType("uuid");
b.Property<byte>("KarakterSzint")
.HasColumnType("smallint");
b.Property<int>("Osztaly")
.HasColumnType("integer");
b.Property<int?>("TolvajExtraKepzettseg")
.HasColumnType("integer");
b.Property<byte?>("TulajdonsagNoveles")
.HasColumnType("smallint");
b.HasKey("Id");
b.HasIndex("KarakterId");
b.ToTable("Szintlepesek2E");
});
modelBuilder.Entity("Microsoft.AspNetCore.DataProtection.EntityFrameworkCore.DataProtectionKey", b =>
{
b.Property<int>("Id")
@@ -571,48 +427,6 @@ namespace Kemkas.Web.Db.Migrations
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Felszereles", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V2Karakter", "Karakter")
.WithMany("Felszereles")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Karakter", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationUser", "OwnerUser")
.WithMany()
.HasForeignKey("OwnerUserId");
b.Navigation("OwnerUser");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2KarakterKepzettseg", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V2Karakter", "Karakter")
.WithMany("KarakterKepzettsegek")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Szintlepes", b =>
{
b.HasOne("Kemkas.Web.Db.Models.V2Karakter", "Karakter")
.WithMany("Szintlepesek")
.HasForeignKey("KarakterId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Karakter");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<int>", b =>
{
b.HasOne("Kemkas.Web.Db.Models.ApplicationRole", null)
@@ -672,15 +486,6 @@ namespace Kemkas.Web.Db.Migrations
b.Navigation("Szintlepesek");
});
modelBuilder.Entity("Kemkas.Web.Db.Models.V2Karakter", b =>
{
b.Navigation("Felszereles");
b.Navigation("KarakterKepzettsegek");
b.Navigation("Szintlepesek");
});
#pragma warning restore 612, 618
}
}
+2 -5
View File
@@ -4,9 +4,6 @@ using Kemkas.Web.Db.Enums;
namespace Kemkas.Web.Db.Models;
/// <summary>
/// 1st edition character sheet
/// </summary>
public class V1Karakter
{
[Key] public Guid Id { get; set; }
@@ -18,8 +15,8 @@ public class V1Karakter
public double? Kor { get; set; }
public Jellem Jellem { get; set; } = Jellem.Semleges;
public string? Isten { get; set; }
public Faj1E Faj { get; set; } = Faj1E.Ember;
public Osztaly1E Osztaly { get; set; }
public Faj Faj { get; set; } = Faj.Ember;
public Osztaly Osztaly { get; set; }
public byte Ero { get; set; }
public byte Ugyesseg { get; set; }
public byte Egeszseg { get; set; }
+1 -1
View File
@@ -9,7 +9,7 @@ public class V1KarakterKepzettseg
[Key]
public Guid Id { get; set; }
public Guid KarakterId { get; set; }
public Kepzettseg1E Kepzettseg { get; set; }
public Kepzettseg Kepzettseg { get; set; }
public bool IsTolvajKepzettseg { get; set; } = false;
[ForeignKey(nameof(KarakterId))]
-2
View File
@@ -19,8 +19,6 @@ public class V1Szintlepes
public byte HpRoll { get; set; }
public Tulajdonsag? TulajdonsagNoveles { get; set; }
// used for both Kaloz/Tengeresz and Harcos
public string? FegyverSpecializacio { get; set; }
[ForeignKey(nameof(KarakterId))]
-17
View File
@@ -1,17 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Kemkas.Web.Db.Models;
public class V2Felszereles
{
[Key]
public Guid Id { get; set; }
public Guid KarakterId { get; set; }
public string TargyId { get; set; }
public bool IsFegyver { get; set; } = true;
[ForeignKey(nameof(KarakterId))]
public virtual V2Karakter Karakter { get; set; }
}
-44
View File
@@ -1,44 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Kemkas.Web.Db.Enums;
namespace Kemkas.Web.Db.Models;
/// <summary>
/// 2nd edition character sheet
/// </summary>
public class V2Karakter
{
[Key] public Guid Id { get; set; }
public bool IsPublic { get; set; } = false;
public int? OwnerUserId { get; set; }
public string Nev { get; set; }
public string? Nem { get; set; }
public double? Kor { get; set; }
public Jellem Jellem { get; set; } = Jellem.Semleges;
public string? Isten { get; set; }
public Faj2E Faj { get; set; } = Faj2E.Ember;
public byte Ero { get; set; }
public byte Ugyesseg { get; set; }
public byte Egeszseg { get; set; }
public byte Intelligencia { get; set; }
public byte Bolcsesseg { get; set; }
public byte Karizma { get; set; }
public byte Szint { get; set; } = 1;
public string? Pancel { get; set; }
public string? Pajzs { get; set; }
[ForeignKey(nameof(OwnerUserId))]
public ApplicationUser? OwnerUser { get; set; }
[InverseProperty(nameof(V2KarakterKepzettseg.Karakter))]
public virtual IEnumerable<V2KarakterKepzettseg> KarakterKepzettsegek { get; set; }
[InverseProperty(nameof(V2Szintlepes.Karakter))]
public virtual IEnumerable<V2Szintlepes> Szintlepesek { get; set; }
[InverseProperty(nameof(V2Felszereles.Karakter))]
public virtual IEnumerable<V2Felszereles> Felszereles { get; set; }
}
@@ -1,17 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Kemkas.Web.Db.Enums;
namespace Kemkas.Web.Db.Models;
public class V2KarakterKepzettseg
{
[Key]
public Guid Id { get; set; }
public Guid KarakterId { get; set; }
public Kepzettseg2E Kepzettseg { get; set; }
public bool IsTolvajKepzettseg { get; set; } = false;
[ForeignKey(nameof(KarakterId))]
public virtual V2Karakter Karakter { get; set; }
}
-29
View File
@@ -1,29 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Kemkas.Web.Db.Enums;
namespace Kemkas.Web.Db.Models;
public class V2Szintlepes
{
[Key]
public Guid Id { get; set; }
public Guid KarakterId { get; set; }
// this is also used for ordering the level ups
public byte KarakterSzint { get; set; }
public Osztaly2E Osztaly { get; set; }
public byte HpRoll { get; set; }
public Tulajdonsag? TulajdonsagNoveles { get; set; }
// used for both Kaloz/Tengeresz and Harcos
public string? FegyverSpecializacio { get; set; }
// for the 9th level Tolvaj specialty
public Kepzettseg2E? TolvajExtraKepzettseg { get; set; }
[ForeignKey(nameof(KarakterId))]
public virtual V2Karakter Karakter { get; set; }
}
-4
View File
@@ -53,10 +53,6 @@
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<ItemGroup>
<Folder Include="Services\FirstEdition\" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
+5 -7
View File
@@ -6,15 +6,14 @@ using Kemkas.Web.Config;
using Microsoft.EntityFrameworkCore;
using Kemkas.Web.Db;
using Kemkas.Web.Db.Models;
using Kemkas.Web.Services.FirstEdition.Character;
using Kemkas.Web.Services.Character;
using Kemkas.Web.Services.Identity;
using Kemkas.Web.Services.SecondEdition.Character;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Identity.UI.Services;
// using OpenTelemetry.Metrics;
// using OpenTelemetry.Resources;
// using OpenTelemetry.Trace;
using OpenTelemetry.Metrics;
using OpenTelemetry.Resources;
using OpenTelemetry.Trace;
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
var builder = WebApplication.CreateBuilder(args);
@@ -52,8 +51,7 @@ builder.AddOpenTelemetry();
builder.Services.AddHealthChecks();
builder.Services.AddCharacter1EServices();
builder.Services.AddCharacter2EServices();
builder.Services.AddCharacterServices();
var app = builder.Build();
app.UsePathBase("/api");
@@ -2,18 +2,18 @@ using Kemkas.Web.Db.Enums;
using Kemkas.Web.Db.Models;
using Kemkas.Web.ViewModels;
namespace Kemkas.Web.Services.FirstEdition.Character;
namespace Kemkas.Web.Services.Character;
public interface ICharacterDbModelToDto1EService
public interface ICharacterDbModelToDtoService
{
public Character1eDto Convert(V1Karakter entity);
public CharacterDto Convert(V1Karakter entity);
}
public class CharacterDbModelToDto1EService : ICharacterDbModelToDto1EService
public class CharacterDbModelToDtoService : ICharacterDbModelToDtoService
{
public Character1eDto Convert(V1Karakter entity)
public CharacterDto Convert(V1Karakter entity)
{
return new Character1eDto
return new CharacterDto
{
Name = entity.Nev,
Nem = entity.Nem,
@@ -36,8 +36,8 @@ public class CharacterDbModelToDto1EService : ICharacterDbModelToDto1EService
Szint = entity.Szint,
HpRolls = entity.Szintlepesek.OrderBy(x => x.KarakterSzint).Skip(1).Select(x => x.HpRoll).ToList(),
TulajdonsagNovelesek = entity.Szintlepesek.OrderBy(x => x.KarakterSzint).Select(x => x.TulajdonsagNoveles).Where(x => x is not null).Cast<Tulajdonsag>().Select(x => x.Convert()).ToList(),
HarcosSpecializaciok = entity.Osztaly == Osztaly1E.Harcos ? entity.Szintlepesek.OrderBy(x => x.KarakterSzint).Select(x => x.FegyverSpecializacio).Where(x => x != null).Cast<string>().ToList() : [],
KalozKritikus = entity.Osztaly == Osztaly1E.Kaloz ? entity.Szintlepesek.OrderBy(x => x.KarakterSzint).Select(x => x.FegyverSpecializacio).Where(x => x != null).Cast<string>().ToList() : [],
HarcosSpecializaciok = entity.Osztaly == Osztaly.Harcos ? entity.Szintlepesek.OrderBy(x => x.KarakterSzint).Select(x => x.FegyverSpecializacio).Where(x => x != null).Cast<string>().ToList() : [],
KalozKritikus = entity.Osztaly == Osztaly.Kaloz ? entity.Szintlepesek.OrderBy(x => x.KarakterSzint).Select(x => x.FegyverSpecializacio).Where(x => x != null).Cast<string>().ToList() : [],
Felszereles = new KarakterFelszerelesDto
{
PajzsId = entity.Pajzs,
@@ -3,18 +3,18 @@ using Kemkas.Web.Db.Enums;
using Kemkas.Web.Db.Models;
using Kemkas.Web.ViewModels;
namespace Kemkas.Web.Services.FirstEdition.Character;
namespace Kemkas.Web.Services.Character;
public interface ICharacter1EDtoToDbModelService
public interface ICharacterDtoToDbModelService
{
public V1Karakter Convert(Character1eDto dto);
public V1Karakter Convert(CharacterDto dto);
public void Update(V1Karakter original, Character1eDto dto);
public void Update(V1Karakter original, CharacterDto dto);
}
public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
public class CharacterDtoToDbModelService : ICharacterDtoToDbModelService
{
public V1Karakter Convert(Character1eDto dto)
public V1Karakter Convert(CharacterDto dto)
{
var karakter = new V1Karakter
{
@@ -23,8 +23,8 @@ public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
Kor = dto.Kor,
Jellem = JellemExtensions.Convert(dto.Jellem),
Isten = dto.Isten,
Faj = FajExtensions.Convert1E(dto.Faj),
Osztaly = OsztalyExtensions.Convert1E(dto.Osztaly),
Faj = FajExtensions.Convert(dto.Faj),
Osztaly = OsztalyExtensions.Convert(dto.Osztaly),
Ero = dto.Tulajdonsagok.Ero,
Ugyesseg = dto.Tulajdonsagok.Ugy,
Egeszseg = dto.Tulajdonsagok.Egs,
@@ -32,10 +32,10 @@ public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
Bolcsesseg = dto.Tulajdonsagok.Bol,
Karizma = dto.Tulajdonsagok.Kar,
Szint = dto.Szint,
Pajzs = dto.Felszereles.PajzsId,
Pancel = dto.Felszereles.PancelId
};
karakter.KarakterKepzettsegek = ConvertKepzettsegek(dto, karakter);
karakter.Pajzs = dto.Felszereles.PajzsId;
karakter.Pancel = dto.Felszereles.PancelId;
karakter.Felszereles = dto.Felszereles.FegyverIds.Select(x => new V1Felszereles
{
Karakter = karakter,
@@ -47,15 +47,15 @@ public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
return karakter;
}
public void Update(V1Karakter original, Character1eDto dto)
public void Update(V1Karakter original, CharacterDto dto)
{
original.Nev = dto.Name;
original.Nem = dto.Nem;
original.Kor = dto.Kor;
original.Jellem = JellemExtensions.Convert(dto.Jellem);
original.Isten = dto.Isten;
original.Faj = FajExtensions.Convert1E(dto.Faj);
original.Osztaly = OsztalyExtensions.Convert1E(dto.Osztaly);
original.Faj = FajExtensions.Convert(dto.Faj);
original.Osztaly = OsztalyExtensions.Convert(dto.Osztaly);
original.Ero = dto.Tulajdonsagok.Ero;
original.Ugyesseg = dto.Tulajdonsagok.Ugy;
original.Egeszseg = dto.Tulajdonsagok.Egs;
@@ -76,7 +76,7 @@ public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
}
// TODO: this is unnecessary duplication of business logic!!
private static List<V1Szintlepes> ConvertSzintLepes(Character1eDto dto, V1Karakter karakter)
private static List<V1Szintlepes> ConvertSzintLepes(CharacterDto dto, V1Karakter karakter)
{
if (dto.HpRolls.Count < dto.Szint - 2)
{
@@ -103,15 +103,15 @@ public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
// OsztalySzint = 1,
HpRoll = karakter.Osztaly switch // TODO: duplication of logic!!
{
Osztaly1E.Barbar => 12,
Osztaly1E.Amazon or Osztaly1E.Harcos or Osztaly1E.Kaloz or Osztaly1E.Ijasz => 10,
Osztaly1E.Pap => 8,
Osztaly1E.Tolvaj => 6,
Osztaly1E.Varazslo or Osztaly1E.Illuzionista => 4,
Osztaly.Barbar => 12,
Osztaly.Amazon or Osztaly.Harcos or Osztaly.Kaloz or Osztaly.Ijasz => 10,
Osztaly.Pap => 8,
Osztaly.Tolvaj => 6,
Osztaly.Varazslo or Osztaly.Illuzionista => 4,
_ => throw new ArgumentOutOfRangeException(nameof(karakter.Osztaly), karakter.Osztaly,
"invalid osztaly!")
},
FegyverSpecializacio = karakter.Osztaly == Osztaly1E.Harcos ? dto.HarcosSpecializaciok[0] : null,
FegyverSpecializacio = karakter.Osztaly == Osztaly.Harcos ? dto.HarcosSpecializaciok[0] : null,
};
return Enumerable.Range(2, count: dto.Szint - 1).Select(szint =>
@@ -131,13 +131,13 @@ public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
}).Prepend(level1).ToList();
}
private static List<V1KarakterKepzettseg> ConvertKepzettsegek(Character1eDto dto, V1Karakter karakter)
private static List<V1KarakterKepzettseg> ConvertKepzettsegek(CharacterDto dto, V1Karakter karakter)
{
var kepzettsegek = dto.Kepzettsegek.Select(x => new V1KarakterKepzettseg
{
Karakter = karakter,
IsTolvajKepzettseg = false,
Kepzettseg = KepzettsegExtensions.Convert1E(x),
Kepzettseg = KepzettsegExtensions.Convert(x),
}).ToList();
if (dto.Tolvajkepzettsegek != null)
{
@@ -145,7 +145,7 @@ public class Character1EDtoToDbModelService : ICharacter1EDtoToDbModelService
{
Karakter = karakter,
IsTolvajKepzettseg = true,
Kepzettseg = KepzettsegExtensions.Convert1E(x),
Kepzettseg = KepzettsegExtensions.Convert(x),
}));
}
return kepzettsegek;
@@ -0,0 +1,88 @@
using Kemkas.Web.Db;
using Kemkas.Web.Db.Enums;
using Kemkas.Web.Db.Models;
using Kemkas.Web.Services.Identity;
using Kemkas.Web.ViewModels;
using Microsoft.EntityFrameworkCore;
namespace Kemkas.Web.Services.Character;
public interface ICharacterPersistenceService
{
public Task<Guid> StoreNewCharacter(V1Karakter karakter, bool isPublic = false);
public Task<V1Karakter?> GetCharacterById(Guid id, bool tracking = false);
public Task<List<CharacterListItemDto>> GetAllCharactersOfUser();
public Task UpdateCharacter(V1Karakter karakter, bool isPublic = false);
}
public class CharacterPersistenceService(
ApplicationDbContext dbContext,
ICurrentUserService currentUserService
) : ICharacterPersistenceService
{
public async Task<Guid> StoreNewCharacter(V1Karakter karakter, bool isPublic = false)
{
var currentUser = await currentUserService.GetCurrentUser();
karakter.OwnerUserId = currentUser?.Id;
karakter.Id = Guid.Empty;
karakter.IsPublic = isPublic;
dbContext.Karakterek.Add(karakter);
await dbContext.SaveChangesAsync();
return karakter.Id;
}
public async Task<V1Karakter?> GetCharacterById(Guid id, bool tracking = false)
{
IQueryable<V1Karakter> queriable = dbContext.Karakterek.Include(x => x.KarakterKepzettsegek)
.Include(x => x.Szintlepesek)
.Include(x => x.Felszereles);
queriable = tracking ? queriable.AsTracking() : queriable.AsNoTracking();
var entity = await queriable
.FirstOrDefaultAsync(x => x.Id == id);
if (entity?.OwnerUserId is null || entity.IsPublic)
{
return entity;
}
var currentUser = await currentUserService.GetCurrentUser();
return entity.OwnerUserId == currentUser?.Id ? entity : null;
}
public async Task<List<CharacterListItemDto>> GetAllCharactersOfUser()
{
var currentUser = await currentUserService.GetCurrentUser();
if (currentUser is null)
{
return [];
}
var characters = await dbContext.Karakterek
.Where(k => k.OwnerUserId == currentUser.Id)
.Select(k => new CharacterListItemDto
{
Id = k.Id,
Name = k.Nev,
Szint = k.Szint,
Faj = k.Faj.Convert(),
Osztaly = k.Osztaly.Convert(),
Edition = "1e"
})
.ToListAsync();
return characters;
}
public async Task UpdateCharacter(V1Karakter karakter, bool isPublic = false)
{
karakter.IsPublic = isPublic;
dbContext.Karakterek.Attach(karakter);
await dbContext.SaveChangesAsync();
}
}
@@ -1,17 +1,16 @@
using Kemkas.Web.Services.Identity;
using Kemkas.Web.Services.Shared;
namespace Kemkas.Web.Services.FirstEdition.Character;
namespace Kemkas.Web.Services.Character;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCharacter1EServices(this IServiceCollection serviceCollection)
public static IServiceCollection AddCharacterServices(this IServiceCollection serviceCollection)
{
serviceCollection.AddScoped<ICurrentUserService, CurrentUserService>();
serviceCollection.AddTransient<ICharacterValidationService, CharacterValidationService>();
serviceCollection.AddTransient<ICharacter1EDtoToDbModelService, Character1EDtoToDbModelService>();
serviceCollection.AddTransient<ICharacterDbModelToDto1EService, CharacterDbModelToDto1EService>();
serviceCollection.AddTransient<ICharacterDtoToDbModelService, CharacterDtoToDbModelService>();
serviceCollection.AddTransient<ICharacterDbModelToDtoService, CharacterDbModelToDtoService>();
serviceCollection.AddScoped<ICharacterPersistenceService, CharacterPersistenceService>();
return serviceCollection;
}
@@ -1,15 +1,15 @@
using Kemkas.Web.ViewModels;
namespace Kemkas.Web.Services.FirstEdition.Character;
namespace Kemkas.Web.Services.Character;
public interface ICharacterValidationService
{
public string? Validate(Character1eDto dto);
public string? Validate(CharacterDto dto);
}
public class CharacterValidationService : ICharacterValidationService
{
public string? Validate(Character1eDto dto)
public string? Validate(CharacterDto dto)
{
// TODO: add validation!!
return null;
@@ -1,113 +0,0 @@
using Kemkas.Web.Db.Enums;
using Kemkas.Web.Db.Models;
using Kemkas.Web.ViewModels;
namespace Kemkas.Web.Services.SecondEdition.Character;
public interface ICharacter2EDtoToDbModelService
{
public V2Karakter Convert(Character2eDto dto);
public void Update(V2Karakter original, Character2eDto dto);
}
public class Character2EDtoToDbModelService : ICharacter2EDtoToDbModelService
{
public V2Karakter Convert(Character2eDto dto)
{
var karakter = new V2Karakter
{
Nev = dto.Nev,
Nem = dto.Nem,
Kor = dto.Kor,
Isten = dto.Isten,
Jellem = JellemExtensions.Convert(dto.Jellem),
Faj = FajExtensions.Convert2E(dto.Faj),
Ero = dto.Tulajdonsagok.Ero,
Ugyesseg = dto.Tulajdonsagok.Ugy,
Egeszseg = dto.Tulajdonsagok.Egs,
Intelligencia = dto.Tulajdonsagok.Int,
Bolcsesseg = dto.Tulajdonsagok.Bol,
Karizma = dto.Tulajdonsagok.Kar,
Szint = dto.Szint,
Pajzs = dto.Felszereles.PancelId,
Pancel = dto.Felszereles.PancelId
};
karakter.KarakterKepzettsegek = ConvertKarakterKepzettsegek(dto, karakter);
karakter.Felszereles = dto.Felszereles.FegyverIds.Select(x => new V2Felszereles
{
Karakter = karakter,
IsFegyver = true,
TargyId = x,
}).ToList();
karakter.Szintlepesek = dto.Szintlepesek.Select((x, i) => new V2Szintlepes
{
Karakter = karakter,
Osztaly = OsztalyExtensions.Convert2E(x.Osztaly),
KarakterSzint = (byte)(i + 1),
HpRoll = x.HProll,
FegyverSpecializacio = x.HarcosFegyver ?? x.KalozKritikus,
TulajdonsagNoveles = x.TulajdonsagNoveles == null ? null : TulajdonsagExtensions.Convert(x.TulajdonsagNoveles),
TolvajExtraKepzettseg = x.TolvajExtraKepzettseg == null ? null : KepzettsegExtensions.Convert2E(x.TolvajExtraKepzettseg),
}).ToList();
return karakter;
}
public void Update(V2Karakter original, Character2eDto dto)
{
original.Nev = dto.Nev;
original.Nem = dto.Nem;
original.Kor = dto.Kor;
original.Isten = dto.Isten;
original.Jellem = JellemExtensions.Convert(dto.Jellem);
original.Faj = FajExtensions.Convert2E(dto.Faj);
original.Ero = dto.Tulajdonsagok.Ero;
original.Ugyesseg = dto.Tulajdonsagok.Ugy;
original.Egeszseg = dto.Tulajdonsagok.Egs;
original.Intelligencia = dto.Tulajdonsagok.Int;
original.Bolcsesseg = dto.Tulajdonsagok.Bol;
original.Karizma = dto.Tulajdonsagok.Kar;
original.Szint = dto.Szint;
original.Pajzs = dto.Felszereles.PajzsId;
original.Pancel = dto.Felszereles.PancelId;
original.KarakterKepzettsegek = ConvertKarakterKepzettsegek(dto, original);
original.Felszereles = dto.Felszereles.FegyverIds.Select(x => new V2Felszereles
{
Karakter = original,
IsFegyver = true,
TargyId = x,
}).ToList();
original.Szintlepesek = dto.Szintlepesek.Select((x, i) => new V2Szintlepes
{
Karakter = original,
Osztaly = OsztalyExtensions.Convert2E(x.Osztaly),
KarakterSzint = (byte)(i + 1),
HpRoll = x.HProll,
FegyverSpecializacio = x.HarcosFegyver ?? x.KalozKritikus,
TulajdonsagNoveles = x.TulajdonsagNoveles == null ? null : TulajdonsagExtensions.Convert(x.TulajdonsagNoveles),
TolvajExtraKepzettseg = x.TolvajExtraKepzettseg == null ? null : KepzettsegExtensions.Convert2E(x.TolvajExtraKepzettseg),
}).ToList();
}
private static List<V2KarakterKepzettseg> ConvertKarakterKepzettsegek(Character2eDto dto, V2Karakter karakter)
{
var kepzettsegek = dto.Kepzettsegek.Select(x => new V2KarakterKepzettseg
{
Karakter = karakter,
IsTolvajKepzettseg = false,
Kepzettseg = KepzettsegExtensions.Convert2E(x),
}).ToList();
if (dto.Tolvajkepzettsegek != null)
{
kepzettsegek.AddRange(dto.Tolvajkepzettsegek.Select(x => new V2KarakterKepzettseg
{
Karakter = karakter,
IsTolvajKepzettseg = true,
Kepzettseg = KepzettsegExtensions.Convert2E(x),
}));
}
return kepzettsegek;
}
}
@@ -1,54 +0,0 @@
using Kemkas.Web.Db.Enums;
using Kemkas.Web.Db.Models;
using Kemkas.Web.ViewModels;
namespace Kemkas.Web.Services.SecondEdition.Character;
public interface ICharacterDbModelToDto2EService
{
public Character2eDto Convert(V2Karakter entity);
}
public class CharacterDbModelToDto2EService : ICharacterDbModelToDto2EService
{
public Character2eDto Convert(V2Karakter entity)
{
return new Character2eDto
{
Nev = entity.Nev,
Nem = entity.Nem,
Kor = entity.Kor,
Jellem = entity.Jellem.Convert(),
Isten = entity.Isten,
Faj = entity.Faj.Convert(),
Tulajdonsagok = new KarakterTulajdonsagokDto
{
Ero = entity.Ero,
Ugy = entity.Ugyesseg,
Egs = entity.Egeszseg,
Int = entity.Intelligencia,
Bol = entity.Bolcsesseg,
Kar = entity.Karizma,
},
Kepzettsegek = entity.KarakterKepzettsegek.Where(x => !x.IsTolvajKepzettseg).Select(x => x.Kepzettseg.Convert()).ToList(),
Tolvajkepzettsegek = entity.KarakterKepzettsegek.Where(x => x.IsTolvajKepzettseg).Select(x => x.Kepzettseg.Convert()).ToList(),
Szint = entity.Szint,
Felszereles = new KarakterFelszerelesDto
{
PajzsId = entity.Pajzs,
PancelId = entity.Pancel,
FegyverIds = entity.Felszereles.Where(x => x.IsFegyver).Select(x => x.TargyId).ToList(),
},
IsPublic = entity.IsPublic,
Szintlepesek = entity.Szintlepesek.OrderBy(x => x.KarakterSzint).Select(sz => new Szintlepes
{
Osztaly = sz.Osztaly.Convert(),
KalozKritikus = sz.Osztaly == Osztaly2E.Tengeresz ? sz.FegyverSpecializacio : null,
HarcosFegyver = sz.Osztaly == Osztaly2E.Harcos ? sz.FegyverSpecializacio : null,
TulajdonsagNoveles = sz.TulajdonsagNoveles?.Convert(),
HProll = sz.HpRoll,
TolvajExtraKepzettseg = sz.TolvajExtraKepzettseg?.Convert()
}).ToList()
};
}
}
@@ -1,11 +0,0 @@
namespace Kemkas.Web.Services.SecondEdition.Character;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddCharacter2EServices(this IServiceCollection serviceCollection)
{
serviceCollection.AddTransient<ICharacter2EDtoToDbModelService, Character2EDtoToDbModelService>();
serviceCollection.AddTransient<ICharacterDbModelToDto2EService, CharacterDbModelToDto2EService>();
return serviceCollection;
}
}
@@ -1,147 +0,0 @@
using Kemkas.Web.Db;
using Kemkas.Web.Db.Enums;
using Kemkas.Web.Db.Models;
using Kemkas.Web.Services.Identity;
using Kemkas.Web.ViewModels;
using Microsoft.EntityFrameworkCore;
namespace Kemkas.Web.Services.Shared;
public interface ICharacterPersistenceService
{
public Task<Guid> StoreNewCharacter1E(V1Karakter karakter, bool isPublic = false);
public Task<Guid> StoreNewCharacter2E(V2Karakter karakter, bool isPublic = false);
public Task<V1Karakter?> GetCharacter1EById(Guid id, bool tracking = false);
public Task<V2Karakter?> GetCharacter2EById(Guid id, bool tracking = false);
public Task<List<CharacterListItemDto>> GetAllCharactersOfUser();
public Task UpdateCharacter1E(V1Karakter karakter, bool isPublic = false);
public Task UpdateCharacter2E(V2Karakter karakter, bool isPublic = false);
}
public class CharacterPersistenceService(
ApplicationDbContext dbContext,
ICurrentUserService currentUserService
) : ICharacterPersistenceService
{
public async Task<Guid> StoreNewCharacter1E(V1Karakter karakter, bool isPublic = false)
{
var currentUser = await currentUserService.GetCurrentUser();
karakter.OwnerUserId = currentUser?.Id;
karakter.Id = Guid.Empty;
karakter.IsPublic = isPublic;
dbContext.Karakterek.Add(karakter);
await dbContext.SaveChangesAsync();
return karakter.Id;
}
public async Task<Guid> StoreNewCharacter2E(V2Karakter karakter, bool isPublic = false)
{
var currentUser = await currentUserService.GetCurrentUser();
karakter.OwnerUserId = currentUser?.Id;
karakter.Id = Guid.Empty;
karakter.IsPublic = isPublic;
dbContext.Karakterek2E.Add(karakter);
await dbContext.SaveChangesAsync();
return karakter.Id;
}
public async Task<V1Karakter?> GetCharacter1EById(Guid id, bool tracking = false)
{
IQueryable<V1Karakter> queryable = dbContext.Karakterek.Include(x => x.KarakterKepzettsegek)
.Include(x => x.Szintlepesek)
.Include(x => x.Felszereles);
queryable = tracking ? queryable.AsTracking() : queryable.AsNoTracking();
var entity = await queryable
.FirstOrDefaultAsync(x => x.Id == id);
if (entity?.OwnerUserId is null || entity.IsPublic)
{
return entity;
}
var currentUser = await currentUserService.GetCurrentUser();
return entity.OwnerUserId == currentUser?.Id ? entity : null;
}
public async Task<V2Karakter?> GetCharacter2EById(Guid id, bool tracking = false)
{
IQueryable<V2Karakter> queryable = dbContext.Karakterek2E.Include(x => x.KarakterKepzettsegek)
.Include(x => x.Szintlepesek)
.Include(x => x.Felszereles);
queryable = tracking ? queryable.AsTracking() : queryable.AsNoTracking();
var entity = await queryable
.FirstOrDefaultAsync(x => x.Id == id);
if (entity?.OwnerUserId is null || entity.IsPublic)
{
return entity;
}
var currentUser = await currentUserService.GetCurrentUser();
return entity.OwnerUserId == currentUser?.Id ? entity : null;
}
public async Task<List<CharacterListItemDto>> GetAllCharactersOfUser()
{
var currentUser = await currentUserService.GetCurrentUser();
if (currentUser is null)
{
return [];
}
var characters = await dbContext.Karakterek
.Where(k => k.OwnerUserId == currentUser.Id)
.Select(k => new CharacterListItemDto
{
Id = k.Id,
Name = k.Nev,
Szint = k.Szint,
Faj = k.Faj.Convert(),
Osztaly = k.Osztaly.Convert(),
Edition = "1e"
})
.ToListAsync();
var characters2E = await dbContext.Karakterek2E.Include(k => k.Szintlepesek)
.Where(k => k.OwnerUserId == currentUser.Id)
.Select(k => new CharacterListItemDto
{
Id = k.Id,
Name = k.Nev,
Szint = k.Szint,
Faj = k.Faj.Convert(),
Osztaly = k.Szintlepesek.OrderBy(x => x.KarakterSzint).Select(x => x.Osztaly).First().Convert(),
Edition = "2e"
})
.ToListAsync();
characters.AddRange(characters2E);
return characters;
}
public async Task UpdateCharacter1E(V1Karakter karakter, bool isPublic = false)
{
karakter.IsPublic = isPublic;
dbContext.Karakterek.Attach(karakter);
await dbContext.SaveChangesAsync();
}
public async Task UpdateCharacter2E(V2Karakter karakter, bool isPublic = false)
{
karakter.IsPublic = isPublic;
dbContext.Karakterek2E.Attach(karakter);
await dbContext.SaveChangesAsync();
}
}
-46
View File
@@ -1,46 +0,0 @@
using System.ComponentModel.DataAnnotations;
using System.Text.Json.Serialization;
namespace Kemkas.Web.ViewModels;
public struct Character2eDto
{
[Required]
[JsonPropertyName("nev")]
public string Nev { get; set; }
[JsonPropertyName("nem")]
public string? Nem { get; set; }
[JsonPropertyName("kor")]
public double? Kor { get; set; }
[JsonPropertyName("jellem")]
public string Jellem { get; set; }
[JsonPropertyName("isten")]
public string? Isten { get; set; }
[JsonPropertyName("faj")]
public string Faj { get; set; }
[JsonPropertyName("tulajdonsagok")]
public KarakterTulajdonsagokDto Tulajdonsagok { get; set; }
[JsonPropertyName("kepzettsegek")]
public IList<string> Kepzettsegek { get; set; }
[JsonPropertyName("tolvajkepzettsegek")]
public IList<string>? Tolvajkepzettsegek { get; set; }
[JsonPropertyName("szint")]
public byte Szint { get; set; }
[JsonPropertyName("szintlepesek")]
public IList<Szintlepes> Szintlepesek { get; set; }
[JsonPropertyName("felszereles")]
public KarakterFelszerelesDto Felszereles { get; set; }
public bool? IsPublic { get; set; }
}
@@ -3,7 +3,7 @@ using System.Text.Json.Serialization;
namespace Kemkas.Web.ViewModels;
public struct Character1eDto
public struct CharacterDto
{
[Required]
[JsonPropertyName("name")]
@@ -2,9 +2,6 @@ using System.Text.Json.Serialization;
namespace Kemkas.Web.ViewModels;
/// <summary>
/// currently the same for 1st edition and 2nd edition, be cautious!
/// </summary>
public struct KarakterFelszerelesDto
{
[JsonPropertyName("pancelID")]
@@ -2,9 +2,6 @@ using System.Text.Json.Serialization;
namespace Kemkas.Web.ViewModels;
/// <summary>
/// currently the same for 1st edition and 2nd edition, be cautious!
/// </summary>
public struct KarakterTulajdonsagokDto
{
[JsonPropertyName("t_ero")]
-24
View File
@@ -1,24 +0,0 @@
using System.Text.Json.Serialization;
namespace Kemkas.Web.ViewModels;
public struct Szintlepes
{
[JsonPropertyName("osztaly")]
public string Osztaly { get; set; }
[JsonPropertyName("HProll")]
public byte HProll { get; set; }
[JsonPropertyName("tolvajExtraKepzettseg")]
public string? TolvajExtraKepzettseg { get; set; }
[JsonPropertyName("harcosFegyver")]
public string? HarcosFegyver { get; set; }
[JsonPropertyName("kalozKritikus")]
public string? KalozKritikus { get; set; }
[JsonPropertyName("tulajdonsagNoveles")]
public string? TulajdonsagNoveles { get; set; }
}
+12
View File
@@ -0,0 +1,12 @@
namespace Kemkas.Web.ViewModels;
public class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
+1 -1
View File
@@ -13,5 +13,5 @@ RUN yarn build
FROM nginx:latest as proxy
# COPY ./nginx/nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder "/src/build" "/usr/share/nginx/html"
COPY ./nginx.conf /etc/nginx/nginx.conf
-36
View File
@@ -1,36 +0,0 @@
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
root /usr/share/nginx/html;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
}
+1 -1
View File
@@ -3,7 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
"@grafana/faro-web-sdk": "^1.3.9",
"@grafana/faro-web-sdk": "^1.2.2",
"@pdf-lib/fontkit": "^1.1.1",
"@testing-library/jest-dom": "^6.1.4",
"@testing-library/react": "^14.0.0",
Binary file not shown.
+6 -6
View File
@@ -3,7 +3,7 @@ import './App.css';
import {Faro} from "@grafana/faro-web-sdk";
import {createBrowserRouter, redirect, RouterProvider} from "react-router-dom";
import CreateCharacter from "./first-edition/pages/CreateCharacter";
import CharacterList from "./shared/pages/CharacterList";
import CharacterList from "./first-edition/pages/CharacterList";
import ErrorBoundary from "./shared/ErrorBoundary";
import Header from "./shared/Header";
import Footer from "./shared/Footer";
@@ -42,7 +42,7 @@ function App(props: {faro?: Faro}) {
const router = createBrowserRouter([
{
path: "/",
loader: () => fetchedUser.data == null ? redirect("/2e/karakter") : redirect("/karaktereim")
loader: () => fetchedUser.data == null ? redirect("/1e/karakter") : redirect("/karaktereim")
},
{
path: "/karaktereim",
@@ -62,7 +62,7 @@ function App(props: {faro?: Faro}) {
{
path: "/1e/karakter/:id",
element: <CreateCharacter faro={props.faro}/>,
loader: args => fetch(`${window.location.origin}/api/Character1E/${args.params.id}`),
loader: args => fetch(`${window.location.origin}/api/Character/${args.params.id}`),
ErrorBoundary: ErrorBoundary,
},
{
@@ -71,13 +71,13 @@ function App(props: {faro?: Faro}) {
},
{
path: "/2e/karakter",
element: <CreateCharacter2E faro={props.faro}/>,
element: <CreateCharacter2E />,
ErrorBoundary: ErrorBoundary,
},
{
path: "/2e/karakter/:id",
element: <CreateCharacter2E faro={props.faro}/>,
loader: args => fetch(`${window.location.origin}/api/Character2E/${args.params.id}`),
element: <CreateCharacter faro={props.faro}/>,
loader: args => fetch(`${window.location.origin}/api/Character/${args.params.id}`),
ErrorBoundary: ErrorBoundary,
},
]);
@@ -2,7 +2,7 @@ import {KarakterInputs} from "../domain-models/karakter";
import axios from "axios";
export async function StoreNewCharacter(karakter: KarakterInputs, isPublic: boolean = false) {
let response = await axios.post(`${window.location.origin}/api/Character1E/`, karakter, {
let response = await axios.post(`${window.location.origin}/api/Character/`, karakter, {
withCredentials: true,
params: {
isPublic,
@@ -17,7 +17,7 @@ export async function StoreNewCharacter(karakter: KarakterInputs, isPublic: bool
}
export async function UpdateCharacter(id: string, karakter: KarakterInputs, isPublic: boolean = false) {
let response = await axios.post(`${window.location.origin}/api/Character1E/${id}`, karakter, {
let response = await axios.post(`${window.location.origin}/api/Character/${id}`, karakter, {
withCredentials: true,
params: {
isPublic,
@@ -30,3 +30,4 @@ export async function UpdateCharacter(id: string, karakter: KarakterInputs, isPu
throw Error(response.statusText)
}
}
@@ -0,0 +1,26 @@
import * as React from "react";
import {Osztaly, OsztalyLabel} from "../domain-models/osztaly";
import {Faj, FajLabel} from "../domain-models/faj";
export interface CharacterListItemDto {
id: string,
name: string,
szint: number,
faj: Faj,
osztaly: Osztaly,
edition: "1e" | "2e"
}
function CharacterListItem(props: {
character: CharacterListItemDto,
}) {
const {character:c} = props
return <>
<td><a href={`/${c.edition}/karakter/${c.id}`}>{c.name}</a></td>
<td>{c.szint}. szintű</td>
<td>{FajLabel(c.faj)}</td>
<td>{OsztalyLabel(c.osztaly)}</td>
</>
}
export default CharacterListItem;
@@ -0,0 +1,35 @@
import * as React from "react";
import {useLoaderData} from "react-router-dom";
import CharacterListItem, {CharacterListItemDto} from "../components/CharacterListItem";
function CharacterList(props: {}) {
const characters = useLoaderData() as CharacterListItemDto[];
return <div className="container">
<div className="container-fluid p-5 bg-black text-white text-center">
<h1>Karakterek</h1>
</div>
<div className="d-grid gap-2 m-5">
<a className="btn btn-dark btn-lg" href="/" type="button">Új karakter létrehozása</a>
</div>
<table className="table mt-3">
<thead>
<tr>
<th scope="col">Név</th>
<th scope="col">Szint</th>
<th scope="col">Faj</th>
<th scope="col">Osztály</th>
</tr>
</thead>
<tbody>
{characters.map(c => (
<tr key={c.id}>
<CharacterListItem character={c}/>
</tr>
))}
</tbody>
</table>
</div>
}
export default CharacterList;
@@ -10,15 +10,16 @@ import {DrawMasodlagosErtekek} from './masodlagos_ertekek.pdf'
import {DrawOsztalySpecialsPage} from './osztaly_specials.pdf'
import {DrawFegyverek} from "./fegyverek.pdf";
function drawBaseInfo(karakter: KarakterPdfView, draw: (text: string, x : number ,y: number, scale: number) => void) {
draw(karakter.Name, 60, 710, 1)
draw(karakter.Nem, 454, 710, 1)
draw(karakter.Kor.toString(), 454, 690, 1)
draw(karakter.Isten, 454, 670, 1)
draw(karakter.Osztaly, 60, 672, 1)
draw(karakter.Szint, karakter.Szint.length > 1 ? 252 : 264, 682, 3)
draw(karakter.Faj, 302, 710, 1)
draw(karakter.Jellem, 302, 672, karakter.Jellem.length > 17 ? 11/12 : 1)
function drawBaseInfo(karakter: KarakterPdfView,
draw: (name: string, text: string, x : number ,y: number, width: number, scale: number) => void) {
draw("nev", karakter.Name, 56, 704, 190, 1)
draw("nem", karakter.Nem, 449, 704, 90, 11/12)
draw("kor", karakter.Kor.toString(), 449, 687, 90, 11/12)
draw("isten", karakter.Isten, 449, 669, 90, 11/12)
draw("osztaly", karakter.Osztaly, 56, 668, 190, 1)
draw("szint", karakter.Szint, 250, 669, 45, 3)
draw("faj", karakter.Faj, 301, 704, 110, 1)
draw("jellem", karakter.Jellem, 301, 669, 110,karakter.Jellem.length > 17 ? 11/12 : 1)
}
function DrawKepzettsegek(draw: (text: string, x: number, y: number) => void, kepzettsegek: KepzettsegPdfView[], startFrom: number) {
@@ -40,14 +41,17 @@ function DrawFelszereles(draw: (text: string, x: number, y:number) => void, fels
export async function CreatePDF(karakter: KarakterPdfView) {
const existingPdfBytes = await fetch('/pdfs/km_karakterlap_hysteria_1.2.pdf').then(res => res.arrayBuffer())
const existingPdfBytes = await fetch('/km_karakterlap_hysteria_1.2.pdf').then(res => res.arrayBuffer())
const pdfDoc = await PDFDocument.load(existingPdfBytes)
pdfDoc.registerFontkit(fontkit)
const fontBytes = await fetch('/fonts/Merienda-Regular.ttf').then(res => res.arrayBuffer())
const fontBytes = await fetch('/Merienda-Regular.ttf').then(res => res.arrayBuffer())
const pdfFont = await pdfDoc.embedFont(fontBytes)
// const pdfFont = await pdfDoc.embedFont(StandardFonts.TimesNewRoman)
const fontSizeBase = 12
const form = pdfDoc.getForm()
const page = pdfDoc.getPage(0)
function drawText(text: string, x: number, y: number, fontScale = 1, shade = 0) {
@@ -60,7 +64,27 @@ export async function CreatePDF(karakter: KarakterPdfView) {
})
}
drawBaseInfo(karakter, drawText);
function drawInputField(name: string, text: string, x: number, y: number, width: number, fontScale = 1) {
let field = form.createTextField(`kemkas.1e.${name}`)
field.addToPage(page, {
x: x,
y: y,
font: pdfFont,
height: pdfFont.heightAtSize(fontSizeBase * fontScale),
width: width,
borderWidth: 0,
borderColor: rgb(0,0,0)
});
field.disablePassword();
field.disableMultiline();
field.disableRichFormatting();
field.disableFileSelection();
field.disableSpellChecking();
field.setFontSize(fontSizeBase * fontScale);
field.setText(text);
}
drawBaseInfo(karakter, drawInputField);
DrawTulajdonsagok(page, karakter.Tulajdonsagok, fontSizeBase, pdfFont);
@@ -79,7 +103,7 @@ export async function CreatePDF(karakter: KarakterPdfView) {
DrawMagic(page, fontSizeBase, pdfFont, karakter.NapiMemorizalhatoVarazslatok, karakter.VarazslatMentokNF)
const secondPage = pdfDoc.addPage()
const fontBoldBytes = await fetch('/fonts/Merienda-Bold.ttf').then(res => res.arrayBuffer())
const fontBoldBytes = await fetch('/Merienda-Bold.ttf').then(res => res.arrayBuffer())
const fontBold = await pdfDoc.embedFont(fontBoldBytes)
DrawOsztalySpecialsPage(secondPage, pdfFont, fontBold, karakter)
@@ -1,32 +0,0 @@
import axios from "axios";
import {Karakter2E} from "../domain-models/karakter2E";
export async function StoreNewCharacter2E(karakter: Karakter2E, isPublic: boolean = false) {
let response = await axios.post(`${window.location.origin}/api/Character2E/`, karakter, {
withCredentials: true,
params: {
isPublic,
}
})
if (response.status < 300){
return response.data as string
}
else {
throw Error(response.statusText)
}
}
export async function UpdateCharacter2E(id: string, karakter: Karakter2E, isPublic: boolean = false) {
let response = await axios.post(`${window.location.origin}/api/Character2E/${id}`, karakter, {
withCredentials: true,
params: {
isPublic,
}
})
if (response.status < 300){
return response.data as string
}
else {
throw Error(response.statusText)
}
}
@@ -3,8 +3,7 @@ import {Karakter2E} from "../domain-models/karakter2E";
import {SignedNumberToText} from "../../shared/components/Helpers";
import {Mentok, MentoTipus, MentoTipusLabel, MentokTotal} from "../domain-models/mentok";
import {BaseHP, HP} from "../domain-models/masodlagos_ertekek";
import {MultiClassTamadasBonusz} from "../domain-models/tamadas_bonusz";
import {Osztaly2E} from "../domain-models/osztaly2E";
import {TamadasBonusz} from "../domain-models/tamadas_bonusz";
function MentoNovekedes(props : {tipus: MentoTipus, ujMentok: Mentok, regiMentok: Mentok}) {
const {tipus, ujMentok, regiMentok} = props
@@ -29,17 +28,16 @@ function UjMento(props : {tipus: MentoTipus, ujMentok: Mentok, regiMentok: Mento
}
function BasicNewLevel(props: {
karakter: Pick<Karakter2E, 'tulajdonsagok' | 'szintlepesek'>
karakter: Pick<Karakter2E, 'osztaly' | 'tulajdonsagok' | 'szintlepesek'>
szint: number
osztaly: Osztaly2E
changeRolledHP: (hp: number) => void,
}) {
const {karakter, szint, osztaly, changeRolledHP} = props
const regiMentok = MentokTotal({...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint - 1)})
const ujMentok = MentokTotal({...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint)})
const {karakter, szint, changeRolledHP} = props
const regiMentok = MentokTotal({...karakter, szint: szint - 1})
const ujMentok = MentokTotal({...karakter, szint: szint})
const regiTB = MultiClassTamadasBonusz(karakter.szintlepesek.slice(0, szint-1))
const ujTB = MultiClassTamadasBonusz(karakter.szintlepesek.slice(0, szint))
const regiTB = TamadasBonusz(karakter.osztaly, szint-1)
const ujTB = TamadasBonusz(karakter.osztaly, szint)
if (regiTB.length < ujTB.length) {
regiTB.push(0)
}
@@ -50,7 +48,7 @@ function BasicNewLevel(props: {
<div className='row'>
<div className='col-lg-6'>
<div className='row m-2'>
<label className='col-sm-6 col-8 col-form-label'>Plusz dobott HP (d{BaseHP(osztaly)}){' '}</label>
<label className='col-sm-6 col-8 col-form-label'>Plusz dobott HP (d{BaseHP(karakter.osztaly)}){' '}</label>
<div className='col-sm-2 col'>
<input
className='form-control'
@@ -73,7 +71,7 @@ function BasicNewLevel(props: {
<div className='col-lg-6'>
<div className='row m-2'>
<label className='col-sm-6 col-8 col-form-label'>Új HP{' '}</label>
<span className='col col-form-label'>{HP({...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint)})}</span>
<span className='col col-form-label'>{HP({...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint-1)})}</span>
</div>
{isTBincreased && <div className='row m-2'>
<label className='col-sm-6 col-8 col-form-label'>Új Támadás bónusz{' '}</label>
@@ -1,11 +1,8 @@
import React from "react";
import {Fegyver} from "../domain-models/felszereles";
export function FegyverFlags(fegyver: Fegyver): string {
export function FegyverLabel(fegyver: Fegyver): string {
const flags = [] as string[]
if (fegyver.Megterheltseg) {
flags.push("M")
}
if (fegyver.Harcos) {
flags.push("H")
}
@@ -47,15 +44,17 @@ export function FegyverFlags(fegyver: Fegyver): string {
if (fegyver.Rohamtoro) {
flags.push("RT")
}
return flags.join(' ');
// Replaced by new group "dobhato"
// if (fegyver.EroBonusz) {
// flags.push("ER")
// }
if (fegyver.Megjegyzes != null && fegyver.Megjegyzes.length > 0) {
flags.push(fegyver.Megjegyzes)
}
export function FegyverLabel(fegyver: Fegyver): string {
const serializedFlags = FegyverFlags(fegyver) + (fegyver.Megjegyzes != null ? " " + fegyver.Megjegyzes : "");
const serializedFlags = flags.reduce((p,c) => `${p}${c} `, '');
const sizeLabel = fegyver.Size < 1 && fegyver.Size > 0 ? ` [1/${Math.round(1 / fegyver.Size)}]` : (fegyver.Size > 1 ? ` [${fegyver.Size}]` : '');
return `${fegyver.Name}${sizeLabel} | ${serializedFlags.length > 0 ? serializedFlags + " |" : ''}${
fegyver.DamageMultiplier > 1 ? `${fegyver.DamageMultiplier}*` : ''}${
fegyver.NumberOfDamageDice}d${fegyver.DamageDice}${fegyver.DamageBonus > 0 ? ` +${fegyver.DamageBonus}` : ''} ${
return `${fegyver.Name}${sizeLabel} ${serializedFlags.length > 0 ? "| " + serializedFlags : ''}| ${
fegyver.DamageMultiplier > 1 ? `${fegyver.DamageMultiplier}*` : ''}${fegyver.NumberOfDamageDice}d${fegyver.DamageDice}${fegyver.DamageBonus > 0 ? ` +${fegyver.DamageBonus}` : ''} ${
fegyver.CritRangeStart < 20 ? `${fegyver.CritRangeStart}-20` : ''}x${fegyver.CritMultiplier}${
fegyver.Price > 0 ? ` | ár: ${fegyver.Price} at ` : ''}${
fegyver.Range > 10 ? ` | táv: ${fegyver.Range}` : ''}`
@@ -1,5 +1,5 @@
import React from "react";
import {ChangeOsztalyAtSzint, Karakter2E} from "../domain-models/karakter2E";
import {Karakter2E} from "../domain-models/karakter2E";
import BasicNewLevel from "./BasicNewLevel";
import TulajdonsagNoveles from "./TulajdonsagNoveles";
import {Tulajdonsag2E, TulajdonsagokTotal} from "../domain-models/tulajdonsag2E";
@@ -8,34 +8,23 @@ import {Osztaly2E} from "../domain-models/osztaly2E";
import KalozKritikus from "./KalozKritikus";
import HarcosFegyverSpecializacio from "./HarcosFegyverSpec";
import MultiClassOsztalySelector2E from "./MultiClassOsztalySelector2E";
import {getClassLevels} from "../domain-models/szintlepes";
function LevelUp(props: {
szint: number,
osztaly: Osztaly2E,
karakter: Karakter2E,
changeTulajdonsagNoveles: (t: Tulajdonsag2E) => void,
changeRolledHP: (rolledHP: number) => void,
changeHarcosSpec: (spec: string) => void,
changeKalozKritikus: (krit: string) => void,
changeOsztaly: (osztaly: Osztaly2E) => void
}) {
const {
szint,
osztaly,
karakter,
changeTulajdonsagNoveles,
changeRolledHP,
changeHarcosSpec,
changeKalozKritikus,
changeOsztaly
} = props
const classLevels = getClassLevels(karakter.szintlepesek)
const harcosSzint = classLevels[Osztaly2E.Harcos]
const kalozSzint = classLevels[Osztaly2E.Tengeresz]
const specialization = karakter.szintlepesek[szint-1].harcosFegyver
const krit = karakter.szintlepesek[szint-1].kalozKritikus
@@ -43,15 +32,8 @@ function LevelUp(props: {
<div className='row mt-3'>
<h5 className='col align-self-center'>{szint}. Szint</h5>
</div>
{osztaly !== Osztaly2E.Druida &&
<MultiClassOsztalySelector2E
faj={karakter.faj}
osztaly={osztaly}
changeOsztaly={changeOsztaly}
osztalySzint={classLevels[osztaly]}
/> }
{szint % 4 === 0 &&
<TulajdonsagNoveles
{szint % 4 === 0
&& <TulajdonsagNoveles
tulajdonsagok={karakter.tulajdonsagok}
tulajdonsagNoveles={karakter.szintlepesek[szint-1].tulajdonsagNoveles!}
changeTulajdonsagNoveles={changeTulajdonsagNoveles}
@@ -59,23 +41,22 @@ function LevelUp(props: {
<BasicNewLevel
szint={szint}
karakter={karakter}
osztaly={osztaly}
changeRolledHP={changeRolledHP}
/>
{osztaly === Osztaly2E.Harcos && harcosSzint % 2 === 1 &&
{karakter.osztaly === Osztaly2E.Harcos && szint % 2 === 1 &&
<HarcosFegyverSpecializacio
specialization={specialization!}
existingSpecializations={karakter.szintlepesek.map(x => x.harcosFegyver)}
changeSpecialization={changeHarcosSpec}
szint={harcosSzint}
szint={szint}
/>
}
{osztaly === Osztaly2E.Tengeresz && kalozSzint % 3 === 0 &&
{karakter.osztaly === Osztaly2E.Tengeresz && szint % 3 === 0 && !!krit &&
<KalozKritikus
kritFegyverId={krit!}
kritFegyverId={krit}
existingKrits={karakter.szintlepesek.map(x => x.kalozKritikus)}
changeKrit={changeKalozKritikus}
szint={kalozSzint}
szint={szint}
/>
}
</div>
@@ -84,10 +65,10 @@ function LevelUp(props: {
export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs: Karakter2E) => void}){
const {karakter, changeKarakter} = props;
const tulajdonsagokAtSzint = (szint: number) => TulajdonsagokTotal({...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint)})
const tulajdonsagokAtSzint = (szint: number) => TulajdonsagokTotal({...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint - 1)})
const changeRolledHPAtSzint = (szint: number) => (newHProll: number) => {
changeKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {...karakter.szintlepesek[szint-1], HProll: newHProll})})
changeKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, szint-2, {...karakter.szintlepesek[szint-2], HProll: newHProll})})
console.log(karakter)
}
const changeTulajdonsagNovelesAtSzint = (szint: number) => {
@@ -132,13 +113,11 @@ export function LevelUps(props: {karakter: Karakter2E, changeKarakter: (inputs:
<LevelUp
key={`level-up-${szint}`}
szint={szint}
osztaly={karakter.szintlepesek[szint-1].osztaly}
karakter={{...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint) ,tulajdonsagok: tulajdonsagokAtSzint(szint)}}
karakter={{...karakter, tulajdonsagok: tulajdonsagokAtSzint(szint)}}
changeTulajdonsagNoveles={changeTulajdonsagNovelesAtSzint(szint)}
changeRolledHP={changeRolledHPAtSzint(szint)}
changeHarcosSpec={changeHarcosSpecializacioAtSzint(szint)}
changeKalozKritikus={changeKalozKritikusAtSzint(szint)}
changeOsztaly={(o) => changeKarakter(ChangeOsztalyAtSzint(karakter, o, szint))}
/>
)}
</>
@@ -1,54 +0,0 @@
import {Faj2E, SzintKorlatokFajokra} from "../domain-models/faj2E";
import {Osztaly2E, OsztalyLabel} from "../domain-models/osztaly2E";
import React from "react";
function MultiClassOsztalySelector2E(props: {
faj: Faj2E,
osztaly: Osztaly2E,
changeOsztaly: (o: Osztaly2E) => void
osztalySzint: number
}) {
const {faj, osztaly, changeOsztaly, osztalySzint} = props
return <>
<div className='row'>
<div className="col-lg-6">
<div className="row m-md-2">
<label className='col-8 col-sm-6 col-form-label'>Osztály</label>
<div className="col">
<select className="col form-select" value={osztaly}
onChange={(e) => changeOsztaly(e.target.value as Osztaly2E)}>
<optgroup label='Harcos'>
<option value={Osztaly2E.Harcos}>{OsztalyLabel(Osztaly2E.Harcos)}</option>
{SzintKorlatokFajokra(faj)[Osztaly2E.Amazon] > 0 && (
<option value={Osztaly2E.Amazon}>{OsztalyLabel(Osztaly2E.Amazon)}</option>)}
<option value={Osztaly2E.Barbar}>{OsztalyLabel(Osztaly2E.Barbar)}</option>
<option value={Osztaly2E.Ijasz}>{OsztalyLabel(Osztaly2E.Ijasz)}</option>
<option value={Osztaly2E.Tengeresz}>{OsztalyLabel(Osztaly2E.Tengeresz)}</option>
</optgroup>
<option value={Osztaly2E.Pap}>{OsztalyLabel(Osztaly2E.Pap)}</option>
<option value={Osztaly2E.Tolvaj}>{OsztalyLabel(Osztaly2E.Tolvaj)}</option>
<optgroup label='Varázsló'>
<option value={Osztaly2E.Varazslo}>{OsztalyLabel(Osztaly2E.Varazslo)}</option>
<option value={Osztaly2E.Illuzionista}>{OsztalyLabel(Osztaly2E.Illuzionista)}</option>
</optgroup>
<optgroup label='Opcionális'>
<option value={Osztaly2E.Dalnok}>{OsztalyLabel(Osztaly2E.Dalnok)}</option>
{/* Druida nem lehet tobb osztalyu karakter! */}
<option value={Osztaly2E.Vandor}>{OsztalyLabel(Osztaly2E.Vandor)}</option>
</optgroup>
</select>
</div>
</div>
</div>
<div className="col-lg-6">
<div className="row m-2">
<label className='col-sm-6 col-8 col-form-label'>Új {OsztalyLabel(osztaly)} szint{' '}</label>
<span className='col col-form-label'>{osztalySzint}</span>
</div>
</div>
</div>
</>
}
export default MultiClassOsztalySelector2E
@@ -2,7 +2,7 @@ import React from "react";
import {Faj2E, FajLabel} from "../domain-models/faj2E";
import {Modifier} from "../domain-models/tulajdonsag2E";
import {SignedNumberToText} from "../../shared/components/Helpers";
import {SignedNumberToText} from "../../shared/helpers";
function fajiModositoText(faj: Faj2E, szamolas: (f: Faj2E) => number) : string {
@@ -487,7 +487,7 @@
"Harcos": true,
"CsakNemHarcos": false,
"Masfelkezes": false,
"Ketkezes": true,
"Ketkezes": false,
"KetkezesBonusz": false,
"HarciManover": false,
"Alakzat": false,
@@ -10,13 +10,14 @@ import {BaseHP} from "./masodlagos_ertekek";
import {dAny} from "../../shared/domain-models/kockak";
export interface Karakter2E {
nev: string,
name: string,
nem?: string,
kor: number,
isten?: string,
jellem: JellemID,
tulajdonsagok: KarakterTulajdonsagok
faj: Faj2E
osztaly: Osztaly2E
kepzettsegek: KepzettsegId[]
tolvajKepzettsegek?: KepzettsegId[]
szint: number,
@@ -25,11 +26,12 @@ export interface Karakter2E {
}
export const DefaultKarakter: Karakter2E = {
nev: 'Névtelen Kalandozó',
name: 'Névtelen Kalandozó',
kor: 20,
jellem: 'S',
tulajdonsagok: TulajdonsagDefaults,
faj: Faj2E.Ember,
osztaly: Osztaly2E.Tengeresz,
kepzettsegek: [],
tolvajKepzettsegek: [],
szint: 1,
@@ -40,93 +42,34 @@ export const DefaultKarakter: Karakter2E = {
}]
}
function setOsztalyForSzintLepes(szintlepesek: Szintlepes[], osztaly: Osztaly2E, szint: number): Szintlepes[] {
const prev = szintlepesek.slice(0, szint-1)
const current : Szintlepes = {
...szintlepesek[szint-1],
function setOsztalyForSzintLepes(szintlepes: Szintlepes, osztaly: Osztaly2E, szint: number): Szintlepes {
const base : Szintlepes = {
...szintlepes,
osztaly,
harcosFegyver: undefined,
kalozKritikus: undefined
}
const tail = szintlepesek.slice(szint).map(x => {return {...x}})
let harcosSzint = prev.filter(x => x.osztaly === Osztaly2E.Harcos).length
// TODO: only pick specializations from valid levels
const harcosSpecializaciok = szintlepesek
.map(x => x.harcosFegyver)
.filter(x => x != null)
const harcosSpecAtSzint = (hSzint: number): (string | undefined) => {
if (hSzint % 2 === 1) {
const specIndex = (hSzint+1)/2 -1
if (harcosSpecializaciok.length > specIndex ) {
return harcosSpecializaciok[specIndex]
} else {
return AllowedFegyver(Osztaly2E.Harcos)[specIndex].Id
if (osztaly === Osztaly2E.Harcos && szint % 2 === 1) {
base.harcosFegyver = AllowedFegyver(Osztaly2E.Harcos)[szint].Id
}
if (osztaly === Osztaly2E.Tengeresz && szint % 3 === 0) {
base.kalozKritikus = AllowedFegyver(Osztaly2E.Tengeresz)[szint].Id
}
else {
return undefined
}
}
if (osztaly === Osztaly2E.Harcos) {
harcosSzint += 1
current.harcosFegyver = harcosSpecAtSzint(harcosSzint)
}
for (let i = 0; i < tail.length; i++) {
if (tail[i].osztaly === Osztaly2E.Harcos) {
harcosSzint++
tail[i].harcosFegyver = harcosSpecAtSzint(harcosSzint)
}
}
let kalozSzint = prev.filter(x => x.osztaly === Osztaly2E.Tengeresz).length
const existingKalozKrits = szintlepesek
.map(x => x.kalozKritikus)
.filter(x => x != null)
const kalozKritAtSzint = (kSzint: number): (string | undefined) => {
if (kSzint % 3 === 0) {
const specIndex = kSzint/3 -1
if (existingKalozKrits.length > specIndex ) {
return existingKalozKrits[specIndex]
} else {
return AllowedFegyver(Osztaly2E.Tengeresz)[specIndex].Id
}
}
else {
return undefined
}
}
if (osztaly === Osztaly2E.Tengeresz) {
kalozSzint++
current.kalozKritikus = kalozKritAtSzint(szint)
}
for (let i = 0; i < tail.length; i++) {
if (tail[i].osztaly === Osztaly2E.Tengeresz) {
kalozSzint++
tail[i].kalozKritikus = kalozKritAtSzint(kalozSzint)
}
}
const HD = BaseHP(osztaly)
if (szint === 1) {
current.HProll = HD
base.HProll = HD
} else {
current.HProll = dAny(HD)
console.log(`Level ${szint} HP roll on d${HD} is: ${current.HProll} due to class change`)
base.HProll = dAny(HD)
console.log(`Level ${szint} HP roll on d${HD} is: ${base.HProll} due to class change`)
}
return [...prev, current, ...tail]
return base
}
export function ChangeLvl1Osztaly(karakter: Karakter2E, osztaly: Osztaly2E): Karakter2E {
return {
...karakter,
szintlepesek: [{...karakter.szintlepesek[0], HProll: BaseHP(osztaly) , osztaly}, ...karakter.szintlepesek.slice(1)]
}
}
export function ChangeOsztalyAtSzint(karakter: Karakter2E, osztaly: Osztaly2E, szint: number): Karakter2E {
return {
...karakter,
szintlepesek: setOsztalyForSzintLepes(karakter.szintlepesek, osztaly, szint)
osztaly,
szintlepesek: karakter.szintlepesek.map((l, idx) => setOsztalyForSzintLepes(l, osztaly, idx +1))
}
}
@@ -209,12 +209,12 @@ 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 AvailableKezpettsegList(osztaly: Osztaly2E): Kepzettseg[] {
return KepzettsegLista.filter(k => k.Osztalyok == null || k.Osztalyok.includes(osztaly))
}
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 + 4 // 3 base, 1 human, 3 from max ability modifier, 4 from Thief
let numberOfKepzettseg = 3 + Modifier(t_int) + (faj === Faj2E.Ember ? 1 : 0)
if (numberOfKepzettseg < 1) {
@@ -228,20 +228,18 @@ export function GetNumberOfKepzettsegek(t_int: number, faj: Faj2E, max: number =
return numberOfKepzettseg;
}
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) {
export function SetDefaultTolvajKepzettsegek(karakter: Pick<Karakter2E, 'osztaly' | 'szintlepesek' | 'tolvajKepzettsegek'>, changeTolvajKepzettsegek: (tolvajKepzettsegek?: KepzettsegId[]) => void) {
if (karakter.osztaly !== Osztaly2E.Tolvaj && karakter.tolvajKepzettsegek != null) {
changeTolvajKepzettsegek(undefined)
}
if (hasTolvajSzint && (karakter.tolvajKepzettsegek == null || karakter.tolvajKepzettsegek.length === 0)) {
if (karakter.osztaly === Osztaly2E.Tolvaj && (karakter.tolvajKepzettsegek == null || karakter.tolvajKepzettsegek.length === 0)) {
const tolvajKepzettsegek = TolvajKepzettsegList.slice(0, 4).map(x => x.Id)
changeTolvajKepzettsegek(tolvajKepzettsegek)
}
}
export function GetKepzettsegListaN(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>) {
const osztalyok = new Set(karakter.szintlepesek.map(x => x.osztaly))
const availableKepzettsegList = AvailableKezpettsegList(...osztalyok)
export function GetKepzettsegListaN(karakter: Pick<Karakter2E, 'osztaly' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>) {
const availableKepzettsegList = AvailableKezpettsegList(karakter.osztaly)
return (n: number): Kepzettseg[] => {
let available = [...availableKepzettsegList]
if (n === 0) {
@@ -251,8 +249,7 @@ export function GetKepzettsegListaN(karakter: Pick<Karakter2E, 'szintlepesek' |
if (karakter.faj === Faj2E.Nomad) {
return [Kepzettsegek.k_lovaglas]
}
// TODO birodalmi tolvaj, tolvajképzettségek!
if (karakter.faj === Faj2E.Birodalmi) {
if (karakter.faj === Faj2E.Birodalmi && karakter.osztaly !== Osztaly2E.Tolvaj) {
return [Kepzettsegek.k_alkimia, Kepzettsegek.k_meregkeveres, Kepzettsegek.k_okkultizmus]
}
if (karakter.faj === Faj2E.Torpe) {
@@ -261,38 +258,30 @@ export function GetKepzettsegListaN(karakter: Pick<Karakter2E, 'szintlepesek' |
if (karakter.faj === Faj2E.Elf || karakter.faj === Faj2E.Felelf) {
return [Kepzettsegek.k_vadonjaras]
}
if (osztalyok.has(Osztaly2E.Druida) || osztalyok.has(Osztaly2E.Vandor)) {
if (karakter.osztaly === Osztaly2E.Druida || karakter.osztaly === Osztaly2E.Vandor) {
return [Kepzettsegek.k_vadonjaras]
}
if (osztalyok.has(Osztaly2E.Dalnok)) {
if (karakter.osztaly === 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) {
if (karakter.osztaly === Osztaly2E.Dalnok
&& [Faj2E.Eszaki, Faj2E.Nomad, Faj2E.Birodalmi, Faj2E.Torpe, Faj2E.Elf, Faj2E.Felelf].includes(karakter.faj)) {
return [Kepzettsegek.k_eloadas]
}
if ([Osztaly2E.Druida, Osztaly2E.Vandor].includes(karakter.osztaly)
&& [Faj2E.Eszaki, Faj2E.Nomad, Faj2E.Birodalmi, Faj2E.Torpe].includes(karakter.faj)) {
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))
}
}
export function SetDefaultKepzettsegek(karakter: Pick<Karakter2E, 'szintlepesek' | 'faj' | 'tulajdonsagok' | 'kepzettsegek' | 'tolvajKepzettsegek'>, changeKepzettsegek: (k: KepzettsegId[]) => void) {
const osztalyok = karakter.szintlepesek.map(x => x.osztaly)
const availableKepzettsegList = AvailableKezpettsegList(...osztalyok)
export function SetDefaultKepzettsegek(karakter: Pick<Karakter2E, 'osztaly' | 'faj' | 'tulajdonsagok' | 'kepzettsegek' | 'tolvajKepzettsegek'>, changeKepzettsegek: (k: KepzettsegId[]) => void) {
const availableKepzettsegList = AvailableKezpettsegList(karakter.osztaly)
const numberOfKepzettsegek = GetNumberOfKepzettsegek(karakter.tulajdonsagok.t_int, karakter.faj, availableKepzettsegList.length)
let kepzettsegek = [...karakter.kepzettsegek]
@@ -14,7 +14,7 @@ export interface MasodlagosErtekekView {
Mentok: Mentok
}
export type KarakterpickForMasodlagosErtekek = Pick<Karakter2E, 'tulajdonsagok' | 'szint' | 'szintlepesek' | 'faj' | 'felszereles'>
export type KarakterpickForMasodlagosErtekek = Pick<Karakter2E, 'osztaly' | 'tulajdonsagok' | 'szint' | 'szintlepesek' | 'faj' | 'felszereles'>
export function BaseHP(osztaly: Osztaly2E) {
let base = 4;
@@ -45,7 +45,7 @@ export function BaseHP(osztaly: Osztaly2E) {
return base
}
export function HP(karakter: Pick<Karakter2E, 'tulajdonsagok' | 'szintlepesek'>): number {
export function HP(karakter: Pick<Karakter2E, 'osztaly' | 'tulajdonsagok' | 'szintlepesek'>): number {
const egeszsegModifier = Modifier(karakter.tulajdonsagok.t_egs)
return karakter.szintlepesek
// https://lfg.hu/forum/topic/15079-kard-es-magia/page/219/#comment-2218333
@@ -53,26 +53,7 @@ export function HP(karakter: Pick<Karakter2E, 'tulajdonsagok' | 'szintlepesek'>)
.reduce((sum, val) => sum + val, 0)
}
export function VOegyeb(karakter: Pick<Karakter2E, 'faj'| 'szintlepesek'>): number {
const osztalyok = new Set(karakter.szintlepesek.map(x => x.osztaly))
let vo = 0;
if (osztalyok.has(Osztaly2E.Tengeresz)) {
const kalozSzintek = karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Tengeresz).length
vo += Math.floor(kalozSzintek / 3)
}
if (osztalyok.has(Osztaly2E.Amazon)) {
const amazonSzintek = karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Amazon).length
vo += Math.floor(amazonSzintek / 2)
}
if (karakter.faj === Faj2E.Felszerzet || karakter.faj === Faj2E.Gnom){
vo += 1
}
return vo;
}
export function VO(karakter: Pick<Karakter2E, 'tulajdonsagok' | 'faj' | 'szintlepesek' | 'szint' | 'felszereles'>): number {
const osztalyok = new Set(karakter.szintlepesek.map(x => x.osztaly))
export function VO(karakter: Pick<Karakter2E, 'tulajdonsagok' | 'faj' | 'osztaly' | 'szint' | 'felszereles'>): number {
const pancel = GetPancel(karakter.felszereles.pancelID)
const pancelVO = pancel?.VO ?? 0
const pajzsVO = GetPajzs(karakter.felszereles.pajzsID)?.VO ?? 0
@@ -81,12 +62,18 @@ export function VO(karakter: Pick<Karakter2E, 'tulajdonsagok' | 'faj' | 'szintle
if (pancel) {
abilityVO = Math.min(MaxAbilityVO(pancel.Type), abilityVO)
}
if (osztalyok.has(Osztaly2E.Amazon)){
if (karakter.osztaly === Osztaly2E.Tengeresz) {
vo += Math.floor(karakter.szint / 3)
}
if (karakter.osztaly === Osztaly2E.Amazon) {
if (karakter.tulajdonsagok.t_kar > karakter.tulajdonsagok.t_ugy) {
abilityVO = Modifier(karakter.tulajdonsagok.t_kar)
}
vo += Math.floor(karakter.szint / 2)
}
if (karakter.faj === Faj2E.Felszerzet || karakter.faj === Faj2E.Gnom){
vo += 1
}
vo += VOegyeb(karakter)
vo += abilityVO
return vo
@@ -1,7 +1,6 @@
import {Osztaly2E} from "./osztaly2E";
import {Karakter2E} from "./karakter2E";
import {KarakterTulajdonsagok, TulajdonsagModosito} from "./tulajdonsag2E";
import {Szintlepes} from "./szintlepes";
export interface Mentok {
kitartas: number
@@ -74,26 +73,8 @@ export function MentoModositok(tulajdonsagModositok: KarakterTulajdonsagok) {
}
}
export function MultiClassMentokAlap(szintlepesek: Szintlepes[]) : Mentok {
const osztalyok = new Set(szintlepesek.map(x => x.osztaly))
let mentok = {
kitartas: 0,
reflex: 0,
akaratero: 0
}
for (const osztaly of osztalyok) {
const szint = szintlepesek.filter(x => x.osztaly === osztaly).length
const uj_mentok = MentokAlap(osztaly, szint)
mentok.akaratero += uj_mentok.akaratero
mentok.reflex += uj_mentok.reflex
mentok.kitartas += uj_mentok.kitartas
}
return mentok
}
export function MentokTotal(karakter: Pick<Karakter2E, 'szintlepesek' | 'tulajdonsagok'>) {
const alap = MultiClassMentokAlap(karakter.szintlepesek)
export function MentokTotal(karakter: Pick<Karakter2E, 'osztaly' | 'szint' | 'tulajdonsagok'>) {
const alap = MentokAlap(karakter.osztaly, karakter.szint)
const modositok = MentoModositok(TulajdonsagModosito(karakter.tulajdonsagok))
return {
kitartas: alap.kitartas + modositok.kitartas,
@@ -9,12 +9,9 @@ import {AllowedFegyver} from "./allowed-fegyver";
export interface Szintlepes {
osztaly: Osztaly2E;
HProll: number;
// only at level 5 and 9
tolvajExtraKepzettseg?: KepzettsegId;
// every odd level
harcosFegyver?: string;
// every 3rd level
kalozKritikus?: string;
tolvajExtraKepzettseg?: KepzettsegId; // only at level 5 and 9
harcosFegyver?: string; // every 3rd level
kalozKritikus?: string; // every odd level
tulajdonsagNoveles?: Tulajdonsag2E;
}
@@ -23,15 +20,14 @@ export function PickableSpecializationFilter(existingSpecilizations: (string | u
}
export function LevelUp(karakter: Karakter2E, changeKarakter: (input: Karakter2E) => void) {
const osztaly = karakter.szintlepesek[0].osztaly
const tulajdonsagokTotal = TulajdonsagokTotal(karakter)
const szint = karakter.szint + 1
const dice = BaseHP(osztaly)
const dice = BaseHP(karakter.osztaly)
const roll = dAny(dice)
console.log(`Level ${szint} HP roll on d${dice} is: ${roll}`)
const szintlepes: Szintlepes = {
osztaly: osztaly,
osztaly: karakter.osztaly,
HProll: roll
}
@@ -43,23 +39,14 @@ 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 (harcosSzint % 2 === 1) {
if(karakter.osztaly === Osztaly2E.Harcos && szint % 2 === 1) {
const harcosSpecializaciok = karakter.szintlepesek.map(x => x.harcosFegyver)
let specializationFilter = PickableSpecializationFilter(harcosSpecializaciok, harcosSzint)
szintlepes.harcosFegyver = AllowedFegyver(Osztaly2E.Harcos).filter(specializationFilter)[0].Id
szintlepes.harcosFegyver = AllowedFegyver(Osztaly2E.Harcos).filter(PickableSpecializationFilter(harcosSpecializaciok, karakter.szint))[0].Id
}
}
if(osztaly === Osztaly2E.Tengeresz) {
const kalozSzint = karakter.szintlepesek.filter(x => x.osztaly === Osztaly2E.Tengeresz).length + 1
if (kalozSzint % 3 === 0) {
if(karakter.osztaly === Osztaly2E.Tengeresz && szint % 3 === 0) {
let kalozKritikus = karakter.szintlepesek.map(x => x.kalozKritikus)
let specializationFilter = PickableSpecializationFilter(kalozKritikus, kalozSzint)
szintlepes.kalozKritikus = AllowedFegyver(Osztaly2E.Tengeresz).filter(specializationFilter)[0].Id
szintlepes.kalozKritikus = AllowedFegyver(Osztaly2E.Tengeresz).filter(PickableSpecializationFilter(kalozKritikus, szint))[0].Id
}
}
changeKarakter({...karakter, szint, szintlepesek: [...karakter.szintlepesek, szintlepes]})
}
@@ -71,32 +58,3 @@ export function LevelDown(karakter: Karakter2E, changeKarakter: (input: Karakter
console.error(`Can't level down character: ${karakter}`)
}
}
export type ClassLevels = {
[key in Osztaly2E]: number;
};
const defaultClassLevels: ClassLevels = {
[Osztaly2E.Amazon]: 0,
[Osztaly2E.Barbar]: 0,
[Osztaly2E.Ijasz]: 0,
[Osztaly2E.Harcos]: 0,
[Osztaly2E.Tengeresz]: 0,
[Osztaly2E.Tolvaj]: 0,
[Osztaly2E.Pap]: 0,
[Osztaly2E.Varazslo]: 0,
[Osztaly2E.Illuzionista]: 0,
[Osztaly2E.Dalnok]: 0,
[Osztaly2E.Druida]: 0,
[Osztaly2E.Vandor]: 0,
}
export function getClassLevels(szintlepesek: Szintlepes[]) : ClassLevels {
return szintlepesek.map(x => x.osztaly).reduce((classLevels, osztaly) => {
classLevels[osztaly]++
return classLevels
}, {...defaultClassLevels})
}
@@ -1,7 +1,6 @@
import {Osztaly2E} from "./osztaly2E";
import {Karakter2E} from "./karakter2E";
import {Modifier} from "./tulajdonsag2E";
import {Szintlepes} from "./szintlepes";
/// Finally second edition doesn't mess with the extra attack of high level clerics rouges and wizards!
function ExtraAttack(attack: number): number[] {
@@ -11,31 +10,6 @@ function ExtraAttack(attack: number): number[] {
return [Math.min(attack, 10), ...ExtraAttack(attack - 5)]
}
export function TamadasBonuszBase(osztaly: Osztaly2E, szint: number = 1) : number {
let base = 0
switch (osztaly){
case Osztaly2E.Barbar:
case Osztaly2E.Amazon:
case Osztaly2E.Ijasz:
case Osztaly2E.Tengeresz:
case Osztaly2E.Harcos:
case Osztaly2E.Vandor:
base = szint;
break;
case Osztaly2E.Pap:
case Osztaly2E.Tolvaj:
case Osztaly2E.Dalnok:
case Osztaly2E.Druida:
base = Math.floor(szint * 2 / 3);
break;
case Osztaly2E.Varazslo:
case Osztaly2E.Illuzionista:
base = Math.floor(szint / 2);
break;
}
return base
}
export function TamadasBonusz(osztaly: Osztaly2E, szint: number = 1) : number[] {
let base = 0
switch (osztaly){
@@ -61,23 +35,12 @@ export function TamadasBonusz(osztaly: Osztaly2E, szint: number = 1) : number[]
return ExtraAttack(base)
}
export function MultiClassTamadasBonusz(szintlepesek: Szintlepes[]) : number[]{
const osztalyok = new Set(szintlepesek.map(x => x.osztaly))
let TBB = 0
for (const osztaly of osztalyok) {
const szint = szintlepesek.filter(x => x.osztaly === osztaly).length
TBB += TamadasBonuszBase(osztaly, szint)
}
return ExtraAttack(TBB)
}
export function KozelharciTB(karakter : Pick<Karakter2E, 'szintlepesek' | 'tulajdonsagok'>): number[] {
const base = MultiClassTamadasBonusz(karakter.szintlepesek);
export function KozelharciTB(karakter : Pick<Karakter2E, 'szint' | 'tulajdonsagok' | 'osztaly'>): number[] {
const base = TamadasBonusz(karakter.osztaly, karakter.szint);
let modifier = Modifier(karakter.tulajdonsagok.t_ero)
return base.map(v => v + modifier)
}
export function CelzoTB(karakter : Pick<Karakter2E, 'szintlepesek' | 'tulajdonsagok'>): number[] {
let base = MultiClassTamadasBonusz(karakter.szintlepesek)
export function CelzoTB(karakter : Pick<Karakter2E, 'szint' | 'tulajdonsagok' | 'osztaly'>): number[] {
let base = TamadasBonusz(karakter.osztaly, karakter.szint)
return base.map(v => v + Modifier(karakter.tulajdonsagok.t_ugy))
}
@@ -1,7 +1,7 @@
import React, {useContext, useState} from 'react'
import {useLoaderData, useNavigate, useParams} from "react-router-dom";
import {Button, InputGroup, Modal, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap";
import {ChangeLvl1Osztaly, DefaultKarakter, Karakter2E} from "../domain-models/karakter2E";
import React, {useState} from 'react'
import {useParams} from "react-router-dom";
import {Toast, ToastContainer} from "react-bootstrap";
import {ChangeLvl1Osztaly, DefaultKarakter} from "../domain-models/karakter2E";
import {KarakterTulajdonsagok} from "../domain-models/tulajdonsag2E";
import FajSelector2E from "../components/FajSelector2E";
import Tulajdonsagok2E from "../components/Tulajdonsagok2E";
@@ -24,33 +24,12 @@ import LevelUps from "../components/LevelUps";
import {LevelDown, LevelUp} from "../domain-models/szintlepes";
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpec";
import {arraySetN} from "../../util";
import saveOverlayTooltip from "../../first-edition/components/SaveOverlayTooltip";
import {UserContext} from "../../shared/contexts/UserContext";
import {
StoreNewCharacter2E,
UpdateCharacter2E
} from "../api/character.api";
import {Faro} from "@grafana/faro-web-sdk";
import Form from "react-bootstrap/Form";
import {CreatePDF} from "../pdf/character.pdf";
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
function CreateCharacter2E(props: {
faro?: Faro
}) {
const {faro} = props
function CreateCharacter2E(props: {}) {
const { id } = useParams();
const fetchedUser = useContext(UserContext);
const loaderData = useLoaderData() as Karakter2E & { isPublic: boolean } | undefined;
let initialKarakterInputs = DefaultKarakter;
if (loaderData != null) {
const { isPublic: t1, ...t2 } = loaderData;
initialKarakterInputs = t2
}
const initialIsPublic = loaderData?.isPublic ?? fetchedUser?.data == null;
const navigate = useNavigate();
const [karakter, setKarakter] = useState(initialKarakterInputs)
const [karakter, setKarakter] = useState(DefaultKarakter)
const tulajdonsagokFajjal = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
const changeKepzettseg = (k: KepzettsegId[]) => setKarakter({...karakter, kepzettsegek: k})
const changeTolvajKepzettseg = (tk?: KepzettsegId[]) => setKarakter({...karakter, tolvajKepzettsegek: tk})
@@ -59,43 +38,8 @@ function CreateCharacter2E(props: {
const changeFelszereles = (f: KarakterFelszereles) => setKarakter({...karakter, felszereles: f})
let [showSaveModal, setShowSaveModal] = useState(false);
let [newId, setNewId] = useState(null as string | null)
let [showSaved, setShowSaved] = useState(false);
let [isPublic, setIsPublic] = useState(initialIsPublic);
const newCharacterUrl = () => `${window.location.origin}/2e/karakter/${newId}`
const handleSaveModalCopyAndClose = async () => {
await navigator.clipboard.writeText(newCharacterUrl());
handleSaveModalClose()
}
const handleSaveModalClose = () => {
setShowSaveModal(false);
navigate(`/2e/karakter/${newId}`)
}
const hideSaved = () => setShowSaved(false);
const onSaveClicked = async () => {
faro?.api.pushEvent('character_stored', {
osztaly: karakter.szintlepesek[0].osztaly.toString(),
szint: karakter.szint.toString(),
faj: karakter.faj.toString(),
is_public: isPublic.toString(),
edition: "2e",
})
if (id == null) {
let recievedId = await StoreNewCharacter2E(karakter, isPublic);
setNewId(recievedId)
setShowSaveModal(true);
} else {
await UpdateCharacter2E(id, karakter, isPublic);
setShowSaved(true);
setTimeout(() => {
hideSaved();
}, 5000)
}
}
return <div>
<div className='container-fluid p-5 bg-black text-white text-center'>
@@ -106,28 +50,6 @@ function CreateCharacter2E(props: {
<Toast.Header><strong>Karakter mentve!</strong></Toast.Header>
</Toast>
</ToastContainer>
<Modal show={showSaveModal} onHide={handleSaveModalClose}>
<Modal.Header closeButton>
<Modal.Title>Karakter mentve!</Modal.Title>
</Modal.Header>
<Modal.Body>
<p>Karaktered az alábbi {isPublic ? 'publikus' : 'privát'} URLen érhető el.</p>
<p><a href={newCharacterUrl()}>{newCharacterUrl()}</a></p>
<InputGroup className="mb-3">
<Form.Control id="input" value={newCharacterUrl()} />
<Button variant={"outline-dark"} onClick={() => {
let copyText = document.querySelector("#input") as any;
copyText?.select()
document.execCommand("copy");
}}>Másolás</Button>
</InputGroup>
</Modal.Body>
<Modal.Footer>
<Button variant="danger" onClick={handleSaveModalCopyAndClose}>
Másolás és bezárás
</Button>
</Modal.Footer>
</Modal>
<div className='p-3'>
<form onSubmit={async (event) => event.preventDefault()}>
<div className='row'>
@@ -136,9 +58,9 @@ function CreateCharacter2E(props: {
<div className='row m-2'>
<label className='col-md-2 col-sm-3 col-form-label'>Név</label>
<input className='col form-control'
value={karakter.nev}
onChange={(e) => setKarakter({...karakter, nev: e.target.value})}/>
{!karakter.nev &&
value={karakter.name}
onChange={(e) => setKarakter({...karakter, name: e.target.value})}/>
{!karakter.name &&
<span className='form-field-error'>A karaktered nem mászkálhat névtelenül a világban!</span>}
</div>
<div className='row m-2'>
@@ -181,19 +103,14 @@ function CreateCharacter2E(props: {
</div>
<OsztalySelector2E
currentFaj={karakter.faj}
currentOsztaly={karakter.szintlepesek[0].osztaly}
currentOsztaly={karakter.osztaly}
changeOsztaly={o => setKarakter(ChangeLvl1Osztaly(karakter, o))}
/>
{karakter.szintlepesek[0].osztaly === Osztaly2E.Harcos &&
<HarcosFegyverSpecializacio
specialization={karakter.szintlepesek[0].harcosFegyver || 'kard_hosszu'}
szint={1}
changeSpecialization={(spec) => setKarakter({...karakter,
szintlepesek: arraySetN(karakter.szintlepesek, 0, {
...karakter.szintlepesek[0],
harcosFegyver: spec
})
})}
changeSpecialization={(spec) => setKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, 0, {...karakter.szintlepesek[0], harcosFegyver: spec})})}
existingSpecializations={karakter.szintlepesek.map(x => x.harcosFegyver)}
/>}
<KarakterKepzettsegek
@@ -217,12 +134,10 @@ function CreateCharacter2E(props: {
{karakter.szint > 1 && <hr/>}
<div className='d-grid gap-2 m-5'>
{karakter.szint < 12 &&
<button className='btn btn-dark btn-lg' type='button'
onClick={() => LevelUp(karakter, setKarakter)}>Szintlépés!
<button className='btn btn-dark btn-lg' type='button' onClick={() => LevelUp(karakter, setKarakter)}>Szintlépés!
</button>}
{karakter.szint > 1 &&
<button className='btn btn-dark btn-lg' type='button'
onClick={() => LevelDown(karakter, setKarakter)}>Visszalépés!
<button className='btn btn-dark btn-lg' type='button' onClick={() => LevelDown(karakter, setKarakter)}>Visszalépés!
</button>}
</div>
<hr/>
@@ -230,64 +145,9 @@ function CreateCharacter2E(props: {
changeFelszereles={changeFelszereles}/>
<hr/>
<div className='row'>
<h5 className='col align-self-center'>Véglegesítés</h5>
</div>
{fetchedUser.data != null &&
<div className='row m-2'>
<label className='col-md-2 col-sm-3 col-form-label'>Publikus karakterlap?</label>
<select className="col form-select" value={isPublic.toString()}
onChange={(event) => setIsPublic(event.target.value === "true")}>
<option value="true">Igen</option>
<option value="false">Nem</option>
</select>
</div>
}
<div className="row">
<div className="col-6">
<div className='d-grid gap-2 m-5'>
{fetchedUser.data == null
? <OverlayTrigger
placement='top'
overlay={saveOverlayTooltip}
delay={0}
defaultShow={false}
flip={false}
>
<button
className='btn btn-danger btn-lg'
type='button'
onClick={onSaveClicked}
>
Mentés
</button>
</OverlayTrigger>
: <button
className='btn btn-danger btn-lg'
type='button'
onClick={onSaveClicked}
>
Mentés
</button>
}
</div>
</div>
<div className="col-6">
<div className='d-grid gap-2 m-5'>
<button className='btn btn-danger btn-lg' type='button' onClick={async () => {
faro?.api.pushEvent('character_created', {
osztaly: karakter.szintlepesek[0].osztaly,
szint: karakter.szint.toString(),
faj: karakter.faj.toString(),
})
await CreatePDF(KarakterInputToPdfView(karakter))
}}>PDF</button>
</div>
</div>
</div>
</form>
</div>
<hr/>
</div>
}
@@ -1,90 +0,0 @@
import {KarakterPdfView} from "./karakter_pdf_view";
import {PDFDocument} from "pdf-lib";
import fontkit from "@pdf-lib/fontkit";
import download from "downloadjs";
import {SignedNumberToText} from "../../shared/components/Helpers";
export async function CreatePDF(karakter: KarakterPdfView) {
const existingPdfBytes = await fetch('/pdfs/kem2karakterlap_form.pdf').then(res => res.arrayBuffer())
const pdfDoc = await PDFDocument.load(existingPdfBytes)
pdfDoc.registerFontkit(fontkit)
const fontBytes = await fetch('/fonts/Milonga-Regular.ttf').then(res => res.arrayBuffer())
const pdfFont = await pdfDoc.embedFont(fontBytes)
const form = pdfDoc.getForm()
const osztalyok = karakter.Osztaly.length > 1 ? karakter.Osztaly.map(x => `${x.osztaly} (${x.szint})`).join(", ") : karakter.Osztaly[0].osztaly
form.getTextField("nev_faj_osztaly").setText(`${karakter.Nev}, ${karakter.Faj} ${osztalyok}`)
form.getTextField("szint").setText((karakter.SzintTotal.length > 1 ? " " : " ") + karakter.SzintTotal)
form.getTextField("jellem").setText(karakter.Jellem)
form.getTextField("istenseg").setText(karakter.Isten)
form.getTextField("vo").setText(karakter.VO.toString())
form.getTextField("pancel").setText(" " + karakter.PancelVO)
form.getTextField("pajzs").setText(" " + karakter.PajzsVO)
form.getTextField("egyeb_vo").setText(" " + karakter.EgyebVO)
form.getTextField("tul_ero").setText(` ${karakter.Tulajdonsagok.t_ero}`)
form.getTextField("tul_ero_mod").setText(SignedNumberToText(karakter.TulajdonsagModositok.t_ero))
form.getTextField("tul_ugy").setText(` ${karakter.Tulajdonsagok.t_ugy}`)
form.getTextField("tul_ugy_mod").setText(SignedNumberToText(karakter.TulajdonsagModositok.t_ugy))
form.getTextField("tul_egs").setText(` ${karakter.Tulajdonsagok.t_egs}`)
form.getTextField("tul_egs_mod").setText(SignedNumberToText(karakter.TulajdonsagModositok.t_egs))
form.getTextField("tul_int").setText(` ${karakter.Tulajdonsagok.t_int}`)
form.getTextField("tul_int_mod").setText(SignedNumberToText(karakter.TulajdonsagModositok.t_int))
form.getTextField("tul_bol").setText(` ${karakter.Tulajdonsagok.t_bol}`)
form.getTextField("tul_bol_mod").setText(SignedNumberToText(karakter.TulajdonsagModositok.t_bol))
form.getTextField("tul_kar").setText(` ${karakter.Tulajdonsagok.t_kar}`)
form.getTextField("tul_kar_mod").setText(SignedNumberToText(karakter.TulajdonsagModositok.t_kar))
form.getTextField("hp_rolls").setText(karakter.HPszintenkent.join(", "))
form.getTextField("hp_aktualis").setText(karakter.HP.toString())
form.getTextField("kitartas_alap").setText(" " + karakter.MentokAlap.kitartas.toString())
form.getTextField("kitartas_mod").setText(" " + SignedNumberToText(karakter.MentoModositok.kitartas))
form.getTextField("kitartas_sum").setText(" " + karakter.MentokModositokkal.kitartas.toString())
form.getTextField("reflex_alap").setText(" " + karakter.MentokAlap.reflex.toString())
form.getTextField("reflex_mod").setText(" " + SignedNumberToText(karakter.MentoModositok.reflex))
form.getTextField("reflex_sum").setText(" " + karakter.MentokModositokkal.reflex.toString())
form.getTextField("akaratero_alap").setText(" " + karakter.MentokAlap.akaratero.toString())
form.getTextField("akaratero_mod").setText(" " + SignedNumberToText(karakter.MentoModositok.akaratero))
form.getTextField("akaratero_sum").setText(" " + karakter.MentokModositokkal.akaratero.toString())
form.getTextField("kezdemenyezes").setText(" " + SignedNumberToText(karakter.Kezdemenyezes))
form.getTextField("tamadas_bonusz_alap").setText(karakter.TamadasBonuszAlap.join("/"))
form.getTextField("tamadas_bonusz_ero").setText(" " + SignedNumberToText(karakter.TulajdonsagModositok.t_ero))
form.getTextField("tamadas_bonusz_kozelharc").setText(karakter.KozelharciTB.join("/"))
form.getTextField("tamadas_bonusz_ugy").setText(" " + SignedNumberToText(karakter.TulajdonsagModositok.t_ugy))
form.getTextField("tamadas_bonusz_tavolsagi").setText(karakter.CelzoTB.join("/"))
for (let i = 0; i < karakter.Kepzettsegek.length; i++) {
const kepzettseg = karakter.Kepzettsegek[i]
form.getTextField(`kepzettseg_${i}_nev`).setText(kepzettseg.nev)
form.getTextField(`kepzettseg_${i}_alap`).setText(kepzettseg.alap)
form.getTextField(`kepzettseg_${i}_bonusz`).setText(kepzettseg.bonusz)
form.getTextField(`kepzettseg_${i}_osszes`).setText(kepzettseg.osszes)
}
for (let i = 0; i < karakter.Fegyverek.length; i++) {
form.getTextField(`fegyver_${i+1}`).setText(karakter.Fegyverek[i])
}
for (let i = 0; i < karakter.FelszerelesViselt.length && i < 8; i++) {
form.getTextField(`viselt_${i}`).setText(karakter.FelszerelesViselt[i])
}
for (let i = 0; i < karakter.FelszerelesCipelt.length && i < 8; i++) {
form.getTextField(`cipelt_${i}`).setText(karakter.FelszerelesCipelt[i])
}
for (let i = 0; i < karakter.FelszerelesAprosagok.length && i < 8; i++) {
form.getTextField(`aprosagok_${i}`).setText(karakter.FelszerelesAprosagok[i])
}
form.updateFieldAppearances(pdfFont)
const pdfBytes = await pdfDoc.save();
download(pdfBytes, `${karakter.Nev}_${karakter.SzintTotal}.pdf`, "application/pdf");
}
@@ -1,176 +0,0 @@
import {Modifier, TulajdonsagokTotal} from "../domain-models/tulajdonsag2E";
import {Mentok, MentoModositok, MultiClassMentokAlap} from "../domain-models/mentok";
import {CalculateMasodlagosErtekek, VOegyeb} from "../domain-models/masodlagos_ertekek";
import {FajLabel} from "../domain-models/faj2E";
import {Osztaly2E, OsztalyLabel} from "../domain-models/osztaly2E";
import {CelzoTB, KozelharciTB, MultiClassTamadasBonusz} from "../domain-models/tamadas_bonusz";
import {Karakter2E} from "../domain-models/karakter2E";
import {GetJellem} from "../domain-models/jellem";
import {GetFegyver, GetPajzs, GetPancel} from '../domain-models/felszereles'
import {
KarakterTulajdonsagok,
TulajdonsagModosito
} from "../domain-models/tulajdonsag2E";
import {SignedNumberToText} from "../../shared/components/Helpers";
import {Kepzettseg, Kepzettsegek} from "../domain-models/kepzettsegek2E";
import {getClassLevels} from "../domain-models/szintlepes";
import {FegyverFlags} from "../components/FegyverSelector";
interface KepzettsegPdfView {
nev: string,
alap: string,
bonusz: string,
osszes: string
}
export interface KarakterPdfView {
Nev: string
Isten: string
Jellem: string
Faj: string
Osztaly: {osztaly: string, szint: number}[]
Tulajdonsagok: KarakterTulajdonsagok,
TulajdonsagModositok: KarakterTulajdonsagok,
SzintTotal: string
HP: number
HPszintenkent: number[]
VO: number
PancelVO: string
PajzsVO: string
EgyebVO: string
Kezdemenyezes: number
TamadasBonuszAlap: number[]
KozelharciTB: number[]
CelzoTB: number[]
MentokAlap: Mentok
MentoModositok: Mentok
MentokModositokkal: Mentok,
Kepzettsegek: KepzettsegPdfView[],
Fegyverek: string[],
FelszerelesViselt: string[],
FelszerelesCipelt: string[],
FelszerelesAprosagok: string[],
}
export function KarakterInputToPdfView(karakter: Karakter2E): KarakterPdfView {
const tulajdonsagok = TulajdonsagokTotal(karakter)
karakter = {...karakter, tulajdonsagok}
const tulajdonsagModositok = TulajdonsagModosito(tulajdonsagok)
const masodlagosErtekek = CalculateMasodlagosErtekek(karakter)
const pancel = GetPancel(karakter.felszereles.pancelID)
const pajzs = GetPajzs(karakter.felszereles.pajzsID)
const kezdemenyezes = tulajdonsagModositok.t_ugy + (karakter.szintlepesek.some(x => x.osztaly === Osztaly2E.Tolvaj) ? 4 : 0)
const mentok = MultiClassMentokAlap(karakter.szintlepesek)
const mentoModositok = MentoModositok(tulajdonsagModositok)
const osztalyok = new Array(...(new Set(karakter.szintlepesek.map(x => x.osztaly))))
const osztaly = osztalyok.map(x => ({
osztaly: OsztalyLabel(x),
szint: karakter.szintlepesek.filter(sz => sz.osztaly === x).length
}))
const classLevels = getClassLevels(karakter.szintlepesek)
let felszereles = [] as string[]
if(pancel != null){
felszereles = felszereles.concat(FelszerelesToPdfView(pancel))
}
if(pajzs != null){
felszereles = felszereles.concat(FelszerelesToPdfView(pajzs))
}
felszereles = felszereles.concat(karakter.felszereles.fegyverIDk.map(x => {
const fegyver = GetFegyver(x)
if (fegyver == null) {
console.error("unknown fegyver: " + x)
return []
}
return FelszerelesToPdfView(fegyver)
}).reduce((acc, item) => acc.concat(item), [] as string[]))
return {
Faj: FajLabel(karakter.faj).toLowerCase(),
Isten: karakter.isten || "",
Jellem: GetJellem(karakter.jellem).Label,
Nev: karakter.nev,
Tulajdonsagok: karakter.tulajdonsagok,
Osztaly: osztaly,
SzintTotal: karakter.szint.toString(),
TulajdonsagModositok: tulajdonsagModositok,
HP: masodlagosErtekek.HP,
HPszintenkent: karakter.szintlepesek.map(x => x.HProll),
Kezdemenyezes: kezdemenyezes,
TamadasBonuszAlap: MultiClassTamadasBonusz(karakter.szintlepesek),
KozelharciTB: KozelharciTB(karakter),
CelzoTB: CelzoTB(karakter),
MentoModositok: mentoModositok,
MentokAlap: mentok,
MentokModositokkal: masodlagosErtekek.Mentok,
VO: masodlagosErtekek.VO,
PajzsVO: SignedNumberToText(pajzs?.VO),
PancelVO: SignedNumberToText(pancel?.VO),
EgyebVO: SignedNumberToText(VOegyeb(karakter)),
Kepzettsegek:
karakter.kepzettsegek.map(k =>
mapKepzettsegToPdfView(Kepzettsegek[k], tulajdonsagok, karakter.szint))
.concat(karakter.tolvajKepzettsegek?.map(k =>
mapKepzettsegToPdfView(Kepzettsegek[k], tulajdonsagok, classLevels[Osztaly2E.Tolvaj])) || []),
Fegyverek: karakter.felszereles.fegyverIDk.slice(0, 4).map(fid => {
const fegyver = GetFegyver(fid)
if (fegyver == null) {
console.error("unknown fegyver: " + fid)
return ""
}
const serializedFlags = FegyverFlags(fegyver);
const critStart = fegyver.CritRangeStart - karakter.szintlepesek.filter(x => x.kalozKritikus === fegyver.Id).length
const damageBonus = fegyver.DamageBonus +
(fegyver.KetkezesBonusz ? 1 : 0) +
(fegyver.Type !== "lofegyver" || fegyver.EroBonusz ? tulajdonsagModositok.t_ero : 0) +
(karakter.szintlepesek.filter(x => x.harcosFegyver === fegyver.Id).length * 2)
return `${fegyver.Name} ${serializedFlags.length > 0 ? serializedFlags + " " : ''} ${
fegyver.DamageMultiplier > 1 ? `${fegyver.DamageMultiplier}*` : ''}${
fegyver.NumberOfDamageDice}d${fegyver.DamageDice}${damageBonus !== 0 ? `${
SignedNumberToText(damageBonus)}` : ''} ${
critStart < 20 ? `${critStart}-20` : '20'}x${fegyver.CritMultiplier}`
}),
FelszerelesViselt: felszereles,
FelszerelesCipelt: [],
FelszerelesAprosagok: []
}
}
interface FelszerelesPdf {
Name: string,
Size: number,
}
function FelszerelesToPdfView(item: FelszerelesPdf): string[] {
const ans = [item.Name]
for (let i = 1; i < item.Size; i ++) {
ans.push("+")
}
return ans
}
function mapKepzettsegToPdfView(kepzettseg: Kepzettseg, tulajdonsagok: KarakterTulajdonsagok, szint: number): KepzettsegPdfView {
const tulajdonsagErtek = kepzettseg.Tulajdonsag.reduce((maxTulajdonsagErtek, currentTulajdonsag) =>
tulajdonsagok[currentTulajdonsag] > maxTulajdonsagErtek
? tulajdonsagok[currentTulajdonsag]
: maxTulajdonsagErtek,
tulajdonsagok[kepzettseg.Tulajdonsag[0]])
return {
nev: kepzettseg.Name,
alap: szint.toString(),
bonusz: SignedNumberToText(Modifier(tulajdonsagErtek)),
osszes: (szint + Modifier(tulajdonsagErtek)).toString(),
}
}
@@ -1,19 +0,0 @@
import * as React from "react";
import {CharacterListItemViewModel} from "../pages/CharacterList";
function CharacterListItem(props: {
character: CharacterListItemViewModel,
}) {
const {character:c} = props
return <>
<td><a href={`/${c.edition}/karakter/${c.id}`}>{c.name}</a></td>
<td>{c.szint}. szintű</td>
<td>{c.faj}</td>
<td>{c.osztaly}</td>
<td>{c.edition}</td>
</>
}
export default CharacterListItem;
@@ -1,3 +1,3 @@
export function SignedNumberToText(val?: number) : string {
return (val === null || val === undefined) ? "" : (val === 0 ? " 0" : (val > 0 ? '+'+val : val.toString()))
export function SignedNumberToText(val: number) : string {
return val === 0 ? " 0" : (val > 0 ? '+'+val : val.toString())
}
@@ -0,0 +1,3 @@
export function SignedNumberToText(val: number) : string {
return val === 0 ? " 0" : (val > 0 ? '+'+val : val.toString())
}
@@ -1,101 +0,0 @@
import * as React from "react";
import {useLoaderData} from "react-router-dom";
import CharacterListItem from "../components/CharacterListItem";
import {Faj, FajLabel as FajLabel1E} from "../../first-edition/domain-models/faj";
import {Faj2E, FajLabel as FajLabel2E} from "../../second-edition/domain-models/faj2E";
import {Osztaly, OsztalyLabel as OsztalyLabel1E} from "../../first-edition/domain-models/osztaly";
import {Osztaly2E, OsztalyLabel as OsztalyLabel2E} from "../../second-edition/domain-models/osztaly2E";
export interface CharacterListItemViewModel {
id: string,
name: string,
szint: number,
faj: string,
osztaly: string,
edition: "1e" | "2e"
}
interface CharacterListItemDto1E {
id: string,
name: string,
szint: number,
faj: Faj,
osztaly: Osztaly,
edition: "1e"
}
interface CharacterListItemDto2E {
id: string,
name: string,
szint: number,
faj: Faj2E,
osztaly: Osztaly2E,
edition: "2e"
}
type CharacterListItemDto = CharacterListItemDto1E | CharacterListItemDto2E;
function mapDtoToViewModel(dto: CharacterListItemDto): CharacterListItemViewModel {
if (dto.edition === "1e") {
return {
id: dto.id,
name: dto.name,
edition: dto.edition,
szint: dto.szint,
faj: FajLabel1E(dto.faj),
osztaly: OsztalyLabel1E(dto.osztaly),
}
}
else {
return {
id: dto.id,
name: dto.name,
edition: dto.edition,
szint: dto.szint,
faj: FajLabel2E(dto.faj),
osztaly: OsztalyLabel2E(dto.osztaly),
}
}
}
function CharacterList(props: {}) {
const characters = useLoaderData() as CharacterListItemDto[];
return <div className="container">
<div className="container-fluid p-5 bg-black text-white text-center">
<h1>Karakterek</h1>
</div>
<div className="row">
<div className="col-6">
<div className="d-grid gap-1 m-3 m-lg-5">
<a className="btn btn-dark btn-lg" href="/2e/karakter/" type="button">Új 2e karakter létrehozása</a>
</div>
</div>
<div className="col-6">
<div className="d-grid gap-1 m-3 m-lg-5">
<a className="btn btn-dark btn-lg" href="/1e/karakter/" type="button">Új 1e karakter létrehozása</a>
</div>
</div>
</div>
<table className="table mt-3">
<thead>
<tr>
<th scope="col">Név</th>
<th scope="col">Szint</th>
<th scope="col">Faj</th>
<th scope="col">Osztály</th>
<th scope="col">Kiadás</th>
</tr>
</thead>
<tbody>
{characters.map(c => (
<tr key={c.id}>
<CharacterListItem character={mapDtoToViewModel(c)}/>
</tr>
))}
</tbody>
</table>
</div>
}
export default CharacterList;
+64 -58
View File
@@ -1322,20 +1322,21 @@
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.56.0.tgz#ef20350fec605a7f7035a01764731b2de0f3782b"
integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==
"@grafana/faro-core@^1.3.9":
version "1.3.9"
resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.3.9.tgz#69d7c4239c3507028eb7a6f21f1213278b11194a"
integrity sha512-zBghaYNKwMwiyErUYEYbx/E/HTdy3tFS7Oy+1f5CiIi5+iUSYidgeQqKdd4vKB1EtDn1MI5iA2dXBavxLNYGlg==
"@grafana/faro-core@^1.3.6":
version "1.3.6"
resolved "https://registry.yarnpkg.com/@grafana/faro-core/-/faro-core-1.3.6.tgz#7e4f2754e35d683c259af2ee4851aceadbfca8ad"
integrity sha512-1N/VWOIuukvqJUbpGRmendbJSG8hEvMqUV79+jPrhSRjM2VlNsqtFC/0VdW9mpQPpZh2cOyI5bPjuAZsRe7+Xw==
dependencies:
"@opentelemetry/api" "^1.7.0"
"@opentelemetry/otlp-transformer" "^0.48.0"
"@opentelemetry/otlp-transformer" "^0.45.1"
murmurhash-js "^1.0.0"
"@grafana/faro-web-sdk@^1.3.9":
version "1.3.9"
resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.3.9.tgz#ebf8c645cbcc3a22e31a89d0e7e94f9d09f88c5f"
integrity sha512-lrUhzITfgpEtOP4I/HbhIh0UCTNpcAWveFN7bzdCJ/N/G3YULd6jXBuBoHcC25Fx3WtLChljzJ5IJ02HTA2Q9g==
"@grafana/faro-web-sdk@^1.2.2":
version "1.3.6"
resolved "https://registry.yarnpkg.com/@grafana/faro-web-sdk/-/faro-web-sdk-1.3.6.tgz#96fecf122d3352a3867bde76a01ef38fe75d868c"
integrity sha512-hxqHRZM1AERK6YZtJpCM1PJoj9/CLhCfQcfprcv751l5xkLCOzCoUWiH8CSW3gfiu7egIzEq0luHF7544Xezvg==
dependencies:
"@grafana/faro-core" "^1.3.9"
"@grafana/faro-core" "^1.3.6"
ua-parser-js "^1.0.32"
web-vitals "^3.1.1"
@@ -1695,10 +1696,10 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
"@opentelemetry/api-logs@0.48.0":
version "0.48.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.48.0.tgz#9521a0c1e920ed536f31cda117164c4afff44caf"
integrity sha512-1/aMiU4Eqo3Zzpfwu51uXssp5pzvHFObk8S9pKAiXb1ne8pvg1qxBQitYL1XUiAMEXFzgjaidYG2V6624DRhhw==
"@opentelemetry/api-logs@0.45.1":
version "0.45.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/api-logs/-/api-logs-0.45.1.tgz#9e4f2c652dcce798c5627939b22304c2b5ce19c5"
integrity sha512-zVGq/k70l+kB/Wuv3O/zhptP2hvDhEbhDu9EtHde1iWZJf3FedeYS/nWVcMBkkyPAjS/JKNk86WN4CBQLGUuOw==
dependencies:
"@opentelemetry/api" "^1.0.0"
@@ -1707,63 +1708,63 @@
resolved "https://registry.yarnpkg.com/@opentelemetry/api/-/api-1.7.0.tgz#b139c81999c23e3c8d3c0a7234480e945920fc40"
integrity sha512-AdY5wvN0P2vXBi3b29hxZgSFvdhdxPB9+f0B6s//P9Q8nibRWeA3cHm8UmLpio9ABigkVHJ5NMPk+Mz8VCCyrw==
"@opentelemetry/core@1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.21.0.tgz#8c16faf16edf861b073c03c9d45977b3f4003ee1"
integrity sha512-KP+OIweb3wYoP7qTYL/j5IpOlu52uxBv5M4+QhSmmUfLyTgu1OIS71msK3chFo1D6Y61BIH3wMiMYRCxJCQctA==
"@opentelemetry/core@1.18.1":
version "1.18.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/core/-/core-1.18.1.tgz#d2e45f6bd6be4f00d20d18d4f1b230ec33805ae9"
integrity sha512-kvnUqezHMhsQvdsnhnqTNfAJs3ox/isB0SVrM1dhVFw7SsB7TstuVa6fgWnN2GdPyilIFLUvvbTZoVRmx6eiRg==
dependencies:
"@opentelemetry/semantic-conventions" "1.21.0"
"@opentelemetry/semantic-conventions" "1.18.1"
"@opentelemetry/otlp-transformer@^0.48.0":
version "0.48.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.48.0.tgz#969d52a767c7538552b88f7baaa001d3f88feb17"
integrity sha512-yuoS4cUumaTK/hhxW3JUy3wl2U4keMo01cFDrUOmjloAdSSXvv1zyQ920IIH4lymp5Xd21Dj2/jq2LOro56TJg==
"@opentelemetry/otlp-transformer@^0.45.1":
version "0.45.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.45.1.tgz#8f6590b93f177510983bea3055e5a3f3d30faad2"
integrity sha512-FhIHgfC0b0XtoBrS5ISfva939yWffNl47ypXR8I7Ru+dunlySpmf2TLocKHYLHGcWiuoeSNO5O4dZCmSKOtpXw==
dependencies:
"@opentelemetry/api-logs" "0.48.0"
"@opentelemetry/core" "1.21.0"
"@opentelemetry/resources" "1.21.0"
"@opentelemetry/sdk-logs" "0.48.0"
"@opentelemetry/sdk-metrics" "1.21.0"
"@opentelemetry/sdk-trace-base" "1.21.0"
"@opentelemetry/api-logs" "0.45.1"
"@opentelemetry/core" "1.18.1"
"@opentelemetry/resources" "1.18.1"
"@opentelemetry/sdk-logs" "0.45.1"
"@opentelemetry/sdk-metrics" "1.18.1"
"@opentelemetry/sdk-trace-base" "1.18.1"
"@opentelemetry/resources@1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.21.0.tgz#e773e918cc8ca26493a987dfbfc6b8a315a2ab45"
integrity sha512-1Z86FUxPKL6zWVy2LdhueEGl9AHDJcx+bvHStxomruz6Whd02mE3lNUMjVJ+FGRoktx/xYQcxccYb03DiUP6Yw==
"@opentelemetry/resources@1.18.1":
version "1.18.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/resources/-/resources-1.18.1.tgz#e27bdc4715bccc8cd4a72d4aca3995ad0a496fe7"
integrity sha512-JjbcQLYMttXcIabflLRuaw5oof5gToYV9fuXbcsoOeQ0BlbwUn6DAZi++PNsSz2jjPeASfDls10iaO/8BRIPRA==
dependencies:
"@opentelemetry/core" "1.21.0"
"@opentelemetry/semantic-conventions" "1.21.0"
"@opentelemetry/core" "1.18.1"
"@opentelemetry/semantic-conventions" "1.18.1"
"@opentelemetry/sdk-logs@0.48.0":
version "0.48.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.48.0.tgz#5248e4cbfc99bbee555ffd1a23b5db53d6553f2c"
integrity sha512-lRcA5/qkSJuSh4ItWCddhdn/nNbVvnzM+cm9Fg1xpZUeTeozjJDBcHnmeKoOaWRnrGYBdz6UTY6bynZR9aBeAA==
"@opentelemetry/sdk-logs@0.45.1":
version "0.45.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-logs/-/sdk-logs-0.45.1.tgz#d59a99147ab15eb36757932517dfc9a10e1645e9"
integrity sha512-z0RRgW4LeKEKnhXS4F/HnqB6+7gsy63YK47F4XAJYHs4s1KKg8XnQ2RkbuL31i/a9nXkylttYtvsT50CGr487g==
dependencies:
"@opentelemetry/core" "1.21.0"
"@opentelemetry/resources" "1.21.0"
"@opentelemetry/core" "1.18.1"
"@opentelemetry/resources" "1.18.1"
"@opentelemetry/sdk-metrics@1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.21.0.tgz#40d71aaec5b696e58743889ce6d5bf2593f9a23d"
integrity sha512-on1jTzIHc5DyWhRP+xpf+zrgrREXcHBH4EDAfaB5mIG7TWpKxNXooQ1JCylaPsswZUv4wGnVTinr4HrBdGARAQ==
"@opentelemetry/sdk-metrics@1.18.1":
version "1.18.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-metrics/-/sdk-metrics-1.18.1.tgz#1dd334744a1e5d2eec27e9e9765c73cd2f43aef3"
integrity sha512-TEFgeNFhdULBYiCoHbz31Y4PDsfjjxRp8Wmdp6ybLQZPqMNEb+dRq+XN8Xw3ivIgTaf9gYsomgV5ensX99RuEQ==
dependencies:
"@opentelemetry/core" "1.21.0"
"@opentelemetry/resources" "1.21.0"
"@opentelemetry/core" "1.18.1"
"@opentelemetry/resources" "1.18.1"
lodash.merge "^4.6.2"
"@opentelemetry/sdk-trace-base@1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.21.0.tgz#ffad912e453a92044fb220bd5d2f6743bf37bb8a"
integrity sha512-yrElGX5Fv0umzp8Nxpta/XqU71+jCAyaLk34GmBzNcrW43nqbrqvdPs4gj4MVy/HcTjr6hifCDCYA3rMkajxxA==
"@opentelemetry/sdk-trace-base@1.18.1":
version "1.18.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.18.1.tgz#256605d90b202002d5672305c66dbcf377132379"
integrity sha512-tRHfDxN5dO+nop78EWJpzZwHsN1ewrZRVVwo03VJa3JQZxToRDH29/+MB24+yoa+IArerdr7INFJiX/iN4gjqg==
dependencies:
"@opentelemetry/core" "1.21.0"
"@opentelemetry/resources" "1.21.0"
"@opentelemetry/semantic-conventions" "1.21.0"
"@opentelemetry/core" "1.18.1"
"@opentelemetry/resources" "1.18.1"
"@opentelemetry/semantic-conventions" "1.18.1"
"@opentelemetry/semantic-conventions@1.21.0":
version "1.21.0"
resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.21.0.tgz#83f7479c524ab523ac2df702ade30b9724476c72"
integrity sha512-lkC8kZYntxVKr7b8xmjCVUgE0a8xgDakPyDo9uSWavXPyYqLgYYGdEd2j8NxihRyb6UwpX3G/hFUF4/9q2V+/g==
"@opentelemetry/semantic-conventions@1.18.1":
version "1.18.1"
resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.18.1.tgz#8e47caf57a84b1dcc1722b2025693348cdf443b4"
integrity sha512-+NLGHr6VZwcgE/2lw8zDIufOCGnzsA5CbQIMleXZTrgkBd0TanCX+MiDYJ1TOS4KL/Tqk0nFRxawnaYr6pkZkA==
"@pdf-lib/fontkit@^1.1.1":
version "1.1.1"
@@ -6960,6 +6961,11 @@ multicast-dns@^7.2.5:
dns-packet "^5.2.2"
thunky "^1.0.2"
murmurhash-js@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/murmurhash-js/-/murmurhash-js-1.0.0.tgz#b06278e21fc6c37fa5313732b0412bcb6ae15f51"
integrity sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==
mz@^2.7.0:
version "2.7.0"
resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32"
-1
View File
@@ -1,3 +1,2 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:Boolean x:Key="/Default/UserDictionary/Words/=karakter/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kemkas/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
+1 -10
View File
@@ -13,21 +13,12 @@
## Features
- multiclass characters
- 2e -ben félig működik
- druidáknál tiltani kell
- PDF-ben varazshasznalok
- tolvaj 9ik szintű képessége
## Epics
- Backend
- Varazslatok
- Felszerelés
- 1e-ben fel van már véve az adat. Gergő neki veselkedik.
- 2e-ben teljesen hiányzik
- KéM 2e
- frontend oldalon úgy, ahogy megvan
- PDF hiányzik
- backend hiányzik
- KéM 2.0-ra felkészülés
- Klikkelésre dobás