@jjlmoya/utils-games-development 1.63.0 → 1.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/category/index.ts +2 -1
- package/src/entries.ts +4 -1
- package/src/index.ts +1 -0
- package/src/tests/locale_completeness.test.ts +2 -2
- package/src/tests/tool_validation.test.ts +2 -2
- package/src/tool/damageFormulaLab/bibliography.astro +24 -0
- package/src/tool/damageFormulaLab/bibliography.ts +10 -0
- package/src/tool/damageFormulaLab/component.astro +178 -0
- package/src/tool/damageFormulaLab/controller.ts +235 -0
- package/src/tool/damageFormulaLab/damage-formula-lab.css +644 -0
- package/src/tool/damageFormulaLab/dom-views.ts +193 -0
- package/src/tool/damageFormulaLab/entry.ts +28 -0
- package/src/tool/damageFormulaLab/evaluator.ts +84 -0
- package/src/tool/damageFormulaLab/expression.ts +191 -0
- package/src/tool/damageFormulaLab/i18n/de.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/en.ts +231 -0
- package/src/tool/damageFormulaLab/i18n/es.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/fr.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/id.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/it.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/ja.ts +182 -0
- package/src/tool/damageFormulaLab/i18n/ko.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/nl.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/pl.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/pt.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/ru.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/sv.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/tr.ts +181 -0
- package/src/tool/damageFormulaLab/i18n/zh.ts +181 -0
- package/src/tool/damageFormulaLab/index.ts +11 -0
- package/src/tool/damageFormulaLab/logic.test.ts +138 -0
- package/src/tool/damageFormulaLab/logic.ts +138 -0
- package/src/tool/damageFormulaLab/model.ts +151 -0
- package/src/tool/damageFormulaLab/seo.astro +13 -0
- package/src/tool/damageFormulaLab/storage.ts +62 -0
- package/src/tool/damageFormulaLab/transfers.ts +89 -0
- package/src/tool/damageFormulaLab/ui.ts +62 -0
- package/src/tools.ts +2 -0
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
FAQPage,
|
|
3
|
+
HowTo,
|
|
4
|
+
SoftwareApplication,
|
|
5
|
+
WithContext,
|
|
6
|
+
} from "schema-dts";
|
|
7
|
+
import type { ToolLocaleContent } from "../../../types";
|
|
8
|
+
import type { DamageFormulaLabUI } from "../ui";
|
|
9
|
+
import { bibliographyEntries } from "../bibliography";
|
|
10
|
+
|
|
11
|
+
const faq = [
|
|
12
|
+
{
|
|
13
|
+
question: "What does the damage formula calculator compare?",
|
|
14
|
+
answer:
|
|
15
|
+
"It runs two safe mathematical expressions against the same combat variables. You can compare damage curves, hit count breakpoints, time to kill, rounding, resistance order, and a two variable attack and defense heatmap without executing JavaScript.",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
question: "Which variables and functions can I use?",
|
|
19
|
+
answer:
|
|
20
|
+
"Available variables are attack, defense, level, power, resistance, flat, criticalChance, and criticalMultiplier. Safe functions are min, max, clamp, abs, sqrt, pow, floor, round, and ceil. Operators include addition, subtraction, multiplication, division, exponentiation, and parentheses.",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
question: "How is time to kill calculated?",
|
|
24
|
+
answer:
|
|
25
|
+
"Hits to kill is target health divided by rounded expected damage, rounded upward. Time to kill is the interval between the first and final hit, so the tool uses hits minus one divided by attacks per second. A one hit kill therefore has a time to kill of zero seconds.",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
question: "Why can resistance order change the result?",
|
|
29
|
+
answer:
|
|
30
|
+
"Applying a flat modifier before percentage resistance also reduces that flat amount. Applying resistance first leaves the later flat modifier untouched. The lab exposes both pipelines because engines and combat designs may intentionally choose different orders.",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
question: "Does a smoother curve mean the game is balanced?",
|
|
34
|
+
answer:
|
|
35
|
+
"No. A curve can reveal cliffs, zero damage zones, and breakpoints, but balance depends on goals, player choices, encounter context, feedback, and playtesting. The lab reports numerical behavior and never presents a universal balance verdict.",
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
const howTo = [
|
|
40
|
+
{
|
|
41
|
+
name: "Choose two formulas",
|
|
42
|
+
text: "Start from the linear, ratio, or level scaled presets, then edit Formula A and Formula B with the documented variables and safe functions.",
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
name: "Set one combat state",
|
|
46
|
+
text: "Enter attack, defense, level, power, resistance, flat adjustment, critical settings, target health, and attack cadence.",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "Make engine rules explicit",
|
|
50
|
+
text: "Choose how damage is rounded and whether resistance applies before or after the flat modifier.",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: "Read curves and breakpoints",
|
|
54
|
+
text: "Compare the impact trajectory, attack sweep, defense heatmap, hit count, time to kill, and diagnostic warnings.",
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: "Preserve the experiment",
|
|
58
|
+
text: "Copy a shareable URL fragment or download the configuration, CSV samples, or chart image. All processing remains in the browser.",
|
|
59
|
+
},
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
const softwareApplication: WithContext<SoftwareApplication> = {
|
|
63
|
+
"@context": "https://schema.org",
|
|
64
|
+
"@type": "SoftwareApplication",
|
|
65
|
+
name: "Damage Formula Lab with TTK Charts",
|
|
66
|
+
applicationCategory: "DeveloperApplication",
|
|
67
|
+
operatingSystem: "Any",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const faqPage: WithContext<FAQPage> = {
|
|
71
|
+
"@context": "https://schema.org",
|
|
72
|
+
"@type": "FAQPage",
|
|
73
|
+
mainEntity: faq.map((item) => ({
|
|
74
|
+
"@type": "Question",
|
|
75
|
+
name: item.question,
|
|
76
|
+
acceptedAnswer: { "@type": "Answer", text: item.answer },
|
|
77
|
+
})),
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
const howToSchema: WithContext<HowTo> = {
|
|
81
|
+
"@context": "https://schema.org",
|
|
82
|
+
"@type": "HowTo",
|
|
83
|
+
name: "How to compare game damage formulas and time to kill",
|
|
84
|
+
step: howTo.map((step) => ({
|
|
85
|
+
"@type": "HowToStep",
|
|
86
|
+
name: step.name,
|
|
87
|
+
text: step.text,
|
|
88
|
+
})),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const content: ToolLocaleContent<DamageFormulaLabUI> = {
|
|
92
|
+
slug: "game-damage-formula-calculator-ttk",
|
|
93
|
+
title: "Damage Formula Lab with TTK Charts",
|
|
94
|
+
description:
|
|
95
|
+
"Compare safe game damage formulas through live curves, attack and defense heatmaps, rounding breakpoints, criticals, hits to kill, and time to kill.",
|
|
96
|
+
ui: {
|
|
97
|
+
onboarding:
|
|
98
|
+
"Write the damage rule you use now, place an alternative beside it, then tune one combat state. The proving ground shows where each formula lands and how it behaves beyond the comfortable middle.",
|
|
99
|
+
localNote: "Private combat model. Formulas and files stay in this browser.",
|
|
100
|
+
formulaDeck: "Formula chamber",
|
|
101
|
+
formulaALabel: "Formula A current model",
|
|
102
|
+
formulaBLabel: "Formula B challenger",
|
|
103
|
+
formulaHint:
|
|
104
|
+
"Variables: attack, defense, level, power, resistance, flat, criticalChance, criticalMultiplier",
|
|
105
|
+
formulaFunctions:
|
|
106
|
+
"Safe functions: min, max, clamp, abs, sqrt, pow, floor, round, ceil",
|
|
107
|
+
presetLinear: "Linear guard",
|
|
108
|
+
presetRatio: "Ratio armor",
|
|
109
|
+
presetLevel: "Level scale",
|
|
110
|
+
combatInputs: "Combat state",
|
|
111
|
+
attackLabel: "Attack",
|
|
112
|
+
defenseLabel: "Defense",
|
|
113
|
+
levelLabel: "Level",
|
|
114
|
+
powerLabel: "Power coefficient",
|
|
115
|
+
resistanceLabel: "Resistance percent",
|
|
116
|
+
flatLabel: "Flat modifier",
|
|
117
|
+
criticalChanceLabel: "Critical chance percent",
|
|
118
|
+
criticalMultiplierLabel: "Critical multiplier",
|
|
119
|
+
healthLabel: "Target health",
|
|
120
|
+
cadenceLabel: "Attacks per second",
|
|
121
|
+
roundingLabel: "Damage rounding",
|
|
122
|
+
roundingNone: "Keep decimals",
|
|
123
|
+
roundingFloor: "Floor",
|
|
124
|
+
roundingRound: "Nearest integer",
|
|
125
|
+
roundingCeil: "Ceiling",
|
|
126
|
+
orderLabel: "Modifier order",
|
|
127
|
+
resistanceFirst: "Resistance then flat",
|
|
128
|
+
flatFirst: "Flat then resistance",
|
|
129
|
+
runLabel: "Live impact comparison",
|
|
130
|
+
resultDamage: "Expected damage",
|
|
131
|
+
resultHits: "Hits to defeat",
|
|
132
|
+
resultTtk: "Time to defeat",
|
|
133
|
+
resultDifference: "Damage gap",
|
|
134
|
+
formulaAName: "Current",
|
|
135
|
+
formulaBName: "Challenger",
|
|
136
|
+
curveTitle: "Attack trajectory",
|
|
137
|
+
curveCaption:
|
|
138
|
+
"Attack sweeps from half to twice the current value while defense stays fixed.",
|
|
139
|
+
heatmapTitle: "Pressure field",
|
|
140
|
+
heatmapCaption:
|
|
141
|
+
"Each tile shows Formula A expected damage across attack and defense combinations.",
|
|
142
|
+
attackAxis: "Attack increases to the right",
|
|
143
|
+
defenseAxis: "Defense increases downward",
|
|
144
|
+
scenariosTitle: "Combat silhouettes",
|
|
145
|
+
scenarioSkirmisher: "Skirmisher",
|
|
146
|
+
scenarioGuardian: "Guardian",
|
|
147
|
+
scenarioBoss: "Boss",
|
|
148
|
+
scenarioCustom: "Current setup",
|
|
149
|
+
diagnosticsTitle: "Breakpoint watch",
|
|
150
|
+
statusBalanced:
|
|
151
|
+
"No numerical hazard detected in this sweep. This is not a balance verdict.",
|
|
152
|
+
exportTitle: "Carry the experiment",
|
|
153
|
+
copyLink: "Copy share link",
|
|
154
|
+
exportCsv: "Download CSV",
|
|
155
|
+
exportJson: "Download JSON",
|
|
156
|
+
importJson: "Import JSON",
|
|
157
|
+
exportPng: "Download chart PNG",
|
|
158
|
+
reset: "Reset model",
|
|
159
|
+
privacyDisclosure:
|
|
160
|
+
"The share link stores configuration in the URL fragment. It is not sent to a server by this tool.",
|
|
161
|
+
limitationDisclosure:
|
|
162
|
+
"Expected critical damage is an average, not a random combat simulation. Animation locks, reloads, misses, status effects, player decisions, and encounter rules are outside this model.",
|
|
163
|
+
importError: "That file is not a compatible damage lab configuration.",
|
|
164
|
+
copiedStatus: "Share link copied to the clipboard.",
|
|
165
|
+
},
|
|
166
|
+
seo: [
|
|
167
|
+
{
|
|
168
|
+
type: "title",
|
|
169
|
+
level: 2,
|
|
170
|
+
text: "Compare game damage formulas before they become combat rules",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
type: "paragraph",
|
|
174
|
+
html: "A damage formula may feel reasonable at one attack and defense pair while collapsing at progression extremes. This lab evaluates two formulas against the same state, then repeats the calculation across a controlled sweep. It makes zero damage regions, sudden jumps, rounding thresholds, and hit count breakpoints visible before the rule is embedded in a game engine.",
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
type: "title",
|
|
178
|
+
level: 2,
|
|
179
|
+
text: "Use a restricted expression language instead of executable code",
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
type: "paragraph",
|
|
183
|
+
html: "The formula field accepts named combat variables, arithmetic operators, parentheses, and a short list of mathematical functions. It does not evaluate JavaScript, access browser APIs, or call arbitrary functions. Division by zero and non finite output become visible errors instead of silently contaminating the chart and exports.",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
type: "table",
|
|
187
|
+
headers: ["Output", "Calculation", "Design question"],
|
|
188
|
+
rows: [
|
|
189
|
+
[
|
|
190
|
+
"Expected damage",
|
|
191
|
+
"Base formula with expected critical factor, modifier order, resistance, and selected rounding",
|
|
192
|
+
"Does the same rule behave sensibly for weak and strong combatants?",
|
|
193
|
+
],
|
|
194
|
+
[
|
|
195
|
+
"Hits to defeat",
|
|
196
|
+
"Target health divided by rounded damage, rounded upward",
|
|
197
|
+
"Where does one stat point remove an entire required hit?",
|
|
198
|
+
],
|
|
199
|
+
[
|
|
200
|
+
"Time to defeat",
|
|
201
|
+
"Intervals between required hits divided by attacks per second",
|
|
202
|
+
"Does cadence create the intended combat rhythm?",
|
|
203
|
+
],
|
|
204
|
+
[
|
|
205
|
+
"Pressure field",
|
|
206
|
+
"Formula A sampled across attack and defense ranges",
|
|
207
|
+
"Are there dead zones, cliffs, or unexpectedly flat regions?",
|
|
208
|
+
],
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
type: "title",
|
|
213
|
+
level: 2,
|
|
214
|
+
text: "Separate arithmetic evidence from a balance verdict",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
type: "paragraph",
|
|
218
|
+
html: "A smooth graph is not proof that combat is fair, expressive, or enjoyable. Numeric relationships only gain meaning beside health, cadence, progression, encounter roles, player options, and the intended experience. Use the lab to find questions worth playtesting, preserve reproducible configurations, and compare implementation rules without presenting one universal formula as correct.",
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
type: "tip",
|
|
222
|
+
title: "Inspect both damage and hit count",
|
|
223
|
+
html: "A small damage change can look harmless on a curve but cross a health breakpoint and remove a full attack. Compare the damage line with hits to defeat and time to defeat whenever you adjust rounding, criticals, resistance, or attack cadence.",
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
faq,
|
|
227
|
+
bibliographyTitle: "Damage modelling references",
|
|
228
|
+
bibliography: bibliographyEntries,
|
|
229
|
+
howTo,
|
|
230
|
+
schemas: [softwareApplication, faqPage, howToSchema],
|
|
231
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
3
|
+
import type { DamageFormulaLabUI } from '../ui';
|
|
4
|
+
import { bibliographyEntries } from '../bibliography';
|
|
5
|
+
|
|
6
|
+
const slug = 'calculadora-formulas-dano-juegos-ttk';
|
|
7
|
+
const title = 'Laboratorio de Fórmulas de Daño y Gráficos TTK';
|
|
8
|
+
const description = 'Compara fórmulas de daño para videojuegos en tiempo real mediante curvas, mapas de calor, puntos de redondeo, críticos y tiempo para derrotar al objetivo (TTK).';
|
|
9
|
+
|
|
10
|
+
const faq = [
|
|
11
|
+
{
|
|
12
|
+
question: '¿Qué compara la calculadora de fórmulas de daño?',
|
|
13
|
+
answer: 'Evalúa dos expresiones matemáticas seguras contra las mismas variables de combate. Permite comparar curvas de daño, saltos en cantidad de golpes, tiempo para derrotar (TTK), reglas de redondeo, orden de resistencias y mapas de calor sin ejecutar JavaScript.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
question: '¿Qué variables y funciones puedo utilizar?',
|
|
17
|
+
answer: 'Las variables disponibles son attack, defense, level, power, resistance, flat, criticalChance y criticalMultiplier. Las funciones seguras son min, max, clamp, abs, sqrt, pow, floor, round y ceil. Admite operadores aritméticos y paréntesis.',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
question: '¿Cómo se calcula el tiempo para derrotar (TTK)?',
|
|
21
|
+
answer: 'Los golpes necesarios resultan de dividir la vida del objetivo entre el daño esperado redondeado (hacia arriba). El TTK mide el intervalo entre el primer y el último golpe, por lo que usa (golpes - 1) / ataques por segundo. Si se elimina de un golpe, el TTK es 0 segundos.',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
question: '¿Por qué influye el orden de aplicación de la resistencia?',
|
|
25
|
+
answer: 'Aplicar un modificador plano antes del porcentaje de resistencia también reduce ese valor plano. Aplicar la resistencia primero deja el modificador plano posterior intacto. El laboratorio expone ambos flujos porque distintos motores de juego eligen reglas diferentes.',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
question: '¿Una curva suave asegura que el juego esté equilibrado?',
|
|
29
|
+
answer: 'No. Una curva revela zonas de daño cero, acantilados y saltos de efectividad, pero el equilibrio depende del contexto del encuentro, roles, ritmo e iteración en pruebas de juego. La herramienta ofrece datos numéricos y nunca un veredicto universal.',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const howTo = [
|
|
34
|
+
{ name: 'Elegir dos fórmulas', text: 'Selecciona una plantilla de partida (lineal, ratio o escalado por nivel) o escribe tus propias fórmulas A y B.' },
|
|
35
|
+
{ name: 'Ajustar el estado de combate', text: 'Ingresa los valores de ataque, defensa, nivel, coeficiente de poder, porcentaje de resistencia, modificador plano, críticos, vida y cadencia.' },
|
|
36
|
+
{ name: 'Definir las reglas del motor', text: 'Configura cómo se redondea el daño y si la resistencia se aplica antes o después del modificador plano.' },
|
|
37
|
+
{ name: 'Analizar curvas y umbrales', text: 'Compara la trayectoria del impacto, el barrido de ataque, el mapa de calor defensivo, los golpes necesarios y los avisos de diagnóstico.' },
|
|
38
|
+
{ name: 'Preservar el experimento', text: 'Copia un enlace compartible o descarga la configuración en JSON, la tabla en CSV o la imagen PNG del gráfico.' },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const softwareApplication: WithContext<SoftwareApplication> = {
|
|
42
|
+
'@context': 'https://schema.org',
|
|
43
|
+
'@type': 'SoftwareApplication',
|
|
44
|
+
name: title,
|
|
45
|
+
applicationCategory: 'DeveloperApplication',
|
|
46
|
+
operatingSystem: 'Any',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const faqPage: WithContext<FAQPage> = {
|
|
50
|
+
'@context': 'https://schema.org',
|
|
51
|
+
'@type': 'FAQPage',
|
|
52
|
+
mainEntity: faq.map((item) => ({
|
|
53
|
+
'@type': 'Question',
|
|
54
|
+
name: item.question,
|
|
55
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
56
|
+
})),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const howToSchema: WithContext<HowTo> = {
|
|
60
|
+
'@context': 'https://schema.org',
|
|
61
|
+
'@type': 'HowTo',
|
|
62
|
+
name: title,
|
|
63
|
+
step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const content: ToolLocaleContent<DamageFormulaLabUI> = {
|
|
67
|
+
slug,
|
|
68
|
+
title,
|
|
69
|
+
description,
|
|
70
|
+
ui: {
|
|
71
|
+
onboarding: 'Escribe la regla de daño actual, coloca una alternativa al lado y ajusta el estado de combate. El laboratorio muestra cómo se comportan ambas fórmulas en los extremos de progresión.',
|
|
72
|
+
localNote: 'Modelo de combate privado. Las fórmulas y archivos se mantienen en este navegador.',
|
|
73
|
+
formulaDeck: 'Cámara de fórmulas',
|
|
74
|
+
formulaALabel: 'Fórmula A (Modelo actual)',
|
|
75
|
+
formulaBLabel: 'Fórmula B (Alternativa)',
|
|
76
|
+
formulaHint: 'Variables: attack, defense, level, power, resistance, flat, criticalChance, criticalMultiplier',
|
|
77
|
+
formulaFunctions: 'Funciones seguras: min, max, clamp, abs, sqrt, pow, floor, round, ceil',
|
|
78
|
+
presetLinear: 'Protección lineal',
|
|
79
|
+
presetRatio: 'Armadura por ratio',
|
|
80
|
+
presetLevel: 'Escalado por nivel',
|
|
81
|
+
combatInputs: 'Estado de combate',
|
|
82
|
+
attackLabel: 'Ataque',
|
|
83
|
+
defenseLabel: 'Defensa',
|
|
84
|
+
levelLabel: 'Nivel',
|
|
85
|
+
powerLabel: 'Coeficiente de poder',
|
|
86
|
+
resistanceLabel: 'Porcentaje de resistencia',
|
|
87
|
+
flatLabel: 'Modificador plano',
|
|
88
|
+
criticalChanceLabel: 'Probabilidad de crítico (%)',
|
|
89
|
+
criticalMultiplierLabel: 'Multiplicador de crítico',
|
|
90
|
+
healthLabel: 'Vida del objetivo',
|
|
91
|
+
cadenceLabel: 'Ataques por segundo',
|
|
92
|
+
roundingLabel: 'Redondeo del daño',
|
|
93
|
+
roundingNone: 'Conservar decimales',
|
|
94
|
+
roundingFloor: 'Redondear hacia abajo (Floor)',
|
|
95
|
+
roundingRound: 'Entero más cercano',
|
|
96
|
+
roundingCeil: 'Redondear hacia arriba (Ceil)',
|
|
97
|
+
orderLabel: 'Orden de modificadores',
|
|
98
|
+
resistanceFirst: 'Resistencia y luego plano',
|
|
99
|
+
flatFirst: 'Plano y luego resistencia',
|
|
100
|
+
runLabel: 'Comparativa de impacto en vivo',
|
|
101
|
+
resultDamage: 'Daño esperado',
|
|
102
|
+
resultHits: 'Golpes para derrotar',
|
|
103
|
+
resultTtk: 'Tiempo para derrotar (TTK)',
|
|
104
|
+
resultDifference: 'Diferencia de daño',
|
|
105
|
+
formulaAName: 'Actual',
|
|
106
|
+
formulaBName: 'Alternativa',
|
|
107
|
+
curveTitle: 'Trayectoria por nivel de ataque',
|
|
108
|
+
curveCaption: 'El ataque se barre desde la mitad hasta el doble del valor actual mientras la defensa se mantiene fija.',
|
|
109
|
+
heatmapTitle: 'Campo de presión',
|
|
110
|
+
heatmapCaption: 'Cada celda muestra el daño esperado de la Fórmula A en combinaciones de ataque y defensa.',
|
|
111
|
+
attackAxis: 'El ataque aumenta hacia la derecha',
|
|
112
|
+
defenseAxis: 'La defensa aumenta hacia abajo',
|
|
113
|
+
scenariosTitle: 'Siluetas de combate',
|
|
114
|
+
scenarioSkirmisher: 'Hostigador',
|
|
115
|
+
scenarioGuardian: 'Guardián',
|
|
116
|
+
scenarioBoss: 'Jefe final',
|
|
117
|
+
scenarioCustom: 'Ajuste actual',
|
|
118
|
+
diagnosticsTitle: 'Puntos críticos y saltos',
|
|
119
|
+
statusBalanced: 'No se detectan anomalías numéricas en este barrido. Esto no constituye un veredicto de equilibrio.',
|
|
120
|
+
exportTitle: 'Exportar experimento',
|
|
121
|
+
copyLink: 'Copiar enlace compartible',
|
|
122
|
+
exportCsv: 'Descargar CSV',
|
|
123
|
+
exportJson: 'Descargar JSON',
|
|
124
|
+
importJson: 'Importar JSON',
|
|
125
|
+
exportPng: 'Descargar gráfico PNG',
|
|
126
|
+
reset: 'Restablecer modelo',
|
|
127
|
+
privacyDisclosure: 'El enlace compartible guarda la configuración en el fragmento de la URL y no se envía a servidores.',
|
|
128
|
+
limitationDisclosure: 'El daño crítico esperado es un promedio y no una simulación estocástica. Bloqueos de animación, recargas, fallos y estados no están incluidos.',
|
|
129
|
+
importError: 'El archivo seleccionado no es una configuración válida del laboratorio de daño.',
|
|
130
|
+
copiedStatus: 'Enlace compartible copiado al portapapeles.',
|
|
131
|
+
},
|
|
132
|
+
seo: [
|
|
133
|
+
{
|
|
134
|
+
type: 'title',
|
|
135
|
+
level: 2,
|
|
136
|
+
text: 'Compara fórmulas de daño en juegos antes de integrarlas en tu motor',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
type: 'paragraph',
|
|
140
|
+
html: 'Una fórmula de daño puede parecer equilibrada en un par concreto de ataque y defensa pero romperse en los extremos de la progresión. Este laboratorio evalúa dos fórmulas contra el mismo estado y analiza su comportamiento a lo largo de un rango controlado, asegurando que las anomalías sean visibles antes de programar las reglas.',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
type: 'title',
|
|
144
|
+
level: 2,
|
|
145
|
+
text: 'Lenguaje de expresiones restringido y seguro',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: 'paragraph',
|
|
149
|
+
html: 'El campo de fórmula acepta variables numéricas con nombre, operadores aritméticos y funciones matemáticas estándar. No evalúa código JavaScript ejecutable, evitando riesgos de seguridad y permitiendo la estabilidad de las gráficas.',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: 'table',
|
|
153
|
+
headers: ['Métrica', 'Cálculo realizado', 'Pregunta de diseño'],
|
|
154
|
+
rows: [
|
|
155
|
+
['Daño esperado', 'Fórmula base con factor de crítico esperado, orden de modificadores y redondeo', '¿La regla responde de forma coherente en personajes débiles y fuertes?'],
|
|
156
|
+
['Golpes para derrotar', 'Vida del objetivo dividida entre el daño redondeado (hacia arriba)', '¿Un solo punto de estadística elimina un golpe completo requerido?'],
|
|
157
|
+
['Tiempo para derrotar (TTK)', 'Intervalos entre golpes divididos entre los ataques por segundo', '¿La cadencia crea el ritmo de combate deseado?'],
|
|
158
|
+
['Campo de presión', 'Muestra de la Fórmula A en combinaciones de ataque y defensa', '¿Existen zonas muertas, acantilados o mesetas inesperadas?'],
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: 'title',
|
|
163
|
+
level: 2,
|
|
164
|
+
text: 'Diferenciar la evidencia aritmética del veredicto de diseño',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: 'paragraph',
|
|
168
|
+
html: 'Un gráfico limpio no demuestra por sí solo que un combate sea divertido o justo. Las relaciones numéricas adquieren significado al contrastarse con los roles de combate, la curva de nivel y las pruebas con jugadores.',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
type: 'tip',
|
|
172
|
+
title: 'Examina tanto el daño por impacto como la cantidad de golpes',
|
|
173
|
+
html: 'Un cambio pequeño en la cifra de daño puede parecer insignificante en la curva pero cruzar un umbral de vida y reducir un golpe entero. Compara siempre el daño con los golpes para derrotar y el TTK.',
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
faq,
|
|
177
|
+
bibliographyTitle: 'Referencias de diseño de combate y matemáticas',
|
|
178
|
+
bibliography: bibliographyEntries,
|
|
179
|
+
howTo,
|
|
180
|
+
schemas: [softwareApplication, faqPage, howToSchema],
|
|
181
|
+
};
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import type { FAQPage, HowTo, SoftwareApplication, WithContext } from 'schema-dts';
|
|
2
|
+
import type { ToolLocaleContent } from '../../../types';
|
|
3
|
+
import type { DamageFormulaLabUI } from '../ui';
|
|
4
|
+
import { bibliographyEntries } from '../bibliography';
|
|
5
|
+
|
|
6
|
+
const slug = 'calculateur-formules-degats-jeux-ttk';
|
|
7
|
+
const title = 'Laboratoire de Formules de Dégâts et Graphiques TTK';
|
|
8
|
+
const description = 'Comparez des formules de dégâts pour jeux vidéo avec des courbes en direct, cartes thermiques, arrondis, coups critiques et temps pour éliminer (TTK).';
|
|
9
|
+
|
|
10
|
+
const faq = [
|
|
11
|
+
{
|
|
12
|
+
question: 'Que permet de comparer ce calculateur de dégâts ?',
|
|
13
|
+
answer: 'Il évalue deux expressions mathématiques sécurisées face aux mêmes variables de combat. Vous pouvez comparer les courbes de dégâts, les seuils de coups, le temps pour éliminer (TTK), le comportement de l arrondi et l ordre d application des résistances.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
question: 'Quelles variables et fonctions sont disponibles ?',
|
|
17
|
+
answer: 'Les variables disponibles sont attack, defense, level, power, resistance, flat, criticalChance et criticalMultiplier. Les fonctions sécurisées sont min, max, clamp, abs, sqrt, pow, floor, round et ceil.',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
question: 'Comment le temps pour éliminer (TTK) est-il calculé ?',
|
|
21
|
+
answer: 'Le nombre de coups nécessaires est la santé de la cible divisée par les dégâts attendus arrondis (arrondi au supérieur). Le TTK mesure l intervalle entre le premier et le dernier coup: (coups - 1) / attaques par seconde.',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
question: 'Pourquoi l ordre d application de la résistance est-il important ?',
|
|
25
|
+
answer: 'Appliquer un modificateur plat avant la résistance en pourcentage réduit également ce montant plat. Appliquer la résistance en premier laisse le modificateur plat intact. Le laboratoire permet de tester les deux configurations.',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
question: 'Une courbe régulière garantit-elle un équilibre parfait ?',
|
|
29
|
+
answer: 'Non. Une courbe permet de détecter des seuils et des zones à dégâts nuls, mais l équilibrage dépend du contexte de jeu, des rôles et des tests utilisateurs.',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
const howTo = [
|
|
34
|
+
{ name: 'Choisir deux formules', text: 'Partez d un modèle prédéfini (linéaire, ratio ou niveau) ou saisissez vos propres formules A et B.' },
|
|
35
|
+
{ name: 'Régler l état de combat', text: 'Ajustez les valeurs d attaque, défense, niveau, puissance, résistance, dégâts plats, critiques, santé et cadence.' },
|
|
36
|
+
{ name: 'Définir les règles du moteur', text: 'Choisissez le mode d arrondi et précisez si la résistance s applique avant ou après le modificateur plat.' },
|
|
37
|
+
{ name: 'Analyser les courbes et seuils', text: 'Observez la trajectoire de l attaque, la carte thermique, les coups nécessaires et les alertes de diagnostic.' },
|
|
38
|
+
{ name: 'Exporter l expérience', text: 'Copiez un lien de partage ou téléchargez la configuration en JSON, le tableau CSV ou l image PNG du graphique.' },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const softwareApplication: WithContext<SoftwareApplication> = {
|
|
42
|
+
'@context': 'https://schema.org',
|
|
43
|
+
'@type': 'SoftwareApplication',
|
|
44
|
+
name: title,
|
|
45
|
+
applicationCategory: 'DeveloperApplication',
|
|
46
|
+
operatingSystem: 'Any',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
const faqPage: WithContext<FAQPage> = {
|
|
50
|
+
'@context': 'https://schema.org',
|
|
51
|
+
'@type': 'FAQPage',
|
|
52
|
+
mainEntity: faq.map((item) => ({
|
|
53
|
+
'@type': 'Question',
|
|
54
|
+
name: item.question,
|
|
55
|
+
acceptedAnswer: { '@type': 'Answer', text: item.answer },
|
|
56
|
+
})),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const howToSchema: WithContext<HowTo> = {
|
|
60
|
+
'@context': 'https://schema.org',
|
|
61
|
+
'@type': 'HowTo',
|
|
62
|
+
name: title,
|
|
63
|
+
step: howTo.map((step) => ({ '@type': 'HowToStep', name: step.name, text: step.text })),
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export const content: ToolLocaleContent<DamageFormulaLabUI> = {
|
|
67
|
+
slug,
|
|
68
|
+
title,
|
|
69
|
+
description,
|
|
70
|
+
ui: {
|
|
71
|
+
onboarding: 'Saisissez votre formule actuelle, placez une alternative en regard et ajustez les paramètres de combat.',
|
|
72
|
+
localNote: 'Modèle privé. Les formules restent dans votre navigateur.',
|
|
73
|
+
formulaDeck: 'Espace des formules',
|
|
74
|
+
formulaALabel: 'Formule A (Modèle actuel)',
|
|
75
|
+
formulaBLabel: 'Formule B (Alternative)',
|
|
76
|
+
formulaHint: 'Variables: attack, defense, level, power, resistance, flat, criticalChance, criticalMultiplier',
|
|
77
|
+
formulaFunctions: 'Fonctions: min, max, clamp, abs, sqrt, pow, floor, round, ceil',
|
|
78
|
+
presetLinear: 'Protection linéaire',
|
|
79
|
+
presetRatio: 'Armure par ratio',
|
|
80
|
+
presetLevel: 'Échelle de niveau',
|
|
81
|
+
combatInputs: 'Paramètres de combat',
|
|
82
|
+
attackLabel: 'Attaque',
|
|
83
|
+
defenseLabel: 'Défense',
|
|
84
|
+
levelLabel: 'Niveau',
|
|
85
|
+
powerLabel: 'Coefficient de puissance',
|
|
86
|
+
resistanceLabel: 'Résistance (%)',
|
|
87
|
+
flatLabel: 'Modificateur plat',
|
|
88
|
+
criticalChanceLabel: 'Chances de coup critique (%)',
|
|
89
|
+
criticalMultiplierLabel: 'Multiplicateur critique',
|
|
90
|
+
healthLabel: 'Santé de la cible',
|
|
91
|
+
cadenceLabel: 'Attaques par seconde',
|
|
92
|
+
roundingLabel: 'Arrondi des dégâts',
|
|
93
|
+
roundingNone: 'Conserver les décimales',
|
|
94
|
+
roundingFloor: 'Arrondi inférieur (Floor)',
|
|
95
|
+
roundingRound: 'Entier le plus proche',
|
|
96
|
+
roundingCeil: 'Arrondi supérieur (Ceil)',
|
|
97
|
+
orderLabel: 'Ordre des modificateurs',
|
|
98
|
+
resistanceFirst: 'Résistance puis plat',
|
|
99
|
+
flatFirst: 'Plat puis résistance',
|
|
100
|
+
runLabel: 'Comparaison en direct',
|
|
101
|
+
resultDamage: 'Dégâts attendus',
|
|
102
|
+
resultHits: 'Coups nécessaires',
|
|
103
|
+
resultTtk: 'Temps pour éliminer (TTK)',
|
|
104
|
+
resultDifference: 'Écart de dégâts',
|
|
105
|
+
formulaAName: 'Actuel',
|
|
106
|
+
formulaBName: 'Alternative',
|
|
107
|
+
curveTitle: 'Trajectoire de l attaque',
|
|
108
|
+
curveCaption: 'L attaque varie de la moitié au double de sa valeur pendant que la défense reste fixe.',
|
|
109
|
+
heatmapTitle: 'Carte thermique de pression',
|
|
110
|
+
heatmapCaption: 'Chaque case montre les dégâts attendus de la Formule A selon l attaque et la défense.',
|
|
111
|
+
attackAxis: 'L attaque augmente vers la droite',
|
|
112
|
+
defenseAxis: 'La défense augmente vers le bas',
|
|
113
|
+
scenariosTitle: 'Profils de combat',
|
|
114
|
+
scenarioSkirmisher: 'Escrimeur',
|
|
115
|
+
scenarioGuardian: 'Gardien',
|
|
116
|
+
scenarioBoss: 'Boss',
|
|
117
|
+
scenarioCustom: 'Configuration actuelle',
|
|
118
|
+
diagnosticsTitle: 'Points de rupture',
|
|
119
|
+
statusBalanced: 'Aucune anomalie mathématique détectée sur cette plage d essai.',
|
|
120
|
+
exportTitle: 'Exporter le projet',
|
|
121
|
+
copyLink: 'Copier le lien',
|
|
122
|
+
exportCsv: 'Télécharger le CSV',
|
|
123
|
+
exportJson: 'Télécharger le JSON',
|
|
124
|
+
importJson: 'Importer un JSON',
|
|
125
|
+
exportPng: 'Télécharger le PNG du graphique',
|
|
126
|
+
reset: 'Réinitialiser le modèle',
|
|
127
|
+
privacyDisclosure: 'Le lien de partage enregistre la configuration dans le fragment d URL sans envoi vers un serveur.',
|
|
128
|
+
limitationDisclosure: 'Les dégâts critiques attendus sont une moyenne et non une simulation aléatoire.',
|
|
129
|
+
importError: 'Ce fichier n est pas une configuration valide.',
|
|
130
|
+
copiedStatus: 'Lien copié dans le presse-papier.',
|
|
131
|
+
},
|
|
132
|
+
seo: [
|
|
133
|
+
{
|
|
134
|
+
type: 'title',
|
|
135
|
+
level: 2,
|
|
136
|
+
text: 'Tester les formules de dégâts avant de les intégrer au moteur',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
type: 'paragraph',
|
|
140
|
+
html: 'Une formule de dégâts peut sembler équilibrée sur quelques valeurs moyennes mais générer des absurdités aux extrêmes. Ce laboratoire permet de détecter rapidement les zones mortes et les décalages de puissance.',
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
type: 'title',
|
|
144
|
+
level: 2,
|
|
145
|
+
text: 'Un langage d évaluation sécurisé et restreint',
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
type: 'paragraph',
|
|
149
|
+
html: 'Le champ de saisie accepte uniquement des variables prédéfinies et des fonctions mathématiques sûres sans exécuter de code arbitraire.',
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
type: 'table',
|
|
153
|
+
headers: ['Indicateur', 'Calcul effectué', 'Question de design'],
|
|
154
|
+
rows: [
|
|
155
|
+
['Dégâts attendus', 'Formule de base incluant le facteur critique et l ordre de résistance', 'La formule reste-t-elle cohérente sur des personnages faibles et puissants ?'],
|
|
156
|
+
['Coups nécessaires', 'Santé de la cible divisée par les dégâts arrondis', 'Un point de stat supplémentaire fait-il disparaître un coup entier ?'],
|
|
157
|
+
['Temps pour éliminer (TTK)', 'Intervalle entre les coups divisé par la cadence d attaque', 'La cadence crée-t-elle le rythme de jeu souhaité ?'],
|
|
158
|
+
['Carte thermique', 'Échantillonnage de la Formule A sur l attaque et la défense', 'Existe-t-il des seuils ou des ruptures anormales ?'],
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
type: 'title',
|
|
163
|
+
level: 2,
|
|
164
|
+
text: 'Séparer la logique mathématique des choix d équilibrage',
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
type: 'paragraph',
|
|
168
|
+
html: 'Une courbe fluide n est pas une preuve de plaisir de jeu. Utilisez ce laboratoire pour identifier les valeurs à tester lors des sessions de playtest.',
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
type: 'tip',
|
|
172
|
+
title: 'Observer conjointement les dégâts et le nombre de coups',
|
|
173
|
+
html: 'Une légère variation de dégâts peut franchir un seuil de santé et supprimer un coup complet. Comparez toujours les dégâts avec le nombre de coups et le TTK.',
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
faq,
|
|
177
|
+
bibliographyTitle: 'Références sur la modélisation des dégâts',
|
|
178
|
+
bibliography: bibliographyEntries,
|
|
179
|
+
howTo,
|
|
180
|
+
schemas: [softwareApplication, faqPage, howToSchema],
|
|
181
|
+
};
|