mirror of
https://github.com/morbalint/kemkas.git
synced 2026-07-17 19:03:46 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 532a9651b9 | |||
| 540c665a14 | |||
| 8f32daf337 | |||
| 978618d1b1 | |||
| 65132fc7c6 | |||
| 8abe228d89 | |||
| cc9a83607c | |||
| 8092210ec8 | |||
| fb8964062b | |||
| 55eeae5693 | |||
| a1f694e30c |
@@ -65,7 +65,8 @@
|
|||||||
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
@foreach (var provider in Model.ExternalLogins!)
|
<button type="submit" class="btn" name="provider" value="Discord" title="Log in using your Discord account"><img height="24px" alt="Discord" src="/img/discord-logo-blue.svg" /></button>
|
||||||
|
@foreach (var provider in Model.ExternalLogins!.Where(el => el.Name != "Discord"))
|
||||||
{
|
{
|
||||||
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,11 +22,13 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
|
|||||||
{
|
{
|
||||||
private readonly SignInManager<ApplicationUser> _signInManager;
|
private readonly SignInManager<ApplicationUser> _signInManager;
|
||||||
private readonly ILogger<LoginModel> _logger;
|
private readonly ILogger<LoginModel> _logger;
|
||||||
|
private readonly IWebHostEnvironment _environment;
|
||||||
|
|
||||||
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger)
|
public LoginModel(SignInManager<ApplicationUser> signInManager, ILogger<LoginModel> logger, IWebHostEnvironment environment)
|
||||||
{
|
{
|
||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
|
_environment = environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -98,6 +100,12 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
|
|||||||
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
|
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
|
||||||
|
|
||||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||||
|
|
||||||
|
// Disable not yet approved external login providers in production
|
||||||
|
if (!_environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
|
||||||
|
}
|
||||||
|
|
||||||
ReturnUrl = returnUrl;
|
ReturnUrl = returnUrl;
|
||||||
}
|
}
|
||||||
@@ -107,6 +115,12 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
|
|||||||
returnUrl ??= Url.Content("~/");
|
returnUrl ??= Url.Content("~/");
|
||||||
|
|
||||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||||
|
|
||||||
|
// Disable not yet approved external login providers in production
|
||||||
|
if (!_environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
|
||||||
|
}
|
||||||
|
|
||||||
if (ModelState.IsValid)
|
if (ModelState.IsValid)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -49,7 +49,8 @@
|
|||||||
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
<form id="external-account" asp-page="./ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" method="post" class="form-horizontal">
|
||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
@foreach (var provider in Model.ExternalLogins!)
|
<button type="submit" class="btn" name="provider" value="Discord" title="Log in using your Discord account"><img height="24px" alt="Discord" src="/img/discord-logo-blue.svg" /></button>
|
||||||
|
@foreach (var provider in Model.ExternalLogins!.Where(el => el.Name != "Discord"))
|
||||||
{
|
{
|
||||||
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
<button type="submit" class="btn btn-primary" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,13 +30,15 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
|
|||||||
private readonly IUserEmailStore<ApplicationUser> _emailStore;
|
private readonly IUserEmailStore<ApplicationUser> _emailStore;
|
||||||
private readonly ILogger<RegisterModel> _logger;
|
private readonly ILogger<RegisterModel> _logger;
|
||||||
private readonly IEmailSender _emailSender;
|
private readonly IEmailSender _emailSender;
|
||||||
|
private readonly IWebHostEnvironment _environment;
|
||||||
|
|
||||||
public RegisterModel(
|
public RegisterModel(
|
||||||
UserManager<ApplicationUser> userManager,
|
UserManager<ApplicationUser> userManager,
|
||||||
IUserStore<ApplicationUser> userStore,
|
IUserStore<ApplicationUser> userStore,
|
||||||
SignInManager<ApplicationUser> signInManager,
|
SignInManager<ApplicationUser> signInManager,
|
||||||
ILogger<RegisterModel> logger,
|
ILogger<RegisterModel> logger,
|
||||||
IEmailSender emailSender)
|
IEmailSender emailSender,
|
||||||
|
IWebHostEnvironment environment)
|
||||||
{
|
{
|
||||||
_userManager = userManager;
|
_userManager = userManager;
|
||||||
_userStore = userStore;
|
_userStore = userStore;
|
||||||
@@ -44,6 +46,7 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
|
|||||||
_signInManager = signInManager;
|
_signInManager = signInManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_emailSender = emailSender;
|
_emailSender = emailSender;
|
||||||
|
_environment = environment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -105,12 +108,22 @@ namespace Kemkas.Web.Areas.Identity.Pages.Account
|
|||||||
{
|
{
|
||||||
ReturnUrl = returnUrl;
|
ReturnUrl = returnUrl;
|
||||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||||
|
// Disable not yet approved external login providers in production
|
||||||
|
if (!_environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
|
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
|
||||||
{
|
{
|
||||||
returnUrl ??= Url.Content("~/");
|
returnUrl ??= Url.Content("~/");
|
||||||
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
|
||||||
|
// Disable not yet approved external login providers in production
|
||||||
|
if (!_environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
ExternalLogins = ExternalLogins.Where(el => el.Name == "Discord").ToList();
|
||||||
|
}
|
||||||
if (!ModelState.IsValid)
|
if (!ModelState.IsValid)
|
||||||
{
|
{
|
||||||
return Page();
|
return Page();
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
namespace Kemkas.Web.Config;
|
||||||
|
|
||||||
|
public class ExternalAuthOptions
|
||||||
|
{
|
||||||
|
public string? ClientId { get; set; }
|
||||||
|
|
||||||
|
public string? ClientSecret { get; set; }
|
||||||
|
|
||||||
|
public bool IsValid() => ClientId != null && ClientSecret != null;
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
using OpenTelemetry.Metrics;
|
||||||
|
using OpenTelemetry.Resources;
|
||||||
|
using OpenTelemetry.Trace;
|
||||||
|
|
||||||
|
namespace Kemkas.Web.Config;
|
||||||
|
|
||||||
|
public static class WebApplicationBuilderExtensions
|
||||||
|
{
|
||||||
|
public static void AddAuth(this WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
var externalAuthConfigSection = builder.Configuration.GetSection("Authentication");
|
||||||
|
var authenticationBuilder = builder.Services.AddAuthentication();
|
||||||
|
|
||||||
|
var googleAuthOptions = new ExternalAuthOptions();
|
||||||
|
externalAuthConfigSection.GetSection("Google").Bind(googleAuthOptions);
|
||||||
|
if (googleAuthOptions.IsValid())
|
||||||
|
{
|
||||||
|
authenticationBuilder.AddGoogle(options =>
|
||||||
|
{
|
||||||
|
options.ClientId = googleAuthOptions.ClientId!;
|
||||||
|
options.ClientSecret = googleAuthOptions.ClientSecret!;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var facebookAuthOptions = new ExternalAuthOptions();
|
||||||
|
externalAuthConfigSection.GetSection("Facebook").Bind(facebookAuthOptions);
|
||||||
|
if (facebookAuthOptions.IsValid())
|
||||||
|
{
|
||||||
|
authenticationBuilder.AddFacebook(options =>
|
||||||
|
{
|
||||||
|
options.ClientId = facebookAuthOptions.ClientId!;
|
||||||
|
options.ClientSecret = facebookAuthOptions.ClientSecret!;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var discordAuthOptions = new ExternalAuthOptions();
|
||||||
|
externalAuthConfigSection.GetSection("Discord").Bind(discordAuthOptions);
|
||||||
|
if (discordAuthOptions.IsValid())
|
||||||
|
{
|
||||||
|
authenticationBuilder.AddDiscord(options =>
|
||||||
|
{
|
||||||
|
options.ClientId = discordAuthOptions.ClientId!;
|
||||||
|
options.ClientSecret = discordAuthOptions.ClientSecret!;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void AddOpenTelemetry(this WebApplicationBuilder builder)
|
||||||
|
{
|
||||||
|
var otlResourceBuilder = ResourceBuilder.CreateDefault().AddService("kemkas-api");
|
||||||
|
var openTelemetryEndpoint = builder.Configuration.GetSection("monitoring")["url"];
|
||||||
|
var consoleEnabled = builder.Configuration.GetSection("monitoring")["console"] == "true";
|
||||||
|
|
||||||
|
builder.Services.AddOpenTelemetry().WithTracing(tracerProviderBuilder =>
|
||||||
|
{
|
||||||
|
tracerProviderBuilder
|
||||||
|
.SetResourceBuilder(otlResourceBuilder)
|
||||||
|
.AddAspNetCoreInstrumentation();
|
||||||
|
if (openTelemetryEndpoint != null)
|
||||||
|
{
|
||||||
|
tracerProviderBuilder.AddOtlpExporter(opt => opt.Endpoint = new Uri(openTelemetryEndpoint));
|
||||||
|
}
|
||||||
|
else if (consoleEnabled)
|
||||||
|
{
|
||||||
|
tracerProviderBuilder.AddConsoleExporter();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.WithMetrics(meterProviderBuilder =>
|
||||||
|
{
|
||||||
|
meterProviderBuilder
|
||||||
|
.SetResourceBuilder(otlResourceBuilder)
|
||||||
|
.AddAspNetCoreInstrumentation();
|
||||||
|
if (openTelemetryEndpoint != null)
|
||||||
|
{
|
||||||
|
meterProviderBuilder.AddOtlpExporter(opt => opt.Endpoint = new Uri(openTelemetryEndpoint));
|
||||||
|
}
|
||||||
|
else if (consoleEnabled)
|
||||||
|
{
|
||||||
|
meterProviderBuilder.AddConsoleExporter();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNet.Security.OAuth.Discord" Version="8.0.0" />
|
<PackageReference Include="AspNet.Security.OAuth.Discord" Version="8.0.0" />
|
||||||
|
<PackageReference Include="Grpc.Core" Version="2.46.6" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Facebook" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.Google" Version="8.0.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.0" />
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="8.0.0" />
|
||||||
@@ -36,6 +37,10 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.0" />
|
||||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
|
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL.Design" Version="1.1.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.Console" Version="1.7.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Exporter.OpenTelemetryProtocol" Version="1.7.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Extensions.Hosting" Version="1.7.0" />
|
||||||
|
<PackageReference Include="OpenTelemetry.Instrumentation.AspNetCore" Version="1.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
+10
-19
@@ -11,6 +11,9 @@ using Kemkas.Web.Services.Identity;
|
|||||||
using Microsoft.AspNetCore.DataProtection;
|
using Microsoft.AspNetCore.DataProtection;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
using Microsoft.AspNetCore.Identity.UI.Services;
|
using Microsoft.AspNetCore.Identity.UI.Services;
|
||||||
|
using OpenTelemetry.Metrics;
|
||||||
|
using OpenTelemetry.Resources;
|
||||||
|
using OpenTelemetry.Trace;
|
||||||
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
using IPNetwork = Microsoft.AspNetCore.HttpOverrides.IPNetwork;
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
@@ -34,25 +37,7 @@ builder.Services.AddSingleton<IEmailSender, MailgunEmailSender>();
|
|||||||
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
|
||||||
.AddEntityFrameworkStores<ApplicationDbContext>();
|
.AddEntityFrameworkStores<ApplicationDbContext>();
|
||||||
|
|
||||||
builder.Services.AddAuthentication()
|
builder.AddAuth();
|
||||||
.AddGoogle(options =>
|
|
||||||
{
|
|
||||||
var section = builder.Configuration.GetSection("Authentication:Google");
|
|
||||||
options.ClientId = section["ClientId"];
|
|
||||||
options.ClientSecret = section["ClientSecret"];
|
|
||||||
})
|
|
||||||
.AddFacebook(options =>
|
|
||||||
{
|
|
||||||
var section = builder.Configuration.GetSection("Authentication:Facebook");
|
|
||||||
options.ClientId = section["ClientId"];
|
|
||||||
options.ClientSecret = section["ClientSecret"];
|
|
||||||
})
|
|
||||||
.AddDiscord(options =>
|
|
||||||
{
|
|
||||||
var section = builder.Configuration.GetSection("Authentication:Discord");
|
|
||||||
options.ClientId = section["ClientId"];
|
|
||||||
options.ClientSecret = section["ClientSecret"];
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.Services.AddControllersWithViews().AddJsonOptions(options =>
|
builder.Services.AddControllersWithViews().AddJsonOptions(options =>
|
||||||
{
|
{
|
||||||
@@ -62,6 +47,10 @@ builder.Services.AddControllersWithViews().AddJsonOptions(options =>
|
|||||||
});
|
});
|
||||||
builder.Services.AddRazorPages();
|
builder.Services.AddRazorPages();
|
||||||
|
|
||||||
|
builder.AddOpenTelemetry();
|
||||||
|
|
||||||
|
builder.Services.AddHealthChecks();
|
||||||
|
|
||||||
builder.Services.AddCharacterServices();
|
builder.Services.AddCharacterServices();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
@@ -93,6 +82,8 @@ else
|
|||||||
app.UseHsts(); // TODO: check if this should be handled by proxy
|
app.UseHsts(); // TODO: check if this should be handled by proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app.UseHealthChecks("/health");
|
||||||
|
|
||||||
await using (var scope = app.Services.CreateAsyncScope())
|
await using (var scope = app.Services.CreateAsyncScope())
|
||||||
{
|
{
|
||||||
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
|
||||||
|
|||||||
@@ -21,14 +21,15 @@ import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
|
|||||||
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
|
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
|
||||||
import JellemSelector from "../components/JellemSelector";
|
import JellemSelector from "../components/JellemSelector";
|
||||||
import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level";
|
import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level";
|
||||||
import {Card, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap";
|
import {Button, Card, InputGroup, Modal, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap";
|
||||||
|
import Form from "react-bootstrap/Form";
|
||||||
import LevelUps from "../components/LevelUps";
|
import LevelUps from "../components/LevelUps";
|
||||||
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio";
|
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio";
|
||||||
import Felszereles from '../components/Felszereles';
|
import Felszereles from '../components/Felszereles';
|
||||||
import { KarakterFelszereles } from '../domain-models/felszereles';
|
import { KarakterFelszereles } from '../domain-models/felszereles';
|
||||||
import {Faro} from "@grafana/faro-web-sdk";
|
import {Faro} from "@grafana/faro-web-sdk";
|
||||||
import {StoreNewCharacter, UpdateCharacter} from "../api/character.api";
|
import {StoreNewCharacter, UpdateCharacter} from "../api/character.api";
|
||||||
import {useLoaderData, useParams} from "react-router-dom";
|
import {useLoaderData, useNavigate, useParams} from "react-router-dom";
|
||||||
import saveOverlayTooltip from "../components/SaveOverlayTooltip";
|
import saveOverlayTooltip from "../components/SaveOverlayTooltip";
|
||||||
import {UserContext} from "../../shared/contexts/UserContext";
|
import {UserContext} from "../../shared/contexts/UserContext";
|
||||||
import {KarakterTulajdonsagok} from "../domain-models/tulajdonsag";
|
import {KarakterTulajdonsagok} from "../domain-models/tulajdonsag";
|
||||||
@@ -39,7 +40,6 @@ function CreateCharacterPage(props: {
|
|||||||
const {faro} = props
|
const {faro} = props
|
||||||
|
|
||||||
const loaderData = useLoaderData() as KarakterInputs & { isPublic: boolean } | undefined;
|
const loaderData = useLoaderData() as KarakterInputs & { isPublic: boolean } | undefined;
|
||||||
const initialIsPublic = loaderData?.isPublic ?? false;
|
|
||||||
let initialKarakterInputs = KarakterDefaults;
|
let initialKarakterInputs = KarakterDefaults;
|
||||||
if (loaderData != null) {
|
if (loaderData != null) {
|
||||||
const { isPublic: t1, ...t2 } = loaderData;
|
const { isPublic: t1, ...t2 } = loaderData;
|
||||||
@@ -47,6 +47,10 @@ function CreateCharacterPage(props: {
|
|||||||
}
|
}
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const fetchedUser = useContext(UserContext);
|
const fetchedUser = useContext(UserContext);
|
||||||
|
|
||||||
|
const initialIsPublic = loaderData?.isPublic ?? fetchedUser?.data == null;
|
||||||
|
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
let [karakter, changeKarakter] = useState(initialKarakterInputs)
|
let [karakter, changeKarakter] = useState(initialKarakterInputs)
|
||||||
|
|
||||||
@@ -64,9 +68,25 @@ function CreateCharacterPage(props: {
|
|||||||
const levelDown = () => LevelDown(karakter, changeKarakter)
|
const levelDown = () => LevelDown(karakter, changeKarakter)
|
||||||
|
|
||||||
const canLevelUp = CanLevelUp(karakter)
|
const canLevelUp = CanLevelUp(karakter)
|
||||||
|
|
||||||
|
let [showSaveModal, setShowSaveModal] = useState(false);
|
||||||
|
let [newId, setNewId] = useState(null as string | null)
|
||||||
|
|
||||||
let [showSaved, setShowSaved] = useState(false);
|
let [showSaved, setShowSaved] = useState(false);
|
||||||
let [isPublic, setIsPublic] = useState(initialIsPublic);
|
let [isPublic, setIsPublic] = useState(initialIsPublic);
|
||||||
|
|
||||||
|
const newCharacterUrl = () => `${window.location.origin}/1e/karakter/${newId}`
|
||||||
|
|
||||||
|
const handleSaveModalCopyAndClose = async () => {
|
||||||
|
|
||||||
|
await navigator.clipboard.writeText(newCharacterUrl());
|
||||||
|
handleSaveModalClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSaveModalClose = () => {
|
||||||
|
setShowSaveModal(false);
|
||||||
|
navigate(`/1e/karakter/${newId}`)
|
||||||
|
}
|
||||||
|
|
||||||
const hideSaved = () => setShowSaved(false);
|
const hideSaved = () => setShowSaved(false);
|
||||||
const onSaveClicked = async () => {
|
const onSaveClicked = async () => {
|
||||||
@@ -77,11 +97,9 @@ function CreateCharacterPage(props: {
|
|||||||
is_public: isPublic.toString(),
|
is_public: isPublic.toString(),
|
||||||
})
|
})
|
||||||
if (id == null) {
|
if (id == null) {
|
||||||
let newId = await StoreNewCharacter(karakter, isPublic);
|
let recievedId = await StoreNewCharacter(karakter, isPublic);
|
||||||
const win = window.open(`/1e/karakter/${newId}`, '_blank');
|
setNewId(recievedId)
|
||||||
if (win != null) {
|
setShowSaveModal(true);
|
||||||
win.focus();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
await UpdateCharacter(id, karakter, isPublic);
|
await UpdateCharacter(id, karakter, isPublic);
|
||||||
setShowSaved(true);
|
setShowSaved(true);
|
||||||
@@ -98,9 +116,31 @@ function CreateCharacterPage(props: {
|
|||||||
</div>
|
</div>
|
||||||
<ToastContainer className="position-fixed" position="top-end">
|
<ToastContainer className="position-fixed" position="top-end">
|
||||||
<Toast show={showSaved} onClose={hideSaved} bg="success">
|
<Toast show={showSaved} onClose={hideSaved} bg="success">
|
||||||
<Toast.Header><strong>Karakter mentve!</strong></Toast.Header>
|
<Toast.Body className="text-light">Karakter mentve!</Toast.Body>
|
||||||
</Toast>
|
</Toast>
|
||||||
</ToastContainer>
|
</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'>
|
<div className='p-3'>
|
||||||
<form onSubmit={async (event) => event.preventDefault()}>
|
<form onSubmit={async (event) => event.preventDefault()}>
|
||||||
<div className='row'>
|
<div className='row'>
|
||||||
|
|||||||
@@ -10,15 +10,16 @@ import {DrawMasodlagosErtekek} from './masodlagos_ertekek.pdf'
|
|||||||
import {DrawOsztalySpecialsPage} from './osztaly_specials.pdf'
|
import {DrawOsztalySpecialsPage} from './osztaly_specials.pdf'
|
||||||
import {DrawFegyverek} from "./fegyverek.pdf";
|
import {DrawFegyverek} from "./fegyverek.pdf";
|
||||||
|
|
||||||
function drawBaseInfo(karakter: KarakterPdfView, draw: (text: string, x : number ,y: number, scale: number) => void) {
|
function drawBaseInfo(karakter: KarakterPdfView,
|
||||||
draw(karakter.Name, 60, 710, 1)
|
draw: (name: string, text: string, x : number ,y: number, width: number, scale: number) => void) {
|
||||||
draw(karakter.Nem, 454, 710, 1)
|
draw("nev", karakter.Name, 56, 704, 190, 1)
|
||||||
draw(karakter.Kor.toString(), 454, 690, 1)
|
draw("nem", karakter.Nem, 449, 704, 90, 11/12)
|
||||||
draw(karakter.Isten, 454, 670, 1)
|
draw("kor", karakter.Kor.toString(), 449, 687, 90, 11/12)
|
||||||
draw(karakter.Osztaly, 60, 672, 1)
|
draw("isten", karakter.Isten, 449, 669, 90, 11/12)
|
||||||
draw(karakter.Szint, karakter.Szint.length > 1 ? 252 : 264, 682, 3)
|
draw("osztaly", karakter.Osztaly, 56, 668, 190, 1)
|
||||||
draw(karakter.Faj, 302, 710, 1)
|
draw("szint", karakter.Szint, 250, 669, 45, 3)
|
||||||
draw(karakter.Jellem, 302, 672, karakter.Jellem.length > 17 ? 11/12 : 1)
|
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) {
|
function DrawKepzettsegek(draw: (text: string, x: number, y: number) => void, kepzettsegek: KepzettsegPdfView[], startFrom: number) {
|
||||||
@@ -43,12 +44,14 @@ export async function CreatePDF(karakter: KarakterPdfView) {
|
|||||||
const existingPdfBytes = await fetch('/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)
|
const pdfDoc = await PDFDocument.load(existingPdfBytes)
|
||||||
pdfDoc.registerFontkit(fontkit)
|
pdfDoc.registerFontkit(fontkit)
|
||||||
|
|
||||||
|
|
||||||
const fontBytes = await fetch('/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(fontBytes)
|
||||||
// const pdfFont = await pdfDoc.embedFont(StandardFonts.TimesNewRoman)
|
// const pdfFont = await pdfDoc.embedFont(StandardFonts.TimesNewRoman)
|
||||||
const fontSizeBase = 12
|
const fontSizeBase = 12
|
||||||
|
|
||||||
|
const form = pdfDoc.getForm()
|
||||||
const page = pdfDoc.getPage(0)
|
const page = pdfDoc.getPage(0)
|
||||||
|
|
||||||
function drawText(text: string, x: number, y: number, fontScale = 1, shade = 0) {
|
function drawText(text: string, x: number, y: number, fontScale = 1, shade = 0) {
|
||||||
@@ -61,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);
|
DrawTulajdonsagok(page, karakter.Tulajdonsagok, fontSizeBase, pdfFont);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,88 @@
|
|||||||
|
import React from "react";
|
||||||
|
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 {TamadasBonusz} from "../domain-models/tamadas_bonusz";
|
||||||
|
|
||||||
|
function MentoNovekedes(props : {tipus: MentoTipus, ujMentok: Mentok, regiMentok: Mentok}) {
|
||||||
|
const {tipus, ujMentok, regiMentok} = props
|
||||||
|
if (ujMentok[tipus] === regiMentok[tipus]) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <div className='row m-2'>
|
||||||
|
<label className='col-sm-6 col-8 col-form-label'>{MentoTipusLabel(tipus)} mentő növekedés{' '}</label>
|
||||||
|
<span className='col col-form-label'>{SignedNumberToText(ujMentok[tipus] - regiMentok[tipus])}</span>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function UjMento(props : {tipus: MentoTipus, ujMentok: Mentok, regiMentok: Mentok}) {
|
||||||
|
const {tipus, ujMentok, regiMentok} = props
|
||||||
|
if (ujMentok[tipus] === regiMentok[tipus]) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return <div className='row m-2'>
|
||||||
|
<label className='col-sm-6 col-8 col-form-label'>{MentoTipusLabel(tipus)} mentő új értéke{' '}</label>
|
||||||
|
<span className='col col-form-label'>{SignedNumberToText(ujMentok[tipus])}</span>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function BasicNewLevel(props: {
|
||||||
|
karakter: Pick<Karakter2E, 'osztaly' | 'tulajdonsagok' | 'szintlepesek'>
|
||||||
|
szint: number
|
||||||
|
changeRolledHP: (hp: number) => void,
|
||||||
|
}) {
|
||||||
|
const {karakter, szint, changeRolledHP} = props
|
||||||
|
const regiMentok = MentokTotal({...karakter, szint: szint - 1})
|
||||||
|
const ujMentok = MentokTotal({...karakter, szint: szint})
|
||||||
|
|
||||||
|
const regiTB = TamadasBonusz(karakter.osztaly, szint-1)
|
||||||
|
const ujTB = TamadasBonusz(karakter.osztaly, szint)
|
||||||
|
if (regiTB.length < ujTB.length) {
|
||||||
|
regiTB.push(0)
|
||||||
|
}
|
||||||
|
const TBdiff = ujTB.map((x, i) => x - regiTB[i])
|
||||||
|
const isTBincreased = TBdiff.length > 0 && TBdiff.some(x => x > 0)
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<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(karakter.osztaly)}){' '}</label>
|
||||||
|
<div className='col-sm-2 col'>
|
||||||
|
<input
|
||||||
|
className='form-control'
|
||||||
|
maxLength={2}
|
||||||
|
type='number'
|
||||||
|
value={karakter.szintlepesek[szint-1].HProll || 1}
|
||||||
|
min={1}
|
||||||
|
max={12}
|
||||||
|
onChange={e => changeRolledHP(Number(e.target.value))} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{ isTBincreased && <div className='row m-2'>
|
||||||
|
<label className='col-sm-6 col-8 col-form-label'>Támadás bónusz növekedés{' '}</label>
|
||||||
|
<span className='col col-form-label'>{TBdiff.map(SignedNumberToText).join(" / ")}</span>
|
||||||
|
</div>}
|
||||||
|
<MentoNovekedes tipus={'kitartas'} ujMentok={ujMentok} regiMentok={regiMentok} />
|
||||||
|
<MentoNovekedes tipus={'reflex'} ujMentok={ujMentok} regiMentok={regiMentok} />
|
||||||
|
<MentoNovekedes tipus={'akaratero'} ujMentok={ujMentok} regiMentok={regiMentok} />
|
||||||
|
</div>
|
||||||
|
<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-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>
|
||||||
|
<span className='col col-form-label'>{ujTB.map(SignedNumberToText).join(" / ")}</span>
|
||||||
|
</div>}
|
||||||
|
<UjMento tipus={'kitartas'} ujMentok={ujMentok} regiMentok={regiMentok} />
|
||||||
|
<UjMento tipus={'reflex'} ujMentok={ujMentok} regiMentok={regiMentok} />
|
||||||
|
<UjMento tipus={'akaratero'} ujMentok={ujMentok} regiMentok={regiMentok} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default BasicNewLevel
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Fegyver} from "../domain-models/felszereles";
|
||||||
|
|
||||||
|
export function FegyverLabel(fegyver: Fegyver): string {
|
||||||
|
const flags = [] as string[]
|
||||||
|
if (fegyver.Harcos) {
|
||||||
|
flags.push("H")
|
||||||
|
}
|
||||||
|
if (fegyver.Masfelkezes) {
|
||||||
|
flags.push("1½K")
|
||||||
|
}
|
||||||
|
if (fegyver.Ketkezes) {
|
||||||
|
if (fegyver.Type === "kozelharci") {
|
||||||
|
flags.push("2K")
|
||||||
|
} else {
|
||||||
|
if (fegyver.KetkezesBonusz) {
|
||||||
|
flags.push("2KB")
|
||||||
|
} else {
|
||||||
|
flags.push("2KN")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (fegyver.HarciManover) {
|
||||||
|
flags.push("+2 HM")
|
||||||
|
}
|
||||||
|
if (fegyver.Alakzat){
|
||||||
|
flags.push("AL")
|
||||||
|
}
|
||||||
|
if (fegyver.Hosszu) {
|
||||||
|
flags.push("HO")
|
||||||
|
}
|
||||||
|
if (fegyver.Kabito) {
|
||||||
|
flags.push("KO")
|
||||||
|
}
|
||||||
|
if (fegyver.LovasRoham) {
|
||||||
|
flags.push("LR")
|
||||||
|
}
|
||||||
|
if (fegyver.PancelToro) {
|
||||||
|
flags.push("PT")
|
||||||
|
}
|
||||||
|
if (fegyver.PajzsZuzo) {
|
||||||
|
flags.push("PZ")
|
||||||
|
}
|
||||||
|
if (fegyver.Rohamtoro) {
|
||||||
|
flags.push("RT")
|
||||||
|
}
|
||||||
|
// Replaced by new group "dobhato"
|
||||||
|
// if (fegyver.EroBonusz) {
|
||||||
|
// flags.push("ER")
|
||||||
|
// }
|
||||||
|
if (fegyver.Megjegyzes != null && fegyver.Megjegyzes.length > 0) {
|
||||||
|
flags.push(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}` : ''} ${
|
||||||
|
fegyver.CritRangeStart < 20 ? `${fegyver.CritRangeStart}-20` : ''}x${fegyver.CritMultiplier}${
|
||||||
|
fegyver.Price > 0 ? ` | ár: ${fegyver.Price} at ` : ''}${
|
||||||
|
fegyver.Range > 10 ? ` | táv: ${fegyver.Range}` : ''}`
|
||||||
|
}
|
||||||
|
|
||||||
|
function FegyverSelector(props: {fegyverek: Fegyver[], selectedId: string, onChange: (id: string) => void}) {
|
||||||
|
|
||||||
|
const { fegyverek, selectedId, onChange } = props
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<select className='col form-select' value={selectedId}
|
||||||
|
onChange={e => onChange(e.target.value)}>
|
||||||
|
<optgroup label="Közelharci">
|
||||||
|
{fegyverek.filter(f => f.Type === 'kozelharci').map(f => <option
|
||||||
|
key={f.Id} value={f.Id}>{FegyverLabel(f)}</option>)}
|
||||||
|
</optgroup>
|
||||||
|
<optgroup label="Közelharci, dobható">
|
||||||
|
{fegyverek.filter(f => f.Type === 'dobhato').map(f => <option
|
||||||
|
key={f.Id} value={f.Id}>{FegyverLabel(f)}</option>)}
|
||||||
|
</optgroup>
|
||||||
|
<optgroup label="Távolsági">
|
||||||
|
{fegyverek.filter(f => f.Type === 'lofegyver').map(f => <option
|
||||||
|
key={f.Id} value={f.Id}>{FegyverLabel(f)}</option>)}
|
||||||
|
</optgroup>
|
||||||
|
</select>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FegyverSelector
|
||||||
@@ -5,64 +5,7 @@ import {AllowedPajzsTypes, AllowedPancelTypes} from '../domain-models/allowed-pa
|
|||||||
import fegyverek from '../domain-models/fegyver.json'
|
import fegyverek from '../domain-models/fegyver.json'
|
||||||
import {arraySetN} from "../../util";
|
import {arraySetN} from "../../util";
|
||||||
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
||||||
|
import FegyverSelector from "./FegyverSelector";
|
||||||
export function FegyverLabel(fegyver: Fegyver): string {
|
|
||||||
const flags = [] as string[]
|
|
||||||
if (fegyver.Harcos) {
|
|
||||||
flags.push("H")
|
|
||||||
}
|
|
||||||
if (fegyver.Masfelkezes) {
|
|
||||||
flags.push("1½K")
|
|
||||||
}
|
|
||||||
if (fegyver.Ketkezes) {
|
|
||||||
if (fegyver.Type === "kozelharci") {
|
|
||||||
flags.push("2K")
|
|
||||||
} else {
|
|
||||||
if (fegyver.KetkezesBonusz) {
|
|
||||||
flags.push("2KB")
|
|
||||||
} else {
|
|
||||||
flags.push("2KN")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (fegyver.HarciManover) {
|
|
||||||
flags.push("+2 HM")
|
|
||||||
}
|
|
||||||
if (fegyver.Alakzat){
|
|
||||||
flags.push("AL")
|
|
||||||
}
|
|
||||||
if (fegyver.Hosszu) {
|
|
||||||
flags.push("HO")
|
|
||||||
}
|
|
||||||
if (fegyver.Kabito) {
|
|
||||||
flags.push("KO")
|
|
||||||
}
|
|
||||||
if (fegyver.LovasRoham) {
|
|
||||||
flags.push("LR")
|
|
||||||
}
|
|
||||||
if (fegyver.PancelToro) {
|
|
||||||
flags.push("PT")
|
|
||||||
}
|
|
||||||
if (fegyver.PajzsZuzo) {
|
|
||||||
flags.push("PZ")
|
|
||||||
}
|
|
||||||
if (fegyver.Rohamtoro) {
|
|
||||||
flags.push("RT")
|
|
||||||
}
|
|
||||||
// if (fegyver.EroBonusz) {
|
|
||||||
// flags.push("ER")
|
|
||||||
// }
|
|
||||||
if (fegyver.Megjegyzes != null && fegyver.Megjegyzes.length > 0) {
|
|
||||||
flags.push(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}` : ''} ${
|
|
||||||
fegyver.CritRangeStart < 20 ? `${fegyver.CritRangeStart}-20` : ''}x${fegyver.CritMultiplier}${
|
|
||||||
fegyver.Price > 0 ? ` | ár: ${fegyver.Price} at ` : ''}${
|
|
||||||
fegyver.Range > 10 ? ` | táv: ${fegyver.Range}` : ''}`
|
|
||||||
}
|
|
||||||
|
|
||||||
function Felszereles(props: {felszereles: KarakterFelszereles, changeFelszereles: (felszereles: KarakterFelszereles) => void, osztaly: Osztaly2E}) {
|
function Felszereles(props: {felszereles: KarakterFelszereles, changeFelszereles: (felszereles: KarakterFelszereles) => void, osztaly: Osztaly2E}) {
|
||||||
const { felszereles, changeFelszereles, osztaly } = props;
|
const { felszereles, changeFelszereles, osztaly } = props;
|
||||||
@@ -116,21 +59,7 @@ function Felszereles(props: {felszereles: KarakterFelszereles, changeFelszereles
|
|||||||
{valasztottFegyverek.map(({idx, fegyver}) => (
|
{valasztottFegyverek.map(({idx, fegyver}) => (
|
||||||
<div key={`fegyver-${idx}`} className='row m-2'>
|
<div key={`fegyver-${idx}`} className='row m-2'>
|
||||||
<label className='col-md-2 col-sm-3 col-form-label'>Fegyver</label>
|
<label className='col-md-2 col-sm-3 col-form-label'>Fegyver</label>
|
||||||
<select className='col form-select' value={fegyver.Id}
|
<FegyverSelector fegyverek={allowedFegyverek} selectedId={fegyver.Id} onChange={(fegyverId) => changeFegyver(idx, fegyverId)} />
|
||||||
onChange={e => changeFegyver(idx, e.target.value)}>
|
|
||||||
<optgroup label="Közelharci">
|
|
||||||
{allowedFegyverek.filter(f => f.Type === 'kozelharci').map(f => <option
|
|
||||||
key={f.Id} value={f.Id}>{FegyverLabel(f)}</option>)}
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="Közelharci, dobható">
|
|
||||||
{allowedFegyverek.filter(f => f.Type === 'dobhato').map(f => <option
|
|
||||||
key={f.Id} value={f.Id}>{FegyverLabel(f)}</option>)}
|
|
||||||
</optgroup>
|
|
||||||
<optgroup label="Távolsági">
|
|
||||||
{allowedFegyverek.filter(f => f.Type === 'lofegyver').map(f => <option
|
|
||||||
key={f.Id} value={f.Id}>{FegyverLabel(f)}</option>)}
|
|
||||||
</optgroup>
|
|
||||||
</select>
|
|
||||||
<button className='col-md-2 col-sm-3 btn btn-outline-dark btn-lg ms-2' type='button'
|
<button className='col-md-2 col-sm-3 btn btn-outline-dark btn-lg ms-2' type='button'
|
||||||
onClick={() => changeFelszereles({
|
onClick={() => changeFelszereles({
|
||||||
...felszereles,
|
...felszereles,
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {GetFegyver} from "../domain-models/felszereles";
|
||||||
|
import FegyverSelector from "./FegyverSelector";
|
||||||
|
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
||||||
|
import {Osztaly2E} from "../domain-models/osztaly2E";
|
||||||
|
|
||||||
|
function HarcosFegyverSpecializacio(props: {
|
||||||
|
specialization: string,
|
||||||
|
existingSpecializations: (string | undefined)[],
|
||||||
|
changeSpecialization: (specialization: string) => void
|
||||||
|
szint: number
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
specialization,
|
||||||
|
existingSpecializations,
|
||||||
|
changeSpecialization,
|
||||||
|
szint
|
||||||
|
} = props
|
||||||
|
const fegyver = GetFegyver(specialization)
|
||||||
|
const availableFegyverek = AllowedFegyver(Osztaly2E.Harcos)
|
||||||
|
const pickableFegyverek = availableFegyverek.filter(f => f.Id === specialization || existingSpecializations.filter(x => x === f.Id).length < (szint < 9 ? 1 : 2))
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className='row m-2'>
|
||||||
|
<label className='col-md-2 col-sm-3 col-form-label' >Fegyver specializáció</label>
|
||||||
|
<FegyverSelector fegyverek={pickableFegyverek} selectedId={specialization} onChange={changeSpecialization} />
|
||||||
|
{fegyver == null && <span className='form-field-error'>Ismeretlen fegyver: {specialization}</span>}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HarcosFegyverSpecializacio
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Osztaly2E} from "../domain-models/osztaly2E";
|
||||||
|
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
||||||
|
import FegyverSelector from "./FegyverSelector";
|
||||||
|
|
||||||
|
function KalozKritikus(props: {
|
||||||
|
kritFegyverId: string,
|
||||||
|
existingKrits: (string | undefined)[],
|
||||||
|
changeKrit: (krit: string) => void,
|
||||||
|
szint: number
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
kritFegyverId,
|
||||||
|
existingKrits,
|
||||||
|
changeKrit,
|
||||||
|
szint
|
||||||
|
} = props
|
||||||
|
const fegyverek = AllowedFegyver(Osztaly2E.Tengeresz).filter(f => f.Id === kritFegyverId || existingKrits.filter(x => x === f.Id).length < (szint < 9 ? 1 : 2))
|
||||||
|
|
||||||
|
return <>
|
||||||
|
<div className='row m-2'>
|
||||||
|
<label className='col-md-2 col-sm-3 col-form-label'>Kritikus</label>
|
||||||
|
<FegyverSelector fegyverek={fegyverek} selectedId={kritFegyverId} onChange={changeKrit} />
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default KalozKritikus
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Karakter2E} from "../domain-models/karakter2E";
|
||||||
|
import BasicNewLevel from "./BasicNewLevel";
|
||||||
|
import TulajdonsagNoveles from "./TulajdonsagNoveles";
|
||||||
|
import {Tulajdonsag2E, TulajdonsagokTotal} from "../domain-models/tulajdonsag2E";
|
||||||
|
import {arraySetN} from "../../util";
|
||||||
|
import {Osztaly2E} from "../domain-models/osztaly2E";
|
||||||
|
import KalozKritikus from "./KalozKritikus";
|
||||||
|
import HarcosFegyverSpecializacio from "./HarcosFegyverSpec";
|
||||||
|
|
||||||
|
function LevelUp(props: {
|
||||||
|
szint: number,
|
||||||
|
karakter: Karakter2E,
|
||||||
|
changeTulajdonsagNoveles: (t: Tulajdonsag2E) => void,
|
||||||
|
changeRolledHP: (rolledHP: number) => void,
|
||||||
|
changeHarcosSpec: (spec: string) => void,
|
||||||
|
changeKalozKritikus: (krit: string) => void,
|
||||||
|
}) {
|
||||||
|
const {
|
||||||
|
szint,
|
||||||
|
karakter,
|
||||||
|
changeTulajdonsagNoveles,
|
||||||
|
changeRolledHP,
|
||||||
|
changeHarcosSpec,
|
||||||
|
changeKalozKritikus,
|
||||||
|
} = props
|
||||||
|
|
||||||
|
const specialization = karakter.szintlepesek[szint-1].harcosFegyver
|
||||||
|
const krit = karakter.szintlepesek[szint-1].kalozKritikus
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<div className='row mt-3'>
|
||||||
|
<h5 className='col align-self-center'>{szint}. Szint</h5>
|
||||||
|
</div>
|
||||||
|
{szint % 4 === 0
|
||||||
|
&& <TulajdonsagNoveles
|
||||||
|
tulajdonsagok={karakter.tulajdonsagok}
|
||||||
|
tulajdonsagNoveles={karakter.szintlepesek[szint-1].tulajdonsagNoveles!}
|
||||||
|
changeTulajdonsagNoveles={changeTulajdonsagNoveles}
|
||||||
|
/>}
|
||||||
|
<BasicNewLevel
|
||||||
|
szint={szint}
|
||||||
|
karakter={karakter}
|
||||||
|
changeRolledHP={changeRolledHP}
|
||||||
|
/>
|
||||||
|
{karakter.osztaly === Osztaly2E.Harcos && szint % 2 === 1 &&
|
||||||
|
<HarcosFegyverSpecializacio
|
||||||
|
specialization={specialization!}
|
||||||
|
existingSpecializations={karakter.szintlepesek.map(x => x.harcosFegyver)}
|
||||||
|
changeSpecialization={changeHarcosSpec}
|
||||||
|
szint={szint}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
{karakter.osztaly === Osztaly2E.Tengeresz && szint % 3 === 0 && !!krit &&
|
||||||
|
<KalozKritikus
|
||||||
|
kritFegyverId={krit}
|
||||||
|
existingKrits={karakter.szintlepesek.map(x => x.kalozKritikus)}
|
||||||
|
changeKrit={changeKalozKritikus}
|
||||||
|
szint={szint}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
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 - 1)})
|
||||||
|
|
||||||
|
const changeRolledHPAtSzint = (szint: number) => (newHProll: number) => {
|
||||||
|
changeKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, szint-2, {...karakter.szintlepesek[szint-2], HProll: newHProll})})
|
||||||
|
console.log(karakter)
|
||||||
|
}
|
||||||
|
const changeTulajdonsagNovelesAtSzint = (szint: number) => {
|
||||||
|
return (t: Tulajdonsag2E) => {
|
||||||
|
changeKarakter({...karakter,
|
||||||
|
szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {
|
||||||
|
...karakter.szintlepesek[szint-1],
|
||||||
|
tulajdonsagNoveles: t
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeHarcosSpecializacioAtSzint = (szint: number) => {
|
||||||
|
return (spec: string) => {
|
||||||
|
changeKarakter({
|
||||||
|
...karakter,
|
||||||
|
szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {
|
||||||
|
...karakter.szintlepesek[szint-1],
|
||||||
|
harcosFegyver: spec
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const changeKalozKritikusAtSzint = (szint: number) => {
|
||||||
|
return (krit: string) => {
|
||||||
|
changeKarakter({
|
||||||
|
...karakter,
|
||||||
|
szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {
|
||||||
|
...karakter.szintlepesek[szint-1],
|
||||||
|
kalozKritikus: krit
|
||||||
|
})
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const levels = karakter.szintlepesek.map((_, i) => i+1);
|
||||||
|
|
||||||
|
return <>
|
||||||
|
{levels.slice(1).map(szint =>
|
||||||
|
<LevelUp
|
||||||
|
key={`level-up-${szint}`}
|
||||||
|
szint={szint}
|
||||||
|
karakter={{...karakter, tulajdonsagok: tulajdonsagokAtSzint(szint)}}
|
||||||
|
changeTulajdonsagNoveles={changeTulajdonsagNovelesAtSzint(szint)}
|
||||||
|
changeRolledHP={changeRolledHPAtSzint(szint)}
|
||||||
|
changeHarcosSpec={changeHarcosSpecializacioAtSzint(szint)}
|
||||||
|
changeKalozKritikus={changeKalozKritikusAtSzint(szint)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LevelUps
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {
|
||||||
|
KarakterTulajdonsagok,
|
||||||
|
Modifier,
|
||||||
|
Tulajdonsag2E,
|
||||||
|
TulajdonsagIDs,
|
||||||
|
TulajdonsagLabel
|
||||||
|
} from "../domain-models/tulajdonsag2E";
|
||||||
|
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||||
|
|
||||||
|
function TulajdonsagNoveles(props: {tulajdonsagok: KarakterTulajdonsagok, tulajdonsagNoveles: Tulajdonsag2E, changeTulajdonsagNoveles: (tulajdonsag: Tulajdonsag2E) => void}) {
|
||||||
|
const {tulajdonsagok, tulajdonsagNoveles, changeTulajdonsagNoveles} = props
|
||||||
|
return <>
|
||||||
|
<div className='row'>
|
||||||
|
<div className='col-lg-6'>
|
||||||
|
<div className='row m-2'>
|
||||||
|
<label className='col-sm-6 col-8 col-form-label'>Tulajdonság növelés{' '}</label>
|
||||||
|
<div className='col'>
|
||||||
|
<select className='form-select' value={tulajdonsagNoveles} onChange={(e) => changeTulajdonsagNoveles(e.target.value as Tulajdonsag2E)}>
|
||||||
|
{TulajdonsagIDs.filter(t => t === tulajdonsagNoveles || tulajdonsagok[t] < 18).map(t => (
|
||||||
|
<option value={t} key={t}>{TulajdonsagLabel(t)}</option>
|
||||||
|
))}
|
||||||
|
</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 {TulajdonsagLabel(tulajdonsagNoveles)}{' '}</label>
|
||||||
|
<span className='col col-form-label'>{tulajdonsagok[tulajdonsagNoveles]} ({SignedNumberToText(Modifier(tulajdonsagok[tulajdonsagNoveles]))})</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default TulajdonsagNoveles
|
||||||
@@ -4,6 +4,10 @@ import {Osztaly2E} from "./osztaly2E";
|
|||||||
import {KepzettsegId} from "./kepzettsegek2E";
|
import {KepzettsegId} from "./kepzettsegek2E";
|
||||||
import {JellemID} from "./jellem";
|
import {JellemID} from "./jellem";
|
||||||
import {DefaultFelszereles, KarakterFelszereles} from "./felszereles";
|
import {DefaultFelszereles, KarakterFelszereles} from "./felszereles";
|
||||||
|
import {Szintlepes} from "./szintlepes";
|
||||||
|
import {AllowedFegyver} from "./allowed-fegyver";
|
||||||
|
import {BaseHP} from "./masodlagos_ertekek";
|
||||||
|
import {dAny} from "../../shared/domain-models/kockak";
|
||||||
|
|
||||||
export interface Karakter2E {
|
export interface Karakter2E {
|
||||||
name: string,
|
name: string,
|
||||||
@@ -14,13 +18,11 @@ export interface Karakter2E {
|
|||||||
tulajdonsagok: KarakterTulajdonsagok
|
tulajdonsagok: KarakterTulajdonsagok
|
||||||
faj: Faj2E
|
faj: Faj2E
|
||||||
osztaly: Osztaly2E
|
osztaly: Osztaly2E
|
||||||
harcosSpecializaciok: string[],
|
|
||||||
kalozKritikus: string[],
|
|
||||||
kepzettsegek: KepzettsegId[]
|
kepzettsegek: KepzettsegId[]
|
||||||
tolvajKepzettsegek?: KepzettsegId[]
|
tolvajKepzettsegek?: KepzettsegId[]
|
||||||
szint: number,
|
szint: number,
|
||||||
hpRolls: number[]
|
|
||||||
felszereles: KarakterFelszereles,
|
felszereles: KarakterFelszereles,
|
||||||
|
szintlepesek: Szintlepes[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DefaultKarakter: Karakter2E = {
|
export const DefaultKarakter: Karakter2E = {
|
||||||
@@ -30,11 +32,44 @@ export const DefaultKarakter: Karakter2E = {
|
|||||||
tulajdonsagok: TulajdonsagDefaults,
|
tulajdonsagok: TulajdonsagDefaults,
|
||||||
faj: Faj2E.Ember,
|
faj: Faj2E.Ember,
|
||||||
osztaly: Osztaly2E.Tengeresz,
|
osztaly: Osztaly2E.Tengeresz,
|
||||||
harcosSpecializaciok: [],
|
|
||||||
kalozKritikus: [],
|
|
||||||
kepzettsegek: [],
|
kepzettsegek: [],
|
||||||
tolvajKepzettsegek: [],
|
tolvajKepzettsegek: [],
|
||||||
szint: 1,
|
szint: 1,
|
||||||
hpRolls: [],
|
|
||||||
felszereles: DefaultFelszereles,
|
felszereles: DefaultFelszereles,
|
||||||
}
|
szintlepesek: [{
|
||||||
|
osztaly: Osztaly2E.Tengeresz,
|
||||||
|
HProll: 10,
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
function setOsztalyForSzintLepes(szintlepes: Szintlepes, osztaly: Osztaly2E, szint: number): Szintlepes {
|
||||||
|
const base : Szintlepes = {
|
||||||
|
...szintlepes,
|
||||||
|
osztaly,
|
||||||
|
harcosFegyver: undefined,
|
||||||
|
kalozKritikus: undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
const HD = BaseHP(osztaly)
|
||||||
|
if (szint === 1) {
|
||||||
|
base.HProll = HD
|
||||||
|
} else {
|
||||||
|
base.HProll = dAny(HD)
|
||||||
|
console.log(`Level ${szint} HP roll on d${HD} is: ${base.HProll} due to class change`)
|
||||||
|
}
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ChangeLvl1Osztaly(karakter: Karakter2E, osztaly: Osztaly2E): Karakter2E {
|
||||||
|
return {
|
||||||
|
...karakter,
|
||||||
|
osztaly,
|
||||||
|
szintlepesek: karakter.szintlepesek.map((l, idx) => setOsztalyForSzintLepes(l, osztaly, idx +1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -228,7 +228,7 @@ export function GetNumberOfKepzettsegek(t_int: number, faj: Faj2E, max: number =
|
|||||||
return numberOfKepzettseg;
|
return numberOfKepzettseg;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SetDefaultTolvajKepzettsegek(karakter: Pick<Karakter2E, 'osztaly' | 'tolvajKepzettsegek'>, changeTolvajKepzettsegek: (tolvajKepzettsegek?: KepzettsegId[]) => void) {
|
export function SetDefaultTolvajKepzettsegek(karakter: Pick<Karakter2E, 'osztaly' | 'szintlepesek' | 'tolvajKepzettsegek'>, changeTolvajKepzettsegek: (tolvajKepzettsegek?: KepzettsegId[]) => void) {
|
||||||
if (karakter.osztaly !== Osztaly2E.Tolvaj && karakter.tolvajKepzettsegek != null) {
|
if (karakter.osztaly !== Osztaly2E.Tolvaj && karakter.tolvajKepzettsegek != null) {
|
||||||
changeTolvajKepzettsegek(undefined)
|
changeTolvajKepzettsegek(undefined)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export interface MasodlagosErtekekView {
|
|||||||
Mentok: Mentok
|
Mentok: Mentok
|
||||||
}
|
}
|
||||||
|
|
||||||
export type KarakterpickForMasodlagosErtekek = Pick<Karakter2E, 'osztaly' | 'hpRolls' | 'tulajdonsagok' | 'szint' | 'faj' | 'felszereles'>
|
export type KarakterpickForMasodlagosErtekek = Pick<Karakter2E, 'osztaly' | 'tulajdonsagok' | 'szint' | 'szintlepesek' | 'faj' | 'felszereles'>
|
||||||
|
|
||||||
export function BaseHP(osztaly: Osztaly2E) {
|
export function BaseHP(osztaly: Osztaly2E) {
|
||||||
let base = 4;
|
let base = 4;
|
||||||
@@ -45,11 +45,11 @@ export function BaseHP(osztaly: Osztaly2E) {
|
|||||||
return base
|
return base
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HP(karakter: Pick<Karakter2E, 'osztaly' | 'tulajdonsagok' | 'hpRolls'>): number {
|
export function HP(karakter: Pick<Karakter2E, 'osztaly' | 'tulajdonsagok' | 'szintlepesek'>): number {
|
||||||
const egeszsegModifier = Modifier(karakter.tulajdonsagok.t_egs)
|
const egeszsegModifier = Modifier(karakter.tulajdonsagok.t_egs)
|
||||||
return BaseHP(karakter.osztaly) + egeszsegModifier + karakter.hpRolls
|
return karakter.szintlepesek
|
||||||
// https://lfg.hu/forum/topic/15079-kard-es-magia/page/219/#comment-2218333
|
// https://lfg.hu/forum/topic/15079-kard-es-magia/page/219/#comment-2218333
|
||||||
.map(hp => Math.max(1, hp + egeszsegModifier))
|
.map(szint => Math.max(1, szint.HProll + egeszsegModifier))
|
||||||
.reduce((sum, val) => sum + val, 0)
|
.reduce((sum, val) => sum + val, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import {Tulajdonsag2E, TulajdonsagIDs, TulajdonsagokTotal} from "./tulajdonsag2E";
|
||||||
|
import {KepzettsegId} from "./kepzettsegek2E";
|
||||||
|
import {Osztaly2E} from "./osztaly2E";
|
||||||
|
import {Karakter2E} from "./karakter2E";
|
||||||
|
import {BaseHP} from "./masodlagos_ertekek";
|
||||||
|
import {dAny} from "../../shared/domain-models/kockak";
|
||||||
|
import {AllowedFegyver} from "./allowed-fegyver";
|
||||||
|
|
||||||
|
export interface Szintlepes {
|
||||||
|
osztaly: Osztaly2E;
|
||||||
|
HProll: number;
|
||||||
|
tolvajExtraKepzettseg?: KepzettsegId; // only at level 5 and 9
|
||||||
|
harcosFegyver?: string; // every 3rd level
|
||||||
|
kalozKritikus?: string; // every odd level
|
||||||
|
tulajdonsagNoveles?: Tulajdonsag2E;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function PickableSpecializationFilter(existingSpecilizations: (string | undefined)[], szint: number) {
|
||||||
|
return (fegyver: {Id: string}) => existingSpecilizations.filter(x => x === fegyver.Id).length < (szint < 9 ? 1 : 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LevelUp(karakter: Karakter2E, changeKarakter: (input: Karakter2E) => void) {
|
||||||
|
const tulajdonsagokTotal = TulajdonsagokTotal(karakter)
|
||||||
|
const szint = karakter.szint + 1
|
||||||
|
const dice = BaseHP(karakter.osztaly)
|
||||||
|
const roll = dAny(dice)
|
||||||
|
console.log(`Level ${szint} HP roll on d${dice} is: ${roll}`)
|
||||||
|
|
||||||
|
const szintlepes: Szintlepes = {
|
||||||
|
osztaly: karakter.osztaly,
|
||||||
|
HProll: roll
|
||||||
|
}
|
||||||
|
|
||||||
|
if (szint % 4 === 0) {
|
||||||
|
for (const tulajdonsag of TulajdonsagIDs) {
|
||||||
|
if (tulajdonsagokTotal[tulajdonsag] < 18) {
|
||||||
|
szintlepes.tulajdonsagNoveles = tulajdonsag;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(karakter.osztaly === Osztaly2E.Harcos && szint % 2 === 1) {
|
||||||
|
const harcosSpecializaciok = karakter.szintlepesek.map(x => x.harcosFegyver)
|
||||||
|
szintlepes.harcosFegyver = AllowedFegyver(Osztaly2E.Harcos).filter(PickableSpecializationFilter(harcosSpecializaciok, karakter.szint))[0].Id
|
||||||
|
}
|
||||||
|
if(karakter.osztaly === Osztaly2E.Tengeresz && szint % 3 === 0) {
|
||||||
|
let kalozKritikus = karakter.szintlepesek.map(x => x.kalozKritikus)
|
||||||
|
szintlepes.kalozKritikus = AllowedFegyver(Osztaly2E.Tengeresz).filter(PickableSpecializationFilter(kalozKritikus, szint))[0].Id
|
||||||
|
}
|
||||||
|
changeKarakter({...karakter, szint, szintlepesek: [...karakter.szintlepesek, szintlepes]})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function LevelDown(karakter: Karakter2E, changeKarakter: (input: Karakter2E) => void) {
|
||||||
|
if (karakter.szintlepesek.length > 1) {
|
||||||
|
changeKarakter({...karakter, szint: karakter.szint - 1, szintlepesek: karakter.szintlepesek.slice(0, -1)})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
console.error(`Can't level down character: ${karakter}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
import {d6} from "../../shared/domain-models/kockak";
|
import {d6} from "../../shared/domain-models/kockak";
|
||||||
|
import {Karakter2E} from "./karakter2E";
|
||||||
|
import {TulajdonsagokFajjal} from "./faj2E";
|
||||||
|
|
||||||
export enum Tulajdonsag2E {
|
export enum Tulajdonsag2E {
|
||||||
Ero = 't_ero',
|
Ero = 't_ero',
|
||||||
@@ -73,4 +75,16 @@ export function TulajdonsagModosito(tulajdonsagok: KarakterTulajdonsagok): Karak
|
|||||||
response[key] = Modifier(tulajdonsagok[key])
|
response[key] = Modifier(tulajdonsagok[key])
|
||||||
}
|
}
|
||||||
return response
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TulajdonsagokTotal(karakter: Pick<Karakter2E, 'tulajdonsagok' | 'faj' | 'szintlepesek'>): KarakterTulajdonsagok {
|
||||||
|
const level1 = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
|
||||||
|
return {
|
||||||
|
t_ero: level1.t_ero + karakter.szintlepesek.filter(s => s.tulajdonsagNoveles === 't_ero').length,
|
||||||
|
t_ugy: level1.t_ugy + karakter.szintlepesek.filter(s => s.tulajdonsagNoveles === 't_ugy').length,
|
||||||
|
t_egs: level1.t_egs + karakter.szintlepesek.filter(s => s.tulajdonsagNoveles === 't_egs').length,
|
||||||
|
t_int: level1.t_int + karakter.szintlepesek.filter(s => s.tulajdonsagNoveles === 't_int').length,
|
||||||
|
t_bol: level1.t_bol + karakter.szintlepesek.filter(s => s.tulajdonsagNoveles === 't_bol').length,
|
||||||
|
t_kar: level1.t_kar + karakter.szintlepesek.filter(s => s.tulajdonsagNoveles === 't_kar').length,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, {useState} from 'react'
|
import React, {useState} from 'react'
|
||||||
import {useParams} from "react-router-dom";
|
import {useParams} from "react-router-dom";
|
||||||
import {Toast, ToastContainer} from "react-bootstrap";
|
import {Toast, ToastContainer} from "react-bootstrap";
|
||||||
import {DefaultKarakter} from "../domain-models/karakter2E";
|
import {ChangeLvl1Osztaly, DefaultKarakter} from "../domain-models/karakter2E";
|
||||||
import {KarakterTulajdonsagok} from "../domain-models/tulajdonsag2E";
|
import {KarakterTulajdonsagok} from "../domain-models/tulajdonsag2E";
|
||||||
import FajSelector2E from "../components/FajSelector2E";
|
import FajSelector2E from "../components/FajSelector2E";
|
||||||
import Tulajdonsagok2E from "../components/Tulajdonsagok2E";
|
import Tulajdonsagok2E from "../components/Tulajdonsagok2E";
|
||||||
@@ -20,6 +20,10 @@ import MasodlagosErtekek from "../components/MasodlagosErtekek";
|
|||||||
import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
|
import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
|
||||||
import Felszereles from "../components/Felszereles";
|
import Felszereles from "../components/Felszereles";
|
||||||
import {KarakterFelszereles} from "../domain-models/felszereles";
|
import {KarakterFelszereles} from "../domain-models/felszereles";
|
||||||
|
import LevelUps from "../components/LevelUps";
|
||||||
|
import {LevelDown, LevelUp} from "../domain-models/szintlepes";
|
||||||
|
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpec";
|
||||||
|
import {arraySetN} from "../../util";
|
||||||
|
|
||||||
function CreateCharacter2E(props: {}) {
|
function CreateCharacter2E(props: {}) {
|
||||||
|
|
||||||
@@ -100,12 +104,15 @@ function CreateCharacter2E(props: {}) {
|
|||||||
<OsztalySelector2E
|
<OsztalySelector2E
|
||||||
currentFaj={karakter.faj}
|
currentFaj={karakter.faj}
|
||||||
currentOsztaly={karakter.osztaly}
|
currentOsztaly={karakter.osztaly}
|
||||||
changeOsztaly={osztaly => setKarakter({...karakter, osztaly})}
|
changeOsztaly={o => setKarakter(ChangeLvl1Osztaly(karakter, o))}
|
||||||
/>
|
/>
|
||||||
{karakter.osztaly === Osztaly2E.Harcos &&
|
{karakter.szintlepesek[0].osztaly === Osztaly2E.Harcos &&
|
||||||
<div className='mb-6'>
|
<HarcosFegyverSpecializacio
|
||||||
TODO: Harcos fegyver specializaciok!!
|
specialization={karakter.szintlepesek[0].harcosFegyver || 'kard_hosszu'}
|
||||||
</div>}
|
szint={1}
|
||||||
|
changeSpecialization={(spec) => setKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, 0, {...karakter.szintlepesek[0], harcosFegyver: spec})})}
|
||||||
|
existingSpecializations={karakter.szintlepesek.map(x => x.harcosFegyver)}
|
||||||
|
/>}
|
||||||
<KarakterKepzettsegek
|
<KarakterKepzettsegek
|
||||||
getKepzettsegListaN={GetKepzettsegListaN(karakter)}
|
getKepzettsegListaN={GetKepzettsegListaN(karakter)}
|
||||||
numberOfKepzettsegek={GetNumberOfKepzettsegek(tulajdonsagokFajjal.t_int, karakter.faj)}
|
numberOfKepzettsegek={GetNumberOfKepzettsegek(tulajdonsagokFajjal.t_int, karakter.faj)}
|
||||||
@@ -120,10 +127,21 @@ function CreateCharacter2E(props: {}) {
|
|||||||
...karakter,
|
...karakter,
|
||||||
tulajdonsagok: tulajdonsagokFajjal,
|
tulajdonsagok: tulajdonsagokFajjal,
|
||||||
szint: 1,
|
szint: 1,
|
||||||
hpRolls: []
|
szintlepesek: karakter.szintlepesek.slice(0,1)
|
||||||
})} />
|
})} />
|
||||||
<hr />
|
<hr />
|
||||||
<Felszereles osztaly={karakter.osztaly} felszereles={karakter.felszereles}
|
<LevelUps karakter={karakter} changeKarakter={setKarakter}/>
|
||||||
|
{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>}
|
||||||
|
{karakter.szint > 1 &&
|
||||||
|
<button className='btn btn-dark btn-lg' type='button' onClick={() => LevelDown(karakter, setKarakter)}>Visszalépés!
|
||||||
|
⇩</button>}
|
||||||
|
</div>
|
||||||
|
<hr/>
|
||||||
|
<Felszereles osztaly={karakter.szintlepesek[0].osztaly} felszereles={karakter.felszereles}
|
||||||
changeFelszereles={changeFelszereles}/>
|
changeFelszereles={changeFelszereles}/>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
|
|||||||
+317
-386
File diff suppressed because it is too large
Load Diff
@@ -91,5 +91,9 @@ http {
|
|||||||
proxy_pass https://backend;
|
proxy_pass https://backend;
|
||||||
proxy_pass_request_headers on;
|
proxy_pass_request_headers on;
|
||||||
}
|
}
|
||||||
|
location /img/ {
|
||||||
|
proxy_pass https://backend;
|
||||||
|
proxy_pass_request_headers on;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,16 @@
|
|||||||
"resolved": "8.0.0",
|
"resolved": "8.0.0",
|
||||||
"contentHash": "+MtOHPctq1QT1c03h+7g4oBWtZ/buQYUJg4AR0DG+qjmD2cQRMGWXC1J6/ITeCc6xa5BcXzJmt1L/8pVXIB4kw=="
|
"contentHash": "+MtOHPctq1QT1c03h+7g4oBWtZ/buQYUJg4AR0DG+qjmD2cQRMGWXC1J6/ITeCc6xa5BcXzJmt1L/8pVXIB4kw=="
|
||||||
},
|
},
|
||||||
|
"Grpc.Core": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[2.46.6, )",
|
||||||
|
"resolved": "2.46.6",
|
||||||
|
"contentHash": "ZoRg3KmOJ2urTF4+u3H0b1Yv10xzz2Y/flFWS2tnRmj8dbKLeiJaSRqu4LOBD3ova90evqLkVZ85kUkC4JT4lw==",
|
||||||
|
"dependencies": {
|
||||||
|
"Grpc.Core.Api": "2.46.6",
|
||||||
|
"System.Memory": "4.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.AspNetCore.Authentication.Facebook": {
|
"Microsoft.AspNetCore.Authentication.Facebook": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[8.0.0, )",
|
"requested": "[8.0.0, )",
|
||||||
@@ -124,6 +134,78 @@
|
|||||||
"Npgsql.EntityFrameworkCore.PostgreSQL": "1.1.0"
|
"Npgsql.EntityFrameworkCore.PostgreSQL": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"OpenTelemetry.Exporter.Console": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.7.0, )",
|
||||||
|
"resolved": "1.7.0",
|
||||||
|
"contentHash": "9mcwpArzG7+5cLnG6marWdVD1TyoVR03WAjShvxADqgsEeuzLMClTlgXi41bTCAgxjYyiHV5l60fJwXTekiJdQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"OpenTelemetry": "1.7.0",
|
||||||
|
"System.Text.Encodings.Web": "4.7.2",
|
||||||
|
"System.Text.Json": "4.7.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OpenTelemetry.Exporter.OpenTelemetryProtocol": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.7.0, )",
|
||||||
|
"resolved": "1.7.0",
|
||||||
|
"contentHash": "ULGTxg4HdnJD+CIuiD15Uov4xVVqwpbNGFd075J3MT3lLM9XcwU4YRz7CCNmqIlehYaiZrGhUurXrI2LgZZL1Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"Google.Protobuf": "[3.22.5, 4.0.0)",
|
||||||
|
"Grpc.Net.Client": "[2.52.0, 3.0.0)",
|
||||||
|
"OpenTelemetry": "1.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OpenTelemetry.Extensions.Hosting": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.7.0, )",
|
||||||
|
"resolved": "1.7.0",
|
||||||
|
"contentHash": "MbB7CWWqb7xHK0jTF9Gtvw/eLWdaKqzkE1XAwLe05xyskHuwJWAbZFax4nGLA71YkMWQNO5iPIBlirvYXOLMlg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Diagnostics.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Hosting.Abstractions": "8.0.0",
|
||||||
|
"OpenTelemetry": "1.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OpenTelemetry.Instrumentation.AspNetCore": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[1.7.0, )",
|
||||||
|
"resolved": "1.7.0",
|
||||||
|
"contentHash": "K/mjCmuR9zgrL6fMC6sbnX/y6BOJJFI3hp42O+tz8nT/w6sxbfjrLcU+fVwfct3lsnohSKdPfrq6fSrxAF5ezw==",
|
||||||
|
"dependencies": {
|
||||||
|
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Google.Protobuf": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "3.22.5",
|
||||||
|
"contentHash": "tTMtDZPbLxJew8pk7NBdqhLqC4OipfkZdwPuCEUNr2AoDo1siUGcxFqJK0wDewTL8ge5Cjrb16CToMPxBUHMGA=="
|
||||||
|
},
|
||||||
|
"Grpc.Core.Api": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "2.52.0",
|
||||||
|
"contentHash": "SQiPyBczG4vKPmI6Fd+O58GcxxDSFr6nfRAJuBDUNj+PgdokhjWJvZE/La1c09AkL2FVm/jrDloG89nkzmVF7A==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Memory": "4.5.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Grpc.Net.Client": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "2.52.0",
|
||||||
|
"contentHash": "hWVH9g/Nnjz40ni//2S8UIOyEmhueQREoZIkD0zKHEPqLxXcNlbp4eebXIOicZtkwDSx0TFz9NpkbecEDn6rBw==",
|
||||||
|
"dependencies": {
|
||||||
|
"Grpc.Net.Common": "2.52.0",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Grpc.Net.Common": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "2.52.0",
|
||||||
|
"contentHash": "di9qzpdx525IxumZdYmu6sG2y/gXJyYeZ1ruFUzB9BJ1nj4kU1/dTAioNCMt1VLRvNVDqh8S8B1oBdKhHJ4xRg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Grpc.Core.Api": "2.52.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Humanizer.Core": {
|
"Humanizer.Core": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "2.14.1",
|
"resolved": "2.14.1",
|
||||||
@@ -265,6 +347,15 @@
|
|||||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Configuration": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Configuration.Abstractions": {
|
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.0",
|
"resolved": "8.0.0",
|
||||||
@@ -273,6 +364,14 @@
|
|||||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Configuration.Binder": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "mBMoXLsr5s1y2zOHWmKsE9veDcx8h1x/c3rz4baEdQKTeDcmQAPNbB54Pi/lhFO3K431eEq6PFbMgLaa6PHFfA==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.DependencyInjection": {
|
"Microsoft.Extensions.DependencyInjection": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.0",
|
"resolved": "8.0.0",
|
||||||
@@ -371,6 +470,21 @@
|
|||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Logging.Configuration": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "ixXXV0G/12g6MXK65TLngYN9V5hQQRuV+fZi882WIoVJT7h5JvoYoxTEwCgdqwLjSneqh1O+66gM8sMr9z/rsQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Configuration.Binder": "8.0.0",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Logging": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Options": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Options": {
|
"Microsoft.Extensions.Options": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.0",
|
"resolved": "8.0.0",
|
||||||
@@ -380,6 +494,18 @@
|
|||||||
"Microsoft.Extensions.Primitives": "8.0.0"
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Options.ConfigurationExtensions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "8.0.0",
|
||||||
|
"contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Configuration.Binder": "8.0.0",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Options": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Primitives": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Primitives": {
|
"Microsoft.Extensions.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.0",
|
"resolved": "8.0.0",
|
||||||
@@ -472,6 +598,33 @@
|
|||||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.0"
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"OpenTelemetry": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.7.0",
|
||||||
|
"contentHash": "HNmOJg++4FtEJGCIn1dCJcDkHRLNuLKU047owrGXUOfz/C/c5oZHOPKrowKVOy2jOOh/F9+HDshzeOk5NnQEZg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Logging": "8.0.0",
|
||||||
|
"Microsoft.Extensions.Logging.Configuration": "8.0.0",
|
||||||
|
"OpenTelemetry.Api.ProviderBuilderExtensions": "1.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OpenTelemetry.Api": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.7.0",
|
||||||
|
"contentHash": "w5uDHl1Nm7R5igWu1QjewpdPzJSavua8NTI3+iThOdRNHD3cabox8JeIJ8LpBSXGHARSNFMJZ/Xr5EGRinMTMg==",
|
||||||
|
"dependencies": {
|
||||||
|
"System.Diagnostics.DiagnosticSource": "8.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"OpenTelemetry.Api.ProviderBuilderExtensions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "1.7.0",
|
||||||
|
"contentHash": "fHLmJcRJk1dAwddjBgvqi/Grmr04hPo1DoFwTa6hxtSvAFOXPU56Xe9Sh2VXqz6Gstzp6TCju8z0Sob1t7BzSg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
|
||||||
|
"OpenTelemetry.Api": "1.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
"runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
@@ -887,6 +1040,11 @@
|
|||||||
"System.Threading": "4.3.0"
|
"System.Threading": "4.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"System.Memory": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "4.5.3",
|
||||||
|
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
|
||||||
|
},
|
||||||
"System.Net.Http": {
|
"System.Net.Http": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "4.3.0",
|
"resolved": "4.3.0",
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 508.67 96.36"><g fill="#5865f2"><path d="M170.85,20.2h27.3q9.87,0,16.7,3.08a22.5,22.5,0,0,1,10.21,8.58,23.34,23.34,0,0,1,3.4,12.56A23.24,23.24,0,0,1,224.93,57a23.94,23.94,0,0,1-10.79,8.92q-7.24,3.3-17.95,3.29H170.85Zm25.06,36.54q6.65,0,10.22-3.32a11.8,11.8,0,0,0,3.57-9.07,11.5,11.5,0,0,0-3.18-8.5q-3.2-3.18-9.63-3.19h-8.54V56.74Z"/><path d="M269.34,69.13a37,37,0,0,1-10.22-4.27V53.24a27.77,27.77,0,0,0,9.2,4.38,39.31,39.31,0,0,0,11.17,1.71,8.71,8.71,0,0,0,3.82-.66c.86-.44,1.29-1,1.29-1.58a2.37,2.37,0,0,0-.7-1.75,6.15,6.15,0,0,0-2.73-1.19l-8.4-1.89q-7.22-1.68-10.25-4.65a10.39,10.39,0,0,1-3-7.81,10.37,10.37,0,0,1,2.66-7.07,17.13,17.13,0,0,1,7.56-4.65,36,36,0,0,1,11.48-1.65A43.27,43.27,0,0,1,292,27.69a30.25,30.25,0,0,1,8.12,3.22v11a30,30,0,0,0-7.6-3.11,34,34,0,0,0-8.85-1.16q-6.58,0-6.58,2.24a1.69,1.69,0,0,0,1,1.58,16.14,16.14,0,0,0,3.74,1.08l7,1.26Q295.65,45,299,48t3.36,8.78a11.61,11.61,0,0,1-5.57,10.12Q291.26,70.61,281,70.6A46.41,46.41,0,0,1,269.34,69.13Z"/><path d="M318.9,67.66a21,21,0,0,1-9.07-8,21.59,21.59,0,0,1-3-11.34,20.62,20.62,0,0,1,3.15-11.27,21.16,21.16,0,0,1,9.24-7.8,34.25,34.25,0,0,1,14.56-2.84q10.5,0,17.43,4.41V43.65a21.84,21.84,0,0,0-5.7-2.73,22.65,22.65,0,0,0-7-1.05q-6.51,0-10.19,2.38a7.15,7.15,0,0,0-.1,12.43q3.57,2.41,10.36,2.41a23.91,23.91,0,0,0,6.9-1,25.71,25.71,0,0,0,5.84-2.49V66a34,34,0,0,1-17.85,4.62A32.93,32.93,0,0,1,318.9,67.66Z"/><path d="M368.64,67.66a21.77,21.77,0,0,1-9.25-8,21.14,21.14,0,0,1-3.18-11.41A20.27,20.27,0,0,1,359.39,37a21.42,21.42,0,0,1,9.21-7.74,38.17,38.17,0,0,1,28.7,0,21.25,21.25,0,0,1,9.17,7.7,20.41,20.41,0,0,1,3.15,11.27,21.29,21.29,0,0,1-3.15,11.41,21.51,21.51,0,0,1-9.2,8,36.32,36.32,0,0,1-28.63,0Zm21.27-12.42a9.12,9.12,0,0,0,2.56-6.76,8.87,8.87,0,0,0-2.56-6.68,9.53,9.53,0,0,0-7-2.49,9.67,9.67,0,0,0-7,2.49,8.9,8.9,0,0,0-2.55,6.68,9.15,9.15,0,0,0,2.55,6.76,9.53,9.53,0,0,0,7,2.55A9.4,9.4,0,0,0,389.91,55.24Z"/><path d="M451.69,29V44.14a12.47,12.47,0,0,0-6.93-1.75c-3.73,0-6.61,1.14-8.61,3.4s-3,5.77-3,10.53V69.2H416V28.25h16.8v13q1.4-7.14,4.52-10.53a10.38,10.38,0,0,1,8-3.4A11.71,11.71,0,0,1,451.69,29Z"/><path d="M508.67,18.8V69.2H491.52V60a16.23,16.23,0,0,1-6.62,7.88A20.81,20.81,0,0,1,474,70.6a18.11,18.11,0,0,1-10.15-2.83A18.6,18.6,0,0,1,457.11,60a25.75,25.75,0,0,1-2.34-11.17,24.87,24.87,0,0,1,2.48-11.55,19.43,19.43,0,0,1,7.21-8,19.85,19.85,0,0,1,10.61-2.87q12.24,0,16.45,10.64V18.8ZM489,55a8.83,8.83,0,0,0,2.63-6.62A8.42,8.42,0,0,0,489,42a11,11,0,0,0-13.89,0,8.55,8.55,0,0,0-2.59,6.47A8.67,8.67,0,0,0,475.14,55,9.42,9.42,0,0,0,482,57.51,9.56,9.56,0,0,0,489,55Z"/><path d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z"/><ellipse cx="242.92" cy="24.93" rx="8.55" ry="7.68"/><path d="M234.36,37.9a22.08,22.08,0,0,0,17.11,0V69.42H234.36Z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.3 KiB |
Reference in New Issue
Block a user