mirror of
https://github.com/morbalint/kemkas.git
synced 2026-07-17 19:03:46 +00:00
ci: split repo: make this repo frontend only again
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
.git/
|
||||
node_modules/
|
||||
build/
|
||||
.tool-versions
|
||||
*.css
|
||||
*.css.map
|
||||
@@ -0,0 +1 @@
|
||||
BROWSER=none
|
||||
@@ -0,0 +1,3 @@
|
||||
PORT=44478
|
||||
HTTPS=true
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
FROM node:21.4-bookworm as builder
|
||||
|
||||
WORKDIR "/src"
|
||||
|
||||
COPY ["package.json", "yarn.lock", "./"]
|
||||
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN ./compile-less.sh
|
||||
RUN yarn build
|
||||
|
||||
FROM nginx:latest as proxy
|
||||
|
||||
COPY --from=builder "/src/build" "/usr/share/nginx/html"
|
||||
COPY ./nginx.conf /etc/nginx/nginx.conf
|
||||
@@ -0,0 +1,46 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `yarn start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||
|
||||
The page will reload if you make edits.\
|
||||
You will also see any lint errors in the console.
|
||||
|
||||
### `yarn test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `yarn run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `yarn run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can’t go back!**
|
||||
|
||||
If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
|
||||
|
||||
You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/bash
|
||||
echo "Compiling all LESS files to CSS"
|
||||
|
||||
function compile_less() {
|
||||
FROM=$1
|
||||
TO=${FROM/.*/.css}
|
||||
SOURCE_MAP=${FROM/.*/.css.map}
|
||||
echo "$FROM --> $TO & $SOURCE_MAP"
|
||||
node_modules/less/bin/lessc "$FROM" "$TO" --source-map="$SOURCE_MAP"
|
||||
}
|
||||
|
||||
export -f compile_less
|
||||
find src -type f -name '*.less' -exec bash -c 'compile_less $1' shell {} \;
|
||||
@@ -0,0 +1,36 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
{
|
||||
"name": "kemkas",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@grafana/faro-web-sdk": "^1.3.9",
|
||||
"@pdf-lib/fontkit": "^1.1.1",
|
||||
"@testing-library/jest-dom": "^6.1.4",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.5.1",
|
||||
"@types/jest": "^29.5.6",
|
||||
"@types/node": "^20.8.9",
|
||||
"@types/react": "^18.2.33",
|
||||
"@types/react-dom": "^18.2.13",
|
||||
"axios": "^1.6.2",
|
||||
"bootstrap": "^5.3.2",
|
||||
"downloadjs": "^1.4.7",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"jquery": "^3.6.0",
|
||||
"merge": "^2.1.1",
|
||||
"oidc-client": "^1.11.5",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.9.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.17.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"typescript": "^5.2.2",
|
||||
"web-vitals": "^3.5.0",
|
||||
"workbox-background-sync": "^6.5.4",
|
||||
"workbox-broadcast-update": "^6.5.4",
|
||||
"workbox-cacheable-response": "^6.5.4",
|
||||
"workbox-core": "^6.5.4",
|
||||
"workbox-expiration": "^6.5.4",
|
||||
"workbox-google-analytics": "^6.5.4",
|
||||
"workbox-navigation-preload": "^6.5.4",
|
||||
"workbox-precaching": "^6.5.4",
|
||||
"workbox-range-requests": "^6.5.4",
|
||||
"workbox-routing": "^6.5.4",
|
||||
"workbox-strategies": "^6.5.4",
|
||||
"workbox-streams": "^6.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||
"@types/downloadjs": "^1.4.4",
|
||||
"cross-env": "^7.0.3",
|
||||
"less": "^4.2.0",
|
||||
"less-loader": "^11.1.3"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "rimraf ./build && react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "cross-env CI=true react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,46 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="hu">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Kém Karakter alkotási segédlet"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Merienda&display=swap" rel="stylesheet">
|
||||
<title>Kém Karakter App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Open Game License v1.0a"
|
||||
/>
|
||||
<title>Open Game License v1.0a</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<P>THIS LICENSE IS APPROVED FOR GENERAL USE. PERMISSION TO DISTRIBUTE THIS LICENSE
|
||||
IS MADE BY WIZARDS OF THE COAST!</P>
|
||||
|
||||
<br>
|
||||
OPEN GAME LICENSE Version 1.0a
|
||||
<br>
|
||||
The following text is the property of Wizards of the Coast, Inc. and is
|
||||
Copyright 2000 Wizards of the Coast, Inc ("Wizards"). All Rights Reserved.
|
||||
<br>
|
||||
1. Definitions: (a)"Contributors" means the copyright and/or trademark owners
|
||||
who have contributed Open Game Content; (b)"Derivative Material" means
|
||||
copyrighted material including derivative works and translations (including into
|
||||
other computer languages), potation, modification, correction, addition,
|
||||
extension, upgrade, improvement, compilation, abridgment or other form in which
|
||||
an existing work may be recast, transformed or adapted; (c) "Distribute" means
|
||||
to reproduce, license, rent, lease, sell, broadcast, publicly display, transmit
|
||||
or otherwise distribute; (d)"Open Game Content" means the game mechanic and
|
||||
includes the methods, procedures, processes and routines to the extent such
|
||||
content does not embody the Product Identity and is an enhancement over the
|
||||
prior art and any additional content clearly identified as Open Game Content by
|
||||
the Contributor, and means any work covered by this License, including
|
||||
translations and derivative works under copyright law, but specifically excludes
|
||||
Product Identity. (e) "Product Identity" means product and product line names,
|
||||
logos and identifying marks including trade dress; artifacts; creatures
|
||||
characters; stories, storylines, plots, thematic elements, dialogue, incidents,
|
||||
language, artwork, symbols, designs, depictions, likenesses, formats, poses,
|
||||
concepts, themes and graphic, photographic and other visual or audio
|
||||
representations; names and descriptions of characters, spells, enchantments,
|
||||
personalities, teams, personas, likenesses and special abilities; places,
|
||||
locations, environments, creatures, equipment, magical or supernatural abilities
|
||||
or effects, logos, symbols, or graphic designs; and any other trademark or
|
||||
registered trademark clearly identified as Product identity by the owner of the
|
||||
Product Identity, and which specifically excludes the Open Game Content; (f)
|
||||
"Trademark" means the logos, names, mark, sign, motto, designs that are used by
|
||||
a Contributor to identify itself or its products or the associated products
|
||||
contributed to the Open Game License by the Contributor (g) "Use", "Used" or
|
||||
"Using" means to use, Distribute, copy, edit, format, modify, translate and
|
||||
otherwise create Derivative Material of Open Game Content. (h) "You" or "Your"
|
||||
means the licensee in terms of this agreement.
|
||||
<br>
|
||||
2. The License: This License applies to any Open Game Content that contains a
|
||||
notice indicating that the Open Game Content may only be Used under and
|
||||
in terms of this License. You must affix such a notice to any Open Game Content
|
||||
that you Use. No terms may be added to or subtracted from this License
|
||||
except as described by the License itself. No other terms or conditions may be
|
||||
applied to any Open Game Content distributed using this License.
|
||||
<br>
|
||||
3. Offer and Acceptance: By Using the Open Game Content You indicate Your
|
||||
acceptance of the terms of this License.
|
||||
<br>
|
||||
4. Grant and Consideration: In consideration for agreeing to use this License,
|
||||
the Contributors grant You a perpetual, worldwide, royalty-free, non-exclusive
|
||||
license with the exact terms of this License to Use, the Open Game Content.
|
||||
<br>
|
||||
5.Representation of Authority to Contribute: If You are contributing original
|
||||
material as Open Game Content, You represent that Your Contributions are Your
|
||||
original creation and/or You have sufficient rights to grant the rights conveyed
|
||||
by this License.
|
||||
<br>
|
||||
6.Notice of License Copyright: You must update the COPYRIGHT NOTICE portion of
|
||||
this License to include the exact text of the COPYRIGHT NOTICE of any Open Game
|
||||
Content You are copying, modifying or distributing, and You must add the title,
|
||||
the copyright date, and the copyright holder's name to the COPYRIGHT NOTICE of
|
||||
any original Open Game Content you Distribute.
|
||||
<br>
|
||||
7. Use of Product Identity: You agree not to Use any Product Identity, including
|
||||
as an indication as to compatibility, except as expressly licensed in another,
|
||||
independent Agreement with the owner of each element of that Product Identity.
|
||||
You agree not to indicate compatibility or co-adaptability with any Trademark or
|
||||
Registered Trademark in conjunction with a work containing Open Game Content
|
||||
except as expressly licensed in another, independent Agreement with the owner of
|
||||
such Trademark or Registered Trademark. The use of any Product Identity in Open
|
||||
Game Content does not constitute a challenge to the ownership of that Product
|
||||
Identity. The owner of any Product Identity used in Open Game Content shall
|
||||
retain all rights, title and interest in and to that Product Identity.
|
||||
<br>
|
||||
8. Identification: If you distribute Open Game Content You must clearly
|
||||
indicate which portions of the work that you are distributing are Open Game
|
||||
Content.
|
||||
<br>
|
||||
9. Updating the License: Wizards or its designated Agents may publish updated
|
||||
versions of this License. You may use any authorized version of this License to
|
||||
copy, modify and distribute any Open Game Content originally distributed under
|
||||
any version of this License.
|
||||
<br>
|
||||
10. Copy of this License: You MUST include a copy of this License with every
|
||||
copy of the Open Game Content You Distribute.
|
||||
<br>
|
||||
11. Use of Contributor Credits: You may not market or advertise the Open Game
|
||||
Content using the name of any Contributor unless You have written permission
|
||||
from the Contributor to do so.
|
||||
<br>
|
||||
12. Inability to Comply: If it is impossible for You to comply with any of the
|
||||
terms of this License with respect to some or all of the Open Game Content due
|
||||
to statute, judicial order, or governmental regulation then You may not Use any
|
||||
Open Game Material so affected.
|
||||
<br>
|
||||
13. Termination: This License will terminate automatically if You fail to
|
||||
comply with all terms herein and fail to cure such breach within 30 days of
|
||||
becoming aware of the breach. All sublicenses shall survive the termination of
|
||||
this License.
|
||||
<br>
|
||||
14. Reformation: If any provision of this License is held to be unenforceable,
|
||||
such provision shall be reformed only to the extent necessary to make it
|
||||
enforceable.
|
||||
<br>
|
||||
15. COPYRIGHT NOTICE
|
||||
<br>
|
||||
Open Game License v 1.0a Copyright 2000, Wizards of the Coast, Inc.
|
||||
<br>
|
||||
System Reference Document Copyright 2003, Wizards of
|
||||
the Coast, Inc.; Authors Jonathan Tweet, Monte Cook, Skip
|
||||
Williams, based on original material by E. Gary Gygax and
|
||||
Dave Arneson.
|
||||
<br>
|
||||
Castles & Crusades Players Handbook 2nd printing,
|
||||
Copyright 2006 by Troll Lord Games, Inc.; Authors Davis
|
||||
Chenault and Mac Golden.
|
||||
<br>
|
||||
Eldritch Sorcery Copyright 2005, Necromancer Games,
|
||||
Inc.; Authors Patrick Lawinger, Scott Greene, and David
|
||||
Mannes, with Erica Balsley, Chris Bernhardt, Casey W.
|
||||
Christofferson, Bill Collins, Jim Collura, Chad Coulter,
|
||||
Patrick Goulah, Skeeter Green, Jeff Harkness, Lance
|
||||
Hawvermale, Travis Hawvermale, Richard Hughes, Robert
|
||||
Hunter, Al Krombach, Rob Mason, Matt McGee, Clark
|
||||
Peterson, Michael Proteau, Greg Ragland, Gary Schotter,
|
||||
Joe Walmsley, and Bill Webb.
|
||||
<br>
|
||||
Eldritch Weirdness, Book One Copyright 2008, Matthew J.
|
||||
Finch
|
||||
<br>
|
||||
Original Spell Name Compendium Copyright 2002 Clark
|
||||
Peterson; based on NPC-named spells from the Player’s
|
||||
Handbook that were renamed in the System Reference
|
||||
Document. The Compendium can be found on the legal
|
||||
page of www.necromancergames.com.
|
||||
<br>
|
||||
Player’s Guide to the Wilderlands Copyright 2003,
|
||||
Necromancer Games, Inc. and Judges Guild; Authors Bob
|
||||
Bledsaw and Clark Peterson based on original material by
|
||||
Bob Bledsaw, Bill Ower and Bryan Hinnen.
|
||||
<br>
|
||||
Kard és Mágia © Copyright 2008 by Gabor Lux. All rights
|
||||
reserved.
|
||||
<br>
|
||||
System Reference Document Copyright 2000-2003, Wizards of the Coast, Inc.;
|
||||
Authors Jonathan Tweet, Monte Cook, Skip Williams, Rich Baker, Andy Collins,
|
||||
David Noonan, Rich Redman, Bruce R. Cordell, John D. Rateliff, Thomas Reid,
|
||||
James Wyatt, based on original material by E. Gary Gygax and Dave Arneson.
|
||||
<br>
|
||||
END OF LICENSE
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,188 @@
|
||||
<h1>Privacy Policy</h1>
|
||||
<p>Last updated: December 28, 2023</p>
|
||||
<p>This Privacy Policy describes Our policies and procedures on the collection, use and disclosure of Your information when You use the Service and tells You about Your privacy rights and how the law protects You.</p>
|
||||
<p>We use Your Personal data to provide and improve the Service. By using the Service, You agree to the collection and use of information in accordance with this Privacy Policy. This Privacy Policy has been created with the help of the <a href="https://www.freeprivacypolicy.com/free-privacy-policy-generator/" target="_blank">Free Privacy Policy Generator</a>.</p>
|
||||
<h2>Interpretation and Definitions</h2>
|
||||
<h3>Interpretation</h3>
|
||||
<p>The words of which the initial letter is capitalized have meanings defined under the following conditions. The following definitions shall have the same meaning regardless of whether they appear in singular or in plural.</p>
|
||||
<h3>Definitions</h3>
|
||||
<p>For the purposes of this Privacy Policy:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Account</strong> means a unique account created for You to access our Service or parts of our Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Affiliate</strong> means an entity that controls, is controlled by or is under common control with a party, where "control" means ownership of 50% or more of the shares, equity interest or other securities entitled to vote for election of directors or other managing authority.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Company</strong> (referred to as either "the Company", "We", "Us" or "Our" in this Agreement) refers to Kemkas.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Cookies</strong> are small files that are placed on Your computer, mobile device or any other device by a website, containing the details of Your browsing history on that website among its many uses.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Country</strong> refers to: Hungary</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Device</strong> means any device that can access the Service such as a computer, a cellphone or a digital tablet.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Personal Data</strong> is any information that relates to an identified or identifiable individual.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Service</strong> refers to the Website.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Service Provider</strong> means any natural or legal person who processes the data on behalf of the Company. It refers to third-party companies or individuals employed by the Company to facilitate the Service, to provide the Service on behalf of the Company, to perform services related to the Service or to assist the Company in analyzing how the Service is used.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Third-party Social Media Service</strong> refers to any website or any social network website through which a User can log in or create an account to use the Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Usage Data</strong> refers to data collected automatically, either generated by the use of the Service or from the Service infrastructure itself (for example, the duration of a page visit).</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Website</strong> refers to Kemkas, accessible from <a href="https://kemkas.hu" rel="external nofollow noopener" target="_blank">https://kemkas.hu</a> or <a href="https://app.kemkas.hu" rel="external nofollow noopener" target="_blank">https://app.kemkas.hu</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>You</strong> means the individual accessing or using the Service, or the company, or other legal entity on behalf of which such individual is accessing or using the Service, as applicable.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Collecting and Using Your Personal Data</h2>
|
||||
<h3>Types of Data Collected</h3>
|
||||
<h4>Personal Data</h4>
|
||||
<p>While using Our Service, We may ask You to provide Us with certain personally identifiable information that can be used to contact or identify You. Personally identifiable information may include, but is not limited to:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Email address</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Phone number</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Usage Data</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h4>Usage Data</h4>
|
||||
<p>Usage Data is collected automatically when using the Service.</p>
|
||||
<p>Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP address), browser type, browser version, the pages of our Service that You visit, the time and date of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data.</p>
|
||||
<p>When You access the Service by or through a mobile device, We may collect certain information automatically, including, but not limited to, the type of mobile device You use, Your mobile device unique ID, the IP address of Your mobile device, Your mobile operating system, the type of mobile Internet browser You use, unique device identifiers and other diagnostic data.</p>
|
||||
<p>We may also collect information that Your browser sends whenever You visit our Service or when You access the Service by or through a mobile device.</p>
|
||||
<h4>Information from Third-Party Social Media Services</h4>
|
||||
<p>The Company allows You to create an account and log in to use the Service through the following Third-party Social Media Services:</p>
|
||||
<ul>
|
||||
<li>Google</li>
|
||||
<li>Facebook</li>
|
||||
<li>Discord</li>
|
||||
</ul>
|
||||
<p>If You decide to register through or otherwise grant us access to a Third-Party Social Media Service, We may collect Personal data that is already associated with Your Third-Party Social Media Service's account, such as Your name, Your email address, Your activities or Your contact list associated with that account.</p>
|
||||
<p>You may also have the option of sharing additional information with the Company through Your Third-Party Social Media Service's account. If You choose to provide such information and Personal Data, during registration or otherwise, You are giving the Company permission to use, share, and store it in a manner consistent with this Privacy Policy.</p>
|
||||
<h4>Tracking Technologies and Cookies</h4>
|
||||
<p>We use Cookies and similar tracking technologies to track the activity on Our Service and store certain information. Tracking technologies used are beacons, tags, and scripts to collect and track information and to improve and analyze Our Service. The technologies We use may include:</p>
|
||||
<ul>
|
||||
<li><strong>Cookies or Browser Cookies.</strong> A cookie is a small file placed on Your Device. You can instruct Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do not accept Cookies, You may not be able to use some parts of our Service. Unless you have adjusted Your browser setting so that it will refuse Cookies, our Service may use Cookies.</li>
|
||||
<li><strong>Web Beacons.</strong> Certain sections of our Service and our emails may contain small electronic files known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that permit the Company, for example, to count users who have visited those pages or opened an email and for other related website statistics (for example, recording the popularity of a certain section and verifying system and server integrity).</li>
|
||||
</ul>
|
||||
<p>Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on Your personal computer or mobile device when You go offline, while Session Cookies are deleted as soon as You close Your web browser. Learn more about cookies on the <a href="https://www.freeprivacypolicy.com/blog/sample-privacy-policy-template/#Use_Of_Cookies_And_Tracking" target="_blank">Free Privacy Policy website</a> article.</p>
|
||||
<p>We use both Session and Persistent Cookies for the purposes set out below:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>Necessary / Essential Cookies</strong></p>
|
||||
<p>Type: Session Cookies</p>
|
||||
<p>Administered by: Us</p>
|
||||
<p>Purpose: These Cookies are essential to provide You with services available through the Website and to enable You to use some of its features. They help to authenticate users and prevent fraudulent use of user accounts. Without these Cookies, the services that You have asked for cannot be provided, and We only use these Cookies to provide You with those services.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Cookies Policy / Notice Acceptance Cookies</strong></p>
|
||||
<p>Type: Persistent Cookies</p>
|
||||
<p>Administered by: Us</p>
|
||||
<p>Purpose: These Cookies identify if users have accepted the use of cookies on the Website.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Functionality Cookies</strong></p>
|
||||
<p>Type: Persistent Cookies</p>
|
||||
<p>Administered by: Us</p>
|
||||
<p>Purpose: These Cookies allow us to remember choices You make when You use the Website, such as remembering your login details or language preference. The purpose of these Cookies is to provide You with a more personal experience and to avoid You having to re-enter your preferences every time You use the Website.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>For more information about the cookies we use and your choices regarding cookies, please visit our Cookies Policy or the Cookies section of our Privacy Policy.</p>
|
||||
<h3>Use of Your Personal Data</h3>
|
||||
<p>The Company may use Personal Data for the following purposes:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><strong>To provide and maintain our Service</strong>, including to monitor the usage of our Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To manage Your Account:</strong> to manage Your registration as a user of the Service. The Personal Data You provide can give You access to different functionalities of the Service that are available to You as a registered user.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>For the performance of a contract:</strong> the development, compliance and undertaking of the purchase contract for the products, items or services You have purchased or of any other contract with Us through the Service.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To contact You:</strong> To contact You by email, telephone calls, SMS, or other equivalent forms of electronic communication, such as a mobile application's push notifications regarding updates or informative communications related to the functionalities, products or contracted services, including the security updates, when necessary or reasonable for their implementation.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To provide You</strong> with news, special offers and general information about other goods, services and events which we offer that are similar to those that you have already purchased or enquired about unless You have opted not to receive such information.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>To manage Your requests:</strong> To attend and manage Your requests to Us.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>For business transfers:</strong> We may use Your information to evaluate or conduct a merger, divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar proceeding, in which Personal Data held by Us about our Service users is among the assets transferred.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>For other purposes</strong>: We may use Your information for other purposes, such as data analysis, identifying usage trends, determining the effectiveness of our promotional campaigns and to evaluate and improve our Service, products, services, marketing and your experience.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<p>We may share Your personal information in the following situations:</p>
|
||||
<ul>
|
||||
<li><strong>With Service Providers:</strong> We may share Your personal information with Service Providers to monitor and analyze the use of our Service, to contact You.</li>
|
||||
<li><strong>For business transfers:</strong> We may share or transfer Your personal information in connection with, or during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a portion of Our business to another company.</li>
|
||||
<li><strong>With Affiliates:</strong> We may share Your information with Our affiliates, in which case we will require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and any other subsidiaries, joint venture partners or other companies that We control or that are under common control with Us.</li>
|
||||
<li><strong>With business partners:</strong> We may share Your information with Our business partners to offer You certain products, services or promotions.</li>
|
||||
<li><strong>With other users:</strong> when You share personal information or otherwise interact in the public areas with other users, such information may be viewed by all users and may be publicly distributed outside. If You interact with other users or register through a Third-Party Social Media Service, Your contacts on the Third-Party Social Media Service may see Your name, profile, pictures and description of Your activity. Similarly, other users will be able to view descriptions of Your activity, communicate with You and view Your profile.</li>
|
||||
<li><strong>With Your consent</strong>: We may disclose Your personal information for any other purpose with Your consent.</li>
|
||||
</ul>
|
||||
<h3>Retention of Your Personal Data</h3>
|
||||
<p>The Company will retain Your Personal Data only for as long as is necessary for the purposes set out in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply with our legal obligations (for example, if we are required to retain your data to comply with applicable laws), resolve disputes, and enforce our legal agreements and policies.</p>
|
||||
<p>The Company will also retain Usage Data for internal analysis purposes. Usage Data is generally retained for a shorter period of time, except when this data is used to strengthen the security or to improve the functionality of Our Service, or We are legally obligated to retain this data for longer time periods.</p>
|
||||
<h3>Transfer of Your Personal Data</h3>
|
||||
<p>Your information, including Personal Data, is processed at the Company's operating offices and in any other places where the parties involved in the processing are located. It means that this information may be transferred to — and maintained on — computers located outside of Your state, province, country or other governmental jurisdiction where the data protection laws may differ than those from Your jurisdiction.</p>
|
||||
<p>Your consent to this Privacy Policy followed by Your submission of such information represents Your agreement to that transfer.</p>
|
||||
<p>The Company will take all steps reasonably necessary to ensure that Your data is treated securely and in accordance with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or a country unless there are adequate controls in place including the security of Your data and other personal information.</p>
|
||||
<h3>Delete Your Personal Data</h3>
|
||||
<p>You have the right to delete or request that We assist in deleting the Personal Data that We have collected about You.</p>
|
||||
<p>Our Service may give You the ability to delete certain information about You from within the Service.</p>
|
||||
<p>You may update, amend, or delete Your information at any time by signing in to Your Account, if you have one, and visiting the account settings section that allows you to manage Your personal information. You may also contact Us to request access to, correct, or delete any personal information that You have provided to Us.</p>
|
||||
<p>Please note, however, that We may need to retain certain information when we have a legal obligation or lawful basis to do so.</p>
|
||||
<h3>Disclosure of Your Personal Data</h3>
|
||||
<h4>Business Transactions</h4>
|
||||
<p>If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be transferred. We will provide notice before Your Personal Data is transferred and becomes subject to a different Privacy Policy.</p>
|
||||
<h4>Law enforcement</h4>
|
||||
<p>Under certain circumstances, the Company may be required to disclose Your Personal Data if required to do so by law or in response to valid requests by public authorities (e.g. a court or a government agency).</p>
|
||||
<h4>Other legal requirements</h4>
|
||||
<p>The Company may disclose Your Personal Data in the good faith belief that such action is necessary to:</p>
|
||||
<ul>
|
||||
<li>Comply with a legal obligation</li>
|
||||
<li>Protect and defend the rights or property of the Company</li>
|
||||
<li>Prevent or investigate possible wrongdoing in connection with the Service</li>
|
||||
<li>Protect the personal safety of Users of the Service or the public</li>
|
||||
<li>Protect against legal liability</li>
|
||||
</ul>
|
||||
<h3>Security of Your Personal Data</h3>
|
||||
<p>The security of Your Personal Data is important to Us, but remember that no method of transmission over the Internet, or method of electronic storage is 100% secure. While We strive to use commercially acceptable means to protect Your Personal Data, We cannot guarantee its absolute security.</p>
|
||||
<h2>Children's Privacy</h2>
|
||||
<p>Our Service does not address anyone under the age of 13. We do not knowingly collect personally identifiable information from anyone under the age of 13. If You are a parent or guardian and You are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware that We have collected Personal Data from anyone under the age of 13 without verification of parental consent, We take steps to remove that information from Our servers.</p>
|
||||
<p>If We need to rely on consent as a legal basis for processing Your information and Your country requires consent from a parent, We may require Your parent's consent before We collect and use that information.</p>
|
||||
<h2>Links to Other Websites</h2>
|
||||
<p>Our Service may contain links to other websites that are not operated by Us. If You click on a third party link, You will be directed to that third party's site. We strongly advise You to review the Privacy Policy of every site You visit.</p>
|
||||
<p>We have no control over and assume no responsibility for the content, privacy policies or practices of any third party sites or services.</p>
|
||||
<h2>Changes to this Privacy Policy</h2>
|
||||
<p>We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the new Privacy Policy on this page.</p>
|
||||
<p>We will let You know via email and/or a prominent notice on Our Service, prior to the change becoming effective and update the "Last updated" date at the top of this Privacy Policy.</p>
|
||||
<p>You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy Policy are effective when they are posted on this page.</p>
|
||||
<h2>Contact Us</h2>
|
||||
<p>If you have any questions about this Privacy Policy, You can contact us:</p>
|
||||
<ul>
|
||||
<li>By email: developer@kemkas.hu</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -0,0 +1,13 @@
|
||||
#root {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
footer {
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.box-shadow {
|
||||
box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .05);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import React from 'react';
|
||||
import { render } from '@testing-library/react';
|
||||
import App from './App';
|
||||
|
||||
test('renders learn react link', () => {
|
||||
render(<App faro={undefined}/>);
|
||||
});
|
||||
@@ -0,0 +1,96 @@
|
||||
import * as React from 'react';
|
||||
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 ErrorBoundary from "./shared/ErrorBoundary";
|
||||
import Header from "./shared/Header";
|
||||
import Footer from "./shared/Footer";
|
||||
import {useState} from "react";
|
||||
import {UserContext, userDefaults} from './shared/contexts/UserContext';
|
||||
import CreateCharacter2E from "./second-edition/pages/CreateCharacter2E";
|
||||
|
||||
function App(props: {faro?: Faro}) {
|
||||
|
||||
const [fetchedUser, setFetchedUser] = useState(userDefaults)
|
||||
|
||||
if (fetchedUser.state === "not-started") {
|
||||
setFetchedUser({...fetchedUser, state: "loading"})
|
||||
fetch(`${window.location.origin}/api/User/me`)
|
||||
.then(response => {
|
||||
if (response.ok) {
|
||||
return response.text();
|
||||
}
|
||||
console.log(response)
|
||||
})
|
||||
.then(userNameResponse => {
|
||||
const userName = userNameResponse && userNameResponse.length > 0 ? userNameResponse : null;
|
||||
setFetchedUser({
|
||||
data: userName,
|
||||
state: "finished"
|
||||
});
|
||||
})
|
||||
.catch(() => {
|
||||
setFetchedUser({
|
||||
data: null,
|
||||
state: "finished"
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
const router = createBrowserRouter([
|
||||
{
|
||||
path: "/",
|
||||
loader: () => fetchedUser.data == null ? redirect("/2e/karakter") : redirect("/karaktereim")
|
||||
},
|
||||
{
|
||||
path: "/karaktereim",
|
||||
element: <CharacterList />,
|
||||
loader: () => fetch(`${window.location.origin}/api/Character`),
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
},
|
||||
{
|
||||
path: "/1e",
|
||||
loader: () => redirect("/1e/karakter")
|
||||
},
|
||||
{
|
||||
path: "/1e/karakter",
|
||||
element: <CreateCharacter faro={props.faro} />,
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
},
|
||||
{
|
||||
path: "/1e/karakter/:id",
|
||||
element: <CreateCharacter faro={props.faro}/>,
|
||||
loader: args => fetch(`${window.location.origin}/api/Character1E/${args.params.id}`),
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
},
|
||||
{
|
||||
path: "/2e",
|
||||
loader: () => redirect("/2e/karakter")
|
||||
},
|
||||
{
|
||||
path: "/2e/karakter",
|
||||
element: <CreateCharacter2E faro={props.faro}/>,
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
},
|
||||
{
|
||||
path: "/2e/karakter/:id",
|
||||
element: <CreateCharacter2E faro={props.faro}/>,
|
||||
loader: args => fetch(`${window.location.origin}/api/Character2E/${args.params.id}`),
|
||||
ErrorBoundary: ErrorBoundary,
|
||||
},
|
||||
]);
|
||||
|
||||
return (
|
||||
<UserContext.Provider value={fetchedUser}>
|
||||
<Header/>
|
||||
<div className='container'>
|
||||
<RouterProvider router={router}/>
|
||||
</div>
|
||||
<Footer />
|
||||
</UserContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
@@ -0,0 +1,32 @@
|
||||
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, {
|
||||
withCredentials: true,
|
||||
params: {
|
||||
isPublic,
|
||||
}
|
||||
})
|
||||
if (response.status < 300){
|
||||
return response.data as string
|
||||
}
|
||||
else {
|
||||
throw Error(response.statusText)
|
||||
}
|
||||
}
|
||||
|
||||
export async function UpdateCharacter(id: string, karakter: KarakterInputs, isPublic: boolean = false) {
|
||||
let response = await axios.post(`${window.location.origin}/api/Character1E/${id}`, karakter, {
|
||||
withCredentials: true,
|
||||
params: {
|
||||
isPublic,
|
||||
}
|
||||
})
|
||||
if (response.status < 300){
|
||||
return response.data as string
|
||||
}
|
||||
else {
|
||||
throw Error(response.statusText)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import React from "react";
|
||||
import {KarakterInputs} from "../domain-models/karakter";
|
||||
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<KarakterInputs, 'osztaly' | 'tulajdonsagok' | 'hpRolls'>
|
||||
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.hpRolls[szint-2] || 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, hpRolls: karakter.hpRolls.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,43 @@
|
||||
import React from "react";
|
||||
import {Faj, FajDescription, FajLabel, FajSpecials} from "../domain-models/faj";
|
||||
|
||||
function FajSelector(props: { faj: Faj, changeFaj: (val: Faj) => void }) {
|
||||
const {faj, changeFaj} = props
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Faj</label>
|
||||
<select className='col form-select' value={faj} onChange={e => changeFaj(e.target.value as Faj)}>
|
||||
<option key={Faj.Ember} value={Faj.Ember}>{FajLabel(Faj.Ember)}</option>
|
||||
<optgroup label='más emberi népek'>
|
||||
<option key={Faj.Amazon} value={Faj.Amazon}>{FajLabel(Faj.Amazon)}</option>
|
||||
<option key={Faj.Birodalmi} value={Faj.Birodalmi}>{FajLabel(Faj.Birodalmi)}</option>
|
||||
<option key={Faj.Eszaki} value={Faj.Eszaki}>{FajLabel(Faj.Eszaki)}</option>
|
||||
<option key={Faj.Etuniai} value={Faj.Etuniai}>{FajLabel(Faj.Etuniai)}</option>
|
||||
<option key={Faj.Osember} value={Faj.Osember}>{FajLabel(Faj.Osember)}</option>
|
||||
</optgroup>
|
||||
<optgroup label='nem emberi fajok'>
|
||||
<option key={Faj.Elf} value={Faj.Elf}>{FajLabel(Faj.Elf)}</option>
|
||||
<option key={Faj.Felelf} value={Faj.Felelf}>{FajLabel(Faj.Felelf)}</option>
|
||||
<option key={Faj.Felork} value={Faj.Felork}>{FajLabel(Faj.Felork)}</option>
|
||||
<option key={Faj.Felszerzet}
|
||||
value={Faj.Felszerzet}>{FajLabel(Faj.Felszerzet)}</option>
|
||||
<option key={Faj.Gnom} value={Faj.Gnom}>{FajLabel(Faj.Gnom)}</option>
|
||||
<option key={Faj.Torpe} value={Faj.Torpe}>{FajLabel(Faj.Torpe)}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 form-label'></label>
|
||||
<div className='col'>
|
||||
<p className='row pt-2'>
|
||||
{FajDescription(faj)}
|
||||
</p>
|
||||
<ul>
|
||||
{FajSpecials(faj).map(((special, i) => (<li key={faj + i}>{special}</li>)))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default FajSelector
|
||||
@@ -0,0 +1,78 @@
|
||||
import React from "react";
|
||||
import {Fegyver, KarakterFelszereles, PancelTypeLabel} from "../domain-models/felszereles";
|
||||
import {Osztaly} from '../domain-models/osztaly'
|
||||
import {AllowedPancelTypes} from '../domain-models/allowed-pancel-types'
|
||||
import pancelok from '../domain-models/pancel.json'
|
||||
import pajzsok from '../domain-models/pajzs.json'
|
||||
import fegyverek from '../domain-models/fegyver.json'
|
||||
import {arraySetN} from "../../util";
|
||||
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
||||
|
||||
export function FegyverLabel(fegyver: Fegyver): string {
|
||||
return `${fegyver.Name}${fegyver.Ketkezes ? '+' : ''}${fegyver.Egzotikus ? '(E)' : ''} | ${
|
||||
fegyver.NumberOfDamageDice}d${fegyver.DamageDice} ${
|
||||
fegyver.CritRangeStart < 20 ? `${fegyver.CritRangeStart}-20` : ''}x${fegyver.CritMultiplier}${
|
||||
fegyver.Price > 0 ? ` | ár: ${fegyver.Price} at ` : ''}${
|
||||
fegyver.Range > 0 ? ` | táv: ${fegyver.Range}` : ''}`
|
||||
}
|
||||
|
||||
function Felszereles(props: {felszereles: KarakterFelszereles, changeFelszereles: (felszereles: KarakterFelszereles) => void, osztaly: Osztaly, harcosSpec: Fegyver['Id'][]}) {
|
||||
const { felszereles, changeFelszereles, osztaly, harcosSpec } = props;
|
||||
const allowedPancelTypes = AllowedPancelTypes([osztaly])
|
||||
const valasztottFegyverek = felszereles.fegyverIDk
|
||||
.map((id, idx) => ({idx, fegyver: fegyverek.data.find(f => f.Id === id)})).filter((x) => x.fegyver != null).map(({idx, fegyver}) => ({idx, fegyver: fegyver as Fegyver}))
|
||||
|
||||
const osztalyAllowedFegyverek = AllowedFegyver(osztaly, harcosSpec)
|
||||
const allowedFegyverek = [...osztalyAllowedFegyverek, ...valasztottFegyverek.filter(({idx, fegyver}) => !osztalyAllowedFegyverek.map(f => f.Id).includes(fegyver.Id)).map(({fegyver}) => fegyver)]
|
||||
const changeFegyver = (idx: number, newID: string) => {
|
||||
const found = fegyverek.data.find(x => x.Id === newID)
|
||||
if (!found) {
|
||||
console.log('Nem létező fegyver ID: ', newID)
|
||||
return
|
||||
}
|
||||
changeFelszereles({...felszereles, fegyverIDk: arraySetN(felszereles.fegyverIDk, idx, newID)})
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className='row'>
|
||||
<h5 className='col align-self-center'>Felszerelés</h5>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Viselt páncél</label>
|
||||
<select className='col form-select' value={felszereles.pancelID} onChange={e => changeFelszereles({...felszereles, pancelID: e.target.value === 'nincs' ? undefined : e.target.value})}>
|
||||
<option key={'nincs'} value={'nincs'}>Nincs</option>
|
||||
{
|
||||
allowedPancelTypes.map(pancelType => (
|
||||
<optgroup key={pancelType} label={PancelTypeLabel(pancelType)}>
|
||||
{pancelok['pancel'].filter(p => p.Type === pancelType).map(p => <option key={p.Id} value={p.Id}>{`${p.Name} (+${p.VO} VO) - ${p.Price} at`}</option>)}
|
||||
</optgroup>
|
||||
))
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Hordott pajzs</label>
|
||||
<select className='col form-select' value={felszereles.pajzsID} onChange={e => changeFelszereles({...felszereles, pajzsID: e.target.value === 'nincs' ? undefined : e.target.value})}>
|
||||
<option key={'nincs'} value={'nincs'}>Nincs</option>
|
||||
{allowedPancelTypes.length > 0 && (pajzsok['pajzs'].map(p => <option key={p.Id} value={p.Id}>{`${p.Name} (+${p.VO} VO) - ${p.Price} at`}</option>))}
|
||||
</select>
|
||||
</div>
|
||||
{valasztottFegyverek.map(({idx, fegyver}) => (
|
||||
<div key={`fegyver-${idx}`} className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Fegyver</label>
|
||||
<select className='col form-select' value={fegyver.Id} 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="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' onClick={() => changeFelszereles({...felszereles, fegyverIDk: [...felszereles.fegyverIDk.slice(0, idx), ...felszereles.fegyverIDk.slice(idx+1)]})}>Elvesz</button>
|
||||
</div>
|
||||
))}
|
||||
<button className='btn btn-outline-dark btn btn-lg ms-2' type='button' onClick={() => changeFelszereles({...felszereles, fegyverIDk: [...felszereles.fegyverIDk, 'okol']})}>Fegyver hozzáadása</button>
|
||||
</>
|
||||
}
|
||||
|
||||
export default Felszereles
|
||||
@@ -0,0 +1,38 @@
|
||||
import React from "react";
|
||||
import fegyverek from "../domain-models/fegyver.json"
|
||||
import {defaultFegyverID, GetFegyver} from "../domain-models/felszereles";
|
||||
|
||||
function HarcosFegyverSpecializacio(props: {
|
||||
specialization: string,
|
||||
existingSpecializations: string[],
|
||||
changeSpecialization: (specialization: string) => void
|
||||
szint: number
|
||||
}) {
|
||||
const {
|
||||
specialization,
|
||||
existingSpecializations,
|
||||
changeSpecialization,
|
||||
szint
|
||||
} = props
|
||||
const fegyver = GetFegyver(specialization)
|
||||
const pickableFegyverek = fegyverek.data.filter(f => f.Id === specialization || existingSpecializations.filter(x => x === f.Id).length < (szint < 9 ? 1 : 2))
|
||||
const kozelharciPickable = pickableFegyverek.filter(f => f.Type === 'kozelharci')
|
||||
const tavolsagiPickable = pickableFegyverek.filter(f => f.Type === 'lofegyver')
|
||||
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label' >Fegyver specializáció</label>
|
||||
<select className='col form-select' value={fegyver?.Id || defaultFegyverID} onChange={e => changeSpecialization(e.target.value)}>
|
||||
<optgroup label="Közelharci">
|
||||
{kozelharciPickable.map(f => <option key={`spec-${szint}-${f.Id}`} value={f.Id}>{f.Name}</option>)}
|
||||
</optgroup>
|
||||
<optgroup label="Távolsági">
|
||||
{tavolsagiPickable.map(f => <option key={`spec-${szint}-${f.Id}`} value={f.Id}>{f.Name}</option>)}
|
||||
</optgroup>
|
||||
</select>
|
||||
{fegyver == null && <span className='form-field-error'>Ismeretlen fegyver: {specialization}</span>}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default HarcosFegyverSpecializacio
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import {AllJellemIDs, GetJellem, JellemID} from "../domain-models/jellem";
|
||||
|
||||
function JellemSelector(props: {selected: JellemID, changeJellem: (val: JellemID) => void}) {
|
||||
const { selected, changeJellem } = props
|
||||
const jellem = GetJellem(selected)
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Jellem</label>
|
||||
<select className='col form-select' value={selected} onChange={e => changeJellem(e.target.value as JellemID)}>
|
||||
{AllJellemIDs.map((id) => (
|
||||
<option key={id} value={id}>{GetJellem(id).Label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 form-label'></label>
|
||||
<div className='col'>
|
||||
<p className='row pt-2'>
|
||||
{jellem.Description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default JellemSelector
|
||||
@@ -0,0 +1,34 @@
|
||||
import React from "react";
|
||||
import {Osztaly} from "../domain-models/osztaly";
|
||||
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
||||
|
||||
function KalozKritikus(props: {
|
||||
kritFegyverId: string,
|
||||
existingKrits: string[],
|
||||
changeKrit: (krit: string) => void,
|
||||
szint: number
|
||||
}) {
|
||||
const {
|
||||
kritFegyverId,
|
||||
existingKrits,
|
||||
changeKrit,
|
||||
szint
|
||||
} = props
|
||||
const fegyverek = AllowedFegyver(Osztaly.Kaloz, []).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>
|
||||
<select className='col form-select' value={kritFegyverId} onChange={e => changeKrit(e.target.value)}>
|
||||
<optgroup label="Közelharci">
|
||||
{fegyverek.filter(f => f.Type === 'kozelharci').map(f => <option key={f.Id} value={f.Id}>{f.Name}</option>)}
|
||||
</optgroup>
|
||||
<optgroup label="Távolsági">
|
||||
{fegyverek.filter(f => f.Type === 'lofegyver').map(f => <option key={f.Id} value={f.Id}>{f.Name}</option>)}
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default KalozKritikus
|
||||
@@ -0,0 +1,89 @@
|
||||
import React from "react";
|
||||
import KepzettsegSelector from "./KepzettsegSelector";
|
||||
import {
|
||||
Kepzettseg,
|
||||
Kepzettsegek,
|
||||
KepzettsegId,
|
||||
TolvajKepzettsegList,
|
||||
} from "../domain-models/kepzettsegek";
|
||||
import {arraySetN} from "../../util";
|
||||
|
||||
|
||||
function InternalKepzettsegekSelector(props: {
|
||||
title: string,
|
||||
numberOfKepzettseg: number,
|
||||
getKepzettsegListaN: (n: number) => Kepzettseg[],
|
||||
kepzettsegek: KepzettsegId[],
|
||||
changeKepzettsegek: (newKepzettsegek: KepzettsegId[]) => void
|
||||
}) {
|
||||
const {title, numberOfKepzettseg, getKepzettsegListaN, kepzettsegek, changeKepzettsegek} = props
|
||||
|
||||
const klist = Array.from(new Array(numberOfKepzettseg).keys())
|
||||
|
||||
const preCalculated: {
|
||||
kepzettsegek: Kepzettseg[],
|
||||
changeKepzettseg: (newKepzettseg: KepzettsegId) => void,
|
||||
selected: Kepzettseg,
|
||||
}[] = [];
|
||||
|
||||
for (let i = 0; i < numberOfKepzettseg; i++) {
|
||||
preCalculated.push({
|
||||
kepzettsegek: getKepzettsegListaN(i),
|
||||
selected: Kepzettsegek[kepzettsegek[i]],
|
||||
changeKepzettseg: (newKepzettseg: KepzettsegId) => changeKepzettsegek(arraySetN(kepzettsegek, i, newKepzettseg))
|
||||
})
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-lg-2 col-md-12 col-form-label'>{title}</label>
|
||||
<div className='col'>
|
||||
{klist.map((idx) =>
|
||||
<KepzettsegSelector
|
||||
key={title+idx}
|
||||
kepzettsegek={preCalculated[idx].kepzettsegek}
|
||||
selected={preCalculated[idx].selected}
|
||||
changeKepzettseg={preCalculated[idx].changeKepzettseg}
|
||||
/>)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
}
|
||||
|
||||
function KarakterKepzettsegek (props: {
|
||||
numberOfKepzettsegek: number
|
||||
kepzettsegek: KepzettsegId[],
|
||||
changeKepzettsegek: (newKepzettsegek: KepzettsegId[]) => void
|
||||
tolvajKepzettsegek: KepzettsegId[],
|
||||
changeTolvajKepzettsegek: (newKepzettsegek: KepzettsegId[]) => void
|
||||
getKepzettsegListaN: (n: number) => Kepzettseg[]
|
||||
}) {
|
||||
const { kepzettsegek, numberOfKepzettsegek, getKepzettsegListaN, changeKepzettsegek, tolvajKepzettsegek, changeTolvajKepzettsegek} = props
|
||||
|
||||
// TODO: Birodalmi tolvajnal az Alikmia, vagy Meregkeveres kezelese
|
||||
|
||||
const getTolvajKepzettsegListaN = (n: number) : Kepzettseg[] => {
|
||||
const tolvajKepzettsegekWithoutN = [...tolvajKepzettsegek.slice(0, n), ...tolvajKepzettsegek.slice(n+1)]
|
||||
return TolvajKepzettsegList.filter(x => !kepzettsegek.includes(x.Id) && !tolvajKepzettsegekWithoutN.includes(x.Id))
|
||||
}
|
||||
|
||||
return <>
|
||||
<InternalKepzettsegekSelector
|
||||
title="Képzettségek"
|
||||
numberOfKepzettseg={numberOfKepzettsegek}
|
||||
getKepzettsegListaN={getKepzettsegListaN}
|
||||
changeKepzettsegek={changeKepzettsegek}
|
||||
kepzettsegek={kepzettsegek} />
|
||||
|
||||
{tolvajKepzettsegek.length > 0 && <InternalKepzettsegekSelector
|
||||
title="Tolvaj képzettségek"
|
||||
numberOfKepzettseg={4}
|
||||
getKepzettsegListaN={getTolvajKepzettsegListaN}
|
||||
changeKepzettsegek={changeTolvajKepzettsegek}
|
||||
kepzettsegek={tolvajKepzettsegek} />}
|
||||
</>
|
||||
}
|
||||
|
||||
export default KarakterKepzettsegek
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import {Kepzettseg, KepzettsegId} from "../domain-models/kepzettsegek";
|
||||
import {TulajdonsagLabel} from "../domain-models/tulajdonsag";
|
||||
import {OsztalyLabel} from "../domain-models/osztaly";
|
||||
|
||||
function kepzettsegOptionText(k: Kepzettseg) {
|
||||
const osztalyok = k.Osztalyok?.reduce((acc, o) => acc + ' / ' + OsztalyLabel(o), '')?.substring(3)
|
||||
return k.Name + ' (' + k.Tulajdonsag.reduce((acc, k) => (acc === '' ? acc : acc + ' / ') + TulajdonsagLabel(k), '') + ')' + (osztalyok == null ? '' : (' - ' + osztalyok));
|
||||
}
|
||||
|
||||
function KepzettsegSelector (props: {kepzettsegek: Kepzettseg[], changeKepzettseg: (newKepzettseg: KepzettsegId) => void, selected : Kepzettseg}) {
|
||||
|
||||
const { kepzettsegek, changeKepzettseg, selected } = props
|
||||
|
||||
return <>
|
||||
<div className='row'>
|
||||
<select className='form-control'
|
||||
value={selected.Id} onChange={e => changeKepzettseg(e.target.value as KepzettsegId)}>
|
||||
{kepzettsegek.map(k =>(
|
||||
<option key={k.Id} value={k.Id}>
|
||||
{kepzettsegOptionText(k)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className='row pt-2'>
|
||||
<p className='col'>{selected.Description}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default KepzettsegSelector
|
||||
@@ -0,0 +1,107 @@
|
||||
import React from "react";
|
||||
import {KarakterInputs} from "../domain-models/karakter";
|
||||
import BasicNewLevel from "./BasicNewLevel";
|
||||
import TulajdonsagNoveles from "./TulajdonsagNoveles";
|
||||
import {Tulajdonsag, TulajdonsagokTotal} from "../domain-models/tulajdonsag";
|
||||
import {arraySetN} from "../../util";
|
||||
import {Osztaly} from "../domain-models/osztaly";
|
||||
import HarcosFegyverSpecializacio from "./HarcosFegyverSpecializacio";
|
||||
import KalozKritikus from "./KalozKritikus";
|
||||
|
||||
function kalozKritIndex(szint: number) {
|
||||
return Math.floor(szint/3)-1
|
||||
}
|
||||
|
||||
function LevelUp(props: {
|
||||
szint: number,
|
||||
karakter: KarakterInputs,
|
||||
changeTulajdonsagNoveles: (t: Tulajdonsag) => void,
|
||||
changeRolledHP: (rolledHP: number) => void,
|
||||
changeHarcosSpec: (spec: string) => void,
|
||||
changeKalozKritikus: (krit: string) => void,
|
||||
}) {
|
||||
const {
|
||||
szint,
|
||||
karakter,
|
||||
changeTulajdonsagNoveles,
|
||||
changeRolledHP,
|
||||
changeHarcosSpec,
|
||||
changeKalozKritikus,
|
||||
} = props
|
||||
|
||||
const specializationIndex = Math.floor((szint-1) / 2)
|
||||
const specialization = karakter.harcosSpecializaciok[specializationIndex]
|
||||
const kritIndex = kalozKritIndex(szint)
|
||||
const krit = karakter.kalozKritikus[kritIndex]
|
||||
|
||||
return <div>
|
||||
<div className='row mt-3'>
|
||||
<h5 className='col align-self-center'>{szint}. Szint</h5>
|
||||
</div>
|
||||
{szint % 4 === 0 && <TulajdonsagNoveles
|
||||
tulajdonsagok={karakter.tulajdonsagok}
|
||||
szint={szint}
|
||||
tulajdonsagNovelesek={karakter.tulajdonsagNovelesek}
|
||||
changeTulajdonsagNoveles={changeTulajdonsagNoveles}
|
||||
/>}
|
||||
<BasicNewLevel
|
||||
szint={szint}
|
||||
karakter={karakter}
|
||||
changeRolledHP={changeRolledHP}
|
||||
/>
|
||||
{karakter.osztaly === Osztaly.Harcos && szint % 2 === 1 &&
|
||||
<HarcosFegyverSpecializacio
|
||||
specialization={specialization}
|
||||
existingSpecializations={karakter.harcosSpecializaciok}
|
||||
changeSpecialization={changeHarcosSpec}
|
||||
szint={szint}
|
||||
/>
|
||||
}
|
||||
{karakter.osztaly === Osztaly.Kaloz && szint % 3 === 0 && !!krit &&
|
||||
<KalozKritikus
|
||||
kritFegyverId={krit}
|
||||
existingKrits={karakter.kalozKritikus}
|
||||
changeKrit={changeKalozKritikus}
|
||||
szint={szint}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
export function LevelUps(props: {karakter: KarakterInputs, changeKarakter: (inputs: KarakterInputs) => void}){
|
||||
const {karakter, changeKarakter} = props;
|
||||
|
||||
const tulajdonsagokAtSzint = (szint: number) => TulajdonsagokTotal({...karakter, tulajdonsagNovelesek: karakter.tulajdonsagNovelesek.slice(0, Math.floor(szint / 4))})
|
||||
|
||||
const changeRolledHPAtSzint = (szint: number) => (newHProll: number) => {
|
||||
changeKarakter({...karakter, hpRolls: arraySetN(karakter.hpRolls, szint-2, newHProll)})
|
||||
console.log(karakter)
|
||||
}
|
||||
const changeTulajdonsagNovelesAtSzint = (szint: number) => (t: Tulajdonsag) => { changeKarakter({...karakter, tulajdonsagNovelesek: arraySetN(karakter.tulajdonsagNovelesek, Math.floor((szint / 4)-1), t)}) }
|
||||
|
||||
const changeHarcosSpecializacioAtSzint = (szint: number) => (spec: string) => {
|
||||
changeKarakter({...karakter, harcosSpecializaciok: arraySetN(karakter.harcosSpecializaciok, Math.floor((szint-1) / 2), spec)})
|
||||
}
|
||||
|
||||
const changeKalozKritikusAtSzint = (szint: number) => (krit: string) => {
|
||||
changeKarakter({...karakter, kalozKritikus: arraySetN(karakter.kalozKritikus, kalozKritIndex(szint), krit)})
|
||||
}
|
||||
|
||||
const levels = karakter.hpRolls.map((_, i) => i+2);
|
||||
|
||||
return <>
|
||||
{levels.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,61 @@
|
||||
import React from "react";
|
||||
import {OverlayTrigger, Tooltip} from "react-bootstrap";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
import {MasodlagosErtekekView} from "../domain-models/masodlagos_ertekek";
|
||||
|
||||
function MasodlagosErtekek(props: MasodlagosErtekekView) {
|
||||
|
||||
const { HP, VO, CelzoTB, Mentok, KozelharciTB } = props
|
||||
|
||||
const tooltip = (
|
||||
<Tooltip id="tooltip">
|
||||
<strong>Hentelési Potenciál</strong>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
return <>
|
||||
<div className='row'>
|
||||
<h5 className='col align-self-center'>Másodlagos értékek</h5>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col-lg-6'>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label'>Életerő{' '}
|
||||
<OverlayTrigger placement='top' overlay={tooltip} delay={0} defaultShow={false} flip={false}>
|
||||
<span>(HP)</span>
|
||||
</OverlayTrigger>
|
||||
</label>
|
||||
<p className='col col-form-label'>{HP}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Védekezési Osztály (VO)</label>
|
||||
<p className='col col-form-label'>{VO}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Közelharci támadás</label>
|
||||
<p className='col col-form-label'>{KozelharciTB.map(SignedNumberToText).join(" / ")}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Célzó támadás</label>
|
||||
<p className='col col-form-label'>{CelzoTB.map(SignedNumberToText).join(" / ")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='col-lg-6'>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Kitartás mentő</label>
|
||||
<p className='col col-form-label'>{SignedNumberToText(Mentok.kitartas)}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Reflex mentő</label>
|
||||
<p className='col col-form-label'>{SignedNumberToText(Mentok.reflex)}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Akaraterő mentő </label>
|
||||
<p className='col col-form-label'>{SignedNumberToText(Mentok.akaratero)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default MasodlagosErtekek
|
||||
@@ -0,0 +1,67 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Osztaly,
|
||||
OsztalyDescription,
|
||||
OsztalyLabel,
|
||||
OsztalyProperties,
|
||||
OsztalySpecialSkills
|
||||
} from "../domain-models/osztaly";
|
||||
import {Faj, SzintKorlatokFajokra} from "../domain-models/faj";
|
||||
|
||||
function OsztalySelector(props: {currentFaj: Faj, currentOsztaly: Osztaly, changeOsztaly: (newOsztaly: Osztaly) => void}) {
|
||||
const {currentFaj, currentOsztaly, changeOsztaly} = props;
|
||||
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Osztály</label>
|
||||
<select className="col form-select" value={currentOsztaly} onChange={(e) => changeOsztaly(e.target.value as Osztaly)} >
|
||||
<optgroup label='Harcos'>
|
||||
<option value={Osztaly.Harcos}>{OsztalyLabel(Osztaly.Harcos)}</option>
|
||||
{SzintKorlatokFajokra(currentFaj)[Osztaly.Amazon] > 0 && (
|
||||
<option value={Osztaly.Amazon}>{OsztalyLabel(Osztaly.Amazon)}</option>) }
|
||||
<option value={Osztaly.Barbar}>{OsztalyLabel(Osztaly.Barbar)}</option>
|
||||
<option value={Osztaly.Ijasz}>{OsztalyLabel(Osztaly.Ijasz)}</option>
|
||||
<option value={Osztaly.Kaloz}>{OsztalyLabel(Osztaly.Kaloz)}</option>
|
||||
</optgroup>
|
||||
<option value={Osztaly.Pap}>{OsztalyLabel(Osztaly.Pap)}</option>
|
||||
{SzintKorlatokFajokra(currentFaj)[Osztaly.Tolvaj] > 0 && (<option value={Osztaly.Tolvaj}>{OsztalyLabel(Osztaly.Tolvaj)}</option>)}
|
||||
{SzintKorlatokFajokra(currentFaj)[Osztaly.Varazslo] > 0 && (
|
||||
<optgroup label='Varázsló'>
|
||||
<option value={Osztaly.Varazslo}>{OsztalyLabel(Osztaly.Varazslo)}</option>
|
||||
<option value={Osztaly.Illuzionista}>{OsztalyLabel(Osztaly.Illuzionista)}</option>
|
||||
</optgroup>
|
||||
)}
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 form-label'></label>
|
||||
<div className='col' >
|
||||
<p className='row pt-2'>
|
||||
{OsztalyDescription(currentOsztaly)}
|
||||
</p>
|
||||
<ul>
|
||||
{OsztalyProperties(currentOsztaly).map(((special, i) => (<li key={currentOsztaly + i}>{special}</li>)))}
|
||||
</ul>
|
||||
<div className='col'>
|
||||
{OsztalySpecialSkills(currentOsztaly).map(skill =>
|
||||
<div key={skill.Id} >
|
||||
<strong className='d-inline'>
|
||||
{skill.Name}
|
||||
</strong>
|
||||
{' '}
|
||||
{skill.Description}
|
||||
{skill.ExtendedDescription && (
|
||||
<ol>
|
||||
{skill.ExtendedDescription.map((ext, i) =>
|
||||
(<li key={skill.Id + '-' + i}>{ext}</li>))}
|
||||
</ol>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default OsztalySelector;
|
||||
@@ -0,0 +1,8 @@
|
||||
import {Tooltip} from "react-bootstrap";
|
||||
import React from "react";
|
||||
|
||||
const SaveOverlayTooltip = <Tooltip id="save-tooltip">
|
||||
A mentéssel egyedi URL-en elérhető lesz a karakter bárkinek, azonban módosítani már nem lehet, csak újat menteni.
|
||||
</Tooltip>
|
||||
|
||||
export default SaveOverlayTooltip
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
|
||||
import {Faj, FajLabel} from "../domain-models/faj";
|
||||
import {Modifier} from "../domain-models/tulajdonsag";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
|
||||
|
||||
function fajiModositoText(faj: Faj, szamolas: (f: Faj) => number) : string {
|
||||
const mod = szamolas(faj)
|
||||
return (mod !== 0) ? SignedNumberToText(mod) + ' (' + FajLabel(faj) + ')' : ''
|
||||
}
|
||||
|
||||
function TulajdonsagInput(props: {
|
||||
tulajdonsag: string,
|
||||
currentFaj : Faj,
|
||||
fajiModosito: (faj: Faj) => number,
|
||||
changeValue: (val: number) => void
|
||||
currentValue: number
|
||||
tooLowError: string,
|
||||
tooHighError: string
|
||||
}) {
|
||||
const {
|
||||
tulajdonsag,
|
||||
changeValue,
|
||||
currentFaj,
|
||||
currentValue,
|
||||
fajiModosito,
|
||||
tooLowError,
|
||||
tooHighError,
|
||||
} = props;
|
||||
return (<div className='row m-2'>
|
||||
<label className='col-lg-1 col-sm-2 col-form-label'>{tulajdonsag}</label>
|
||||
<div className='col-lg-1 col-sm-2 m-2'>
|
||||
<input className='form-control' maxLength={2} type='number' value={currentValue} onChange={e => changeValue(Number(e.target.value))} />
|
||||
</div>
|
||||
<span className='col-sm-2 m-2'>
|
||||
{fajiModositoText(currentFaj, fajiModosito)}
|
||||
</span>
|
||||
<span className='col-sm-2 m-2'>
|
||||
Összesen: { (currentValue + (fajiModosito(currentFaj))).toString() }
|
||||
</span>
|
||||
<span className='col-sm-2 m-2'>
|
||||
Módosító: { SignedNumberToText(Modifier(currentValue + fajiModosito(currentFaj))) }
|
||||
</span>
|
||||
{currentValue < 3 && (
|
||||
<span className='form-field-error'>{tooLowError}</span>)}
|
||||
{currentValue > 18 && (
|
||||
<span className='form-field-error'>{tooHighError}</span>)}
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default TulajdonsagInput;
|
||||
@@ -0,0 +1,38 @@
|
||||
import React from "react";
|
||||
import {
|
||||
KarakterTulajdonsagok,
|
||||
Modifier,
|
||||
Tulajdonsag,
|
||||
TulajdonsagIDs,
|
||||
TulajdonsagLabel
|
||||
} from "../domain-models/tulajdonsag";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
|
||||
function TulajdonsagNoveles(props: {tulajdonsagok: KarakterTulajdonsagok, szint: number, tulajdonsagNovelesek: Tulajdonsag[], changeTulajdonsagNoveles: (tulajdonsag: Tulajdonsag) => void}) {
|
||||
const {tulajdonsagok, szint, tulajdonsagNovelesek, changeTulajdonsagNoveles} = props
|
||||
const tulajdonsagNoveles = tulajdonsagNovelesek[(szint / 4)-1]
|
||||
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 Tulajdonsag)}>
|
||||
{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
|
||||
@@ -0,0 +1,83 @@
|
||||
import React from "react";
|
||||
import {
|
||||
KarakterTulajdonsagok,
|
||||
RollAllAbilities,
|
||||
Tulajdonsag,
|
||||
} from "../domain-models/tulajdonsag";
|
||||
import TulajdonsagInput from "./TulajdonsagInput";
|
||||
import {Faj, TulajdonsagModositokFajokra} from "../domain-models/faj";
|
||||
|
||||
function Tulajdonsagok(props: {
|
||||
currentFaj: Faj,
|
||||
tulajdonsagok: KarakterTulajdonsagok
|
||||
changeTulajdonsagok: (tulajdonsagok: KarakterTulajdonsagok) => void
|
||||
}) {
|
||||
const {currentFaj, tulajdonsagok, changeTulajdonsagok} = props
|
||||
return <>
|
||||
<div className='row'>
|
||||
<h5 className='col-lg-2 col-sm-4 align-self-center'>Tulajdonságok</h5>
|
||||
<div className='col-sm-2 m-2'>
|
||||
<button className='btn btn-dark' type='button'
|
||||
onClick={() => changeTulajdonsagok(RollAllAbilities())}>Dobás
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Erő'
|
||||
currentValue={tulajdonsagok.t_ero}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag.Ero)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_ero: val})}
|
||||
tooLowError='Túl gyenge vagy, nem bírtad felemelni a kezed a jelentkezéshez!'
|
||||
tooHighError='Szét szakadtak az izmaid!'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Ügyesség'
|
||||
currentValue={tulajdonsagok.t_ugy}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag.Ugyesseg)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_ugy: val})}
|
||||
tooLowError='Orrabuktál jelentkezés helyett!'
|
||||
tooHighError='Emberfeletti zsonglörködésedre záptojással válaszoltak a helyiek!'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Egészség'
|
||||
currentValue={tulajdonsagok.t_egs}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag.Egeszseg)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_egs: val})}
|
||||
tooLowError='Túl beteg vagy ahhoz, hogy kalandozni menj!'
|
||||
tooHighError='Kicsattanó egészségedet csak a diambroid állíthatja meg, minő véletlen, hogy pont az arcodba robbant...'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Intelligencia'
|
||||
currentValue={tulajdonsagok.t_int}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag.Intelligencia)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_int: val})}
|
||||
tooLowError='Elfelejtetted, hogy mikor is kéne kalandozni indulni!'
|
||||
tooHighError='Ilyen tudás és logika birtokában mi szükséged van új információkra? Mindent le tudsz vezetni a már meglévő ismereteidből, és ezt azonnal beláttad.'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Bölcsesség'
|
||||
currentValue={tulajdonsagok.t_bol}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag.Bolcsesseg)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_bol: val})}
|
||||
tooLowError='Nem bírtál ellenállni a kíváncsiságodnak, hogy közelebbről is megvizsgáld a tőr hegyét. Nagyon közelről.'
|
||||
tooHighError='Hatalmas bölcsességedben beláttad a kalandozás veszélyeit és inkább más tevékenységbe fogtál.'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Karizma'
|
||||
currentValue={tulajdonsagok.t_kar}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag.Karizma)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_kar: val})}
|
||||
tooLowError='Mintha taszítanád az embereket, sose sikerült kalandozó csapatot találnod.'
|
||||
tooHighError='Az ellenkező nem tagjai nem engedték, hogy útnak indulj.'
|
||||
/>
|
||||
|
||||
</>
|
||||
}
|
||||
|
||||
export default Tulajdonsagok
|
||||
@@ -0,0 +1,24 @@
|
||||
import {Fegyver, GetFegyver} from "./felszereles";
|
||||
import fegyverDB from "./fegyver.json";
|
||||
import {Osztaly} from "./osztaly";
|
||||
|
||||
export function AllowedFegyver(o: Osztaly, harcosSpec: string[]): Fegyver[] {
|
||||
const fegyverek = fegyverDB.data.map(x => x as Fegyver)
|
||||
const nemEgzotikus = fegyverek.filter(f => !f.Egzotikus)
|
||||
const varazslo = fegyverek.filter(f => ['okol', 'bot', 'bunko', 'tor', 'parittya', 'dobotu'].includes(f.Id))
|
||||
const tolvaj = fegyverek.filter(f => ['okol', 'tor', 'parittya', 'rovid_ij', 'dobotu', 'konnyu_szamszerij', 'nehez_szamszerij', 'szablya', 'hosszu_kard', 'rovid_kard' ].includes(f.Id))
|
||||
switch (o) {
|
||||
case Osztaly.Harcos:
|
||||
const harcosSpecFegyverek = harcosSpec.map(GetFegyver).filter(x => x != null && x.Egzotikus).map(x => x as Fegyver)
|
||||
return [...nemEgzotikus, ...harcosSpecFegyverek]
|
||||
case Osztaly.Amazon:
|
||||
case Osztaly.Barbar:
|
||||
case Osztaly.Kaloz: return nemEgzotikus;
|
||||
case Osztaly.Ijasz: return [...nemEgzotikus, fegyverDB.data.find(f => f.Id === 'visszacsapo_ij') as Fegyver]
|
||||
// Note: Isteni fegyver barmi lehet istentol foggoen
|
||||
case Osztaly.Pap: return fegyverek;
|
||||
case Osztaly.Tolvaj: return tolvaj;
|
||||
case Osztaly.Illuzionista:
|
||||
case Osztaly.Varazslo: return varazslo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import {PancelType} from "./felszereles";
|
||||
import {Osztaly} from "./osztaly";
|
||||
|
||||
export function AllowedPancelTypes(osztalyok: Osztaly[]): PancelType[] {
|
||||
return [...new Set(osztalyok.flatMap(osztalyAllowedPancelTypes))]
|
||||
}
|
||||
|
||||
function osztalyAllowedPancelTypes(o: Osztaly): PancelType[] {
|
||||
switch (o) {
|
||||
case Osztaly.Amazon: return ['konnyu'];
|
||||
case Osztaly.Barbar: return ['konnyu', 'kozepes', 'nehez'];
|
||||
case Osztaly.Pap: return ['konnyu', 'kozepes', 'nehez'];
|
||||
case Osztaly.Illuzionista: return [];
|
||||
case Osztaly.Varazslo: return [];
|
||||
case Osztaly.Harcos: return ['konnyu', 'kozepes', 'nehez'];
|
||||
case Osztaly.Ijasz: return ['konnyu', 'kozepes'];
|
||||
case Osztaly.Kaloz: return ['konnyu', 'kozepes'];
|
||||
case Osztaly.Tolvaj: return ['konnyu']
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,328 @@
|
||||
import {Osztaly} from "./osztaly";
|
||||
import {KarakterTulajdonsagok, Tulajdonsag} from "./tulajdonsag";
|
||||
|
||||
export enum Faj {
|
||||
Ember = 'f_ember',
|
||||
Amazon = 'f_amazon',
|
||||
Birodalmi = 'f_birodalmi',
|
||||
Etuniai = 'f_etuniai',
|
||||
Eszaki = 'f_eszaki',
|
||||
Osember = 'f_osember',
|
||||
Elf = 'f_elf',
|
||||
Felelf = 'f_felelf',
|
||||
Felork = 'f_felork',
|
||||
Felszerzet = 'f_felszerzet',
|
||||
Gnom = 'f_gnom',
|
||||
Torpe = 'f_torpe',
|
||||
}
|
||||
|
||||
export function FajLabel(faj: Faj) : string {
|
||||
switch (faj) {
|
||||
case Faj.Ember: return 'Ember';
|
||||
case Faj.Amazon: return 'Amazon';
|
||||
case Faj.Birodalmi: return 'Birodalmi';
|
||||
case Faj.Etuniai: return 'Etúniai';
|
||||
case Faj.Eszaki: return 'Északi';
|
||||
case Faj.Osember: return 'Ősember';
|
||||
case Faj.Elf: return 'Elf';
|
||||
case Faj.Felelf: return 'Félelf';
|
||||
case Faj.Felork: return 'Félork';
|
||||
case Faj.Felszerzet: return 'Félszerzet';
|
||||
case Faj.Gnom: return 'Gnóm';
|
||||
case Faj.Torpe: return 'Törpe';
|
||||
}
|
||||
}
|
||||
|
||||
export function FajDescription(faj: Faj) : string {
|
||||
switch (faj) {
|
||||
case Faj.Ember: return "Az emberi népek sokfélesége és szaporasága, valamint a bennük élő felfedezői hajlam és erkölcsi rugalmasság hatására képviselőik majdnem minden földön megtalálhatók. A legtöbb ember a lenti vonásokkal rendelkezik.";
|
||||
case Faj.Amazon: return "Bár az amazonok népe igen kis létszámú, harciasságuk miatt mégis félik őket. Az amazonok nyúlánk termetűek, hajuk általában vöröses vagy világosbarna, bőrük világos. Társadalmukban teljes a nőuralom, a férfiakat rabszolgaságban tartják és megtiltják számukra a fegyverviselést. Képzett tengeri rablók, de a szárazföldön is megállják a helyüket. Az amazon nők kivétel nélkül értenek a harchoz és soha, soha nem hagyják megtorlatlanul az őket ért sérelmeket. Technikailag fejletlenek. Kis erejű passzív pszionikus (elmebeli) képességeik vannak.";
|
||||
case Faj.Birodalmi: return "Bár a Birodalom történelemelőtti kora már évezredek óta elmúlt, a nép maradékai még megtalálhatók. Az irántuk érzett gyűlölet miatt sokan rejtőzködni kényszerülnek közülük, pedig hatalmuk már meg sem közelíti a régit – életüket többnyire dekadens élvezetek habzsolásával, kábítószeres mámorban töltik. Bőrük lilás, a tisztavérűek esetén padlizsánszínű, szemük ibolyaszín. A fajtiszta birodalmiak között a beltenyészet és a degeneráció miatt gyakoriak az örökletes betegségek. Városaik számtalan titkot és mesés kincseket rejtenek.";
|
||||
case Faj.Etuniai: return "Az etúniai lovas nomádok kultúrája mindmáig megőrizte primitívségét. Akár földművelésből, akár lovas portyázásból, akár rablásból és kereskedésből élnek, nem fogékonyak a finomságok iránt. Eszközeik is egyszerűek: fegyvereik főleg hosszú lándzsák, és bár kedvelik a kardokat és láncvérteket, nem jeleskednek azok előállításában (a vas megmunkálását kovácsaik féltett titokként őrzik). Többnyire semleges jelleműek – bár azok, akik otthonuktól elszakadva kénytelenek megélni, inkább a gonosz felé hajlanak. Az etúniaiak középtermetűek, bőrük cserzett, hajuk olajos fekete, amit leggyakrabban copfban fognak össze. A férfiak kedvelik a bajusz viseletét.";
|
||||
case Faj.Eszaki: return "Az északi kultúra lételeme a harc és a hajózás. Még nőik is kiválóan forgatják a harci fejszét vagy a hosszú élű bárdot, s – bár rabszolgatartók – kegyetlenségnek tartják rabszolgáikat a legelemibb védekező eszközöktől, mint a késtől vagy a rövidkardtól megfosztani vagy fegyvertelenekre támadni. Ettől eltekintve vérszomjasak és általában semleges vagy gonosz jelleműek. Testalkatuk magas és erős, hajuk vöröses, szőke vagy világosbarna. A férfiak szakállat vagy bajuszt, a nők hosszú hajat viselnek. A déli vidékeken civilizálatlanságuk és faragatlanságuk miatt gyakran megvetik őket.";
|
||||
case Faj.Osember: return "Az Ősemberek vad földek primitív őslakói. Máig merizték görnyedt tartásukat, szőrös küllemüket és loboncos fekete hajukat. A fémmegmunkálást még sokan nem ismerik, s kőeszközöket – esetleg rezet– használnak. Írásuk egyáltalán nincs. Félisteneént tisztelik hátasaikat, a hatalmas mamutokat.";
|
||||
case Faj.Elf: return "Az elfek szépségükről, hosszú életükről és fejlett civilizációjukról ismertek, amely ötvözi a városi és természeti élet előnyeit. Termetük nyúlánk, vonásaik az embernél finomabbak, de egyben törékenyebbek. Kiváló íjászok és varázslók. Általában visszahúzódóak, csak ritkán lépnek kapcsolatba a rövidebb életű népekkel – legjobban az emberekkel és a félszerzetekkel jönnek ki. Jellemük általában kaotikus jó.";
|
||||
case Faj.Felelf: return "A félelfek elf és ember szülők gyermekei. Kis számuk miatt nem alkotnak külön közösségeket.";
|
||||
case Faj.Felork: return "A félorkok többsége külsejében inkább rút emberre hasonlít (bár termetük gyakran görnyedt, arcvonásaik pedig a disznóéra emlékeztetnek), belsőleg azonban számos ork vonással rendelkeznek: számítók, magányosak és bizalmatlanok a szebb fajokkal, de legtöbbször fajtársaikkal is. Különösen sok közöttük az orgyilkos és a közönséges gonosztevő; egyikük-másikuk ezt némi mágikus erővel vegyíti. A legtöbb félork gonosz jellemű.";
|
||||
case Faj.Felszerzet: return "A félszerzetek általában megelégszenek a nyugodt vidéki élettel. Termetük az emberi fele. Hajlamosak az elhízásra, s lábukat vastag szőr borítja. Általában mezítláb járnak. Mivel lusták és kényelemszeretők, csak ritkán adják fejüket kalandokra – ekkor azonban kiváló tolvajokká válhatnak.";
|
||||
case Faj.Gnom: return "A gnómok különösen ritka, elsősorban emberi városokban megtalálható alacsony termetű faj. A gnómokat alacsony termetükről, vékony végtagjaikról és tömpe, húsos orrukról lehet fölismerni. A gnómok jó kézművesek és van érzékük a mágiához is – elsősorban az illuzionisták trükkjeihez vonzódnak.";
|
||||
case Faj.Torpe: return "A törpék elsősorban hegyek között és dombvidékeken élnek. Termetük kicsi (1,2 m), de testük tömzsi és igen szívós. Bozontos szakállat viselnek, amely a férfiak esetén dús és sörteszerű, a nőknél finomabb és ritkásabb. A törpék kiemelkedőek a mindenféle mesterségekben, különösen a fémmunkákban, de harcban is megállják helyüket. Nagy nemzetségekbe szerveződnek és híresek igazságérzetükről, makacsságukról és kapzsiságukról. A legtöbb törpe törvényes jó vagy törvényes semleges jellemű.";
|
||||
}
|
||||
}
|
||||
|
||||
export function FajSpecials(faj : Faj) : string[] {
|
||||
switch (faj) {
|
||||
case Faj.Ember: return [
|
||||
"A játék kezdetén egy extra képzettséggel kezdenek",
|
||||
"Korlátlanul fejlődhetnek minden osztályban",
|
||||
];
|
||||
case Faj.Amazon: return [
|
||||
"Ha két vagy több amazon együttesen harcol, VO-juk 2-vel nő pszionikus képességeik miatt",
|
||||
"Szintkorlátok: Harcos -, Pap 5, Tolvaj 0, Varázsló 0",
|
||||
];
|
||||
case Faj.Birodalmi: return [
|
||||
"+1 Int, -1 Egs",
|
||||
"Egyik kezdő képzettségük mindenképpen az Alkímia vagy a Méregkeverés",
|
||||
"Szintkorlátok: Harcos 7, Pap 5, Tolvaj 5, Varázsló -",
|
||||
];
|
||||
case Faj.Etuniai: return [
|
||||
"+1 Egs, -1 Böl",
|
||||
"Az egyik kezdő képzettségük mindenképpen a Lovaglás",
|
||||
"Szintkorlátok: Harcos -, Pap 5, Tolvaj -, Varázsló 4",
|
||||
];
|
||||
case Faj.Eszaki: return [
|
||||
"+1 Erő, -1 Böl",
|
||||
"Az egyik kezdő képzettségük mindenképpen a Hajózás",
|
||||
"Szintkorlátok: Harcos -, Pap 7, Tolvaj -, Varázsló 5",
|
||||
];
|
||||
case Faj.Osember: return [
|
||||
"+1 Erő, +1 Egészség, -1 Int, -1 Böl",
|
||||
"Szintkorlátok: Harcos -, Pap 5, Tolvaj 4, Varázsló 0",
|
||||
];
|
||||
case Faj.Elf: return [
|
||||
"+1 Ügy, -1 Egs",
|
||||
"Immunisak az altató mágiára, +2 mentődobás bűbáj ellen",
|
||||
"Automatikusan képzettek az íjak és a hosszúkard használatában akkor is, ha osztályuk ezt nem adná meg nekik",
|
||||
"Nem támaszthatók föl közönséges mágiával",
|
||||
"Szintkorlátok: Harcos 9, Pap 7, Tolvaj 6, Varázsló 9",
|
||||
];
|
||||
case Faj.Felelf: return [
|
||||
"Automatikusan képzettek az íjak és a hosszúkard használatában",
|
||||
"Szintkorlátok: Harcos 9, Pap 5, Tolvaj 9, Varázsló 9",
|
||||
];
|
||||
case Faj.Felork: return [
|
||||
"+1 Erő, +1 Egs, -2 Kar",
|
||||
"Szintkorlátok: Harcos 9, Pap 5, Tolvaj 9, Varázsló 5",
|
||||
];
|
||||
case Faj.Felszerzet: return [
|
||||
"+1 Ügy, -1 Erő",
|
||||
"+1 VO kis méretük miatt",
|
||||
"+1 támadást kapnak dobófegyverekre és parittyákra",
|
||||
"Szintkorlátok: Harcos 6, Pap 6, Tolvaj 9, Varázsló 4",
|
||||
];
|
||||
case Faj.Gnom: return [
|
||||
"+1 Int, -1 Erő",
|
||||
"Szintkorlátok: Harcos 6, Pap 6, Tolvaj 8, Varázsló 7",
|
||||
];
|
||||
case Faj.Torpe: return [
|
||||
"+1 Egs, -1 Kar",
|
||||
"Lassabban mozognak az embereknél (alapsebességük 20’)",
|
||||
"+2 mentődobást kapnak mérgek és varázslatok hatásai ellen",
|
||||
"Szintkorlátok: Harcos 9, Pap 9, Tolvaj 6, Varázsló 4",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export type Szintkorlatok = Record<Osztaly, number>
|
||||
|
||||
export interface FajDetails {
|
||||
ID: Faj,
|
||||
Label: string,
|
||||
Description: string,
|
||||
Specials: string[],
|
||||
TulajdonsagModifiers: KarakterTulajdonsagok
|
||||
Szintkorlatok: Szintkorlatok
|
||||
}
|
||||
|
||||
|
||||
export function GetFajDetails(faj: Faj): FajDetails {
|
||||
return {
|
||||
ID: faj,
|
||||
Label: FajLabel(faj),
|
||||
Description: FajDescription(faj),
|
||||
Specials: FajSpecials(faj),
|
||||
TulajdonsagModifiers: fajiTulajdonsagModositok(faj),
|
||||
Szintkorlatok: SzintKorlatokFajokra(faj),
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection OverlyComplexFunctionJS,FunctionTooLongJS
|
||||
function tulajdonsagModositokPerFaj(tul: Tulajdonsag, faj: Faj) : number {
|
||||
switch (faj) {
|
||||
case Faj.Birodalmi: switch (tul) {
|
||||
case Tulajdonsag.Egeszseg: return -1;
|
||||
case Tulajdonsag.Intelligencia: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj.Eszaki: switch (tul) {
|
||||
case Tulajdonsag.Ero: return +1;
|
||||
case Tulajdonsag.Bolcsesseg: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj.Etuniai: switch (tul) {
|
||||
case Tulajdonsag.Egeszseg: return +1;
|
||||
case Tulajdonsag.Bolcsesseg: return -1;
|
||||
default: return 0
|
||||
}
|
||||
case Faj.Osember: switch (tul) {
|
||||
case Tulajdonsag.Ero: return +1;
|
||||
case Tulajdonsag.Egeszseg: return +1;
|
||||
case Tulajdonsag.Intelligencia: return -1;
|
||||
case Tulajdonsag.Bolcsesseg: return -1;
|
||||
default: return 0
|
||||
}
|
||||
case Faj.Elf: switch (tul) {
|
||||
case Tulajdonsag.Egeszseg: return -1;
|
||||
case Tulajdonsag.Ugyesseg: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj.Felork: switch (tul) {
|
||||
case Tulajdonsag.Ero: return +1;
|
||||
case Tulajdonsag.Egeszseg: return +1;
|
||||
case Tulajdonsag.Karizma: return -2;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj.Felszerzet: switch (tul) {
|
||||
case Tulajdonsag.Ero: return -1;
|
||||
case Tulajdonsag.Ugyesseg: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj.Gnom: switch (tul) {
|
||||
case Tulajdonsag.Ero: return -1;
|
||||
case Tulajdonsag.Intelligencia: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj.Torpe: switch (tul) {
|
||||
case Tulajdonsag.Egeszseg: return +1;
|
||||
case Tulajdonsag.Karizma: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function TulajdonsagModositokFajokra(tul: Tulajdonsag) {
|
||||
return (faj: Faj) => tulajdonsagModositokPerFaj(tul, faj);
|
||||
}
|
||||
|
||||
export function TulajdonsagokFajjal(tulajdonsagok: KarakterTulajdonsagok, faj: Faj): KarakterTulajdonsagok {
|
||||
return {
|
||||
[Tulajdonsag.Ero]: tulajdonsagok.t_ero + tulajdonsagModositokPerFaj(Tulajdonsag.Ero, faj),
|
||||
[Tulajdonsag.Ugyesseg]: tulajdonsagok.t_ugy + tulajdonsagModositokPerFaj(Tulajdonsag.Ugyesseg, faj),
|
||||
[Tulajdonsag.Egeszseg]: tulajdonsagok.t_egs + tulajdonsagModositokPerFaj(Tulajdonsag.Egeszseg, faj),
|
||||
[Tulajdonsag.Intelligencia]: tulajdonsagok.t_int + tulajdonsagModositokPerFaj(Tulajdonsag.Intelligencia, faj),
|
||||
[Tulajdonsag.Bolcsesseg]: tulajdonsagok.t_bol + tulajdonsagModositokPerFaj(Tulajdonsag.Bolcsesseg, faj),
|
||||
[Tulajdonsag.Karizma]: tulajdonsagok.t_kar + tulajdonsagModositokPerFaj(Tulajdonsag.Karizma, faj),
|
||||
}
|
||||
}
|
||||
|
||||
function fajiTulajdonsagModositok(faj: Faj): KarakterTulajdonsagok {
|
||||
return {
|
||||
[Tulajdonsag.Ero]: TulajdonsagModositokFajokra(Tulajdonsag.Ero)(faj),
|
||||
[Tulajdonsag.Ugyesseg]: TulajdonsagModositokFajokra(Tulajdonsag.Ugyesseg)(faj),
|
||||
[Tulajdonsag.Egeszseg]: TulajdonsagModositokFajokra(Tulajdonsag.Egeszseg)(faj),
|
||||
[Tulajdonsag.Intelligencia]: TulajdonsagModositokFajokra(Tulajdonsag.Intelligencia)(faj),
|
||||
[Tulajdonsag.Bolcsesseg]: TulajdonsagModositokFajokra(Tulajdonsag.Bolcsesseg)(faj),
|
||||
[Tulajdonsag.Karizma]: TulajdonsagModositokFajokra(Tulajdonsag.Karizma)(faj),
|
||||
}
|
||||
}
|
||||
|
||||
const EmberiSzintKorlatok: Szintkorlatok = {
|
||||
o_amazon: 0,
|
||||
o_barbar: 20,
|
||||
o_harcos: 20,
|
||||
o_ijasz: 20,
|
||||
o_illuzionista: 20,
|
||||
o_kaloz: 20,
|
||||
o_pap: 20,
|
||||
o_tolvaj: 20,
|
||||
o_varazslo: 20
|
||||
|
||||
}
|
||||
|
||||
// noinspection OverlyComplexFunctionJS,FunctionTooLongJS
|
||||
export function SzintKorlatokFajokra(faj: Faj) : Szintkorlatok {
|
||||
let szintkorlatok = {...EmberiSzintKorlatok}
|
||||
switch (faj) {
|
||||
case Faj.Ember: break;
|
||||
case Faj.Amazon:
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 0
|
||||
szintkorlatok.o_illuzionista = 0
|
||||
szintkorlatok.o_varazslo = 0
|
||||
szintkorlatok.o_amazon = 20
|
||||
break
|
||||
case Faj.Birodalmi:
|
||||
szintkorlatok.o_harcos = 7
|
||||
szintkorlatok.o_barbar = 7
|
||||
szintkorlatok.o_ijasz = 7
|
||||
szintkorlatok.o_kaloz = 7
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 5
|
||||
break
|
||||
case Faj.Eszaki:
|
||||
case Faj.Etuniai:
|
||||
szintkorlatok.o_pap = 7
|
||||
szintkorlatok.o_illuzionista = 5
|
||||
szintkorlatok.o_varazslo = 5
|
||||
break
|
||||
case Faj.Osember:
|
||||
szintkorlatok.o_pap = 7
|
||||
szintkorlatok.o_tolvaj = 4
|
||||
szintkorlatok.o_illuzionista = 0
|
||||
szintkorlatok.o_varazslo = 0
|
||||
break
|
||||
case Faj.Elf:
|
||||
szintkorlatok.o_pap = 7
|
||||
szintkorlatok.o_tolvaj = 6
|
||||
szintkorlatok.o_illuzionista = 9
|
||||
szintkorlatok.o_varazslo = 9
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
case Faj.Felelf:
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 9
|
||||
szintkorlatok.o_illuzionista = 9
|
||||
szintkorlatok.o_varazslo = 9
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
case Faj.Felork:
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 9
|
||||
szintkorlatok.o_illuzionista = 5
|
||||
szintkorlatok.o_varazslo = 5
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
case Faj.Felszerzet:
|
||||
szintkorlatok.o_pap = 6
|
||||
szintkorlatok.o_tolvaj = 9
|
||||
szintkorlatok.o_illuzionista = 4
|
||||
szintkorlatok.o_varazslo = 4
|
||||
szintkorlatok.o_harcos = 6
|
||||
szintkorlatok.o_barbar = 6
|
||||
szintkorlatok.o_ijasz = 6
|
||||
szintkorlatok.o_kaloz = 6
|
||||
break
|
||||
case Faj.Gnom:
|
||||
szintkorlatok.o_pap = 6
|
||||
szintkorlatok.o_tolvaj = 8
|
||||
szintkorlatok.o_illuzionista = 7
|
||||
szintkorlatok.o_varazslo = 7
|
||||
szintkorlatok.o_harcos = 6
|
||||
szintkorlatok.o_barbar = 6
|
||||
szintkorlatok.o_ijasz = 6
|
||||
szintkorlatok.o_kaloz = 6
|
||||
break
|
||||
case Faj.Torpe:
|
||||
szintkorlatok.o_pap = 9
|
||||
szintkorlatok.o_tolvaj = 6
|
||||
szintkorlatok.o_illuzionista = 4
|
||||
szintkorlatok.o_varazslo = 4
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
}
|
||||
return szintkorlatok
|
||||
}
|
||||
@@ -0,0 +1,467 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"Id": "alabard",
|
||||
"Name": "Alabárd és más szálfegyverek",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": true,
|
||||
"Price": 10,
|
||||
"DamageDice": 10,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "bot",
|
||||
"Name": "Bot",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 0,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "bunko",
|
||||
"Name": "Bunkó",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 0,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "buzogany",
|
||||
"Name": "Buzogány és láncos buzogány",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 8,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "csatabard",
|
||||
"Name": "Csatabárd",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 10,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "csatabard_2",
|
||||
"Name": "Kétkezes csatabárd",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 20,
|
||||
"DamageDice": 12,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "csakany",
|
||||
"Name": "Csákány",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 5,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 4,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "darda",
|
||||
"Name": "Dárda",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": true,
|
||||
"Price": 10,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "fejsze",
|
||||
"Name": "Fejsze",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 6,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 10
|
||||
},
|
||||
{
|
||||
"Id": "torpe_fejsze",
|
||||
"Name": "Törpe fejsze",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": true,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 30,
|
||||
"DamageDice": 10,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "handzsar",
|
||||
"Name": "Handzsár",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 50,
|
||||
"DamageDice": 4,
|
||||
"NumberOfDamageDice": 2,
|
||||
"CritRangeStart": 18,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "harci_kalapacs",
|
||||
"Name": "Harci kalapács",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 12,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "harci_kalapacs_2",
|
||||
"Name": "Kétkezes harci kalapács",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 25,
|
||||
"DamageDice": 10,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "fattyu_kard",
|
||||
"Name": "Fattyú kard",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": true,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 35,
|
||||
"DamageDice": 10,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 19,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "rovid_kard",
|
||||
"Name": "Rövid kard",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 10,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 19,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "hosszu_kard",
|
||||
"Name": "Hosszú kard",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 15,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 19,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "kard_2",
|
||||
"Name": "Kétkezes kard",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 50,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 2,
|
||||
"CritRangeStart": 19,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "kasza",
|
||||
"Name": "Kasza",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": true,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 18,
|
||||
"DamageDice": 4,
|
||||
"NumberOfDamageDice": 2,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 4,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "landzsa",
|
||||
"Name": "Lándzsa",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 5,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 20
|
||||
},
|
||||
{
|
||||
"Id": "sarlo",
|
||||
"Name": "Sarló",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 3,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "szablya",
|
||||
"Name": "Szablya",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 15,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 18,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "szigony",
|
||||
"Name": "Háromágú szigony",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 10,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 10
|
||||
},
|
||||
{
|
||||
"Id": "tor",
|
||||
"Name": "Tőr",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 2,
|
||||
"DamageDice": 4,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 19,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 10
|
||||
},
|
||||
{
|
||||
"Id": "ostor",
|
||||
"Name": "Ostor",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": true,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 1,
|
||||
"DamageDice": 3,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
{
|
||||
"Id": "okol",
|
||||
"Name": "Ököl",
|
||||
"Type": "kozelharci",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 0,
|
||||
"DamageDice": 4,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 0
|
||||
},
|
||||
|
||||
{
|
||||
"Id": "dobodarda",
|
||||
"Name": "Dobódárda",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 0.1,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 30
|
||||
},
|
||||
{
|
||||
"Id": "dobotu",
|
||||
"Name": "Dobótű",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": false,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 0.5,
|
||||
"DamageDice": 4,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 20
|
||||
},
|
||||
{
|
||||
"Id": "rovid_ij",
|
||||
"Name": "Rövid íj",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 30,
|
||||
"DamageDice": 6,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 60
|
||||
},
|
||||
{
|
||||
"Id": "hosszu_ij",
|
||||
"Name": "Hosszú íj",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 75,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 70
|
||||
},
|
||||
{
|
||||
"Id": "visszacsapo_ij",
|
||||
"Name": "Visszacsapó íj",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": true,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 100,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 3,
|
||||
"Range": 110
|
||||
},
|
||||
{
|
||||
"Id": "parittya",
|
||||
"Name": "Parittya",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 0,
|
||||
"DamageDice": 4,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 20,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 50
|
||||
},
|
||||
{
|
||||
"Id": "konnyu_szamszerij",
|
||||
"Name": "Könnyű számszeríj",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 35,
|
||||
"DamageDice": 8,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 19,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 80
|
||||
},
|
||||
{
|
||||
"Id": "nehez_szamszerij",
|
||||
"Name": "Nehéz számszeríj",
|
||||
"Type": "lofegyver",
|
||||
"Ketkezes": true,
|
||||
"Egzotikus": false,
|
||||
"Rohamfelfogo": false,
|
||||
"Price": 50,
|
||||
"DamageDice": 10,
|
||||
"NumberOfDamageDice": 1,
|
||||
"CritRangeStart": 19,
|
||||
"CritMultiplier": 2,
|
||||
"Range": 120
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,419 @@
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"Id": "acel_es_kova",
|
||||
"Name": "Acél és kova",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.1
|
||||
},
|
||||
{
|
||||
"Id": "aso",
|
||||
"Name": "Ásó",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "vas_bogracs",
|
||||
"Name": "Bogrács, vas",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.5
|
||||
},
|
||||
{
|
||||
"Id": "borostomlo",
|
||||
"Name": "Borostömlő",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "csakany",
|
||||
"Name": "Csákány",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 5
|
||||
},
|
||||
{
|
||||
"Id": "elelem",
|
||||
"Name": "Élelem, tartós úti, egy napra",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.5
|
||||
},
|
||||
{
|
||||
"Id": "faklya",
|
||||
"Name": "Fáklya",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.01
|
||||
},
|
||||
|
||||
{
|
||||
"Id": "farud",
|
||||
"Name": "Farúd, 10’",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.03
|
||||
},
|
||||
{
|
||||
"Id": "feszitovas",
|
||||
"Name": "Feszítővas",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 2
|
||||
},
|
||||
{
|
||||
"Id": "fustulo",
|
||||
"Name": "Füstölő, rúd",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "gyertya_viasz",
|
||||
"Name": "Gyertya, viasz",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.1
|
||||
},
|
||||
{
|
||||
"Id": "halasz_halo",
|
||||
"Name": "Háló, halász, 5’*5’",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 4
|
||||
},
|
||||
{
|
||||
"Id": "hatizsak",
|
||||
"Name": "Hátizsák",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 2
|
||||
},
|
||||
{
|
||||
"Id": "hordo_kicsi",
|
||||
"Name": "Hordó, kicsi",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 2
|
||||
},
|
||||
{
|
||||
"Id": "illatszer",
|
||||
"Name": "Illatszer",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 5
|
||||
},
|
||||
{
|
||||
"Id": "kotel_kender_50",
|
||||
"Name": "Kötél, kender, 50’",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "kotel_selyem_50",
|
||||
"Name": "Kötél, selyem, 50’",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 10
|
||||
},
|
||||
{
|
||||
"Id": "kreta",
|
||||
"Name": "Kréta",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.01
|
||||
},
|
||||
{
|
||||
"Id": "lada_fa_kicsi",
|
||||
"Name": "Láda, fa, kicsi",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 2
|
||||
},
|
||||
{
|
||||
"Id": "lada_fa_nagy",
|
||||
"Name": "Láda, fa, nagy",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 5
|
||||
},
|
||||
{
|
||||
"Id": "lada_vas_kicsi",
|
||||
"Name": "Láda, vas, kicsi",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 9
|
||||
},{
|
||||
"Id": "lada_vas_nagy",
|
||||
"Name": "Láda, vas, nagy",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 28
|
||||
},
|
||||
{
|
||||
"Id": "lakat_egyszeru",
|
||||
"Name": "Lakat, egyszerű",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 20
|
||||
},
|
||||
{
|
||||
"Id": "lakat_kivalo",
|
||||
"Name": "Lakat, kiváló",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 80
|
||||
},
|
||||
{
|
||||
"Id": "olaj_lampa_egyszeru",
|
||||
"Name": "Lámpa, olaj, egyszerű",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
|
||||
{
|
||||
"Id": "olaj_lampa_vedett",
|
||||
"Name": "Lámpa, olaj, védett",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 7
|
||||
},
|
||||
{
|
||||
"Id": "olaj_lampa_nagy",
|
||||
"Name": "Lámpa, olaj, nagy",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 12
|
||||
},
|
||||
{
|
||||
"Id": "lanc_10",
|
||||
"Name": "Lánc, 10’",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 10
|
||||
},
|
||||
{
|
||||
"Id": "maszovas",
|
||||
"Name": "Mászóvas",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "olaj_palck",
|
||||
"Name": "Olaj, palack",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "palack_cserep",
|
||||
"Name": "Palack, cserép",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.03
|
||||
},
|
||||
{
|
||||
"Id": "palack_uveg",
|
||||
"Name": "Palack, üveg",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 2
|
||||
},
|
||||
{
|
||||
"Id": "papir",
|
||||
"Name": "Papír, lap",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.4
|
||||
},
|
||||
{
|
||||
"Id": "pecsetgyuru",
|
||||
"Name": "Pecsétgyűrű",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 8
|
||||
},
|
||||
{
|
||||
"Id": "pecsetviasz",
|
||||
"Name": "Pecsétviasz",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "pergamen",
|
||||
"Name": "Pergamen, lap",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.2
|
||||
},
|
||||
{
|
||||
"Id": "sator",
|
||||
"Name": "Sátor",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 10
|
||||
},
|
||||
{
|
||||
"Id": "sav",
|
||||
"Name": "Sav",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 10
|
||||
},
|
||||
{
|
||||
"Id": "szappan",
|
||||
"Name": "Szappan",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.5
|
||||
},
|
||||
{
|
||||
"Id": "szentelt_viz",
|
||||
"Name": "Szenteltvíz",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 25
|
||||
},
|
||||
{
|
||||
"Id": "szog",
|
||||
"Name": "Szög",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.01
|
||||
},
|
||||
{
|
||||
"Id": "takaro",
|
||||
"Name": "Takaró",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.2
|
||||
},
|
||||
{
|
||||
"Id": "tarsoly",
|
||||
"Name": "Tarsoly",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "tegez",
|
||||
"Name": "Tegez",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 2
|
||||
},
|
||||
{
|
||||
"Id": "telercstarto",
|
||||
"Name": "Tekercstartó",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 5
|
||||
},
|
||||
{
|
||||
"Id": "tinta",
|
||||
"Name": "Tinta",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 8
|
||||
},
|
||||
{
|
||||
"Id": "tukor",
|
||||
"Name": "Tükör",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 10
|
||||
},
|
||||
{
|
||||
"Id": "uvegcse",
|
||||
"Name": "Üvegcse",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "vodor",
|
||||
"Name": "Vödör",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.5
|
||||
},
|
||||
{
|
||||
"Id": "zsak",
|
||||
"Name": "Zsák",
|
||||
"Type": "simple",
|
||||
"PriceInGold": 0.1
|
||||
},
|
||||
{
|
||||
"Id": "elokelo_ruha",
|
||||
"Name": "Előkelő",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 75
|
||||
},
|
||||
{
|
||||
"Id": "elokelo_ruha",
|
||||
"Name": "Előkelő",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 75
|
||||
},
|
||||
{
|
||||
"Id": "kozrendu_ruha",
|
||||
"Name": "Közrendű",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 0.1
|
||||
},
|
||||
{
|
||||
"Id": "meleg_ruha",
|
||||
"Name": "Meleg",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 8
|
||||
},
|
||||
{
|
||||
"Id": "mesterember_ruha",
|
||||
"Name": "Mesterember",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "nagyuri_ruha",
|
||||
"Name": "Nagyúri",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 200
|
||||
},
|
||||
{
|
||||
"Id": "papi_ruha",
|
||||
"Name": "Papi",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 5
|
||||
},
|
||||
{
|
||||
"Id": "utazo_ruha",
|
||||
"Name": "Utazó",
|
||||
"Type": "clothes",
|
||||
"PriceInGold": 1
|
||||
},
|
||||
{
|
||||
"Id": "alkimista_labor",
|
||||
"Name": "Alkimista labor",
|
||||
"Type": "special",
|
||||
"PriceInGold": 500
|
||||
},
|
||||
{
|
||||
"Id": "homokora",
|
||||
"Name": "Homokóra",
|
||||
"Type": "special",
|
||||
"PriceInGold": 25
|
||||
},
|
||||
{
|
||||
"Id": "merleg",
|
||||
"Name": "Mérleg",
|
||||
"Type": "special",
|
||||
"PriceInGold": 2
|
||||
},
|
||||
{
|
||||
"Id": "nagyito",
|
||||
"Name": "Nagyító",
|
||||
"Type": "special",
|
||||
"PriceInGold": 100
|
||||
},
|
||||
{
|
||||
"Id": "szent_szimbolum",
|
||||
"Name": "Szent szimbólum",
|
||||
"Type": "special",
|
||||
"PriceInGold": 25
|
||||
},
|
||||
{
|
||||
"Id": "tavcso",
|
||||
"Name": "Távcső",
|
||||
"Type": "special",
|
||||
"PriceInGold": 1000
|
||||
},
|
||||
{
|
||||
"Id": "tolvajszerszamok",
|
||||
"Name": "Tolvajszerszámok",
|
||||
"Type": "special",
|
||||
"PriceInGold": 30
|
||||
},
|
||||
{
|
||||
"Id": "varazskomponens_tarto",
|
||||
"Name": "Varázskomponenstartó",
|
||||
"Type": "special",
|
||||
"PriceInGold": 5
|
||||
},
|
||||
{
|
||||
"Id": "varazskonyv",
|
||||
"Name": "Varázskönyv, üres",
|
||||
"Type": "special",
|
||||
"PriceInGold": 15
|
||||
},
|
||||
{
|
||||
"Id": "vizora",
|
||||
"Name": "Vízóra",
|
||||
"Type": "special",
|
||||
"PriceInGold": 500
|
||||
},
|
||||
{
|
||||
"Id": "zeneszerszam",
|
||||
"Name": "Zeneszerszám, egyszerű",
|
||||
"Type": "special",
|
||||
"PriceInGold": 5
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
import pancelok from './pancel.json'
|
||||
import pajzsok from './pajzs.json'
|
||||
import fegyverek from './fegyver.json'
|
||||
|
||||
export type PancelType = 'konnyu' | 'kozepes' | 'nehez'
|
||||
|
||||
export const PancelTypes: PancelType[] = ['konnyu', 'kozepes', 'nehez']
|
||||
|
||||
export interface Pancel {
|
||||
Id: string,
|
||||
Name: string,
|
||||
Type: PancelType
|
||||
VO: number,
|
||||
Price: number,
|
||||
}
|
||||
|
||||
export interface Pajzs {
|
||||
Id: string,
|
||||
Name: string,
|
||||
Type: 'pajzs'
|
||||
VO: number,
|
||||
Price: number,
|
||||
}
|
||||
|
||||
export interface Fegyver {
|
||||
Id: string,
|
||||
Name: string,
|
||||
Type: 'kozelharci' | 'lofegyver'
|
||||
Ketkezes: boolean,
|
||||
Egzotikus: boolean,
|
||||
Rohamfelfogo: boolean,
|
||||
Price: number,
|
||||
DamageDice: number,
|
||||
NumberOfDamageDice: number,
|
||||
CritRangeStart: number,
|
||||
CritMultiplier: number,
|
||||
Range: number
|
||||
}
|
||||
|
||||
export interface KarakterFelszereles {
|
||||
pancelID?: string
|
||||
pajzsID?: string
|
||||
fegyverIDk: string[]
|
||||
}
|
||||
|
||||
export const DefaultFelszereles: KarakterFelszereles = {
|
||||
fegyverIDk: [],
|
||||
}
|
||||
|
||||
export function PancelTypeLabel(type: PancelType): string {
|
||||
let result: string
|
||||
switch(type) {
|
||||
case 'konnyu':
|
||||
result = 'Könnyű'
|
||||
break
|
||||
case 'kozepes':
|
||||
result = 'Közepes'
|
||||
break
|
||||
case 'nehez':
|
||||
result = 'Nehéz'
|
||||
break
|
||||
default:
|
||||
result = 'Egyéb páncél'
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
export function GetPancel(id?: string): Pancel | undefined {
|
||||
if (id == null) {
|
||||
return undefined
|
||||
}
|
||||
const filteredPancel = pancelok['pancel'].filter(p => p.Id === id) as Pancel[]
|
||||
return filteredPancel.length > 0 ? filteredPancel[0] : undefined
|
||||
}
|
||||
|
||||
export function MaxAbilityVO(p: PancelType) {
|
||||
switch(p){
|
||||
case 'konnyu': return 3;
|
||||
case 'kozepes': return 2;
|
||||
case 'nehez': return 1;
|
||||
default: return 9999;
|
||||
}
|
||||
}
|
||||
|
||||
export function GetPajzs(id?: string): Pajzs | undefined {
|
||||
if (id == null) {
|
||||
return undefined
|
||||
}
|
||||
const filtered = pajzsok['pajzs'].filter(p => p.Id === id) as Pajzs[]
|
||||
return filtered.length > 0 ? filtered[0] : undefined
|
||||
}
|
||||
|
||||
export function GetFegyver(id: string): Fegyver | undefined {
|
||||
return fegyverek.data.find(f => f.Id === id) as Fegyver | undefined
|
||||
}
|
||||
|
||||
export function GetFegyverek(ids: string[]): Fegyver[] {
|
||||
return ids.map(GetFegyver).filter(x => x != null).map(x => x as Fegyver)
|
||||
}
|
||||
export const defaultFegyverID = 'okol'
|
||||
export const defaultFegyver = GetFegyver('okol')!
|
||||
@@ -0,0 +1,59 @@
|
||||
export type JellemID = 'TJ' | 'SJ' | 'KJ' | 'TS' | 'S' | 'KS' | 'TG' | 'SG' | 'KG'
|
||||
|
||||
export const AllJellemIDs: JellemID[] = ['TJ', 'SJ', 'KJ', 'TS', 'S', 'KS', 'TG', 'SG', 'KG']
|
||||
|
||||
export interface Jellem {
|
||||
ID: JellemID
|
||||
Label: string
|
||||
Description: string
|
||||
}
|
||||
|
||||
export function GetJellem(id: JellemID): Jellem {
|
||||
switch (id) {
|
||||
case "TJ": return {
|
||||
ID: "TJ",
|
||||
Label: "Törvényes Jó",
|
||||
Description: "A törvényes jó karakterek betartják és fontosnak tartják az igazságos törvényeket, valamint a kiérdemelt tekintély tiszteletét. Viselkedésükben lehetőleg egyenesek, és nem okoznak szükségtelen károkat másnak; továbbá segítenek a kevésbé szerencséseken.",
|
||||
}
|
||||
case "SJ": return {
|
||||
ID: "SJ",
|
||||
Label: "Semleges Jó",
|
||||
Description: "A semleges jó karakterek általában jóindulatúak, de nem jellemző rájuk sem a törvényes jók szigora, sem a kaotikus jók kiszámíthatatlansága.",
|
||||
}
|
||||
case "KJ": return {
|
||||
ID: "KJ",
|
||||
Label: "Kaotikus Jó",
|
||||
Description: "A kaotikus jó karakterek nagy súlyt fektetnek az egyéni szabadságra és a jótéteményekre – akkor is, ha ezek a nézetek és tettek ellentétesek a társadalmi szokásokkal és írott törvényekkel.",
|
||||
}
|
||||
case "TS": return {
|
||||
ID: "TS",
|
||||
Label: "Törvényes Semleges",
|
||||
Description: "A törvényes semleges karakterek szigorúan betartják a törvényeket és adott szavukat, de ez a törvénytisztelet nem altruizmusból, hanem elsősorban önzésből, közömbösségből vagy a törvények öncélú tiszteletéből fakad.",
|
||||
}
|
||||
case "S": return {
|
||||
ID: "S",
|
||||
Label: "Semleges",
|
||||
Description: "A semleges karakterek vagy nem törődnek a fontos erkölcsi kérdésekkel – azaz nem kötelezik el magukat egyes ügyek mellett – vagy éppen ellenkezőleg, aktívan a különféle nézetek közötti egyensúlyra és harmóniára törekednek. Az átlagemberek többsége ehhez a jellemhez tartozik.",
|
||||
}
|
||||
case "KS": return {
|
||||
ID: "KS",
|
||||
Label: "Kaotikus Semleges",
|
||||
Description: "A kaotikus semleges karakterek kiszámíthatatlanok, saját boldogulásukra törekednek akár mások ellenében is. A kalandozók igen jelentős része kaotikus semleges jellemű"
|
||||
}
|
||||
case "TG": return {
|
||||
ID: "TG",
|
||||
Label: "Törvényes Gonosz",
|
||||
Description: "A törvényes gonosz karakterek lételeme a törvényadta lehetőségek kihasználása mások kisemmizésére és önmaguk gyarapítására. Nem csoda, hogy számos zsarnok és kiskirály e jellem képviselője.",
|
||||
}
|
||||
case "SG": return {
|
||||
ID: "SG",
|
||||
Label: "Semleges Gonosz",
|
||||
Description: "A semleges gonosz karakterek döntően aljasak és rosszindulatúak, s céljaikat hol a törvények kijátszásával, hol a rájuk való hivatkozással érik el."
|
||||
}
|
||||
case "KG": return {
|
||||
ID: "KG",
|
||||
Label: "Kaotikus Gonosz",
|
||||
Description: "A kaotikus gonosz karakterek kíméletlenül, mindenen és mindenkin átgázolva hajszolják a hatalmat vagy a vagyont, s ennek érdekében bármilyen gaztettre képesek."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import {Faj} from "./faj";
|
||||
import {Osztaly} from "./osztaly";
|
||||
import {KepzettsegId} from "./kepzettsegek";
|
||||
import {JellemID} from "./jellem";
|
||||
import { DefaultFelszereles, KarakterFelszereles } from './felszereles'
|
||||
import {KarakterTulajdonsagok, Tulajdonsag, TulajdonsagDefaults} from "./tulajdonsag";
|
||||
|
||||
export interface KarakterInputs {
|
||||
name: string,
|
||||
nem?: string,
|
||||
kor: number,
|
||||
jellem: JellemID,
|
||||
isten?: string,
|
||||
faj: Faj,
|
||||
osztaly: Osztaly,
|
||||
tulajdonsagok: KarakterTulajdonsagok,
|
||||
kepzettsegek: KepzettsegId[],
|
||||
tolvajKepzettsegek?: KepzettsegId[]
|
||||
szint: number
|
||||
hpRolls: number[],
|
||||
tulajdonsagNovelesek: Tulajdonsag[],
|
||||
harcosSpecializaciok: string[],
|
||||
kalozKritikus: string[],
|
||||
felszereles: KarakterFelszereles,
|
||||
}
|
||||
|
||||
export const KarakterDefaults: KarakterInputs = {
|
||||
name: "Névtelen Kalandozó",
|
||||
faj: Faj.Ember,
|
||||
kor: 20,
|
||||
jellem: 'S',
|
||||
tulajdonsagok: TulajdonsagDefaults,
|
||||
osztaly: Osztaly.Kaloz,
|
||||
kepzettsegek: [],
|
||||
szint: 1,
|
||||
hpRolls: [],
|
||||
tulajdonsagNovelesek: [],
|
||||
harcosSpecializaciok: [],
|
||||
kalozKritikus: [],
|
||||
felszereles: DefaultFelszereles,
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
import {Osztaly} from "./osztaly";
|
||||
import {Faj} from "./faj";
|
||||
import {KarakterInputs} from "./karakter";
|
||||
import {Modifier, Tulajdonsag} from "./tulajdonsag";
|
||||
|
||||
export type KepzettsegId = 'k_alkimia' | 'k_alcazas' | 'k_allatidomitas' | 'k_csapdak' | 'k_csillagjoslas' | 'k_egyensulyozas' | 'k_eloadas' | 'k_ertekbecsles' | 'k_gyogyitas' | 'k_hajozas' | 'k_hallgatozas' | 'k_hamisitas' | 'k_jelek_olvasasa' | 'k_koncentracio' | 'k_lovaglas' | 'k_maszas' | 'k_megfigyeles' | 'k_meregkeveres' | 'k_mesterseg' | 'k_nyomkereses' | 'k_osonas' | 'k_rejtozes' | 'k_szabadulomuveszet' | 'k_tudas' | 'k_ugras' | 'k_uszas' | 'k_varazslatismeret' | 'k_zarnyitas' | 'k_zsebmetszes'
|
||||
|
||||
export interface Kepzettseg {
|
||||
Id: KepzettsegId,
|
||||
Name: string,
|
||||
Description: string,
|
||||
Tulajdonsag: Tulajdonsag[],
|
||||
Osztalyok?: Osztaly[],
|
||||
}
|
||||
|
||||
export const KepzettsegLista: Kepzettseg[] = [
|
||||
{
|
||||
Id: 'k_alkimia',
|
||||
Name: 'Alkímia',
|
||||
Description: 'Különféle különleges anyagok, pl. savak, görögtűz, stb. kikeverésére szolgál. Használatához gyakran jól felszerelt laboratórium szükséges. Az Alkímia képzettséggel a karakter képes beazonosítani a különféle vegyi anyagokat és mérgeket, bizonyos esetekben varázsitalokat is.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia],
|
||||
Osztalyok: [Osztaly.Varazslo, Osztaly.Illuzionista],
|
||||
},
|
||||
{
|
||||
Id: 'k_alcazas',
|
||||
Name: 'Álcázás',
|
||||
Description: 'Álöltözetek készítése és effektív használata. Próbadobást akkor kell dobni, ha az álca hitelességét valaki kétségbe vonhatja (általában titkos dobás; az eredményt csak a mesélő ismeri).',
|
||||
Tulajdonsag: [Tulajdonsag.Karizma],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
{
|
||||
Id: 'k_allatidomitas',
|
||||
Name: 'Állatidomítás',
|
||||
Description: 'Állatok megszelídítésére, betanítására szolgál. A járatos karakter próbát tehet arra is, hogy a különféle vadállatok ne tekintsék ellenségüknek vagy prédájuknak',
|
||||
Tulajdonsag: [Tulajdonsag.Karizma],
|
||||
},
|
||||
{
|
||||
Id: 'k_csapdak',
|
||||
Name: 'Csapdák állítása',
|
||||
Description: 'A karakter a rendelkezésre álló idő és alapanyagok függvényében készíthet szimpla vagy komplex csapdákat. Ha egy csapda eltávolítására tett próba sikertelen, az bizonyos eséllyel kisülhet és veszélybe sodorhatja az óvatlan próbálkozót.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
{
|
||||
Id: 'k_csillagjoslas',
|
||||
Name: 'Csillagjóslás',
|
||||
Description: 'A karakter a képzettséggel egyrészt képes meghatározni a karakterek hozzávetőleges pozícióját a térképen, másrészt egyszerűbb jóslatokat készíthet.',
|
||||
Tulajdonsag: [Tulajdonsag.Bolcsesseg],
|
||||
Osztalyok: [Osztaly.Varazslo, Osztaly.Illuzionista],
|
||||
},
|
||||
{
|
||||
Id: 'k_egyensulyozas',
|
||||
Name: 'Egyensúlyozás',
|
||||
Description: 'Omlatag talajon vagy keskeny járófelületen való átjutáshoz szükséges képzettség. Ha a próba sikertelen, a karakter lezuhan.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
{
|
||||
Id: 'k_eloadas',
|
||||
Name: 'Előadás',
|
||||
Description: 'A képzettséggel rendelkező karakter járatos a hangszerek használatában, éneklésben, eposzmondásban, stb.',
|
||||
Tulajdonsag: [Tulajdonsag.Karizma],
|
||||
},
|
||||
{
|
||||
Id: 'k_ertekbecsles',
|
||||
Name: 'Értékbecslés',
|
||||
Description: 'Sikeres próba esetén a karakter hozzávetőlegesen felméri egy tárgy pénzbeli értékét és kiszúrja a hamisítványokat.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia],
|
||||
},
|
||||
{
|
||||
Id: 'k_gyogyitas',
|
||||
Name: 'Gyógyítás',
|
||||
Description: 'A sebek ellátásának, mérgek és betegségek semlegesítésének vagy enyhítésének tudománya. Ha a képzettséget sikeresen alkalmazzák közvetlenül harc után, a bekötözött karakter visszanyer 1d4 elvesztett Hp-t.',
|
||||
Tulajdonsag: [Tulajdonsag.Bolcsesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_hajozas',
|
||||
Name: 'Hajózás',
|
||||
Description: 'A karakter ismeri a hajózás trükkjeit, tehát elkormányoz kisebb vitorlásokat vagy gályákat, tudja hogyan kell elkerülni a zátonyokat, képes javításokat végezni, stb.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_hallgatozas',
|
||||
Name: 'Hallgatózás',
|
||||
Description: 'Alig hallható zajok, beszéd meghallása.',
|
||||
Tulajdonsag: [Tulajdonsag.Bolcsesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_hamisitas',
|
||||
Name: 'Hamisítás',
|
||||
Description: 'A képzettséggel hamis pénz, iratok, pecsétek és értéktárgyak készíthetők. Próbadobást akkor kell dobni, ha a hamisítvány hitelességét valaki kétségbe vonhatja.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
{
|
||||
Id: 'k_jelek_olvasasa',
|
||||
Name: 'Jelek Olvasása',
|
||||
Description: 'A képzettséggel a karakter el tud olvasni más nyelven írt írásokat és feliratokat.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia],
|
||||
Osztalyok: [Osztaly.Tolvaj, Osztaly.Varazslo, Osztaly.Illuzionista],
|
||||
},
|
||||
{
|
||||
Id: 'k_koncentracio',
|
||||
Name: 'Koncentráció',
|
||||
Description: 'Ez a képesség arra teszi alkalmassá a varázshasználót, hogy nehéz körülmények között – sebesülten, vágtató lovon, hánykolódó hajón, stb. – is alkalmazhassa varázslatait.',
|
||||
Tulajdonsag: [Tulajdonsag.Bolcsesseg],
|
||||
Osztalyok: [Osztaly.Varazslo, Osztaly.Illuzionista],
|
||||
},
|
||||
{
|
||||
Id: 'k_lovaglas',
|
||||
Name: 'Lovaglás',
|
||||
Description: 'A karakter kiemelkedően jól ért a lovagláshoz; harcban és nehéz helyzetekben is csodákra képes sarkallni hátasát.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_maszas',
|
||||
Name: 'Mászás',
|
||||
Description: 'A képzettség olyan falakra való felmászásra alkalmas, ami egy átlagembernek komol gondot jelentene. Sikertelen próba esetén a karakter lezuhan, vagy a feladat meghaladja a képességeit.',
|
||||
Tulajdonsag: [Tulajdonsag.Ero],
|
||||
},
|
||||
{
|
||||
Id: 'k_megfigyeles',
|
||||
Name: 'Megfigyelés',
|
||||
Description: 'Ez a képzettség olyan érzékelési képességet jelent, ami meghaladja az átlagemberét. Így olyan részletek vehetők észre, amelye szabad szemmel láthatóak, de csak az avatott megfigyelő számára.',
|
||||
Tulajdonsag: [Tulajdonsag.Bolcsesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_meregkeveres',
|
||||
Name: 'Méregkeverés',
|
||||
Description: 'A megfelelő eszközök és alapanyagok birtokában különféle mérgek készíthetők. Sikertelen próbadobás esetén a keverék hatástalan, vagy a méregkeverő veszélybe sodorja önmagát.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
{
|
||||
Id: 'k_mesterseg',
|
||||
Name: 'Mesterség',
|
||||
Description: 'A karakter járatos egy kiválasztott mesterségben – pl. kovácsolás, gyertyaöntés, adószedés, ötvösség. A kézügyességet igénylő mesterségekhez Ügyesség, a szellemi foglalkozásokhoz Intelligencia szükséges.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia, Tulajdonsag.Ugyesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_nyomkereses',
|
||||
Name: 'Nyomkeresés',
|
||||
Description: 'A karakter képes a nyomok követésére és hozzávetőleges azonosítására, vagyis megtudhatja, milyen régiek, miféle szerzet hagyta őket, milyen gyorsan haladt a nyomokat hagyó, stb.',
|
||||
Tulajdonsag: [Tulajdonsag.Bolcsesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_osonas',
|
||||
Name: 'Osonás',
|
||||
Description: 'Csöndes és általában viszonylag gyors mozgás.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_rejtozes',
|
||||
Name: 'Rejtőzés',
|
||||
Description: 'A képzettséget ismerő karakter olyan helyeken is elrejtőzhet, ahol más nem volna képes – például sötétebb sarkokban, árnyékokban.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
},
|
||||
{
|
||||
Id: 'k_szabadulomuveszet',
|
||||
Name: 'Szabadulóművészet',
|
||||
Description: 'A karakter képes kiszabadulni kötelékeiből és láncaiból.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
{
|
||||
Id: 'k_tudas',
|
||||
Name: 'Tudás',
|
||||
Description: 'A karakter járatos egy bizonyos tudományterületen. Számos példa lehetséges, a leggyakoribbak a Történelemismeret, Országismeret, Mágiaismeret (csak varázshasználók sajátíthatják el), Teológia, Vadonismeret és a Növényismeret.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia],
|
||||
},
|
||||
{
|
||||
Id: 'k_ugras',
|
||||
Name: 'Ugrás',
|
||||
Description: 'A karakter képes átugrani szélesebb vagy magasabb akadályokat is, és tompíthatja az esésből származó sebesüléseket. Ha a próba sikertelen, a karakter leesik.',
|
||||
Tulajdonsag: [Tulajdonsag.Ero],
|
||||
},
|
||||
{
|
||||
Id: 'k_uszas',
|
||||
Name: 'Úszás',
|
||||
Description: 'A karakter jól tud úszni, akár nehéz körülmények között (zajló vízben, megterhelten, stb.) is képes a felszínen maradni.',
|
||||
Tulajdonsag: [Tulajdonsag.Ero],
|
||||
},
|
||||
{
|
||||
Id: 'k_varazslatismeret',
|
||||
Name: 'Varázslatismeret',
|
||||
Description: 'A Mágiaismerettel ellentétben ez a képzettség nem a mágia elméletében, hanem a konkrét varázslatokban való ismereteket méri. Sikeres próbával a karakter azonosíthatja az elmondás alatt álló varázslatokat (NF= a mentődobás nehézsége), bizonyos mágikus effektusokat, csapdákat, stb.',
|
||||
Tulajdonsag: [Tulajdonsag.Intelligencia],
|
||||
Osztalyok: [Osztaly.Illuzionista, Osztaly.Varazslo],
|
||||
},
|
||||
{
|
||||
Id: 'k_zarnyitas',
|
||||
Name: 'Zárnyitás',
|
||||
Description: 'Tolvajszerszámok segítségével a karakter felnyithatja a különféle mechanikus zárakat. Sikertelen próba esetén nem képes az adott zár felnyitására – egészen addig, amíg új tapasztalatokat nem szerez (vagyis a következő szintlépéséig).',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
{
|
||||
Id: 'k_zsebmetszes',
|
||||
Name: 'Zsebmetszés',
|
||||
Description: 'Őrizetlenül hagyott vagy övön, zsebben található kisebb tárgyak észrevétlen eltulajdonítása. Ha a próba sikertelen, a karaktert észreveszik vagy legalábbis gyanút kelt.',
|
||||
Tulajdonsag: [Tulajdonsag.Ugyesseg],
|
||||
Osztalyok: [Osztaly.Tolvaj],
|
||||
},
|
||||
]
|
||||
|
||||
export const TolvajKepzettsegList = KepzettsegLista.filter(x => x.Osztalyok?.includes(Osztaly.Tolvaj))
|
||||
|
||||
export const Kepzettsegek: Record<KepzettsegId, Kepzettseg> =
|
||||
KepzettsegLista.reduce(
|
||||
(acc: Record<KepzettsegId, Kepzettseg>, k) => { acc[k.Id] = k; return acc; },
|
||||
{} as Record<KepzettsegId, Kepzettseg>);
|
||||
|
||||
export function AvailableKezpettsegList(osztaly: Osztaly): Kepzettseg[] {
|
||||
return KepzettsegLista.filter(k => k.Osztalyok == null || k.Osztalyok.includes(osztaly))
|
||||
}
|
||||
|
||||
export function GetNumberOfKepzettsegek(t_int: number, faj: Faj, max: number) {
|
||||
let numberOfKepzettseg = 3 + Modifier(t_int) + (faj === Faj.Ember ? 1 : 0)
|
||||
|
||||
if (numberOfKepzettseg < 1) {
|
||||
numberOfKepzettseg = 1
|
||||
console.log('Adjusted Number of Kepzetsegek = ', numberOfKepzettseg)
|
||||
}
|
||||
if (numberOfKepzettseg > max) {
|
||||
numberOfKepzettseg = max
|
||||
console.log('Adjusted Number of Kepzetsegek = ', numberOfKepzettseg)
|
||||
}
|
||||
return numberOfKepzettseg;
|
||||
}
|
||||
|
||||
export function SetDefaultTolvajKepzettsegek(karakter: Pick<KarakterInputs, 'osztaly' | 'tolvajKepzettsegek'>, changeTolvajKepzettsegek: (tolvajKepzettsegek?: KepzettsegId[]) => void) {
|
||||
if (karakter.osztaly !== Osztaly.Tolvaj && karakter.tolvajKepzettsegek != null) {
|
||||
changeTolvajKepzettsegek(undefined)
|
||||
}
|
||||
if (karakter.osztaly === Osztaly.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<KarakterInputs, 'osztaly' | 'faj' | 'kepzettsegek' | 'tolvajKepzettsegek'>) {
|
||||
const availableKepzettsegList = AvailableKezpettsegList(karakter.osztaly)
|
||||
return (n: number): Kepzettseg[] => {
|
||||
let available = [...availableKepzettsegList]
|
||||
if (n === 0) {
|
||||
if (karakter.faj === Faj.Eszaki) {
|
||||
return [Kepzettsegek.k_hajozas]
|
||||
}
|
||||
if (karakter.faj === Faj.Etuniai) {
|
||||
return [Kepzettsegek.k_lovaglas]
|
||||
}
|
||||
if (karakter.faj === Faj.Birodalmi && karakter.osztaly !== Osztaly.Tolvaj) {
|
||||
available = [Kepzettsegek.k_meregkeveres, Kepzettsegek.k_alkimia]
|
||||
}
|
||||
}
|
||||
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<KarakterInputs, '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]
|
||||
|
||||
let mustChangeKepzettsegek = false
|
||||
|
||||
const restrictedKepzettsegek = GetKepzettsegListaN(karakter)(0)
|
||||
if (kepzettsegek.length === 0) {
|
||||
if (restrictedKepzettsegek.length > 0) {
|
||||
kepzettsegek.push(restrictedKepzettsegek[0].Id)
|
||||
mustChangeKepzettsegek = true
|
||||
}
|
||||
} else {
|
||||
if (!restrictedKepzettsegek.includes(Kepzettsegek[kepzettsegek[0]])) {
|
||||
kepzettsegek[0] = restrictedKepzettsegek[0].Id
|
||||
mustChangeKepzettsegek = true
|
||||
}
|
||||
}
|
||||
|
||||
if (kepzettsegek.length < numberOfKepzettsegek) {
|
||||
for (let i = kepzettsegek.length; i < numberOfKepzettsegek; i++) {
|
||||
const kepzettsegLista = GetKepzettsegListaN({...karakter, kepzettsegek})(i)
|
||||
if (kepzettsegLista.length > 0) {
|
||||
kepzettsegek.push(kepzettsegLista[0].Id)
|
||||
}
|
||||
}
|
||||
mustChangeKepzettsegek = true
|
||||
}
|
||||
if (kepzettsegek.length > numberOfKepzettsegek){
|
||||
kepzettsegek = kepzettsegek.slice(0, numberOfKepzettsegek)
|
||||
mustChangeKepzettsegek = true
|
||||
}
|
||||
if (mustChangeKepzettsegek){
|
||||
changeKepzettsegek(kepzettsegek)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import {BaseHP} from "./masodlagos_ertekek";
|
||||
import {KarakterInputs} from "./karakter";
|
||||
import {GetFajDetails} from "./faj";
|
||||
import {Osztaly} from "./osztaly";
|
||||
import fegyverek from "./fegyver.json"
|
||||
import {AllowedFegyver} from "./allowed-fegyver";
|
||||
import {TulajdonsagokTotal} from "./tulajdonsag";
|
||||
import {dAny} from "../../shared/domain-models/kockak";
|
||||
import {TulajdonsagIDs} from "./tulajdonsag";
|
||||
|
||||
export function PickableSpecializationFilter(existingSpecilizations: string[], szint: number) {
|
||||
return (fegyver: {Id: string}) => existingSpecilizations.filter(x => x === fegyver.Id).length < (szint < 9 ? 1 : 2)
|
||||
}
|
||||
|
||||
export function LevelUp(karakter: KarakterInputs, changeKarakter: (input: KarakterInputs) => void) {
|
||||
const tulajdonsagokTotal = TulajdonsagokTotal(karakter)
|
||||
const szint = karakter.szint + 1
|
||||
const dice = BaseHP(karakter.osztaly)
|
||||
const roll = dAny(dice)
|
||||
const hpRolls = [...karakter.hpRolls, roll]
|
||||
console.log(`Level ${szint} HP roll on d${dice} is: ${roll}`)
|
||||
let tulajdonsagNovelesek = karakter.tulajdonsagNovelesek
|
||||
if (szint % 4 === 0) {
|
||||
for (const tulajdonsag of TulajdonsagIDs) {
|
||||
if (tulajdonsagokTotal[tulajdonsag] < 18) {
|
||||
tulajdonsagNovelesek = [...tulajdonsagNovelesek, tulajdonsag]
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
let harcosSpecializaciok = karakter.harcosSpecializaciok
|
||||
if(karakter.osztaly === Osztaly.Harcos && szint % 2 === 1) {
|
||||
const nextPickableFegyverId = fegyverek.data.filter(PickableSpecializationFilter(karakter.harcosSpecializaciok, karakter.szint))[0].Id
|
||||
harcosSpecializaciok = [...harcosSpecializaciok, nextPickableFegyverId]
|
||||
}
|
||||
let kalozKritikus = karakter.kalozKritikus
|
||||
if(karakter.osztaly === Osztaly.Kaloz && szint % 3 === 0) {
|
||||
const nextPickableFegyverId = AllowedFegyver(Osztaly.Kaloz, []).filter(PickableSpecializationFilter(karakter.kalozKritikus, szint))[0].Id
|
||||
kalozKritikus = [...kalozKritikus, nextPickableFegyverId]
|
||||
}
|
||||
changeKarakter({...karakter, szint, hpRolls, tulajdonsagNovelesek, harcosSpecializaciok, kalozKritikus})
|
||||
}
|
||||
|
||||
export function LevelDown(karakter: KarakterInputs, changeKarakter: (input: KarakterInputs) => void) {
|
||||
let tulajdonsagNovelesek = karakter.tulajdonsagNovelesek
|
||||
if (karakter.szint % 4 === 0) {
|
||||
tulajdonsagNovelesek = tulajdonsagNovelesek.slice(0, -1)
|
||||
}
|
||||
const szint = karakter.szint - 1
|
||||
const hpRolls = karakter.hpRolls.slice(0, -1)
|
||||
let harcosSpecializaciok = karakter.harcosSpecializaciok
|
||||
if (karakter.osztaly === Osztaly.Harcos && szint % 2 === 0) {
|
||||
harcosSpecializaciok = harcosSpecializaciok.slice(0, -1)
|
||||
}
|
||||
changeKarakter({...karakter, szint, hpRolls, tulajdonsagNovelesek, harcosSpecializaciok})
|
||||
}
|
||||
|
||||
export function CanLevelUp(karakter: Pick<KarakterInputs, 'szint' | 'faj' | 'osztaly'>): boolean {
|
||||
return karakter.szint < 10 && karakter.szint < GetFajDetails(karakter.faj).Szintkorlatok[karakter.osztaly]
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
import {Mentok, MentokTotal} from "./mentok";
|
||||
import {Osztaly} from "./osztaly";
|
||||
import {KarakterInputs} from "./karakter";
|
||||
import {CelzoTB, KozelharciTB} from "./tamadas_bonusz";
|
||||
import {Faj} from "./faj";
|
||||
import { GetPajzs, GetPancel, MaxAbilityVO } from "./felszereles";
|
||||
import {Modifier} from "./tulajdonsag";
|
||||
|
||||
export interface MasodlagosErtekekView {
|
||||
HP: number
|
||||
VO: number
|
||||
KozelharciTB: number[]
|
||||
CelzoTB: number[]
|
||||
Mentok: Mentok
|
||||
}
|
||||
|
||||
export type KarakterpickForMasodlagosErtekek = Pick<KarakterInputs, 'osztaly' | 'hpRolls' | 'tulajdonsagok' | 'szint' | 'faj' | 'felszereles'>
|
||||
|
||||
export function BaseHP(osztaly: Osztaly) {
|
||||
let base = 4;
|
||||
switch (osztaly){
|
||||
case Osztaly.Barbar:
|
||||
base = 12
|
||||
break;
|
||||
case Osztaly.Amazon:
|
||||
case Osztaly.Ijasz:
|
||||
case Osztaly.Kaloz:
|
||||
case Osztaly.Harcos:
|
||||
base = 10;
|
||||
break
|
||||
case Osztaly.Pap:
|
||||
base = 8;
|
||||
break;
|
||||
case Osztaly.Tolvaj:
|
||||
base = 6;
|
||||
break;
|
||||
case Osztaly.Varazslo:
|
||||
case Osztaly.Illuzionista:
|
||||
base = 4;
|
||||
break;
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
export function HP(karakter: Pick<KarakterInputs, 'osztaly' | 'tulajdonsagok' | 'hpRolls'>): number {
|
||||
const egeszsegModifier = Modifier(karakter.tulajdonsagok.t_egs)
|
||||
return BaseHP(karakter.osztaly) + egeszsegModifier + karakter.hpRolls
|
||||
// https://lfg.hu/forum/topic/15079-kard-es-magia/page/219/#comment-2218333
|
||||
.map(hp => Math.max(1, hp + egeszsegModifier))
|
||||
.reduce((sum, val) => sum + val, 0)
|
||||
}
|
||||
|
||||
export function VO(karakter: Pick<KarakterInputs, '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
|
||||
let vo = 10 + pajzsVO + pancelVO
|
||||
let abilityVO = Modifier(karakter.tulajdonsagok.t_ugy)
|
||||
if (karakter.osztaly === Osztaly.Kaloz) {
|
||||
vo += Math.floor(karakter.szint / 3)
|
||||
}
|
||||
if (karakter.osztaly === Osztaly.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 === Faj.Felszerzet){
|
||||
vo += 1
|
||||
}
|
||||
if (pancel) {
|
||||
abilityVO = Math.min(MaxAbilityVO(pancel.Type), abilityVO)
|
||||
}
|
||||
vo += abilityVO
|
||||
|
||||
return vo
|
||||
}
|
||||
|
||||
export function CalculateMasodlagosErtekek(karakter: KarakterpickForMasodlagosErtekek): MasodlagosErtekekView {
|
||||
return {
|
||||
HP: HP(karakter),
|
||||
VO: VO(karakter),
|
||||
CelzoTB: CelzoTB(karakter),
|
||||
KozelharciTB: KozelharciTB(karakter),
|
||||
Mentok: MentokTotal(karakter)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"varazslatok": [
|
||||
[3,1],
|
||||
[4,2],
|
||||
[4,2,1],
|
||||
[5,3,2],
|
||||
[5,3,2,1],
|
||||
[5,3,2,2],
|
||||
[6,4,3,2,1],
|
||||
[6,4,3,3,2],
|
||||
[6,4,4,3,2,1],
|
||||
[6,4,4,3,3,2],
|
||||
[7,5,4,4,3,2],
|
||||
[7,5,4,4,3,3],
|
||||
[7,5,5,4,4,3],
|
||||
[7,5,5,4,4,3],
|
||||
[7,5,5,5,4,4],
|
||||
[8,6,5,5,4,4],
|
||||
[8,6,5,5,5,4],
|
||||
[8,6,6,5,5,4],
|
||||
[8,6,6,5,5,5],
|
||||
[8,6,6,6,5,5]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import MemorizaltVarazslatTabla from "./memorizalt_varazslat_tabla.json";
|
||||
import {KarakterInputs} from "./karakter";
|
||||
import {Osztaly} from "./osztaly";
|
||||
import {Modifier} from "./tulajdonsag";
|
||||
|
||||
function isSpellcaster(osztaly: Osztaly): boolean {
|
||||
return osztaly === Osztaly.Pap || osztaly === Osztaly.Illuzionista || osztaly === Osztaly.Varazslo;
|
||||
}
|
||||
|
||||
function getMagicAbilityModifier(karakter: Pick<KarakterInputs, 'osztaly' | 'tulajdonsagok'>) : number {
|
||||
const magicAbility = karakter.osztaly === Osztaly.Pap ? karakter.tulajdonsagok.t_bol : karakter.tulajdonsagok.t_int
|
||||
return Modifier(magicAbility)
|
||||
}
|
||||
|
||||
export function NapiVarazslatok(karakter: Pick<KarakterInputs, 'szint' | 'osztaly' | 'tulajdonsagok'>) : number[] {
|
||||
if (!isSpellcaster(karakter.osztaly)) {
|
||||
return []
|
||||
}
|
||||
const magicAbilityModifier = getMagicAbilityModifier(karakter)
|
||||
const response = [...MemorizaltVarazslatTabla.varazslatok[karakter.szint-1]]
|
||||
for (let i = 1; i <= magicAbilityModifier && i < response.length; i++){
|
||||
response[i] += 1
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
export function CalculateVarazslatMentokNF(karakter: Pick<KarakterInputs, 'osztaly' | 'tulajdonsagok'>): number[] {
|
||||
if (!isSpellcaster(karakter.osztaly)) {
|
||||
return []
|
||||
}
|
||||
const magicAbilityModifier = getMagicAbilityModifier(karakter)
|
||||
const response = []
|
||||
for (let spellLevel = 0; spellLevel < 6; spellLevel++){
|
||||
const NF = 10 + spellLevel + magicAbilityModifier
|
||||
response.push(NF)
|
||||
}
|
||||
return response
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import {Osztaly} from "./osztaly";
|
||||
import {KarakterInputs} from "./karakter";
|
||||
import {KarakterTulajdonsagok, TulajdonsagModosito} from "./tulajdonsag";
|
||||
|
||||
export interface Mentok {
|
||||
kitartas: number
|
||||
reflex: number
|
||||
akaratero: number
|
||||
}
|
||||
export type MentoTipus = keyof Mentok
|
||||
|
||||
export function MentoTipusLabel(tipus: MentoTipus): string {
|
||||
switch (tipus) {
|
||||
case "akaratero":
|
||||
return "Akaraterő";
|
||||
case "kitartas":
|
||||
return "Kitartás";
|
||||
case "reflex":
|
||||
return "Reflex";
|
||||
}
|
||||
}
|
||||
|
||||
export function ElsodlegesMento(szint: number): number {
|
||||
return Math.min(Math.floor(2 + szint / 2), 10);
|
||||
}
|
||||
|
||||
export function MasodlagosMento(szint: number): number {
|
||||
return Math.floor(szint / 3)
|
||||
}
|
||||
|
||||
export function ElsodlegesMentok(osztaly: Osztaly) : MentoTipus[] {
|
||||
let t: MentoTipus[] = []
|
||||
switch (osztaly){
|
||||
case Osztaly.Barbar:
|
||||
case Osztaly.Amazon:
|
||||
case Osztaly.Ijasz:
|
||||
case Osztaly.Kaloz:
|
||||
case Osztaly.Harcos:
|
||||
t = ['kitartas'];
|
||||
break;
|
||||
case Osztaly.Pap:
|
||||
t = ['kitartas', 'akaratero'];
|
||||
break;
|
||||
case Osztaly.Tolvaj:
|
||||
t = ['reflex'];
|
||||
break;
|
||||
case Osztaly.Varazslo:
|
||||
case Osztaly.Illuzionista:
|
||||
t = ['akaratero']
|
||||
break;
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
export function MentokAlap(osztaly: Osztaly, szint: number = 1) {
|
||||
const elsodlegesek = ElsodlegesMentok(osztaly)
|
||||
return {
|
||||
kitartas: elsodlegesek.includes('kitartas') ? ElsodlegesMento(szint) : MasodlagosMento(szint),
|
||||
reflex: elsodlegesek.includes('reflex') ? ElsodlegesMento(szint) : MasodlagosMento(szint),
|
||||
akaratero: elsodlegesek.includes('akaratero') ? ElsodlegesMento(szint) : MasodlagosMento(szint),
|
||||
}
|
||||
}
|
||||
|
||||
export function MentoModositok(tulajdonsagModositok: KarakterTulajdonsagok) {
|
||||
return {
|
||||
kitartas: tulajdonsagModositok.t_egs,
|
||||
reflex: tulajdonsagModositok.t_ugy,
|
||||
akaratero: tulajdonsagModositok.t_bol,
|
||||
}
|
||||
}
|
||||
|
||||
export function MentokTotal(karakter: Pick<KarakterInputs, 'osztaly' | 'szint' | 'tulajdonsagok'>) {
|
||||
const alap = MentokAlap(karakter.osztaly, karakter.szint)
|
||||
const modositok = MentoModositok(TulajdonsagModosito(karakter.tulajdonsagok))
|
||||
return {
|
||||
kitartas: alap.kitartas + modositok.kitartas,
|
||||
reflex: alap.reflex + modositok.reflex,
|
||||
akaratero: alap.akaratero + modositok.akaratero,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
import {GetPancel, KarakterFelszereles} from "./felszereles";
|
||||
import {AllowedPancelTypes} from "./allowed-pancel-types";
|
||||
|
||||
export enum Osztaly {
|
||||
Harcos = 'o_harcos',
|
||||
Ijasz = 'o_ijasz',
|
||||
Amazon = 'o_amazon',
|
||||
Kaloz = 'o_kaloz',
|
||||
Barbar = 'o_barbar',
|
||||
Pap = 'o_pap',
|
||||
Tolvaj = 'o_tolvaj',
|
||||
Varazslo = 'o_varazslo',
|
||||
Illuzionista = 'o_illuzionista',
|
||||
}
|
||||
|
||||
export function SetFelszerelesForChangedOsztaly(o: Osztaly, felszereles: KarakterFelszereles, changeFelszereles: (f: KarakterFelszereles) => void) {
|
||||
const allowedPancelTypes = AllowedPancelTypes([o])
|
||||
const pancel = GetPancel(felszereles.pancelID)
|
||||
if (pancel && !allowedPancelTypes.includes(pancel.Type)) {
|
||||
changeFelszereles({...felszereles, pancelID: undefined})
|
||||
}
|
||||
if (allowedPancelTypes.length === 0 && !!felszereles.pajzsID){
|
||||
changeFelszereles({...felszereles, pajzsID: undefined})
|
||||
}
|
||||
}
|
||||
|
||||
export function OsztalyLabel(osztaly: Osztaly) : string {
|
||||
switch (osztaly) {
|
||||
case Osztaly.Amazon: return 'Amazon';
|
||||
case Osztaly.Barbar: return 'Barbár';
|
||||
case Osztaly.Pap: return 'Pap';
|
||||
case Osztaly.Illuzionista: return 'Illúzionista';
|
||||
case Osztaly.Varazslo: return 'Varázsló';
|
||||
case Osztaly.Harcos: return 'Harcos';
|
||||
case Osztaly.Ijasz: return 'Íjász';
|
||||
case Osztaly.Kaloz: return 'Tengerész/Kalóz';
|
||||
case Osztaly.Tolvaj: return 'Tolvaj'
|
||||
}
|
||||
}
|
||||
|
||||
export function OsztalyDescription(osztaly: Osztaly) : string {
|
||||
switch (osztaly) {
|
||||
case Osztaly.Harcos:
|
||||
case Osztaly.Amazon:
|
||||
case Osztaly.Barbar:
|
||||
case Osztaly.Ijasz:
|
||||
case Osztaly.Kaloz:
|
||||
return 'A harcosok a fegyverhasználat mesterei. Megállják a helyüket a közelharcban és a távolsági összecsapásokban is, s sokkal jobban viselik a sebesüléseket, mint más osztályok képviselői. Ez az osztály mind közül a leggyakoribb, de egyben a legváltozatosabb is – öt alosztállyal rendelkezik.';
|
||||
case Osztaly.Tolvaj:
|
||||
return 'A tolvajok a becstelen harc és a csöndes gyilkolás mesterei (közülük sokan alkalmaznak mérgeket – őket orgyilkosoknak nevezik). Harci képességeik és életerejük viszonylag gyenge, s nehezebb vértezeteket sem használhatnak. Ezért ha módjukban áll, nem szemtől szembe, hanem lesből támadnak áldozataikra, és ha ez nem sikerülne, gyorsan kereket oldanak. Emellett alvilági pályafutásuk során számos hasznos képzettségben válnak járatossá.';
|
||||
case Osztaly.Pap:
|
||||
return 'A papok az istenek militáns varázshasználó szolgái. Hitük parancsait minden körülmények között be kell tartaniuk, s bizonyos rendszerességgel áldozatokat kell bemutatniuk. A papok csak istenükkel azonos vagy attól legfeljebb eggyel különböző jelleműek lehetnek. A papok csak az istenük által kijelölt fegyvereket forgathatják, de szabadon válogathatnak a különféle vértek között.';
|
||||
case Osztaly.Varazslo:
|
||||
return 'A varázslók kiemelkedő szellemi fegyelmezettségük segítségével képesek a magasabb fokú mágikus erőket irányító varázsigék memorizálására és fölhasználására. Tudásukat varázskönyekben rögzítik, s mindent elkövetnek egy ismeretlen formula megszerzéséért. Többségüket a magabiztos önhittség és az alacsonyabb szellemi képeségűek megvetése jellemzi. A varázslók nem képesek _bármiféle_ páncélban varázsolni, és csak kevés fegyvertípus forgatásában járatosak.';
|
||||
case Osztaly.Illuzionista:
|
||||
return 'A varázslók kiemelkedő szellemi fegyelmezettségük segítségével képesek a magasabb fokú mágikus erőket irányító varázsigék memorizálására és fölhasználására. Tudásukat varázskönyekben rögzítik, s mindent elkövetnek egy ismeretlen formula megszerzéséért. Többségüket a magabiztos önhittség és az alacsonyabb szellemi képeségűek megvetése jellemzi. Az illuzionisták a mágia egy igen hasonló, de több lényeges területen eltérő fajtáját művelik. Lételemük a káprázat, a megtévesztés és mások elméjének befolyásolása – többségük hipnotizőr vagy ügyes manipulátor. Az illuzionista varázslatok csekélyebb pusztító erőt képviselnek, ellenben egy élelmes illuzionista kezében szinte bármire képesek – beleértve a közönséges varázslók egyes varázslatainak utánzását. Az illuzionisták nem képesek _bármiféle_ páncélban varázsolni, és csak kevés fegyvertípus forgatásában járatosak.';
|
||||
}
|
||||
}
|
||||
|
||||
export function OsztalyProperties(osztaly: Osztaly) : string[] {
|
||||
switch (osztaly) {
|
||||
case Osztaly.Harcos: return [
|
||||
'Támadásbónusz: Szint * 1',
|
||||
'Mentődobások: Kitartás az első, Reflex és Akaraterő a második oszlop szerint',
|
||||
'Fegyverhasználat: az egzotikus fegyvereken kívül bármilyen fegyvertípust használhatnak',
|
||||
'Páncélhasználat: bármilyen',
|
||||
'Hp: szintenként 1d10, 9. szint („Nagyúr”) fölött 3/szint',
|
||||
'Képzettségek: 3',
|
||||
]
|
||||
case Osztaly.Ijasz: return [
|
||||
'Támadásbónusz: Szint x 1',
|
||||
'Mentődobások: Kitartás az első, Reflex és Akaraterő a második oszlop szerint',
|
||||
'Fegyverhasználat: az egzotikus fegyvereken kívül bármilyen fegyvertípust használhatnak',
|
||||
'Páncélhasználat: nehéz vérteken kívül bármilyen',
|
||||
'Hp: szintenként 1d10, 9. szint („Nagyúr”) fölött 3/szint',
|
||||
'Képzettségek: 3',
|
||||
]
|
||||
case Osztaly.Amazon: return [
|
||||
'Támadásbónusz: Szint x 1',
|
||||
'Mentődobások: Kitartás az első, Reflex és Akaraterő a második oszlop szerint',
|
||||
'Fegyverhasználat: az egzotikus fegyvereken kívül bármilyen fegyvertípust használhatnak',
|
||||
'Páncélhasználat: láncing vagy könnyebb vértek',
|
||||
'Hp: szintenként 1d10, 9. szint („Nagyúr”) fölött 3/szint',
|
||||
'Képzettségek: 3',
|
||||
]
|
||||
case Osztaly.Kaloz: return [
|
||||
'Támadásbónusz: Szint x 1',
|
||||
'Mentődobások: Kitartás az első, Reflex és Akaraterő a második oszlop szerint',
|
||||
'Fegyverhasználat: az egzotikus fegyvereken kívül bármilyen fegyvertípust használhatnak',
|
||||
'Páncélhasználat: nehéz vérteken kívül bármilyen',
|
||||
'Hp: szintenként 1d10, 9. szint („Nagyúr”) fölött 3/szint',
|
||||
'Képzettségek: 3',
|
||||
]
|
||||
case Osztaly.Barbar: return [
|
||||
'Támadásbónusz: Szint x 1',
|
||||
'Mentődobások: Kitartás az első, Reflex és Akaraterő a második oszlop szerint',
|
||||
'Fegyverhasználat: az egzotikus fegyvereken kívül bármilyen fegyvertípust használhatnak',
|
||||
'Páncélhasználat: bármilyen',
|
||||
'Hp: szintenként 1d12, 9. szint („Nagyúr”) fölött 3/szint',
|
||||
'Képzettségek: 3',
|
||||
]
|
||||
case Osztaly.Pap: return [
|
||||
'Támadásbónusz: Szint x 2/3',
|
||||
'Mentődobás: Kitartás és Akaraterő az első, Reflex a második oszlop szerint',
|
||||
'Fegyverhasználat: csak buzogányokat, tőröket és istenük kijelölt fegyvereit használhatják',
|
||||
'Páncélhasználat: bármilyen',
|
||||
'Hp: szintenként 1d8, 9. szint („Főpap”) fölött 2/szint',
|
||||
'Képzettségek: 3',
|
||||
]
|
||||
case Osztaly.Tolvaj: return [
|
||||
'Támadásbónusz: Szint x 2/3',
|
||||
'Mentődobás: Reflex az első, Kitartás és Akaraterő a második oszlop szerint',
|
||||
'Fegyverhasználat: tőröket, dobótűket, parittyákat, számszeríjakat , rövidíjakat és egykezes kardokat használhatnak',
|
||||
'Páncélhasználat: csak könnyű',
|
||||
'Hp: szintenként 1d6, 9. szint („Mestertolvaj”) fölött 2/szint',
|
||||
'Képzettségek: 7 (ebből legalább 4 minden képpen a „tolvajképzettségek” listájáról); 9. és ezután minden páratlan szinten újabb, eddig akár tiltott képzettséget tanulhatnak meg.'
|
||||
]
|
||||
case Osztaly.Varazslo:
|
||||
case Osztaly.Illuzionista: return [
|
||||
'Támadásbónusz: Szint x 1/2',
|
||||
'Mentődobás: Akaraterő az első, Kitartás és Reflex a második oszlop szerint',
|
||||
'Fegyverhasználat: tőrt, botot, dobótűket, bunkót és parittyát használhatnak',
|
||||
'Páncélhasználat: nincs',
|
||||
'Hp: szintenként 1d4, 9. szint („Varázslónagyúr”) fölött 1/szint',
|
||||
'Képzettségek: 3'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
export interface Skill {
|
||||
Id: string
|
||||
Name: string,
|
||||
Description: string
|
||||
ExtendedDescription?: string[]
|
||||
}
|
||||
|
||||
export function OsztalySpecialSkills(osztaly: Osztaly) : Skill[] {
|
||||
switch (osztaly) {
|
||||
case Osztaly.Harcos: return [{
|
||||
Id: 's_harcos_harcos',
|
||||
Name: 'Harcos',
|
||||
Description: 'Speciális harci tapasztalatuknak köszönhetően minden páratlan szinten +2-t kapnak egy választott fegyvertípus (pl. csatabárd, hosszúkard, stb.) sebzésére. Ez fegyverenként csak egyszer választható, s arra is fölhasználható, hogy a harcos megtanulja egy egzotikus fegyver használatát, amire később specializálódhat is. 9. szinttől elérhető számukra a kettős specializáció: ezzel sebzésmódosítójukat az adott fegyverre +4-re emelhetik.'
|
||||
}
|
||||
]
|
||||
case Osztaly.Ijasz: return [
|
||||
{
|
||||
Id: 's_harcos_ijasz',
|
||||
Name: 'Íjász',
|
||||
Description: 'A távolsági harc mesterei. Íjak használatakor körönként eggyel többször támadhatnak. Értenek a visszacsapó íjak használatához is.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_ijasz_vert',
|
||||
Name: 'Kötelező mozgékonyság',
|
||||
Description: 'Az íjászok nem viselhetnek nehéz vérteket.'
|
||||
}
|
||||
]
|
||||
case Osztaly.Amazon: return [
|
||||
{
|
||||
Id: 's_harcos_amazon',
|
||||
Name: 'Amazon',
|
||||
Description: 'Az amazonok barbár népe szépségéről és a karizmatikus jelenlétre építő védekező harcmodoráról ismert.',
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_amazon_vert',
|
||||
Name: 'MMO vért',
|
||||
Description: 'Az amazonok csak láncinget vagy könnyebb vérteket viselhetnek, de VO-juk Szint/2-vel javul, továbbá Karizma- és Ügyességmódosítói közül a kedvezőbbet választhatják.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_amazon_csapatmunka',
|
||||
Name: 'Csapatmunka',
|
||||
Description: 'Ha kettő vagy több amazon együttesen harcol, VO-juk további 2 ponttal nő pszionikus képességeik miatt.'
|
||||
},
|
||||
]
|
||||
case Osztaly.Kaloz: return [
|
||||
{
|
||||
Id: 's_harcos_kaloz',
|
||||
Name: 'Tengerész/Kalóz',
|
||||
Description: 'A tengerészek a hajózás mesterei; kereskedők, tengeri rablók és rabszolgavadászok.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_kaloz_ugyes_huzas',
|
||||
Name: 'Ügyes húzás',
|
||||
Description: 'A kalózok és tengerészek ha magasabb, Ügyességbónuszukat adják hozzá közelharci támadásaikhoz.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_kaloz_vasmacska',
|
||||
Name: 'Vasmacska',
|
||||
Description: 'A kalózok és tengerészek nem viselhetnek nehéz vértezetet, de VO-juk könnyű vértben Szint/3-al javul.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_kaloz_kritikus',
|
||||
Name: 'Kritikus',
|
||||
Description: 'Minden harmadik szinten kiválaszthatnak egy fegyvert, amivel könnyebben okoznak kritikus sebesülést, tehát pl. csatabárddal 20 helyett 19-20-on, hosszúkarddal 19-20 helyett 18-20-on, szablyával 18-20 helyett 17-20-on, stb. Ez a képesség 9. szintig fegyverenként csak egyszer választható.'
|
||||
}]
|
||||
case Osztaly.Barbar: return [
|
||||
{
|
||||
Id: 's_harcos_barbar',
|
||||
Name: 'Barbár',
|
||||
Description: 'A barbár törzsek köré sorolhatók a pusztai és sivatagi nomádok, a déli dzsungelek emberevői és az északi tengermelléki rablók nemzetségei egyaránt.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_barbar_eletero',
|
||||
Name: 'Túlélő',
|
||||
Description: 'A barbárok 1d12-vel dobják a Hp-jüket, -5 Hp-ig öntudatuknál vannak és +1 bónuszt (10. szinttől +2, 15. szinttől +4) kapnak a mentődobásaikra.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_barbar_iras',
|
||||
Name: 'Írástudatlan',
|
||||
Description: 'Minden barbár írástudatlanul kezdi a játékot, de ha kell, később megtanulhatja a betűvetést.'
|
||||
}
|
||||
]
|
||||
case Osztaly.Pap: return [
|
||||
{
|
||||
Id: 's_pap_varazslat',
|
||||
Name: 'Varázslatok',
|
||||
Description: 'a papi varázslatok általában gyógyításra, mások megsegítésére és vallási feladatok ellátására szolgálnak. Minél magasabb szintűek, egy nap annál több varázslatot tudnak alkalmazni a következő oldalon található táblának megfelelően. Például egy 4. szintű, 17-es Bölcsességgel rendelkező pap öt nulladik szintű, négy első szintű és három második szintű varázslatot tarthat naponta elméjében.'
|
||||
},
|
||||
{
|
||||
Id: 's_pap_gyogyseb',
|
||||
Name: 'Gyógyítás vagy sebokozás',
|
||||
Description: 'a pap az aznap már memorizált (megtanult) varázslatokat gyógyításra vagy sebek okozására is fölhasználhatja. Érintésével a varázslat minden szintjéért 1d8 Hp-t gyógyít vagy sebez – így pl. egy Ómen elhasználásával 2d8 Hp-t. Az így konvertált varázslat természetesen elvész. Az, hogy a képesség sebek gyógyítására vagy okozására szolgál, a pap istenétől függ. A békésebb istenek főleg az elsőt, a harciasabbak főleg a másodikat részesítik előnyben, s vannak olyanok is, akik híveikre bízzák, hogy melyik utat választják. Ha azonban a pap már eldöntötte, melyik képességben járatos, döntését többé nem másíthatja meg!'
|
||||
},
|
||||
{
|
||||
Id: 's_pap_elohalott',
|
||||
Name: 'Élőholtak elűzése vagy irányítása',
|
||||
Description: 'A papok istenük dogmájának megfelelően képesek lehetnek arra, hogy élőholt szörnyeket (mint például zombikat, lidérceket vagy vámpírokat) szimbólumuk felmutatásával elűzzenek vagy szolgálatukba állítsanak. Ez a képesség naponta csak egyszer (5. szinttől kétszer, 10. szinttől háromszor, 15. szinttől négyszer) használható. A cselekedet a következőképpen működik:',
|
||||
ExtendedDescription: [
|
||||
'A pap [1d20+Kar bónusz] próbát tesz. Ennek az értékét összeveti a standard bónusztáblázattal. Az innen kiolvasható módosítót hozzáadja saját szintjéhez (ha negatív, akkor levonja). Az eredmény jelzi, hogy a pap legfeljebb milyen szintű élőholtakra lesz hatással. Ha tehát pl. a próba végeredménye 14 és a pap ötödik szintű, akkor 5+1, azaz 6. szintű a legerősebb élőhalott, amire a kísérlet sikeres. A 20-as dobás itt is automatikus siker, az 1-es automatikus kudarc.',
|
||||
'A pap [2d6+szint] szintű élőhalottat űzhet el vagy irányíthat. Először a leggyengébb élőholtakra hat, azután a következő leggyengébbekre, stb. Az elűzött élőholtak elmenekülnek a pap szeme elől és addig nem is ártanak neki és társainak, amíg a pap csapata meg nem támadja őket! Ezzel szemben a gonosz papok parancsokat adhatnak az irányított szörnyeknek. Mindkét hatás legfeljebb pár óráig tart, az élőholtak szintjétől és a körülményektől függően.',
|
||||
'Ha az összes szem előtt lévő élőholtat sikerült elűzni vagy irányítani és még maradt „a szent energiából”, akkor ismét el kell kezdeni a hatást a leggyengébb ellenségektől. Az így elűzött szörnyek megsemmisülnek, illetve irányítás esetén végleg a gonosz pap szolgálatába állnak.',
|
||||
'A két hatás egymás ellen is fölhasználható, például egy jó pap kiolthatja egy gonosz pap irányítását, de akár két gonosz pap is versenyezhet egy csapat sírlidérc „megtérítésén”.',
|
||||
]
|
||||
},
|
||||
{
|
||||
Id: 's_pap_invokacio',
|
||||
Name: 'Invokáció',
|
||||
Description: 'A pap kérheti istene segítségét (általában nevének kimondásával), ami +1-et, ritkábban +2-t ad hozzá dobásaihoz. A papok hetente annyiszor használhatják az invokációt, amekkora a Bölcsességbónuszuk (de legalább egyszer).'
|
||||
}
|
||||
]
|
||||
case Osztaly.Tolvaj: return [
|
||||
{
|
||||
Id: 's_tolvaj_orvtamadas',
|
||||
Name: 'Orvtámadás',
|
||||
Description: 'az orvtámadás akkor használható, ha a tolvaj meglepi áldozatát, tehát pl. csöndesen a hátába kerül, vagy beszélgetés közben tőrt ránt és egyetlen mozdulattal gyomron szúrja. Az orvtámadás minden páratlan szintért 1d6 bónusz sebzést okoz (maximuma +5d6). Dobó- és lőfegyverrel is használható, és ha a tolvaj úgy dönt, illetve a használt fegyver lehetővé teszi, az ellenfél elkábítására is alkalmazható.'
|
||||
},
|
||||
{
|
||||
Id: 's_tolvaj_kezdemenyezes',
|
||||
Name: 'Jobb kezdeményezés',
|
||||
Description: 'a tolvajok +4-et kapnak kezdeményezési dobásaikra.',
|
||||
},
|
||||
{
|
||||
Id: 's_tolvaj_kepzettsegek',
|
||||
Name: 'Tolvajképzettségek',
|
||||
Description: 'minden tolvaj jártas több olyan képzettségben, amely segíti a rejtőzködésben, a jól őrzött értékek eltulajdonításában és hasonló feladatokban. A tolvajok azokat a tolvajképzettségeket is használhatják, amelyekben nem járatosak külön, de ekkor szintjük nem számít bele a próbadobás módosítójába! A tolvajképzettségek listája: Álcázás, Csapdák állítása és eltávolítása, Egyensúlyozás, Értékbecslés, Hallgatózás, Hamisítás, Jelek olvasása, Keresés, Mászás, Megfigyelés, Méregkeverés, Osonás, Rejtőzés, Szabadulóművészet, Zárnyitás és Zsebmetszés.',
|
||||
},
|
||||
]
|
||||
case Osztaly.Varazslo: return [{
|
||||
Id: 's_varazslo_varazskonyv',
|
||||
Name: 'Varázskönyv',
|
||||
Description: 'egy első szintű varázsló varázskönyve 6 nulladik és 3 első szintű varázslatot tartalmaz, harmadik szintű kezdő karakteré ezen felül még 2 első szintűt és 2 második szintűt. Az újabb varázslatokat mások könyveiből, mágikus tekercsekből vagy más módszerek segítségével kell könyvébe másolnia. Az illuzionisták szintén varázskönyveket használnak, de eltérő mágiaformájuk miatt nem képesek a varázslói varázslatok megértésére – és viszont.'
|
||||
}]
|
||||
case Osztaly.Illuzionista: return [{
|
||||
Id: 's_illuzionista_varazskonyv',
|
||||
Name: 'Varázskönyv',
|
||||
Description: 'egy első szintű varázsló varázskönyve 6 nulladik és 3 első szintű varázslatot tartalmaz, harmadik szintű kezdő karakteré ezen felül még 2 első szintűt és 2 második szintűt. Az újabb varázslatokat mások könyveiből, mágikus tekercsekből vagy más módszerek segítségével kell könyvébe másolnia. Az illuzionisták szintén varázskönyveket használnak, de eltérő mágiaformájuk miatt nem képesek a varázslói varázslatok megértésére – és viszont.'
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"pajzs": [
|
||||
{
|
||||
"Id": "kis_fa",
|
||||
"Name": "Kis fapajzs ",
|
||||
"Type": "pajzs",
|
||||
"VO": 1,
|
||||
"Price": 3
|
||||
},
|
||||
{
|
||||
"Id": "kis_fem",
|
||||
"Name": "Kis fémpajzs ",
|
||||
"Type": "pajzs",
|
||||
"VO": 1,
|
||||
"Price": 9
|
||||
},
|
||||
{
|
||||
"Id": "nagy_fa",
|
||||
"Name": "Nagy fapajzs ",
|
||||
"Type": "pajzs",
|
||||
"VO": 2,
|
||||
"Price": 7
|
||||
},
|
||||
{
|
||||
"Id": "nagy_fem",
|
||||
"Name": "Nagy fémpajzs ",
|
||||
"Type": "pajzs",
|
||||
"VO": 2,
|
||||
"Price": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
{
|
||||
"pancel": [
|
||||
{
|
||||
"Id": "tomott",
|
||||
"Name": "Tömött páncél",
|
||||
"Type": "konnyu",
|
||||
"VO": 1,
|
||||
"Price": 4
|
||||
},
|
||||
{
|
||||
"Id": "bor",
|
||||
"Name": "Bőrvért",
|
||||
"Type": "konnyu",
|
||||
"VO": 2,
|
||||
"Price": 5
|
||||
},
|
||||
{
|
||||
"Id": "kivert_bor",
|
||||
"Name": "Kivert bőrvért",
|
||||
"Type": "konnyu",
|
||||
"VO": 3,
|
||||
"Price": 15
|
||||
},
|
||||
{
|
||||
"Id": "gyuruvert",
|
||||
"Name": "Gyűrűvért",
|
||||
"Type": "konnyu",
|
||||
"VO": 3,
|
||||
"Price": 20
|
||||
},
|
||||
{
|
||||
"Id": "lancing",
|
||||
"Name": "Láncing",
|
||||
"Type": "konnyu",
|
||||
"VO": 4,
|
||||
"Price": 50
|
||||
},
|
||||
{
|
||||
"Id": "pikkelyvert",
|
||||
"Name": "Pikkelyvért",
|
||||
"Type": "kozepes",
|
||||
"VO": 4,
|
||||
"Price": 30
|
||||
},
|
||||
{
|
||||
"Id": "lancvert",
|
||||
"Name": "Láncvért",
|
||||
"Type": "kozepes",
|
||||
"VO": 5,
|
||||
"Price": 75
|
||||
},
|
||||
{
|
||||
"Id": "mellvert",
|
||||
"Name": "Mellvért",
|
||||
"Type": "kozepes",
|
||||
"VO": 5,
|
||||
"Price": 100
|
||||
},
|
||||
{
|
||||
"Id": "racsvert",
|
||||
"Name": "Rácsvért",
|
||||
"Type": "nehez",
|
||||
"VO": 6,
|
||||
"Price": 200
|
||||
},
|
||||
{
|
||||
"Id": "szalagvert",
|
||||
"Name": "Szalagvért",
|
||||
"Type": "nehez",
|
||||
"VO": 6,
|
||||
"Price": 250
|
||||
},
|
||||
{
|
||||
"Id": "lemezvert",
|
||||
"Name": "Lemezvért",
|
||||
"Type": "nehez",
|
||||
"VO": 7,
|
||||
"Price": 400
|
||||
},
|
||||
{
|
||||
"Id": "teljes_lemezvert",
|
||||
"Name": "Teljes lemezvért",
|
||||
"Type": "nehez",
|
||||
"VO": 8,
|
||||
"Price": 800
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
{
|
||||
"elsodleges": [
|
||||
[1],
|
||||
[2],
|
||||
[3],
|
||||
[4],
|
||||
[5],
|
||||
[6,1],
|
||||
[7,2],
|
||||
[8,3],
|
||||
[9,4],
|
||||
[10,5],
|
||||
[10,6,1],
|
||||
[10,7,2],
|
||||
[10,8,3],
|
||||
[10,9,4],
|
||||
[10,10,5],
|
||||
[10,10,6],
|
||||
[10,10,7],
|
||||
[10,10,8],
|
||||
[10,10,9],
|
||||
[10,10,10]
|
||||
],
|
||||
"ketharmados": [
|
||||
[0],
|
||||
[1],
|
||||
[2],
|
||||
[2],
|
||||
[3],
|
||||
[4],
|
||||
[4],
|
||||
[5],
|
||||
[6,1],
|
||||
[6,1],
|
||||
[7,2],
|
||||
[8,3],
|
||||
[8,3],
|
||||
[9,4],
|
||||
[10,5],
|
||||
[10,5],
|
||||
[10,6],
|
||||
[10,7],
|
||||
[10,7],
|
||||
[10,8]
|
||||
],
|
||||
"feles": [
|
||||
[0],
|
||||
[1],
|
||||
[1],
|
||||
[2],
|
||||
[2],
|
||||
[3],
|
||||
[3],
|
||||
[4],
|
||||
[4],
|
||||
[5],
|
||||
[5],
|
||||
[6],
|
||||
[6],
|
||||
[7],
|
||||
[7],
|
||||
[8],
|
||||
[8],
|
||||
[9],
|
||||
[9],
|
||||
[10]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
import {Osztaly} from "./osztaly";
|
||||
import {CelzoTB, KozelharciTB, TamadasBonusz} from "./tamadas_bonusz";
|
||||
import {KarakterTulajdonsagok, Modifier} from "./tulajdonsag";
|
||||
|
||||
describe('Tamadas Bonusz calculation', () => {
|
||||
|
||||
describe('Base Tamadas Bonusz', () => {
|
||||
test.each([
|
||||
[Osztaly.Harcos, 1, [1]],
|
||||
[Osztaly.Amazon, 6, [6,1]],
|
||||
[Osztaly.Ijasz, 20, [10,10,10]],
|
||||
[Osztaly.Tolvaj, 1, [0]],
|
||||
[Osztaly.Tolvaj, 9, [6,1]],
|
||||
[Osztaly.Pap, 17, [10,6]],
|
||||
[Osztaly.Varazslo, 1, [0]],
|
||||
[Osztaly.Varazslo, 12, [6]],
|
||||
[Osztaly.Illuzionista, 20, [10]],
|
||||
])('%s has a TB of %i at level %i', (osztaly: Osztaly, szint: number, expectedTB: number[]) => {
|
||||
const actual = TamadasBonusz(osztaly, szint)
|
||||
expect(actual).toEqual(expectedTB)
|
||||
})
|
||||
});
|
||||
|
||||
describe('CelzoTB', () => {
|
||||
const szint = 10
|
||||
const tulajdonsagok: KarakterTulajdonsagok = {
|
||||
t_ugy: 17,
|
||||
t_kar: 3,
|
||||
t_bol: 3,
|
||||
t_egs: 3,
|
||||
t_ero: 3,
|
||||
t_int: 3,
|
||||
}
|
||||
const modifier = Modifier(tulajdonsagok.t_ugy)
|
||||
|
||||
it('should be equal base + ugyesseg modifier', () => {
|
||||
const osztaly = Osztaly.Tolvaj
|
||||
const base = TamadasBonusz(osztaly, szint)
|
||||
const expected = base.map(x => x + modifier)
|
||||
|
||||
const actual = CelzoTB({
|
||||
osztaly,
|
||||
szint,
|
||||
tulajdonsagok
|
||||
})
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
});
|
||||
it('should double the first base TB for Íjász', () => {
|
||||
const osztaly = Osztaly.Ijasz
|
||||
const base = TamadasBonusz(osztaly, szint)
|
||||
const ijaszDoubleBase = [base[0], ...base]
|
||||
const expected = ijaszDoubleBase.map(x => x + modifier)
|
||||
|
||||
const actual = CelzoTB({
|
||||
osztaly,
|
||||
szint,
|
||||
tulajdonsagok
|
||||
})
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
});
|
||||
});
|
||||
|
||||
describe('KozelharciTB', () => {
|
||||
const szint = 10
|
||||
const tulajdonsagok: KarakterTulajdonsagok = {
|
||||
t_ugy: 3,
|
||||
t_kar: 3,
|
||||
t_bol: 3,
|
||||
t_egs: 3,
|
||||
t_ero: 3,
|
||||
t_int: 3,
|
||||
}
|
||||
const modifier = Modifier(tulajdonsagok.t_ero)
|
||||
|
||||
it('should be equal base + ero modifier', () => {
|
||||
const osztaly = Osztaly.Tolvaj
|
||||
const base = TamadasBonusz(osztaly, szint)
|
||||
const expected = base.map(x => x + modifier)
|
||||
|
||||
const actual = KozelharciTB({
|
||||
osztaly,
|
||||
szint,
|
||||
tulajdonsagok
|
||||
})
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
});
|
||||
it('should use t_ugy for Kaloz if t_ugy > t_ero', () => {
|
||||
const osztaly = Osztaly.Kaloz
|
||||
const tulajdonsagok: KarakterTulajdonsagok = {
|
||||
t_ugy: 17,
|
||||
t_kar: 3,
|
||||
t_bol: 3,
|
||||
t_egs: 3,
|
||||
t_ero: 3,
|
||||
t_int: 3,
|
||||
}
|
||||
const modifier = Modifier(tulajdonsagok.t_ugy)
|
||||
const base = TamadasBonusz(osztaly, szint)
|
||||
const expected = base.map(x => x + modifier)
|
||||
|
||||
const actual = KozelharciTB({
|
||||
osztaly,
|
||||
szint,
|
||||
tulajdonsagok
|
||||
})
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
});
|
||||
it('should use t_ero for Kaloz if t_ero > t_ugy', () => {
|
||||
const osztaly = Osztaly.Kaloz
|
||||
const tulajdonsagok: KarakterTulajdonsagok = {
|
||||
t_ugy: 3,
|
||||
t_kar: 3,
|
||||
t_bol: 3,
|
||||
t_egs: 3,
|
||||
t_ero: 13,
|
||||
t_int: 3,
|
||||
}
|
||||
const modifier = Modifier(tulajdonsagok.t_ero)
|
||||
const base = TamadasBonusz(osztaly, szint)
|
||||
const expected = base.map(x => x + modifier)
|
||||
|
||||
const actual = KozelharciTB({
|
||||
osztaly,
|
||||
szint,
|
||||
tulajdonsagok
|
||||
})
|
||||
|
||||
expect(actual).toEqual(expected)
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
@@ -0,0 +1,42 @@
|
||||
import {Osztaly} from "./osztaly";
|
||||
import TamadasBonuszTabla from "./tamadas_bonus_tabla.json";
|
||||
import {KarakterInputs} from "./karakter";
|
||||
import {Modifier} from "./tulajdonsag";
|
||||
|
||||
export function TamadasBonusz(osztaly: Osztaly, szint: number = 1) : number[] {
|
||||
let base = []
|
||||
switch (osztaly){
|
||||
case Osztaly.Barbar:
|
||||
case Osztaly.Amazon:
|
||||
case Osztaly.Ijasz:
|
||||
case Osztaly.Kaloz:
|
||||
case Osztaly.Harcos:
|
||||
base = TamadasBonuszTabla['elsodleges'];
|
||||
break;
|
||||
case Osztaly.Pap:
|
||||
case Osztaly.Tolvaj:
|
||||
base = TamadasBonuszTabla['ketharmados'];
|
||||
break;
|
||||
case Osztaly.Varazslo:
|
||||
case Osztaly.Illuzionista:
|
||||
base = TamadasBonuszTabla['feles'];
|
||||
break;
|
||||
}
|
||||
return [...base[szint-1]]
|
||||
}
|
||||
|
||||
export function KozelharciTB(karakter : Pick<KarakterInputs, 'szint' | 'tulajdonsagok' | 'osztaly'>): number[] {
|
||||
const base = TamadasBonusz(karakter.osztaly, karakter.szint);
|
||||
let modifier = Modifier(karakter.tulajdonsagok.t_ero)
|
||||
if (karakter.osztaly === Osztaly.Kaloz && karakter.tulajdonsagok.t_ugy > karakter.tulajdonsagok.t_ero) {
|
||||
modifier = Modifier(karakter.tulajdonsagok.t_ugy)
|
||||
}
|
||||
return base.map(v => v + modifier)
|
||||
}
|
||||
export function CelzoTB(karakter : Pick<KarakterInputs, 'szint' | 'tulajdonsagok' | 'osztaly'>): number[] {
|
||||
let base = TamadasBonusz(karakter.osztaly, karakter.szint)
|
||||
if (karakter.osztaly === Osztaly.Ijasz) {
|
||||
base = [base[0], ...base]
|
||||
}
|
||||
return base.map(v => v + Modifier(karakter.tulajdonsagok.t_ugy))
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import {TulajdonsagokFajjal} from "./faj";
|
||||
import {KarakterInputs} from "./karakter";
|
||||
|
||||
import {d6} from "../../shared/domain-models/kockak";
|
||||
|
||||
export enum Tulajdonsag {
|
||||
Ero = 't_ero',
|
||||
Ugyesseg = 't_ugy',
|
||||
Egeszseg = 't_egs',
|
||||
Intelligencia = 't_int',
|
||||
Bolcsesseg = 't_bol',
|
||||
Karizma = 't_kar',
|
||||
}
|
||||
|
||||
export type KarakterTulajdonsagok = Record<Tulajdonsag, number>
|
||||
|
||||
export const TulajdonsagIDs = [
|
||||
Tulajdonsag.Ero,
|
||||
Tulajdonsag.Ugyesseg,
|
||||
Tulajdonsag.Egeszseg,
|
||||
Tulajdonsag.Intelligencia,
|
||||
Tulajdonsag.Bolcsesseg,
|
||||
Tulajdonsag.Karizma
|
||||
]
|
||||
|
||||
export const TulajdonsagDefaults: KarakterTulajdonsagok = {
|
||||
t_ero: 10,
|
||||
t_ugy: 10,
|
||||
t_egs: 10,
|
||||
t_int: 10,
|
||||
t_bol: 10,
|
||||
t_kar: 10,
|
||||
}
|
||||
|
||||
export function TulajdonsagLabel(tul: Tulajdonsag) : string {
|
||||
switch (tul) {
|
||||
case Tulajdonsag.Bolcsesseg: return 'Bölcsesség';
|
||||
case Tulajdonsag.Ero: return 'Erő';
|
||||
case Tulajdonsag.Ugyesseg: return 'Ügyesség';
|
||||
case Tulajdonsag.Egeszseg: return 'Egészség';
|
||||
case Tulajdonsag.Intelligencia: return 'Intelligencia';
|
||||
case Tulajdonsag.Karizma: return 'Karizma';
|
||||
}
|
||||
}
|
||||
|
||||
function rollAbility() {
|
||||
let min = 6;
|
||||
let sum = 0;
|
||||
let rolls: number[] = []
|
||||
for (let i = 0; i < 4; i++) {
|
||||
const roll = d6();
|
||||
if (roll < min) {
|
||||
min = roll;
|
||||
}
|
||||
sum += roll;
|
||||
rolls.push(roll)
|
||||
}
|
||||
const result = sum - min;
|
||||
console.log("Rolled: " + rolls + " got: " + result)
|
||||
return result;
|
||||
}
|
||||
|
||||
export function RollAllAbilities() : KarakterTulajdonsagok {
|
||||
const response = {...TulajdonsagDefaults}
|
||||
for (const key of TulajdonsagIDs) {
|
||||
response[key] = rollAbility()
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
export const Modifier = (val : number) => Math.floor(val / 3) - 3
|
||||
|
||||
export function TulajdonsagModosito(tulajdonsagok: KarakterTulajdonsagok): KarakterTulajdonsagok {
|
||||
let response: KarakterTulajdonsagok = { ...tulajdonsagok }
|
||||
for (const key of TulajdonsagIDs) {
|
||||
response[key] = Modifier(tulajdonsagok[key])
|
||||
}
|
||||
return response
|
||||
}
|
||||
|
||||
export function TulajdonsagokTotal(karakter: Pick<KarakterInputs, 'tulajdonsagok' | 'faj' | 'tulajdonsagNovelesek'>): KarakterTulajdonsagok {
|
||||
const response = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
|
||||
for (const tulajdonsag of karakter.tulajdonsagNovelesek) {
|
||||
// @ts-ignore // Trust me bro!
|
||||
response[tulajdonsag] += 1
|
||||
}
|
||||
return response
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
*.css
|
||||
@@ -0,0 +1,20 @@
|
||||
.form-field-error {
|
||||
display: block;
|
||||
color: #8c0000;
|
||||
}
|
||||
|
||||
form label {
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
/* Chrome, Safari, Edge, Opera */
|
||||
input::-webkit-outer-spin-button,
|
||||
input::-webkit-inner-spin-button {
|
||||
-webkit-appearance: none;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* Firefox */
|
||||
input[type=number] {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
import React, {useContext, useState} from 'react';
|
||||
import './CreateCharacter.css'
|
||||
import {Faj, TulajdonsagokFajjal} from "../domain-models/faj";
|
||||
import {Osztaly, SetFelszerelesForChangedOsztaly} from "../domain-models/osztaly"
|
||||
import FajSelector from "../components/FajSelector";
|
||||
import Tulajdonsagok from "../components/Tulajdonsagok";
|
||||
import OsztalySelector from "../components/OsztalySelector";
|
||||
import KarakterKepzettsegek from "../components/KarakterKepzettsegek";
|
||||
import MasodlagosErtekek from "../components/MasodlagosErtekek";
|
||||
import {
|
||||
AvailableKezpettsegList,
|
||||
GetKepzettsegListaN,
|
||||
GetNumberOfKepzettsegek,
|
||||
KepzettsegId,
|
||||
SetDefaultKepzettsegek,
|
||||
SetDefaultTolvajKepzettsegek,
|
||||
} from "../domain-models/kepzettsegek";
|
||||
import {CreatePDF} from "../pdf/character.pdf";
|
||||
import {KarakterDefaults, KarakterInputs} from "../domain-models/karakter";
|
||||
import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
|
||||
import {KarakterInputToPdfView} from "../pdf/karakter_pdf_view";
|
||||
import JellemSelector from "../components/JellemSelector";
|
||||
import {CanLevelUp, LevelDown, LevelUp} from "../domain-models/level";
|
||||
import {Button, Card, InputGroup, Modal, OverlayTrigger, Toast, ToastContainer} from "react-bootstrap";
|
||||
import Form from "react-bootstrap/Form";
|
||||
import LevelUps from "../components/LevelUps";
|
||||
import HarcosFegyverSpecializacio from "../components/HarcosFegyverSpecializacio";
|
||||
import Felszereles from '../components/Felszereles';
|
||||
import { KarakterFelszereles } from '../domain-models/felszereles';
|
||||
import {Faro} from "@grafana/faro-web-sdk";
|
||||
import {StoreNewCharacter, UpdateCharacter} from "../api/character.api";
|
||||
import {useLoaderData, useNavigate, useParams} from "react-router-dom";
|
||||
import saveOverlayTooltip from "../components/SaveOverlayTooltip";
|
||||
import {UserContext} from "../../shared/contexts/UserContext";
|
||||
import {KarakterTulajdonsagok} from "../domain-models/tulajdonsag";
|
||||
|
||||
function CreateCharacterPage(props: {
|
||||
faro?: Faro,
|
||||
}) {
|
||||
const {faro} = props
|
||||
|
||||
const loaderData = useLoaderData() as KarakterInputs & { isPublic: boolean } | undefined;
|
||||
let initialKarakterInputs = KarakterDefaults;
|
||||
if (loaderData != null) {
|
||||
const { isPublic: t1, ...t2 } = loaderData;
|
||||
initialKarakterInputs = t2
|
||||
}
|
||||
const { id } = useParams();
|
||||
const fetchedUser = useContext(UserContext);
|
||||
|
||||
const initialIsPublic = loaderData?.isPublic ?? fetchedUser?.data == null;
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
let [karakter, changeKarakter] = useState(initialKarakterInputs)
|
||||
|
||||
const tulajdonsagokFajjal = TulajdonsagokFajjal(karakter.tulajdonsagok, karakter.faj)
|
||||
|
||||
const changeKepzettseg = (k: KepzettsegId[]) => changeKarakter({...karakter, kepzettsegek: k})
|
||||
const changeTolvajKepzettseg = (tk?: KepzettsegId[]) => changeKarakter({...karakter, tolvajKepzettsegek: tk})
|
||||
SetDefaultTolvajKepzettsegek(karakter, changeTolvajKepzettseg)
|
||||
SetDefaultKepzettsegek({...karakter, tulajdonsagok: tulajdonsagokFajjal}, changeKepzettseg)
|
||||
const availableKepzettsegList = AvailableKezpettsegList(karakter.osztaly)
|
||||
const setFelszereles = (f: KarakterFelszereles) => changeKarakter({...karakter, felszereles: f})
|
||||
SetFelszerelesForChangedOsztaly(karakter.osztaly, karakter.felszereles, setFelszereles)
|
||||
|
||||
const levelUp = () => LevelUp(karakter, changeKarakter)
|
||||
const levelDown = () => LevelDown(karakter, changeKarakter)
|
||||
|
||||
const canLevelUp = CanLevelUp(karakter)
|
||||
|
||||
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}/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 onSaveClicked = async () => {
|
||||
faro?.api.pushEvent('character_stored', {
|
||||
osztaly: karakter.osztaly,
|
||||
szint: karakter.szint.toString(),
|
||||
faj: karakter.faj.toString(),
|
||||
is_public: isPublic.toString(),
|
||||
})
|
||||
if (id == null) {
|
||||
let recievedId = await StoreNewCharacter(karakter, isPublic);
|
||||
setNewId(recievedId)
|
||||
setShowSaveModal(true);
|
||||
} else {
|
||||
await UpdateCharacter(id, karakter, isPublic);
|
||||
setShowSaved(true);
|
||||
setTimeout(() => {
|
||||
hideSaved();
|
||||
}, 5000)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className='container-fluid p-5 bg-black text-white text-center'>
|
||||
<h1>Karakter {!!id ? "szerkesztése" : "létrehozása"}</h1>
|
||||
</div>
|
||||
<ToastContainer className="position-fixed" position="top-end">
|
||||
<Toast show={showSaved} onClose={hideSaved} bg="success">
|
||||
<Toast.Body className="text-light">Karakter mentve!</Toast.Body>
|
||||
</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'>
|
||||
<h5 className='col align-self-center'>Származás</h5>
|
||||
</div>
|
||||
<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.name}
|
||||
onChange={(e) => changeKarakter({...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'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Nem</label>
|
||||
<input className='col form-control'
|
||||
value={karakter.nem}
|
||||
onChange={(e) => changeKarakter({...karakter, nem: e.target.value})}/>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Kor</label>
|
||||
<input className='col form-control'
|
||||
value={karakter.kor}
|
||||
type={"number"}
|
||||
onChange={(e) => changeKarakter({...karakter, kor: Number(e.target.value)})}/>
|
||||
</div>
|
||||
<JellemSelector selected={karakter.jellem}
|
||||
changeJellem={(val) => changeKarakter({...karakter, jellem: val})}/>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Választott istenség</label>
|
||||
<input className='col form-control'
|
||||
value={karakter.isten}
|
||||
onChange={(e) => changeKarakter({...karakter, isten: e.target.value})}/>
|
||||
</div>
|
||||
<FajSelector
|
||||
changeFaj={(faj: Faj) => changeKarakter({...karakter, faj: faj})}
|
||||
faj={karakter.faj}
|
||||
/>
|
||||
<hr/>
|
||||
<Tulajdonsagok
|
||||
currentFaj={karakter.faj}
|
||||
tulajdonsagok={karakter.tulajdonsagok}
|
||||
changeTulajdonsagok={(tul: KarakterTulajdonsagok) => changeKarakter({
|
||||
...karakter,
|
||||
tulajdonsagok: tul
|
||||
})}
|
||||
/>
|
||||
<hr/>
|
||||
<div className='row'>
|
||||
<h5 className='col align-self-center'>Tanult</h5>
|
||||
</div>
|
||||
<OsztalySelector
|
||||
currentFaj={karakter.faj}
|
||||
currentOsztaly={karakter.osztaly}
|
||||
changeOsztaly={(o: Osztaly) =>
|
||||
changeKarakter({
|
||||
...karakter,
|
||||
osztaly: o,
|
||||
harcosSpecializaciok: (o === Osztaly.Harcos && karakter.harcosSpecializaciok.length === 0) ? ['hosszu_kard'] : karakter.harcosSpecializaciok,
|
||||
})}
|
||||
/>
|
||||
{karakter.osztaly === Osztaly.Harcos &&
|
||||
<div className='mb-6'>
|
||||
<HarcosFegyverSpecializacio
|
||||
specialization={karakter.harcosSpecializaciok[0]}
|
||||
existingSpecializations={karakter.harcosSpecializaciok}
|
||||
changeSpecialization={(spec: string) => changeKarakter({
|
||||
...karakter,
|
||||
harcosSpecializaciok: [spec, ...karakter.harcosSpecializaciok.slice(1)]
|
||||
})}
|
||||
szint={1}
|
||||
/>
|
||||
</div>}
|
||||
<KarakterKepzettsegek
|
||||
getKepzettsegListaN={GetKepzettsegListaN(karakter)}
|
||||
numberOfKepzettsegek={GetNumberOfKepzettsegek(tulajdonsagokFajjal.t_int, karakter.faj, availableKepzettsegList.length)}
|
||||
kepzettsegek={karakter.kepzettsegek}
|
||||
changeKepzettsegek={changeKepzettseg}
|
||||
tolvajKepzettsegek={karakter.tolvajKepzettsegek || []}
|
||||
changeTolvajKepzettsegek={changeTolvajKepzettseg}
|
||||
/>
|
||||
|
||||
<hr/>
|
||||
<MasodlagosErtekek {...CalculateMasodlagosErtekek({
|
||||
...karakter,
|
||||
tulajdonsagok: tulajdonsagokFajjal,
|
||||
szint: 1,
|
||||
hpRolls: []
|
||||
})} />
|
||||
|
||||
<hr/>
|
||||
|
||||
<LevelUps key={'level-ups'} karakter={karakter} changeKarakter={changeKarakter}/>
|
||||
|
||||
{karakter.szint > 1 && <hr/>}
|
||||
<div className='d-grid gap-2 m-5'>
|
||||
{canLevelUp &&
|
||||
<button className='btn btn-dark btn-lg' type='button' onClick={levelUp}>Szintlépés!
|
||||
⇧</button>}
|
||||
{!canLevelUp && karakter.szint < 10 &&
|
||||
<Card className='col text-center p-3'>Elérted a fajod szint limitjét</Card>}
|
||||
{karakter.szint > 1 &&
|
||||
<button className='btn btn-dark btn-lg' type='button' onClick={levelDown}>Visszalépés!
|
||||
⇩</button>}
|
||||
</div>
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
<Felszereles osztaly={karakter.osztaly} felszereles={karakter.felszereles}
|
||||
changeFelszereles={setFelszereles} harcosSpec={karakter.harcosSpecializaciok}/>
|
||||
|
||||
<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.osztaly,
|
||||
szint: karakter.szint.toString(),
|
||||
faj: karakter.faj.toString(),
|
||||
})
|
||||
await CreatePDF(KarakterInputToPdfView(karakter))
|
||||
}}>PDF
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default CreateCharacterPage;
|
||||
@@ -0,0 +1,89 @@
|
||||
import {KarakterPdfView, KepzettsegPdfView} from "./karakter_pdf_view";
|
||||
import {PDFDocument, rgb} from "pdf-lib";
|
||||
import fontkit from '@pdf-lib/fontkit'
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
import download from "downloadjs";
|
||||
import {DrawTulajdonsagok} from "./tulajdonsagok.pdf";
|
||||
import {DrawMentok} from "./mentok.pdf";
|
||||
import {DrawMagic} from "./magic.pdf";
|
||||
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 DrawKepzettsegek(draw: (text: string, x: number, y: number) => void, kepzettsegek: KepzettsegPdfView[], startFrom: number) {
|
||||
for (let i = 0; i < kepzettsegek.length; i++) {
|
||||
let kepzettseg = kepzettsegek[i]
|
||||
draw(kepzettseg.KepzettsegName, 60, startFrom - (i * 18))
|
||||
const kepzettsegModifier = SignedNumberToText(kepzettseg.KepzettsegModifier)
|
||||
draw(kepzettsegModifier, kepzettsegModifier.length > 2 ? 172 : 175, startFrom - (i * 18))
|
||||
}
|
||||
}
|
||||
|
||||
function DrawFelszereles(draw: (text: string, x: number, y:number) => void, felszereles: string[]) {
|
||||
const startFrom = 337
|
||||
for (let i = 0; i < felszereles.length; i++) {
|
||||
const item = felszereles[i];
|
||||
draw(item, 390, startFrom - (i * 18))
|
||||
}
|
||||
}
|
||||
|
||||
export async function CreatePDF(karakter: KarakterPdfView) {
|
||||
|
||||
const existingPdfBytes = await fetch('/pdfs/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 pdfFont = await pdfDoc.embedFont(fontBytes)
|
||||
const fontSizeBase = 12
|
||||
|
||||
const page = pdfDoc.getPage(0)
|
||||
|
||||
function drawText(text: string, x: number, y: number, fontScale = 1, shade = 0) {
|
||||
page.drawText(text, {
|
||||
x: x,
|
||||
y: y,
|
||||
size: fontSizeBase * fontScale,
|
||||
font: pdfFont,
|
||||
color: rgb(shade, shade, shade),
|
||||
})
|
||||
}
|
||||
|
||||
drawBaseInfo(karakter, drawText);
|
||||
|
||||
DrawTulajdonsagok(page, karakter.Tulajdonsagok, fontSizeBase, pdfFont);
|
||||
|
||||
DrawMasodlagosErtekek(page, karakter, fontSizeBase, pdfFont);
|
||||
|
||||
DrawMentok(page, karakter, fontSizeBase, pdfFont);
|
||||
|
||||
DrawKepzettsegek(drawText, karakter.Kepzettsegek, 337);
|
||||
const nextKepzettsegFrom = 337 - (karakter.Kepzettsegek.length * 18)
|
||||
DrawKepzettsegek(drawText, karakter.TolvajKepzettsegek, nextKepzettsegFrom)
|
||||
|
||||
DrawFelszereles(drawText, karakter.Felszereles)
|
||||
|
||||
DrawFegyverek(karakter, pdfFont, fontSizeBase, page)
|
||||
|
||||
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 fontBold = await pdfDoc.embedFont(fontBoldBytes)
|
||||
DrawOsztalySpecialsPage(secondPage, pdfFont, fontBold, karakter)
|
||||
|
||||
const pdfBytes = await pdfDoc.save();
|
||||
download(pdfBytes, karakter.Name + ".pdf", "application/pdf");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import {KarakterPdfView} from "./karakter_pdf_view";
|
||||
import {PDFFont, PDFPage} from "pdf-lib";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
|
||||
function fitTextInWidth(font: PDFFont, text: string, startingSize: number, maxWidth: number): number {
|
||||
let size = startingSize
|
||||
while(font.widthOfTextAtSize(text, size) > maxWidth) {
|
||||
size--
|
||||
}
|
||||
return size
|
||||
}
|
||||
|
||||
export function DrawFegyverek(karakter: KarakterPdfView, pdfFont: PDFFont, fontSizeBase: number, page: PDFPage) {
|
||||
const startFrom = 337
|
||||
for (let i = 0; i < karakter.Fegyverek.length && i < 3; i++) {
|
||||
const fegyver = karakter.Fegyverek[i];
|
||||
const size = fitTextInWidth(pdfFont, fegyver.Name, fontSizeBase, 60)
|
||||
page.drawText(fegyver.Name, {
|
||||
x: 200,
|
||||
y: startFrom - (i * 18) + ((18 - pdfFont.heightAtSize(size)) / 3),
|
||||
size: size,
|
||||
font: pdfFont,
|
||||
})
|
||||
page.drawText(SignedNumberToText(fegyver.TamadoBonusz), {
|
||||
x: 265,
|
||||
y: startFrom - (i * 18),
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
})
|
||||
const damageSize = fitTextInWidth(pdfFont, fegyver.Damage, fontSizeBase, 24)
|
||||
page.drawText(fegyver.Damage, {
|
||||
x: 291,
|
||||
y: startFrom - (i * 18) + ((18 - pdfFont.heightAtSize(damageSize)) / 3),
|
||||
size: damageSize,
|
||||
font: pdfFont,
|
||||
})
|
||||
const critSize = fitTextInWidth(pdfFont, fegyver.Crit, fontSizeBase, 35)
|
||||
page.drawText(fegyver.Crit, {
|
||||
x: 318,
|
||||
y: startFrom - (i * 18) + ((18 - pdfFont.heightAtSize(critSize)) / 3),
|
||||
size: critSize,
|
||||
font: pdfFont,
|
||||
})
|
||||
page.drawText(fegyver.Range, {
|
||||
x: 360,
|
||||
y: startFrom - (i * 18),
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
import {TulajdonsagokTotal} from "../domain-models/tulajdonsag";
|
||||
import {Mentok, MentokAlap, MentoModositok} from "../domain-models/mentok";
|
||||
import {Kepzettseg, Kepzettsegek} from "../domain-models/kepzettsegek";
|
||||
import {CalculateMasodlagosErtekek} from "../domain-models/masodlagos_ertekek";
|
||||
import {Faj, FajLabel} from "../domain-models/faj";
|
||||
import {Osztaly, OsztalyLabel, Skill} from "../domain-models/osztaly";
|
||||
import {CelzoTB, KozelharciTB} from "../domain-models/tamadas_bonusz";
|
||||
import {KarakterInputs} from "../domain-models/karakter";
|
||||
import {CalculateVarazslatMentokNF, NapiVarazslatok} from "../domain-models/memorizalt_varazslatok";
|
||||
import {GetJellem} from "../domain-models/jellem";
|
||||
import {Fegyver, GetFegyverek, GetPajzs, GetPancel} from '../domain-models/felszereles'
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
import {OsztalySkillsTordelt} from "./osztaly_skills";
|
||||
import {
|
||||
KarakterTulajdonsagok,
|
||||
Modifier,
|
||||
TulajdonsagModosito
|
||||
} from "../domain-models/tulajdonsag";
|
||||
|
||||
export interface KepzettsegPdfView {
|
||||
KepzettsegName: string
|
||||
KepzettsegModifier: number
|
||||
}
|
||||
|
||||
export interface FegyverPdfView {
|
||||
Name: string
|
||||
TamadoBonusz: number
|
||||
Damage: string
|
||||
Crit: string
|
||||
Range: string
|
||||
}
|
||||
|
||||
export interface KarakterPdfView {
|
||||
Name: string
|
||||
Nem: string
|
||||
Kor: number
|
||||
Isten: string
|
||||
Jellem: string
|
||||
Faj: string
|
||||
Osztaly: string
|
||||
OsztalySkills: Skill[],
|
||||
Tulajdonsagok: KarakterTulajdonsagok,
|
||||
TulajdonsagModositok: KarakterTulajdonsagok,
|
||||
Szint: string
|
||||
HP: number
|
||||
VO: number
|
||||
Mozgas: number
|
||||
Kezdemenyezes: number
|
||||
KozelharciTB: number[]
|
||||
CelzoTB: number[]
|
||||
MentokAlap: Mentok
|
||||
MentoModositok: Mentok
|
||||
MentokModositokkal: Mentok
|
||||
Kepzettsegek: KepzettsegPdfView[]
|
||||
TolvajKepzettsegek: KepzettsegPdfView[]
|
||||
NapiMemorizalhatoVarazslatok: number[]
|
||||
VarazslatMentokNF : number[]
|
||||
Felszereles: string[]
|
||||
PancelVO: number
|
||||
PajzsVO: number
|
||||
Fegyverek: FegyverPdfView[]
|
||||
}
|
||||
|
||||
export function KarakterInputToPdfView(karakter: KarakterInputs): 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 mozgas = karakter.faj === Faj.Torpe || pancel?.Type === 'nehez' || pancel?.Type === 'kozepes' ? 20 : 30
|
||||
const kezdemenyezes = tulajdonsagModositok.t_ugy + (karakter.osztaly === Osztaly.Tolvaj ? 4 : 0)
|
||||
|
||||
const mentok = MentokAlap(karakter.osztaly, karakter.szint)
|
||||
const mentoModositok = MentoModositok(tulajdonsagModositok)
|
||||
|
||||
const NapiMemorizalhatoVarazslatok = NapiVarazslatok(karakter)
|
||||
const VarazslatMentokNF = CalculateVarazslatMentokNF(karakter)
|
||||
const fegyverek = GetFegyverek(karakter.felszereles.fegyverIDk)
|
||||
|
||||
const felszereles = [ pancel?.Name, pajzs?.Name, ...fegyverek.filter(f => f.Id !== 'okol').map(f => f.Name.includes('és') ? f.Name.split(' ')[0] : f.Name) ].filter(x => !!x) as string[]
|
||||
|
||||
return {
|
||||
Faj: FajLabel(karakter.faj),
|
||||
Isten: karakter.isten || "",
|
||||
Jellem: GetJellem(karakter.jellem).Label,
|
||||
Kor: karakter.kor,
|
||||
Name: karakter.name,
|
||||
Nem: karakter.nem || "",
|
||||
Tulajdonsagok: karakter.tulajdonsagok,
|
||||
Osztaly: OsztalyLabel(karakter.osztaly),
|
||||
OsztalySkills: OsztalySkillsTordelt(karakter.osztaly),
|
||||
Szint: karakter.szint.toString(),
|
||||
Kepzettsegek: karakter.kepzettsegek.map(id => mapKepzettsegToPdfView(Kepzettsegek[id], tulajdonsagok, karakter.szint)),
|
||||
TolvajKepzettsegek: karakter.tolvajKepzettsegek?.map(id => mapKepzettsegToPdfView(Kepzettsegek[id], tulajdonsagok, karakter.szint)) || [],
|
||||
TulajdonsagModositok: tulajdonsagModositok,
|
||||
|
||||
HP: masodlagosErtekek.HP,
|
||||
VO: masodlagosErtekek.VO,
|
||||
Mozgas: mozgas,
|
||||
Kezdemenyezes: kezdemenyezes,
|
||||
KozelharciTB: KozelharciTB(karakter),
|
||||
CelzoTB: CelzoTB(karakter),
|
||||
|
||||
MentoModositok: mentoModositok,
|
||||
MentokAlap: mentok,
|
||||
MentokModositokkal: masodlagosErtekek.Mentok,
|
||||
|
||||
NapiMemorizalhatoVarazslatok,
|
||||
VarazslatMentokNF,
|
||||
Felszereles: felszereles,
|
||||
PajzsVO: pajzs?.VO ?? 0,
|
||||
PancelVO: pancel?.VO ?? 0,
|
||||
Fegyverek: fegyverek.map(mapFegyverToPdfView(karakter)),
|
||||
}
|
||||
}
|
||||
|
||||
function mapKepzettsegToPdfView(kepzettseg: Kepzettseg, tulajdonsagok: KarakterTulajdonsagok, szint: number) {
|
||||
const tulajdonsagErtek = kepzettseg.Tulajdonsag.reduce((maxTulajdonsagErtek, currentTulajdonsag) =>
|
||||
tulajdonsagok[currentTulajdonsag] > maxTulajdonsagErtek
|
||||
? tulajdonsagok[currentTulajdonsag]
|
||||
: maxTulajdonsagErtek,
|
||||
tulajdonsagok[kepzettseg.Tulajdonsag[0]])
|
||||
|
||||
const modifier = Modifier(tulajdonsagErtek) + szint
|
||||
return {
|
||||
KepzettsegName: kepzettseg.Name,
|
||||
KepzettsegModifier: modifier,
|
||||
}
|
||||
}
|
||||
|
||||
function mapFegyverToPdfView(karakter: KarakterInputs) {
|
||||
return (fegyver: Fegyver): FegyverPdfView => {
|
||||
const simplifiedName = fegyver.Name.includes('és') ? fegyver.Name.split(' ')[0] : fegyver.Name
|
||||
const tb = fegyver.Type === 'kozelharci' ? KozelharciTB(karakter)[0] : CelzoTB(karakter)[0]
|
||||
const tulajdonsagModositok = TulajdonsagModosito(TulajdonsagokTotal(karakter))
|
||||
let damageModifier = fegyver.Type === 'kozelharci' || (fegyver.Id === 'visszacsapo_ij' && tulajdonsagModositok.t_ero > 0) ? tulajdonsagModositok.t_ero : 0
|
||||
damageModifier += karakter.harcosSpecializaciok.filter(x => x === fegyver.Id).length * 2
|
||||
if (fegyver.Id === 'visszacsapo_ij' && tulajdonsagModositok.t_ero > 0) { // "hozzaadhato", so only add if positive
|
||||
damageModifier += tulajdonsagModositok.t_ero
|
||||
}
|
||||
if (fegyver.Ketkezes) {
|
||||
damageModifier += Math.floor(tulajdonsagModositok.t_ero / 2)
|
||||
}
|
||||
const damage = `${fegyver.NumberOfDamageDice > 1 ? fegyver.NumberOfDamageDice.toString() : ''}d${fegyver.DamageDice}${damageModifier !== 0 ? SignedNumberToText(damageModifier) : ''}`
|
||||
const critStart = fegyver.CritRangeStart - karakter.kalozKritikus.filter(x => x === fegyver.Id).length
|
||||
const crit = `${critStart < 20 ? `${critStart}-20` : '20'} x${fegyver.CritMultiplier}`
|
||||
const range = fegyver.Range === 0 ? '-' : fegyver.Range.toString()
|
||||
return {
|
||||
Name: simplifiedName,
|
||||
TamadoBonusz: tb,
|
||||
Damage: damage,
|
||||
Crit: crit,
|
||||
Range: range,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
import {PDFFont, PDFPage, rgb} from "pdf-lib";
|
||||
|
||||
export function DrawMagic(page: PDFPage, fontSizeBase: number, pdfFont: PDFFont, napiVarazslatok: number[], varazsMentokNF: number[]){
|
||||
for(let i = 0; i < 6; i++) {
|
||||
const y = 247 - (i*18)
|
||||
page.drawText(i.toString(), {
|
||||
x: 210,
|
||||
y: y,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
if (i < napiVarazslatok.length) {
|
||||
page.drawText(napiVarazslatok[i].toString(), {
|
||||
x: 242,
|
||||
y: y,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(varazsMentokNF[i].toString(), {
|
||||
x: 269,
|
||||
y: y,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import {PDFFont, PDFPage} from "pdf-lib";
|
||||
import {KarakterPdfView} from "./karakter_pdf_view";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
|
||||
export function DrawMasodlagosErtekek(
|
||||
page: PDFPage,
|
||||
karakter: KarakterPdfView,
|
||||
fontSizeBase: number,
|
||||
pdfFont: PDFFont)
|
||||
{
|
||||
page.drawText(karakter.Mozgas.toString(), {
|
||||
x: 162,
|
||||
y: 416,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
})
|
||||
page.drawText(SignedNumberToText(karakter.Kezdemenyezes), {
|
||||
x: 505,
|
||||
y: 416,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
})
|
||||
page.drawText(karakter.HP.toString(), {
|
||||
x: 318,
|
||||
y: 517,
|
||||
size: fontSizeBase * 1.5,
|
||||
font: pdfFont,
|
||||
})
|
||||
page.drawText(karakter.VO.toString(), {
|
||||
x: 368,
|
||||
y: 495,
|
||||
size: fontSizeBase * 3,
|
||||
font: pdfFont,
|
||||
})
|
||||
page.drawText(karakter.PancelVO.toString(), {
|
||||
x: 512,
|
||||
y: 515,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
})
|
||||
page.drawText(karakter.PajzsVO.toString(), {
|
||||
x: 512,
|
||||
y: 482,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
})
|
||||
const kozelharciTB = karakter.KozelharciTB.map(SignedNumberToText).join("/")
|
||||
|
||||
function getFontSize(length: number): number {
|
||||
switch (length) {
|
||||
case 1:
|
||||
case 2:
|
||||
return 24;
|
||||
case 3:
|
||||
return 18;
|
||||
case 4:
|
||||
return 14;
|
||||
case 5:
|
||||
return 11;
|
||||
case 6:
|
||||
return 9;
|
||||
case 7:
|
||||
return 8;
|
||||
default:
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
|
||||
function getYOffset(length: number): number {
|
||||
return Math.min(length - 2, 6);
|
||||
}
|
||||
|
||||
const kozelHarciFontSize = getFontSize(kozelharciTB.length)
|
||||
page.drawText(kozelharciTB, {
|
||||
x: kozelharciTB.length > 4 ? 256 : 258,
|
||||
y: 383 + getYOffset(kozelharciTB.length),
|
||||
size: kozelHarciFontSize,
|
||||
font: pdfFont,
|
||||
})
|
||||
const celzoTB = karakter.CelzoTB.map(SignedNumberToText).join("/")
|
||||
const celzoFontSize = getFontSize(celzoTB.length)
|
||||
page.drawText(celzoTB, {
|
||||
x: celzoTB.length > 4 ? 343 : 346,
|
||||
y: 383 + getYOffset(celzoTB.length),
|
||||
size: celzoFontSize,
|
||||
font: pdfFont,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
import {PDFFont, PDFPage, rgb} from "pdf-lib";
|
||||
import {KarakterPdfView} from "./karakter_pdf_view";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
import {Modifier} from "../domain-models/tulajdonsag";
|
||||
|
||||
export function DrawMentok(page: PDFPage, karakter: KarakterPdfView, fontSizeBase: number, pdfFont: PDFFont) {
|
||||
const mentokAlap = karakter.MentokAlap
|
||||
page.drawText(SignedNumberToText(mentokAlap.kitartas), {
|
||||
x: 435,
|
||||
y: 613,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(mentokAlap.reflex), {
|
||||
x: 435,
|
||||
y: 580,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(mentokAlap.akaratero), {
|
||||
x: 435,
|
||||
y: 547,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(karakter.Tulajdonsagok.t_egs)), {
|
||||
x: 475,
|
||||
y: 613,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(karakter.Tulajdonsagok.t_ugy)), {
|
||||
x: 475,
|
||||
y: 580,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(karakter.Tulajdonsagok.t_bol)), {
|
||||
x: 475,
|
||||
y: 547,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
const mentok = karakter.MentokModositokkal
|
||||
page.drawText(SignedNumberToText(mentok.kitartas), {
|
||||
x: 515,
|
||||
y: 613,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(mentok.reflex), {
|
||||
x: 515,
|
||||
y: 580,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(mentok.akaratero), {
|
||||
x: 515,
|
||||
y: 547,
|
||||
size: fontSizeBase,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
import {Osztaly, Skill} from "../domain-models/osztaly";
|
||||
|
||||
export function OsztalySkillsTordelt(osztaly: Osztaly) : Skill[] {
|
||||
switch (osztaly) {
|
||||
case Osztaly.Harcos: return [{
|
||||
Id: 's_harcos_harcos',
|
||||
Name: 'Harcos',
|
||||
Description: 'Speciális harci tapasztalatuknak köszönhetően minden páratlan szinten +2-t kapnak egy\n' +
|
||||
'választott fegyvertípus (pl. csatabárd, hosszúkard, stb.) sebzésére. Ez fegyverenként csak\n' +
|
||||
'egyszer választható, s arra is fölhasználható, hogy a harcos megtanulja egy egzotikus\n' +
|
||||
'fegyver használatát, amire később specializálódhat is. 9. szinttől elérhető számukra a\n' +
|
||||
'kettős specializáció: ezzel sebzésmódosítójukat az adott fegyverre +4-re emelhetik.'
|
||||
}]
|
||||
case Osztaly.Ijasz: return [
|
||||
{
|
||||
Id: 's_harcos_ijasz',
|
||||
Name: 'Íjász',
|
||||
Description: 'Íjak használatakor körönként eggyel többször támadhatnak.\n' +
|
||||
'Értenek a visszacsapó íjak használatához is.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_ijasz_vert',
|
||||
Name: 'Kötelező mozgékonyság',
|
||||
Description: 'Az íjászok nem viselhetnek nehéz vérteket.'
|
||||
}
|
||||
]
|
||||
case Osztaly.Amazon: return [
|
||||
{
|
||||
Id: 's_harcos_amazon_vert',
|
||||
Name: 'MMO vért',
|
||||
Description:
|
||||
'Az amazonok csak láncinget vagy könnyebb vérteket viselhetnek, de VO-juk Szint/2-vel\n' +
|
||||
'javul, továbbá Karizma- és Ügyességmódosítói közül a kedvezőbbet választhatják.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_amazon_csapatmunka',
|
||||
Name: 'Csapatmunka',
|
||||
Description: 'Ha kettő vagy több amazon együttesen harcol, VO-juk további 2 ponttal nő pszionikus\n' +
|
||||
'képességeik miatt.'
|
||||
},
|
||||
]
|
||||
case Osztaly.Kaloz: return [
|
||||
{
|
||||
Id: 's_harcos_kaloz_ugyes_huzas',
|
||||
Name: 'Ügyes húzás',
|
||||
Description: 'A kalózok és tengerészek ha magasabb, Ügyességbónuszukat adják hozzá közelharci\n' +
|
||||
'támadásaikhoz.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_kaloz_vasmacska',
|
||||
Name: 'Vasmacska',
|
||||
Description: 'A kalózok és tengerészek nem viselhetnek nehéz vértezetet, de VO-juk könnyű vértben\n' +
|
||||
'Szint/3-al javul.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_kaloz_kritikus',
|
||||
Name: 'Kritikus',
|
||||
Description: 'Minden harmadik szinten kiválaszthatnak egy fegyvert, amivel könnyebben okoznak\n' +
|
||||
'kritikus sebesülést, tehát pl. csatabárddal 20 helyett 19-20-on, hosszúkarddal 19-20\n' +
|
||||
'helyett 18-20-on, szablyával 18-20 helyett 17-20-on, stb. Ez a képesség 9. szintig\n' +
|
||||
'fegyverenként csak egyszer választható.'
|
||||
}]
|
||||
case Osztaly.Barbar: return [
|
||||
{
|
||||
Id: 's_harcos_barbar_eletero',
|
||||
Name: 'Túlélő',
|
||||
Description: 'A barbárok 1d12-vel dobják a Hp-jüket, -5 Hp-ig öntudatuknál vannak és\n' +
|
||||
'+1 bónuszt (10. szinttől +2, 15. szinttől +4) kapnak a mentődobásaikra.'
|
||||
},
|
||||
{
|
||||
Id: 's_harcos_barbar_iras',
|
||||
Name: 'Írástudatlan',
|
||||
Description: 'Minden barbár írástudatlanul kezdi a játékot, de ha kell,\n' +
|
||||
'később megtanulhatja a betűvetést.'
|
||||
}
|
||||
]
|
||||
case Osztaly.Pap: return [
|
||||
{
|
||||
Id: 's_pap_gyogyseb',
|
||||
Name: 'Gyógyítás vagy sebokozás',
|
||||
Description:
|
||||
'A pap az aznap már memorizált (megtanult) varázslatokat gyógyításra vagy sebek\n' +
|
||||
'okozására is fölhasználhatja. Érintésével a varázslat minden szintjéért 1d8 Hp-t gyógyít\n' +
|
||||
'vagy sebez – így pl. egy Ómen elhasználásával 2d8 Hp-t. Az így konvertált varázslat\n' +
|
||||
'természetesen elvész. Az, hogy a képesség sebek gyógyítására vagy okozására szolgál, a\n' +
|
||||
'pap istenétől függ. A békésebb istenek főleg az elsőt, a harciasabbak főleg a másodikat\n' +
|
||||
'részesítik előnyben, s vannak olyanok is, akik híveikre bízzák, hogy melyik utat választják.\n' +
|
||||
'Ha azonban a pap már eldöntötte, melyik képességben járatos, döntését többé nem\n' +
|
||||
'másíthatja meg!'
|
||||
},
|
||||
{
|
||||
Id: 's_pap_elohalott',
|
||||
Name: 'Élőholtak elűzése vagy irányítása',
|
||||
Description:
|
||||
'A papok istenük dogmájának megfelelően képesek lehetnek arra, hogy élőholt szörnyeket\n' +
|
||||
'(mint például zombikat, lidérceket vagy vámpírokat) szimbólumuk felmutatásával\n' +
|
||||
'elűzzenek vagy szolgálatukba állítsanak. Ez a képesség naponta csak egyszer (5. szinttől\n' +
|
||||
'kétszer, 10. szinttől háromszor, 15. szinttől négyszer) használható. A cselekedet a\n' +
|
||||
'következő módon működik:',
|
||||
ExtendedDescription: [
|
||||
'A pap [1d20+Kar bónusz] próbát tesz. Ennek az értékét összeveti a standard bónusztáblázattal. Az innen kiolvasható módosítót hozzáadja saját szintjéhez (ha negatív, akkor levonja). Az eredmény jelzi, hogy a pap legfeljebb milyen szintű élőholtakra lesz hatással. Ha tehát pl. a próba végeredménye 14 és a pap ötödik szintű, akkor 5+1, azaz 6. szintű a legerősebb élőhalott, amire a kísérlet sikeres. A 20-as dobás itt is automatikus siker, az 1-es automatikus kudarc.',
|
||||
'A pap [2d6+szint] szintű élőhalottat űzhet el vagy irányíthat. Először a leggyengébb élőholtakra hat, azután a következő leggyengébbekre, stb. Az elűzött élőholtak elmenekülnek a pap szeme elől és addig nem is ártanak neki és társainak, amíg a pap csapata meg nem támadja őket! Ezzel szemben a gonosz papok parancsokat adhatnak az irányított szörnyeknek. Mindkét hatás legfeljebb pár óráig tart, az élőholtak szintjétől és a körülményektől függően.',
|
||||
'Ha az összes szem előtt lévő élőholtat sikerült elűzni vagy irányítani és még maradt „a szent energiából”, akkor ismét el kell kezdeni a hatást a leggyengébb ellenségektől. Az így elűzött szörnyek megsemmisülnek, illetve irányítás esetén végleg a gonosz pap szolgálatába állnak.',
|
||||
'A két hatás egymás ellen is fölhasználható, például egy jó pap kiolthatja egy gonosz pap irányítását, de akár két gonosz pap is versenyezhet egy csapat sírlidérc „megtérítésén”.',
|
||||
]
|
||||
},
|
||||
{
|
||||
Id: 's_pap_invokacio',
|
||||
Name: 'Invokáció',
|
||||
Description:
|
||||
'A pap kérheti istene segítségét (általában nevének kimondásával), ami +1-et, ritkábban\n' +
|
||||
' +2-t ad hozzá dobásaihoz. A papok hetente annyiszor használhatják az invokációt,\n' +
|
||||
' amekkora a Bölcsességbónuszuk (de legalább egyszer).'
|
||||
}
|
||||
]
|
||||
case Osztaly.Tolvaj: return [
|
||||
{
|
||||
Id: 's_tolvaj_orvtamadas',
|
||||
Name: 'Orvtámadás',
|
||||
Description:
|
||||
'az orvtámadás akkor használható, ha a tolvaj meglepi áldozatát, tehát pl. csöndesen a\n' +
|
||||
'hátába kerül, vagy beszélgetés közben tőrt ránt és egyetlen mozdulattal gyomron szúrja.\n' +
|
||||
'Az orvtámadás minden páratlan szintért 1d6 bónusz sebzést okoz (maximuma +5d6).\n' +
|
||||
'Dobó- és lőfegyverrel is használható, és ha a tolvaj úgy dönt, illetve a használt fegyver\n' +
|
||||
'lehetővé teszi, az ellenfél elkábítására is alkalmazható.'
|
||||
},
|
||||
{
|
||||
Id: 's_tolvaj_kezdemenyezes',
|
||||
Name: 'Jobb kezdeményezés',
|
||||
Description: 'a tolvajok +4-et kapnak kezdeményezési dobásaikra.',
|
||||
},
|
||||
{
|
||||
Id: 's_tolvaj_kepzettsegek',
|
||||
Name: 'Tolvajképzettségek',
|
||||
Description:
|
||||
'Minden tolvaj jártas több olyan képzettségben, amely segíti a rejtőzködésben, a jól őrzött\n' +
|
||||
'értékek eltulajdonításában és hasonló feladatokban. A tolvajok azokat a tolvajképzettség-\n' +
|
||||
'eket is használhatják, amelyekben nem járatosak külön, de ekkor szintjük nem számít bele\n' +
|
||||
'a próbadobás módosítójába! A tolvajképzettségek listája:\n' +
|
||||
'Álcázás, Csapdák állítása és eltávolítása, Egyensúlyozás, Értékbecslés, Hallgatózás,\n' +
|
||||
'Hamisítás, Jelek olvasása, Keresés, Mászás, Megfigyelés, Méregkeverés, Osonás, Rejtőzés,\n' +
|
||||
'Szabadulóművészet, Zárnyitás és Zsebmetszés.',
|
||||
},
|
||||
]
|
||||
case Osztaly.Varazslo: return [{
|
||||
Id: 's_varazslo_varazskonyv',
|
||||
Name: 'Varázskönyv',
|
||||
Description:
|
||||
'Egy első szintű varázsló varázskönyve 6 nulladik és 3 első szintű varázslatot tartalmaz,\n' +
|
||||
'harmadik szintű kezdő karakteré ezen felül még 2 első szintűt és 2 második szintűt.\n' +
|
||||
'Az újabb varázslatokat mások könyveiből, mágikus tekercsekből vagy más módszerek\n' +
|
||||
'segítségével kell könyvébe másolnia. Az illuzionisták szintén varázskönyveket használnak\n' +
|
||||
'de eltérő mágiaformájuk miatt nem képesek a varázslói varázslatok megértésére – és viszont.'
|
||||
}]
|
||||
case Osztaly.Illuzionista: return [{
|
||||
Id: 's_illuzionista_varazskonyv',
|
||||
Name: 'Varázskönyv',
|
||||
Description:
|
||||
'Egy első szintű illuzionista varázskönyve 6 nulladik és 3 első szintű varázslatot tartalmaz,\n' +
|
||||
'harmadik szintű kezdő karakteré ezen felül még 2 első szintűt és 2 második szintűt. Az\n' +
|
||||
'újabb varázslatokat mások könyveiből, mágikus tekercsekből vagy más módszerek\n' +
|
||||
'segítségével kell könyvébe másolnia. Az varázslók szintén varázskönyveket használnak, de\n' +
|
||||
'eltérő mágiaformájuk miatt nem képesek a varázslói varázslatok megértésére – és viszont.'
|
||||
}]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import {PDFFont, PDFPage, rgb, breakTextIntoLines} from "pdf-lib";
|
||||
import {KarakterPdfView} from "./karakter_pdf_view";
|
||||
import {Skill} from "../domain-models/osztaly";
|
||||
|
||||
const maxWidth = 540
|
||||
|
||||
function drawExtendedSkillDescription(skill: Skill, font: PDFFont, baseFontSize: number, page: PDFPage, rows: number) {
|
||||
const indent = 20
|
||||
for (let j = 0; j < (skill.ExtendedDescription?.length || 0); j++) {
|
||||
const paragraph = `${j + 1}. ${skill.ExtendedDescription![j]}`
|
||||
const lines = breakTextIntoLines(paragraph, [' ', '-'], maxWidth - indent, (s) => font.widthOfTextAtSize(s, baseFontSize))
|
||||
page.drawText(paragraph, {
|
||||
x: 30 + indent,
|
||||
y: 700 - rows,
|
||||
size: baseFontSize,
|
||||
font: font,
|
||||
lineHeight: 16,
|
||||
color: rgb(0, 0, 0),
|
||||
maxWidth: maxWidth - indent,
|
||||
wordBreaks: [' ', '-']
|
||||
})
|
||||
rows += lines.length * font.heightAtSize(baseFontSize)
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
export function DrawOsztalySpecialsPage(page: PDFPage, font: PDFFont, fontBold: PDFFont, karakter: KarakterPdfView): number {
|
||||
const baseFontSize = 12
|
||||
const titleFontSize = baseFontSize * 3
|
||||
const pageCenterX = page.getWidth()/2
|
||||
const titleWidth = font.widthOfTextAtSize(karakter.Osztaly, titleFontSize)
|
||||
const titleX = pageCenterX - (titleWidth / 2)
|
||||
|
||||
page.drawText(karakter.Osztaly, {
|
||||
x: titleX,
|
||||
y: 770,
|
||||
size: titleFontSize,
|
||||
font: font,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
let rows = 0
|
||||
for (let i = 0; i < karakter.OsztalySkills.length; i++) {
|
||||
const skill = karakter.OsztalySkills[i];
|
||||
page.drawText(skill.Name, {
|
||||
x: 30,
|
||||
y: 720 - rows,
|
||||
size: baseFontSize,
|
||||
font: fontBold,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
const lines = breakTextIntoLines(skill.Description, [' ', '-'], maxWidth, (s) => font.widthOfTextAtSize(s, baseFontSize))
|
||||
page.drawText(skill.Description, {
|
||||
x: 30,
|
||||
y: 700 - rows,
|
||||
size: baseFontSize,
|
||||
font: font,
|
||||
lineHeight: 16,
|
||||
color: rgb(0, 0, 0),
|
||||
maxWidth: maxWidth,
|
||||
wordBreaks: [' ', '-']
|
||||
})
|
||||
// rows += Math.ceil(font.widthOfTextAtSize(skill.Description, baseFontSize)/textWidth)*20 + 30
|
||||
// rows += skill.Description.split('\n').length*16 + 30
|
||||
rows += lines.length * font.heightAtSize(baseFontSize)
|
||||
rows = drawExtendedSkillDescription(skill, font, baseFontSize, page, rows);
|
||||
rows += 24 // for title and spacing
|
||||
}
|
||||
return rows
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import {PDFFont, PDFPage, rgb} from "pdf-lib";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
import {KarakterTulajdonsagok, Modifier} from "../domain-models/tulajdonsag";
|
||||
|
||||
export function DrawTulajdonsagok(page: PDFPage, tulajdonsagok: KarakterTulajdonsagok, fontSizeBase: number, pdfFont: PDFFont) {
|
||||
page.drawText(tulajdonsagok.t_ero.toString(), {
|
||||
x: 130,
|
||||
y: 613,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(tulajdonsagok.t_ero)), {
|
||||
x: 176,
|
||||
y: 613,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(tulajdonsagok.t_ugy.toString(), {
|
||||
x: 130,
|
||||
y: 580,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(tulajdonsagok.t_ugy)), {
|
||||
x: 176,
|
||||
y: 580,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(tulajdonsagok.t_egs.toString(), {
|
||||
x: 130,
|
||||
y: 547,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(tulajdonsagok.t_egs)), {
|
||||
x: 176,
|
||||
y: 547,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(tulajdonsagok.t_int.toString(), {
|
||||
x: 130,
|
||||
y: 515,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(tulajdonsagok.t_int)), {
|
||||
x: 176,
|
||||
y: 515,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(tulajdonsagok.t_bol.toString(), {
|
||||
x: 130,
|
||||
y: 482,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(tulajdonsagok.t_bol)), {
|
||||
x: 176,
|
||||
y: 482,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(tulajdonsagok.t_kar.toString(), {
|
||||
x: 130,
|
||||
y: 449,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
page.drawText(SignedNumberToText(Modifier(tulajdonsagok.t_kar)), {
|
||||
x: 176,
|
||||
y: 449,
|
||||
size: fontSizeBase * 2,
|
||||
font: pdfFont,
|
||||
color: rgb(0, 0, 0),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
||||
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
||||
sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
import { getWebInstrumentations, initializeFaro } from '@grafana/faro-web-sdk';
|
||||
|
||||
const faro = window.location.hostname === 'localhost' ? undefined : initializeFaro({
|
||||
url: 'https://faro-collector-prod-eu-west-2.grafana.net/collect/88adcc2543da5af525c451166286f2cc',
|
||||
app: {
|
||||
name: 'kemkas',
|
||||
version: '1.0.0',
|
||||
environment: 'production'
|
||||
},
|
||||
instrumentations: [
|
||||
// Mandatory, overwriting the instrumentations array would cause the default instrumentations to be omitted
|
||||
...getWebInstrumentations(),
|
||||
|
||||
// Initialization of the tracing package.
|
||||
// This packages is optional because it increases the bundle size noticeably. Only add it if you want tracing data.
|
||||
// new TracingInstrumentation(),
|
||||
],
|
||||
});
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
document.getElementById('root') as HTMLElement
|
||||
);
|
||||
root.render(
|
||||
<React.StrictMode>
|
||||
<App faro={faro} />
|
||||
</React.StrictMode>
|
||||
);
|
||||
Vendored
+1
@@ -0,0 +1 @@
|
||||
/// <reference types="react-scripts" />
|
||||
@@ -0,0 +1,15 @@
|
||||
import { ReportHandler } from 'web-vitals';
|
||||
|
||||
const reportWebVitals = (onPerfEntry?: ReportHandler) => {
|
||||
if (onPerfEntry && onPerfEntry instanceof Function) {
|
||||
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
||||
getCLS(onPerfEntry);
|
||||
getFID(onPerfEntry);
|
||||
getFCP(onPerfEntry);
|
||||
getLCP(onPerfEntry);
|
||||
getTTFB(onPerfEntry);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default reportWebVitals;
|
||||
@@ -0,0 +1,32 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
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 {MultiClassTamadasBonusz} from "../domain-models/tamadas_bonusz";
|
||||
import {Osztaly2E} from "../domain-models/osztaly2E";
|
||||
|
||||
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, '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 regiTB = MultiClassTamadasBonusz(karakter.szintlepesek.slice(0, szint-1))
|
||||
const ujTB = MultiClassTamadasBonusz(karakter.szintlepesek.slice(0, 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(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)})}</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,43 @@
|
||||
import React from "react";
|
||||
import {Faj2E, FajDescription, FajLabel, FajSpecials} from "../domain-models/faj2E";
|
||||
|
||||
function FajSelector2E(props: { faj: Faj2E, changeFaj: (val: Faj2E) => void }) {
|
||||
const {faj, changeFaj} = props
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Faj</label>
|
||||
<select className='col form-select' value={faj} onChange={e => changeFaj(e.target.value as Faj2E)}>
|
||||
<option key={Faj2E.Ember} value={Faj2E.Ember}>{FajLabel(Faj2E.Ember)}</option>
|
||||
<optgroup label='más emberi népek'>
|
||||
<option key={Faj2E.Amazon} value={Faj2E.Amazon}>{FajLabel(Faj2E.Amazon)}</option>
|
||||
<option key={Faj2E.Birodalmi} value={Faj2E.Birodalmi}>{FajLabel(Faj2E.Birodalmi)}</option>
|
||||
<option key={Faj2E.Eszaki} value={Faj2E.Eszaki}>{FajLabel(Faj2E.Eszaki)}</option>
|
||||
<option key={Faj2E.Nomad} value={Faj2E.Nomad}>{FajLabel(Faj2E.Nomad)}</option>
|
||||
<option key={Faj2E.Osember} value={Faj2E.Osember}>{FajLabel(Faj2E.Osember)}</option>
|
||||
</optgroup>
|
||||
<optgroup label='nem emberi fajok'>
|
||||
<option key={Faj2E.Elf} value={Faj2E.Elf}>{FajLabel(Faj2E.Elf)}</option>
|
||||
<option key={Faj2E.Felelf} value={Faj2E.Felelf}>{FajLabel(Faj2E.Felelf)}</option>
|
||||
<option key={Faj2E.Felork} value={Faj2E.Felork}>{FajLabel(Faj2E.Felork)}</option>
|
||||
<option key={Faj2E.Felszerzet}
|
||||
value={Faj2E.Felszerzet}>{FajLabel(Faj2E.Felszerzet)}</option>
|
||||
<option key={Faj2E.Gnom} value={Faj2E.Gnom}>{FajLabel(Faj2E.Gnom)}</option>
|
||||
<option key={Faj2E.Torpe} value={Faj2E.Torpe}>{FajLabel(Faj2E.Torpe)}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 form-label'></label>
|
||||
<div className='col'>
|
||||
<p className='row pt-2'>
|
||||
{FajDescription(faj)}
|
||||
</p>
|
||||
<ul>
|
||||
{FajSpecials(faj).map(((special, i) => (<li key={faj + i}>{special}</li>)))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default FajSelector2E
|
||||
@@ -0,0 +1,87 @@
|
||||
import React from "react";
|
||||
import {Fegyver} from "../domain-models/felszereles";
|
||||
|
||||
export function FegyverFlags(fegyver: Fegyver): string {
|
||||
const flags = [] as string[]
|
||||
if (fegyver.Megterheltseg) {
|
||||
flags.push("M")
|
||||
}
|
||||
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")
|
||||
}
|
||||
return flags.join(' ');
|
||||
}
|
||||
|
||||
export function FegyverLabel(fegyver: Fegyver): string {
|
||||
const serializedFlags = FegyverFlags(fegyver) + (fegyver.Megjegyzes != null ? " " + fegyver.Megjegyzes : "");
|
||||
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
|
||||
@@ -0,0 +1,73 @@
|
||||
import React from "react";
|
||||
import {Fegyver, KarakterFelszereles, PancelTypeLabel} from "../domain-models/felszereles";
|
||||
import {Osztaly2E} from '../domain-models/osztaly2E'
|
||||
import {AllowedPajzsTypes, AllowedPancelTypes} from '../domain-models/allowed-pancel-types'
|
||||
import fegyverek from '../domain-models/fegyver.json'
|
||||
import {arraySetN} from "../../util";
|
||||
import {AllowedFegyver} from "../domain-models/allowed-fegyver";
|
||||
import FegyverSelector from "./FegyverSelector";
|
||||
|
||||
function Felszereles(props: {felszereles: KarakterFelszereles, changeFelszereles: (felszereles: KarakterFelszereles) => void, osztaly: Osztaly2E}) {
|
||||
const { felszereles, changeFelszereles, osztaly } = props;
|
||||
const allowedPancel = AllowedPancelTypes([osztaly])
|
||||
const allowedPajzs = AllowedPajzsTypes([osztaly])
|
||||
const valasztottFegyverek = felszereles.fegyverIDk
|
||||
.map((id, idx) => ({idx, fegyver: fegyverek.data.find(f => f.Id === id)})).filter((x) => x.fegyver != null).map(({idx, fegyver}) => ({idx, fegyver: fegyver as Fegyver}))
|
||||
|
||||
const osztalyAllowedFegyverek = AllowedFegyver(osztaly)
|
||||
const allowedFegyverek = [...osztalyAllowedFegyverek, ...valasztottFegyverek.filter(({idx, fegyver}) => !osztalyAllowedFegyverek.map(f => f.Id).includes(fegyver.Id)).map(({fegyver}) => fegyver)]
|
||||
const changeFegyver = (idx: number, newID: string) => {
|
||||
const found = fegyverek.data.find(x => x.Id === newID)
|
||||
if (!found) {
|
||||
console.log('Nem létező fegyver ID: ', newID)
|
||||
return
|
||||
}
|
||||
changeFelszereles({...felszereles, fegyverIDk: arraySetN(felszereles.fegyverIDk, idx, newID)})
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className='row'>
|
||||
<h5 className='col align-self-center'>Felszerelés</h5>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Viselt páncél</label>
|
||||
<select className='col form-select' value={felszereles.pancelID} onChange={e => changeFelszereles({...felszereles, pancelID: e.target.value === 'nincs' ? undefined : e.target.value})}>
|
||||
<option key={'nincs'} value={'nincs'}>Nincs</option>
|
||||
{
|
||||
<optgroup label={PancelTypeLabel("konnyu")}>
|
||||
{allowedPancel.filter(p => p.Type === "konnyu").map(p =>
|
||||
<option key={p.Id} value={p.Id}>{`${p.Name}${p.Size > 1 ? ` [${p.Size}]` : ''} (+${p.VO} VO) - ${p.Price} at`}</option>)}
|
||||
</optgroup>
|
||||
}
|
||||
{
|
||||
allowedPancel.some(p => p.Type === "nehez") &&
|
||||
<optgroup label={PancelTypeLabel("nehez")}>
|
||||
{allowedPancel.filter(p => p.Type === "nehez").map(p =>
|
||||
<option key={p.Id} value={p.Id}>{`${p.Name} (+${p.VO} VO) - ${p.Price} at`}</option>)}
|
||||
</optgroup>
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Hordott pajzs</label>
|
||||
<select className='col form-select' value={felszereles.pajzsID}
|
||||
onChange={e => changeFelszereles({...felszereles, pajzsID: e.target.value === 'nincs' ? undefined : e.target.value})}>
|
||||
<option key={'nincs'} value={'nincs'}>Nincs</option>
|
||||
{allowedPajzs.map(p => <option key={p.Id} value={p.Id}>{`${p.Name} (+${p.VO} VO) - ${p.Price} at`}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
{valasztottFegyverek.map(({idx, fegyver}) => (
|
||||
<div key={`fegyver-${idx}`} className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Fegyver</label>
|
||||
<FegyverSelector fegyverek={allowedFegyverek} selectedId={fegyver.Id} onChange={(fegyverId) => changeFegyver(idx, fegyverId)} />
|
||||
<button className='col-md-2 col-sm-3 btn btn-outline-dark btn-lg ms-2' type='button'
|
||||
onClick={() => changeFelszereles({
|
||||
...felszereles,
|
||||
fegyverIDk: [...felszereles.fegyverIDk.slice(0, idx), ...felszereles.fegyverIDk.slice(idx+1)]})}>Elvesz</button>
|
||||
</div>
|
||||
))}
|
||||
<button className='btn btn-outline-dark btn btn-lg ms-2' type='button' onClick={() => changeFelszereles({...felszereles, fegyverIDk: [...felszereles.fegyverIDk, 'bot']})}>Fegyver hozzáadása</button>
|
||||
</>
|
||||
}
|
||||
|
||||
export default 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,38 @@
|
||||
// import React from "react";
|
||||
// import fegyverek from "../domain-models/fegyver.json"
|
||||
// import {defaultFegyverID, GetFegyver} from "../domain-models/felszereles";
|
||||
//
|
||||
// function HarcosFegyverSpecializacio(props: {
|
||||
// specialization: string,
|
||||
// existingSpecializations: string[],
|
||||
// changeSpecialization: (specialization: string) => void
|
||||
// szint: number
|
||||
// }) {
|
||||
// const {
|
||||
// specialization,
|
||||
// existingSpecializations,
|
||||
// changeSpecialization,
|
||||
// szint
|
||||
// } = props
|
||||
// const fegyver = GetFegyver(specialization)
|
||||
// const pickableFegyverek = fegyverek.data.filter(f => f.Id === specialization || existingSpecializations.filter(x => x === f.Id).length < (szint < 9 ? 1 : 2))
|
||||
// const kozelharciPickable = pickableFegyverek.filter(f => f.Type === 'kozelharci')
|
||||
// const tavolsagiPickable = pickableFegyverek.filter(f => f.Type === 'lofegyver')
|
||||
//
|
||||
// return <>
|
||||
// <div className='row m-2'>
|
||||
// <label className='col-md-2 col-sm-3 col-form-label' >Fegyver specializáció</label>
|
||||
// <select className='col form-select' value={fegyver?.Id || defaultFegyverID} onChange={e => changeSpecialization(e.target.value)}>
|
||||
// <optgroup label="Közelharci">
|
||||
// {kozelharciPickable.map(f => <option key={`spec-${szint}-${f.Id}`} value={f.Id}>{f.Name}</option>)}
|
||||
// </optgroup>
|
||||
// <optgroup label="Távolsági">
|
||||
// {tavolsagiPickable.map(f => <option key={`spec-${szint}-${f.Id}`} value={f.Id}>{f.Name}</option>)}
|
||||
// </optgroup>
|
||||
// </select>
|
||||
// {fegyver == null && <span className='form-field-error'>Ismeretlen fegyver: {specialization}</span>}
|
||||
// </div>
|
||||
// </>
|
||||
// }
|
||||
//
|
||||
// export default HarcosFegyverSpecializacio
|
||||
@@ -0,0 +1,27 @@
|
||||
import React from "react";
|
||||
import {AllJellemIDs, GetJellem, JellemID} from "../domain-models/jellem";
|
||||
|
||||
function JellemSelector(props: {selected: JellemID, changeJellem: (val: JellemID) => void}) {
|
||||
const { selected, changeJellem } = props
|
||||
const jellem = GetJellem(selected)
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Jellem</label>
|
||||
<select className='col form-select' value={selected} onChange={e => changeJellem(e.target.value as JellemID)}>
|
||||
{AllJellemIDs.map((id) => (
|
||||
<option key={id} value={id}>{GetJellem(id).Label}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 form-label'></label>
|
||||
<div className='col'>
|
||||
<p className='row pt-2'>
|
||||
{jellem.Description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default JellemSelector
|
||||
@@ -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,89 @@
|
||||
import React from "react";
|
||||
import KepzettsegSelector from "./KepzettsegSelector2E";
|
||||
import {
|
||||
Kepzettseg,
|
||||
Kepzettsegek,
|
||||
KepzettsegId,
|
||||
TolvajKepzettsegList,
|
||||
} from "../domain-models/kepzettsegek2E";
|
||||
import {arraySetN} from "../../util";
|
||||
|
||||
|
||||
function InternalKepzettsegekSelector(props: {
|
||||
title: string,
|
||||
numberOfKepzettseg: number,
|
||||
getKepzettsegListaN: (n: number) => Kepzettseg[],
|
||||
kepzettsegek: KepzettsegId[],
|
||||
changeKepzettsegek: (newKepzettsegek: KepzettsegId[]) => void
|
||||
}) {
|
||||
const {title, numberOfKepzettseg, getKepzettsegListaN, kepzettsegek, changeKepzettsegek} = props
|
||||
|
||||
const klist = Array.from(new Array(numberOfKepzettseg).keys())
|
||||
|
||||
const preCalculated: {
|
||||
kepzettsegek: Kepzettseg[],
|
||||
changeKepzettseg: (newKepzettseg: KepzettsegId) => void,
|
||||
selected: Kepzettseg,
|
||||
}[] = [];
|
||||
|
||||
for (let i = 0; i < numberOfKepzettseg; i++) {
|
||||
preCalculated.push({
|
||||
kepzettsegek: getKepzettsegListaN(i),
|
||||
selected: Kepzettsegek[kepzettsegek[i]],
|
||||
changeKepzettseg: (newKepzettseg: KepzettsegId) => changeKepzettsegek(arraySetN(kepzettsegek, i, newKepzettseg))
|
||||
})
|
||||
}
|
||||
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-lg-2 col-md-12 col-form-label'>{title}</label>
|
||||
<div className='col'>
|
||||
{klist.map((idx) =>
|
||||
<KepzettsegSelector
|
||||
key={title+idx}
|
||||
kepzettsegek={preCalculated[idx].kepzettsegek}
|
||||
selected={preCalculated[idx].selected}
|
||||
changeKepzettseg={preCalculated[idx].changeKepzettseg}
|
||||
/>)
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
}
|
||||
|
||||
function KarakterKepzettsegek (props: {
|
||||
numberOfKepzettsegek: number
|
||||
kepzettsegek: KepzettsegId[],
|
||||
changeKepzettsegek: (newKepzettsegek: KepzettsegId[]) => void
|
||||
tolvajKepzettsegek: KepzettsegId[],
|
||||
changeTolvajKepzettsegek: (newKepzettsegek: KepzettsegId[]) => void
|
||||
getKepzettsegListaN: (n: number) => Kepzettseg[]
|
||||
}) {
|
||||
const { kepzettsegek, numberOfKepzettsegek, getKepzettsegListaN, changeKepzettsegek, tolvajKepzettsegek, changeTolvajKepzettsegek} = props
|
||||
|
||||
// TODO: Birodalmi tolvajnal az Alikmia, vagy Meregkeveres kezelese
|
||||
|
||||
const getTolvajKepzettsegListaN = (n: number) : Kepzettseg[] => {
|
||||
const tolvajKepzettsegekWithoutN = [...tolvajKepzettsegek.slice(0, n), ...tolvajKepzettsegek.slice(n+1)]
|
||||
return TolvajKepzettsegList.filter(x => !kepzettsegek.includes(x.Id) && !tolvajKepzettsegekWithoutN.includes(x.Id))
|
||||
}
|
||||
|
||||
return <>
|
||||
<InternalKepzettsegekSelector
|
||||
title="Képzettségek"
|
||||
numberOfKepzettseg={numberOfKepzettsegek}
|
||||
getKepzettsegListaN={getKepzettsegListaN}
|
||||
changeKepzettsegek={changeKepzettsegek}
|
||||
kepzettsegek={kepzettsegek} />
|
||||
|
||||
{tolvajKepzettsegek.length > 0 && <InternalKepzettsegekSelector
|
||||
title="Tolvaj képzettségek"
|
||||
numberOfKepzettseg={4}
|
||||
getKepzettsegListaN={getTolvajKepzettsegListaN}
|
||||
changeKepzettsegek={changeTolvajKepzettsegek}
|
||||
kepzettsegek={tolvajKepzettsegek} />}
|
||||
</>
|
||||
}
|
||||
|
||||
export default KarakterKepzettsegek
|
||||
@@ -0,0 +1,32 @@
|
||||
import React from "react";
|
||||
import {Kepzettseg, KepzettsegId} from "../domain-models/kepzettsegek2E";
|
||||
import {TulajdonsagLabel} from "../domain-models/tulajdonsag2E";
|
||||
import {OsztalyLabel} from "../domain-models/osztaly2E";
|
||||
|
||||
function kepzettsegOptionText(k: Kepzettseg) {
|
||||
const osztalyok = k.Osztalyok?.reduce((acc, o) => acc + ' / ' + OsztalyLabel(o), '')?.substring(3)
|
||||
return k.Name + ' (' + k.Tulajdonsag.reduce((acc, k) => (acc === '' ? acc : acc + ' / ') + TulajdonsagLabel(k), '') + ')' + (osztalyok == null ? '' : (' - ' + osztalyok));
|
||||
}
|
||||
|
||||
function KepzettsegSelector (props: {kepzettsegek: Kepzettseg[], changeKepzettseg: (newKepzettseg: KepzettsegId) => void, selected : Kepzettseg}) {
|
||||
|
||||
const { kepzettsegek, changeKepzettseg, selected } = props
|
||||
|
||||
return <>
|
||||
<div className='row'>
|
||||
<select className='form-control'
|
||||
value={selected.Id} onChange={e => changeKepzettseg(e.target.value as KepzettsegId)}>
|
||||
{kepzettsegek.map(k =>(
|
||||
<option key={k.Id} value={k.Id}>
|
||||
{kepzettsegOptionText(k)}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className='row pt-2'>
|
||||
<p className='col'>{selected.Description}</p>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default KepzettsegSelector
|
||||
@@ -0,0 +1,147 @@
|
||||
import React from "react";
|
||||
import {ChangeOsztalyAtSzint, 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";
|
||||
|
||||
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
|
||||
|
||||
return <div>
|
||||
<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
|
||||
tulajdonsagok={karakter.tulajdonsagok}
|
||||
tulajdonsagNoveles={karakter.szintlepesek[szint-1].tulajdonsagNoveles!}
|
||||
changeTulajdonsagNoveles={changeTulajdonsagNoveles}
|
||||
/> }
|
||||
<BasicNewLevel
|
||||
szint={szint}
|
||||
karakter={karakter}
|
||||
osztaly={osztaly}
|
||||
changeRolledHP={changeRolledHP}
|
||||
/>
|
||||
{osztaly === Osztaly2E.Harcos && harcosSzint % 2 === 1 &&
|
||||
<HarcosFegyverSpecializacio
|
||||
specialization={specialization!}
|
||||
existingSpecializations={karakter.szintlepesek.map(x => x.harcosFegyver)}
|
||||
changeSpecialization={changeHarcosSpec}
|
||||
szint={harcosSzint}
|
||||
/>
|
||||
}
|
||||
{osztaly === Osztaly2E.Tengeresz && kalozSzint % 3 === 0 &&
|
||||
<KalozKritikus
|
||||
kritFegyverId={krit!}
|
||||
existingKrits={karakter.szintlepesek.map(x => x.kalozKritikus)}
|
||||
changeKrit={changeKalozKritikus}
|
||||
szint={kalozSzint}
|
||||
/>
|
||||
}
|
||||
</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)})
|
||||
|
||||
const changeRolledHPAtSzint = (szint: number) => (newHProll: number) => {
|
||||
changeKarakter({...karakter, szintlepesek: arraySetN(karakter.szintlepesek, szint-1, {...karakter.szintlepesek[szint-1], 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}
|
||||
osztaly={karakter.szintlepesek[szint-1].osztaly}
|
||||
karakter={{...karakter, szintlepesek: karakter.szintlepesek.slice(0, szint) ,tulajdonsagok: tulajdonsagokAtSzint(szint)}}
|
||||
changeTulajdonsagNoveles={changeTulajdonsagNovelesAtSzint(szint)}
|
||||
changeRolledHP={changeRolledHPAtSzint(szint)}
|
||||
changeHarcosSpec={changeHarcosSpecializacioAtSzint(szint)}
|
||||
changeKalozKritikus={changeKalozKritikusAtSzint(szint)}
|
||||
changeOsztaly={(o) => changeKarakter(ChangeOsztalyAtSzint(karakter, o, szint))}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
}
|
||||
|
||||
export default LevelUps
|
||||
@@ -0,0 +1,61 @@
|
||||
import React from "react";
|
||||
import {OverlayTrigger, Tooltip} from "react-bootstrap";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
import {MasodlagosErtekekView} from "../domain-models/masodlagos_ertekek";
|
||||
|
||||
function MasodlagosErtekek(props: MasodlagosErtekekView) {
|
||||
|
||||
const { HP, VO, CelzoTB, Mentok, KozelharciTB } = props
|
||||
|
||||
const tooltip = (
|
||||
<Tooltip id="tooltip">
|
||||
<strong>Hentelési Potenciál</strong>
|
||||
</Tooltip>
|
||||
);
|
||||
|
||||
return <>
|
||||
<div className='row'>
|
||||
<h5 className='col align-self-center'>Másodlagos értékek</h5>
|
||||
</div>
|
||||
<div className='row'>
|
||||
<div className='col-lg-6'>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label'>Életerő{' '}
|
||||
<OverlayTrigger placement='top' overlay={tooltip} delay={0} defaultShow={false} flip={false}>
|
||||
<span>(HP)</span>
|
||||
</OverlayTrigger>
|
||||
</label>
|
||||
<p className='col col-form-label'>{HP}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Védekezési Osztály (VO)</label>
|
||||
<p className='col col-form-label'>{VO}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Közelharci támadás</label>
|
||||
<p className='col col-form-label'>{KozelharciTB.map(SignedNumberToText).join(" / ")}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Célzó támadás</label>
|
||||
<p className='col col-form-label'>{CelzoTB.map(SignedNumberToText).join(" / ")}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className='col-lg-6'>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Kitartás mentő</label>
|
||||
<p className='col col-form-label'>{SignedNumberToText(Mentok.kitartas)}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Reflex mentő</label>
|
||||
<p className='col col-form-label'>{SignedNumberToText(Mentok.reflex)}</p>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-sm-6 col-8 col-form-label' >Akaraterő mentő </label>
|
||||
<p className='col col-form-label'>{SignedNumberToText(Mentok.akaratero)}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default MasodlagosErtekek
|
||||
@@ -0,0 +1,54 @@
|
||||
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
|
||||
@@ -0,0 +1,75 @@
|
||||
import React from "react";
|
||||
import {
|
||||
Osztaly2E,
|
||||
OsztalyDescription,
|
||||
OsztalyLabel,
|
||||
OsztalyProperties,
|
||||
OsztalySpecialSkills
|
||||
} from "../domain-models/osztaly2E";
|
||||
import {Faj2E, SzintKorlatokFajokra} from "../domain-models/faj2E";
|
||||
|
||||
function OsztalySelector2E(props: {
|
||||
currentFaj: Faj2E,
|
||||
currentOsztaly: Osztaly2E,
|
||||
changeOsztaly: (newOsztaly: Osztaly2E) => void
|
||||
}) {
|
||||
const {currentFaj, currentOsztaly, changeOsztaly} = props;
|
||||
|
||||
return <>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 col-form-label'>Osztály</label>
|
||||
<select className="col form-select" value={currentOsztaly}
|
||||
onChange={(e) => changeOsztaly(e.target.value as Osztaly2E)}>
|
||||
<optgroup label='Harcos'>
|
||||
<option value={Osztaly2E.Harcos}>{OsztalyLabel(Osztaly2E.Harcos)}</option>
|
||||
{SzintKorlatokFajokra(currentFaj)[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>
|
||||
<option value={Osztaly2E.Druida}>{OsztalyLabel(Osztaly2E.Druida)}</option>
|
||||
<option value={Osztaly2E.Vandor}>{OsztalyLabel(Osztaly2E.Vandor)}</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div className='row m-2'>
|
||||
<label className='col-md-2 col-sm-3 form-label'></label>
|
||||
<div className='col'>
|
||||
<p className='row pt-2'>
|
||||
{OsztalyDescription(currentOsztaly)}
|
||||
</p>
|
||||
<ul>
|
||||
{OsztalyProperties(currentOsztaly).map(((special, i) => (<li key={currentOsztaly + i}>{special}</li>)))}
|
||||
</ul>
|
||||
<div className='col'>
|
||||
{OsztalySpecialSkills(currentOsztaly).map(skill =>
|
||||
<div key={skill.Id} >
|
||||
<strong className='d-inline'>
|
||||
{skill.Name}
|
||||
</strong>
|
||||
{' '}
|
||||
{skill.Description}
|
||||
{skill.ExtendedDescription && (
|
||||
<ol>
|
||||
{skill.ExtendedDescription.map((ext, i) =>
|
||||
(<li key={skill.Id + '-' + i}>{ext}</li>))}
|
||||
</ol>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
||||
export default OsztalySelector2E;
|
||||
@@ -0,0 +1,52 @@
|
||||
import React from "react";
|
||||
|
||||
import {Faj2E, FajLabel} from "../domain-models/faj2E";
|
||||
import {Modifier} from "../domain-models/tulajdonsag2E";
|
||||
import {SignedNumberToText} from "../../shared/components/Helpers";
|
||||
|
||||
|
||||
function fajiModositoText(faj: Faj2E, szamolas: (f: Faj2E) => number) : string {
|
||||
const mod = szamolas(faj)
|
||||
return (mod !== 0) ? SignedNumberToText(mod) + ' (' + FajLabel(faj) + ')' : ''
|
||||
}
|
||||
|
||||
function TulajdonsagInput(props: {
|
||||
tulajdonsag: string,
|
||||
currentFaj : Faj2E,
|
||||
fajiModosito: (faj: Faj2E) => number,
|
||||
changeValue: (val: number) => void
|
||||
currentValue: number
|
||||
tooLowError: string,
|
||||
tooHighError: string
|
||||
}) {
|
||||
const {
|
||||
tulajdonsag,
|
||||
changeValue,
|
||||
currentFaj,
|
||||
currentValue,
|
||||
fajiModosito,
|
||||
tooLowError,
|
||||
tooHighError,
|
||||
} = props;
|
||||
return (<div className='row m-2'>
|
||||
<label className='col-lg-1 col-sm-2 col-form-label'>{tulajdonsag}</label>
|
||||
<div className='col-lg-1 col-sm-2 m-2'>
|
||||
<input className='form-control' maxLength={2} type='number' value={currentValue} onChange={e => changeValue(Number(e.target.value))} />
|
||||
</div>
|
||||
<span className='col-sm-2 m-2'>
|
||||
{fajiModositoText(currentFaj, fajiModosito)}
|
||||
</span>
|
||||
<span className='col-sm-2 m-2'>
|
||||
Összesen: { (currentValue + (fajiModosito(currentFaj))).toString() }
|
||||
</span>
|
||||
<span className='col-sm-2 m-2'>
|
||||
Módosító: { SignedNumberToText(Modifier(currentValue + fajiModosito(currentFaj))) }
|
||||
</span>
|
||||
{currentValue < 3 && (
|
||||
<span className='form-field-error'>{tooLowError}</span>)}
|
||||
{currentValue > 18 && (
|
||||
<span className='form-field-error'>{tooHighError}</span>)}
|
||||
</div>)
|
||||
}
|
||||
|
||||
export default TulajdonsagInput;
|
||||
@@ -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
|
||||
@@ -0,0 +1,83 @@
|
||||
import React from "react";
|
||||
import {
|
||||
KarakterTulajdonsagok,
|
||||
RollAllAbilities,
|
||||
Tulajdonsag2E,
|
||||
} from "../domain-models/tulajdonsag2E";
|
||||
import TulajdonsagInput from "./TulajdonsagInput2E";
|
||||
import {Faj2E, TulajdonsagModositokFajokra} from "../domain-models/faj2E";
|
||||
|
||||
function Tulajdonsagok(props: {
|
||||
currentFaj: Faj2E,
|
||||
tulajdonsagok: KarakterTulajdonsagok
|
||||
changeTulajdonsagok: (tulajdonsagok: KarakterTulajdonsagok) => void
|
||||
}) {
|
||||
const {currentFaj, tulajdonsagok, changeTulajdonsagok} = props
|
||||
return <>
|
||||
<div className='row'>
|
||||
<h5 className='col-lg-2 col-sm-4 align-self-center'>Tulajdonságok</h5>
|
||||
<div className='col-sm-2 m-2'>
|
||||
<button className='btn btn-dark' type='button'
|
||||
onClick={() => changeTulajdonsagok(RollAllAbilities())}>Dobás
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Erő'
|
||||
currentValue={tulajdonsagok.t_ero}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag2E.Ero)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_ero: val})}
|
||||
tooLowError='Túl gyenge vagy, nem bírtad felemelni a kezed a jelentkezéshez!'
|
||||
tooHighError='Szét szakadtak az izmaid!'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Ügyesség'
|
||||
currentValue={tulajdonsagok.t_ugy}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag2E.Ugyesseg)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_ugy: val})}
|
||||
tooLowError='Orrabuktál jelentkezés helyett!'
|
||||
tooHighError='Emberfeletti zsonglörködésedre záptojással válaszoltak a helyiek!'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Egészség'
|
||||
currentValue={tulajdonsagok.t_egs}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag2E.Egeszseg)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_egs: val})}
|
||||
tooLowError='Túl beteg vagy ahhoz, hogy kalandozni menj!'
|
||||
tooHighError='Kicsattanó egészségedet csak a diambroid állíthatja meg, minő véletlen, hogy pont az arcodba robbant...'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Intelligencia'
|
||||
currentValue={tulajdonsagok.t_int}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag2E.Intelligencia)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_int: val})}
|
||||
tooLowError='Elfelejtetted, hogy mikor is kéne kalandozni indulni!'
|
||||
tooHighError='Ilyen tudás és logika birtokában mi szükséged van új információkra? Mindent le tudsz vezetni a már meglévő ismereteidből, és ezt azonnal beláttad.'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Bölcsesség'
|
||||
currentValue={tulajdonsagok.t_bol}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag2E.Bolcsesseg)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_bol: val})}
|
||||
tooLowError='Nem bírtál ellenállni a kíváncsiságodnak, hogy közelebbről is megvizsgáld a tőr hegyét. Nagyon közelről.'
|
||||
tooHighError='Hatalmas bölcsességedben beláttad a kalandozás veszélyeit és inkább más tevékenységbe fogtál.'
|
||||
/>
|
||||
<TulajdonsagInput
|
||||
tulajdonsag='Karizma'
|
||||
currentValue={tulajdonsagok.t_kar}
|
||||
currentFaj={currentFaj}
|
||||
fajiModosito={TulajdonsagModositokFajokra(Tulajdonsag2E.Karizma)}
|
||||
changeValue={(val: number) => changeTulajdonsagok({...tulajdonsagok, t_kar: val})}
|
||||
tooLowError='Mintha taszítanád az embereket, sose sikerült kalandozó csapatot találnod.'
|
||||
tooHighError='Az ellenkező nem tagjai nem engedték, hogy útnak indulj.'
|
||||
/>
|
||||
|
||||
</>
|
||||
}
|
||||
|
||||
export default Tulajdonsagok
|
||||
@@ -0,0 +1,29 @@
|
||||
import {Fegyver} from "./felszereles";
|
||||
import fegyverDB from "./fegyver.json";
|
||||
import {Osztaly2E} from "./osztaly2E";
|
||||
|
||||
export function AllowedFegyver(o: Osztaly2E): Fegyver[] {
|
||||
const fegyverek = fegyverDB.data.map(x => x as Fegyver)
|
||||
const varazslo = fegyverek.filter(f => ['okol', 'bot', 'bot_vasalt' , 'bunko', 'tor', 'parittya', 'dobotu'].includes(f.Id))
|
||||
const tolvaj = fegyverek.filter(f => !f.Ketkezes || !f.Masfelkezes || ['ij_rovid', 'szamszerij_konnyu', 'szamszerij_nehez' ].includes(f.Id))
|
||||
const dalnok = fegyverek.filter(f => !f.Ketkezes || !f.Masfelkezes || ['okol', 'ij_rovid', 'szamszerij_konnyu' ].includes(f.Id))
|
||||
const druida = fegyverek.filter(f => ['okol', 'bot', 'bunko', 'tor', 'dobotu', 'kard_szablya', 'sarlo', 'landzsa', 'parittya'].includes(f.Id))
|
||||
const nemHarcos = fegyverek.filter(f => !f.Harcos)
|
||||
const harcos = fegyverek.filter(f => !f.CsakNemHarcos)
|
||||
switch (o) {
|
||||
case Osztaly2E.Harcos:
|
||||
case Osztaly2E.Amazon:
|
||||
case Osztaly2E.Barbar:
|
||||
case Osztaly2E.Ijasz:
|
||||
case Osztaly2E.Tengeresz:
|
||||
case Osztaly2E.Vandor:
|
||||
return harcos;
|
||||
// Note: Isteni fegyver barmi lehet istentol foggoen
|
||||
case Osztaly2E.Pap: return nemHarcos;
|
||||
case Osztaly2E.Tolvaj: return tolvaj;
|
||||
case Osztaly2E.Illuzionista:
|
||||
case Osztaly2E.Varazslo: return varazslo;
|
||||
case Osztaly2E.Dalnok: return dalnok;
|
||||
case Osztaly2E.Druida: return druida;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import {Pajzs, Pancel} from "./felszereles";
|
||||
import {Osztaly2E} from "./osztaly2E";
|
||||
import pancelDB from "./pancel.json";
|
||||
import pajzsDB from "./pajzs.json"
|
||||
|
||||
export function AllowedPajzsTypes(osztalyok: Osztaly2E[]): Pajzs[] {
|
||||
return [...new Set(osztalyok.flatMap(osztalyAllowedPajzs))]
|
||||
}
|
||||
|
||||
function osztalyAllowedPajzs(o: Osztaly2E): Pajzs[] {
|
||||
const pajzsok = pajzsDB.pajzs.map(x => x as Pajzs)
|
||||
|
||||
switch (o) {
|
||||
case Osztaly2E.Harcos: return pajzsok;
|
||||
case Osztaly2E.Amazon: return pajzsok;
|
||||
case Osztaly2E.Barbar: return pajzsok;
|
||||
case Osztaly2E.Tengeresz: return pajzsok;
|
||||
case Osztaly2E.Ijasz: return pajzsok;
|
||||
case Osztaly2E.Tolvaj: return [];
|
||||
case Osztaly2E.Pap: return pajzsok;
|
||||
case Osztaly2E.Illuzionista: return [];
|
||||
case Osztaly2E.Varazslo: return [];
|
||||
case Osztaly2E.Dalnok: return pajzsok;
|
||||
case Osztaly2E.Druida: return pajzsok.filter(f => f.Id === "pajzs_fa");
|
||||
case Osztaly2E.Vandor: return pajzsok;
|
||||
}
|
||||
}
|
||||
|
||||
export function AllowedPancelTypes(osztalyok: Osztaly2E[]): Pancel[] {
|
||||
return [...new Set(osztalyok.flatMap(osztalyAllowedPancel))]
|
||||
}
|
||||
|
||||
function osztalyAllowedPancel(o: Osztaly2E): Pancel[] {
|
||||
const pancelok = pancelDB.pancel.map(x => x as Pancel)
|
||||
const konnyu = pancelok.filter(x => x.Type === "konnyu")
|
||||
switch (o) {
|
||||
case Osztaly2E.Harcos: return pancelok;
|
||||
case Osztaly2E.Amazon: return konnyu;
|
||||
case Osztaly2E.Barbar: return pancelok;
|
||||
case Osztaly2E.Ijasz: return konnyu;
|
||||
case Osztaly2E.Tengeresz: return konnyu;
|
||||
case Osztaly2E.Pap: return pancelok;
|
||||
case Osztaly2E.Illuzionista: return [];
|
||||
case Osztaly2E.Varazslo: return [];
|
||||
case Osztaly2E.Tolvaj: return konnyu;
|
||||
case Osztaly2E.Dalnok: return konnyu;
|
||||
case Osztaly2E.Druida: return pancelok.filter(f => ['csuha', 'bor', 'kivert_bor', 'prem'].includes(f.Id));
|
||||
case Osztaly2E.Vandor: return konnyu;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,337 @@
|
||||
import {KarakterTulajdonsagok, Tulajdonsag2E} from "./tulajdonsag2E";
|
||||
|
||||
export enum Faj2E {
|
||||
Ember = 'f_2e_ember',
|
||||
Amazon = 'f_2e_amazon',
|
||||
Birodalmi = 'f_2e_birodalmi',
|
||||
Nomad = 'f_2e_nomad',
|
||||
Eszaki = 'f_2e_eszaki',
|
||||
Osember = 'f_2e_osember',
|
||||
Elf = 'f_2e_elf',
|
||||
Felelf = 'f_2e_felelf',
|
||||
Felork = 'f_2e_felork',
|
||||
Felszerzet = 'f_2e_felszerzet',
|
||||
Gnom = 'f_2e_gnom',
|
||||
Torpe = 'f_2e_torpe',
|
||||
}
|
||||
|
||||
export function FajLabel(faj: Faj2E) : string {
|
||||
switch (faj) {
|
||||
case Faj2E.Ember: return 'Ember';
|
||||
case Faj2E.Amazon: return 'Amazon';
|
||||
case Faj2E.Birodalmi: return 'Birodalmi';
|
||||
case Faj2E.Nomad: return 'Nomád';
|
||||
case Faj2E.Eszaki: return 'Északi';
|
||||
case Faj2E.Osember: return 'Ősember';
|
||||
case Faj2E.Elf: return 'Elf';
|
||||
case Faj2E.Felelf: return 'Félelf';
|
||||
case Faj2E.Felork: return 'Félork';
|
||||
case Faj2E.Felszerzet: return 'Félszerzet';
|
||||
case Faj2E.Gnom: return 'Gnóm';
|
||||
case Faj2E.Torpe: return 'Törpe';
|
||||
}
|
||||
}
|
||||
|
||||
export function FajDescription(faj: Faj2E) : string {
|
||||
switch (faj) {
|
||||
case Faj2E.Ember: return "Az emberi népek sokfélesége és szaporasága, valamint a bennük élő felfedezői hajlam és erkölcsi rugalmasság hatására képviselőik majdnem minden földön megtalálhatók. A legtöbb ember a lenti vonásokkal rendelkezik.";
|
||||
case Faj2E.Amazon: return "Bár az amazonok barbár népe igen kis létszámú, harciasságuk miatt mégis félik őket. Az amazonok nyúlánk termetűek, hajuk általában vöröses vagy világosbarna, bőrük világos. Társadalmukban teljes a nőuralom; a férfiakat rabszolgaságban tartják és megtiltják számukra a fegyverek viselését. Képzett tengeri rablók, de a szárazföldön is megállják a helyüket. Az amazon nők kivétel nélkül értenek a harchoz és soha, soha nem hagyják megtorlatlanul az őket ért sérelmeket. Technikailag fejletlenek. Kis erejű passzív pszionikus (elmebeli) képességeik vannak.";
|
||||
case Faj2E.Birodalmi: return "Dekadens, hanyatló birodalmak előkelő lakói. Életüket többnyire dekadens élvezetek habzsolásával, kábítószeres mámorban töltik; soraikban a beltenyészet és a degeneráció miatt gyakoriak az örökletes betegségek. Városaik számtalan titkot és mesés kincseket rejtenek.";
|
||||
case Faj2E.Eszaki: return "Az északi kultúra lételeme a harc és a hajózás. Még nőik is kiválóan forgatják a harci fejszét vagy a hosszú nyelű bárdot, s – bár rabszolgatartók – kegyetlenségnek tartják rabszolgáikat a legelemibb védekező eszközöktől, mint a késtől vagy a rövidkardtól megfosztani, vagy fegyvertelenekre támadni. Ettől eltekintve vérszomjasak, és általában semleges vagy gonosz jelleműek. Testalkatuk magas és erős, hajuk vöröses, szőke vagy világosbarna. A férfiak szakállat vagy bajuszt, a nők hosszú hajat viselnek. A déli vidékeken civilizálatlanságuk és faragatlanságuk miatt gyakran megvetik őket.";
|
||||
case Faj2E.Nomad: return "A lovas nomádok kultúrája mindmáig megőrizte primitívségét. Az alkalomnak megfelelően állattartásból, lovas portyázásból, kereskedésből vagy ezek kombinációjából élnek. Eszközeik is egyszerűek: fegyvereik főleg hosszú lándzsák és íjak, és bár kedvelik a kardokat és láncvérteket, nem jeleskednek azok előállításában (a vas megmunkálását kovácsaik féltett titokként őrzik). Többnyire semleges jelleműek, de otthonuktól elszakadva mindenhol feltalálják magukat, és hajlamosak a gonoszra. A nomádok középtermetűek, bőrük cserzett, hajuk olajos fekete, amit leggyakrabban copfban fognak össze. A férfiak kedvelik a bajusz viseletét." ;
|
||||
case Faj2E.Osember: return "Vad földek primitív őslakói. Máig megőrizték görnyedt tartásukat, szőrös küllemüket és loboncos fekete hajukat. A fémmegmunkálást még sokan nem ismerik, s kőeszközöket – esetleg rezet – használnak. Írásuk egyáltalán nincs. Félistenekként tisztelik hátasaikat, a hatalmas mamutokat. Sokan értelem nélküli vagy gyermeki vadaknak hiszik őket, nagy kárukra: az ősemberekben gyakran lakozik bestiális ravaszság, és a civilizált ember eszközeihez jutva rendkívül veszedelmesek.";
|
||||
case Faj2E.Elf: return "Az elfek szépségükről, 150-200 éves élettartamukról és fejlett civilizációjukról ismertek, amely ötvözi a városi és természeti élet előnyeit. Termetük nyúlánk, vonásaik az embernél finomabbak, de egyben törékenyebbek. Kiváló íjászok és varázslók. Általában visszahúzódók, csak ritkán lépnek kapcsolatba a rövidebb életű népekkel – legjobban az emberekkel és a félszerzetekkel jönnek ki. Jellemük általában kaotikus jó.";
|
||||
case Faj2E.Felelf: return "A félelfek elf és ember szülők gyermekei, akik nem tartoznak egyik közösséghez sem – jellemvonásaik általában az elfekhez húznak, de élettartamuk emberi. Kis számuk miatt nem alkotnak külön nemzetségeket, többségük magányos utazó.";
|
||||
case Faj2E.Felork: return "A félorkok többsége külsejében inkább rút emberre hasonlít (bár termetük gyakran görnyedt, arcvonásaik pedig disznószerűek), belsőleg azonban számos ork vonással rendelkeznek: számítók, magányosak és bizalmatlanok a szebb fajokkal, de legtöbbször fajtársaikkal is. Különösen sok közöttük az orgyilkos és a közönséges gonosztevő; egyikük-másikuk ezt némi mágikus erővel vegyíti. Nem alkotnak különálló közösségeket, életük általában rövid és erőszakos. A legtöbb félork gonosz jellemű.";
|
||||
case Faj2E.Felszerzet: return "A félszerzetek általában megelégszenek a nyugodt vidéki élettel. Termetük az emberi fele, élettartamuk a másfélszerese. Hajlamosak az elhízásra, s lábukat vastag szőr borítja. Általában mezítláb járnak. Mivel lusták és kényelemszeretők, csak ritkán adják fejüket kalandokra – ekkor azonban kiváló tolvajokká válhatnak.";
|
||||
case Faj2E.Gnom: return "A gnómok különösen ritka, elsősorban az embernéppel együtt élő Faj2E. A gnómokat alacsony termetükről, vékony végtagjaikról és tömpe, húsos orrukról lehet fölismerni. Élettartamuk az emberi másfélszerese. A gnómok jó kézművesek és van érzékük a mágiához is – elsősorban az illuzionisták trükkjeihez vonzódnak. A legtöbb gnóm semleges jó vagy semleges jellemű.";
|
||||
case Faj2E.Torpe: return "A törpék elsősorban hegyek között és dombvidékeken élnek. Termetük kicsi, de testük tömzsi és igen szívós. Bozontos szakállat viselnek, amely a férfiak esetén dús és sörteszerű, a nőknél finomabb és ritkásabb. A törpék kiemelkedőek a mindenféle mesterségekben, különösen a fémmunkákban, de harcban is megállják helyüket. Nagy nemzetségekbe szerveződnek és híresek igazságérzetükről, makacsságukról és kapzsiságukról. A legtöbb törpe törvényes jó vagy törvényes semleges jellemű..";
|
||||
}
|
||||
}
|
||||
|
||||
export function FajSpecials(faj : Faj2E) : string[] {
|
||||
switch (faj) {
|
||||
case Faj2E.Ember: return [
|
||||
"A játék kezdetén egy extra képzettséggel kezdenek",
|
||||
"Korlátlanul fejlődhetnek minden osztályban",
|
||||
];
|
||||
case Faj2E.Amazon: return [
|
||||
"+1-et kapnak kezdeményezésükre",
|
||||
"Ha két vagy több amazon együttesen harcol, VO-juk 2-vel nő pszionikus képességeik miatt",
|
||||
"Szintkorlátok: Harcos 9, Pap 5, Tolvaj 3, Varázsló 3",
|
||||
];
|
||||
case Faj2E.Birodalmi: return [
|
||||
"+1 Intelligencia, -1 Egészség",
|
||||
"Egyik kezdő képzettségük mindenképpen az Alkímia, a Méregkeverés vagy az Okkultizmus.",
|
||||
"Szintkorlátok: Harcos 7, Pap 5, Tolvaj 5, Varázsló 9",
|
||||
];
|
||||
case Faj2E.Eszaki: return [
|
||||
"+1 Erő, -1 Bölcsesség",
|
||||
"Az egyik kezdő képzettségük mindenképpen a Hajózás",
|
||||
"-1-et kapnak minden Karizmapróbájukra (népük tagjai között is)",
|
||||
"Szintkorlátok: Harcos 9, Pap 7, Tolvaj 7, Varázsló 3",
|
||||
];
|
||||
case Faj2E.Nomad: return [
|
||||
"+1 Egészség, -1 Bölcsesség",
|
||||
"Az egyik kezdő képzettségük mindenképpen a Lovaglás",
|
||||
"Szintkorlátok: Harcos 9, Pap 5, Tolvaj 7, Varázsló 3",
|
||||
];
|
||||
case Faj2E.Osember: return [
|
||||
"+1 Erő, +1 Egészség, -1 Intelligencia, -1 Bölcsesség",
|
||||
"Szintkorlátok: Harcos -, Pap 5, Tolvaj 4, Varázsló 0",
|
||||
];
|
||||
case Faj2E.Elf: return [
|
||||
"+1 Ügyesség, -1 Egészség",
|
||||
"Immunisak az altató mágiára, +2 mentődobás bűbáj ellen",
|
||||
"Képzettek a hosszúíjak és a hosszúkard használatában akkor is, ha osztályuk ezt nem adná meg nekik",
|
||||
"Az egyik képzettségük mindenképpen a Vadonjárás",
|
||||
"Nem támaszthatók föl",
|
||||
"Szintkorlátok: Harcos 7, Pap 3, Tolvaj 5, Varázsló 7",
|
||||
];
|
||||
case Faj2E.Felelf: return [
|
||||
"Képzettek a hosszúíjak és a hosszúkard használatában akkor is, ha osztályuk ezt nem adná meg nekik",
|
||||
"Az egyik képzettségük mindenképpen a Vadonjárás",
|
||||
"Szintkorlátok: Harcos 9, Pap 5, Tolvaj 9, Varázsló 9",
|
||||
];
|
||||
case Faj2E.Felork: return [
|
||||
"+1 Erő, +1 Egészség, -2 Karizma",
|
||||
"A fenti levonáson túl -1-et kapnak minden Karizmapróbájukra (más félorkokkal szemben is)",
|
||||
"Szintkorlátok: Harcos 7, Pap 5, Tolvaj 7, Varázsló 5",
|
||||
];
|
||||
case Faj2E.Felszerzet: return [
|
||||
"+1 Ügyesség, -1 Erő",
|
||||
"+1 VO-t kapnak kis méretük miatt",
|
||||
"+1 támadást kapnak dobófegyverekre és parittyákra",
|
||||
"Kétkezes közelharci fegyvereket -4 levonással, másfélkezes fegyvereket két kézzel forgathatnak",
|
||||
"Kétszer annyi élelmet kell enniük, mint másoknak",
|
||||
"Szintkorlátok: Harcos 5, Pap 3, Tolvaj 7, Varázsló 3",
|
||||
];
|
||||
case Faj2E.Gnom: return [
|
||||
"+1 Intelligencia, -1 Erő",
|
||||
"+1 VO-t kapnak kis méretük miatt",
|
||||
"+1-et kapnak a mágia elleni mentődobásaikra",
|
||||
"Kétkezes közelharci fegyvereket -4 levonással, másfélkezes fegyvereket két kézzel forgathatnak",
|
||||
"Szintkorlátok: Harcos 3, Pap 3, Tolvaj 5, Varázsló 7",
|
||||
];
|
||||
case Faj2E.Torpe: return [
|
||||
"+1 Egészség, -1 Karizma",
|
||||
"Lassabban mozognak az embereknél, kezdeményezésükre -2-t kapnak",
|
||||
"+2 mentődobást kapnak mérgek, betegségek és varázslatok hatásai ellen",
|
||||
"Az egyik képzettségük mindenképpen az Értékbecslés",
|
||||
"Szintkorlátok: Harcos 7, Pap 5, Tolvaj 5, Varázsló 3",
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
export type Szintkorlatok = Record<string, number> // TODO!! use Osztaly enum, rule fix!
|
||||
|
||||
export interface FajDetails {
|
||||
ID: Faj2E,
|
||||
Label: string,
|
||||
Description: string,
|
||||
Specials: string[],
|
||||
TulajdonsagModifiers: KarakterTulajdonsagok
|
||||
Szintkorlatok: Szintkorlatok
|
||||
}
|
||||
|
||||
export function GetFajDetails(faj: Faj2E): FajDetails {
|
||||
return {
|
||||
ID: faj,
|
||||
Label: FajLabel(faj),
|
||||
Description: FajDescription(faj),
|
||||
Specials: FajSpecials(faj),
|
||||
TulajdonsagModifiers: fajiTulajdonsagModositok(faj),
|
||||
Szintkorlatok: SzintKorlatokFajokra(faj),
|
||||
}
|
||||
}
|
||||
|
||||
// noinspection OverlyComplexFunctionJS,FunctionTooLongJS
|
||||
function tulajdonsagModositokPerFaj(tul: Tulajdonsag2E, faj: Faj2E) : number {
|
||||
switch (faj) {
|
||||
case Faj2E.Birodalmi: switch (tul) {
|
||||
case Tulajdonsag2E.Egeszseg: return -1;
|
||||
case Tulajdonsag2E.Intelligencia: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj2E.Eszaki: switch (tul) {
|
||||
case Tulajdonsag2E.Ero: return +1;
|
||||
case Tulajdonsag2E.Bolcsesseg: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj2E.Nomad: switch (tul) {
|
||||
case Tulajdonsag2E.Egeszseg: return +1;
|
||||
case Tulajdonsag2E.Bolcsesseg: return -1;
|
||||
default: return 0
|
||||
}
|
||||
case Faj2E.Osember: switch (tul) {
|
||||
case Tulajdonsag2E.Ero: return +1;
|
||||
case Tulajdonsag2E.Egeszseg: return +1;
|
||||
case Tulajdonsag2E.Intelligencia: return -1;
|
||||
case Tulajdonsag2E.Bolcsesseg: return -1;
|
||||
default: return 0
|
||||
}
|
||||
case Faj2E.Elf: switch (tul) {
|
||||
case Tulajdonsag2E.Egeszseg: return -1;
|
||||
case Tulajdonsag2E.Ugyesseg: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj2E.Felork: switch (tul) {
|
||||
case Tulajdonsag2E.Ero: return +1;
|
||||
case Tulajdonsag2E.Egeszseg: return +1;
|
||||
case Tulajdonsag2E.Karizma: return -2;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj2E.Felszerzet: switch (tul) {
|
||||
case Tulajdonsag2E.Ero: return -1;
|
||||
case Tulajdonsag2E.Ugyesseg: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj2E.Gnom: switch (tul) {
|
||||
case Tulajdonsag2E.Ero: return -1;
|
||||
case Tulajdonsag2E.Intelligencia: return +1;
|
||||
default: return 0;
|
||||
}
|
||||
case Faj2E.Torpe: switch (tul) {
|
||||
case Tulajdonsag2E.Egeszseg: return +1;
|
||||
case Tulajdonsag2E.Karizma: return -1;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function TulajdonsagModositokFajokra(tul: Tulajdonsag2E) {
|
||||
return (faj: Faj2E) => tulajdonsagModositokPerFaj(tul, faj);
|
||||
}
|
||||
|
||||
export function TulajdonsagokFajjal(tulajdonsagok: KarakterTulajdonsagok, faj: Faj2E): KarakterTulajdonsagok {
|
||||
return {
|
||||
[Tulajdonsag2E.Ero]: tulajdonsagok.t_ero + tulajdonsagModositokPerFaj(Tulajdonsag2E.Ero, faj),
|
||||
[Tulajdonsag2E.Ugyesseg]: tulajdonsagok.t_ugy + tulajdonsagModositokPerFaj(Tulajdonsag2E.Ugyesseg, faj),
|
||||
[Tulajdonsag2E.Egeszseg]: tulajdonsagok.t_egs + tulajdonsagModositokPerFaj(Tulajdonsag2E.Egeszseg, faj),
|
||||
[Tulajdonsag2E.Intelligencia]: tulajdonsagok.t_int + tulajdonsagModositokPerFaj(Tulajdonsag2E.Intelligencia, faj),
|
||||
[Tulajdonsag2E.Bolcsesseg]: tulajdonsagok.t_bol + tulajdonsagModositokPerFaj(Tulajdonsag2E.Bolcsesseg, faj),
|
||||
[Tulajdonsag2E.Karizma]: tulajdonsagok.t_kar + tulajdonsagModositokPerFaj(Tulajdonsag2E.Karizma, faj),
|
||||
}
|
||||
}
|
||||
|
||||
function fajiTulajdonsagModositok(faj: Faj2E): KarakterTulajdonsagok {
|
||||
return {
|
||||
[Tulajdonsag2E.Ero]: TulajdonsagModositokFajokra(Tulajdonsag2E.Ero)(faj),
|
||||
[Tulajdonsag2E.Ugyesseg]: TulajdonsagModositokFajokra(Tulajdonsag2E.Ugyesseg)(faj),
|
||||
[Tulajdonsag2E.Egeszseg]: TulajdonsagModositokFajokra(Tulajdonsag2E.Egeszseg)(faj),
|
||||
[Tulajdonsag2E.Intelligencia]: TulajdonsagModositokFajokra(Tulajdonsag2E.Intelligencia)(faj),
|
||||
[Tulajdonsag2E.Bolcsesseg]: TulajdonsagModositokFajokra(Tulajdonsag2E.Bolcsesseg)(faj),
|
||||
[Tulajdonsag2E.Karizma]: TulajdonsagModositokFajokra(Tulajdonsag2E.Karizma)(faj),
|
||||
}
|
||||
}
|
||||
|
||||
const EmberiSzintKorlatok: Szintkorlatok = {
|
||||
o_amazon: 0,
|
||||
o_barbar: 12,
|
||||
o_harcos: 12,
|
||||
o_ijasz: 12,
|
||||
o_illuzionista: 12,
|
||||
o_kaloz: 12,
|
||||
o_pap: 12,
|
||||
o_tolvaj: 12,
|
||||
o_varazslo: 12
|
||||
|
||||
}
|
||||
|
||||
// noinspection OverlyComplexFunctionJS,FunctionTooLongJS
|
||||
export function SzintKorlatokFajokra(faj: Faj2E) : Szintkorlatok {
|
||||
let szintkorlatok = {...EmberiSzintKorlatok}
|
||||
switch (faj) {
|
||||
case Faj2E.Ember: break;
|
||||
case Faj2E.Amazon:
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 0
|
||||
szintkorlatok.o_illuzionista = 0
|
||||
szintkorlatok.o_varazslo = 0
|
||||
szintkorlatok.o_amazon = 20
|
||||
break
|
||||
case Faj2E.Birodalmi:
|
||||
szintkorlatok.o_harcos = 7
|
||||
szintkorlatok.o_barbar = 7
|
||||
szintkorlatok.o_ijasz = 7
|
||||
szintkorlatok.o_kaloz = 7
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 5
|
||||
break
|
||||
case Faj2E.Eszaki:
|
||||
case Faj2E.Nomad:
|
||||
szintkorlatok.o_pap = 7
|
||||
szintkorlatok.o_illuzionista = 5
|
||||
szintkorlatok.o_varazslo = 5
|
||||
break
|
||||
case Faj2E.Osember:
|
||||
szintkorlatok.o_pap = 7
|
||||
szintkorlatok.o_tolvaj = 4
|
||||
szintkorlatok.o_illuzionista = 0
|
||||
szintkorlatok.o_varazslo = 0
|
||||
break
|
||||
case Faj2E.Elf:
|
||||
szintkorlatok.o_pap = 7
|
||||
szintkorlatok.o_tolvaj = 6
|
||||
szintkorlatok.o_illuzionista = 9
|
||||
szintkorlatok.o_varazslo = 9
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
case Faj2E.Felelf:
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 9
|
||||
szintkorlatok.o_illuzionista = 9
|
||||
szintkorlatok.o_varazslo = 9
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
case Faj2E.Felork:
|
||||
szintkorlatok.o_pap = 5
|
||||
szintkorlatok.o_tolvaj = 9
|
||||
szintkorlatok.o_illuzionista = 5
|
||||
szintkorlatok.o_varazslo = 5
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
case Faj2E.Felszerzet:
|
||||
szintkorlatok.o_pap = 6
|
||||
szintkorlatok.o_tolvaj = 9
|
||||
szintkorlatok.o_illuzionista = 4
|
||||
szintkorlatok.o_varazslo = 4
|
||||
szintkorlatok.o_harcos = 6
|
||||
szintkorlatok.o_barbar = 6
|
||||
szintkorlatok.o_ijasz = 6
|
||||
szintkorlatok.o_kaloz = 6
|
||||
break
|
||||
case Faj2E.Gnom:
|
||||
szintkorlatok.o_pap = 6
|
||||
szintkorlatok.o_tolvaj = 8
|
||||
szintkorlatok.o_illuzionista = 7
|
||||
szintkorlatok.o_varazslo = 7
|
||||
szintkorlatok.o_harcos = 6
|
||||
szintkorlatok.o_barbar = 6
|
||||
szintkorlatok.o_ijasz = 6
|
||||
szintkorlatok.o_kaloz = 6
|
||||
break
|
||||
case Faj2E.Torpe:
|
||||
szintkorlatok.o_pap = 9
|
||||
szintkorlatok.o_tolvaj = 6
|
||||
szintkorlatok.o_illuzionista = 4
|
||||
szintkorlatok.o_varazslo = 4
|
||||
szintkorlatok.o_harcos = 9
|
||||
szintkorlatok.o_barbar = 9
|
||||
szintkorlatok.o_ijasz = 9
|
||||
szintkorlatok.o_kaloz = 9
|
||||
break
|
||||
}
|
||||
return szintkorlatok
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user