diff --git a/.gitignore b/.gitignore index 1ca480e25..b7cb775af 100644 --- a/.gitignore +++ b/.gitignore @@ -19,5 +19,4 @@ dump /scripts/output/* !/scripts/output/.gitkeep -/scripts/dicts/*.json -/scripts/dicts/langs/*.json \ No newline at end of file +/scripts/dicts/**/*.json \ No newline at end of file diff --git a/.nvmrc b/.nvmrc index f274881e5..37e391feb 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.16.0 +v16.17.0 diff --git a/README.md b/README.md index b03fb9a7f..156bd08cf 100644 --- a/README.md +++ b/README.md @@ -8,22 +8,18 @@ Prerequisites: [nvm](https://github.com/nvm-sh/nvm) There is a sequence of commands you need to run: -1. `nvm use` to switch to the correct Node version. If you have problems with nvm you can also install the latest LTS version of Node.js from [their website](https://nodejs.org/en/). +1. `nvm use` to switch to the correct Node version. If you don't have the correct Node.js version yet it will prompt you to install it via the `nvm install` command. If you have problems with nvm you can also install the latest LTS version of Node.js from [their website](https://nodejs.org/en/). 2. `npm i` to install the dependencies. -3. Make a copy of `.env.example` that's called `.env`. See below for note about environment variables. +3. Make a copy of `.env.example` that's called `.env`. Filling additional values is not necessary unless you want to use real Discord auth or develop Lohi bot. 4. `npm run migrate up` to set up the database tables. -5. `npm run seed` to fill database with test data. -6. `npm run dev` to run the project in development mode. +5. `npm run dev` to run the project in development mode. +6. Navigate to `http://localhost:5800/admin`. There press the seed button to fill the DB with test data. You can also impersonate any user (Sendou#0043 = admin). And if you want to run the E2E tests: 6. Make a copy of the `db.sqlite3` file created by migration and name it `db-cypress.sqlite3`. 7. `npm run dev:cypress` and `npm run cy:open` can be used to run the E2E tests. -#### Environment variables - -You don't need to fill the missing values from `.env.example` to get started. Instead of using real auth via Discord you can "impersonate" the admin (=Sendou#0043) or any other use in the /admin page once the project has started up. `LOHI_TOKEN` is only needed for bot + sendou.ink interoperability. - ## Lohi TODO: instructions on how to develop Lohi locally diff --git a/app/components/AbilitiesSelector.tsx b/app/components/AbilitiesSelector.tsx index 85d4909c1..cfb059ce3 100644 --- a/app/components/AbilitiesSelector.tsx +++ b/app/components/AbilitiesSelector.tsx @@ -37,7 +37,7 @@ export function AbilitiesSelector({ onChange(abilitiesClone); }; const onButtonClick = (ability: typeof abilities[number]) => { - onChange(addAbility({ oldAbilites: selectedAbilities, ability })); + onChange(addAbility({ oldAbilities: selectedAbilities, ability })); }; return ( @@ -77,14 +77,14 @@ export function AbilitiesSelector({ } function addAbility({ - oldAbilites, + oldAbilities, ability, }: { - oldAbilites: BuildAbilitiesTupleWithUnknown; + oldAbilities: BuildAbilitiesTupleWithUnknown; ability: typeof abilities[number]; }): BuildAbilitiesTupleWithUnknown { const abilitiesClone = JSON.parse( - JSON.stringify(oldAbilites) + JSON.stringify(oldAbilities) ) as BuildAbilitiesTupleWithUnknown; for (const [i, row] of abilitiesClone.entries()) { diff --git a/app/components/BuildCard.tsx b/app/components/BuildCard.tsx index 6c7511701..55a2dadc9 100644 --- a/app/components/BuildCard.tsx +++ b/app/components/BuildCard.tsx @@ -9,7 +9,7 @@ import type { } from "~/modules/in-game-lists"; import type { BuildAbilitiesTuple } from "~/modules/in-game-lists/types"; import { databaseTimestampToDate } from "~/utils/dates"; -import { gearImageUrl, modeImageUrl, weaponImageUrl } from "~/utils/urls"; +import { gearImageUrl, modeImageUrl, mainWeaponImageUrl } from "~/utils/urls"; import { Ability } from "./Ability"; import { Button, LinkButton } from "./Button"; import { FormWithConfirm } from "./FormWithConfirm"; @@ -128,7 +128,7 @@ export function BuildCard({ {weapons.map((weaponSplId) => (
{t(`weapons:${weaponSplId}` - {t(`weapons:${weapons[0]!}` as any)} + {t(`weapons:MAIN_${weapons[0]!}` as any)}
)} diff --git a/app/components/Combobox.tsx b/app/components/Combobox.tsx index b1c48472a..b1700a267 100644 --- a/app/components/Combobox.tsx +++ b/app/components/Combobox.tsx @@ -10,9 +10,9 @@ import { clothesGearIds, headGearIds, shoesGearIds, - weaponIds, + mainWeaponIds, } from "~/modules/in-game-lists"; -import { gearImageUrl, weaponImageUrl } from "~/utils/urls"; +import { gearImageUrl, mainWeaponImageUrl } from "~/utils/urls"; import { Image } from "./Image"; const MAX_RESULTS_SHOWN = 6; @@ -33,6 +33,7 @@ interface ComboboxProps { isLoading?: boolean; required?: boolean; initialValue?: ComboboxOption; + clearsInputOnFocus?: boolean; onChange?: (selectedOption?: ComboboxOption) => void; } @@ -41,6 +42,7 @@ export function Combobox>({ inputName, placeholder, initialValue, + clearsInputOnFocus = false, onChange, required, className, @@ -49,10 +51,13 @@ export function Combobox>({ }: ComboboxProps) { const [selectedOption, setSelectedOption] = React.useState>(); + const [lastSelectedOption, setLastSelectedOption] = + React.useState>(); const [query, setQuery] = React.useState(""); React.useEffect(() => { setSelectedOption(initialValue); + setLastSelectedOption(initialValue); }, [initialValue]); const filteredOptions = (() => { @@ -75,16 +80,27 @@ export function Combobox>({ onChange={(selected) => { onChange?.(selected); setSelectedOption(selected); + setLastSelectedOption(selected); }} name={inputName} disabled={isLoading} > { + if (clearsInputOnFocus) { + setSelectedOption(undefined); + } + }} + onBlur={() => { + if (!selectedOption && clearsInputOnFocus) { + setSelectedOption(lastSelectedOption); + } + }} onChange={(event) => setQuery(event.target.value)} placeholder={isLoading ? "Loading..." : placeholder} className={clsx("combobox-input", className)} displayValue={(option) => - (option as Unpacked)?.label ?? "" + (option as unknown as Unpacked)?.label ?? "" } data-cy={`${inputName}-combobox-input`} id={id} @@ -192,28 +208,39 @@ export function WeaponCombobox({ inputName, onChange, initialWeaponId, + clearsInputOnFocus, }: Pick< ComboboxProps, - "inputName" | "onChange" | "className" | "id" | "required" -> & { initialWeaponId?: typeof weaponIds[number] }) { + | "inputName" + | "onChange" + | "className" + | "id" + | "required" + | "clearsInputOnFocus" +> & { initialWeaponId?: typeof mainWeaponIds[number] }) { const { t } = useTranslation("weapons"); - const idToWeapon = (id: typeof weaponIds[number]) => ({ + const idToWeapon = (id: typeof mainWeaponIds[number]) => ({ value: String(id), - label: t(`${id}`), - imgPath: weaponImageUrl(id), + label: t(`MAIN_${id}`), + imgPath: mainWeaponImageUrl(id), }); return ( ); } diff --git a/app/components/Label.tsx b/app/components/Label.tsx index 0f420d896..828456dc7 100644 --- a/app/components/Label.tsx +++ b/app/components/Label.tsx @@ -12,6 +12,7 @@ type LabelProps = Pick< max: number; }; required?: boolean; + className?: string; }; export function Label({ @@ -19,9 +20,10 @@ export function Label({ required, children, htmlFor, + className, }: LabelProps) { return ( -
+
diff --git a/app/components/Toggle.tsx b/app/components/Toggle.tsx new file mode 100644 index 000000000..72afdf10e --- /dev/null +++ b/app/components/Toggle.tsx @@ -0,0 +1,22 @@ +import { Switch } from "@headlessui/react"; +import clsx from "clsx"; + +export function Toggle({ + checked, + setChecked, + tiny, +}: { + checked: boolean; + setChecked: (checked: boolean) => void; + tiny?: boolean; +}) { + return ( + + + + ); +} diff --git a/app/constants.ts b/app/constants.ts index a9ad97def..442b909e7 100644 --- a/app/constants.ts +++ b/app/constants.ts @@ -1,5 +1,6 @@ import allTags from "~/routes/calendar/tags.json"; import type { CalendarEventTag } from "./db/types"; +import type { BuildAbilitiesTupleWithUnknown } from "./modules/in-game-lists"; export const TWEET_LENGTH_MAX_LENGTH = 280; export const DISCORD_MESSAGE_MAX_LENGTH = 2000; @@ -14,7 +15,7 @@ export const CALENDAR_EVENT = { NAME_MAX_LENGTH: 100, DESCRIPTION_MAX_LENGTH: DISCORD_MESSAGE_MAX_LENGTH, DISCORD_INVITE_CODE_MAX_LENGTH: 50, - BRACKET_URL_MAX_LENGTH: 100, + BRACKET_URL_MAX_LENGTH: 200, MAX_AMOUNT_OF_DATES: 5, TAGS: Object.keys(allTags) as Array, }; @@ -35,6 +36,12 @@ export const BUILD = { MAX_COUNT: 250, } as const; +export const EMPTY_BUILD: BuildAbilitiesTupleWithUnknown = [ + ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"], + ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"], + ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"], +]; + export const PLUS_TIERS = [1, 2, 3]; export const PLUS_UPVOTE = 1; diff --git a/app/db/models/users/upsert.sql b/app/db/models/users/upsert.sql index 02af168d0..6498811cb 100644 --- a/app/db/models/users/upsert.sql +++ b/app/db/models/users/upsert.sql @@ -24,5 +24,5 @@ set "discordDiscriminator" = excluded."discordDiscriminator", "discordAvatar" = excluded."discordAvatar", "twitch" = excluded."twitch", - "twitch" = excluded."twitch", - "youtubeId" = excluded."youtubeId" returning * \ No newline at end of file + "twitter" = excluded."twitter", + "youtubeId" = excluded."youtubeId" returning * diff --git a/app/db/seed.ts b/app/db/seed.ts index cee4fd723..1342dfac6 100644 --- a/app/db/seed.ts +++ b/app/db/seed.ts @@ -12,7 +12,7 @@ import { headGearIds, modesShort, shoesGearIds, - weaponIds, + mainWeaponIds, } from "~/modules/in-game-lists"; import { lastCompletedVoting, @@ -503,7 +503,7 @@ function adminBuilds() { const randomOrderHeadGear = shuffle(headGearIds.slice()); const randomOrderClothesGear = shuffle(clothesGearIds.slice()); const randomOrderShoesGear = shuffle(shoesGearIds.slice()); - const randomOrderWeaponIds = shuffle(weaponIds.slice()); + const randomOrderWeaponIds = shuffle(mainWeaponIds.slice()); const randomAbility = (legalTypes: AbilityType[]) => { const randomOrderAbilities = shuffle([...abilities]); diff --git a/app/db/types.ts b/app/db/types.ts index 9d33d158a..72a0c8f75 100644 --- a/app/db/types.ts +++ b/app/db/types.ts @@ -1,4 +1,4 @@ -import type { Ability } from "~/modules/in-game-lists"; +import type { Ability, MainWeaponId } from "~/modules/in-game-lists"; import type allTags from "../routes/calendar/tags.json"; export interface User { @@ -133,7 +133,7 @@ export interface Build { export interface BuildWeapon { buildId: number; - weaponSplId: number; + weaponSplId: MainWeaponId; } export type GearType = "HEAD" | "CLOTHES" | "SHOES"; diff --git a/app/modules/analyzer/ability-values.json b/app/modules/analyzer/ability-values.json new file mode 100644 index 000000000..63df529ac --- /dev/null +++ b/app/modules/analyzer/ability-values.json @@ -0,0 +1,49 @@ +{ + "ConsumeRt_Main": [0.55, 0.775, 1.0], + "ConsumeRt_Sub_Lv0": [0.8, 0.9, 1.0], + "ConsumeRt_Sub_Lv1": [0.7, 0.85, 1.0], + "ConsumeRt_Sub_Lv2": [0.65, 0.825, 1.0], + "ConsumeRt_Sub_Lv3": [0.6, 0.8, 1.0], + "DamageRt_BombH": [0.5, 0.75, 1.0], + "DamageRt_BombL": [0.6, 0.8, 1.0], + "DamageRt_LineMarker": [0.5, 0.75, 1.0], + "DamageRt_Shield": [0.5, 0.75, 1.0], + "DamageRt_Sprinkler": [0.5, 0.75, 1.0], + "Dying_AroundFrm": [30.0, 60.0, 90.0], + "Dying_ChaseFrm": [90.0, 180.0, 270.0], + "IncreaseRt_Special": [1.3, 1.15, 1.0], + "InkRecoverFrm_Std": [220.0, 410.0, 600.0], + "InkRecoverFrm_Stealth": [117.0, 148.5, 180.0], + "MarkingTimeRt": [0.1, 0.43, 1.0], + "MarkingTimeRt_Trap": [0.1, 0.55, 1.0], + "MoveDownRt_PoisonMist": [0.5, 0.75, 1.0], + "MoveVelRt_Shot": [1.25, 1.125, 1.0], + "MoveVel_Human": [0.144, 0.12, 0.096], + "MoveVel_Human_Fast": [0.144, 0.124, 0.104], + "MoveVel_Human_Slow": [0.144, 0.116, 0.088], + "MoveVel_Stealth": [0.24, 0.216, 0.192], + "MoveVel_Stealth_Fast": [0.24, 0.2208, 0.2016], + "MoveVel_Stealth_Slow": [0.24, 0.216, 0.1728], + "OpInk_ArmorHP": [39.0, 26.0, 0.0], + "OpInk_DamageLmt": [0.2, 0.3, 0.4], + "OpInk_DamagePerFrame": [0.0015, 0.0022, 0.003], + "OpInk_JumpVel": [0.11, 0.098, 0.08], + "OpInk_MoveVel": [0.0768, 0.0557, 0.024], + "OpInk_MoveVel_Shot": [0.042, 0.033, 0.012], + "OpInk_MoveVel_ShotK": [1.0, 0.75, 0.5], + "Overwrite_ConsumeRt_Main": [-1.0, -1.0, -1.0], + "Overwrite_MoveVelRt_Shot": [-1.0, -1.0, -1.0], + "Somersault_MoveVelKd": [1.0, 0.925, 0.85], + "SpecialGaugeRt_Restart": [1.0, 0.8, 0.5], + "SuperJump_ChargeFrm": [20.0, 35.0, 80.0], + "SuperJump_MoveFrm": [96.6, 132.3, 138.0], + "WallJumpChargeFrm": [0.0, 0.0, 0.0], + "ReduceJumpSwerveRate": [1.0, 0.75, 0.0], + "SpawnSpeedZSpecUp": [0.0, 0.0, 0.0], + "PeriodFirst": [0.0, 0.0, 0.0], + "PeriodSecond": [0.0, 0.0, 0.0], + "MarkingFrameSubSpec": [0.0, 0.0, 0.0], + "SensorRadius": [0.0, 0.0, 0.0], + "ExplosionRadius": [0.0, 0.0, 0.0], + "MaxHP": [0.0, 0.0, 0.0] +} diff --git a/app/modules/analyzer/constants.ts b/app/modules/analyzer/constants.ts new file mode 100644 index 000000000..89b7e959a --- /dev/null +++ b/app/modules/analyzer/constants.ts @@ -0,0 +1,2 @@ +export const MAX_LDE_INTENSITY = 21; +export const MAX_AP = 57; diff --git a/app/modules/analyzer/index.ts b/app/modules/analyzer/index.ts new file mode 100644 index 000000000..c60392b72 --- /dev/null +++ b/app/modules/analyzer/index.ts @@ -0,0 +1,14 @@ +export type { + DistanceDamage, + MainWeaponParams, + SubWeaponParams, + Stat, + AnalyzedBuild, + SpecialEffectType, +} from "./types"; + +export { useAnalyzeBuild } from "./useAnalyzeBuild"; + +export { MAX_LDE_INTENSITY } from "./constants"; + +export { lastDitchEffortIntensityToAp } from "./specialEffects"; diff --git a/app/modules/analyzer/specialEffects.test.ts b/app/modules/analyzer/specialEffects.test.ts new file mode 100644 index 000000000..5bdb82732 --- /dev/null +++ b/app/modules/analyzer/specialEffects.test.ts @@ -0,0 +1,95 @@ +import { suite } from "uvu"; +import * as assert from "uvu/assert"; +import { applySpecialEffects } from "./specialEffects"; + +const ApplySpecialEffects = suite("applySpecialEffects()"); + +ApplySpecialEffects("Adds an effect to empty build", () => { + const aps = applySpecialEffects({ + effects: ["CB"], + abilityPoints: new Map(), + ldeIntensity: 0, + }); + + assert.equal(aps.size, 6); + assert.equal(aps.get("ISM"), 10); +}); + +ApplySpecialEffects( + "Adds an effect to build while keeping existing abilities untouched", + () => { + const aps = applySpecialEffects({ + effects: ["CB"], + abilityPoints: new Map([["SPU", 10]]), + ldeIntensity: 0, + }); + + assert.equal(aps.size, 7); + assert.equal(aps.get("SPU"), 10); + } +); + +ApplySpecialEffects("Does not boost ability beyond 57", () => { + const aps = applySpecialEffects({ + effects: ["CB"], + abilityPoints: new Map([["ISM", 57]]), + ldeIntensity: 0, + }); + + assert.equal(aps.get("ISM"), 57); +}); + +ApplySpecialEffects("Tacticooler doesn't boost swim speed beyond 29", () => { + const aps = applySpecialEffects({ + effects: ["TACTICOOLER"], + abilityPoints: new Map([["SSU", 28]]), + ldeIntensity: 0, + }); + + assert.equal(aps.get("SSU"), 29); +}); + +ApplySpecialEffects( + "Tacticooler limit swim speed at 29 if more in build", + () => { + const aps = applySpecialEffects({ + effects: ["TACTICOOLER"], + abilityPoints: new Map([["SSU", 30]]), + ldeIntensity: 0, + }); + + assert.equal(aps.get("SSU"), 30); + } +); + +ApplySpecialEffects("Applies many effects", () => { + const aps = applySpecialEffects({ + effects: ["DR", "CB"], + abilityPoints: new Map([["SSU", 1]]), + ldeIntensity: 0, + }); + + assert.equal(aps.get("SSU"), 21); +}); + +ApplySpecialEffects("Applies LDE", () => { + const aps = applySpecialEffects({ + effects: ["LDE"], + abilityPoints: new Map([["ISM", 1]]), + ldeIntensity: 1, + }); + + assert.equal(aps.get("ISM"), 2); +}); + +ApplySpecialEffects("Applies LDE (intensity != aps given)", () => { + const aps = applySpecialEffects({ + effects: ["LDE"], + abilityPoints: new Map([["ISM", 1]]), + ldeIntensity: 15, + }); + + assert.equal(aps.get("ISM"), 18); +}); + +ApplySpecialEffects.run(); diff --git a/app/modules/analyzer/specialEffects.ts b/app/modules/analyzer/specialEffects.ts new file mode 100644 index 000000000..767ae0f43 --- /dev/null +++ b/app/modules/analyzer/specialEffects.ts @@ -0,0 +1,174 @@ +import { MAX_AP } from "./constants"; +import type { AbilityPoints } from "./types"; + +export const SPECIAL_EFFECTS = [ + { + type: "DR", + values: [ + { + type: "SSU", + ap: 10, + }, + { + type: "RSU", + ap: 10, + }, + { + type: "RES", + ap: 10, + }, + ], + }, + { + type: "OG", + values: [ + { + type: "SSU", + ap: 30, + }, + { + type: "RSU", + ap: 30, + }, + { + type: "RES", + ap: 30, + }, + ], + }, + { + type: "LDE", + values: lastDitchEffortValues, + }, + { + type: "CB", + values: [ + { + type: "ISM", + ap: 10, + }, + { + type: "ISS", + ap: 10, + }, + { + type: "IRU", + ap: 10, + }, + { + type: "RSU", + ap: 10, + }, + { + type: "SSU", + ap: 10, + }, + { + type: "SCU", + ap: 10, + }, + ], + }, + { + type: "TACTICOOLER", + values: [ + { + type: "SSU", + ap: 29, + boostsBeyond: false, + }, + { + type: "RSU", + ap: 29, + boostsBeyond: false, + }, + { + type: "RES", + ap: MAX_AP, + }, + { + type: "QR", + ap: MAX_AP, + }, + { + type: "QSJ", + ap: MAX_AP, + }, + { + type: "SS", + ap: MAX_AP, + }, + { + type: "IA", + ap: MAX_AP, + }, + ], + }, +] as const; + +export function lastDitchEffortIntensityToAp(intensity: number) { + return Math.floor((24 / 21) * intensity); +} + +function lastDitchEffortValues(intensity: number) { + const ap = lastDitchEffortIntensityToAp(intensity); + + return [ + { + type: "ISM", + ap, + }, + { + type: "ISS", + ap, + }, + { + type: "IRU", + ap, + }, + ] as const; +} + +export function applySpecialEffects({ + abilityPoints, + effects, + ldeIntensity, +}: { + abilityPoints: AbilityPoints; + effects: Array; + ldeIntensity: number; +}): AbilityPoints { + const result: AbilityPoints = new Map(abilityPoints); + + for (const effectObj of SPECIAL_EFFECTS) { + if (!effects.includes(effectObj.type)) continue; + + const valuesArr = effectObjToValuesArr({ effectObj, ldeIntensity }); + + for (const value of valuesArr) { + const boostsBeyond = "boostsBeyond" in value ? value.boostsBeyond : true; + const currentAP = result.get(value.type) ?? 0; + const newAP = boostsBeyond + ? currentAP + value.ap + : Math.max(currentAP, value.ap); + + result.set(value.type, Math.min(newAP, MAX_AP)); + } + } + + return result; +} + +function effectObjToValuesArr({ + effectObj, + ldeIntensity, +}: { + effectObj: typeof SPECIAL_EFFECTS[number]; + ldeIntensity: number; +}) { + if (typeof effectObj.values === "function") { + return effectObj.values(ldeIntensity); + } + + return effectObj.values; +} diff --git a/app/modules/analyzer/stats.ts b/app/modules/analyzer/stats.ts new file mode 100644 index 000000000..5fb60462a --- /dev/null +++ b/app/modules/analyzer/stats.ts @@ -0,0 +1,827 @@ +import type { Ability, MainWeaponId } from "~/modules/in-game-lists"; +import { ANGLE_SHOOTER_ID } from "~/modules/in-game-lists"; +import { INK_MINE_ID, POINT_SENSOR_ID } from "~/modules/in-game-lists"; +import type { + AbilityPoints, + AnalyzedBuild, + DamageType, + InkConsumeType, + MainWeaponParams, + StatFunctionInput, + SubWeaponParams, +} from "./types"; +import { DAMAGE_TYPE } from "./types"; +import { INK_CONSUME_TYPES } from "./types"; +import invariant from "tiny-invariant"; +import { + abilityPointsToEffects, + apFromMap, + hasEffect, + weaponParams, +} from "./utils"; +import { assertUnreachable } from "~/utils/types"; +import { semiRandomId } from "~/utils/strings"; +import { roundToTwoDecimalPlaces } from "~/utils/number"; + +export function buildStats({ + abilityPoints, + weaponSplId, + mainOnlyAbilities, +}: { + abilityPoints: AbilityPoints; + weaponSplId: MainWeaponId; + mainOnlyAbilities: Array; +}): AnalyzedBuild { + const mainWeaponParams = weaponParams().mainWeapons[weaponSplId]; + invariant(mainWeaponParams, `Weapon with splId ${weaponSplId} not found`); + + const subWeaponParams = + weaponParams().subWeapons[mainWeaponParams.subWeaponId]; + invariant( + subWeaponParams, + `Sub weapon with splId ${mainWeaponParams.subWeaponId} not found` + ); + + const input: StatFunctionInput = { + mainWeaponParams, + subWeaponParams, + abilityPoints, + mainOnlyAbilities, + }; + + return { + weapon: { + subWeaponSplId: mainWeaponParams.subWeaponId, + specialWeaponSplId: mainWeaponParams.specialWeaponId, + brellaCanopyHp: mainWeaponParams.CanopyHP, + fullChargeSeconds: mainWeaponParams.ChargeFrameFullCharge + ? framesToSeconds(mainWeaponParams.ChargeFrameFullCharge) + : undefined, + maxChargeHoldSeconds: mainWeaponParams.KeepChargeFullFrame + ? framesToSeconds(mainWeaponParams.KeepChargeFullFrame) + : undefined, + speedType: mainWeaponParams.WeaponSpeedType ?? "Normal", + isTripleShooter: Boolean(mainWeaponParams.TripleShotSpanFrame), + }, + stats: { + specialPoint: specialPoint(input), + specialSavedAfterDeath: specialSavedAfterDeath(input), + fullInkTankOptions: fullInkTankOptions(input), + damages: damages(input), + mainWeaponWhiteInkSeconds: + typeof mainWeaponParams.InkRecoverStop === "number" + ? framesToSeconds(mainWeaponParams.InkRecoverStop) + : undefined, + subWeaponWhiteInkSeconds: framesToSeconds(subWeaponParams.InkRecoverStop), + squidFormInkRecoverySeconds: squidFormInkRecoverySeconds(input), + runSpeed: runSpeed(input), + // shootingRunSpeed: shootingRunSpeed(input), + swimSpeed: swimSpeed(input), + runSpeedInEnemyInk: runSpeedInEnemyInk(input), + damageTakenInEnemyInkPerSecond: damageTakenInEnemyInkPerSecond(input), + enemyInkDamageLimit: enemyInkDamageLimit(input), + framesBeforeTakingDamageInEnemyInk: + framesBeforeTakingDamageInEnemyInk(input), + quickRespawnTime: quickRespawnTime(input), + superJumpTimeGroundFrames: superJumpTimeGroundFrames(input), + superJumpTimeTotal: superJumpTimeTotal(input), + subDefPointSensorMarkedTimeInSeconds: + subDefPointSensorMarkedTimeInSeconds(input), + subDefInkMineMarkedTimeInSeconds: subDefInkMineMarkedTimeInSeconds(input), + subDefAngleShooterMarkedTimeInSeconds: + subDefAngleShooterMarkedTimeInSeconds(input), + subDefToxicMistMovementReduction: subDefToxicMistMovementReduction(input), + subDefAngleShooterDamage: subDefAngleShooterDamage(input), + subDefSplashWallDamagePercentage: subDefSplashWallDamagePercentage(input), + subDefSprinklerDamagePercentage: subDefSprinklerDamagePercentage(input), + ...subStats(input), + }, + }; +} + +function specialPoint({ + abilityPoints, + mainWeaponParams, +}: StatFunctionInput): AnalyzedBuild["stats"]["specialPoint"] { + const SPECIAL_POINT_ABILITY = "SCU"; + + const { effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: abilityPoints, + ability: SPECIAL_POINT_ABILITY, + }), + key: "IncreaseRt_Special", + weapon: mainWeaponParams, + }); + + return { + baseValue: mainWeaponParams.SpecialPoint, + modifiedBy: SPECIAL_POINT_ABILITY, + value: Math.ceil(mainWeaponParams.SpecialPoint / effect), + }; +} + +function specialSavedAfterDeath({ + abilityPoints, + mainWeaponParams, +}: StatFunctionInput): AnalyzedBuild["stats"]["specialPoint"] { + const SPECIAL_SAVED_AFTER_DEATH_ABILITY = "SS"; + const specialSavedAfterDeathForDisplay = (effect: number) => + Number(((1.0 - effect) * 100).toFixed(2)); + + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: abilityPoints, + ability: SPECIAL_SAVED_AFTER_DEATH_ABILITY, + }), + key: "SpecialGaugeRt_Restart", + weapon: mainWeaponParams, + }); + + return { + baseValue: specialSavedAfterDeathForDisplay(baseEffect), + value: specialSavedAfterDeathForDisplay(effect), + modifiedBy: SPECIAL_SAVED_AFTER_DEATH_ABILITY, + }; +} + +function fullInkTankOptions( + args: StatFunctionInput +): AnalyzedBuild["stats"]["fullInkTankOptions"] { + const result: AnalyzedBuild["stats"]["fullInkTankOptions"] = []; + + const { inkConsume: subWeaponInkConsume, maxSubsFromFullInkTank } = + subWeaponConsume(args); + + for ( + let subsFromFullInkTank = 0; + subsFromFullInkTank <= maxSubsFromFullInkTank; + subsFromFullInkTank++ + ) { + for (const type of INK_CONSUME_TYPES) { + const mainWeaponInkConsume = mainWeaponInkConsumeByType({ + type, + ...args, + }); + + if (typeof mainWeaponInkConsume !== "number") continue; + + result.push({ + id: semiRandomId(), + subsUsed: subsFromFullInkTank, + type, + value: effectToRounded( + (1 - subWeaponInkConsume * subsFromFullInkTank) / mainWeaponInkConsume + ), + }); + } + } + + return result; +} + +function effectToRounded(effect: number) { + return Number(effect.toFixed(2)); +} + +function subWeaponConsume({ + mainWeaponParams, + subWeaponParams, + abilityPoints, +}: StatFunctionInput) { + const { effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints, + ability: "ISS", + }), + // xxx: placeholder fallback before prod + key: `ConsumeRt_Sub_Lv${subWeaponParams.SubInkSaveLv ?? 0}`, + weapon: mainWeaponParams, + }); + + // xxx: placeholder fallback before prod + const inkConsume = subWeaponParams.InkConsume ?? 0.6; + + const inkConsumeAfterISS = inkConsume * effect; + + return { + inkConsume: inkConsumeAfterISS, + maxSubsFromFullInkTank: Math.floor(1 / inkConsumeAfterISS), + }; +} + +function mainWeaponInkConsumeByType({ + mainWeaponParams, + abilityPoints, + type, +}: { + type: InkConsumeType; +} & StatFunctionInput) { + const { effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints, + ability: "ISM", + }), + key: "ConsumeRt_Main", + weapon: mainWeaponParams, + }); + + // these keys are always mutually exclusive i.e. even if inkConsumeTypeToParamsKeys() returns many keys + // then weapon params of this weapon should only have one defined + for (const key of inkConsumeTypeToParamsKeys(type)) { + const value = mainWeaponParams[key]; + + if (typeof value === "number") { + return value * effect; + } + } + + // not all weapons have all ink consume types + // i.e. blaster does not (hopefully) perform dualie dodge rolls + return; +} + +function inkConsumeTypeToParamsKeys( + type: InkConsumeType +): Array { + switch (type) { + case "NORMAL": + return ["InkConsume", "InkConsume_WeaponShelterShotgunParam"]; + case "SWING": + return ["InkConsume_SwingParam", "InkConsume_WeaponSwingParam"]; + case "SLOSH": + return ["InkConsumeSlosher"]; + case "TAP_SHOT": + return ["InkConsumeMinCharge"]; + case "FULL_CHARGE": + return ["InkConsumeFullCharge", "InkConsumeFullCharge_ChargeParam"]; + case "SPLATLING_CHARGE": + return ["InkConsumeFullChargeSplatling"]; + case "HORIZONTAL_SWING": + return ["InkConsume_WeaponWideSwingParam"]; + case "VERTICAL_SWING": + return ["InkConsume_WeaponVerticalSwingParam"]; + case "DUALIE_ROLL": + return ["InkConsume_SideStepParam"]; + case "SHIELD_LAUNCH": + return ["InkConsumeUmbrella_WeaponShelterCanopyParam"]; + default: { + assertUnreachable(type); + } + } +} + +const damageTypeToParamsKey: Record< + DamageType, + keyof MainWeaponParams | keyof SubWeaponParams +> = { + NORMAL_MIN: "DamageParam_ValueMin", + NORMAL_MAX: "DamageParam_ValueMax", + DIRECT: "DamageParam_ValueDirect", + DISTANCE: "BlastParam_DistanceDamage", + FULL_CHARGE: "DamageParam_ValueFullCharge", + MAX_CHARGE: "DamageParam_ValueMaxCharge", + TAP_SHOT: "DamageParam_ValueMinCharge", + BOMB_NORMAL: "DistanceDamage", + BOMB_DIRECT: "DirectDamage", +}; + +function damages(args: StatFunctionInput): AnalyzedBuild["stats"]["damages"] { + const result: AnalyzedBuild["stats"]["damages"] = []; + + for (const type of DAMAGE_TYPE) { + const key = damageTypeToParamsKey[type]; + const value = + args.mainWeaponParams[key as keyof MainWeaponParams] ?? + args.subWeaponParams[key as keyof SubWeaponParams]; + + if (Array.isArray(value)) { + for (const subValue of value) { + result.push({ + type, + value: subValue.Damage / 10, + distance: subValue.Distance, + id: semiRandomId(), + }); + } + + continue; + } + + if (typeof value !== "number") continue; + + result.push({ + id: semiRandomId(), + type, + value: value / 10, + shotsToSplat: shotsToSplat({ + value, + type, + isTripleShooter: Boolean(args.mainWeaponParams.TripleShotSpanFrame), + }), + }); + } + + return result; +} + +function shotsToSplat({ + value, + type, + isTripleShooter, +}: { + value: number; + type: DamageType; + isTripleShooter: boolean; +}) { + if (type !== "NORMAL_MAX") return; + + const multiplier = isTripleShooter ? 3 : 1; + + return Math.ceil(1000 / (value * multiplier)); +} + +const framesToSeconds = (frames: number) => + effectToRounded(Math.ceil(frames) / 60); +function squidFormInkRecoverySeconds( + args: StatFunctionInput +): AnalyzedBuild["stats"]["squidFormInkRecoverySeconds"] { + const SQUID_FORM_INK_RECOVERY_SECONDS_ABILITY = "IRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SQUID_FORM_INK_RECOVERY_SECONDS_ABILITY, + }), + key: "InkRecoverFrm_Stealth", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: framesToSeconds(baseEffect), + value: framesToSeconds(effect), + modifiedBy: SQUID_FORM_INK_RECOVERY_SECONDS_ABILITY, + }; +} + +function runSpeed(args: StatFunctionInput): AnalyzedBuild["stats"]["runSpeed"] { + const key = + args.mainWeaponParams.WeaponSpeedType === "Fast" + ? "_Fast" + : args.mainWeaponParams.WeaponSpeedType === "Slow" + ? "_Slow" + : ""; + const RUN_SPEED_ABILITY = "RSU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: RUN_SPEED_ABILITY, + }), + key: `MoveVel_Human${key}`, + weapon: args.mainWeaponParams, + }); + + return { + baseValue: effectToRounded(baseEffect * 10), + value: effectToRounded(effect * 10), + modifiedBy: RUN_SPEED_ABILITY, + }; +} + +function runSpeedInEnemyInk( + args: StatFunctionInput +): AnalyzedBuild["stats"]["runSpeedInEnemyInk"] { + const RUN_SPEED_IN_ENEMY_INK_ABILITY = "RES"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: RUN_SPEED_IN_ENEMY_INK_ABILITY, + }), + key: "OpInk_MoveVel", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: effectToRounded(baseEffect * 10), + value: effectToRounded(effect * 10), + modifiedBy: RUN_SPEED_IN_ENEMY_INK_ABILITY, + }; +} + +function swimSpeed( + args: StatFunctionInput +): AnalyzedBuild["stats"]["swimSpeed"] { + const key = + args.mainWeaponParams.WeaponSpeedType === "Fast" + ? "_Fast" + : args.mainWeaponParams.WeaponSpeedType === "Slow" + ? "_Slow" + : ""; + const SWIM_SPEED_ABILITY = "SSU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SWIM_SPEED_ABILITY, + }), + key: `MoveVel_Stealth${key}`, + weapon: args.mainWeaponParams, + }); + + const ninjaSquidMultiplier = args.mainOnlyAbilities.includes("NS") ? 0.9 : 1; + + return { + baseValue: effectToRounded(baseEffect * 10), + value: effectToRounded(effect * 10 * ninjaSquidMultiplier), + modifiedBy: SWIM_SPEED_ABILITY, + }; +} + +const RESPAWN_CHASE_FRAME = 150; +function quickRespawnTime( + args: StatFunctionInput +): AnalyzedBuild["stats"]["quickRespawnTime"] { + const QUICK_RESPAWN_TIME_ABILITY = "QR"; + + const chase = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: QUICK_RESPAWN_TIME_ABILITY, + }), + key: "Dying_ChaseFrm", + weapon: args.mainWeaponParams, + }); + const around = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: QUICK_RESPAWN_TIME_ABILITY, + }), + key: "Dying_AroundFrm", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: framesToSeconds( + RESPAWN_CHASE_FRAME + chase.baseEffect + around.baseEffect + ), + value: framesToSeconds(RESPAWN_CHASE_FRAME + chase.effect + around.effect), + modifiedBy: QUICK_RESPAWN_TIME_ABILITY, + }; +} + +function superJumpTimeGroundFrames( + args: StatFunctionInput +): AnalyzedBuild["stats"]["superJumpTimeGroundFrames"] { + const SUPER_JUMP_TIME_GROUND_ABILITY = "QSJ"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUPER_JUMP_TIME_GROUND_ABILITY, + }), + key: "SuperJump_ChargeFrm", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: Math.ceil(baseEffect), + value: Math.ceil(effect), + modifiedBy: SUPER_JUMP_TIME_GROUND_ABILITY, + }; +} + +function superJumpTimeTotal( + args: StatFunctionInput +): AnalyzedBuild["stats"]["superJumpTimeTotal"] { + const SUPER_JUMP_TIME_TOTAL_ABILITY = "QSJ"; + + const charge = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUPER_JUMP_TIME_TOTAL_ABILITY, + }), + key: "SuperJump_ChargeFrm", + weapon: args.mainWeaponParams, + }); + const move = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUPER_JUMP_TIME_TOTAL_ABILITY, + }), + key: "SuperJump_MoveFrm", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: framesToSeconds( + Math.ceil(charge.baseEffect) + Math.ceil(move.baseEffect) + ), + value: framesToSeconds(Math.ceil(charge.effect) + Math.ceil(move.effect)), + modifiedBy: SUPER_JUMP_TIME_TOTAL_ABILITY, + }; +} + +function damageTakenInEnemyInkPerSecond( + args: StatFunctionInput +): AnalyzedBuild["stats"]["damageTakenInEnemyInkPerSecond"] { + const DAMAGE_TAKEN_IN_ENEMY_INK_ABILITY = "RES"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: DAMAGE_TAKEN_IN_ENEMY_INK_ABILITY, + }), + key: "OpInk_DamagePerFrame", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: effectToDamage(baseEffect) * 60, + value: effectToDamage(effect) * 60, + modifiedBy: DAMAGE_TAKEN_IN_ENEMY_INK_ABILITY, + }; +} + +function enemyInkDamageLimit( + args: StatFunctionInput +): AnalyzedBuild["stats"]["enemyInkDamageLimit"] { + const ENEMY_INK_DAMAGE_LIMIT_ABILITY = "RES"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: ENEMY_INK_DAMAGE_LIMIT_ABILITY, + }), + key: "OpInk_DamageLmt", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: effectToDamage(baseEffect), + value: effectToDamage(effect), + modifiedBy: ENEMY_INK_DAMAGE_LIMIT_ABILITY, + }; +} + +function effectToDamage(effect: number) { + // not sure where the 0.05 is coming from. Old analyzer had it as well so assuming it's correct. + return Number((effect * 100 - 0.05).toFixed(1)); +} + +function framesBeforeTakingDamageInEnemyInk( + args: StatFunctionInput +): AnalyzedBuild["stats"]["framesBeforeTakingDamageInEnemyInk"] { + const FRAMES_BEFORE_TAKING_DAMAGE_IN_ENEMY_INK_ABILITY = "RES"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: FRAMES_BEFORE_TAKING_DAMAGE_IN_ENEMY_INK_ABILITY, + }), + key: "OpInk_ArmorHP", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: Math.ceil(baseEffect), + value: Math.ceil(effect), + modifiedBy: FRAMES_BEFORE_TAKING_DAMAGE_IN_ENEMY_INK_ABILITY, + }; +} + +const SUB_WEAPON_STATS = [ + { + analyzedBuildKey: "subVelocity", + abilityValuesKey: "SpawnSpeedZSpecUp", + type: "NO_CHANGE", + }, + { + analyzedBuildKey: "subFirstPhaseDuration", + abilityValuesKey: "PeriodFirst", + type: "TIME", + }, + { + analyzedBuildKey: "subSecondPhaseDuration", + abilityValuesKey: "PeriodSecond", + type: "TIME", + }, + { + analyzedBuildKey: "subMarkingTimeInSeconds", + abilityValuesKey: "MarkingFrameSubSpec", + type: "TIME", + }, + { + analyzedBuildKey: "subMarkingRadius", + abilityValuesKey: "SensorRadius", + type: "NO_CHANGE", + }, + { + analyzedBuildKey: "subExplosionRadius", + abilityValuesKey: "ExplosionRadius", + type: "NO_CHANGE", + }, + { analyzedBuildKey: "subHp", abilityValuesKey: "MaxHP", type: "HP" }, +] as const; +function subStats(args: StatFunctionInput) { + const result: Partial = {}; + const SUB_STATS_KEY = "BRU"; + + for (const { analyzedBuildKey, abilityValuesKey, type } of SUB_WEAPON_STATS) { + if (!hasEffect({ key: abilityValuesKey, weapon: args.subWeaponParams })) { + continue; + } + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_STATS_KEY, + }), + key: abilityValuesKey, + weapon: args.subWeaponParams, + }); + + const toValue = (effect: number) => { + switch (type) { + case "NO_CHANGE": + return roundToTwoDecimalPlaces(effect); + case "HP": + return roundToTwoDecimalPlaces(effect / 10); + case "TIME": + return framesToSeconds(effect); + default: + assertUnreachable(type); + } + }; + + result[analyzedBuildKey] = { + baseValue: toValue(baseEffect), + modifiedBy: SUB_STATS_KEY, + value: toValue(effect), + }; + } + + return result; +} + +function subDefPointSensorMarkedTimeInSeconds( + args: StatFunctionInput +): AnalyzedBuild["stats"]["subDefPointSensorMarkedTimeInSeconds"] { + const SUB_DEF_POINT_SENSOR_MARKED_TIME_IN_SECONDS_KEY = "SRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_DEF_POINT_SENSOR_MARKED_TIME_IN_SECONDS_KEY, + }), + key: "MarkingTimeRt", + weapon: args.mainWeaponParams, + }); + + const pointSensorParams = weaponParams().subWeapons[POINT_SENSOR_ID]; + + const { baseEffect: markingTimeEffect } = abilityPointsToEffects({ + abilityPoints: 0, + key: "MarkingFrameSubSpec", + weapon: pointSensorParams, + }); + + return { + baseValue: framesToSeconds(markingTimeEffect * baseEffect), + modifiedBy: SUB_DEF_POINT_SENSOR_MARKED_TIME_IN_SECONDS_KEY, + value: framesToSeconds(markingTimeEffect * effect), + }; +} + +function subDefInkMineMarkedTimeInSeconds( + args: StatFunctionInput +): AnalyzedBuild["stats"]["subDefInkMineMarkedTimeInSeconds"] { + const SUB_DEF_INK_MINE_MARKED_TIME_IN_SECONDS_KEY = "SRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_DEF_INK_MINE_MARKED_TIME_IN_SECONDS_KEY, + }), + key: "MarkingTimeRt_Trap", + weapon: args.mainWeaponParams, + }); + + const inkMineParams = weaponParams().subWeapons[INK_MINE_ID]; + + const { baseEffect: markingTimeEffect } = abilityPointsToEffects({ + abilityPoints: 0, + key: "MarkingFrameSubSpec", + weapon: inkMineParams, + }); + + return { + baseValue: framesToSeconds(markingTimeEffect * baseEffect), + modifiedBy: SUB_DEF_INK_MINE_MARKED_TIME_IN_SECONDS_KEY, + value: framesToSeconds(markingTimeEffect * effect), + }; +} + +function subDefAngleShooterMarkedTimeInSeconds( + args: StatFunctionInput +): AnalyzedBuild["stats"]["subDefAngleShooterMarkedTimeInSeconds"] { + const SUB_DEF_ANGLE_SHOOTER_MARKED_TIME_IN_SECONDS_KEY = "SRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_DEF_ANGLE_SHOOTER_MARKED_TIME_IN_SECONDS_KEY, + }), + key: "MarkingTimeRt", + weapon: args.mainWeaponParams, + }); + + const angleShooterParams = weaponParams().subWeapons[ANGLE_SHOOTER_ID]; + + const { baseEffect: markingTimeEffect } = abilityPointsToEffects({ + abilityPoints: 0, + key: "MarkingFrameSubSpec", + weapon: angleShooterParams, + }); + + return { + baseValue: framesToSeconds(markingTimeEffect * baseEffect), + modifiedBy: SUB_DEF_ANGLE_SHOOTER_MARKED_TIME_IN_SECONDS_KEY, + value: framesToSeconds(markingTimeEffect * effect), + }; +} + +function subDefToxicMistMovementReduction( + args: StatFunctionInput +): AnalyzedBuild["stats"]["subDefToxicMistMovementReduction"] { + const SUB_DEF_TOXIC_MIST_MOVEMENT_REDUCTION_KEY = "SRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_DEF_TOXIC_MIST_MOVEMENT_REDUCTION_KEY, + }), + key: "MoveDownRt_PoisonMist", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: roundToTwoDecimalPlaces(baseEffect * 100), + value: roundToTwoDecimalPlaces(effect * 100), + modifiedBy: SUB_DEF_TOXIC_MIST_MOVEMENT_REDUCTION_KEY, + }; +} + +function subDefAngleShooterDamage( + args: StatFunctionInput +): AnalyzedBuild["stats"]["subDefAngleShooterDamage"] { + const SUB_DEF_ANGLE_SHOOTER_DAMAGE_KEY = "SRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_DEF_ANGLE_SHOOTER_DAMAGE_KEY, + }), + key: "DamageRt_LineMarker", + weapon: args.mainWeaponParams, + }); + + const angleShooterDirectDamage = + weaponParams().subWeapons[ANGLE_SHOOTER_ID].DirectDamage; + invariant(angleShooterDirectDamage); + + return { + baseValue: roundToTwoDecimalPlaces( + (angleShooterDirectDamage * baseEffect) / 10 + ), + value: roundToTwoDecimalPlaces((angleShooterDirectDamage * effect) / 10), + modifiedBy: SUB_DEF_ANGLE_SHOOTER_DAMAGE_KEY, + }; +} + +function subDefSplashWallDamagePercentage( + args: StatFunctionInput +): AnalyzedBuild["stats"]["subDefSplashWallDamagePercentage"] { + const SUB_DEF_SPLASH_WALL_DAMAGE_PERCENTAGE_KEY = "SRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_DEF_SPLASH_WALL_DAMAGE_PERCENTAGE_KEY, + }), + key: "DamageRt_Shield", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: roundToTwoDecimalPlaces(baseEffect * 100), + value: roundToTwoDecimalPlaces(effect * 100), + modifiedBy: SUB_DEF_SPLASH_WALL_DAMAGE_PERCENTAGE_KEY, + }; +} + +function subDefSprinklerDamagePercentage( + args: StatFunctionInput +): AnalyzedBuild["stats"]["subDefSprinklerDamagePercentage"] { + const SUB_DEF_SPRINKLER_DAMAGE_PERCENTAGE_KEY = "SRU"; + const { baseEffect, effect } = abilityPointsToEffects({ + abilityPoints: apFromMap({ + abilityPoints: args.abilityPoints, + ability: SUB_DEF_SPRINKLER_DAMAGE_PERCENTAGE_KEY, + }), + key: "DamageRt_Sprinkler", + weapon: args.mainWeaponParams, + }); + + return { + baseValue: roundToTwoDecimalPlaces(baseEffect * 100), + value: roundToTwoDecimalPlaces(effect * 100), + modifiedBy: SUB_DEF_SPRINKLER_DAMAGE_PERCENTAGE_KEY, + }; +} diff --git a/app/modules/analyzer/types.ts b/app/modules/analyzer/types.ts new file mode 100644 index 000000000..3467d56eb --- /dev/null +++ b/app/modules/analyzer/types.ts @@ -0,0 +1,217 @@ +import type { + Ability, + MainWeaponId, + SpecialWeaponId, + SubWeaponId, +} from "~/modules/in-game-lists"; +import type { SPECIAL_EFFECTS } from "./specialEffects"; +import type abilityValues from "./ability-values.json"; + +export interface MainWeaponParams { + subWeaponId: SubWeaponId; + specialWeaponId: SpecialWeaponId; + /** Replacing default values of the ability json for this specific weapon */ + overwrites?: Record>>; + SpecialPoint: number; + /** Weapon's weight class. "Light/Heavy weapon" */ + WeaponSpeedType?: "Slow" | "Fast"; + /** Total frames it takes the weapon to shoot out three times */ + TripleShotSpanFrame?: number; + /** Amount of frames charge can be held */ + KeepChargeFullFrame?: number; + /** Amount of frames full charge takes */ + ChargeFrameFullCharge?: number; + DamageParam_ValueMax?: number; + DamageParam_ValueMin?: number; + DamageParam_ValueDirect?: number; + /** Damage caused by charger's full charged shot */ + DamageParam_ValueFullCharge?: number; + /** Max damage caused by charger's charged shot before fully charged */ + DamageParam_ValueMaxCharge?: number; + /** Charger tap shot damage */ + DamageParam_ValueMinCharge?: number; + BlastParam_DistanceDamage?: Array; + // DamageParam_ReduceStartFrame?: number; + // DamageParam_ReduceEndFrame?: number; + /** Brella shield HP */ + CanopyHP?: number; + /** Amount of frames white ink (=no ink recovery during this time) takes */ + InkRecoverStop?: number; + /** How much ink one shot consumes? InkConsume = 0.5 means 2 shots per full tank */ + InkConsume?: number; + /** How much ink one slosh of slosher consumes? */ + InkConsumeSlosher?: number; + /** How much ink one fully charged shot consumes? */ + InkConsumeFullCharge?: number; + /** How much ink one tap shot consumes? */ + InkConsumeMinCharge?: number; + /** How much ink one full charge of splatling consumes? */ + InkConsumeFullChargeSplatling?: number; + /** How much ink one swing of brush consumes? */ + InkConsume_WeaponSwingParam?: number; + /** How much ink one vertical swing of roller consumes? */ + InkConsume_WeaponVerticalSwingParam?: number; + /** How much ink one horizontal swing of roller consumes? */ + InkConsume_WeaponWideSwingParam?: number; + /** How much ink one swing of splatana consumes? */ + InkConsume_SwingParam?: number; + /** How much ink brella shield launch consumes? */ + InkConsumeUmbrella_WeaponShelterCanopyParam?: number; + /** How much ink one brella shot consumes? */ + InkConsume_WeaponShelterShotgunParam?: number; + /** How much ink a dualie dodge roll consumes? */ + InkConsume_SideStepParam?: number; + /** How much ink a fully charger Splatana shot consumes? */ + InkConsumeFullCharge_ChargeParam?: number; + //InkConsumeMidCharge_ChargeParam?: number; + // SpeedInkConsumeMax_WeaponRollParam?: number; + // SpeedInkConsumeMin_WeaponRollParam?: number; +} + +export interface DistanceDamage { + Damage: number; + Distance: number; +} + +export interface SubWeaponParams { + overwrites?: Record>>; + SubInkSaveLv: 0 | 1 | 2 | 3; + /** How much ink one usage of the sub consumes */ + InkConsume: number; + /** Amount of frames white ink (=no ink recovery during this time) takes */ + InkRecoverStop: number; + /** Damage dealt at different radiuses */ + DistanceDamage?: Array; + /** Damage dealt by explosion at different radiuses (curling bomb charged all the way) */ + DistanceDamage_BlastParamMaxCharge?: Array; + /** Damage dealt by explosion at different radiuses (curling bomb not charged) */ + DistanceDamage_BlastParamMinCharge?: Array; + /** Damage dealt by explosion at different radiuses (fizzy bomb bounces) */ + DistanceDamage_BlastParamArray?: Array; + /** Damage dealt by explosion at different radiuses (torpedo explosion air to ground) */ + DistanceDamage_BlastParamChase?: Array; + /** Damage dealt by explosion at different radiuses (rolling torpedo) */ + DistanceDamage_SplashBlastParam?: Array; + /** Damage dealt by direct hit */ + DirectDamage?: number; +} + +export type ParamsJson = { + mainWeapons: Record; + subWeapons: Record; +}; + +export interface Stat { + value: number; + baseValue: number; + modifiedBy: Ability; +} + +export type AbilityPoints = Map; + +export interface StatFunctionInput { + mainWeaponParams: MainWeaponParams; + subWeaponParams: SubWeaponParams; + abilityPoints: AbilityPoints; + mainOnlyAbilities: Array; +} + +export type InkConsumeType = typeof INK_CONSUME_TYPES[number]; + +export const INK_CONSUME_TYPES = [ + "NORMAL", + "SWING", + "SLOSH", + "VERTICAL_SWING", + "HORIZONTAL_SWING", + "TAP_SHOT", + "FULL_CHARGE", + "SPLATLING_CHARGE", + "SHIELD_LAUNCH", + "DUALIE_ROLL", +] as const; + +export interface FullInkTankOption { + subsUsed: number; + value: number; + type: InkConsumeType; +} + +export const DAMAGE_TYPE = [ + "NORMAL_MIN", + "NORMAL_MAX", + "DIRECT", + "FULL_CHARGE", + "MAX_CHARGE", + "TAP_SHOT", + "DISTANCE", + "BOMB_NORMAL", + "BOMB_DIRECT", +] as const; + +export type DamageType = typeof DAMAGE_TYPE[number]; + +export interface Damage { + value: number; + type: DamageType; + distance?: number; + shotsToSplat?: number; +} + +export interface AnalyzedBuild { + weapon: { + subWeaponSplId: SubWeaponId; + specialWeaponSplId: SpecialWeaponId; + brellaCanopyHp?: number; + maxChargeHoldSeconds?: number; + fullChargeSeconds?: number; + speedType: NonNullable | "Normal"; + isTripleShooter: boolean; + }; + stats: { + specialPoint: Stat; + /** % of special charge saved when dying */ + specialSavedAfterDeath: Stat; + mainWeaponWhiteInkSeconds?: number; + subWeaponWhiteInkSeconds: number; + fullInkTankOptions: Array; + damages: Array; + squidFormInkRecoverySeconds: Stat; + runSpeed: Stat; + // shootingRunSpeed: Stat; + swimSpeed: Stat; + runSpeedInEnemyInk: Stat; + framesBeforeTakingDamageInEnemyInk: Stat; + damageTakenInEnemyInkPerSecond: Stat; + enemyInkDamageLimit: Stat; + quickRespawnTime: Stat; + superJumpTimeGroundFrames: Stat; + superJumpTimeTotal: Stat; + + subDefPointSensorMarkedTimeInSeconds: Stat; + subDefInkMineMarkedTimeInSeconds: Stat; + subDefAngleShooterMarkedTimeInSeconds: Stat; + subDefToxicMistMovementReduction: Stat; + subDefAngleShooterDamage: Stat; + subDefSplashWallDamagePercentage: Stat; + subDefSprinklerDamagePercentage: Stat; + // subDefBombDamageLight: Stat; + // subDefBombDamageHeavy: Stat; + // subDefAngleShooterDamage: Stat; + // subDefSplashWallDamage: Stat; + // subDefSprinklerDamage: Stat; + // subDefToxicMistMoveReduction: Stat; + + subVelocity?: Stat; + subFirstPhaseDuration?: Stat; + subSecondPhaseDuration?: Stat; + subMarkingTimeInSeconds?: Stat; + subMarkingRadius?: Stat; + subExplosionRadius?: Stat; + subHp?: Stat; + }; +} + +export type SpecialEffectType = typeof SPECIAL_EFFECTS[number]["type"]; + +export type AbilityValuesKeys = keyof typeof abilityValues; diff --git a/app/modules/analyzer/useAnalyzeBuild.ts b/app/modules/analyzer/useAnalyzeBuild.ts new file mode 100644 index 000000000..e1e2adafa --- /dev/null +++ b/app/modules/analyzer/useAnalyzeBuild.ts @@ -0,0 +1,201 @@ +import { useSearchParams } from "@remix-run/react"; +import { EMPTY_BUILD } from "~/constants"; +import { + type BuildAbilitiesTupleWithUnknown, + type MainWeaponId, + mainWeaponIds, + abilities, + isAbility, +} from "../in-game-lists"; +import type { + Ability, + AbilityType, + AbilityWithUnknown, +} from "../in-game-lists/types"; +import { MAX_LDE_INTENSITY } from "./constants"; +import { applySpecialEffects, SPECIAL_EFFECTS } from "./specialEffects"; +import { buildStats } from "./stats"; +import type { SpecialEffectType } from "./types"; +import { buildToAbilityPoints } from "./utils"; + +const UNKNOWN_SHORT = "U"; + +export function useAnalyzeBuild() { + const [searchParams, setSearchParams] = useSearchParams(); + + const mainWeaponId = validatedWeaponIdFromSearchParams(searchParams); + const build = validatedBuildFromSearchParams(searchParams); + const ldeIntensity = validatedLdeIntensityFromSearchParams(searchParams); + const effects = validatedEffectsFromSearchParams({ searchParams, build }); + + const handleChange = ({ + newMainWeaponId = mainWeaponId, + newBuild = build, + newLdeIntensity = ldeIntensity, + newEffects = effects, + }: { + newMainWeaponId?: MainWeaponId; + newBuild?: BuildAbilitiesTupleWithUnknown; + newLdeIntensity?: number; + newEffects?: Array; + }) => { + setSearchParams({ + weapon: String(newMainWeaponId), + build: serializeBuild(newBuild), + lde: String(newLdeIntensity), + effect: newEffects, + }); + }; + + const buildsAbilityPoints = buildToAbilityPoints(build); + + const abilityPoints = applySpecialEffects({ + abilityPoints: buildsAbilityPoints, + effects, + ldeIntensity, + }); + + const analyzed = buildStats({ + abilityPoints, + weaponSplId: mainWeaponId, + mainOnlyAbilities: build + .map((row) => row[0]) + .filter((ability): ability is Ability => { + const abilityObj = abilities.find((a) => a.name === ability); + return Boolean(abilityObj && abilityObj.type !== "STACKABLE"); + }), + }); + + return { + build, + mainWeaponId, + handleChange, + analyzed, + abilityPoints, + effects, + ldeIntensity, + }; +} + +function serializeBuild(build: BuildAbilitiesTupleWithUnknown) { + return build + .flat() + .map((ability) => (ability === "UNKNOWN" ? UNKNOWN_SHORT : ability)) + .join(","); +} + +function validatedWeaponIdFromSearchParams( + searchParams: URLSearchParams +): MainWeaponId { + const weaponId = searchParams.get("weapon") + ? Number(searchParams.get("weapon")) + : null; + + if (mainWeaponIds.includes(weaponId as any)) { + return weaponId as MainWeaponId; + } + + return mainWeaponIds[0]; +} + +function validatedBuildFromSearchParams( + searchParams: URLSearchParams +): BuildAbilitiesTupleWithUnknown { + const abilitiesArr = searchParams.get("build") + ? searchParams.get("build")?.split(",") + : null; + + if (!abilitiesArr) return EMPTY_BUILD; + + try { + return [ + [ + validateAbility(["STACKABLE", "HEAD_MAIN_ONLY"], abilitiesArr[0]), + validateAbility(["STACKABLE"], abilitiesArr[1]), + validateAbility(["STACKABLE"], abilitiesArr[2]), + validateAbility(["STACKABLE"], abilitiesArr[3]), + ], + [ + validateAbility(["STACKABLE", "CLOTHES_MAIN_ONLY"], abilitiesArr[4]), + validateAbility(["STACKABLE"], abilitiesArr[5]), + validateAbility(["STACKABLE"], abilitiesArr[6]), + validateAbility(["STACKABLE"], abilitiesArr[7]), + ], + [ + validateAbility(["STACKABLE", "SHOES_MAIN_ONLY"], abilitiesArr[8]), + validateAbility(["STACKABLE"], abilitiesArr[9]), + validateAbility(["STACKABLE"], abilitiesArr[10]), + validateAbility(["STACKABLE"], abilitiesArr[11]), + ], + ]; + } catch (err) { + return EMPTY_BUILD; + } +} + +function validateAbility( + legalTypes: Array, + ability?: string +): AbilityWithUnknown { + if (!ability) throw new Error("Ability missing"); + if (ability === UNKNOWN_SHORT) return "UNKNOWN"; + + const abilityObj = abilities.find( + (a) => a.name === ability && legalTypes.includes(a.type) + ); + if (abilityObj) return abilityObj.name; + + throw new Error("Invalid ability"); +} + +function validatedLdeIntensityFromSearchParams(searchParams: URLSearchParams) { + const ldeIntensity = searchParams.get("lde") + ? Number(searchParams.get("lde")) + : null; + + if ( + !ldeIntensity || + !Number.isInteger(ldeIntensity) || + ldeIntensity < 0 || + ldeIntensity > MAX_LDE_INTENSITY + ) { + return 0; + } + + return ldeIntensity; +} + +function validatedEffectsFromSearchParams({ + searchParams, + build, +}: { + searchParams: URLSearchParams; + build: BuildAbilitiesTupleWithUnknown; +}) { + const result: Array = []; + + const effects = searchParams.getAll("effect"); + const effectsNoDuplicates = [...new Set(effects)]; + const abilities = build.flat(); + + for (const effect of effectsNoDuplicates) { + const effectObj = SPECIAL_EFFECTS.find((e) => e.type === effect); + if (!effectObj) continue; + + // e.g. even if OG effect is active in state + // it can't be on unless build has OG + if (isAbility(effect) && !abilities.includes(effect)) { + continue; + } + + result.push(effect as SpecialEffectType); + } + + // lde is a special case in that it's always + // considered active when in the build + if (abilities.includes("LDE") && !result.includes("LDE")) { + result.push("LDE"); + } + + return result; +} diff --git a/app/modules/analyzer/utils.test.ts b/app/modules/analyzer/utils.test.ts new file mode 100644 index 000000000..99dac92c4 --- /dev/null +++ b/app/modules/analyzer/utils.test.ts @@ -0,0 +1,52 @@ +import { suite } from "uvu"; +import * as assert from "uvu/assert"; +import type { AbilityWithUnknown } from "../in-game-lists/types"; +import { buildToAbilityPoints } from "./utils"; + +const BuildToAbilityPoints = suite("buildToAbilityPoints()"); + +const EMPTY_ROW: [ + AbilityWithUnknown, + AbilityWithUnknown, + AbilityWithUnknown, + AbilityWithUnknown +] = ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"]; + +BuildToAbilityPoints("Empty build leads to empty AP map", () => { + const aps = buildToAbilityPoints([EMPTY_ROW, EMPTY_ROW, EMPTY_ROW]); + + assert.equal(aps.size, 0); +}); + +BuildToAbilityPoints("Calculates ability points", () => { + const aps = buildToAbilityPoints([ + ["SS", "SS", "RSU", "RSU"], + EMPTY_ROW, + EMPTY_ROW, + ]); + + assert.equal(aps.get("SS"), 13); + assert.equal(aps.get("RSU"), 6); +}); + +BuildToAbilityPoints("Handles ability doubler", () => { + const aps = buildToAbilityPoints([ + EMPTY_ROW, + ["AD", "SS", "UNKNOWN", "UNKNOWN"], + EMPTY_ROW, + ]); + + assert.equal(aps.get("SS"), 6); +}); + +BuildToAbilityPoints("Does not calculate AP for main only abilities", () => { + const aps = buildToAbilityPoints([ + ["LDE", "SS", "RSU", "RSU"], + EMPTY_ROW, + EMPTY_ROW, + ]); + + assert.not.ok(aps.has("LDE")); +}); + +BuildToAbilityPoints.run(); diff --git a/app/modules/analyzer/utils.ts b/app/modules/analyzer/utils.ts new file mode 100644 index 000000000..ad495d38e --- /dev/null +++ b/app/modules/analyzer/utils.ts @@ -0,0 +1,149 @@ +import type { Ability, BuildAbilitiesTupleWithUnknown } from "../in-game-lists"; +import { abilities } from "../in-game-lists"; +import weaponParamsJson from "./weapon-params.json"; +import abilityValuesJson from "./ability-values.json"; +import type { + AbilityPoints, + MainWeaponParams, + ParamsJson, + SubWeaponParams, +} from "./types"; +import invariant from "tiny-invariant"; +import type { AbilityWithUnknown } from "../in-game-lists/types"; + +export function weaponParams(): ParamsJson { + // @ts-expect-error can be removed when Lean updates the json + return weaponParamsJson as ParamsJson; +} + +export function buildToAbilityPoints(build: BuildAbilitiesTupleWithUnknown) { + const result: AbilityPoints = new Map(); + + for (const abilityRow of build) { + let abilityDoublerActive = false; + for (const [i, ability] of abilityRow.entries()) { + if (ability === "AD") { + abilityDoublerActive = true; + } + if (!isStackableAbility(ability)) { + continue; + } + + const aps = i === 0 ? 10 : 3; + const apsDoubled = aps * (abilityDoublerActive ? 2 : 1); + + result.set(ability, (result.get(ability) ?? 0) + apsDoubled); + } + } + + return result; +} + +function isStackableAbility(ability: AbilityWithUnknown): ability is Ability { + if (ability === "UNKNOWN") return false; + const abilityObj = abilities.find((a) => a.name === ability); + invariant(abilityObj); + + return abilityObj.type === "STACKABLE"; +} + +export function apFromMap({ + abilityPoints, + ability, +}: { + abilityPoints: AbilityPoints; + ability: Ability; +}) { + return abilityPoints.get(ability) ?? 0; +} + +function abilityValues({ + key, + weapon, +}: { + key: keyof typeof abilityValuesJson; + weapon: MainWeaponParams | SubWeaponParams; +}): [number, number, number] { + const overwrites = weapon.overwrites?.[key]; + + const [High, Mid, Low] = abilityValuesJson[key]; + invariant(typeof High === "number"); + invariant(typeof Mid === "number"); + invariant(typeof Low === "number"); + + return [ + overwrites?.High ?? High, + overwrites?.Mid ?? Mid, + overwrites?.Low ?? Low, + ]; +} + +function calculateAbilityPointToPercent(ap: number) { + return Math.min(3.3 * ap - 0.027 * Math.pow(ap, 2), 100); +} + +function getSlope(high: number, mid: number, low: number) { + if (mid === low) { + return 0; + } + return (mid - low) / (high - low); +} + +function lerpN(p: number, s: number) { + if (s.toFixed(3) === "0.500") { + return p; + } + if (p === 0.0) { + return p; + } + if (p === 1.0) { + return p; + } + + return Math.pow(Math.E, -1 * ((Math.log(p) * Math.log(s)) / Math.log(2))); +} + +function abilityPointsToEffect({ + key, + abilityPoints, + weapon, +}: { + key: keyof typeof abilityValuesJson; + abilityPoints: number; + weapon: MainWeaponParams | SubWeaponParams; +}) { + const [high, mid, low] = abilityValues({ key, weapon }); + + const slope = getSlope(high, mid, low); + const percentage = calculateAbilityPointToPercent(abilityPoints) / 100.0; + const result = low + (high - low) * lerpN(slope, percentage); + + return result; +} + +export function abilityPointsToEffects({ + key, + abilityPoints, + weapon, +}: { + key: keyof typeof abilityValuesJson; + abilityPoints: number; + weapon: MainWeaponParams | SubWeaponParams; +}) { + return { + baseEffect: abilityPointsToEffect({ key, abilityPoints: 0, weapon }), + effect: abilityPointsToEffect({ key, abilityPoints, weapon }), + }; +} + +export function hasEffect({ + key, + weapon, +}: { + key: keyof typeof abilityValuesJson; + weapon: MainWeaponParams | SubWeaponParams; +}) { + const [high, mid, low] = abilityValues({ key, weapon }); + + return high !== mid || mid !== low; +} diff --git a/app/modules/analyzer/weapon-params.json b/app/modules/analyzer/weapon-params.json new file mode 100644 index 000000000..aca2ad6d7 --- /dev/null +++ b/app/modules/analyzer/weapon-params.json @@ -0,0 +1,966 @@ +{ + "mainWeapons": { + "0": { + "SpecialPoint": 180, + "subWeaponId": 6, + "specialWeaponId": 11, + "WeaponSpeedType": "Fast", + "DamageParam_ValueMax": 380, + "DamageParam_ValueMin": 190, + "InkRecoverStop": 15, + "InkConsume": 0.008 + }, + "10": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 2, + "WeaponSpeedType": "Fast", + "DamageParam_ValueMax": 280, + "DamageParam_ValueMin": 140, + "InkRecoverStop": 15, + "InkConsume": 0.0043 + }, + "20": { + "SpecialPoint": 200, + "subWeaponId": 2, + "specialWeaponId": 12, + "WeaponSpeedType": "Fast", + "DamageParam_ValueMax": 280, + "DamageParam_ValueMin": 140, + "InkConsume": 0.008 + }, + "30": { + "SpecialPoint": 200, + "subWeaponId": 5, + "specialWeaponId": 13, + "WeaponSpeedType": "Fast", + "DamageParam_ValueMax": 240, + "DamageParam_ValueMin": 120, + "InkRecoverStop": 15, + "InkConsume": 0.0055 + }, + "40": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 1, + "DamageParam_ValueMax": 360, + "DamageParam_ValueMin": 180, + "InkConsume": 0.0092 + }, + "45": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 1, + "DamageParam_ValueMax": 360, + "DamageParam_ValueMin": 180, + "InkConsume": 0.0092 + }, + "50": { + "SpecialPoint": 200, + "subWeaponId": 4, + "specialWeaponId": 9, + "DamageParam_ValueMax": 520, + "DamageParam_ValueMin": 300, + "InkConsume": 0.013 + }, + "60": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 15, + "WeaponSpeedType": "Fast", + "DamageParam_ValueMax": 280, + "DamageParam_ValueMin": 140, + "InkConsume": 0.008 + }, + "70": { + "SpecialPoint": 200, + "subWeaponId": 12, + "specialWeaponId": 12, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Mid": 0.7 + }, + "MoveVelRt_Shot": { + "High": -1, + "Mid": -1 + } + }, + "DamageParam_ValueMax": 420, + "DamageParam_ValueMin": 210, + "InkConsume": 0.02 + }, + "80": { + "SpecialPoint": 200, + "subWeaponId": 3, + "specialWeaponId": 8, + "DamageParam_ValueMax": 620, + "DamageParam_ValueMin": 350, + "InkConsume": 0.025 + }, + "90": { + "SpecialPoint": 200, + "subWeaponId": 12, + "specialWeaponId": 8, + "DamageParam_ValueMax": 320, + "DamageParam_ValueMin": 160, + "InkConsume": 0.016 + }, + "200": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 3, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Mid": 0.7 + }, + "ReduceJumpSwerveRate": { + "Mid": 0.5 + } + }, + "WeaponSpeedType": "Fast", + "DamageParam_ValueDirect": 1250, + "BlastParam_DistanceDamage": [ + { + "Damage": 700, + "Distance": 1 + }, + { + "Damage": 500, + "Distance": 3.57 + } + ], + "InkRecoverStop": 55, + "InkConsume": 0.075 + }, + "210": { + "SpecialPoint": 180, + "subWeaponId": 7, + "specialWeaponId": 2, + "overwrites": { + "ReduceJumpSwerveRate": { + "Mid": 0.5 + } + }, + "DamageParam_ValueDirect": 1250, + "BlastParam_DistanceDamage": [ + { + "Damage": 700, + "Distance": 0.94 + }, + { + "Damage": 500, + "Distance": 3.3 + } + ], + "InkRecoverStop": 60, + "InkConsume": 0.1 + }, + "220": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 7, + "overwrites": { + "ReduceJumpSwerveRate": { + "Mid": 0.5 + } + }, + "DamageParam_ValueDirect": 1250, + "BlastParam_DistanceDamage": [ + { + "Damage": 700, + "Distance": 1 + }, + { + "Damage": 500, + "Distance": 3.5 + } + ], + "InkRecoverStop": 70, + "InkConsume": 0.11 + }, + "230": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 1, + "overwrites": { + "ReduceJumpSwerveRate": { + "Mid": 0.5 + } + }, + "WeaponSpeedType": "Fast", + "DamageParam_ValueDirect": 600, + "BlastParam_DistanceDamage": [ + { + "Damage": 300, + "Distance": 1 + }, + { + "Damage": 300, + "Distance": 4 + } + ], + "InkRecoverStop": 40, + "InkConsume": 0.04 + }, + "240": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 14, + "overwrites": { + "ReduceJumpSwerveRate": { + "Mid": 0.5 + } + }, + "DamageParam_ValueDirect": 850, + "BlastParam_DistanceDamage": [ + { + "Damage": 350, + "Distance": 0.94 + }, + { + "Damage": 350, + "Distance": 3.3 + } + ], + "InkRecoverStop": 50, + "InkConsume": 0.07 + }, + "250": { + "SpecialPoint": 180, + "subWeaponId": 11, + "specialWeaponId": 8, + "overwrites": { + "ReduceJumpSwerveRate": { + "Mid": 0.5 + } + }, + "DamageParam_ValueDirect": 850, + "BlastParam_DistanceDamage": [ + { + "Damage": 350, + "Distance": 0.94 + }, + { + "Damage": 350, + "Distance": 3.3 + } + ], + "InkRecoverStop": 50, + "InkConsume": 0.08 + }, + "300": { + "SpecialPoint": 200, + "subWeaponId": 6, + "specialWeaponId": 12, + "TripleShotSpanFrame": 8, + "DamageParam_ValueMax": 290, + "DamageParam_ValueMin": 145, + "InkRecoverStop": 25, + "InkConsume": 0.0115 + }, + "310": { + "SpecialPoint": 200, + "subWeaponId": 9, + "specialWeaponId": 15, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Mid": 0.7 + }, + "MoveVelRt_Shot": { + "High": -1, + "Mid": -1 + } + }, + "TripleShotSpanFrame": 20, + "DamageParam_ValueMax": 410, + "DamageParam_ValueMin": 205, + "InkRecoverStop": 25, + "InkConsume": 0.0225 + }, + "400": { + "SpecialPoint": 200, + "subWeaponId": 4, + "specialWeaponId": 1, + "DamageParam_ValueMax": 380, + "DamageParam_ValueMin": 190, + "InkConsume": 0.022 + }, + "1000": { + "SpecialPoint": 180, + "subWeaponId": 7, + "specialWeaponId": 3, + "WeaponSpeedType": "Fast", + "InkConsume_WeaponSwingParam": 0.0396 + }, + "1010": { + "SpecialPoint": 180, + "subWeaponId": 6, + "specialWeaponId": 2, + "InkConsume_WeaponSwingParam": 0.085 + }, + "1020": { + "SpecialPoint": 190, + "subWeaponId": 3, + "specialWeaponId": 15, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Mid": 0.7 + } + }, + "WeaponSpeedType": "Slow", + "InkConsume_WeaponSwingParam": 0.18 + }, + "1030": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 4, + "InkConsume_WeaponVerticalSwingParam": 0.12, + "InkConsume_WeaponWideSwingParam": 0.08 + }, + "1100": { + "SpecialPoint": 180, + "subWeaponId": 0, + "specialWeaponId": 9, + "WeaponSpeedType": "Fast", + "InkConsume_WeaponSwingParam": 0.02 + }, + "1110": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 3, + "InkConsume_WeaponSwingParam": 0.032 + }, + "2000": { + "SpecialPoint": 190, + "subWeaponId": 9, + "specialWeaponId": 2, + "DamageParam_ValueFullCharge": 1400, + "DamageParam_ValueMaxCharge": 800, + "DamageParam_ValueMinCharge": 400, + "ChargeFrameFullCharge": 45, + "KeepChargeFullFrame": 75, + "InkConsumeFullCharge": 0.105, + "InkConsumeMinCharge": 0.018667 + }, + "2010": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 8, + "DamageParam_ValueFullCharge": 1600, + "DamageParam_ValueMaxCharge": 800, + "DamageParam_ValueMinCharge": 400, + "KeepChargeFullFrame": 75, + "InkConsumeFullCharge": 0.18, + "InkConsumeMinCharge": 0.0225 + }, + "2020": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 8, + "DamageParam_ValueFullCharge": 1600, + "DamageParam_ValueMaxCharge": 800, + "DamageParam_ValueMinCharge": 400, + "InkConsumeFullCharge": 0.18, + "InkConsumeMinCharge": 0.0225 + }, + "2030": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 7, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Mid": 0.7 + } + }, + "WeaponSpeedType": "Slow", + "DamageParam_ValueFullCharge": 1800, + "DamageParam_ValueMaxCharge": 800, + "DamageParam_ValueMinCharge": 400, + "ChargeFrameFullCharge": 92, + "KeepChargeFullFrame": 75, + "InkConsumeFullCharge": 0.25, + "InkConsumeMinCharge": 0.0225 + }, + "2040": { + "SpecialPoint": 200, + "subWeaponId": 10, + "specialWeaponId": 7, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Mid": 0.7 + } + }, + "WeaponSpeedType": "Slow", + "DamageParam_ValueFullCharge": 1800, + "DamageParam_ValueMaxCharge": 800, + "DamageParam_ValueMinCharge": 400, + "ChargeFrameFullCharge": 92, + "InkConsumeFullCharge": 0.25, + "InkConsumeMinCharge": 0.0225 + }, + "2050": { + "SpecialPoint": 200, + "subWeaponId": 7, + "specialWeaponId": 9, + "WeaponSpeedType": "Fast", + "DamageParam_ValueFullCharge": 850, + "DamageParam_ValueMaxCharge": 850, + "DamageParam_ValueMinCharge": 300, + "ChargeFrameFullCharge": 20, + "InkConsumeFullCharge": 0.084, + "InkConsumeMinCharge": 0.0336 + }, + "2060": { + "SpecialPoint": 200, + "subWeaponId": 13, + "specialWeaponId": 4, + "DamageParam_ValueFullCharge": 1800, + "DamageParam_ValueMaxCharge": 1300, + "DamageParam_ValueMinCharge": 400, + "ChargeFrameFullCharge": 75, + "KeepChargeFullFrame": 300, + "InkConsumeFullCharge": 0.15, + "InkConsumeMinCharge": 0.02 + }, + "3000": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 14, + "InkRecoverStop": 40, + "InkConsumeSlosher": 0.07 + }, + "3010": { + "SpecialPoint": 190, + "subWeaponId": 11, + "specialWeaponId": 10, + "WeaponSpeedType": "Fast", + "InkRecoverStop": 35, + "InkConsumeSlosher": 0.06 + }, + "3020": { + "SpecialPoint": 200, + "subWeaponId": 5, + "specialWeaponId": 6, + "InkRecoverStop": 42, + "InkConsumeSlosher": 0.084 + }, + "3030": { + "SpecialPoint": 190, + "subWeaponId": 3, + "specialWeaponId": 5, + "InkRecoverStop": 40, + "InkConsumeSlosher": 0.08 + }, + "3040": { + "SpecialPoint": 200, + "subWeaponId": 9, + "specialWeaponId": 5, + "WeaponSpeedType": "Slow", + "InkRecoverStop": 70, + "InkConsumeSlosher": 0.117 + }, + "4000": { + "SpecialPoint": 180, + "subWeaponId": 2, + "specialWeaponId": 11, + "overwrites": { + "MoveVelRt_Shot": { + "High": 1.4, + "Low": 1, + "Mid": 1.2 + } + }, + "DamageParam_ValueMax": 320, + "DamageParam_ValueMin": 160, + "InkRecoverStop": 30, + "InkConsumeFullChargeSplatling": 0.1725 + }, + "4010": { + "SpecialPoint": 200, + "subWeaponId": 3, + "specialWeaponId": 7, + "overwrites": { + "MoveVelRt_Shot": { + "High": 1.35, + "Low": 1, + "Mid": 1.175 + } + }, + "DamageParam_ValueMax": 300, + "DamageParam_ValueMin": 150, + "InkRecoverStop": 40, + "InkConsumeFullChargeSplatling": 0.225 + }, + "4020": { + "SpecialPoint": 190, + "subWeaponId": 7, + "specialWeaponId": 6, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Low": 1, + "Mid": 0.7 + }, + "MoveVelRt_Shot": { + "High": 1.35, + "Low": 1, + "Mid": 1.175 + } + }, + "WeaponSpeedType": "Slow", + "DamageParam_ValueMax": 320, + "DamageParam_ValueMin": 160, + "InkRecoverStop": 40, + "InkConsumeFullChargeSplatling": 0.35 + }, + "4030": { + "SpecialPoint": 200, + "subWeaponId": 5, + "specialWeaponId": 10, + "overwrites": { + "MoveVelRt_Shot": { + "High": 1.25, + "Low": 1, + "Mid": 1.125 + } + }, + "DamageParam_ValueMax": 280, + "DamageParam_ValueMin": 140, + "InkRecoverStop": 40, + "InkConsumeFullChargeSplatling": 0.25 + }, + "4040": { + "SpecialPoint": 190, + "subWeaponId": 9, + "specialWeaponId": 5, + "overwrites": { + "MoveVelRt_Shot": { + "High": 1.3, + "Low": 1, + "Mid": 1.15 + } + }, + "DamageParam_ValueMax": 320, + "DamageParam_ValueMin": 160, + "KeepChargeFullFrame": 200, + "InkRecoverStop": 40, + "InkConsumeFullChargeSplatling": 0.15 + }, + "5000": { + "SpecialPoint": 180, + "subWeaponId": 8, + "specialWeaponId": 15, + "WeaponSpeedType": "Fast", + "DamageParam_ValueMax": 360, + "DamageParam_ValueMin": 180, + "InkConsume": 0.00663, + "InkConsume_SideStepParam": 0.05 + }, + "5010": { + "SpecialPoint": 200, + "subWeaponId": 1, + "specialWeaponId": 12, + "DamageParam_ValueMax": 300, + "DamageParam_ValueMin": 150, + "InkConsume": 0.0072, + "InkConsume_SideStepParam": 0.07 + }, + "5020": { + "SpecialPoint": 180, + "subWeaponId": 4, + "specialWeaponId": 6, + "DamageParam_ValueMax": 360, + "DamageParam_ValueMin": 180, + "InkConsume": 0.014, + "InkConsume_SideStepParam": 0.08 + }, + "5030": { + "SpecialPoint": 200, + "subWeaponId": 0, + "specialWeaponId": 7, + "DamageParam_ValueMax": 280, + "DamageParam_ValueMin": 140, + "InkConsume": 0.012, + "InkConsume_SideStepParam": 0.08 + }, + "5040": { + "SpecialPoint": 200, + "subWeaponId": 7, + "specialWeaponId": 13, + "DamageParam_ValueMax": 280, + "DamageParam_ValueMin": 140, + "InkConsume": 0.008, + "InkConsume_SideStepParam": 0.03 + }, + "6000": { + "SpecialPoint": 200, + "subWeaponId": 3, + "specialWeaponId": 14, + "DamageParam_ValueMax": 810, + "InkConsumeUmbrella_WeaponShelterCanopyParam": 0.3 + }, + "6010": { + "SpecialPoint": 190, + "subWeaponId": 8, + "specialWeaponId": 8, + "overwrites": { + "ConsumeRt_Main": { + "High": 0.5, + "Mid": 0.7 + } + }, + "WeaponSpeedType": "Slow", + "DamageParam_ValueMax": 1190, + "CanopyHP": 7000, + "InkConsumeUmbrella_WeaponShelterCanopyParam": 0.3, + "InkConsume_WeaponShelterShotgunParam": 0.11 + }, + "6020": { + "SpecialPoint": 180, + "subWeaponId": 10, + "specialWeaponId": 13, + "WeaponSpeedType": "Fast", + "DamageParam_ValueMax": 400, + "CanopyHP": 2000, + "InkConsume_WeaponShelterShotgunParam": 0.04 + }, + "7010": { + "SpecialPoint": 200, + "subWeaponId": 11, + "specialWeaponId": 9, + "ChargeFrameFullCharge": 72, + "InkConsumeFullCharge_ChargeParam": 0.085 + }, + "7020": { + "SpecialPoint": 200, + "subWeaponId": 6, + "specialWeaponId": 4, + "WeaponSpeedType": "Fast", + "ChargeFrameFullCharge": 34, + "KeepChargeFullFrame": 75, + "InkConsumeFullCharge_ChargeParam": 0.065 + }, + "8000": { + "SpecialPoint": 200, + "subWeaponId": 2, + "specialWeaponId": 3, + "InkConsume_SwingParam": 0.04, + "InkConsumeFullCharge_ChargeParam": 0.09 + }, + "8010": { + "SpecialPoint": 180, + "subWeaponId": 13, + "specialWeaponId": 11, + "WeaponSpeedType": "Fast", + "InkConsume_SwingParam": 0.03, + "InkConsumeFullCharge_ChargeParam": 0.06 + } + }, + "subWeapons": { + "0": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.68, + "Low": 1.12, + "Mid": 1.4 + } + }, + "InkRecoverStop": 60, + "DistanceDamage": [ + { + "Damage": 1800, + "Distance": 3.6 + }, + { + "Damage": 300, + "Distance": 7 + } + ] + }, + "1": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.68, + "Low": 1.12, + "Mid": 1.4 + } + }, + "InkRecoverStop": 60, + "DistanceDamage": [ + { + "Damage": 1800, + "Distance": 4.6 + }, + { + "Damage": 300, + "Distance": 8 + } + ] + }, + "2": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.68, + "Low": 1.12, + "Mid": 1.4 + } + }, + "SubInkSaveLv": 0, + "InkConsume": 0.4, + "InkRecoverStop": 50, + "DistanceDamage": [ + { + "Damage": 350, + "Distance": 2.8 + }, + { + "Damage": 250, + "Distance": 4 + } + ] + }, + "3": { + "overwrites": { + "PeriodFirst": { + "High": 600, + "Low": 300, + "Mid": 450 + }, + "PeriodSecond": { + "High": 1020, + "Low": 900, + "Mid": 960 + } + }, + "SubInkSaveLv": 3, + "InkConsume": 0.6, + "InkRecoverStop": 60 + }, + "4": { + "overwrites": { + "MaxHP": { + "High": 15000, + "Low": 8000, + "Mid": 11500 + } + }, + "InkConsume": 0.6, + "InkRecoverStop": 85 + }, + "5": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.84, + "Low": 1.36, + "Mid": 1.6 + } + }, + "SubInkSaveLv": 1, + "InkConsume": 0.6, + "InkRecoverStop": 70, + "DistanceDamage_BlastParamArray": [ + [ + { + "Damage": 500, + "Distance": 1.6 + }, + { + "Damage": 350, + "Distance": 3.8 + } + ], + [ + { + "Damage": 500, + "Distance": 1.95 + }, + { + "Damage": 350, + "Distance": 4.5 + } + ], + [ + { + "Damage": 500, + "Distance": 2.6 + }, + { + "Damage": 350, + "Distance": 5.45 + } + ] + ] + }, + "6": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 0.52, + "Low": 0.4, + "Mid": 0.46 + } + }, + "InkRecoverStop": 70, + "DistanceDamage_BlastParamMaxCharge": [ + { + "Damage": 1800, + "Distance": 4.6 + }, + { + "Damage": 300, + "Distance": 8 + } + ], + "DistanceDamage_BlastParamMinCharge": [ + { + "Damage": 1800, + "Distance": 1.6 + }, + { + "Damage": 300, + "Distance": 5 + } + ], + "DirectDamage": 200 + }, + "7": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.68, + "Low": 1.12, + "Mid": 1.4 + } + }, + "SubInkSaveLv": 1, + "InkConsume": 0.55, + "InkRecoverStop": 85, + "DistanceDamage": [ + { + "Damage": 1800, + "Distance": 2.85 + }, + { + "Damage": 300, + "Distance": 6.5 + } + ] + }, + "8": { + "overwrites": {}, + "SubInkSaveLv": 3, + "InkConsume": 0.75, + "InkRecoverStop": 0 + }, + "9": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.87, + "Low": 1.38, + "Mid": 1.64 + }, + "MarkingFrameSubSpec": { + "High": 960, + "Low": 480, + "Mid": 720 + } + }, + "SubInkSaveLv": 1, + "InkConsume": 0.45, + "InkRecoverStop": 75 + }, + "10": { + "overwrites": { + "MarkingFrameSubSpec": { + "High": 600, + "Low": 300, + "Mid": 450 + }, + "SensorRadius": { + "High": 4, + "Low": 3, + "Mid": 3.5 + }, + "ExplosionRadius": { + "High": 11, + "Low": 8, + "Mid": 9.5 + } + }, + "SubInkSaveLv": 3, + "InkConsume": 0.6, + "InkRecoverStop": 0, + "DistanceDamage": [ + { + "Damage": 450, + "Distance": 3.6 + }, + { + "Damage": 350, + "Distance": 8 + } + ] + }, + "11": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.68, + "Low": 1.12, + "Mid": 1.4 + } + }, + "SubInkSaveLv": 1, + "InkConsume": 0.6, + "InkRecoverStop": 75 + }, + "12": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 5.4, + "Low": 5, + "Mid": 5.2 + }, + "MarkingFrameSubSpec": { + "High": 600, + "Low": 300, + "Mid": 450 + } + }, + "SubInkSaveLv": 0, + "InkConsume": 0.4, + "InkRecoverStop": 50, + "DirectDamage": 300 + }, + "13": { + "overwrites": { + "SpawnSpeedZSpecUp": { + "High": 1.84, + "Low": 1.36, + "Mid": 1.6 + } + }, + "InkConsume": 0.65, + "InkRecoverStop": 88, + "DistanceDamage_BlastParamChase": [ + { + "Damage": 600, + "Distance": 2.6 + }, + { + "Damage": 350, + "Distance": 6 + } + ], + "DistanceDamage_SplashBlastParam": [ + { + "Damage": 120, + "Distance": 2.6 + } + ] + } + } +} diff --git a/app/modules/i18n/config.ts b/app/modules/i18n/config.ts index 3d893b1dd..fc2e21c49 100644 --- a/app/modules/i18n/config.ts +++ b/app/modules/i18n/config.ts @@ -1,6 +1,10 @@ export const DEFAULT_LANGUAGE = "en"; export const languages = [ + { + code: "da", + name: "Dansk", + }, { code: "de", name: "Deutsch", diff --git a/app/modules/in-game-lists/gear-ids.ts b/app/modules/in-game-lists/gear-ids.ts index 12accddcd..2ffb54671 100644 --- a/app/modules/in-game-lists/gear-ids.ts +++ b/app/modules/in-game-lists/gear-ids.ts @@ -1,23 +1,29 @@ export const headGearIds = [ - 1, 1000, 1002, 1003, 1005, 1012, 1020, 1021, 1028, 1036, 2008, 3001, 3003, - 3008, 3009, 3011, 3012, 3016, 3021, 3025, 3026, 3027, 4004, 4008, 4015, 4016, - 4017, 5001, 5004, 5007, 5008, 6001, 6003, 6004, 7007, 7012, 7013, 7014, 8005, - 8008, 8011, 8014, 8016, 9003, 9007, 9009, + 1, 1000, 1002, 1003, 1005, 1012, 1020, 1021, 1028, 1036, 2008, 3001, 3002, + 3003, 3008, 3009, 3011, 3012, 3016, 3021, 3022, 3023, 3024, 3025, 3026, 3027, + 3029, 4004, 4006, 4008, 4015, 4016, 4017, 4019, 5000, 5001, 5004, 5007, 5008, + 6001, 6003, 6004, 7007, 7012, 7013, 7014, 8005, 8008, 8011, 8014, 8015, 8016, + 9003, 9007, 9009, 21010, 25000, 25001, 25002, 25003, 25004, 25005, 25006, + 25007, 25008, 25009, 25010, 25016, 25017, 27000, 27004, 27109, 27306, 28000, ] as const; export const clothesGearIds = [ - 1001, 1004, 1005, 1006, 1013, 1014, 1015, 1016, 1018, 1019, 1020, 1021, 1035, - 1062, 1066, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1082, 1083, - 1084, 1085, 1088, 1091, 2004, 3000, 3001, 3006, 3008, 3009, 4004, 4005, 4009, - 4010, 5000, 5001, 5006, 5014, 5015, 5019, 5023, 5045, 5046, 5047, 5048, 5049, - 5050, 5051, 5054, 6000, 6008, 7001, 7010, 7016, 7017, 7018, 8000, 8003, 8005, - 8012, 8017, 8018, 8019, 8020, 8024, 8025, 8030, 8031, 8033, 8034, 8036, 8040, - 9010, 9011, 10006, 10012, + 1000, 1001, 1004, 1005, 1006, 1013, 1014, 1015, 1016, 1018, 1019, 1020, 1021, + 1035, 1062, 1063, 1066, 1067, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, + 1077, 1082, 1083, 1084, 1085, 1088, 1090, 1091, 2004, 3000, 3001, 3004, 3006, + 3008, 3009, 4004, 4005, 4009, 4010, 5000, 5001, 5006, 5014, 5015, 5019, 5023, + 5045, 5046, 5047, 5048, 5049, 5050, 5051, 5054, 6000, 6008, 7001, 7010, 7016, + 7017, 7018, 8000, 8003, 8005, 8012, 8017, 8018, 8019, 8020, 8024, 8025, 8030, + 8031, 8033, 8034, 8036, 8040, 9010, 9011, 9012, 9013, 10006, 10012, 10014, + 25000, 25001, 25002, 25003, 25004, 25005, 25006, 25007, 25008, 25009, 25010, + 25014, 25015, 25017, 26000, 27000, 27004, 27306, ] as const; export const shoesGearIds = [ - 1000, 1008, 1009, 1021, 1022, 1024, 2000, 2001, 2004, 2005, 2016, 2017, 2018, - 2042, 2043, 2045, 3001, 3004, 3013, 3020, 3022, 3023, 3024, 3025, 4000, 4001, - 4007, 4008, 4009, 4011, 4012, 4015, 4016, 4017, 4021, 4022, 5000, 5001, 6000, - 6001, 6006, 6007, 6012, 6021, 7002, 8010, 8013, 8014, + 1000, 1008, 1009, 1021, 1022, 1023, 1024, 2000, 2001, 2003, 2004, 2005, 2016, + 2017, 2018, 2042, 2043, 2045, 3000, 3001, 3004, 3013, 3020, 3022, 3023, 3024, + 3025, 3026, 4000, 4001, 4007, 4008, 4009, 4011, 4012, 4014, 4015, 4016, 4017, + 4021, 4022, 5000, 5001, 6000, 6001, 6006, 6007, 6012, 6020, 6021, 6023, 6025, + 7002, 8010, 8013, 8014, 25000, 25001, 25002, 25003, 25004, 25005, 25006, + 25007, 25008, 25009, 25010, 25014, 25015, 27000, 27004, 27306, ] as const; diff --git a/app/modules/in-game-lists/index.ts b/app/modules/in-game-lists/index.ts index e152b6648..1959a8aa3 100644 --- a/app/modules/in-game-lists/index.ts +++ b/app/modules/in-game-lists/index.ts @@ -1,6 +1,35 @@ export { stages } from "./stages"; export { modes, modesShort } from "./modes"; -export { weaponIds } from "./weapon-ids"; +export { + mainWeaponIds, + subWeaponIds, + specialWeaponIds, + SPLAT_BOMB_ID, + SUCTION_BOMB_ID, + BURST_BOMB_ID, + SPRINKLER_ID, + SPLASH_WALL_ID, + FIZZY_BOMB_ID, + CURLING_BOMB_ID, + AUTO_BOMB_ID, + SQUID_BEAKON_ID, + POINT_SENSOR_ID, + INK_MINE_ID, + TOXIC_MIST_ID, + ANGLE_SHOOTER_ID, + TORPEDO_ID, +} from "./weapon-ids"; export { headGearIds, clothesGearIds, shoesGearIds } from "./gear-ids"; export { abilitiesShort, abilities } from "./abilities"; -export type { Ability, AbilityType, ModeShort, Stage } from "./types"; +export type { + Ability, + AbilityType, + ModeShort, + Stage, + BuildAbilitiesTuple, + BuildAbilitiesTupleWithUnknown, + MainWeaponId, + SubWeaponId, + SpecialWeaponId, +} from "./types"; +export { isAbility } from "./utils"; diff --git a/app/modules/in-game-lists/types.ts b/app/modules/in-game-lists/types.ts index fef1affee..026e42ab6 100644 --- a/app/modules/in-game-lists/types.ts +++ b/app/modules/in-game-lists/types.ts @@ -1,6 +1,11 @@ import type { abilities } from "./abilities"; import type { modes } from "./modes"; import type { stages } from "./stages"; +import type { + subWeaponIds, + mainWeaponIds, + specialWeaponIds, +} from "./weapon-ids"; export type ModeShort = typeof modes[number]["short"]; @@ -10,6 +15,10 @@ export type Ability = typeof abilities[number]["name"]; export type AbilityWithUnknown = typeof abilities[number]["name"] | "UNKNOWN"; export type AbilityType = typeof abilities[number]["type"]; +export type MainWeaponId = typeof mainWeaponIds[number]; +export type SubWeaponId = typeof subWeaponIds[number]; +export type SpecialWeaponId = typeof specialWeaponIds[number]; + export type BuildAbilitiesTuple = [ head: [main: Ability, s1: Ability, s2: Ability, s3: Ability], clothes: [main: Ability, s1: Ability, s2: Ability, s3: Ability], diff --git a/app/modules/in-game-lists/utils.ts b/app/modules/in-game-lists/utils.ts new file mode 100644 index 000000000..c44e9c085 --- /dev/null +++ b/app/modules/in-game-lists/utils.ts @@ -0,0 +1,6 @@ +import { abilities } from "./abilities"; +import type { Ability } from "./types"; + +export function isAbility(value: string): value is Ability { + return Boolean(abilities.some((a) => a.name === value)); +} diff --git a/app/modules/in-game-lists/weapon-ids.ts b/app/modules/in-game-lists/weapon-ids.ts index 5a86bae4d..11b48fde9 100644 --- a/app/modules/in-game-lists/weapon-ids.ts +++ b/app/modules/in-game-lists/weapon-ids.ts @@ -1,6 +1,42 @@ -export const weaponIds = [ - 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 200, 210, 220, 230, 240, 250, 300, 310, - 400, 1000, 1010, 1020, 1030, 1100, 1110, 2000, 2010, 2020, 2030, 2040, 2050, - 2060, 3000, 3010, 3020, 3030, 3040, 4000, 4010, 4020, 4030, 4040, 5000, 5010, - 5020, 5030, 5040, 6000, 6010, 6020, 7010, 8000, 8010, +export const mainWeaponIds = [ + 0, 10, 20, 30, 40, 45, 50, 60, 70, 80, 90, 200, 210, 220, 230, 240, 250, 300, + 310, 400, 1000, 1010, 1020, 1030, 1100, 1110, 2000, 2010, 2020, 2030, 2040, + 2050, 2060, 3000, 3010, 3020, 3030, 3040, 4000, 4010, 4020, 4030, 4040, 5000, + 5010, 5020, 5030, 5040, 6000, 6010, 6020, 7010, 7020, 8000, 8010, +] as const; + +export const SPLAT_BOMB_ID = 0; +export const SUCTION_BOMB_ID = 1; +export const BURST_BOMB_ID = 2; +export const SPRINKLER_ID = 3; +export const SPLASH_WALL_ID = 4; +export const FIZZY_BOMB_ID = 5; +export const CURLING_BOMB_ID = 6; +export const AUTO_BOMB_ID = 7; +export const SQUID_BEAKON_ID = 8; +export const POINT_SENSOR_ID = 9; +export const INK_MINE_ID = 10; +export const TOXIC_MIST_ID = 11; +export const ANGLE_SHOOTER_ID = 12; +export const TORPEDO_ID = 13; + +export const subWeaponIds = [ + SPLAT_BOMB_ID, + SUCTION_BOMB_ID, + BURST_BOMB_ID, + SPRINKLER_ID, + SPLASH_WALL_ID, + FIZZY_BOMB_ID, + CURLING_BOMB_ID, + AUTO_BOMB_ID, + SQUID_BEAKON_ID, + POINT_SENSOR_ID, + INK_MINE_ID, + TOXIC_MIST_ID, + ANGLE_SHOOTER_ID, + TORPEDO_ID, +] as const; + +export const specialWeaponIds = [ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ] as const; diff --git a/app/root.tsx b/app/root.tsx index 25a551ea2..61d764c39 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -31,6 +31,7 @@ import { useChangeLanguage } from "remix-i18next"; import { useTranslation } from "react-i18next"; import { Theme, ThemeHead, useTheme, ThemeProvider } from "./modules/theme"; import { getThemeSession } from "./modules/theme/session.server"; +import { COMMON_PREVIEW_IMAGE } from "./utils/urls"; export const unstable_shouldReload: ShouldReloadFunction = () => false; @@ -49,6 +50,7 @@ export const meta: MetaFunction = () => ({ title: "sendou.ink", viewport: "width=device-width,initial-scale=1", "theme-color": "#8263de", + "og:image": COMMON_PREVIEW_IMAGE, }); export interface RootLoaderData { diff --git a/app/routes/analyzer.tsx b/app/routes/analyzer.tsx new file mode 100644 index 000000000..fffc046cb --- /dev/null +++ b/app/routes/analyzer.tsx @@ -0,0 +1,672 @@ +import { type MetaFunction, type LinksFunction } from "@remix-run/node"; +import * as React from "react"; +import { useTranslation } from "react-i18next"; +import { AbilitiesSelector } from "~/components/AbilitiesSelector"; +import { Ability } from "~/components/Ability"; +import { WeaponCombobox } from "~/components/Combobox"; +import { Image } from "~/components/Image"; +import { Main } from "~/components/Main"; +import { Toggle } from "~/components/Toggle"; +import { ADMIN_DISCORD_ID } from "~/constants"; +import { useSetTitle } from "~/hooks/useSetTitle"; +import type { AnalyzedBuild, Stat } from "~/modules/analyzer"; +import { MAX_LDE_INTENSITY } from "~/modules/analyzer"; +import { useAnalyzeBuild } from "~/modules/analyzer"; +import { + lastDitchEffortIntensityToAp, + SPECIAL_EFFECTS, +} from "~/modules/analyzer/specialEffects"; +import type { + AbilityPoints, + SpecialEffectType, +} from "~/modules/analyzer/types"; +import { useUser } from "~/modules/auth"; +import type { BuildAbilitiesTupleWithUnknown } from "~/modules/in-game-lists"; +import { + SPLASH_WALL_ID, + SPRINKLER_ID, + TOXIC_MIST_ID, +} from "~/modules/in-game-lists"; +import { ANGLE_SHOOTER_ID } from "~/modules/in-game-lists"; +import { INK_MINE_ID, POINT_SENSOR_ID } from "~/modules/in-game-lists"; +import { + abilities, + isAbility, + type MainWeaponId, + type SubWeaponId, +} from "~/modules/in-game-lists"; +import styles from "~/styles/analyzer.css"; +import { makeTitle } from "~/utils/strings"; +import { specialWeaponImageUrl, subWeaponImageUrl } from "~/utils/urls"; + +export const CURRENT_PATCH = "1.1"; + +export const meta: MetaFunction = () => { + return { + title: makeTitle("Build Analyzer"), + }; +}; + +export const links: LinksFunction = () => { + return [{ rel: "stylesheet", href: styles }]; +}; + +export const handle = { + i18n: ["weapons", "analyzer"], +}; + +const canViewInProduction = (discordId?: string) => { + const LEAN_ID = "86905636402495488"; + const SENDOU_ID = ADMIN_DISCORD_ID; + + return discordId === LEAN_ID || discordId === SENDOU_ID; +}; + +export default function BuildAnalyzerPage() { + const user = useUser(); + const { t } = useTranslation(["analyzer", "common", "weapons"]); + useSetTitle(t("common:pages.buildAnalyzer")); + const { + build, + mainWeaponId, + handleChange, + analyzed, + abilityPoints, + ldeIntensity, + effects, + } = useAnalyzeBuild(); + + if ( + process.env.NODE_ENV === "production" && + !canViewInProduction(user?.discordId) + ) { + return
Coming soon :)
; + } + + return ( +
+
+
+
+
+ + opt && + handleChange({ + newMainWeaponId: Number(opt.value) as MainWeaponId, + }) + } + className="w-full-important" + clearsInputOnFocus + /> +
+ +
+
+ handleChange({ newBuild })} + /> + + handleChange({ newLdeIntensity }) + } + handleAddEffect={(newEffect) => + handleChange({ newEffects: [...effects, newEffect] }) + } + handleRemoveEffect={(effectToRemove) => + handleChange({ + newEffects: effects.filter((e) => e !== effectToRemove), + }) + } + effects={effects} + /> + +
+
+ {t("analyzer:patch")} {CURRENT_PATCH} +
+
+
+ + {typeof analyzed.stats.mainWeaponWhiteInkSeconds === "number" && ( + + )} + {typeof analyzed.weapon.brellaCanopyHp === "number" && ( + + )} + {typeof analyzed.weapon.fullChargeSeconds === "number" && ( + + )} + {typeof analyzed.weapon.maxChargeHoldSeconds === "number" && ( + + )} + + + + + {analyzed.stats.subVelocity && ( + + )} + {analyzed.stats.subFirstPhaseDuration && ( + + )} + {analyzed.stats.subSecondPhaseDuration && ( + + )} + {analyzed.stats.subMarkingTimeInSeconds && ( + + )} + {analyzed.stats.subMarkingRadius && ( + + )} + {analyzed.stats.subExplosionRadius && ( + + )} + {analyzed.stats.subHp && ( + + )} + + + + + + + + + + + + + + +
+ {t("analyzer:trackingSubDefExplanation")} +
+
+ + {analyzed.stats.damages.length > 0 && ( + + + + )} + + {analyzed.stats.fullInkTankOptions.length > 0 && ( + + + + )} + + + + + + + + + + + + + + + + +
+
+
+ ); +} + +function WeaponInfoBadges({ analyzed }: { analyzed: AnalyzedBuild }) { + const { t } = useTranslation(["weapons", "analyzer"]); + + return ( +
+
+ {t(`weapons:SUB_${analyzed.weapon.subWeaponSplId}`)} + {t(`weapons:SUB_${analyzed.weapon.subWeaponSplId}`)} +
+
+ {t(`weapons:SPECIAL_${analyzed.weapon.specialWeaponSplId}`)} + {t(`weapons:SPECIAL_${analyzed.weapon.specialWeaponSplId}`)} +
+
+ {t("analyzer:attribute.weight")}{" "} + {t(`analyzer:attribute.weight.${analyzed.weapon.speedType}`)} +
+
+ ); +} + +function EffectsSelector({ + build, + effects, + ldeIntensity, + handleLdeIntensityChange, + handleAddEffect, + handleRemoveEffect, +}: { + build: BuildAbilitiesTupleWithUnknown; + effects: Array; + ldeIntensity: number; + handleLdeIntensityChange: (newLdeIntensity: number) => void; + handleAddEffect: (effect: SpecialEffectType) => void; + handleRemoveEffect: (effect: SpecialEffectType) => void; +}) { + const { t } = useTranslation(["weapons", "analyzer"]); + + const effectsToShow = SPECIAL_EFFECTS.filter( + (effect) => !isAbility(effect.type) || build.flat().includes(effect.type) + ).reverse(); // reverse to show Tacticooler first as it always shows + + return ( +
+ {effectsToShow.map((effect) => { + return ( + +
+ {isAbility(effect.type) ? ( + + ) : ( + {t("weapons:SPECIAL_15")} + )} +
+
+ {effect.type === "LDE" ? ( + + ) : ( + + checked + ? handleAddEffect(effect.type) + : handleRemoveEffect(effect.type) + } + tiny + /> + )} +
+
+ ); + })} +
+ ); +} + +function AbilityPointsDetails({ + abilityPoints, +}: { + abilityPoints: AbilityPoints; +}) { + const { t } = useTranslation("analyzer"); + + return ( +
+ {t("abilityPoints")} +
+ {abilities + .filter((a) => (abilityPoints.get(a.name) ?? 0) > 0) + .sort((a, b) => { + return abilityPoints.get(b.name)! - abilityPoints.get(a.name)!; + }) + .map((a) => ( +
+ +
+ {abilityPoints.get(a.name)} +
+
+ ))} +
+
+ ); +} + +function StatCategory({ + title, + children, + containerClassName = "analyzer__stat-collection", +}: { + title: string; + children: React.ReactNode; + containerClassName?: string; +}) { + return ( +
+ {title} +
{children}
+
+ ); +} + +function StatCard({ + title, + stat, + suffix, +}: { + title: string; + stat: Stat | number; + suffix?: string; +}) { + const { t } = useTranslation("analyzer"); + const baseValue = typeof stat === "number" ? stat : stat.baseValue; + + return ( +
+
+

{title}

+
+
+

+ {typeof stat === "number" ? t("value") : t("base")} +

{" "} +
+ {baseValue} + {suffix} +
+
+ {typeof stat !== "number" && stat.value !== stat.baseValue && ( +
+

+ {t("build")} +

{" "} +
+ {stat.value} + {suffix} +
+
+ )} +
+
+ {typeof stat !== "number" && ( +
+ +
+ )} +
+ ); +} + +function DamageTable({ + values, + isTripleShooter, + subWeaponId, +}: { + values: AnalyzedBuild["stats"]["damages"]; + isTripleShooter: AnalyzedBuild["weapon"]["isTripleShooter"]; + subWeaponId: SubWeaponId; +}) { + const { t } = useTranslation(["weapons", "analyzer"]); + + const showDistanceColumn = values.some((val) => val.distance); + + return ( + <> + + + + + + {showDistanceColumn && ( + + )} + + + + {values.map((val) => { + const damage = isTripleShooter + ? `${val.value}+${val.value}+${val.value}` + : val.value; + + const typeRowName = val.type.startsWith("BOMB_") + ? t(`weapons:SUB_${subWeaponId}`) + : t(`analyzer:damage.${val.type as "NORMAL_MIN"}`); + + return ( + + + + {showDistanceColumn && } + + ); + })} + +
{t("analyzer:damage.header.type")}{t("analyzer:damage.header.damage")}{t("analyzer:damage.header.distance")}
{typeRowName} + {damage}{" "} + {val.shotsToSplat && ( + + {t("analyzer:damage.toSplat", { + count: val.shotsToSplat, + })} + + )} + {val.distance}
+ + ); +} + +function ConsumptionTable({ + options, + subWeaponId, +}: { + options: AnalyzedBuild["stats"]["fullInkTankOptions"]; + subWeaponId: SubWeaponId; +}) { + const { t } = useTranslation(["analyzer", "weapons"]); + const maxSubsToUse = Math.max(...options.map((opt) => opt.subsUsed)); + const types = Array.from(new Set(options.map((opt) => opt.type))); + + return ( + <> + + + + + {types.map((type) => ( + + ))} + + + + {new Array(maxSubsToUse + 1).fill(null).map((_, subsUsed) => { + return ( + + + {options + .filter((opt) => opt.subsUsed === subsUsed) + .map((opt) => { + return ; + })} + + ); + })} + +
{t(`weapons:SUB_${subWeaponId}`)}{t(`analyzer:stat.consumption.${type}`)}
×{subsUsed}{opt.value}
+
+ {t("analyzer:consumptionExplanation", { maxSubsToUse })} +
+ + ); +} diff --git a/app/routes/badges/$id/edit.tsx b/app/routes/badges/$id/edit.tsx index c0cf7ab35..d597b644c 100644 --- a/app/routes/badges/$id/edit.tsx +++ b/app/routes/badges/$id/edit.tsx @@ -18,6 +18,7 @@ import { assertUnreachable } from "~/utils/types"; import { db } from "~/db"; import type { User } from "~/db/types"; import { badgePage } from "~/utils/urls"; +import { Label } from "~/components/Label"; const editBadgeActionSchema = z.union([ z.object({ @@ -121,6 +122,22 @@ function Managers({ data }: { data: BadgeDetailsLoaderData }) {

Managers

+
+ + { + if (!user) return; + + setManagers([ + ...managers, + { discordFullName: user.label, id: Number(user.value) }, + ]); + }} + userIdsToOmit={userIdsToOmitFromCombobox} + /> +
    {managers.map((manager) => (
  • @@ -137,21 +154,6 @@ function Managers({ data }: { data: BadgeDetailsLoaderData }) {
  • ))}
-
- { - if (!user) return; - - setManagers([ - ...managers, - { discordFullName: user.label, id: Number(user.value) }, - ]); - }} - userIdsToOmit={userIdsToOmitFromCombobox} - /> -

Owners

-
    - {owners.map((owner) => ( -
  • - {owner.discordFullName} - - setOwners( - owners.map((o) => - o.id === owner.id - ? { ...o, count: Number(e.target.value) } - : o - ) - ) - } - /> -
  • - ))} -
-
+
+
+
    + {owners.map((owner) => ( +
  • + {owner.discordFullName} + + setOwners( + owners.map((o) => + o.id === owner.id + ? { ...o, count: Number(e.target.value) } + : o + ) + ) + } + /> +
  • + ))} +
{ownerDifferences.length > 0 ? (
    {ownerDifferences.map((o) => ( diff --git a/app/routes/calendar/$id/report-winners.tsx b/app/routes/calendar/$id/report-winners.tsx index 46e07686e..a3c501115 100644 --- a/app/routes/calendar/$id/report-winners.tsx +++ b/app/routes/calendar/$id/report-winners.tsx @@ -402,6 +402,7 @@ function Players({ variant="minimal" onClick={() => handlePlayerInputTypeChange(i)} data-cy="change-input-type-button" + className="outline-theme" > {asPlainInput ? t("forms.team.player.addAsUser") diff --git a/app/routes/calendar/index.tsx b/app/routes/calendar/index.tsx index 8dadf56d3..735bd364e 100644 --- a/app/routes/calendar/index.tsx +++ b/app/routes/calendar/index.tsx @@ -330,83 +330,74 @@ function EventsList({
- {events.map((calendarEvent, i) => { + {events.map((calendarEvent) => { return ( - -
-
-
+
+
+
-
- -

- {calendarEvent.name}{" "} - {calendarEvent.nthAppearance > 1 ? ( - - {t("day", { - number: calendarEvent.nthAppearance, - })} - - ) : null} -

- - + {databaseTimestampToDate( + calendarEvent.startTime + ).toLocaleTimeString(i18n.language, { + hour: "numeric", + minute: "numeric", + })} + +
+ From {discordFullName(calendarEvent)}
-
- {calendarEvent.discordUrl ? ( - - Discord - - ) : null} +
+ +

+ {calendarEvent.name}{" "} + {calendarEvent.nthAppearance > 1 ? ( + + {t("day", { + number: calendarEvent.nthAppearance, + })} + + ) : null} +

+ + +
+
+
+ {calendarEvent.discordUrl ? ( - {resolveBaseUrl(calendarEvent.bracketUrl)} + Discord -
-
- {i < events.length - 1 ? ( -
- ) : null} -
+ ) : null} + + {resolveBaseUrl(calendarEvent.bracketUrl)} + +
+ ); })}
diff --git a/app/routes/u.$identifier/builds/new.tsx b/app/routes/u.$identifier/builds/new.tsx index 694a0a9b6..18fd16072 100644 --- a/app/routes/u.$identifier/builds/new.tsx +++ b/app/routes/u.$identifier/builds/new.tsx @@ -14,7 +14,7 @@ import { GearCombobox, WeaponCombobox } from "~/components/Combobox"; import { Image } from "~/components/Image"; import { Label } from "~/components/Label"; import { Main } from "~/components/Main"; -import { BUILD } from "~/constants"; +import { BUILD, EMPTY_BUILD } from "~/constants"; import { db } from "~/db"; import type { GearType } from "~/db/types"; import { requireUser } from "~/modules/auth"; @@ -23,11 +23,12 @@ import { headGearIds, modesShort, shoesGearIds, - weaponIds, + mainWeaponIds, } from "~/modules/in-game-lists"; import type { BuildAbilitiesTuple, BuildAbilitiesTupleWithUnknown, + MainWeaponId, } from "~/modules/in-game-lists/types"; import { parseRequestFormData } from "~/utils/remix"; import { modeImageUrl, userBuildsPage } from "~/utils/urls"; @@ -67,7 +68,7 @@ const newBuildActionSchema = z.object({ z .number() .refine((val) => - weaponIds.includes(val as typeof weaponIds[number]) + mainWeaponIds.includes(val as typeof mainWeaponIds[number]) ) ) ) @@ -141,7 +142,7 @@ export const action: ActionFunction = async ({ request }) => { clothesGearSplId: data["CLOTHES[value]"], shoesGearSplId: data["SHOES[value]"], modes: modesShort.filter((mode) => data[mode]), - weaponSplIds: data["weapon[value]"], + weaponSplIds: data["weapon[value]"] as Array, ownerId: user.id, }; if (data.buildToEditId) { @@ -367,11 +368,7 @@ function Abilities() { const { buildToEdit } = useLoaderData(); const [abilities, setAbilities] = React.useState( - buildToEdit?.abilities ?? [ - ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"], - ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"], - ["UNKNOWN", "UNKNOWN", "UNKNOWN", "UNKNOWN"], - ] + buildToEdit?.abilities ?? EMPTY_BUILD ); return ( diff --git a/app/styles/analyzer.css b/app/styles/analyzer.css new file mode 100644 index 000000000..058028e1d --- /dev/null +++ b/app/styles/analyzer.css @@ -0,0 +1,156 @@ +.analyzer__container { + display: grid; + gap: var(--s-10); + grid-template-columns: 1fr 2fr; +} + +.analyzer__left-column { + position: sticky; + top: 2rem; + display: flex; + height: max-content; + flex-direction: column; + align-items: center; + gap: var(--s-8); +} + +.analyzer__weapon-info-badges { + display: grid; + color: var(--text-lighter); + font-size: var(--fonts-xxs); + font-weight: var(--semi-bold); + gap: var(--s-2); + grid-template-columns: 1fr 1fr; +} + +.analyzer__weapon-info-badge { + display: flex; + align-items: center; + justify-content: center; + background-color: var(--theme-transparent); + border-radius: var(--rounded); + gap: var(--s-1); + padding-block: var(--s-1); + padding-inline: var(--s-1-5); +} + +.analyzer__effects-selector { + display: grid; + gap: var(--s-2); + grid-template-columns: 1fr 2.5fr; + place-items: center; +} + +.analyzer__lde-intensity-select { + font-size: var(--fonts-xxs); +} + +.analyzer__ap-summary { + width: 100%; + background-color: var(--bg-lighter); + border-radius: var(--rounded); + font-size: var(--fonts-xxs); + font-weight: var(--semi-bold); + padding-block: var(--s-1); + padding-inline: var(--s-2); +} + +.analyzer__ap-text { + color: var(--text-lighter); + font-size: var(--fonts-xxs); + font-weight: var(--semi-bold); +} + +.analyzer__summary { + background-color: var(--bg-lighter); + border-radius: var(--rounded); + font-size: var(--fonts-md); + font-weight: var(--bold); + padding-block: var(--s-2); + padding-inline: var(--s-3); +} + +.analyzer__stat-collection { + display: grid; + gap: var(--s-2); + grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr)); + margin-block-start: var(--s-4); +} + +.analyzer__stat-card { + display: flex; + flex-direction: column; + justify-content: space-between; + padding: var(--s-2); + background-color: var(--bg-darker); + border-radius: var(--rounded); + gap: var(--s-4); +} + +.analyzer__stat-card__title { + height: 2.75rem; + font-size: var(--fonts-xs); + text-align: center; +} + +.analyzer__stat-card-values { + display: flex; + justify-content: space-evenly; + gap: var(--s-1); +} + +.analyzer__stat-card__value { + display: flex; + flex-direction: column; + align-items: center; +} + +.analyzer__stat-card__value__title { + color: var(--text-lighter); + font-size: var(--fonts-xxs); + font-weight: 400; + letter-spacing: 0.5px; + text-transform: uppercase; +} + +.analyzer__stat-card__value__number { + font-size: var(--fonts-md); + font-weight: var(--bold); +} + +.analyzer__table-container { + width: 100%; + padding: var(--s-3); + background-color: var(--bg-darker); + border-radius: var(--rounded); + margin-block-start: var(--s-4); + padding-block: var(--s-2); +} + +.analyzer__shots-to-splat { + color: var(--text-lighter); + font-size: var(--fonts-xxxs); + margin-inline-start: var(--s-4); +} + +.analyzer__consumption-table-explanation { + margin-top: var(--s-2); + color: var(--text-lighter); + font-size: var(--fonts-xxs); +} + +.analyzer__stat-category-explanation { + color: var(--text-lighter); + font-size: var(--fonts-xxs); + grid-column: 1 / 4; +} + +.analyzer__patch { + background-color: var(--theme-transparent); + border-radius: var(--rounded); + color: var(--text-lighter); + font-size: var(--fonts-xxxs); + font-weight: var(--bold); + padding-block: var(--s-0-5); + padding-inline: var(--s-1); +} diff --git a/app/styles/calendar.css b/app/styles/calendar.css index e383de3f5..717db96f5 100644 --- a/app/styles/calendar.css +++ b/app/styles/calendar.css @@ -103,9 +103,14 @@ .calendar__event { display: flex; flex-direction: column; + padding-top: var(--s-4); font-size: var(--fonts-lg); } +.calendar__event + .calendar__event { + border-top: 2px solid var(--divider); +} + .calendar__event:last-child { padding-block-end: var(--s-4); } @@ -152,11 +157,6 @@ gap: var(--s-2); } -.calendar__event__divider { - width: 50rem; - margin: 0 auto; -} - .calendar__no-events { color: var(--text-lighter); padding-block: var(--s-20); diff --git a/app/styles/common.css b/app/styles/common.css index bb409be77..c93d2e826 100644 --- a/app/styles/common.css +++ b/app/styles/common.css @@ -302,7 +302,6 @@ abbr[title] { } dialog { - overflow: visible; width: min(90%, 24rem); border: 0; margin: auto; @@ -333,6 +332,54 @@ dialog::backdrop { } } +.toggle { + all: unset; + position: relative; + display: inline-flex; + width: var(--s-11); + height: var(--s-6); + align-items: center; + background-color: var(--theme-transparent); + border-radius: var(--rounded); +} + +.toggle.tiny { + width: var(--s-6); + height: var(--s-3); +} + +.toggle.checked { + background-color: var(--theme); +} + +.toggle:active { + transform: initial; +} + +.toggle-dot { + display: inline-block; + width: var(--s-4); + height: var(--s-4); + background-color: white; + border-radius: 50%; + transform: translateX(var(--s-1)); + transition: transform 0.2s ease; +} + +.toggle-dot.tiny { + width: var(--s-3); + height: var(--s-3); + transform: translateX(-0.2rem); +} + +.toggle-dot.checked { + transform: translateX(var(--s-6)); +} + +.toggle-dot.checked.tiny { + transform: translateX(var(--s-4)); +} + .button-text-paragraph { display: flex; gap: var(--s-1); diff --git a/app/styles/layout.css b/app/styles/layout.css index 4c1f5c344..078694087 100644 --- a/app/styles/layout.css +++ b/app/styles/layout.css @@ -226,6 +226,10 @@ gap: var(--s-2); } +.layout__user-popover > button:focus { + outline: 2px solid var(--theme); +} + .layout__footer { display: flex; flex-direction: column; diff --git a/app/styles/utils.css b/app/styles/utils.css index 554e1f777..d93191d18 100644 --- a/app/styles/utils.css +++ b/app/styles/utils.css @@ -30,6 +30,10 @@ color: var(--theme-success); } +.bg-darker-important { + background-color: var(--bg-darker) !important; +} + .font-semi-bold { font-weight: var(--semi-bold); } @@ -38,6 +42,10 @@ width: 100%; } +.w-full-important { + width: 100% !important; +} + .w-24 { width: var(--s-24); } @@ -74,6 +82,10 @@ margin: 0 auto; } +.my-4 { + margin-block: var(--s-4); +} + .hidden { display: none; } @@ -113,3 +125,7 @@ .all-unset { all: unset; } + +.outline-theme:focus { + outline: 2px solid var(--theme); +} diff --git a/app/styles/vars.css b/app/styles/vars.css index f2bb1da84..71e346065 100644 --- a/app/styles/vars.css +++ b/app/styles/vars.css @@ -15,6 +15,7 @@ html { --text: rgb(0 0 0 / 95%); --black-text: rgb(0 0 0 / 95%); --text-lighter: rgb(75 75 75 / 95%); + --divider: #635dab; --theme-error: rgb(199 13 6); --theme-error-transparent: rgba(199 13 6 / 75%); --theme-warning: #c9c900; diff --git a/app/utils/strings.ts b/app/utils/strings.ts index 01094b7ed..e7fea579b 100644 --- a/app/utils/strings.ts +++ b/app/utils/strings.ts @@ -17,3 +17,7 @@ export function placementString(placement: number) { return `${placement}th`; } + +export function semiRandomId() { + return String(Math.random()); +} diff --git a/app/utils/urls.ts b/app/utils/urls.ts index c8d1ebf76..de2da1837 100644 --- a/app/utils/urls.ts +++ b/app/utils/urls.ts @@ -1,6 +1,11 @@ import type { Badge, GearType } from "~/db/types"; import type { ModeShort } from "~/modules/in-game-lists"; -import type { AbilityWithUnknown } from "~/modules/in-game-lists/types"; +import type { + AbilityWithUnknown, + MainWeaponId, + SpecialWeaponId, + SubWeaponId, +} from "~/modules/in-game-lists/types"; export const PLUS_SERVER_DISCORD_URL = "https://discord.gg/FW4dKrY"; export const SENDOU_INK_DISCORD_URL = "https://discord.gg/sendou"; @@ -23,6 +28,8 @@ export const CALENDAR_PAGE = "/calendar"; export const STOP_IMPERSONATING_URL = "/auth/impersonate/stop"; export const SEED_URL = "/seed"; +export const COMMON_PREVIEW_IMAGE = "/img/layout/common-preview.png"; + export const userPage = (discordId: string) => `/u/${discordId}`; export const userBuildsPage = (discordId: string) => `${userPage(discordId)}/builds`; @@ -51,8 +58,12 @@ export const articlePreviewUrl = (slug: string) => export const navIconUrl = (navItem: string) => `/img/layout/${navItem}`; export const gearImageUrl = (gearType: GearType, gearSplId: number) => `/img/gear/${gearType.toLowerCase()}/${gearSplId}`; -export const weaponImageUrl = (weaponSplId: number) => - `/img/weapons/${weaponSplId}`; +export const mainWeaponImageUrl = (mainWeaponSplId: MainWeaponId) => + `/img/main-weapons/${mainWeaponSplId}`; +export const subWeaponImageUrl = (subWeaponSplId: SubWeaponId) => + `/img/sub-weapons/${subWeaponSplId}`; +export const specialWeaponImageUrl = (specialWeaponSplId: SpecialWeaponId) => + `/img/special-weapons/${specialWeaponSplId}`; export const abilityImageUrl = (ability: AbilityWithUnknown) => `/img/abilities/${ability}`; export const modeImageUrl = (mode: ModeShort) => `/img/modes/${mode}`; diff --git a/content/articles/splatoon-3-breaks-sales-record.md b/content/articles/splatoon-3-breaks-sales-record.md new file mode 100644 index 000000000..ddcf42947 --- /dev/null +++ b/content/articles/splatoon-3-breaks-sales-record.md @@ -0,0 +1,15 @@ +--- +title: Splatoon 3 Breaks Sales Records in Japan +date: 2022-09-12 +author: Riczi +--- + +Nintendo is known for developing some of the biggest video game franchises in the world. From Pokémon to Mario to Legend of Zelda, Nintendo has created some of the most well-known and memorable games and characters in history. You would think that one of these franchises hold the record for most sales on release of a new game. You would be wrong. + +Splatoon 3 released in September of 2022 and it is shattering sales records in Japan. In just three days, the game sold nearly three and a half million copies in Japan alone. This crushed the previous record held by Animal Crossing: New Horizons which sold 2.6 million copies when it released at the beginning of Covid-19. + +The Splatoon franchise has been a fan-favorite in Japan for years. The first game released on the Wii U back in 2015, with Splatoon 2 debuting on the Nintendo Switch just a couple of years after. Despite huge success in their home country, Nintendo hasn't seen Splatoon take off in other countries quite as well. The arrival of Splatoon 3 may cause an increase in popularity in western countries where the game series hasn't quite reached yet. + +Splatoon has a thriving competitive scene that is welcoming new players into its ranks. Top players in the United States and Europe such as ProChara and ThatSrb2DUDE create content with the hope that players in their respective regions will enter the Splatlands with the same amount of hype being generated in Japan. + +If you're interested in watching or even participating in a Splatoon tournament, check out the Sendou.ink calendar. It contains all of the upcoming events for Splatoon 3 with information on where to sign up and how to follow along live. diff --git a/package-lock.json b/package-lock.json index d7cd10252..c463d138e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "name": "sendou.ink", "dependencies": { "@faker-js/faker": "^7.5.0", - "@headlessui/react": "^1.6.6", + "@headlessui/react": "^1.7.1", "@popperjs/core": "^2.11.6", "@remix-run/node": "^1.7.0", "@remix-run/react": "^1.7.0", @@ -15,7 +15,7 @@ "better-sqlite3": "^7.6.2", "clsx": "^1.2.1", "countries-list": "^2.6.1", - "date-fns": "^2.29.2", + "date-fns": "^2.29.3", "fuse.js": "^6.6.2", "gray-matter": "^4.0.3", "i18next": "^21.9.1", @@ -29,30 +29,30 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-flip-toolkit": "^7.0.16", - "react-i18next": "^11.18.5", + "react-i18next": "^11.18.6", "react-popper": "^2.3.0", - "remix-auth": "^3.2.2", + "remix-auth": "^3.3.0", "remix-auth-oauth2": "^1.3.0", "remix-i18next": "^4.1.1", "swr": "^1.3.0", "tiny-invariant": "^1.2.0", - "zod": "^3.18.0" + "zod": "^3.19.1" }, "devDependencies": { "@remix-run/dev": "^1.7.0", "@remix-run/eslint-config": "^1.7.0", "@types/better-sqlite3": "^7.6.0", "@types/i18next-fs-backend": "^1.1.2", - "@types/node-cron": "^3.0.3", - "@types/react": "^18.0.18", + "@types/node-cron": "^3.0.4", + "@types/react": "^18.0.20", "@types/react-dom": "^18.0.6", - "@typescript-eslint/eslint-plugin": "^5.36.1", - "@typescript-eslint/parser": "^5.36.1", + "@typescript-eslint/eslint-plugin": "^5.37.0", + "@typescript-eslint/parser": "^5.37.0", "cross-env": "^7.0.3", - "cypress": "^10.7.0", + "cypress": "^10.8.0", "dotenv": "^16.0.2", - "eslint": "^8.23.0", - "eslint-plugin-react": "^7.31.5", + "eslint": "^8.23.1", + "eslint-plugin-react": "^7.31.8", "eslint-plugin-react-hooks": "^4.6.0", "ley": "^0.7.1", "prettier": "^2.7.1", @@ -64,7 +64,7 @@ "ts-node": "^10.9.1", "tsconfig-paths": "^4.1.0", "tsm": "^2.2.2", - "typescript": "^4.8.2", + "typescript": "^4.8.3", "uvu": "^0.5.6" }, "engines": { @@ -2199,9 +2199,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -2275,9 +2275,9 @@ "dev": true }, "node_modules/@headlessui/react": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz", - "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.1.tgz", + "integrity": "sha512-vnRlB71kvEr3y26Lm1WpCiMML8n5JcJ7jK5+vaF0hGTZFArW206j61meVemXkTOuGLhmyWe6yj3OETzsxHoryQ==", "engines": { "node": ">=10" }, @@ -2988,9 +2988,9 @@ "dev": true }, "node_modules/@types/node-cron": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.3.tgz", - "integrity": "sha512-FPzux/llEiCe5mPn3TvLEORcF2pRXvH5cugtJCJf+UrkwQ7pYfb4wn9J/sxJ8QkT/sw9BjWSi9uur5Vh1OuAZQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.4.tgz", + "integrity": "sha512-A2H+uz5ry4hohYjRe5mQSE/8Dx/HGw4WZ728JxhKUZ7z8CMvRuG2tpbzGHRGQCuQzz5aCNB1iXzPZYHd4BPHvw==", "dev": true }, "node_modules/@types/normalize-package-data": { @@ -3012,9 +3012,9 @@ "dev": true }, "node_modules/@types/react": { - "version": "18.0.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.18.tgz", - "integrity": "sha512-6hI08umYs6NaiHFEEGioXnxJ+oEhY3eRz8VCUaudZmGdtvPviCJB8mgaMxaDWAdPSYd4eFavrPk2QIolwbLYrg==", + "version": "18.0.20", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.20.tgz", + "integrity": "sha512-MWul1teSPxujEHVwZl4a5HxQ9vVNsjTchVA+xRqv/VYGCuKGAU6UhfrTdF5aBefwD1BHUD8i/zq+O/vyCm/FrA==", "dev": true, "dependencies": { "@types/prop-types": "*", @@ -3075,14 +3075,14 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.1.tgz", - "integrity": "sha512-iC40UK8q1tMepSDwiLbTbMXKDxzNy+4TfPWgIL661Ym0sD42vRcQU93IsZIrmi+x292DBr60UI/gSwfdVYexCA==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz", + "integrity": "sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.36.1", - "@typescript-eslint/type-utils": "5.36.1", - "@typescript-eslint/utils": "5.36.1", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/type-utils": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -3131,14 +3131,14 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.1.tgz", - "integrity": "sha512-/IsgNGOkBi7CuDfUbwt1eOqUXF9WGVBW9dwEe1pi+L32XrTsZIgmDFIi2RxjzsvB/8i+MIf5JIoTEH8LOZ368A==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.37.0.tgz", + "integrity": "sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.36.1", - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/typescript-estree": "5.36.1", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "debug": "^4.3.4" }, "engines": { @@ -3181,13 +3181,13 @@ "dev": true }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.1.tgz", - "integrity": "sha512-pGC2SH3/tXdu9IH3ItoqciD3f3RRGCh7hb9zPdN2Drsr341zgd6VbhP5OHQO/reUqihNltfPpMpTNihFMarP2w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", + "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/visitor-keys": "5.36.1" + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3198,13 +3198,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.1.tgz", - "integrity": "sha512-xfZhfmoQT6m3lmlqDvDzv9TiCYdw22cdj06xY0obSznBsT///GK5IEZQdGliXpAOaRL34o8phEvXzEo/VJx13Q==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", + "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.36.1", - "@typescript-eslint/utils": "5.36.1", + "@typescript-eslint/typescript-estree": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -3248,9 +3248,9 @@ "dev": true }, "node_modules/@typescript-eslint/types": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.1.tgz", - "integrity": "sha512-jd93ShpsIk1KgBTx9E+hCSEuLCUFwi9V/urhjOWnOaksGZFbTOxAT47OH2d4NLJnLhkVD+wDbB48BuaycZPLBg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", + "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3261,13 +3261,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.1.tgz", - "integrity": "sha512-ih7V52zvHdiX6WcPjsOdmADhYMDN15SylWRZrT2OMy80wzKbc79n8wFW0xpWpU0x3VpBz/oDgTm2xwDAnFTl+g==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", + "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/visitor-keys": "5.36.1", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -3331,15 +3331,15 @@ "dev": true }, "node_modules/@typescript-eslint/utils": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.1.tgz", - "integrity": "sha512-lNj4FtTiXm5c+u0pUehozaUWhh7UYKnwryku0nxJlYUEWetyG92uw2pr+2Iy4M/u0ONMKzfrx7AsGBTCzORmIg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", + "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", "dev": true, "dependencies": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.1", - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/typescript-estree": "5.36.1", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" }, @@ -3355,12 +3355,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.1.tgz", - "integrity": "sha512-ojB9aRyRFzVMN3b5joSYni6FAS10BBSCAfKJhjJAV08t/a95aM6tAhz+O1jF+EtgxktuSO3wJysp2R+Def/IWQ==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", + "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.36.1", + "@typescript-eslint/types": "5.37.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -5158,9 +5158,9 @@ "dev": true }, "node_modules/cypress": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.7.0.tgz", - "integrity": "sha512-gTFvjrUoBnqPPOu9Vl5SBHuFlzx/Wxg/ZXIz2H4lzoOLFelKeF7mbwYUOzgzgF0oieU2WhJAestQdkgwJMMTvQ==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.8.0.tgz", + "integrity": "sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -5183,7 +5183,7 @@ "dayjs": "^1.10.4", "debug": "^4.3.2", "enquirer": "^2.3.6", - "eventemitter2": "^6.4.3", + "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", @@ -5378,9 +5378,9 @@ } }, "node_modules/date-fns": { - "version": "2.29.2", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.2.tgz", - "integrity": "sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==", + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==", "engines": { "node": ">=0.11" }, @@ -6232,12 +6232,12 @@ } }, "node_modules/eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", + "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", "dev": true, "dependencies": { - "@eslint/eslintrc": "^1.3.1", + "@eslint/eslintrc": "^1.3.2", "@humanwhocodes/config-array": "^0.10.4", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "@humanwhocodes/module-importer": "^1.0.1", @@ -6256,7 +6256,6 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -6265,6 +6264,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -6719,9 +6719,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.31.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.5.tgz", - "integrity": "sha512-y7472VAcqns17rsQUk6tQCnqBi+boYjGdYarX022719+wGd1T4U1fOYJ2T2Trd3Od2q5M92e42zJ2uZOGmWamA==", + "version": "7.31.8", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", + "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", "dev": true, "dependencies": { "array-includes": "^3.1.5", @@ -7259,9 +7259,9 @@ } }, "node_modules/eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", "dev": true }, "node_modules/executable": { @@ -9360,6 +9360,12 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "node_modules/js-sdsl": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", + "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", + "dev": true + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -12373,9 +12379,9 @@ } }, "node_modules/react-i18next": { - "version": "11.18.5", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.5.tgz", - "integrity": "sha512-cKcyuuzIv0YUZ4l9WORflVNuhISPAqQShOAsxwFyYuJoCA7HlLmHm7XnvO6hfAGmGpDNRhJHoBX8hG49Cb2xZQ==", + "version": "11.18.6", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", + "integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==", "dependencies": { "@babel/runtime": "^7.14.5", "html-parse-stringify": "^3.0.1" @@ -12786,9 +12792,9 @@ "integrity": "sha512-agFFS3RzrLXJl5LY5xg/xYyXvUuVAnkhgKO7RaO9J1Ssth6yvbO+PIiV67V59MB5NCdAK2flvGvNT4mdKVniFA==" }, "node_modules/remix-auth": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/remix-auth/-/remix-auth-3.2.2.tgz", - "integrity": "sha512-VtzkfxeXbnXilupRTZkP40aik4vFSdwwRT96mbq0UBDMqHVRfQ7h9Y51HFrTufHJZEfAdkCopedMVvm0vQYKag==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/remix-auth/-/remix-auth-3.3.0.tgz", + "integrity": "sha512-sLY5s6DQF4OJp03HM/dIEw3tLfSOIowerS2QDTuvEVXoEA3IHVmk7QkvOKosWdVPbcnlRfwF6PbeBLKgo6vqsg==", "dependencies": { "uuid": "^8.3.2" }, @@ -14800,9 +14806,9 @@ } }, "node_modules/typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -15668,9 +15674,9 @@ } }, "node_modules/zod": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.18.0.tgz", - "integrity": "sha512-gwTm8RfUCe8l9rDwN5r2A17DkAa8Ez4Yl4yXqc5VqeGaXaJahzYYXbTwvhroZi0SNBqTwh/bKm2N0mpCzuw4bA==", + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", + "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==", "funding": { "url": "https://github.com/sponsors/colinhacks" } @@ -17182,9 +17188,9 @@ } }, "@eslint/eslintrc": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.1.tgz", - "integrity": "sha512-OhSY22oQQdw3zgPOOwdoj01l/Dzl1Z+xyUP33tkSN+aqyEhymJCcPHyXt+ylW8FSe0TfRC2VG+ROQOapD0aZSQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.3.2.tgz", + "integrity": "sha512-AXYd23w1S/bv3fTs3Lz0vjiYemS08jWkI3hYyS9I1ry+0f+Yjs1wm+sU0BS8qDOPrBIkp4qHYC16I8uVtpLajQ==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -17236,9 +17242,9 @@ "dev": true }, "@headlessui/react": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.6.6.tgz", - "integrity": "sha512-MFJtmj9Xh/hhBMhLccGbBoSk+sk61BlP6sJe4uQcVMtXZhCgGqd2GyIQzzmsdPdTEWGSF434CBi8mnhR6um46Q==", + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.1.tgz", + "integrity": "sha512-vnRlB71kvEr3y26Lm1WpCiMML8n5JcJ7jK5+vaF0hGTZFArW206j61meVemXkTOuGLhmyWe6yj3OETzsxHoryQ==", "requires": {} }, "@humanwhocodes/config-array": { @@ -17820,9 +17826,9 @@ "dev": true }, "@types/node-cron": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.3.tgz", - "integrity": "sha512-FPzux/llEiCe5mPn3TvLEORcF2pRXvH5cugtJCJf+UrkwQ7pYfb4wn9J/sxJ8QkT/sw9BjWSi9uur5Vh1OuAZQ==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.4.tgz", + "integrity": "sha512-A2H+uz5ry4hohYjRe5mQSE/8Dx/HGw4WZ728JxhKUZ7z8CMvRuG2tpbzGHRGQCuQzz5aCNB1iXzPZYHd4BPHvw==", "dev": true }, "@types/normalize-package-data": { @@ -17844,9 +17850,9 @@ "dev": true }, "@types/react": { - "version": "18.0.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.18.tgz", - "integrity": "sha512-6hI08umYs6NaiHFEEGioXnxJ+oEhY3eRz8VCUaudZmGdtvPviCJB8mgaMxaDWAdPSYd4eFavrPk2QIolwbLYrg==", + "version": "18.0.20", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.20.tgz", + "integrity": "sha512-MWul1teSPxujEHVwZl4a5HxQ9vVNsjTchVA+xRqv/VYGCuKGAU6UhfrTdF5aBefwD1BHUD8i/zq+O/vyCm/FrA==", "dev": true, "requires": { "@types/prop-types": "*", @@ -17907,14 +17913,14 @@ } }, "@typescript-eslint/eslint-plugin": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.36.1.tgz", - "integrity": "sha512-iC40UK8q1tMepSDwiLbTbMXKDxzNy+4TfPWgIL661Ym0sD42vRcQU93IsZIrmi+x292DBr60UI/gSwfdVYexCA==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.37.0.tgz", + "integrity": "sha512-Fde6W0IafXktz1UlnhGkrrmnnGpAo1kyX7dnyHHVrmwJOn72Oqm3eYtddrpOwwel2W8PAK9F3pIL5S+lfoM0og==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.36.1", - "@typescript-eslint/type-utils": "5.36.1", - "@typescript-eslint/utils": "5.36.1", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/type-utils": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "functional-red-black-tree": "^1.0.1", "ignore": "^5.2.0", @@ -17941,14 +17947,14 @@ } }, "@typescript-eslint/parser": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.36.1.tgz", - "integrity": "sha512-/IsgNGOkBi7CuDfUbwt1eOqUXF9WGVBW9dwEe1pi+L32XrTsZIgmDFIi2RxjzsvB/8i+MIf5JIoTEH8LOZ368A==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.37.0.tgz", + "integrity": "sha512-01VzI/ipYKuaG5PkE5+qyJ6m02fVALmMPY3Qq5BHflDx3y4VobbLdHQkSMg9VPRS4KdNt4oYTMaomFoHonBGAw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.36.1", - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/typescript-estree": "5.36.1", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "debug": "^4.3.4" }, "dependencies": { @@ -17970,23 +17976,23 @@ } }, "@typescript-eslint/scope-manager": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.36.1.tgz", - "integrity": "sha512-pGC2SH3/tXdu9IH3ItoqciD3f3RRGCh7hb9zPdN2Drsr341zgd6VbhP5OHQO/reUqihNltfPpMpTNihFMarP2w==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.37.0.tgz", + "integrity": "sha512-F67MqrmSXGd/eZnujjtkPgBQzgespu/iCZ+54Ok9X5tALb9L2v3G+QBSoWkXG0p3lcTJsL+iXz5eLUEdSiJU9Q==", "dev": true, "requires": { - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/visitor-keys": "5.36.1" + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0" } }, "@typescript-eslint/type-utils": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.36.1.tgz", - "integrity": "sha512-xfZhfmoQT6m3lmlqDvDzv9TiCYdw22cdj06xY0obSznBsT///GK5IEZQdGliXpAOaRL34o8phEvXzEo/VJx13Q==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.37.0.tgz", + "integrity": "sha512-BSx/O0Z0SXOF5tY0bNTBcDEKz2Ec20GVYvq/H/XNKiUorUFilH7NPbFUuiiyzWaSdN3PA8JV0OvYx0gH/5aFAQ==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "5.36.1", - "@typescript-eslint/utils": "5.36.1", + "@typescript-eslint/typescript-estree": "5.37.0", + "@typescript-eslint/utils": "5.37.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -18009,19 +18015,19 @@ } }, "@typescript-eslint/types": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.36.1.tgz", - "integrity": "sha512-jd93ShpsIk1KgBTx9E+hCSEuLCUFwi9V/urhjOWnOaksGZFbTOxAT47OH2d4NLJnLhkVD+wDbB48BuaycZPLBg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.37.0.tgz", + "integrity": "sha512-3frIJiTa5+tCb2iqR/bf7XwU20lnU05r/sgPJnRpwvfZaqCJBrl8Q/mw9vr3NrNdB/XtVyMA0eppRMMBqdJ1bA==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.36.1.tgz", - "integrity": "sha512-ih7V52zvHdiX6WcPjsOdmADhYMDN15SylWRZrT2OMy80wzKbc79n8wFW0xpWpU0x3VpBz/oDgTm2xwDAnFTl+g==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.37.0.tgz", + "integrity": "sha512-JkFoFIt/cx59iqEDSgIGnQpCTRv96MQnXCYvJi7QhBC24uyuzbD8wVbajMB1b9x4I0octYFJ3OwjAwNqk1AjDA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/visitor-keys": "5.36.1", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/visitor-keys": "5.37.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -18061,26 +18067,26 @@ } }, "@typescript-eslint/utils": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.36.1.tgz", - "integrity": "sha512-lNj4FtTiXm5c+u0pUehozaUWhh7UYKnwryku0nxJlYUEWetyG92uw2pr+2Iy4M/u0ONMKzfrx7AsGBTCzORmIg==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.37.0.tgz", + "integrity": "sha512-jUEJoQrWbZhmikbcWSMDuUSxEE7ID2W/QCV/uz10WtQqfOuKZUqFGjqLJ+qhDd17rjgp+QJPqTdPIBWwoob2NQ==", "dev": true, "requires": { "@types/json-schema": "^7.0.9", - "@typescript-eslint/scope-manager": "5.36.1", - "@typescript-eslint/types": "5.36.1", - "@typescript-eslint/typescript-estree": "5.36.1", + "@typescript-eslint/scope-manager": "5.37.0", + "@typescript-eslint/types": "5.37.0", + "@typescript-eslint/typescript-estree": "5.37.0", "eslint-scope": "^5.1.1", "eslint-utils": "^3.0.0" } }, "@typescript-eslint/visitor-keys": { - "version": "5.36.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.36.1.tgz", - "integrity": "sha512-ojB9aRyRFzVMN3b5joSYni6FAS10BBSCAfKJhjJAV08t/a95aM6tAhz+O1jF+EtgxktuSO3wJysp2R+Def/IWQ==", + "version": "5.37.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.37.0.tgz", + "integrity": "sha512-Hp7rT4cENBPIzMwrlehLW/28EVCOcE9U1Z1BQTc8EA8v5qpr7GRGuG+U58V5tTY48zvUOA3KHvw3rA8tY9fbdA==", "dev": true, "requires": { - "@typescript-eslint/types": "5.36.1", + "@typescript-eslint/types": "5.37.0", "eslint-visitor-keys": "^3.3.0" }, "dependencies": { @@ -19417,9 +19423,9 @@ "dev": true }, "cypress": { - "version": "10.7.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.7.0.tgz", - "integrity": "sha512-gTFvjrUoBnqPPOu9Vl5SBHuFlzx/Wxg/ZXIz2H4lzoOLFelKeF7mbwYUOzgzgF0oieU2WhJAestQdkgwJMMTvQ==", + "version": "10.8.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-10.8.0.tgz", + "integrity": "sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA==", "dev": true, "requires": { "@cypress/request": "^2.88.10", @@ -19441,7 +19447,7 @@ "dayjs": "^1.10.4", "debug": "^4.3.2", "enquirer": "^2.3.6", - "eventemitter2": "^6.4.3", + "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", @@ -19588,9 +19594,9 @@ "integrity": "sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og==" }, "date-fns": { - "version": "2.29.2", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.2.tgz", - "integrity": "sha512-0VNbwmWJDS/G3ySwFSJA3ayhbURMTJLtwM2DTxf9CWondCnh6DTNlO9JgRSq6ibf4eD0lfMJNBxUdEAHHix+bA==" + "version": "2.29.3", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.29.3.tgz", + "integrity": "sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==" }, "dayjs": { "version": "1.11.2", @@ -20137,12 +20143,12 @@ "dev": true }, "eslint": { - "version": "8.23.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.0.tgz", - "integrity": "sha512-pBG/XOn0MsJcKcTRLr27S5HpzQo4kLr+HjLQIyK4EiCsijDl/TB+h5uEuJU6bQ8Edvwz1XWOjpaP2qgnXGpTcA==", + "version": "8.23.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.23.1.tgz", + "integrity": "sha512-w7C1IXCc6fNqjpuYd0yPlcTKKmHlHHktRkzmBPZ+7cvNBQuiNjx0xaMTjAJGCafJhQkrFJooREv0CtrVzmHwqg==", "dev": true, "requires": { - "@eslint/eslintrc": "^1.3.1", + "@eslint/eslintrc": "^1.3.2", "@humanwhocodes/config-array": "^0.10.4", "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", "@humanwhocodes/module-importer": "^1.0.1", @@ -20161,7 +20167,6 @@ "fast-deep-equal": "^3.1.3", "file-entry-cache": "^6.0.1", "find-up": "^5.0.0", - "functional-red-black-tree": "^1.0.1", "glob-parent": "^6.0.1", "globals": "^13.15.0", "globby": "^11.1.0", @@ -20170,6 +20175,7 @@ "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", + "js-sdsl": "^4.1.4", "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", "levn": "^0.4.1", @@ -20639,9 +20645,9 @@ } }, "eslint-plugin-react": { - "version": "7.31.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.5.tgz", - "integrity": "sha512-y7472VAcqns17rsQUk6tQCnqBi+boYjGdYarX022719+wGd1T4U1fOYJ2T2Trd3Od2q5M92e42zJ2uZOGmWamA==", + "version": "7.31.8", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", + "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", "dev": true, "requires": { "array-includes": "^3.1.5", @@ -20887,9 +20893,9 @@ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==" }, "eventemitter2": { - "version": "6.4.5", - "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.5.tgz", - "integrity": "sha512-bXE7Dyc1i6oQElDG0jMRZJrRAn9QR2xyyFGmBdZleNmyQX0FqGYmhZIrIrpPfm/w//LTo4tVQGOGQcGCb5q9uw==", + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", "dev": true }, "executable": { @@ -22464,6 +22470,12 @@ "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", "dev": true }, + "js-sdsl": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.4.tgz", + "integrity": "sha512-Y2/yD55y5jteOAmY50JbUZYwk3CP3wnLPEZnlR1w9oKhITrBEtAxwuWKebFf8hMrPMgbYwFoWK/lH2sBkErELw==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -24633,9 +24645,9 @@ } }, "react-i18next": { - "version": "11.18.5", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.5.tgz", - "integrity": "sha512-cKcyuuzIv0YUZ4l9WORflVNuhISPAqQShOAsxwFyYuJoCA7HlLmHm7XnvO6hfAGmGpDNRhJHoBX8hG49Cb2xZQ==", + "version": "11.18.6", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.18.6.tgz", + "integrity": "sha512-yHb2F9BiT0lqoQDt8loZ5gWP331GwctHz9tYQ8A2EIEUu+CcEdjBLQWli1USG3RdWQt3W+jqQLg/d4rrQR96LA==", "requires": { "@babel/runtime": "^7.14.5", "html-parse-stringify": "^3.0.1" @@ -24951,9 +24963,9 @@ "integrity": "sha512-agFFS3RzrLXJl5LY5xg/xYyXvUuVAnkhgKO7RaO9J1Ssth6yvbO+PIiV67V59MB5NCdAK2flvGvNT4mdKVniFA==" }, "remix-auth": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/remix-auth/-/remix-auth-3.2.2.tgz", - "integrity": "sha512-VtzkfxeXbnXilupRTZkP40aik4vFSdwwRT96mbq0UBDMqHVRfQ7h9Y51HFrTufHJZEfAdkCopedMVvm0vQYKag==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/remix-auth/-/remix-auth-3.3.0.tgz", + "integrity": "sha512-sLY5s6DQF4OJp03HM/dIEw3tLfSOIowerS2QDTuvEVXoEA3IHVmk7QkvOKosWdVPbcnlRfwF6PbeBLKgo6vqsg==", "requires": { "uuid": "^8.3.2" } @@ -26495,9 +26507,9 @@ } }, "typescript": { - "version": "4.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.2.tgz", - "integrity": "sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw==", + "version": "4.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.3.tgz", + "integrity": "sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==", "dev": true }, "unbox-primitive": { @@ -27131,9 +27143,9 @@ "dev": true }, "zod": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.18.0.tgz", - "integrity": "sha512-gwTm8RfUCe8l9rDwN5r2A17DkAa8Ez4Yl4yXqc5VqeGaXaJahzYYXbTwvhroZi0SNBqTwh/bKm2N0mpCzuw4bA==" + "version": "3.19.1", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", + "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==" }, "zwitch": { "version": "2.0.2", diff --git a/package.json b/package.json index 1809478f5..537801bc1 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "add-badge": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/add-badge.ts", "create-weapon-json": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/create-weapon-json.ts", "create-gear-json": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/create-gear-json.ts", + "create-analyzer-json": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/create-analyzer-json.ts", "replace-img-names": "node --experimental-specifier-resolution=node --loader ts-node/esm -r tsconfig-paths/register scripts/replace-img-names.ts", "lint:ts": "eslint . --ext .ts,.tsx", "lint:styles": "stylelint \"app/styles/**/*.css\"", @@ -28,7 +29,7 @@ }, "dependencies": { "@faker-js/faker": "^7.5.0", - "@headlessui/react": "^1.6.6", + "@headlessui/react": "^1.7.1", "@popperjs/core": "^2.11.6", "@remix-run/node": "^1.7.0", "@remix-run/react": "^1.7.0", @@ -36,7 +37,7 @@ "better-sqlite3": "^7.6.2", "clsx": "^1.2.1", "countries-list": "^2.6.1", - "date-fns": "^2.29.2", + "date-fns": "^2.29.3", "fuse.js": "^6.6.2", "gray-matter": "^4.0.3", "i18next": "^21.9.1", @@ -50,30 +51,30 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-flip-toolkit": "^7.0.16", - "react-i18next": "^11.18.5", + "react-i18next": "^11.18.6", "react-popper": "^2.3.0", - "remix-auth": "^3.2.2", + "remix-auth": "^3.3.0", "remix-auth-oauth2": "^1.3.0", "remix-i18next": "^4.1.1", "swr": "^1.3.0", "tiny-invariant": "^1.2.0", - "zod": "^3.18.0" + "zod": "^3.19.1" }, "devDependencies": { "@remix-run/dev": "^1.7.0", "@remix-run/eslint-config": "^1.7.0", "@types/better-sqlite3": "^7.6.0", "@types/i18next-fs-backend": "^1.1.2", - "@types/node-cron": "^3.0.3", - "@types/react": "^18.0.18", + "@types/node-cron": "^3.0.4", + "@types/react": "^18.0.20", "@types/react-dom": "^18.0.6", - "@typescript-eslint/eslint-plugin": "^5.36.1", - "@typescript-eslint/parser": "^5.36.1", + "@typescript-eslint/eslint-plugin": "^5.37.0", + "@typescript-eslint/parser": "^5.37.0", "cross-env": "^7.0.3", - "cypress": "^10.7.0", + "cypress": "^10.8.0", "dotenv": "^16.0.2", - "eslint": "^8.23.0", - "eslint-plugin-react": "^7.31.5", + "eslint": "^8.23.1", + "eslint-plugin-react": "^7.31.8", "eslint-plugin-react-hooks": "^4.6.0", "ley": "^0.7.1", "prettier": "^2.7.1", @@ -85,7 +86,7 @@ "ts-node": "^10.9.1", "tsconfig-paths": "^4.1.0", "tsm": "^2.2.2", - "typescript": "^4.8.2", + "typescript": "^4.8.3", "uvu": "^0.5.6" }, "engines": { diff --git a/public/img/gear/clothes/1000.avif b/public/img/gear/clothes/1000.avif new file mode 100644 index 000000000..05bbaa3d3 Binary files /dev/null and b/public/img/gear/clothes/1000.avif differ diff --git a/public/img/gear/clothes/1000.png b/public/img/gear/clothes/1000.png new file mode 100644 index 000000000..33070fb45 Binary files /dev/null and b/public/img/gear/clothes/1000.png differ diff --git a/public/img/gear/clothes/10006.png b/public/img/gear/clothes/10006.png index 6a1a9a907..76ec8f6b6 100644 Binary files a/public/img/gear/clothes/10006.png and b/public/img/gear/clothes/10006.png differ diff --git a/public/img/gear/clothes/1001.png b/public/img/gear/clothes/1001.png index 370fd8ac8..be7efacd1 100644 Binary files a/public/img/gear/clothes/1001.png and b/public/img/gear/clothes/1001.png differ diff --git a/public/img/gear/clothes/10012.png b/public/img/gear/clothes/10012.png index 40298dc86..679b82c32 100644 Binary files a/public/img/gear/clothes/10012.png and b/public/img/gear/clothes/10012.png differ diff --git a/public/img/gear/clothes/10014.avif b/public/img/gear/clothes/10014.avif new file mode 100644 index 000000000..f96edd144 Binary files /dev/null and b/public/img/gear/clothes/10014.avif differ diff --git a/public/img/gear/clothes/10014.png b/public/img/gear/clothes/10014.png new file mode 100644 index 000000000..87a1058ef Binary files /dev/null and b/public/img/gear/clothes/10014.png differ diff --git a/public/img/gear/clothes/1004.png b/public/img/gear/clothes/1004.png index 3521e6b62..2104a385d 100644 Binary files a/public/img/gear/clothes/1004.png and b/public/img/gear/clothes/1004.png differ diff --git a/public/img/gear/clothes/1005.png b/public/img/gear/clothes/1005.png index dee3e7945..c0eef2c7b 100644 Binary files a/public/img/gear/clothes/1005.png and b/public/img/gear/clothes/1005.png differ diff --git a/public/img/gear/clothes/1006.png b/public/img/gear/clothes/1006.png index 497ce876b..849093939 100644 Binary files a/public/img/gear/clothes/1006.png and b/public/img/gear/clothes/1006.png differ diff --git a/public/img/gear/clothes/1013.png b/public/img/gear/clothes/1013.png index f911e9f09..59060e820 100644 Binary files a/public/img/gear/clothes/1013.png and b/public/img/gear/clothes/1013.png differ diff --git a/public/img/gear/clothes/1014.png b/public/img/gear/clothes/1014.png index a5b512817..86fae04a8 100644 Binary files a/public/img/gear/clothes/1014.png and b/public/img/gear/clothes/1014.png differ diff --git a/public/img/gear/clothes/1015.png b/public/img/gear/clothes/1015.png index 3375b3ee6..0188bd011 100644 Binary files a/public/img/gear/clothes/1015.png and b/public/img/gear/clothes/1015.png differ diff --git a/public/img/gear/clothes/1016.png b/public/img/gear/clothes/1016.png index 4070bb3ee..8bd298b66 100644 Binary files a/public/img/gear/clothes/1016.png and b/public/img/gear/clothes/1016.png differ diff --git a/public/img/gear/clothes/1018.png b/public/img/gear/clothes/1018.png index c2e2f88b8..50e17058f 100644 Binary files a/public/img/gear/clothes/1018.png and b/public/img/gear/clothes/1018.png differ diff --git a/public/img/gear/clothes/1019.png b/public/img/gear/clothes/1019.png index 2eb42853a..6f0a0a839 100644 Binary files a/public/img/gear/clothes/1019.png and b/public/img/gear/clothes/1019.png differ diff --git a/public/img/gear/clothes/1020.png b/public/img/gear/clothes/1020.png index 92a10f52e..7309bd7c2 100644 Binary files a/public/img/gear/clothes/1020.png and b/public/img/gear/clothes/1020.png differ diff --git a/public/img/gear/clothes/1021.png b/public/img/gear/clothes/1021.png index f30230e42..cb120f824 100644 Binary files a/public/img/gear/clothes/1021.png and b/public/img/gear/clothes/1021.png differ diff --git a/public/img/gear/clothes/1035.png b/public/img/gear/clothes/1035.png index 59f738a74..a1144d0fb 100644 Binary files a/public/img/gear/clothes/1035.png and b/public/img/gear/clothes/1035.png differ diff --git a/public/img/gear/clothes/1062.png b/public/img/gear/clothes/1062.png index 66427a188..f69e2ef19 100644 Binary files a/public/img/gear/clothes/1062.png and b/public/img/gear/clothes/1062.png differ diff --git a/public/img/gear/clothes/1063.avif b/public/img/gear/clothes/1063.avif new file mode 100644 index 000000000..ce8508066 Binary files /dev/null and b/public/img/gear/clothes/1063.avif differ diff --git a/public/img/gear/clothes/1063.png b/public/img/gear/clothes/1063.png new file mode 100644 index 000000000..59af479eb Binary files /dev/null and b/public/img/gear/clothes/1063.png differ diff --git a/public/img/gear/clothes/1066.png b/public/img/gear/clothes/1066.png index ff25fef7d..98340858b 100644 Binary files a/public/img/gear/clothes/1066.png and b/public/img/gear/clothes/1066.png differ diff --git a/public/img/gear/clothes/1067.avif b/public/img/gear/clothes/1067.avif new file mode 100644 index 000000000..cc7c852d1 Binary files /dev/null and b/public/img/gear/clothes/1067.avif differ diff --git a/public/img/gear/clothes/1067.png b/public/img/gear/clothes/1067.png new file mode 100644 index 000000000..65028bf15 Binary files /dev/null and b/public/img/gear/clothes/1067.png differ diff --git a/public/img/gear/clothes/1069.png b/public/img/gear/clothes/1069.png index ce3ba22e3..46d964bd1 100644 Binary files a/public/img/gear/clothes/1069.png and b/public/img/gear/clothes/1069.png differ diff --git a/public/img/gear/clothes/1070.png b/public/img/gear/clothes/1070.png index 9d3330259..fd9ef3603 100644 Binary files a/public/img/gear/clothes/1070.png and b/public/img/gear/clothes/1070.png differ diff --git a/public/img/gear/clothes/1071.png b/public/img/gear/clothes/1071.png index 76d0b20b9..933f6d609 100644 Binary files a/public/img/gear/clothes/1071.png and b/public/img/gear/clothes/1071.png differ diff --git a/public/img/gear/clothes/1072.png b/public/img/gear/clothes/1072.png index db5cddbe2..07f6d33eb 100644 Binary files a/public/img/gear/clothes/1072.png and b/public/img/gear/clothes/1072.png differ diff --git a/public/img/gear/clothes/1073.png b/public/img/gear/clothes/1073.png index 51e388650..eb9f6c364 100644 Binary files a/public/img/gear/clothes/1073.png and b/public/img/gear/clothes/1073.png differ diff --git a/public/img/gear/clothes/1074.png b/public/img/gear/clothes/1074.png index 9fbf134d2..b7858cdc0 100644 Binary files a/public/img/gear/clothes/1074.png and b/public/img/gear/clothes/1074.png differ diff --git a/public/img/gear/clothes/1075.png b/public/img/gear/clothes/1075.png index 545dc8e81..4b5bd4d71 100644 Binary files a/public/img/gear/clothes/1075.png and b/public/img/gear/clothes/1075.png differ diff --git a/public/img/gear/clothes/1076.png b/public/img/gear/clothes/1076.png index fb7919491..14453c52b 100644 Binary files a/public/img/gear/clothes/1076.png and b/public/img/gear/clothes/1076.png differ diff --git a/public/img/gear/clothes/1077.png b/public/img/gear/clothes/1077.png index 3fba13faf..fd402db8f 100644 Binary files a/public/img/gear/clothes/1077.png and b/public/img/gear/clothes/1077.png differ diff --git a/public/img/gear/clothes/1082.png b/public/img/gear/clothes/1082.png index 69ee382af..654e59f07 100644 Binary files a/public/img/gear/clothes/1082.png and b/public/img/gear/clothes/1082.png differ diff --git a/public/img/gear/clothes/1083.png b/public/img/gear/clothes/1083.png index 4e133a89a..41a0519e3 100644 Binary files a/public/img/gear/clothes/1083.png and b/public/img/gear/clothes/1083.png differ diff --git a/public/img/gear/clothes/1084.png b/public/img/gear/clothes/1084.png index 33a07f81e..fc25ffac3 100644 Binary files a/public/img/gear/clothes/1084.png and b/public/img/gear/clothes/1084.png differ diff --git a/public/img/gear/clothes/1085.png b/public/img/gear/clothes/1085.png index 02f661560..f0b0012f2 100644 Binary files a/public/img/gear/clothes/1085.png and b/public/img/gear/clothes/1085.png differ diff --git a/public/img/gear/clothes/1088.png b/public/img/gear/clothes/1088.png index bfe84e7f1..9be23d553 100644 Binary files a/public/img/gear/clothes/1088.png and b/public/img/gear/clothes/1088.png differ diff --git a/public/img/gear/clothes/1090.avif b/public/img/gear/clothes/1090.avif new file mode 100644 index 000000000..bfebecfe8 Binary files /dev/null and b/public/img/gear/clothes/1090.avif differ diff --git a/public/img/gear/clothes/1090.png b/public/img/gear/clothes/1090.png new file mode 100644 index 000000000..e94e7b57f Binary files /dev/null and b/public/img/gear/clothes/1090.png differ diff --git a/public/img/gear/clothes/1091.png b/public/img/gear/clothes/1091.png index ce6d7efdc..d6aff26f9 100644 Binary files a/public/img/gear/clothes/1091.png and b/public/img/gear/clothes/1091.png differ diff --git a/public/img/gear/clothes/2004.png b/public/img/gear/clothes/2004.png index 81391f02e..54e7d8d68 100644 Binary files a/public/img/gear/clothes/2004.png and b/public/img/gear/clothes/2004.png differ diff --git a/public/img/gear/clothes/25000.avif b/public/img/gear/clothes/25000.avif new file mode 100644 index 000000000..006a03a28 Binary files /dev/null and b/public/img/gear/clothes/25000.avif differ diff --git a/public/img/gear/clothes/25000.png b/public/img/gear/clothes/25000.png new file mode 100644 index 000000000..7386d3d9b Binary files /dev/null and b/public/img/gear/clothes/25000.png differ diff --git a/public/img/gear/clothes/25001.avif b/public/img/gear/clothes/25001.avif new file mode 100644 index 000000000..bbdf06798 Binary files /dev/null and b/public/img/gear/clothes/25001.avif differ diff --git a/public/img/gear/clothes/25001.png b/public/img/gear/clothes/25001.png new file mode 100644 index 000000000..7eb8a0103 Binary files /dev/null and b/public/img/gear/clothes/25001.png differ diff --git a/public/img/gear/clothes/25002.avif b/public/img/gear/clothes/25002.avif new file mode 100644 index 000000000..d02a27e72 Binary files /dev/null and b/public/img/gear/clothes/25002.avif differ diff --git a/public/img/gear/clothes/25002.png b/public/img/gear/clothes/25002.png new file mode 100644 index 000000000..48ea81c72 Binary files /dev/null and b/public/img/gear/clothes/25002.png differ diff --git a/public/img/gear/clothes/25003.avif b/public/img/gear/clothes/25003.avif new file mode 100644 index 000000000..eaba8b8e6 Binary files /dev/null and b/public/img/gear/clothes/25003.avif differ diff --git a/public/img/gear/clothes/25003.png b/public/img/gear/clothes/25003.png new file mode 100644 index 000000000..e34860c61 Binary files /dev/null and b/public/img/gear/clothes/25003.png differ diff --git a/public/img/gear/clothes/25004.avif b/public/img/gear/clothes/25004.avif new file mode 100644 index 000000000..70cb30799 Binary files /dev/null and b/public/img/gear/clothes/25004.avif differ diff --git a/public/img/gear/clothes/25004.png b/public/img/gear/clothes/25004.png new file mode 100644 index 000000000..d5e447990 Binary files /dev/null and b/public/img/gear/clothes/25004.png differ diff --git a/public/img/gear/clothes/25005.avif b/public/img/gear/clothes/25005.avif new file mode 100644 index 000000000..da31aaf3b Binary files /dev/null and b/public/img/gear/clothes/25005.avif differ diff --git a/public/img/gear/clothes/25005.png b/public/img/gear/clothes/25005.png new file mode 100644 index 000000000..e180dc292 Binary files /dev/null and b/public/img/gear/clothes/25005.png differ diff --git a/public/img/gear/clothes/25006.avif b/public/img/gear/clothes/25006.avif new file mode 100644 index 000000000..5ac01be74 Binary files /dev/null and b/public/img/gear/clothes/25006.avif differ diff --git a/public/img/gear/clothes/25006.png b/public/img/gear/clothes/25006.png new file mode 100644 index 000000000..5636a7d76 Binary files /dev/null and b/public/img/gear/clothes/25006.png differ diff --git a/public/img/gear/clothes/25007.avif b/public/img/gear/clothes/25007.avif new file mode 100644 index 000000000..4e42d3765 Binary files /dev/null and b/public/img/gear/clothes/25007.avif differ diff --git a/public/img/gear/clothes/25007.png b/public/img/gear/clothes/25007.png new file mode 100644 index 000000000..876b65a17 Binary files /dev/null and b/public/img/gear/clothes/25007.png differ diff --git a/public/img/gear/clothes/25008.avif b/public/img/gear/clothes/25008.avif new file mode 100644 index 000000000..36f94fea9 Binary files /dev/null and b/public/img/gear/clothes/25008.avif differ diff --git a/public/img/gear/clothes/25008.png b/public/img/gear/clothes/25008.png new file mode 100644 index 000000000..2e66fe6f7 Binary files /dev/null and b/public/img/gear/clothes/25008.png differ diff --git a/public/img/gear/clothes/25009.avif b/public/img/gear/clothes/25009.avif new file mode 100644 index 000000000..376b3b22e Binary files /dev/null and b/public/img/gear/clothes/25009.avif differ diff --git a/public/img/gear/clothes/25009.png b/public/img/gear/clothes/25009.png new file mode 100644 index 000000000..5d72bf876 Binary files /dev/null and b/public/img/gear/clothes/25009.png differ diff --git a/public/img/gear/clothes/25010.avif b/public/img/gear/clothes/25010.avif new file mode 100644 index 000000000..2b9229bbb Binary files /dev/null and b/public/img/gear/clothes/25010.avif differ diff --git a/public/img/gear/clothes/25010.png b/public/img/gear/clothes/25010.png new file mode 100644 index 000000000..f9a0bf5b6 Binary files /dev/null and b/public/img/gear/clothes/25010.png differ diff --git a/public/img/gear/clothes/25014.avif b/public/img/gear/clothes/25014.avif new file mode 100644 index 000000000..400df2997 Binary files /dev/null and b/public/img/gear/clothes/25014.avif differ diff --git a/public/img/gear/clothes/25014.png b/public/img/gear/clothes/25014.png new file mode 100644 index 000000000..7b5f2b293 Binary files /dev/null and b/public/img/gear/clothes/25014.png differ diff --git a/public/img/gear/clothes/25015.avif b/public/img/gear/clothes/25015.avif new file mode 100644 index 000000000..1634b864b Binary files /dev/null and b/public/img/gear/clothes/25015.avif differ diff --git a/public/img/gear/clothes/25015.png b/public/img/gear/clothes/25015.png new file mode 100644 index 000000000..2d99d2e31 Binary files /dev/null and b/public/img/gear/clothes/25015.png differ diff --git a/public/img/gear/clothes/25017.avif b/public/img/gear/clothes/25017.avif new file mode 100644 index 000000000..2d907df5f Binary files /dev/null and b/public/img/gear/clothes/25017.avif differ diff --git a/public/img/gear/clothes/25017.png b/public/img/gear/clothes/25017.png new file mode 100644 index 000000000..6ec2ac01b Binary files /dev/null and b/public/img/gear/clothes/25017.png differ diff --git a/public/img/gear/clothes/26000.avif b/public/img/gear/clothes/26000.avif new file mode 100644 index 000000000..36de51c78 Binary files /dev/null and b/public/img/gear/clothes/26000.avif differ diff --git a/public/img/gear/clothes/26000.png b/public/img/gear/clothes/26000.png new file mode 100644 index 000000000..b70d82680 Binary files /dev/null and b/public/img/gear/clothes/26000.png differ diff --git a/public/img/gear/clothes/27000.avif b/public/img/gear/clothes/27000.avif new file mode 100644 index 000000000..48bb4afcc Binary files /dev/null and b/public/img/gear/clothes/27000.avif differ diff --git a/public/img/gear/clothes/27000.png b/public/img/gear/clothes/27000.png new file mode 100644 index 000000000..7858d9906 Binary files /dev/null and b/public/img/gear/clothes/27000.png differ diff --git a/public/img/gear/clothes/27004.avif b/public/img/gear/clothes/27004.avif new file mode 100644 index 000000000..18f99a6e7 Binary files /dev/null and b/public/img/gear/clothes/27004.avif differ diff --git a/public/img/gear/clothes/27004.png b/public/img/gear/clothes/27004.png new file mode 100644 index 000000000..2aa789e7b Binary files /dev/null and b/public/img/gear/clothes/27004.png differ diff --git a/public/img/gear/clothes/27306.avif b/public/img/gear/clothes/27306.avif new file mode 100644 index 000000000..ef4c60a90 Binary files /dev/null and b/public/img/gear/clothes/27306.avif differ diff --git a/public/img/gear/clothes/27306.png b/public/img/gear/clothes/27306.png new file mode 100644 index 000000000..f01703d60 Binary files /dev/null and b/public/img/gear/clothes/27306.png differ diff --git a/public/img/gear/clothes/3000.png b/public/img/gear/clothes/3000.png index 7eeac7e01..fe7b69ba9 100644 Binary files a/public/img/gear/clothes/3000.png and b/public/img/gear/clothes/3000.png differ diff --git a/public/img/gear/clothes/3001.png b/public/img/gear/clothes/3001.png index 7b2014920..787694842 100644 Binary files a/public/img/gear/clothes/3001.png and b/public/img/gear/clothes/3001.png differ diff --git a/public/img/gear/clothes/3004.avif b/public/img/gear/clothes/3004.avif new file mode 100644 index 000000000..d9dff6980 Binary files /dev/null and b/public/img/gear/clothes/3004.avif differ diff --git a/public/img/gear/clothes/3004.png b/public/img/gear/clothes/3004.png new file mode 100644 index 000000000..62ef3e240 Binary files /dev/null and b/public/img/gear/clothes/3004.png differ diff --git a/public/img/gear/clothes/3006.png b/public/img/gear/clothes/3006.png index fa72b3a8c..ec6382902 100644 Binary files a/public/img/gear/clothes/3006.png and b/public/img/gear/clothes/3006.png differ diff --git a/public/img/gear/clothes/3008.png b/public/img/gear/clothes/3008.png index 48a33d822..8f4956da1 100644 Binary files a/public/img/gear/clothes/3008.png and b/public/img/gear/clothes/3008.png differ diff --git a/public/img/gear/clothes/3009.png b/public/img/gear/clothes/3009.png index b43487d53..b2cd226ff 100644 Binary files a/public/img/gear/clothes/3009.png and b/public/img/gear/clothes/3009.png differ diff --git a/public/img/gear/clothes/4004.png b/public/img/gear/clothes/4004.png index f48d6f6dd..eedcc5764 100644 Binary files a/public/img/gear/clothes/4004.png and b/public/img/gear/clothes/4004.png differ diff --git a/public/img/gear/clothes/4005.png b/public/img/gear/clothes/4005.png index 279054652..cb5023b8c 100644 Binary files a/public/img/gear/clothes/4005.png and b/public/img/gear/clothes/4005.png differ diff --git a/public/img/gear/clothes/4009.png b/public/img/gear/clothes/4009.png index c2120c936..e99c276b5 100644 Binary files a/public/img/gear/clothes/4009.png and b/public/img/gear/clothes/4009.png differ diff --git a/public/img/gear/clothes/4010.png b/public/img/gear/clothes/4010.png index caa173d0f..7858c47a1 100644 Binary files a/public/img/gear/clothes/4010.png and b/public/img/gear/clothes/4010.png differ diff --git a/public/img/gear/clothes/5000.png b/public/img/gear/clothes/5000.png index 4301ed796..c73622a15 100644 Binary files a/public/img/gear/clothes/5000.png and b/public/img/gear/clothes/5000.png differ diff --git a/public/img/gear/clothes/5001.png b/public/img/gear/clothes/5001.png index 40fc021fb..650f682ad 100644 Binary files a/public/img/gear/clothes/5001.png and b/public/img/gear/clothes/5001.png differ diff --git a/public/img/gear/clothes/5006.png b/public/img/gear/clothes/5006.png index b38ac590d..11d2e201a 100644 Binary files a/public/img/gear/clothes/5006.png and b/public/img/gear/clothes/5006.png differ diff --git a/public/img/gear/clothes/5014.png b/public/img/gear/clothes/5014.png index 7023c1006..dbbf07873 100644 Binary files a/public/img/gear/clothes/5014.png and b/public/img/gear/clothes/5014.png differ diff --git a/public/img/gear/clothes/5015.png b/public/img/gear/clothes/5015.png index d099bb92d..2ac58d889 100644 Binary files a/public/img/gear/clothes/5015.png and b/public/img/gear/clothes/5015.png differ diff --git a/public/img/gear/clothes/5019.png b/public/img/gear/clothes/5019.png index 0927d26a8..1b1c1c4de 100644 Binary files a/public/img/gear/clothes/5019.png and b/public/img/gear/clothes/5019.png differ diff --git a/public/img/gear/clothes/5023.png b/public/img/gear/clothes/5023.png index 743472ade..d30b65fd6 100644 Binary files a/public/img/gear/clothes/5023.png and b/public/img/gear/clothes/5023.png differ diff --git a/public/img/gear/clothes/5045.png b/public/img/gear/clothes/5045.png index 9a5832bd5..cd94a9b3b 100644 Binary files a/public/img/gear/clothes/5045.png and b/public/img/gear/clothes/5045.png differ diff --git a/public/img/gear/clothes/5046.png b/public/img/gear/clothes/5046.png index a56c83bda..b4bf94703 100644 Binary files a/public/img/gear/clothes/5046.png and b/public/img/gear/clothes/5046.png differ diff --git a/public/img/gear/clothes/5047.png b/public/img/gear/clothes/5047.png index 7f74ee004..0dd10420f 100644 Binary files a/public/img/gear/clothes/5047.png and b/public/img/gear/clothes/5047.png differ diff --git a/public/img/gear/clothes/5048.png b/public/img/gear/clothes/5048.png index f2a04b8e5..ee72a7894 100644 Binary files a/public/img/gear/clothes/5048.png and b/public/img/gear/clothes/5048.png differ diff --git a/public/img/gear/clothes/5049.png b/public/img/gear/clothes/5049.png index 3e2ffc0cc..9ee04e549 100644 Binary files a/public/img/gear/clothes/5049.png and b/public/img/gear/clothes/5049.png differ diff --git a/public/img/gear/clothes/5050.png b/public/img/gear/clothes/5050.png index 9c701d4e0..0b015eeec 100644 Binary files a/public/img/gear/clothes/5050.png and b/public/img/gear/clothes/5050.png differ diff --git a/public/img/gear/clothes/5051.png b/public/img/gear/clothes/5051.png index a68b0f79b..50859eb3c 100644 Binary files a/public/img/gear/clothes/5051.png and b/public/img/gear/clothes/5051.png differ diff --git a/public/img/gear/clothes/5054.png b/public/img/gear/clothes/5054.png index ffa42bdd6..892af027d 100644 Binary files a/public/img/gear/clothes/5054.png and b/public/img/gear/clothes/5054.png differ diff --git a/public/img/gear/clothes/6000.png b/public/img/gear/clothes/6000.png index bb81d857e..923d45449 100644 Binary files a/public/img/gear/clothes/6000.png and b/public/img/gear/clothes/6000.png differ diff --git a/public/img/gear/clothes/6008.png b/public/img/gear/clothes/6008.png index 306fc6dd6..7b9cd956a 100644 Binary files a/public/img/gear/clothes/6008.png and b/public/img/gear/clothes/6008.png differ diff --git a/public/img/gear/clothes/7001.png b/public/img/gear/clothes/7001.png index eb3b1f801..c7a7dfbfa 100644 Binary files a/public/img/gear/clothes/7001.png and b/public/img/gear/clothes/7001.png differ diff --git a/public/img/gear/clothes/7010.png b/public/img/gear/clothes/7010.png index 8219d5670..b63b09721 100644 Binary files a/public/img/gear/clothes/7010.png and b/public/img/gear/clothes/7010.png differ diff --git a/public/img/gear/clothes/7016.png b/public/img/gear/clothes/7016.png index 4c526d50e..4f8bfe0d9 100644 Binary files a/public/img/gear/clothes/7016.png and b/public/img/gear/clothes/7016.png differ diff --git a/public/img/gear/clothes/7017.png b/public/img/gear/clothes/7017.png index 70bac8d23..8ecbb81db 100644 Binary files a/public/img/gear/clothes/7017.png and b/public/img/gear/clothes/7017.png differ diff --git a/public/img/gear/clothes/7018.png b/public/img/gear/clothes/7018.png index 23123cfc2..e5fa67420 100644 Binary files a/public/img/gear/clothes/7018.png and b/public/img/gear/clothes/7018.png differ diff --git a/public/img/gear/clothes/8000.png b/public/img/gear/clothes/8000.png index 8687c403d..b90849614 100644 Binary files a/public/img/gear/clothes/8000.png and b/public/img/gear/clothes/8000.png differ diff --git a/public/img/gear/clothes/8003.png b/public/img/gear/clothes/8003.png index 88018e370..7b384e4ef 100644 Binary files a/public/img/gear/clothes/8003.png and b/public/img/gear/clothes/8003.png differ diff --git a/public/img/gear/clothes/8005.png b/public/img/gear/clothes/8005.png index 88a286c81..d8c2d80df 100644 Binary files a/public/img/gear/clothes/8005.png and b/public/img/gear/clothes/8005.png differ diff --git a/public/img/gear/clothes/8012.png b/public/img/gear/clothes/8012.png index aa83d3981..86aa13c25 100644 Binary files a/public/img/gear/clothes/8012.png and b/public/img/gear/clothes/8012.png differ diff --git a/public/img/gear/clothes/8017.png b/public/img/gear/clothes/8017.png index e7f4d4bd1..43fe8c42e 100644 Binary files a/public/img/gear/clothes/8017.png and b/public/img/gear/clothes/8017.png differ diff --git a/public/img/gear/clothes/8018.png b/public/img/gear/clothes/8018.png index e22f277d2..fdb1593ed 100644 Binary files a/public/img/gear/clothes/8018.png and b/public/img/gear/clothes/8018.png differ diff --git a/public/img/gear/clothes/8019.png b/public/img/gear/clothes/8019.png index e41f5a7e0..28dd13b16 100644 Binary files a/public/img/gear/clothes/8019.png and b/public/img/gear/clothes/8019.png differ diff --git a/public/img/gear/clothes/8020.png b/public/img/gear/clothes/8020.png index 447a56cd1..85b2389af 100644 Binary files a/public/img/gear/clothes/8020.png and b/public/img/gear/clothes/8020.png differ diff --git a/public/img/gear/clothes/8024.png b/public/img/gear/clothes/8024.png index 25e41117b..1a588f35e 100644 Binary files a/public/img/gear/clothes/8024.png and b/public/img/gear/clothes/8024.png differ diff --git a/public/img/gear/clothes/8025.png b/public/img/gear/clothes/8025.png index 4f6b405cb..25e755437 100644 Binary files a/public/img/gear/clothes/8025.png and b/public/img/gear/clothes/8025.png differ diff --git a/public/img/gear/clothes/8030.png b/public/img/gear/clothes/8030.png index 20f4b2d98..8fe3baab2 100644 Binary files a/public/img/gear/clothes/8030.png and b/public/img/gear/clothes/8030.png differ diff --git a/public/img/gear/clothes/8031.png b/public/img/gear/clothes/8031.png index 92ce77752..57ef63240 100644 Binary files a/public/img/gear/clothes/8031.png and b/public/img/gear/clothes/8031.png differ diff --git a/public/img/gear/clothes/8033.png b/public/img/gear/clothes/8033.png index b6efc5c7c..144833d90 100644 Binary files a/public/img/gear/clothes/8033.png and b/public/img/gear/clothes/8033.png differ diff --git a/public/img/gear/clothes/8034.png b/public/img/gear/clothes/8034.png index a2cb0b5ca..7d8d59764 100644 Binary files a/public/img/gear/clothes/8034.png and b/public/img/gear/clothes/8034.png differ diff --git a/public/img/gear/clothes/8036.png b/public/img/gear/clothes/8036.png index 3d7b6ddbe..c8fa7dca6 100644 Binary files a/public/img/gear/clothes/8036.png and b/public/img/gear/clothes/8036.png differ diff --git a/public/img/gear/clothes/8040.png b/public/img/gear/clothes/8040.png index 3a4b70bfe..850115fd7 100644 Binary files a/public/img/gear/clothes/8040.png and b/public/img/gear/clothes/8040.png differ diff --git a/public/img/gear/clothes/9010.png b/public/img/gear/clothes/9010.png index ac0b98c52..99b4ff5bd 100644 Binary files a/public/img/gear/clothes/9010.png and b/public/img/gear/clothes/9010.png differ diff --git a/public/img/gear/clothes/9011.png b/public/img/gear/clothes/9011.png index 08ef45e06..e7b010a2b 100644 Binary files a/public/img/gear/clothes/9011.png and b/public/img/gear/clothes/9011.png differ diff --git a/public/img/gear/clothes/9012.avif b/public/img/gear/clothes/9012.avif new file mode 100644 index 000000000..1cdbd90c8 Binary files /dev/null and b/public/img/gear/clothes/9012.avif differ diff --git a/public/img/gear/clothes/9012.png b/public/img/gear/clothes/9012.png new file mode 100644 index 000000000..b04bba703 Binary files /dev/null and b/public/img/gear/clothes/9012.png differ diff --git a/public/img/gear/clothes/9013.avif b/public/img/gear/clothes/9013.avif new file mode 100644 index 000000000..48c45f316 Binary files /dev/null and b/public/img/gear/clothes/9013.avif differ diff --git a/public/img/gear/clothes/9013.png b/public/img/gear/clothes/9013.png new file mode 100644 index 000000000..60ae32fbc Binary files /dev/null and b/public/img/gear/clothes/9013.png differ diff --git a/public/img/gear/head/1.png b/public/img/gear/head/1.png index cc8832b2c..d2a39af3a 100644 Binary files a/public/img/gear/head/1.png and b/public/img/gear/head/1.png differ diff --git a/public/img/gear/head/1000.png b/public/img/gear/head/1000.png index 16023e3bb..334b238f8 100644 Binary files a/public/img/gear/head/1000.png and b/public/img/gear/head/1000.png differ diff --git a/public/img/gear/head/1002.png b/public/img/gear/head/1002.png index 3a943455d..c9626fc32 100644 Binary files a/public/img/gear/head/1002.png and b/public/img/gear/head/1002.png differ diff --git a/public/img/gear/head/1003.png b/public/img/gear/head/1003.png index fb8dbf2c9..9607d907f 100644 Binary files a/public/img/gear/head/1003.png and b/public/img/gear/head/1003.png differ diff --git a/public/img/gear/head/1005.png b/public/img/gear/head/1005.png index da1141c9d..3064054b0 100644 Binary files a/public/img/gear/head/1005.png and b/public/img/gear/head/1005.png differ diff --git a/public/img/gear/head/1012.png b/public/img/gear/head/1012.png index c346b5103..59c1808db 100644 Binary files a/public/img/gear/head/1012.png and b/public/img/gear/head/1012.png differ diff --git a/public/img/gear/head/1020.png b/public/img/gear/head/1020.png index 246fb5e11..82e3b3b36 100644 Binary files a/public/img/gear/head/1020.png and b/public/img/gear/head/1020.png differ diff --git a/public/img/gear/head/1021.png b/public/img/gear/head/1021.png index d9317cd2b..f46dfcf93 100644 Binary files a/public/img/gear/head/1021.png and b/public/img/gear/head/1021.png differ diff --git a/public/img/gear/head/1028.png b/public/img/gear/head/1028.png index e0cdfb90c..050888700 100644 Binary files a/public/img/gear/head/1028.png and b/public/img/gear/head/1028.png differ diff --git a/public/img/gear/head/1036.png b/public/img/gear/head/1036.png index 0381bfd66..c96e6e84c 100644 Binary files a/public/img/gear/head/1036.png and b/public/img/gear/head/1036.png differ diff --git a/public/img/gear/head/2008.png b/public/img/gear/head/2008.png index 7ea8c5b9b..ea7fb4eaa 100644 Binary files a/public/img/gear/head/2008.png and b/public/img/gear/head/2008.png differ diff --git a/public/img/gear/head/21010.avif b/public/img/gear/head/21010.avif new file mode 100644 index 000000000..1733631db Binary files /dev/null and b/public/img/gear/head/21010.avif differ diff --git a/public/img/gear/head/21010.png b/public/img/gear/head/21010.png new file mode 100644 index 000000000..9e133c04d Binary files /dev/null and b/public/img/gear/head/21010.png differ diff --git a/public/img/gear/head/25000.avif b/public/img/gear/head/25000.avif new file mode 100644 index 000000000..aa8da3aa2 Binary files /dev/null and b/public/img/gear/head/25000.avif differ diff --git a/public/img/gear/head/25000.png b/public/img/gear/head/25000.png new file mode 100644 index 000000000..7c446daa6 Binary files /dev/null and b/public/img/gear/head/25000.png differ diff --git a/public/img/gear/head/25001.avif b/public/img/gear/head/25001.avif new file mode 100644 index 000000000..0f9bee47c Binary files /dev/null and b/public/img/gear/head/25001.avif differ diff --git a/public/img/gear/head/25001.png b/public/img/gear/head/25001.png new file mode 100644 index 000000000..2a620c8d2 Binary files /dev/null and b/public/img/gear/head/25001.png differ diff --git a/public/img/gear/head/25002.avif b/public/img/gear/head/25002.avif new file mode 100644 index 000000000..1fbecf5e2 Binary files /dev/null and b/public/img/gear/head/25002.avif differ diff --git a/public/img/gear/head/25002.png b/public/img/gear/head/25002.png new file mode 100644 index 000000000..9e549e511 Binary files /dev/null and b/public/img/gear/head/25002.png differ diff --git a/public/img/gear/head/25003.avif b/public/img/gear/head/25003.avif new file mode 100644 index 000000000..ab1ccd49f Binary files /dev/null and b/public/img/gear/head/25003.avif differ diff --git a/public/img/gear/head/25003.png b/public/img/gear/head/25003.png new file mode 100644 index 000000000..02ef7725c Binary files /dev/null and b/public/img/gear/head/25003.png differ diff --git a/public/img/gear/head/25004.avif b/public/img/gear/head/25004.avif new file mode 100644 index 000000000..c14637e82 Binary files /dev/null and b/public/img/gear/head/25004.avif differ diff --git a/public/img/gear/head/25004.png b/public/img/gear/head/25004.png new file mode 100644 index 000000000..2e633bee6 Binary files /dev/null and b/public/img/gear/head/25004.png differ diff --git a/public/img/gear/head/25005.avif b/public/img/gear/head/25005.avif new file mode 100644 index 000000000..2dc459ca9 Binary files /dev/null and b/public/img/gear/head/25005.avif differ diff --git a/public/img/gear/head/25005.png b/public/img/gear/head/25005.png new file mode 100644 index 000000000..ac500ee0c Binary files /dev/null and b/public/img/gear/head/25005.png differ diff --git a/public/img/gear/head/25006.avif b/public/img/gear/head/25006.avif new file mode 100644 index 000000000..847dc751c Binary files /dev/null and b/public/img/gear/head/25006.avif differ diff --git a/public/img/gear/head/25006.png b/public/img/gear/head/25006.png new file mode 100644 index 000000000..3b6988072 Binary files /dev/null and b/public/img/gear/head/25006.png differ diff --git a/public/img/gear/head/25007.avif b/public/img/gear/head/25007.avif new file mode 100644 index 000000000..e4bd3c04a Binary files /dev/null and b/public/img/gear/head/25007.avif differ diff --git a/public/img/gear/head/25007.png b/public/img/gear/head/25007.png new file mode 100644 index 000000000..dd30990af Binary files /dev/null and b/public/img/gear/head/25007.png differ diff --git a/public/img/gear/head/25008.avif b/public/img/gear/head/25008.avif new file mode 100644 index 000000000..38eba5b51 Binary files /dev/null and b/public/img/gear/head/25008.avif differ diff --git a/public/img/gear/head/25008.png b/public/img/gear/head/25008.png new file mode 100644 index 000000000..a1b049c9a Binary files /dev/null and b/public/img/gear/head/25008.png differ diff --git a/public/img/gear/head/25009.avif b/public/img/gear/head/25009.avif new file mode 100644 index 000000000..594dd723f Binary files /dev/null and b/public/img/gear/head/25009.avif differ diff --git a/public/img/gear/head/25009.png b/public/img/gear/head/25009.png new file mode 100644 index 000000000..801928801 Binary files /dev/null and b/public/img/gear/head/25009.png differ diff --git a/public/img/gear/head/25010.avif b/public/img/gear/head/25010.avif new file mode 100644 index 000000000..e1c9a86f2 Binary files /dev/null and b/public/img/gear/head/25010.avif differ diff --git a/public/img/gear/head/25010.png b/public/img/gear/head/25010.png new file mode 100644 index 000000000..6b8679972 Binary files /dev/null and b/public/img/gear/head/25010.png differ diff --git a/public/img/gear/head/25016.avif b/public/img/gear/head/25016.avif new file mode 100644 index 000000000..450273dc2 Binary files /dev/null and b/public/img/gear/head/25016.avif differ diff --git a/public/img/gear/head/25016.png b/public/img/gear/head/25016.png new file mode 100644 index 000000000..af2716c98 Binary files /dev/null and b/public/img/gear/head/25016.png differ diff --git a/public/img/gear/head/25017.avif b/public/img/gear/head/25017.avif new file mode 100644 index 000000000..a80936e24 Binary files /dev/null and b/public/img/gear/head/25017.avif differ diff --git a/public/img/gear/head/25017.png b/public/img/gear/head/25017.png new file mode 100644 index 000000000..8514bd76a Binary files /dev/null and b/public/img/gear/head/25017.png differ diff --git a/public/img/gear/head/27000.avif b/public/img/gear/head/27000.avif new file mode 100644 index 000000000..def12f5e0 Binary files /dev/null and b/public/img/gear/head/27000.avif differ diff --git a/public/img/gear/head/27000.png b/public/img/gear/head/27000.png new file mode 100644 index 000000000..12a528a45 Binary files /dev/null and b/public/img/gear/head/27000.png differ diff --git a/public/img/gear/head/27004.avif b/public/img/gear/head/27004.avif new file mode 100644 index 000000000..86584c340 Binary files /dev/null and b/public/img/gear/head/27004.avif differ diff --git a/public/img/gear/head/27004.png b/public/img/gear/head/27004.png new file mode 100644 index 000000000..ea646ee59 Binary files /dev/null and b/public/img/gear/head/27004.png differ diff --git a/public/img/gear/head/27109.avif b/public/img/gear/head/27109.avif new file mode 100644 index 000000000..253ecc863 Binary files /dev/null and b/public/img/gear/head/27109.avif differ diff --git a/public/img/gear/head/27109.png b/public/img/gear/head/27109.png new file mode 100644 index 000000000..ac2f3e666 Binary files /dev/null and b/public/img/gear/head/27109.png differ diff --git a/public/img/gear/head/27306.avif b/public/img/gear/head/27306.avif new file mode 100644 index 000000000..94d4b68f2 Binary files /dev/null and b/public/img/gear/head/27306.avif differ diff --git a/public/img/gear/head/27306.png b/public/img/gear/head/27306.png new file mode 100644 index 000000000..d6666a5ed Binary files /dev/null and b/public/img/gear/head/27306.png differ diff --git a/public/img/gear/head/28000.avif b/public/img/gear/head/28000.avif new file mode 100644 index 000000000..2326be882 Binary files /dev/null and b/public/img/gear/head/28000.avif differ diff --git a/public/img/gear/head/28000.png b/public/img/gear/head/28000.png new file mode 100644 index 000000000..1805d18a7 Binary files /dev/null and b/public/img/gear/head/28000.png differ diff --git a/public/img/gear/head/3001.png b/public/img/gear/head/3001.png index b4e7ac6e0..4593fd9dd 100644 Binary files a/public/img/gear/head/3001.png and b/public/img/gear/head/3001.png differ diff --git a/public/img/gear/head/3002.avif b/public/img/gear/head/3002.avif new file mode 100644 index 000000000..c83c49aba Binary files /dev/null and b/public/img/gear/head/3002.avif differ diff --git a/public/img/gear/head/3002.png b/public/img/gear/head/3002.png new file mode 100644 index 000000000..4b58650dc Binary files /dev/null and b/public/img/gear/head/3002.png differ diff --git a/public/img/gear/head/3003.png b/public/img/gear/head/3003.png index f9da882f9..36cfa6f2d 100644 Binary files a/public/img/gear/head/3003.png and b/public/img/gear/head/3003.png differ diff --git a/public/img/gear/head/3008.png b/public/img/gear/head/3008.png index d1519e7c7..338ec0ab5 100644 Binary files a/public/img/gear/head/3008.png and b/public/img/gear/head/3008.png differ diff --git a/public/img/gear/head/3009.png b/public/img/gear/head/3009.png index 8b8d89ebd..4ca650bba 100644 Binary files a/public/img/gear/head/3009.png and b/public/img/gear/head/3009.png differ diff --git a/public/img/gear/head/3011.png b/public/img/gear/head/3011.png index 4525f6eb8..3d9541bee 100644 Binary files a/public/img/gear/head/3011.png and b/public/img/gear/head/3011.png differ diff --git a/public/img/gear/head/3012.png b/public/img/gear/head/3012.png index 93449e80b..bd3aa2f18 100644 Binary files a/public/img/gear/head/3012.png and b/public/img/gear/head/3012.png differ diff --git a/public/img/gear/head/3016.png b/public/img/gear/head/3016.png index 5858cef97..383c74a8f 100644 Binary files a/public/img/gear/head/3016.png and b/public/img/gear/head/3016.png differ diff --git a/public/img/gear/head/3021.png b/public/img/gear/head/3021.png index a8137e0f3..75c5896e9 100644 Binary files a/public/img/gear/head/3021.png and b/public/img/gear/head/3021.png differ diff --git a/public/img/gear/head/3022.avif b/public/img/gear/head/3022.avif new file mode 100644 index 000000000..b997c218f Binary files /dev/null and b/public/img/gear/head/3022.avif differ diff --git a/public/img/gear/head/3022.png b/public/img/gear/head/3022.png new file mode 100644 index 000000000..c8c4c38e0 Binary files /dev/null and b/public/img/gear/head/3022.png differ diff --git a/public/img/gear/head/3023.avif b/public/img/gear/head/3023.avif new file mode 100644 index 000000000..18e24dac8 Binary files /dev/null and b/public/img/gear/head/3023.avif differ diff --git a/public/img/gear/head/3023.png b/public/img/gear/head/3023.png new file mode 100644 index 000000000..68fcb27d4 Binary files /dev/null and b/public/img/gear/head/3023.png differ diff --git a/public/img/gear/head/3024.avif b/public/img/gear/head/3024.avif new file mode 100644 index 000000000..64c19314c Binary files /dev/null and b/public/img/gear/head/3024.avif differ diff --git a/public/img/gear/head/3024.png b/public/img/gear/head/3024.png new file mode 100644 index 000000000..3239849f4 Binary files /dev/null and b/public/img/gear/head/3024.png differ diff --git a/public/img/gear/head/3025.png b/public/img/gear/head/3025.png index b999d4435..830883678 100644 Binary files a/public/img/gear/head/3025.png and b/public/img/gear/head/3025.png differ diff --git a/public/img/gear/head/3026.png b/public/img/gear/head/3026.png index 6ede1b205..75d7a18e1 100644 Binary files a/public/img/gear/head/3026.png and b/public/img/gear/head/3026.png differ diff --git a/public/img/gear/head/3027.png b/public/img/gear/head/3027.png index 3e00dc14a..5c905e431 100644 Binary files a/public/img/gear/head/3027.png and b/public/img/gear/head/3027.png differ diff --git a/public/img/gear/head/3029.avif b/public/img/gear/head/3029.avif new file mode 100644 index 000000000..ba161c64c Binary files /dev/null and b/public/img/gear/head/3029.avif differ diff --git a/public/img/gear/head/3029.png b/public/img/gear/head/3029.png new file mode 100644 index 000000000..1cea82a29 Binary files /dev/null and b/public/img/gear/head/3029.png differ diff --git a/public/img/gear/head/4004.png b/public/img/gear/head/4004.png index 516d9627f..2a1dd66b1 100644 Binary files a/public/img/gear/head/4004.png and b/public/img/gear/head/4004.png differ diff --git a/public/img/gear/head/4006.avif b/public/img/gear/head/4006.avif new file mode 100644 index 000000000..dd0701cc6 Binary files /dev/null and b/public/img/gear/head/4006.avif differ diff --git a/public/img/gear/head/4006.png b/public/img/gear/head/4006.png new file mode 100644 index 000000000..5831d7a87 Binary files /dev/null and b/public/img/gear/head/4006.png differ diff --git a/public/img/gear/head/4008.png b/public/img/gear/head/4008.png index e37eb660a..8595b93f0 100644 Binary files a/public/img/gear/head/4008.png and b/public/img/gear/head/4008.png differ diff --git a/public/img/gear/head/4015.png b/public/img/gear/head/4015.png index bec0459c7..5ac1b7d0d 100644 Binary files a/public/img/gear/head/4015.png and b/public/img/gear/head/4015.png differ diff --git a/public/img/gear/head/4016.png b/public/img/gear/head/4016.png index abf3e5159..7466d2a82 100644 Binary files a/public/img/gear/head/4016.png and b/public/img/gear/head/4016.png differ diff --git a/public/img/gear/head/4017.png b/public/img/gear/head/4017.png index d03745938..8f4587091 100644 Binary files a/public/img/gear/head/4017.png and b/public/img/gear/head/4017.png differ diff --git a/public/img/gear/head/4019.avif b/public/img/gear/head/4019.avif new file mode 100644 index 000000000..3328a7d23 Binary files /dev/null and b/public/img/gear/head/4019.avif differ diff --git a/public/img/gear/head/4019.png b/public/img/gear/head/4019.png new file mode 100644 index 000000000..d8e6e1bcc Binary files /dev/null and b/public/img/gear/head/4019.png differ diff --git a/public/img/gear/head/5000.avif b/public/img/gear/head/5000.avif new file mode 100644 index 000000000..4b8578693 Binary files /dev/null and b/public/img/gear/head/5000.avif differ diff --git a/public/img/gear/head/5000.png b/public/img/gear/head/5000.png new file mode 100644 index 000000000..679ec2f48 Binary files /dev/null and b/public/img/gear/head/5000.png differ diff --git a/public/img/gear/head/5001.png b/public/img/gear/head/5001.png index 9d29e602f..57b4bf761 100644 Binary files a/public/img/gear/head/5001.png and b/public/img/gear/head/5001.png differ diff --git a/public/img/gear/head/5004.png b/public/img/gear/head/5004.png index 7ba03d980..cc20b6ca4 100644 Binary files a/public/img/gear/head/5004.png and b/public/img/gear/head/5004.png differ diff --git a/public/img/gear/head/5007.png b/public/img/gear/head/5007.png index cf534314e..3578085e0 100644 Binary files a/public/img/gear/head/5007.png and b/public/img/gear/head/5007.png differ diff --git a/public/img/gear/head/5008.png b/public/img/gear/head/5008.png index f0a72ea55..1092202f6 100644 Binary files a/public/img/gear/head/5008.png and b/public/img/gear/head/5008.png differ diff --git a/public/img/gear/head/6001.png b/public/img/gear/head/6001.png index 25dfb0bb7..d52f158d7 100644 Binary files a/public/img/gear/head/6001.png and b/public/img/gear/head/6001.png differ diff --git a/public/img/gear/head/6003.png b/public/img/gear/head/6003.png index bef247a84..1da91b6ff 100644 Binary files a/public/img/gear/head/6003.png and b/public/img/gear/head/6003.png differ diff --git a/public/img/gear/head/6004.png b/public/img/gear/head/6004.png index 124426b73..591367bfa 100644 Binary files a/public/img/gear/head/6004.png and b/public/img/gear/head/6004.png differ diff --git a/public/img/gear/head/7007.png b/public/img/gear/head/7007.png index 8ae6f38be..a683b6479 100644 Binary files a/public/img/gear/head/7007.png and b/public/img/gear/head/7007.png differ diff --git a/public/img/gear/head/7012.png b/public/img/gear/head/7012.png index b03a7047b..af060446b 100644 Binary files a/public/img/gear/head/7012.png and b/public/img/gear/head/7012.png differ diff --git a/public/img/gear/head/7013.png b/public/img/gear/head/7013.png index fd1cf5628..93883be89 100644 Binary files a/public/img/gear/head/7013.png and b/public/img/gear/head/7013.png differ diff --git a/public/img/gear/head/7014.png b/public/img/gear/head/7014.png index fe31bd296..6e1d5a94b 100644 Binary files a/public/img/gear/head/7014.png and b/public/img/gear/head/7014.png differ diff --git a/public/img/gear/head/8005.png b/public/img/gear/head/8005.png index c7e3db32e..3badbb6db 100644 Binary files a/public/img/gear/head/8005.png and b/public/img/gear/head/8005.png differ diff --git a/public/img/gear/head/8008.png b/public/img/gear/head/8008.png index e6d4fd94e..46dab7b28 100644 Binary files a/public/img/gear/head/8008.png and b/public/img/gear/head/8008.png differ diff --git a/public/img/gear/head/8011.png b/public/img/gear/head/8011.png index e75482f5c..843fa18bd 100644 Binary files a/public/img/gear/head/8011.png and b/public/img/gear/head/8011.png differ diff --git a/public/img/gear/head/8014.png b/public/img/gear/head/8014.png index ae67b2024..857547499 100644 Binary files a/public/img/gear/head/8014.png and b/public/img/gear/head/8014.png differ diff --git a/public/img/gear/head/8015.avif b/public/img/gear/head/8015.avif new file mode 100644 index 000000000..bad1983b8 Binary files /dev/null and b/public/img/gear/head/8015.avif differ diff --git a/public/img/gear/head/8015.png b/public/img/gear/head/8015.png new file mode 100644 index 000000000..c03a54326 Binary files /dev/null and b/public/img/gear/head/8015.png differ diff --git a/public/img/gear/head/8016.png b/public/img/gear/head/8016.png index 6b3e44962..ebe36b9b4 100644 Binary files a/public/img/gear/head/8016.png and b/public/img/gear/head/8016.png differ diff --git a/public/img/gear/head/9003.png b/public/img/gear/head/9003.png index c02fbbf9a..71f1ff220 100644 Binary files a/public/img/gear/head/9003.png and b/public/img/gear/head/9003.png differ diff --git a/public/img/gear/head/9007.png b/public/img/gear/head/9007.png index 5d1a2187f..03b20707b 100644 Binary files a/public/img/gear/head/9007.png and b/public/img/gear/head/9007.png differ diff --git a/public/img/gear/head/9009.png b/public/img/gear/head/9009.png index a70afbf5b..0dc8b1b5e 100644 Binary files a/public/img/gear/head/9009.png and b/public/img/gear/head/9009.png differ diff --git a/public/img/gear/shoes/1000.png b/public/img/gear/shoes/1000.png index f3f8c4017..edcaa1e65 100644 Binary files a/public/img/gear/shoes/1000.png and b/public/img/gear/shoes/1000.png differ diff --git a/public/img/gear/shoes/1008.png b/public/img/gear/shoes/1008.png index e5ccfc452..fcf7b5b84 100644 Binary files a/public/img/gear/shoes/1008.png and b/public/img/gear/shoes/1008.png differ diff --git a/public/img/gear/shoes/1009.png b/public/img/gear/shoes/1009.png index 6530866de..c630ebcd2 100644 Binary files a/public/img/gear/shoes/1009.png and b/public/img/gear/shoes/1009.png differ diff --git a/public/img/gear/shoes/1021.png b/public/img/gear/shoes/1021.png index c5c72e5c6..74a82ae16 100644 Binary files a/public/img/gear/shoes/1021.png and b/public/img/gear/shoes/1021.png differ diff --git a/public/img/gear/shoes/1022.png b/public/img/gear/shoes/1022.png index fb0657c0a..699a58d72 100644 Binary files a/public/img/gear/shoes/1022.png and b/public/img/gear/shoes/1022.png differ diff --git a/public/img/gear/shoes/1023.avif b/public/img/gear/shoes/1023.avif new file mode 100644 index 000000000..f4fa65b09 Binary files /dev/null and b/public/img/gear/shoes/1023.avif differ diff --git a/public/img/gear/shoes/1023.png b/public/img/gear/shoes/1023.png new file mode 100644 index 000000000..4f89bb4aa Binary files /dev/null and b/public/img/gear/shoes/1023.png differ diff --git a/public/img/gear/shoes/1024.png b/public/img/gear/shoes/1024.png index 6f5a65b48..f5cdd9505 100644 Binary files a/public/img/gear/shoes/1024.png and b/public/img/gear/shoes/1024.png differ diff --git a/public/img/gear/shoes/2000.png b/public/img/gear/shoes/2000.png index d995e5ff9..8fe4e21d5 100644 Binary files a/public/img/gear/shoes/2000.png and b/public/img/gear/shoes/2000.png differ diff --git a/public/img/gear/shoes/2001.png b/public/img/gear/shoes/2001.png index 6a59bf05a..5b3f7defe 100644 Binary files a/public/img/gear/shoes/2001.png and b/public/img/gear/shoes/2001.png differ diff --git a/public/img/gear/shoes/2003.avif b/public/img/gear/shoes/2003.avif new file mode 100644 index 000000000..9ec7ad112 Binary files /dev/null and b/public/img/gear/shoes/2003.avif differ diff --git a/public/img/gear/shoes/2003.png b/public/img/gear/shoes/2003.png new file mode 100644 index 000000000..ec98a8d00 Binary files /dev/null and b/public/img/gear/shoes/2003.png differ diff --git a/public/img/gear/shoes/2004.png b/public/img/gear/shoes/2004.png index 091f463da..457927114 100644 Binary files a/public/img/gear/shoes/2004.png and b/public/img/gear/shoes/2004.png differ diff --git a/public/img/gear/shoes/2005.png b/public/img/gear/shoes/2005.png index 08f3a06e4..b56372b62 100644 Binary files a/public/img/gear/shoes/2005.png and b/public/img/gear/shoes/2005.png differ diff --git a/public/img/gear/shoes/2016.png b/public/img/gear/shoes/2016.png index 9ee152632..76d7b685a 100644 Binary files a/public/img/gear/shoes/2016.png and b/public/img/gear/shoes/2016.png differ diff --git a/public/img/gear/shoes/2017.png b/public/img/gear/shoes/2017.png index 84ddfdd06..493c41eb9 100644 Binary files a/public/img/gear/shoes/2017.png and b/public/img/gear/shoes/2017.png differ diff --git a/public/img/gear/shoes/2018.png b/public/img/gear/shoes/2018.png index 152bc3b4b..0a57340c8 100644 Binary files a/public/img/gear/shoes/2018.png and b/public/img/gear/shoes/2018.png differ diff --git a/public/img/gear/shoes/2042.png b/public/img/gear/shoes/2042.png index dc967c7ce..c98e7cbed 100644 Binary files a/public/img/gear/shoes/2042.png and b/public/img/gear/shoes/2042.png differ diff --git a/public/img/gear/shoes/2043.png b/public/img/gear/shoes/2043.png index c312677d9..0604c1d1a 100644 Binary files a/public/img/gear/shoes/2043.png and b/public/img/gear/shoes/2043.png differ diff --git a/public/img/gear/shoes/2045.png b/public/img/gear/shoes/2045.png index 42c90ec47..0a498c47c 100644 Binary files a/public/img/gear/shoes/2045.png and b/public/img/gear/shoes/2045.png differ diff --git a/public/img/gear/shoes/25000.avif b/public/img/gear/shoes/25000.avif new file mode 100644 index 000000000..e8dba276e Binary files /dev/null and b/public/img/gear/shoes/25000.avif differ diff --git a/public/img/gear/shoes/25000.png b/public/img/gear/shoes/25000.png new file mode 100644 index 000000000..64a5905c6 Binary files /dev/null and b/public/img/gear/shoes/25000.png differ diff --git a/public/img/gear/shoes/25001.avif b/public/img/gear/shoes/25001.avif new file mode 100644 index 000000000..d5d7b56a8 Binary files /dev/null and b/public/img/gear/shoes/25001.avif differ diff --git a/public/img/gear/shoes/25001.png b/public/img/gear/shoes/25001.png new file mode 100644 index 000000000..14d72223c Binary files /dev/null and b/public/img/gear/shoes/25001.png differ diff --git a/public/img/gear/shoes/25002.avif b/public/img/gear/shoes/25002.avif new file mode 100644 index 000000000..f4547854e Binary files /dev/null and b/public/img/gear/shoes/25002.avif differ diff --git a/public/img/gear/shoes/25002.png b/public/img/gear/shoes/25002.png new file mode 100644 index 000000000..6e4e35e66 Binary files /dev/null and b/public/img/gear/shoes/25002.png differ diff --git a/public/img/gear/shoes/25003.avif b/public/img/gear/shoes/25003.avif new file mode 100644 index 000000000..4269348b9 Binary files /dev/null and b/public/img/gear/shoes/25003.avif differ diff --git a/public/img/gear/shoes/25003.png b/public/img/gear/shoes/25003.png new file mode 100644 index 000000000..e127835bb Binary files /dev/null and b/public/img/gear/shoes/25003.png differ diff --git a/public/img/gear/shoes/25004.avif b/public/img/gear/shoes/25004.avif new file mode 100644 index 000000000..945e4d1cf Binary files /dev/null and b/public/img/gear/shoes/25004.avif differ diff --git a/public/img/gear/shoes/25004.png b/public/img/gear/shoes/25004.png new file mode 100644 index 000000000..793c3ac3c Binary files /dev/null and b/public/img/gear/shoes/25004.png differ diff --git a/public/img/gear/shoes/25005.avif b/public/img/gear/shoes/25005.avif new file mode 100644 index 000000000..996bbbbac Binary files /dev/null and b/public/img/gear/shoes/25005.avif differ diff --git a/public/img/gear/shoes/25005.png b/public/img/gear/shoes/25005.png new file mode 100644 index 000000000..87b0d7121 Binary files /dev/null and b/public/img/gear/shoes/25005.png differ diff --git a/public/img/gear/shoes/25006.avif b/public/img/gear/shoes/25006.avif new file mode 100644 index 000000000..bdaa3c0a3 Binary files /dev/null and b/public/img/gear/shoes/25006.avif differ diff --git a/public/img/gear/shoes/25006.png b/public/img/gear/shoes/25006.png new file mode 100644 index 000000000..c7538f081 Binary files /dev/null and b/public/img/gear/shoes/25006.png differ diff --git a/public/img/gear/shoes/25007.avif b/public/img/gear/shoes/25007.avif new file mode 100644 index 000000000..07b4f3cc9 Binary files /dev/null and b/public/img/gear/shoes/25007.avif differ diff --git a/public/img/gear/shoes/25007.png b/public/img/gear/shoes/25007.png new file mode 100644 index 000000000..005b16dc5 Binary files /dev/null and b/public/img/gear/shoes/25007.png differ diff --git a/public/img/gear/shoes/25008.avif b/public/img/gear/shoes/25008.avif new file mode 100644 index 000000000..1b7d3aef4 Binary files /dev/null and b/public/img/gear/shoes/25008.avif differ diff --git a/public/img/gear/shoes/25008.png b/public/img/gear/shoes/25008.png new file mode 100644 index 000000000..947aabd1b Binary files /dev/null and b/public/img/gear/shoes/25008.png differ diff --git a/public/img/gear/shoes/25009.avif b/public/img/gear/shoes/25009.avif new file mode 100644 index 000000000..163c9c5d7 Binary files /dev/null and b/public/img/gear/shoes/25009.avif differ diff --git a/public/img/gear/shoes/25009.png b/public/img/gear/shoes/25009.png new file mode 100644 index 000000000..0957a5632 Binary files /dev/null and b/public/img/gear/shoes/25009.png differ diff --git a/public/img/gear/shoes/25010.avif b/public/img/gear/shoes/25010.avif new file mode 100644 index 000000000..4f7d3ac28 Binary files /dev/null and b/public/img/gear/shoes/25010.avif differ diff --git a/public/img/gear/shoes/25010.png b/public/img/gear/shoes/25010.png new file mode 100644 index 000000000..b4fa23e49 Binary files /dev/null and b/public/img/gear/shoes/25010.png differ diff --git a/public/img/gear/shoes/25014.avif b/public/img/gear/shoes/25014.avif new file mode 100644 index 000000000..7e2f8ba73 Binary files /dev/null and b/public/img/gear/shoes/25014.avif differ diff --git a/public/img/gear/shoes/25014.png b/public/img/gear/shoes/25014.png new file mode 100644 index 000000000..4301405af Binary files /dev/null and b/public/img/gear/shoes/25014.png differ diff --git a/public/img/gear/shoes/25015.avif b/public/img/gear/shoes/25015.avif new file mode 100644 index 000000000..6df8305c6 Binary files /dev/null and b/public/img/gear/shoes/25015.avif differ diff --git a/public/img/gear/shoes/25015.png b/public/img/gear/shoes/25015.png new file mode 100644 index 000000000..ff45aa6f4 Binary files /dev/null and b/public/img/gear/shoes/25015.png differ diff --git a/public/img/gear/shoes/27000.avif b/public/img/gear/shoes/27000.avif new file mode 100644 index 000000000..0531eaa1b Binary files /dev/null and b/public/img/gear/shoes/27000.avif differ diff --git a/public/img/gear/shoes/27000.png b/public/img/gear/shoes/27000.png new file mode 100644 index 000000000..cb6da40aa Binary files /dev/null and b/public/img/gear/shoes/27000.png differ diff --git a/public/img/gear/shoes/27004.avif b/public/img/gear/shoes/27004.avif new file mode 100644 index 000000000..c0c279496 Binary files /dev/null and b/public/img/gear/shoes/27004.avif differ diff --git a/public/img/gear/shoes/27004.png b/public/img/gear/shoes/27004.png new file mode 100644 index 000000000..f8f443876 Binary files /dev/null and b/public/img/gear/shoes/27004.png differ diff --git a/public/img/gear/shoes/27306.avif b/public/img/gear/shoes/27306.avif new file mode 100644 index 000000000..5c65a4c18 Binary files /dev/null and b/public/img/gear/shoes/27306.avif differ diff --git a/public/img/gear/shoes/27306.png b/public/img/gear/shoes/27306.png new file mode 100644 index 000000000..96b65b8c6 Binary files /dev/null and b/public/img/gear/shoes/27306.png differ diff --git a/public/img/gear/shoes/3000.avif b/public/img/gear/shoes/3000.avif new file mode 100644 index 000000000..6db882013 Binary files /dev/null and b/public/img/gear/shoes/3000.avif differ diff --git a/public/img/gear/shoes/3000.png b/public/img/gear/shoes/3000.png new file mode 100644 index 000000000..d8bbde2d7 Binary files /dev/null and b/public/img/gear/shoes/3000.png differ diff --git a/public/img/gear/shoes/3001.png b/public/img/gear/shoes/3001.png index 5449417ca..b99a9048d 100644 Binary files a/public/img/gear/shoes/3001.png and b/public/img/gear/shoes/3001.png differ diff --git a/public/img/gear/shoes/3004.png b/public/img/gear/shoes/3004.png index 9d977ed63..9973c5903 100644 Binary files a/public/img/gear/shoes/3004.png and b/public/img/gear/shoes/3004.png differ diff --git a/public/img/gear/shoes/3013.png b/public/img/gear/shoes/3013.png index ae4be74dc..6b9430619 100644 Binary files a/public/img/gear/shoes/3013.png and b/public/img/gear/shoes/3013.png differ diff --git a/public/img/gear/shoes/3020.png b/public/img/gear/shoes/3020.png index eae455e67..d639613b3 100644 Binary files a/public/img/gear/shoes/3020.png and b/public/img/gear/shoes/3020.png differ diff --git a/public/img/gear/shoes/3022.png b/public/img/gear/shoes/3022.png index 9edf726aa..6d4265f0d 100644 Binary files a/public/img/gear/shoes/3022.png and b/public/img/gear/shoes/3022.png differ diff --git a/public/img/gear/shoes/3023.png b/public/img/gear/shoes/3023.png index 30c77e0b0..58d64ae12 100644 Binary files a/public/img/gear/shoes/3023.png and b/public/img/gear/shoes/3023.png differ diff --git a/public/img/gear/shoes/3024.png b/public/img/gear/shoes/3024.png index 720f9f047..869dde569 100644 Binary files a/public/img/gear/shoes/3024.png and b/public/img/gear/shoes/3024.png differ diff --git a/public/img/gear/shoes/3025.png b/public/img/gear/shoes/3025.png index c20b06fbb..176890ffd 100644 Binary files a/public/img/gear/shoes/3025.png and b/public/img/gear/shoes/3025.png differ diff --git a/public/img/gear/shoes/3026.avif b/public/img/gear/shoes/3026.avif new file mode 100644 index 000000000..92adf4679 Binary files /dev/null and b/public/img/gear/shoes/3026.avif differ diff --git a/public/img/gear/shoes/3026.png b/public/img/gear/shoes/3026.png new file mode 100644 index 000000000..1248e4e25 Binary files /dev/null and b/public/img/gear/shoes/3026.png differ diff --git a/public/img/gear/shoes/4000.png b/public/img/gear/shoes/4000.png index 0cff12fb3..5beb52e8e 100644 Binary files a/public/img/gear/shoes/4000.png and b/public/img/gear/shoes/4000.png differ diff --git a/public/img/gear/shoes/4001.png b/public/img/gear/shoes/4001.png index 82d95c2c3..9b6f78841 100644 Binary files a/public/img/gear/shoes/4001.png and b/public/img/gear/shoes/4001.png differ diff --git a/public/img/gear/shoes/4007.png b/public/img/gear/shoes/4007.png index 33ae8d465..9c982d1d5 100644 Binary files a/public/img/gear/shoes/4007.png and b/public/img/gear/shoes/4007.png differ diff --git a/public/img/gear/shoes/4008.png b/public/img/gear/shoes/4008.png index 18d8c8d14..4f5288ead 100644 Binary files a/public/img/gear/shoes/4008.png and b/public/img/gear/shoes/4008.png differ diff --git a/public/img/gear/shoes/4009.png b/public/img/gear/shoes/4009.png index 40d6d18e1..4211636c0 100644 Binary files a/public/img/gear/shoes/4009.png and b/public/img/gear/shoes/4009.png differ diff --git a/public/img/gear/shoes/4011.png b/public/img/gear/shoes/4011.png index 2f6b94ddf..d7534b8e7 100644 Binary files a/public/img/gear/shoes/4011.png and b/public/img/gear/shoes/4011.png differ diff --git a/public/img/gear/shoes/4012.png b/public/img/gear/shoes/4012.png index 95de1f213..966f7c9e2 100644 Binary files a/public/img/gear/shoes/4012.png and b/public/img/gear/shoes/4012.png differ diff --git a/public/img/gear/shoes/4014.avif b/public/img/gear/shoes/4014.avif new file mode 100644 index 000000000..72f27cae9 Binary files /dev/null and b/public/img/gear/shoes/4014.avif differ diff --git a/public/img/gear/shoes/4014.png b/public/img/gear/shoes/4014.png new file mode 100644 index 000000000..94d37472b Binary files /dev/null and b/public/img/gear/shoes/4014.png differ diff --git a/public/img/gear/shoes/4015.png b/public/img/gear/shoes/4015.png index 6ce0cdc73..9a9a204af 100644 Binary files a/public/img/gear/shoes/4015.png and b/public/img/gear/shoes/4015.png differ diff --git a/public/img/gear/shoes/4016.png b/public/img/gear/shoes/4016.png index 6f7a1675a..66bb45b64 100644 Binary files a/public/img/gear/shoes/4016.png and b/public/img/gear/shoes/4016.png differ diff --git a/public/img/gear/shoes/4017.png b/public/img/gear/shoes/4017.png index 5a6e42bac..f40f6a435 100644 Binary files a/public/img/gear/shoes/4017.png and b/public/img/gear/shoes/4017.png differ diff --git a/public/img/gear/shoes/4021.png b/public/img/gear/shoes/4021.png index 74038bfc7..9a478f459 100644 Binary files a/public/img/gear/shoes/4021.png and b/public/img/gear/shoes/4021.png differ diff --git a/public/img/gear/shoes/4022.png b/public/img/gear/shoes/4022.png index 8218c8fd7..7041d7e0e 100644 Binary files a/public/img/gear/shoes/4022.png and b/public/img/gear/shoes/4022.png differ diff --git a/public/img/gear/shoes/5000.png b/public/img/gear/shoes/5000.png index 0134524b1..2b1ca539e 100644 Binary files a/public/img/gear/shoes/5000.png and b/public/img/gear/shoes/5000.png differ diff --git a/public/img/gear/shoes/5001.png b/public/img/gear/shoes/5001.png index ff79f87ca..5a555e423 100644 Binary files a/public/img/gear/shoes/5001.png and b/public/img/gear/shoes/5001.png differ diff --git a/public/img/gear/shoes/6000.png b/public/img/gear/shoes/6000.png index 21027c473..eb5a3d13e 100644 Binary files a/public/img/gear/shoes/6000.png and b/public/img/gear/shoes/6000.png differ diff --git a/public/img/gear/shoes/6001.png b/public/img/gear/shoes/6001.png index 0d7474ce4..295901147 100644 Binary files a/public/img/gear/shoes/6001.png and b/public/img/gear/shoes/6001.png differ diff --git a/public/img/gear/shoes/6006.png b/public/img/gear/shoes/6006.png index 7508c8bd8..c29523751 100644 Binary files a/public/img/gear/shoes/6006.png and b/public/img/gear/shoes/6006.png differ diff --git a/public/img/gear/shoes/6007.png b/public/img/gear/shoes/6007.png index 1d7970ed4..2243dc3c8 100644 Binary files a/public/img/gear/shoes/6007.png and b/public/img/gear/shoes/6007.png differ diff --git a/public/img/gear/shoes/6012.png b/public/img/gear/shoes/6012.png index be2ad3be1..d13a6f824 100644 Binary files a/public/img/gear/shoes/6012.png and b/public/img/gear/shoes/6012.png differ diff --git a/public/img/gear/shoes/6020.avif b/public/img/gear/shoes/6020.avif new file mode 100644 index 000000000..ccb568815 Binary files /dev/null and b/public/img/gear/shoes/6020.avif differ diff --git a/public/img/gear/shoes/6020.png b/public/img/gear/shoes/6020.png new file mode 100644 index 000000000..46239f415 Binary files /dev/null and b/public/img/gear/shoes/6020.png differ diff --git a/public/img/gear/shoes/6021.png b/public/img/gear/shoes/6021.png index 228062041..83869b0a9 100644 Binary files a/public/img/gear/shoes/6021.png and b/public/img/gear/shoes/6021.png differ diff --git a/public/img/gear/shoes/6023.avif b/public/img/gear/shoes/6023.avif new file mode 100644 index 000000000..b24f847e2 Binary files /dev/null and b/public/img/gear/shoes/6023.avif differ diff --git a/public/img/gear/shoes/6023.png b/public/img/gear/shoes/6023.png new file mode 100644 index 000000000..5b9e1d8f1 Binary files /dev/null and b/public/img/gear/shoes/6023.png differ diff --git a/public/img/gear/shoes/6025.avif b/public/img/gear/shoes/6025.avif new file mode 100644 index 000000000..981597f9b Binary files /dev/null and b/public/img/gear/shoes/6025.avif differ diff --git a/public/img/gear/shoes/6025.png b/public/img/gear/shoes/6025.png new file mode 100644 index 000000000..100eb56df Binary files /dev/null and b/public/img/gear/shoes/6025.png differ diff --git a/public/img/gear/shoes/7002.png b/public/img/gear/shoes/7002.png index d214a6c7d..62df41ce4 100644 Binary files a/public/img/gear/shoes/7002.png and b/public/img/gear/shoes/7002.png differ diff --git a/public/img/gear/shoes/8010.png b/public/img/gear/shoes/8010.png index fef5a4a74..de92214ed 100644 Binary files a/public/img/gear/shoes/8010.png and b/public/img/gear/shoes/8010.png differ diff --git a/public/img/gear/shoes/8013.png b/public/img/gear/shoes/8013.png index 2d6af67c0..e614bb4e0 100644 Binary files a/public/img/gear/shoes/8013.png and b/public/img/gear/shoes/8013.png differ diff --git a/public/img/gear/shoes/8014.png b/public/img/gear/shoes/8014.png index 061a5613c..ff23a6576 100644 Binary files a/public/img/gear/shoes/8014.png and b/public/img/gear/shoes/8014.png differ diff --git a/public/img/layout/common-preview.png b/public/img/layout/common-preview.png new file mode 100644 index 000000000..fb84770a5 Binary files /dev/null and b/public/img/layout/common-preview.png differ diff --git a/public/img/weapons/0.avif b/public/img/main-weapons/0.avif similarity index 100% rename from public/img/weapons/0.avif rename to public/img/main-weapons/0.avif diff --git a/public/img/weapons/0.png b/public/img/main-weapons/0.png similarity index 100% rename from public/img/weapons/0.png rename to public/img/main-weapons/0.png diff --git a/public/img/weapons/10.avif b/public/img/main-weapons/10.avif similarity index 100% rename from public/img/weapons/10.avif rename to public/img/main-weapons/10.avif diff --git a/public/img/weapons/10.png b/public/img/main-weapons/10.png similarity index 100% rename from public/img/weapons/10.png rename to public/img/main-weapons/10.png diff --git a/public/img/weapons/1000.avif b/public/img/main-weapons/1000.avif similarity index 100% rename from public/img/weapons/1000.avif rename to public/img/main-weapons/1000.avif diff --git a/public/img/weapons/1000.png b/public/img/main-weapons/1000.png similarity index 100% rename from public/img/weapons/1000.png rename to public/img/main-weapons/1000.png diff --git a/public/img/weapons/1010.avif b/public/img/main-weapons/1010.avif similarity index 100% rename from public/img/weapons/1010.avif rename to public/img/main-weapons/1010.avif diff --git a/public/img/weapons/1010.png b/public/img/main-weapons/1010.png similarity index 100% rename from public/img/weapons/1010.png rename to public/img/main-weapons/1010.png diff --git a/public/img/weapons/1020.avif b/public/img/main-weapons/1020.avif similarity index 100% rename from public/img/weapons/1020.avif rename to public/img/main-weapons/1020.avif diff --git a/public/img/weapons/1020.png b/public/img/main-weapons/1020.png similarity index 100% rename from public/img/weapons/1020.png rename to public/img/main-weapons/1020.png diff --git a/public/img/weapons/1030.avif b/public/img/main-weapons/1030.avif similarity index 100% rename from public/img/weapons/1030.avif rename to public/img/main-weapons/1030.avif diff --git a/public/img/weapons/1030.png b/public/img/main-weapons/1030.png similarity index 100% rename from public/img/weapons/1030.png rename to public/img/main-weapons/1030.png diff --git a/public/img/weapons/1100.avif b/public/img/main-weapons/1100.avif similarity index 100% rename from public/img/weapons/1100.avif rename to public/img/main-weapons/1100.avif diff --git a/public/img/weapons/1100.png b/public/img/main-weapons/1100.png similarity index 100% rename from public/img/weapons/1100.png rename to public/img/main-weapons/1100.png diff --git a/public/img/weapons/1110.avif b/public/img/main-weapons/1110.avif similarity index 100% rename from public/img/weapons/1110.avif rename to public/img/main-weapons/1110.avif diff --git a/public/img/weapons/1110.png b/public/img/main-weapons/1110.png similarity index 100% rename from public/img/weapons/1110.png rename to public/img/main-weapons/1110.png diff --git a/public/img/weapons/20.avif b/public/img/main-weapons/20.avif similarity index 100% rename from public/img/weapons/20.avif rename to public/img/main-weapons/20.avif diff --git a/public/img/weapons/20.png b/public/img/main-weapons/20.png similarity index 100% rename from public/img/weapons/20.png rename to public/img/main-weapons/20.png diff --git a/public/img/weapons/200.avif b/public/img/main-weapons/200.avif similarity index 100% rename from public/img/weapons/200.avif rename to public/img/main-weapons/200.avif diff --git a/public/img/weapons/200.png b/public/img/main-weapons/200.png similarity index 100% rename from public/img/weapons/200.png rename to public/img/main-weapons/200.png diff --git a/public/img/weapons/2000.avif b/public/img/main-weapons/2000.avif similarity index 100% rename from public/img/weapons/2000.avif rename to public/img/main-weapons/2000.avif diff --git a/public/img/weapons/2000.png b/public/img/main-weapons/2000.png similarity index 100% rename from public/img/weapons/2000.png rename to public/img/main-weapons/2000.png diff --git a/public/img/weapons/2010.avif b/public/img/main-weapons/2010.avif similarity index 100% rename from public/img/weapons/2010.avif rename to public/img/main-weapons/2010.avif diff --git a/public/img/weapons/2010.png b/public/img/main-weapons/2010.png similarity index 100% rename from public/img/weapons/2010.png rename to public/img/main-weapons/2010.png diff --git a/public/img/weapons/2020.avif b/public/img/main-weapons/2020.avif similarity index 100% rename from public/img/weapons/2020.avif rename to public/img/main-weapons/2020.avif diff --git a/public/img/weapons/2020.png b/public/img/main-weapons/2020.png similarity index 100% rename from public/img/weapons/2020.png rename to public/img/main-weapons/2020.png diff --git a/public/img/weapons/2030.avif b/public/img/main-weapons/2030.avif similarity index 100% rename from public/img/weapons/2030.avif rename to public/img/main-weapons/2030.avif diff --git a/public/img/weapons/2030.png b/public/img/main-weapons/2030.png similarity index 100% rename from public/img/weapons/2030.png rename to public/img/main-weapons/2030.png diff --git a/public/img/weapons/2040.avif b/public/img/main-weapons/2040.avif similarity index 100% rename from public/img/weapons/2040.avif rename to public/img/main-weapons/2040.avif diff --git a/public/img/weapons/2040.png b/public/img/main-weapons/2040.png similarity index 100% rename from public/img/weapons/2040.png rename to public/img/main-weapons/2040.png diff --git a/public/img/weapons/2050.avif b/public/img/main-weapons/2050.avif similarity index 100% rename from public/img/weapons/2050.avif rename to public/img/main-weapons/2050.avif diff --git a/public/img/weapons/2050.png b/public/img/main-weapons/2050.png similarity index 100% rename from public/img/weapons/2050.png rename to public/img/main-weapons/2050.png diff --git a/public/img/weapons/2060.avif b/public/img/main-weapons/2060.avif similarity index 100% rename from public/img/weapons/2060.avif rename to public/img/main-weapons/2060.avif diff --git a/public/img/weapons/2060.png b/public/img/main-weapons/2060.png similarity index 100% rename from public/img/weapons/2060.png rename to public/img/main-weapons/2060.png diff --git a/public/img/weapons/210.avif b/public/img/main-weapons/210.avif similarity index 100% rename from public/img/weapons/210.avif rename to public/img/main-weapons/210.avif diff --git a/public/img/weapons/210.png b/public/img/main-weapons/210.png similarity index 100% rename from public/img/weapons/210.png rename to public/img/main-weapons/210.png diff --git a/public/img/weapons/220.avif b/public/img/main-weapons/220.avif similarity index 100% rename from public/img/weapons/220.avif rename to public/img/main-weapons/220.avif diff --git a/public/img/weapons/220.png b/public/img/main-weapons/220.png similarity index 100% rename from public/img/weapons/220.png rename to public/img/main-weapons/220.png diff --git a/public/img/weapons/230.avif b/public/img/main-weapons/230.avif similarity index 100% rename from public/img/weapons/230.avif rename to public/img/main-weapons/230.avif diff --git a/public/img/weapons/230.png b/public/img/main-weapons/230.png similarity index 100% rename from public/img/weapons/230.png rename to public/img/main-weapons/230.png diff --git a/public/img/weapons/240.avif b/public/img/main-weapons/240.avif similarity index 100% rename from public/img/weapons/240.avif rename to public/img/main-weapons/240.avif diff --git a/public/img/weapons/240.png b/public/img/main-weapons/240.png similarity index 100% rename from public/img/weapons/240.png rename to public/img/main-weapons/240.png diff --git a/public/img/weapons/250.avif b/public/img/main-weapons/250.avif similarity index 100% rename from public/img/weapons/250.avif rename to public/img/main-weapons/250.avif diff --git a/public/img/weapons/250.png b/public/img/main-weapons/250.png similarity index 100% rename from public/img/weapons/250.png rename to public/img/main-weapons/250.png diff --git a/public/img/weapons/30.avif b/public/img/main-weapons/30.avif similarity index 100% rename from public/img/weapons/30.avif rename to public/img/main-weapons/30.avif diff --git a/public/img/weapons/30.png b/public/img/main-weapons/30.png similarity index 100% rename from public/img/weapons/30.png rename to public/img/main-weapons/30.png diff --git a/public/img/weapons/300.avif b/public/img/main-weapons/300.avif similarity index 100% rename from public/img/weapons/300.avif rename to public/img/main-weapons/300.avif diff --git a/public/img/weapons/300.png b/public/img/main-weapons/300.png similarity index 100% rename from public/img/weapons/300.png rename to public/img/main-weapons/300.png diff --git a/public/img/weapons/3000.avif b/public/img/main-weapons/3000.avif similarity index 100% rename from public/img/weapons/3000.avif rename to public/img/main-weapons/3000.avif diff --git a/public/img/weapons/3000.png b/public/img/main-weapons/3000.png similarity index 100% rename from public/img/weapons/3000.png rename to public/img/main-weapons/3000.png diff --git a/public/img/weapons/3010.avif b/public/img/main-weapons/3010.avif similarity index 100% rename from public/img/weapons/3010.avif rename to public/img/main-weapons/3010.avif diff --git a/public/img/weapons/3010.png b/public/img/main-weapons/3010.png similarity index 100% rename from public/img/weapons/3010.png rename to public/img/main-weapons/3010.png diff --git a/public/img/weapons/3020.avif b/public/img/main-weapons/3020.avif similarity index 100% rename from public/img/weapons/3020.avif rename to public/img/main-weapons/3020.avif diff --git a/public/img/weapons/3020.png b/public/img/main-weapons/3020.png similarity index 100% rename from public/img/weapons/3020.png rename to public/img/main-weapons/3020.png diff --git a/public/img/weapons/3030.avif b/public/img/main-weapons/3030.avif similarity index 100% rename from public/img/weapons/3030.avif rename to public/img/main-weapons/3030.avif diff --git a/public/img/weapons/3030.png b/public/img/main-weapons/3030.png similarity index 100% rename from public/img/weapons/3030.png rename to public/img/main-weapons/3030.png diff --git a/public/img/weapons/3040.avif b/public/img/main-weapons/3040.avif similarity index 100% rename from public/img/weapons/3040.avif rename to public/img/main-weapons/3040.avif diff --git a/public/img/weapons/3040.png b/public/img/main-weapons/3040.png similarity index 100% rename from public/img/weapons/3040.png rename to public/img/main-weapons/3040.png diff --git a/public/img/weapons/310.avif b/public/img/main-weapons/310.avif similarity index 100% rename from public/img/weapons/310.avif rename to public/img/main-weapons/310.avif diff --git a/public/img/weapons/310.png b/public/img/main-weapons/310.png similarity index 100% rename from public/img/weapons/310.png rename to public/img/main-weapons/310.png diff --git a/public/img/weapons/40.avif b/public/img/main-weapons/40.avif similarity index 100% rename from public/img/weapons/40.avif rename to public/img/main-weapons/40.avif diff --git a/public/img/weapons/40.png b/public/img/main-weapons/40.png similarity index 100% rename from public/img/weapons/40.png rename to public/img/main-weapons/40.png diff --git a/public/img/weapons/400.avif b/public/img/main-weapons/400.avif similarity index 100% rename from public/img/weapons/400.avif rename to public/img/main-weapons/400.avif diff --git a/public/img/weapons/400.png b/public/img/main-weapons/400.png similarity index 100% rename from public/img/weapons/400.png rename to public/img/main-weapons/400.png diff --git a/public/img/weapons/4000.avif b/public/img/main-weapons/4000.avif similarity index 100% rename from public/img/weapons/4000.avif rename to public/img/main-weapons/4000.avif diff --git a/public/img/weapons/4000.png b/public/img/main-weapons/4000.png similarity index 100% rename from public/img/weapons/4000.png rename to public/img/main-weapons/4000.png diff --git a/public/img/weapons/4010.avif b/public/img/main-weapons/4010.avif similarity index 100% rename from public/img/weapons/4010.avif rename to public/img/main-weapons/4010.avif diff --git a/public/img/weapons/4010.png b/public/img/main-weapons/4010.png similarity index 100% rename from public/img/weapons/4010.png rename to public/img/main-weapons/4010.png diff --git a/public/img/weapons/4020.avif b/public/img/main-weapons/4020.avif similarity index 100% rename from public/img/weapons/4020.avif rename to public/img/main-weapons/4020.avif diff --git a/public/img/weapons/4020.png b/public/img/main-weapons/4020.png similarity index 100% rename from public/img/weapons/4020.png rename to public/img/main-weapons/4020.png diff --git a/public/img/weapons/4030.avif b/public/img/main-weapons/4030.avif similarity index 100% rename from public/img/weapons/4030.avif rename to public/img/main-weapons/4030.avif diff --git a/public/img/weapons/4030.png b/public/img/main-weapons/4030.png similarity index 100% rename from public/img/weapons/4030.png rename to public/img/main-weapons/4030.png diff --git a/public/img/weapons/4040.avif b/public/img/main-weapons/4040.avif similarity index 100% rename from public/img/weapons/4040.avif rename to public/img/main-weapons/4040.avif diff --git a/public/img/weapons/4040.png b/public/img/main-weapons/4040.png similarity index 100% rename from public/img/weapons/4040.png rename to public/img/main-weapons/4040.png diff --git a/public/img/main-weapons/45.avif b/public/img/main-weapons/45.avif new file mode 100644 index 000000000..5b6bafbcf Binary files /dev/null and b/public/img/main-weapons/45.avif differ diff --git a/public/img/main-weapons/45.png b/public/img/main-weapons/45.png new file mode 100644 index 000000000..766f546ae Binary files /dev/null and b/public/img/main-weapons/45.png differ diff --git a/public/img/weapons/50.avif b/public/img/main-weapons/50.avif similarity index 100% rename from public/img/weapons/50.avif rename to public/img/main-weapons/50.avif diff --git a/public/img/weapons/50.png b/public/img/main-weapons/50.png similarity index 100% rename from public/img/weapons/50.png rename to public/img/main-weapons/50.png diff --git a/public/img/weapons/5000.avif b/public/img/main-weapons/5000.avif similarity index 100% rename from public/img/weapons/5000.avif rename to public/img/main-weapons/5000.avif diff --git a/public/img/weapons/5000.png b/public/img/main-weapons/5000.png similarity index 100% rename from public/img/weapons/5000.png rename to public/img/main-weapons/5000.png diff --git a/public/img/weapons/5010.avif b/public/img/main-weapons/5010.avif similarity index 100% rename from public/img/weapons/5010.avif rename to public/img/main-weapons/5010.avif diff --git a/public/img/weapons/5010.png b/public/img/main-weapons/5010.png similarity index 100% rename from public/img/weapons/5010.png rename to public/img/main-weapons/5010.png diff --git a/public/img/weapons/5020.avif b/public/img/main-weapons/5020.avif similarity index 100% rename from public/img/weapons/5020.avif rename to public/img/main-weapons/5020.avif diff --git a/public/img/weapons/5020.png b/public/img/main-weapons/5020.png similarity index 100% rename from public/img/weapons/5020.png rename to public/img/main-weapons/5020.png diff --git a/public/img/weapons/5030.avif b/public/img/main-weapons/5030.avif similarity index 100% rename from public/img/weapons/5030.avif rename to public/img/main-weapons/5030.avif diff --git a/public/img/weapons/5030.png b/public/img/main-weapons/5030.png similarity index 100% rename from public/img/weapons/5030.png rename to public/img/main-weapons/5030.png diff --git a/public/img/weapons/5040.avif b/public/img/main-weapons/5040.avif similarity index 100% rename from public/img/weapons/5040.avif rename to public/img/main-weapons/5040.avif diff --git a/public/img/weapons/5040.png b/public/img/main-weapons/5040.png similarity index 100% rename from public/img/weapons/5040.png rename to public/img/main-weapons/5040.png diff --git a/public/img/weapons/60.avif b/public/img/main-weapons/60.avif similarity index 100% rename from public/img/weapons/60.avif rename to public/img/main-weapons/60.avif diff --git a/public/img/weapons/60.png b/public/img/main-weapons/60.png similarity index 100% rename from public/img/weapons/60.png rename to public/img/main-weapons/60.png diff --git a/public/img/weapons/6000.avif b/public/img/main-weapons/6000.avif similarity index 100% rename from public/img/weapons/6000.avif rename to public/img/main-weapons/6000.avif diff --git a/public/img/weapons/6000.png b/public/img/main-weapons/6000.png similarity index 100% rename from public/img/weapons/6000.png rename to public/img/main-weapons/6000.png diff --git a/public/img/weapons/6010.avif b/public/img/main-weapons/6010.avif similarity index 100% rename from public/img/weapons/6010.avif rename to public/img/main-weapons/6010.avif diff --git a/public/img/weapons/6010.png b/public/img/main-weapons/6010.png similarity index 100% rename from public/img/weapons/6010.png rename to public/img/main-weapons/6010.png diff --git a/public/img/weapons/6020.avif b/public/img/main-weapons/6020.avif similarity index 100% rename from public/img/weapons/6020.avif rename to public/img/main-weapons/6020.avif diff --git a/public/img/weapons/6020.png b/public/img/main-weapons/6020.png similarity index 100% rename from public/img/weapons/6020.png rename to public/img/main-weapons/6020.png diff --git a/public/img/weapons/70.avif b/public/img/main-weapons/70.avif similarity index 100% rename from public/img/weapons/70.avif rename to public/img/main-weapons/70.avif diff --git a/public/img/weapons/70.png b/public/img/main-weapons/70.png similarity index 100% rename from public/img/weapons/70.png rename to public/img/main-weapons/70.png diff --git a/public/img/weapons/7010.avif b/public/img/main-weapons/7010.avif similarity index 100% rename from public/img/weapons/7010.avif rename to public/img/main-weapons/7010.avif diff --git a/public/img/weapons/7010.png b/public/img/main-weapons/7010.png similarity index 100% rename from public/img/weapons/7010.png rename to public/img/main-weapons/7010.png diff --git a/public/img/main-weapons/7020.avif b/public/img/main-weapons/7020.avif new file mode 100644 index 000000000..1f2f7a41a Binary files /dev/null and b/public/img/main-weapons/7020.avif differ diff --git a/public/img/main-weapons/7020.png b/public/img/main-weapons/7020.png new file mode 100644 index 000000000..783814f48 Binary files /dev/null and b/public/img/main-weapons/7020.png differ diff --git a/public/img/weapons/80.avif b/public/img/main-weapons/80.avif similarity index 100% rename from public/img/weapons/80.avif rename to public/img/main-weapons/80.avif diff --git a/public/img/weapons/80.png b/public/img/main-weapons/80.png similarity index 100% rename from public/img/weapons/80.png rename to public/img/main-weapons/80.png diff --git a/public/img/weapons/8000.avif b/public/img/main-weapons/8000.avif similarity index 100% rename from public/img/weapons/8000.avif rename to public/img/main-weapons/8000.avif diff --git a/public/img/weapons/8000.png b/public/img/main-weapons/8000.png similarity index 100% rename from public/img/weapons/8000.png rename to public/img/main-weapons/8000.png diff --git a/public/img/weapons/8010.avif b/public/img/main-weapons/8010.avif similarity index 100% rename from public/img/weapons/8010.avif rename to public/img/main-weapons/8010.avif diff --git a/public/img/weapons/8010.png b/public/img/main-weapons/8010.png similarity index 100% rename from public/img/weapons/8010.png rename to public/img/main-weapons/8010.png diff --git a/public/img/weapons/90.avif b/public/img/main-weapons/90.avif similarity index 100% rename from public/img/weapons/90.avif rename to public/img/main-weapons/90.avif diff --git a/public/img/weapons/90.png b/public/img/main-weapons/90.png similarity index 100% rename from public/img/weapons/90.png rename to public/img/main-weapons/90.png diff --git a/public/img/special-weapons/1.avif b/public/img/special-weapons/1.avif new file mode 100644 index 000000000..649cb42f2 Binary files /dev/null and b/public/img/special-weapons/1.avif differ diff --git a/public/img/special-weapons/1.png b/public/img/special-weapons/1.png new file mode 100644 index 000000000..0e78a3f1e Binary files /dev/null and b/public/img/special-weapons/1.png differ diff --git a/public/img/special-weapons/10.avif b/public/img/special-weapons/10.avif new file mode 100644 index 000000000..1b78f4e1e Binary files /dev/null and b/public/img/special-weapons/10.avif differ diff --git a/public/img/special-weapons/10.png b/public/img/special-weapons/10.png new file mode 100644 index 000000000..2d3abaf86 Binary files /dev/null and b/public/img/special-weapons/10.png differ diff --git a/public/img/special-weapons/11.avif b/public/img/special-weapons/11.avif new file mode 100644 index 000000000..9461ead8d Binary files /dev/null and b/public/img/special-weapons/11.avif differ diff --git a/public/img/special-weapons/11.png b/public/img/special-weapons/11.png new file mode 100644 index 000000000..c81bc54c1 Binary files /dev/null and b/public/img/special-weapons/11.png differ diff --git a/public/img/special-weapons/12.avif b/public/img/special-weapons/12.avif new file mode 100644 index 000000000..9e96a542b Binary files /dev/null and b/public/img/special-weapons/12.avif differ diff --git a/public/img/special-weapons/12.png b/public/img/special-weapons/12.png new file mode 100644 index 000000000..a6a8da42a Binary files /dev/null and b/public/img/special-weapons/12.png differ diff --git a/public/img/special-weapons/13.avif b/public/img/special-weapons/13.avif new file mode 100644 index 000000000..9834d500a Binary files /dev/null and b/public/img/special-weapons/13.avif differ diff --git a/public/img/special-weapons/13.png b/public/img/special-weapons/13.png new file mode 100644 index 000000000..736b4e479 Binary files /dev/null and b/public/img/special-weapons/13.png differ diff --git a/public/img/special-weapons/14.avif b/public/img/special-weapons/14.avif new file mode 100644 index 000000000..437991fca Binary files /dev/null and b/public/img/special-weapons/14.avif differ diff --git a/public/img/special-weapons/14.png b/public/img/special-weapons/14.png new file mode 100644 index 000000000..b4b3066c8 Binary files /dev/null and b/public/img/special-weapons/14.png differ diff --git a/public/img/special-weapons/15.avif b/public/img/special-weapons/15.avif new file mode 100644 index 000000000..6742cecc8 Binary files /dev/null and b/public/img/special-weapons/15.avif differ diff --git a/public/img/special-weapons/15.png b/public/img/special-weapons/15.png new file mode 100644 index 000000000..137d3f836 Binary files /dev/null and b/public/img/special-weapons/15.png differ diff --git a/public/img/special-weapons/2.avif b/public/img/special-weapons/2.avif new file mode 100644 index 000000000..a7209b607 Binary files /dev/null and b/public/img/special-weapons/2.avif differ diff --git a/public/img/special-weapons/2.png b/public/img/special-weapons/2.png new file mode 100644 index 000000000..05b558db5 Binary files /dev/null and b/public/img/special-weapons/2.png differ diff --git a/public/img/special-weapons/20.avif b/public/img/special-weapons/20.avif new file mode 100644 index 000000000..6742cecc8 Binary files /dev/null and b/public/img/special-weapons/20.avif differ diff --git a/public/img/special-weapons/20.png b/public/img/special-weapons/20.png new file mode 100644 index 000000000..137d3f836 Binary files /dev/null and b/public/img/special-weapons/20.png differ diff --git a/public/img/special-weapons/3.avif b/public/img/special-weapons/3.avif new file mode 100644 index 000000000..f354f4be9 Binary files /dev/null and b/public/img/special-weapons/3.avif differ diff --git a/public/img/special-weapons/3.png b/public/img/special-weapons/3.png new file mode 100644 index 000000000..f298203a0 Binary files /dev/null and b/public/img/special-weapons/3.png differ diff --git a/public/img/special-weapons/4.avif b/public/img/special-weapons/4.avif new file mode 100644 index 000000000..63ac6aa4f Binary files /dev/null and b/public/img/special-weapons/4.avif differ diff --git a/public/img/special-weapons/4.png b/public/img/special-weapons/4.png new file mode 100644 index 000000000..75ca9ac73 Binary files /dev/null and b/public/img/special-weapons/4.png differ diff --git a/public/img/special-weapons/5.avif b/public/img/special-weapons/5.avif new file mode 100644 index 000000000..55520fd5d Binary files /dev/null and b/public/img/special-weapons/5.avif differ diff --git a/public/img/special-weapons/5.png b/public/img/special-weapons/5.png new file mode 100644 index 000000000..56e8127c7 Binary files /dev/null and b/public/img/special-weapons/5.png differ diff --git a/public/img/special-weapons/6.avif b/public/img/special-weapons/6.avif new file mode 100644 index 000000000..de6bdc550 Binary files /dev/null and b/public/img/special-weapons/6.avif differ diff --git a/public/img/special-weapons/6.png b/public/img/special-weapons/6.png new file mode 100644 index 000000000..8629fcdbb Binary files /dev/null and b/public/img/special-weapons/6.png differ diff --git a/public/img/special-weapons/7.avif b/public/img/special-weapons/7.avif new file mode 100644 index 000000000..8e0658df3 Binary files /dev/null and b/public/img/special-weapons/7.avif differ diff --git a/public/img/special-weapons/7.png b/public/img/special-weapons/7.png new file mode 100644 index 000000000..032687faa Binary files /dev/null and b/public/img/special-weapons/7.png differ diff --git a/public/img/special-weapons/8.avif b/public/img/special-weapons/8.avif new file mode 100644 index 000000000..a155b6101 Binary files /dev/null and b/public/img/special-weapons/8.avif differ diff --git a/public/img/special-weapons/8.png b/public/img/special-weapons/8.png new file mode 100644 index 000000000..5fa709257 Binary files /dev/null and b/public/img/special-weapons/8.png differ diff --git a/public/img/special-weapons/9.avif b/public/img/special-weapons/9.avif new file mode 100644 index 000000000..f873cfa94 Binary files /dev/null and b/public/img/special-weapons/9.avif differ diff --git a/public/img/special-weapons/9.png b/public/img/special-weapons/9.png new file mode 100644 index 000000000..09863e3e2 Binary files /dev/null and b/public/img/special-weapons/9.png differ diff --git a/public/img/sub-weapons/0.avif b/public/img/sub-weapons/0.avif new file mode 100644 index 000000000..7545674aa Binary files /dev/null and b/public/img/sub-weapons/0.avif differ diff --git a/public/img/sub-weapons/0.png b/public/img/sub-weapons/0.png new file mode 100644 index 000000000..b85c642b4 Binary files /dev/null and b/public/img/sub-weapons/0.png differ diff --git a/public/img/sub-weapons/1.avif b/public/img/sub-weapons/1.avif new file mode 100644 index 000000000..3b7177cf2 Binary files /dev/null and b/public/img/sub-weapons/1.avif differ diff --git a/public/img/sub-weapons/1.png b/public/img/sub-weapons/1.png new file mode 100644 index 000000000..d84ab3dd7 Binary files /dev/null and b/public/img/sub-weapons/1.png differ diff --git a/public/img/sub-weapons/10.avif b/public/img/sub-weapons/10.avif new file mode 100644 index 000000000..57e678add Binary files /dev/null and b/public/img/sub-weapons/10.avif differ diff --git a/public/img/sub-weapons/10.png b/public/img/sub-weapons/10.png new file mode 100644 index 000000000..c132f3e8d Binary files /dev/null and b/public/img/sub-weapons/10.png differ diff --git a/public/img/sub-weapons/11.avif b/public/img/sub-weapons/11.avif new file mode 100644 index 000000000..11f97a8f2 Binary files /dev/null and b/public/img/sub-weapons/11.avif differ diff --git a/public/img/sub-weapons/11.png b/public/img/sub-weapons/11.png new file mode 100644 index 000000000..acd9b7db0 Binary files /dev/null and b/public/img/sub-weapons/11.png differ diff --git a/public/img/sub-weapons/12.avif b/public/img/sub-weapons/12.avif new file mode 100644 index 000000000..b37c1e35a Binary files /dev/null and b/public/img/sub-weapons/12.avif differ diff --git a/public/img/sub-weapons/12.png b/public/img/sub-weapons/12.png new file mode 100644 index 000000000..346a33aff Binary files /dev/null and b/public/img/sub-weapons/12.png differ diff --git a/public/img/sub-weapons/13.avif b/public/img/sub-weapons/13.avif new file mode 100644 index 000000000..b518cc824 Binary files /dev/null and b/public/img/sub-weapons/13.avif differ diff --git a/public/img/sub-weapons/13.png b/public/img/sub-weapons/13.png new file mode 100644 index 000000000..0f5e2024d Binary files /dev/null and b/public/img/sub-weapons/13.png differ diff --git a/public/img/sub-weapons/2.avif b/public/img/sub-weapons/2.avif new file mode 100644 index 000000000..e2c05aca8 Binary files /dev/null and b/public/img/sub-weapons/2.avif differ diff --git a/public/img/sub-weapons/2.png b/public/img/sub-weapons/2.png new file mode 100644 index 000000000..52ad805d0 Binary files /dev/null and b/public/img/sub-weapons/2.png differ diff --git a/public/img/sub-weapons/3.avif b/public/img/sub-weapons/3.avif new file mode 100644 index 000000000..7a44ef857 Binary files /dev/null and b/public/img/sub-weapons/3.avif differ diff --git a/public/img/sub-weapons/3.png b/public/img/sub-weapons/3.png new file mode 100644 index 000000000..98d9caecf Binary files /dev/null and b/public/img/sub-weapons/3.png differ diff --git a/public/img/sub-weapons/4.avif b/public/img/sub-weapons/4.avif new file mode 100644 index 000000000..48580be05 Binary files /dev/null and b/public/img/sub-weapons/4.avif differ diff --git a/public/img/sub-weapons/4.png b/public/img/sub-weapons/4.png new file mode 100644 index 000000000..30c4da130 Binary files /dev/null and b/public/img/sub-weapons/4.png differ diff --git a/public/img/sub-weapons/5.avif b/public/img/sub-weapons/5.avif new file mode 100644 index 000000000..56f80018e Binary files /dev/null and b/public/img/sub-weapons/5.avif differ diff --git a/public/img/sub-weapons/5.png b/public/img/sub-weapons/5.png new file mode 100644 index 000000000..7ca50c569 Binary files /dev/null and b/public/img/sub-weapons/5.png differ diff --git a/public/img/sub-weapons/6.avif b/public/img/sub-weapons/6.avif new file mode 100644 index 000000000..19f774eca Binary files /dev/null and b/public/img/sub-weapons/6.avif differ diff --git a/public/img/sub-weapons/6.png b/public/img/sub-weapons/6.png new file mode 100644 index 000000000..70611fbc9 Binary files /dev/null and b/public/img/sub-weapons/6.png differ diff --git a/public/img/sub-weapons/7.avif b/public/img/sub-weapons/7.avif new file mode 100644 index 000000000..ed25ae9a3 Binary files /dev/null and b/public/img/sub-weapons/7.avif differ diff --git a/public/img/sub-weapons/7.png b/public/img/sub-weapons/7.png new file mode 100644 index 000000000..40aad0a23 Binary files /dev/null and b/public/img/sub-weapons/7.png differ diff --git a/public/img/sub-weapons/8.avif b/public/img/sub-weapons/8.avif new file mode 100644 index 000000000..ec47c3a94 Binary files /dev/null and b/public/img/sub-weapons/8.avif differ diff --git a/public/img/sub-weapons/8.png b/public/img/sub-weapons/8.png new file mode 100644 index 000000000..ba4863264 Binary files /dev/null and b/public/img/sub-weapons/8.png differ diff --git a/public/img/sub-weapons/9.avif b/public/img/sub-weapons/9.avif new file mode 100644 index 000000000..82d41bbb4 Binary files /dev/null and b/public/img/sub-weapons/9.avif differ diff --git a/public/img/sub-weapons/9.png b/public/img/sub-weapons/9.png new file mode 100644 index 000000000..282a1069b Binary files /dev/null and b/public/img/sub-weapons/9.png differ diff --git a/public/locales/da/badges.json b/public/locales/da/badges.json new file mode 100644 index 000000000..a5835ece8 --- /dev/null +++ b/public/locales/da/badges.json @@ -0,0 +1,9 @@ +{ + "patreon": "Støtter af sendou.ink på Patreon", + "patreon+": "+Støtter af sendou.ink på Patreon", + "tournament_one": "Tildeldt for at vinde {{tournament}}", + "tournament_other": "Tildeldt for at vinde {{tournament}} (×{{count}})", + "forYourEvent": "Mærke til dit arrangement?", + "madeBy": "Mærker er lavet af <2>borzoic", + "managedBy": "Styres af {{users}}" +} diff --git a/public/locales/da/builds.json b/public/locales/da/builds.json new file mode 100644 index 000000000..67c7e7986 --- /dev/null +++ b/public/locales/da/builds.json @@ -0,0 +1,15 @@ +{ + "addBuild": "Lav et udrustningssæt", + "noBuilds": "Her er ingen sæt. Lav dit første sæt!", + "buildCard.info": "Info", + "buildCard.edit": "Rediger", + + "forms.title": "Titel", + "forms.modes": "spiltilstand", + "forms.weapons": "Våben", + "forms.gear.HEAD": "Udstyr (hovedbeklædning)", + "forms.gear.CLOTHES": "Udstyr (tøj)", + "forms.gear.SHOES": "Udstyr (sko)", + + "deleteConfirm": "Vil du slette sættet '{{title}}'?" +} diff --git a/public/locales/da/calendar.json b/public/locales/da/calendar.json new file mode 100644 index 000000000..8c127e55b --- /dev/null +++ b/public/locales/da/calendar.json @@ -0,0 +1,53 @@ +{ + "inYourTimeZone": "Klokkeslæt vises i din lokale tidszone:", + "addNew": "Tilføj ny", + "noEvents": "Der er ingen begivendeheder i den valgte uge", + "reportResults": "Du kan rapportere resultaterne:", + "day": "Dag {{number}}", + "actions.reportWinners": "Vis vinderne", + "participatedCount": "{{count}} hold deltog", + "members": "Medlemmer", + "results": "Resultater", + + "forms.dates": "Datoer", + "forms.bracketUrl": "Turneringsplans-URL", + "forms.discordInvite": "Discordserver-invitations-URL", + "forms.tags": "Tags", + "forms.tags.placeholder": "Vælg et tag", + "forms.tags.info": "\"Præmiemærker\" tag tilføjes automatisk, hvis den er anvendelig", + "forms.badges": "Præmiemærker", + "forms.badges.placeholder": "Vælg et premiemærke", + + "forms.participantCount": "Antal deltagere", + "forms.reportResultsHeader": "Viser resultater for {{eventName}}", + "forms.reportResultsInfo": "Du vælger hvor mange resultater der skal vises. Det kan være det vindende hold eller top 3.", + "forms.team.add": "Tilføj hold", + "forms.team.remove": "Fjern hold", + "forms.team.name": "Holdnavn", + "forms.team.placing": "Placerer", + + "forms.team.player.header": "Spiller {{number}}", + "forms.team.player.add": "Tilføj spiller", + "forms.team.player.remove": "Fjern spiller", + "forms.team.player.addAsUser": "Tilføj som bruger (anbefales)", + "forms.team.player.addAsText": "Tilføj som tekst", + + "forms.errors.uniqueTeamName": "Alle hold skal have et unikt navn.", + "forms.errors.duplicatePlayer": "Man kan ikke have den samme spiller på samme hold 2 gange.", + "forms.errors.emptyTeam": "Alle hold skal have mindst en spiller.", + + "week.this": "Denne", + "week.next": "Næste", + "week.last": "Sidste", + "week.week": "Uge", + + "tag.desc.BADGE": "Vinderne af denne begivenhed får et sendou.ink-mærke.", + "tag.desc.SPECIAL": "Regelsættet afviger fra standardreglerne.", + "tag.desc.ART": "Man kan vinde kunst ved at deltage i denne turnering.", + "tag.desc.MONEY": "Man kan vinde penge ved at deltage i denne turnering", + "tag.desc.REGION": "Kun deltagere fra bestemte regioner kan deltage i denne turnering.", + "tag.desc.LOW": "Deltagelse i denne turnering kræver, at deltagerne har de nødvendige kvalifikationer.", + "tag.desc.COUNT": "Der er et loft over antalet af hold, der kan registrere sig til denne begivenhed.", + "tag.desc.LAN": "Denne begivenhed spilles på en fysisk lokation.", + "tag.desc.QUALIFIER": "Dette er en kvalifikationsturnering." +} diff --git a/public/locales/da/common.json b/public/locales/da/common.json new file mode 100644 index 000000000..c497d110b --- /dev/null +++ b/public/locales/da/common.json @@ -0,0 +1,43 @@ +{ + "pages.admin": "Administratorer", + "pages.badges": "Mærker", + "pages.plus": "Plus Server", + "pages.contributors": "Bidragydere", + "pages.calendar": "Kalender", + "pages.faq": "FAQ", + "pages.builds": "Udrustningssæt", + + "header.profile": "Profil", + "header.logout": "Log ud", + "header.login": "Log ind", + + "footer.github.subtitle": "Kildekode", + "footer.twitter.subtitle": "Opdateringer", + "footer.discord.subtitle": "Hjælp og feedback", + "footer.patreon.subtitle": "Støt hjemmesiden", + "footer.thanks": "Tak til vores patrons for støtten", + + "actions.save": "Gem", + "actions.saving": "Gemmer...", + "actions.submit": "Fremlæg", + "actions.edit": "Rediger", + "actions.add": "Tilføj", + "actions.remove": "Fjern", + "actions.delete": "Slet", + + "results": "Resultater", + + "forms.name": "Navn", + "forms.description": "Beskrivelse", + "forms.errors.title": "Følgende fejl skal rettes", + + "tag.name.BADGE": "Premiemærker", + "tag.name.SPECIAL": "Særregler", + "tag.name.ART": "Kunstpræmier", + "tag.name.MONEY": "Pengepræmier", + "tag.name.REGION": "Regional turnering", + "tag.name.LOW": "Kvalifikationsloft", + "tag.name.COUNT": "Tilmeldingsloft", + "tag.name.LAN": "LAN", + "tag.name.QUALIFIER": "Kvalifikationsturnering" +} diff --git a/public/locales/da/contributions.json b/public/locales/da/contributions.json new file mode 100644 index 000000000..5edefb2c8 --- /dev/null +++ b/public/locales/da/contributions.json @@ -0,0 +1,7 @@ +{ + "project": "Sendou.ink er et projekt af <2>Sendou med hjælp fra bidragsydere:", + "code": "Mange har bidraget til koden", + "lean": "Hjalp med at fremvise Splatoons indre og skabte Lanista-botten", + "borzoic": "lavede mærker, ikoner and forsidekunst", + "uberu": "Tegnede mini-Judd mens han holder et hjerte-emoji" +} diff --git a/public/locales/da/faq.json b/public/locales/da/faq.json new file mode 100644 index 000000000..7519c9602 --- /dev/null +++ b/public/locales/da/faq.json @@ -0,0 +1,9 @@ +{ + "q1": "Hvad er Plus Serveren?", + "a1": "Plus-serveren er en Discord-server for vestlige spillere, der spiller på højt niveau, så de kan lede efter folk at spille med og imod. Den blev grundlagt i september 2017. Den er opdelt ind i 3 niveauer, hvor +1 er det højeste. Du får adgang til serveren, når du er blevet indstillet af et servermedlem og godkendt af det månedlige valg. \n\nGennem valget for du en procentscore baseret på dit valgresultat. Hvis du får en score på 0% har alle vælgere nedstemt dig og det omvendte gælder ved en score på 100%. Du skal have en score på 50% eller højere for at bestå valget. Hvis et medlem får score på mindre end 50%, vil de blive nedgraderet til et lavere niveau. Hvis medlemmet er på niveau 3+, når dette sker, vil medlemmet blive smidt ud af serveren.", + "q2": "Hvordan får jeg et præmiemærke til min begivenhed?", + "a2": "Du afgiver bestillingen af mærket til borzoic#1991. Prisen er 10-30€ afhængig af detaljegraden af mærket. Derefter skal du kontakte Sendou for at få den tilføjet til hjemmesiden.\n\nEnhver turnering kan have et mærke som en præmie. Hvis du ønsker at tildele mærker for andre præstationer, så anbefales det, at du først kontakter Sendou og fortæller om din ide.", + + "q3": "Hvordan opdaterer jeg min avatar eller brugernavn?", + "a3": "Ændringer af brugernavn eller avatar på Discord bliver ikke synkroniseret til Sendou.ink med det samme. For at synkroniserer ændringerne med det samme har du 2 muligheder:\n\n1) Hvis du er medlem af hjemmesidens Discord-server eller Plus-serveren, så kan du blot vente, da der kører en synkronisering 1 gang om dagen, der håndterer ændringer af din Discord-profil.\n\n2) Du kan også logge af og på hjemmesiden, så sker synkroniseringen med det samme." +} diff --git a/public/locales/da/front.json b/public/locales/da/front.json new file mode 100644 index 000000000..41662ac39 --- /dev/null +++ b/public/locales/da/front.json @@ -0,0 +1,10 @@ +{ + "websiteSubtitle": "Konkurrencepræget Splatoon-hub", + "calendarGoTo": "Se alle tidligere og kommende begivenheder på kalender-siden", + "moreFeatures": "Flere funktioner", + "plus.description": "Se plus-serverens valghistorik med mere", + "badges.description": "Liste af alle de premiemærker til din profil, som du kan gøre dig fortjent til", + "recentWinners": "Se de seneste vindere", + "upcomingEvents": "Kommende begivenheder", + "articleBy": "Af {{author}}" +} diff --git a/public/locales/da/gear.json b/public/locales/da/gear.json new file mode 100644 index 000000000..2437b7a51 --- /dev/null +++ b/public/locales/da/gear.json @@ -0,0 +1,178 @@ +{ + "H_1": "White Headband", + "H_1000": "Urchins Cap", + "S_1000": "Blue Lo-Tops", + "C_1001": "Black Squideye", + "H_1002": "Takoroka Mesh", + "H_1003": "Streetstyle Cap", + "C_1004": "Rockenberg White", + "H_1005": "Squidvader Cap", + "C_1005": "Rockenberg Black", + "C_1006": "Black Tee", + "S_1008": "White 3-Straps", + "S_1009": "Red 3-Straps", + "H_1012": "Cycling Cap", + "C_1013": "Red Vector Tee", + "C_1014": "Gray Vector Tee", + "C_1015": "Blue Peaks Tee", + "C_1016": "Ivory Peaks Tee", + "C_1018": "Pirate-Stripe Tee", + "C_1019": "Sailor-Stripe Tee", + "H_1020": "Hickory Work Cap", + "C_1020": "White 8-Bit FishFry", + "H_1021": "Woolly Urchins Classic", + "C_1021": "Black 8-Bit FishFry", + "S_1021": "Wasabi Tabi", + "S_1022": "Suede Basics", + "S_1024": "Suede Bosses", + "H_1028": "Ink-Black Flap Cap", + "C_1035": "White V-Neck Tee", + "H_1036": "Wharfside Cap", + "C_1062": "Tri-Shred Tee", + "C_1066": "Annaki Choker Tee", + "C_1069": "Blue Retro Tee", + "C_1070": "Tan Retro Tee", + "C_1071": "Barazushi Wrap", + "C_1072": "Barazushi Rice Tee", + "C_1073": "Barazushi Black Tee", + "C_1074": "Barazushi Sakura Tee", + "C_1075": "Octosquid Tandem Tee", + "C_1076": "Tri-Squid Tee", + "C_1077": "Tri-Octo Tee", + "C_1082": "Pineapple Ringer", + "C_1083": "Apple Ringer", + "C_1084": "Vaporwave Tee", + "C_1085": "Duskwave Tee", + "C_1088": "Eelzebub Tee", + "C_1091": "Berry BlobMob Tee", + "S_2000": "Red Hi-Horses", + "S_2001": "Zombie Hi-Horses", + "C_2004": "Zekko Baseball LS", + "S_2004": "Hunter Hi-Tops", + "S_2005": "Red Hi-Tops", + "H_2008": "Knitted Hat", + "S_2016": "Sunset Orca Hi-Tops", + "S_2017": "Red & Black Squidkid IV", + "S_2018": "Blue & Black Squidkid IV", + "S_2042": "Force ReBoots", + "S_2043": "Tenya OctoReds", + "S_2045": "Pearl 01STERs", + "C_3000": "White Layered LS", + "H_3001": "Splash Goggles", + "C_3001": "Yellow Layered LS", + "S_3001": "Orange Arrows", + "H_3003": "Tinted Shades", + "S_3004": "Cyan Trainers", + "C_3006": "Choco Layered LS", + "H_3008": "18K Aviators", + "C_3008": "Layered Vector LS", + "H_3009": "Full-Moon Glasses", + "C_3009": "Green Tee", + "H_3011": "Half-Rim Glasses", + "H_3012": "Double Egg Shades", + "S_3013": "Arrow Pull-Ons", + "H_3016": "Swim Goggles", + "S_3020": "U Jellys", + "H_3021": "Ink-Tinted Goggles", + "S_3022": "Turbo Tabi Red", + "S_3023": "E-JECT 30XX", + "S_3024": "Slamgerine Slip-Ons", + "H_3025": "Invisifloats", + "S_3025": "Mako Bucket Hi-Tops", + "H_3026": "Moto Shades", + "H_3027": "Annaki Charms", + "S_4000": "Oyster Clogs", + "S_4001": "Choco Clogs", + "H_4004": "Bamboo Hat", + "C_4004": "Black Polo", + "C_4005": "Cycling Shirt", + "S_4007": "Neon Delta Straps", + "H_4008": "Bucket Hat", + "S_4008": "Black Flip-Flops", + "C_4009": "Rugby King 10", + "S_4009": "Snow Delta Straps", + "C_4010": "Rugby King 08", + "S_4011": "Red FishFry Sandals", + "S_4012": "Yellow FishFry Sandals", + "H_4015": "Classic Bowler", + "S_4015": "Arrow Toesies Blu", + "H_4016": "Jean Dream Bucket", + "S_4016": "BlobMob Flip-Flops", + "H_4017": "Howdy Hat", + "S_4017": "Orange Dadfoot Sandals", + "S_4021": "Pink Dadfoot Sandals", + "S_4022": "Cyan Dadfoot Sandals", + "C_5000": "Olive Ski Jacket", + "S_5000": "Trail Boots", + "H_5001": "Designer Headphones", + "C_5001": "Takoroka Nylon Vintage", + "S_5001": "Custom Trail Boots", + "H_5004": "Squidlife Headphones", + "C_5006": "Black Inky Rider", + "H_5007": "Ocho OctoPhones", + "H_5008": "Cephalo Pods", + "C_5014": "Squid Satin Jacket", + "C_5015": "Zapfish Satin Jacket", + "C_5019": "Matcha Down Jacket", + "C_5023": "Kensa Coat", + "C_5045": "Arctic Monster Parka", + "C_5046": "Barazushi Anorak", + "C_5047": "Patchwork Bomber", + "C_5048": "Airflow & Hustle Jacket", + "C_5049": "Ink-Black Paddle Jack", + "C_5050": "Orca Bolero", + "C_5051": "Cream Tundra Fleece", + "C_5054": "Dusty Field Jacket", + "C_6000": "B-ball Jersey (Home)", + "S_6000": "Moto Boots", + "H_6001": "FishFry Visor", + "S_6001": "Tan Work Boots", + "H_6003": "Takoroka Visor", + "H_6004": "Face Visor", + "S_6006": "Punk Whites", + "S_6007": "Punk Cherries", + "C_6008": "Umibozu Home Jersey", + "S_6012": "Hunting Boots", + "S_6021": "Arctic Duck Boots", + "C_7001": "Squidmark Sweat", + "S_7002": "Squid-Stitch Slip-Ons", + "H_7007": "Hockey Helmet", + "C_7010": "Annaki Blue Cuff", + "H_7012": "Winkle Stripe Helm", + "H_7013": "Party Hard Hat", + "H_7014": "Home-Team Catcher", + "C_7016": "Manatee Swag Sweat", + "C_7017": "Apex Sweater", + "C_7018": "Octo Jumper Away", + "C_8000": "Lumberjack Shirt", + "C_8003": "White Shirt", + "H_8005": "Annaki Mask", + "C_8005": "Aloha Shirt", + "H_8008": "Firefin Facemask", + "S_8010": "Annaki Habaneros", + "H_8011": "Forge Mask", + "C_8012": "Logo Aloha Shirt", + "S_8013": "Desert Chukkas", + "H_8014": "BlobMob Mask", + "S_8014": "Dark-Roast Boaties", + "H_8016": "Squidbeak Shield", + "C_8017": "Hula Punk Shirt", + "C_8018": "Octobowler Shirt", + "C_8019": "Inkfall Shirt", + "C_8020": "Crimson Parashooter", + "C_8024": "Chili Octo Aloha", + "C_8025": "Annaki Flannel Hoodie", + "C_8030": "Seahorse Shoreliner", + "C_8031": "Button-Clown Shirt", + "C_8033": "Business Animal", + "C_8034": "Fancyfish Stitch", + "C_8036": "Fashion Splash Shirt", + "C_8040": "Urban Upcycle Top", + "H_9003": "Tennis Headband", + "H_9007": "FishFry Biscuit Bandana", + "H_9009": "Squidband", + "C_9010": "Khaki Ranger Vest", + "C_9011": "Red Battlecrab Shell", + "C_10006": "Gray Hoodie", + "C_10012": "Sudadera Roja" +} diff --git a/public/locales/da/user.json b/public/locales/da/user.json new file mode 100644 index 000000000..0510cdb4f --- /dev/null +++ b/public/locales/da/user.json @@ -0,0 +1,10 @@ +{ + "country": "Land", + "bio": "Biografi", + + "results.placing": "Rang", + "results.team": "Hold", + "results.tournament": "Turnering", + "results.date": "Dato", + "results.mates": "Holdkammerater" +} diff --git a/public/locales/da/weapons.json b/public/locales/da/weapons.json new file mode 100644 index 000000000..ba45a035a --- /dev/null +++ b/public/locales/da/weapons.json @@ -0,0 +1,55 @@ +{ + "0": "Sploosh-o-matic", + "10": "Splattershot Jr.", + "20": "Splash-o-matic", + "30": "Aerospray MG", + "40": "Splattershot", + "50": ".52 Gal", + "60": "N-ZAP '85", + "70": "Splattershot Pro", + "80": ".96 Gal", + "90": "Jet Squelcher", + "200": "Luna Blaster", + "210": "Blaster", + "220": "Range Blaster", + "230": "Clash Blaster", + "240": "Rapid Blaster", + "250": "Rapid Blaster Pro", + "300": "L-3 Nozzlenose", + "310": "H-3 Nozzlenose", + "400": "Squeezer", + "1000": "Carbon Roller", + "1010": "Splat Roller", + "1020": "Dynamo Roller", + "1030": "Flingza Roller", + "1100": "Inkbrush", + "1110": "Octobrush", + "2000": "Classic Squiffer", + "2010": "Splat Charger", + "2020": "Splatterscope", + "2030": "E-liter 4K", + "2040": "E-liter 4K Scope", + "2050": "Bamboozler 14 Mk I", + "2060": "Goo Tuber", + "3000": "Slosher", + "3010": "Tri-Slosher", + "3020": "Sloshing Machine", + "3030": "Bloblobber", + "3040": "Explosher", + "4000": "Mini Splatling", + "4010": "Heavy Splatling", + "4020": "Hydra Splatling", + "4030": "Ballpoint Splatling", + "4040": "Nautilus 47", + "5000": "Dapple Dualies", + "5010": "Splat Dualies", + "5020": "Glooga Dualies", + "5030": "Dualie Squelchers", + "5040": "Dark Tetra Dualies", + "6000": "Splat Brella", + "6010": "Tenta Brella", + "6020": "Undercover Brella", + "7010": "Tri-Stringer", + "8000": "Splatana Stamper", + "8010": "Splatana Wiper" +} diff --git a/public/locales/de/calendar.json b/public/locales/de/calendar.json new file mode 100644 index 000000000..7c495c47c --- /dev/null +++ b/public/locales/de/calendar.json @@ -0,0 +1,52 @@ +{ + "inYourTimeZone": " Alle Zeiten sind konvertiert zur lokalen Zeitzone:", + "addNew": "Turnier hinzufügen", + "noEvents": "Keine Events in dieser Woche", + "reportResults": "Ergebnisse können eingetragen werden für:", + "day": "Tag {{number}}", + "actions.reportWinners": "Gewinner berichten", + "participatedCount": "{{count}} teilnehmende Teams", + "members": "Mitglieder", + "results": "Resultate", + + "forms.dates": "Datum", + "forms.bracketUrl": "Turnierbaum URL", + "forms.discordInvite": "Discord server Einladung URL", + "forms.tags": "Tags", + "forms.tags.placeholder": "Wähle einen Tag", + "forms.tags.info": "\"Abzeichen-Preis\" tag wird automatisch hinzugefügt (falls anwendbar)", + "forms.badges": "Abzeichen-Preis", + "forms.badges.placeholder": "Wähle ein Abzeichen für das Event", + + "forms.participantCount": "Anzahl Teilnehmer", + "forms.reportResultsHeader": "Berichten der Ergebnisse von {{eventName}}", + "forms.reportResultsInfo": "Die Anzahl der eintragbaren Resultate ist frei wählbar. Es kann nur das erste Team sein, die Top 3 oder mehr.", + "forms.team.add": "Team hinzufügen", + "forms.team.remove": "Team löschen", + "forms.team.name": "Name des Teams", + "forms.team.placing": "Platz", + + "forms.team.player.header": "Spieler {{number}}", + "forms.team.player.add": "Spieler hinzufügen", + "forms.team.player.remove": "Spieler löschen", + "forms.team.player.addAsUser": "Hinzufügen als Benutzer (empfohlen)", + "forms.team.player.addAsText": "Hinzufügen als Text", + + "forms.errors.uniqueTeamName": "Zwei Teams dürfen nicht den gleichen Namen haben.", + "forms.errors.duplicatePlayer": "Ein Spieler kann nicht doppelt in einem Team sein.", + "forms.errors.emptyTeam": "Jedes Team brauch mindestens einen gelisteten Spieler.", + + "week.this": "Diese Woche", + "week.next": "Nächste Woche", + "week.last": "Letzte Woche", + + "tag.desc.BADGE": "Die Gewinner des Events bekommen eine Abzeichen für ihr Profil.", + "tag.desc.SPECIAL": "Die Regeln des Events weichen vom Standard ab. (zum Beispiel: Limitierte Waffen).", + "tag.desc.ART": "In dem Event kann man einen Kunst-Preis gewinnen.", + "tag.desc.MONEY": "In dem Event kann man Geld gewinnen.", + "tag.desc.REGION": "Das Event beschränkt, welche Regionen auf der Welt mitspielen dürfen.", + "tag.desc.LOW": "Dieses Event besitzt eine Skill-Grenze.", + "tag.desc.COUNT": "Nur eine beschränkte Anzahl an Teams dürfen mitspielen.", + "tag.desc.LAN": "Dieses Event wird lokal gespielt.", + "tag.desc.QUALIFIER": "Dieses Turnier ist eine Qualifikation für ein anderes Event." +} diff --git a/public/locales/de/front.json b/public/locales/de/front.json index a5a9b99ad..ef2cd061f 100644 --- a/public/locales/de/front.json +++ b/public/locales/de/front.json @@ -3,7 +3,7 @@ "calendarGoTo": "Sieh alle bisherigen und zukünftigen Events auf der Kalender-Seite", "moreFeatures": "Weitere Funktionen", "plus.description": "Sieh vergangene Plus Server Abstimmungen und mehr", - "badges.description": "Liste aller Abzeichen, die du für den Profil verdienen kannst", + "badges.description": "Liste aller Abzeichen, die du für dein Profil verdienen kannst", "recentWinners": "Aktuelle Gewinner", "upcomingEvents": "Bevorstehende Events", "articleBy": "von {{author}}" diff --git a/public/locales/de/gear.json b/public/locales/de/gear.json index da50c5a48..b33e89bfe 100644 --- a/public/locales/de/gear.json +++ b/public/locales/de/gear.json @@ -1,6 +1,7 @@ { "H_1": "Weißes Stirnband", "H_1000": "Urchins-Kappe", + "C_1000": "Weißes Shirt", "S_1000": "Blaue Low-Tops", "C_1001": "Schwarzes Krakenaugen-Shirt", "H_1002": "Kalamati-Netzkappe", @@ -24,12 +25,15 @@ "C_1021": "Schwarzes Rilax-Pixel-Shirt", "S_1021": "Wasabi-Tabi", "S_1022": "Basic-Tennisschuhe", + "S_1023": "600er Kanro", "S_1024": "Profi-Tennisschuhe", "H_1028": "Klappenkappe Dark", "C_1035": "Weißes V-Shirt", "H_1036": "Dockermütze", "C_1062": "Terpentakel-Shirt", + "C_1063": "Tentatek-Duo-Shirt", "C_1066": "Annaki-Shirt mit Choker", + "C_1067": "Annaki-Shirt mit Armband", "C_1069": "Schiefer-Re-Issue-Shirt", "C_1070": "Karamell-Re-Issue-Shirt", "C_1071": "Barazushi-Tuch", @@ -44,9 +48,11 @@ "C_1084": "Zwielichtwellen-Shirt", "C_1085": "Dämmerwellen-Shirt", "C_1088": "Aalzazel-Shirt", + "C_1090": "Limetten-BlobMob-Shirt", "C_1091": "Beeren-BlobMob-Shirt", "S_2000": "Rote High-Top-Sneaker", "S_2001": "Zombie-High-Top-Sneaker", + "S_2003": "Lila High-Top-Sneaker", "C_2004": "Zekko-Baseball-Shirt", "S_2004": "Tannengrüne Leinen-High-Tops", "S_2005": "Rote Leinen-High-Tops", @@ -58,10 +64,13 @@ "S_2043": "Rote Tenya8", "S_2045": "4USTERs Perle", "C_3000": "Weißes Lagen-Shirt", + "S_3000": "Pinke Turnschuhe", "H_3001": "Taucherbrille", "C_3001": "Gelbes Lagen-Shirt", "S_3001": "Orange Pfeilschuhe", + "H_3002": "Fliegerbrille", "H_3003": "Getönte Brille", + "C_3004": "Sagitron-Lagen-Shirt", "S_3004": "Türkise Turnschuhe", "C_3006": "Schoko-Lagen-Shirt", "H_3008": "Sonnenbrille 18K", @@ -74,18 +83,24 @@ "H_3016": "Schwimmbrille", "S_3020": "Sneaker Translux", "H_3021": "Macropinna-Brille", + "H_3022": "Pixelbrille", "S_3022": "Lachs-Turbo-Tabi", + "H_3023": "Brille ohne Gläser", "S_3023": "AL-G 9", + "H_3024": "Triple-Brille", "S_3024": "Orange X-Sneaker", "H_3025": "Transparente Brille", "S_3025": "Mako-Sneaker", "H_3026": "Biker-Brille", + "S_3026": "Blaue Shrimpsider", "H_3027": "Eckige Annaki-Brille", + "H_3029": "BC925-Rundbrille", "S_4000": "Austerngraue Clogs", "S_4001": "Schokobraune Clogs", "H_4004": "Bambushut", "C_4004": "Schwarzes Polohemd", "C_4005": "Radlertrikot", + "H_4006": "Klassischer Boater", "S_4007": "Neon-Delta-Sandalen", "H_4008": "Fischerhut", "S_4008": "Schwarze Strandsandalen", @@ -94,14 +109,17 @@ "C_4010": "Vierfarb-King-Hemd 08", "S_4011": "Rote Schlappen", "S_4012": "Gelbe Schlappen", + "S_4014": "Gräten-Sandalen", "H_4015": "Melone", "S_4015": "Blaue Pfeilsandalen", "H_4016": "Jeans-Hut", "S_4016": "BlobMob-Strandsandalen", "H_4017": "Türkise-Cowboyhut", "S_4017": "Orange Strumpflatschen", + "H_4019": "Strandhut", "S_4021": "Pinke Strumpflatschen", "S_4022": "Türkise Strumpflatschen", + "H_5000": "Studio-Kopfhörer", "C_5000": "Grüner Anorak", "S_5000": "Wanderstiefel", "H_5001": "Kolor-Kopfhörer", @@ -133,7 +151,10 @@ "S_6007": "Rotbraune Punkstiefel", "C_6008": "Umibozu-Heimtrikot", "S_6012": "Jagdstiefel", + "S_6020": "Bonito-Arbeitsstiefel", "S_6021": "Eis-Duck-Boots", + "S_6023": "Rote Hammerhai-Stiefel", + "S_6025": "Rosa Punkstiefel", "C_7001": "Kalmar-Sweatshirt", "S_7002": "Pfeil-Slip-ons", "H_7007": "Hockey-Helm", @@ -155,6 +176,7 @@ "S_8013": "Wüsten-Chukkas", "H_8014": "BlobMob-Mundschutz", "S_8014": "Dunkelbraune Boaties", + "H_8015": "Atemmaske Pro", "H_8016": "Airflow-Schild R255", "C_8017": "Hula-Punk-Hemd", "C_8018": "Oktobowler-Hemd", @@ -173,6 +195,62 @@ "H_9009": "TT-Stirnband", "C_9010": "Kaki-Ranger-Kombo", "C_9011": "Roter Krabbenschützer", + "C_9012": "Grüner Krabbenschützer", + "C_9013": "Klecks-Pullunder", "C_10006": "Grauer Hoodie", - "C_10012": "Sudadera Roja" + "C_10012": "Sudadera Roja", + "C_10014": "Sudadera Celeste", + "H_21010": "Schnapperkappe", + "H_25000": "Tintenfisch-Spange", + "C_25000": "Schuluniform A", + "S_25000": "Schuluniform-Schuhe", + "H_25001": "Samurai-Helm", + "C_25001": "Samurai-Rüstung", + "S_25001": "Samurai-Schuhe", + "H_25002": "Exo-Helm", + "C_25002": "Exo-Rüstung", + "S_25002": "Exo-Stiefel", + "H_25003": "Tintenfisch-Ohrclips", + "C_25003": "Schul-Cardigan A", + "S_25003": "Stulpen-Loafer", + "H_25004": "Ninja-Maske II", + "C_25004": "Ninja-Anzug", + "S_25004": "Ninja-Stiefel", + "H_25005": "Exo-Prototypenhelm", + "C_25005": "Exo-Prototypenrüstung", + "S_25005": "Exo-Prototypenstiefel", + "H_25006": "Perla-Krone S", + "C_25006": "Perla-Pulli", + "S_25006": "Perla-Sneaker", + "H_25007": "Marina-Kopfhörer", + "C_25007": "Marina-Top", + "S_25007": "Marina-Slip-ons", + "H_25008": "Zauberhut", + "C_25008": "Zaubergewand A", + "S_25008": "Zauberstiefel", + "H_25009": "Oktoritter-Helm", + "C_25009": "Oktoritter-Rüstung", + "S_25009": "Oktoritter-Stiefel", + "H_25010": "Flosso-Kopf", + "C_25010": "Flosso-Handschuhe", + "S_25010": "Flosso-Schuhe", + "C_25014": "Schuluniform B", + "S_25014": "Basic-Schuluniform-Schuhe", + "C_25015": "Schul-Cardigan B", + "S_25015": "Basic-Loafer", + "H_25016": "Ninja-Maske I", + "H_25017": "Perla-Krone L", + "C_25017": "Zaubergewand B", + "C_26000": "Splatfest-Shirt", + "H_27000": "Helden-Headset Replik", + "C_27000": "Heldenjacke Replik", + "S_27000": "Heldenschuhe Replik", + "H_27004": "Rüstungshelm Replik", + "C_27004": "Rüstungsjacke Replik", + "S_27004": "Rüstungsstiefel Replik", + "H_27109": "Bärchenöhrchen", + "H_27306": "Helden-Neuroset Replik", + "C_27306": "Heldenanzug Replik", + "S_27306": "Heldenstiefel Replik", + "H_28000": "Shrimpson-Haube" } diff --git a/public/locales/de/user.json b/public/locales/de/user.json new file mode 100644 index 000000000..d72d7d3d5 --- /dev/null +++ b/public/locales/de/user.json @@ -0,0 +1,10 @@ +{ + "country": "Land", + "bio": "Über mich", + + "results.placing": "Platzierung", + "results.team": "Team", + "results.tournament": "Turnier", + "results.date": "Datum", + "results.mates": "Mitspieler" +} diff --git a/public/locales/de/weapons.json b/public/locales/de/weapons.json index c4eb31ace..c55115d39 100644 --- a/public/locales/de/weapons.json +++ b/public/locales/de/weapons.json @@ -1,55 +1,86 @@ { - "0": "Disperser", - "10": "Junior-Kleckser", - "20": "Fein-Disperser", - "30": "Airbrush MG", - "40": "Kleckser", - "50": ".52 Gallon", - "60": "N-ZAP85", - "70": "Profi-Kleckser", - "80": ".96 Gallon", - "90": "Platscher", - "200": "Luna-Blaster", - "210": "Blaster", - "220": "Fern-Blaster", - "230": "Kontra-Blaster", - "240": "Turbo-Blaster", - "250": "Turbo-Blaster Plus", - "300": "L3 Tintenwerfer", - "310": "S3 Tintenwerfer", - "400": "Quetscher", - "1000": "Karbonroller", - "1010": "Klecksroller", - "1020": "Dynaroller", - "1030": "Flex-Roller", - "1100": "Quasto", - "1110": "Kalligraf", - "2000": "Sepiator α", - "2010": "Klecks-Konzentrator", - "2020": "Ziel-Konzentrator", - "2030": "E-liter 4K", - "2040": "Ziel-E-liter 4K", - "2050": "Klotzer 14-A", - "2060": "T-Tuber", - "3000": "Schwapper", - "3010": "3R-Schwapper", - "3020": "Trommel-Schwapper", - "3030": "Wannen-Schwapper", - "3040": "Knall-Schwapper", - "4000": "Klecks-Splatling", - "4010": "Splatling", - "4020": "Hydrant", - "4030": "Kuli-Splatling", - "4040": "Nautilus 47", - "5000": "Sprenkler", - "5010": "Klecks-Doppler", - "5020": "Kelvin 525", - "5030": "Dual-Platscher", - "5040": "Quadhopper Noir", - "6000": "Parapluviator", - "6010": "Camp-Pluviator", - "6020": "UnderCover", - "7010": "Tri-Stringer", - "8000": "Stempel-Splatana", - "8010": "Wischer-Splatana" + "MAIN_250": "Turbo-Blaster Plus", + "MAIN_230": "Kontra-Blaster", + "MAIN_240": "Turbo-Blaster", + "MAIN_220": "Fern-Blaster", + "MAIN_210": "Blaster", + "MAIN_200": "Luna-Blaster", + "MAIN_1100": "Quasto", + "MAIN_1110": "Kalligraf", + "MAIN_2060": "T-Tuber", + "MAIN_2050": "Klotzer 14-A", + "MAIN_2040": "Ziel-E-liter 4K", + "MAIN_2030": "E-liter 4K", + "MAIN_2020": "Ziel-Konzentrator", + "MAIN_2010": "Klecks-Konzentrator", + "MAIN_2000": "Sepiator α", + "MAIN_5030": "Dual-Platscher", + "MAIN_5020": "Kelvin 525", + "MAIN_5010": "Klecks-Doppler", + "MAIN_5000": "Sprenkler", + "MAIN_5040": "Quadhopper Noir", + "MAIN_1000": "Karbonroller", + "MAIN_1020": "Dynaroller", + "MAIN_1030": "Flex-Roller", + "MAIN_1010": "Klecksroller", + "MAIN_8010": "Wischer-Splatana", + "MAIN_8000": "Stempel-Splatana", + "MAIN_6020": "UnderCover", + "MAIN_6000": "Parapluviator", + "MAIN_6010": "Camp-Pluviator", + "MAIN_30": "Airbrush MG", + "MAIN_70": "Profi-Kleckser", + "MAIN_10": "Junior-Kleckser", + "MAIN_400": "Quetscher", + "MAIN_50": ".52 Gallon", + "MAIN_80": ".96 Gallon", + "MAIN_90": "Platscher", + "MAIN_40": "Kleckser", + "MAIN_45": "Heldenwaffe Replik", + "MAIN_20": "Fein-Disperser", + "MAIN_60": "N-ZAP85", + "MAIN_0": "Disperser", + "MAIN_310": "S3 Tintenwerfer", + "MAIN_300": "L3 Tintenwerfer", + "MAIN_3030": "Wannen-Schwapper", + "MAIN_3010": "3R-Schwapper", + "MAIN_3020": "Trommel-Schwapper", + "MAIN_3000": "Schwapper", + "MAIN_3040": "Knall-Schwapper", + "MAIN_4030": "Kuli-Splatling", + "MAIN_4020": "Hydrant", + "MAIN_4000": "Klecks-Splatling", + "MAIN_4040": "Nautilus 47", + "MAIN_4010": "Splatling", + "MAIN_7010": "Tri-Stringer", + "MAIN_7020": "LACT-450", + "SUB_8": "Sprungboje", + "SUB_6": "Curling-Bombe", + "SUB_5": "Sprudel-Bombe", + "SUB_2": "Insta-Bombe", + "SUB_7": "Robo-Bombe", + "SUB_0": "Klecks-Bombe", + "SUB_1": "Haftbombe", + "SUB_13": "Torpedo", + "SUB_12": "Winkelmarker", + "SUB_9": "Detektor", + "SUB_11": "Sepitox-Nebel", + "SUB_4": "Tintenwall", + "SUB_3": "Sprinkler", + "SUB_10": "Tintenmine", + "SPECIAL_8": "Tintegrator", + "SPECIAL_12": "Krabbenpanzer", + "SPECIAL_15": "Tranktank", + "SPECIAL_2": "Kugelschild Pro", + "SPECIAL_5": "Tintenschauer", + "SPECIAL_10": "Tintendüser", + "SPECIAL_9": "Heulboje 5.1", + "SPECIAL_4": "Schwarmraketen", + "SPECIAL_6": "Cool-Kugel", + "SPECIAL_7": "Schauerwelle", + "SPECIAL_13": "Haihammer", + "SPECIAL_3": "Haftsprung", + "SPECIAL_14": "Tri-Tintferno", + "SPECIAL_1": "Trizooka", + "SPECIAL_11": "Ultra-Stempel" } diff --git a/public/locales/en/analyzer.json b/public/locales/en/analyzer.json new file mode 100644 index 000000000..c7ab84fe7 --- /dev/null +++ b/public/locales/en/analyzer.json @@ -0,0 +1,72 @@ +{ + "attribute.weight": "Weight:", + "attribute.weight.Fast": "Light", + "attribute.weight.Slow": "Heavy", + "attribute.weight.Normal": "Normal", + "stat.category.main": "Main weapon", + "stat.category.sub": "Sub weapon", + "stat.category.special": "Special weapon", + "stat.category.subDef": "Sub weapon defense", + "stat.category.actionsPerInkTank": "Actions per ink tank", + "stat.category.damage": "Damage", + "stat.category.movement": "Movement", + "stat.category.misc": "Miscellaneous", + "stat.canopyHp": "Canopy durability", + "stat.fullChargeSeconds": "Charge time to full", + "stat.maxChargeHoldSeconds": "Max charge hold time", + "stat.specialPoints": "Points to special", + "stat.specialLost": "Special lost when splatted", + "stat.whiteInk": "No ink recovery time after usage", + "stat.squidFormInkRecoverySeconds": "Ink tank full recovery time (squid form)", + "stat.quickRespawnTime": "Quick respawn time", + "stat.superJumpTimeGround": "Super jump vulnerable frames", + "stat.superJumpTimeTotal": "Super jump time (total)", + "stat.swimSpeed": "Swim speed (units per frame)", + "stat.runSpeed": "Run speed (units per frame)", + "stat.runSpeedInEnemyInk": "Run speed in enemy ink", + "stat.framesBeforeTakingDamageInEnemyInk": "Frames before enemy ink damage", + "stat.damageTakenInEnemyInkPerSecond": "Damage from enemy ink per second", + "stat.enemyInkDamageLimit": "Max damage from enemy ink", + "stat.markedTime": "{{weapon}} tracking time", + "stat.movementReduction": "{{weapon}} movement reduction", + "stat.damage": "{{weapon}} damage", + "stat.consumption.NORMAL": "Shots", + "stat.consumption.SWING": "Swings", + "stat.consumption.SLOSH": "Sloshes", + "stat.consumption.VERTICAL_SWING": "Vertical swings", + "stat.consumption.HORIZONTAL_SWING": "Horizontal swings", + "stat.consumption.TAP_SHOT": "Tap shots", + "stat.consumption.FULL_CHARGE": "Fully charged shots", + "stat.consumption.SPLATLING_CHARGE": "Full charges", + "stat.consumption.SHIELD_LAUNCH": "Shield launches", + "stat.consumption.DUALIE_ROLL": "Dodge Rolls", + "stat.sub.velocity": "Velocity (decides range)", + "stat.sub.firstPhaseDuration": "Full power phase duration", + "stat.sub.secondPhaseDuration": "Mid phase duration", + "stat.sub.markingTimeInSeconds": "Marking duration", + "stat.sub.markingRadius": "Marking radius", + "stat.sub.explosionRadius": "Explosion radius", + "stat.sub.hp": "Durability", + "damage.header.type": "Type", + "damage.header.damage": "Damage", + "damage.header.distance": "Distance", + "damage.toSplat": "{{count}} hits to splat", + "damage.NORMAL_MIN": "Minimum", + "damage.NORMAL_MAX": "Maximum", + "damage.DIRECT": "Direct", + "damage.FULL_CHARGE": "Fully charged shot", + "damage.MAX_CHARGE": "Maximum partial charge", + "damage.TAP_SHOT": "Tap shot", + "damage.DISTANCE": "Splash", + "suffix.seconds": "s", + "suffix.hp": "hp", + "suffix.specialPointsShort": "p", + "base": "Base", + "value": "Value", + "build": "Build", + "patch": "Patch:", + "abilityPoints": "Ability points", + "abilityPoints.short": "AP", + "consumptionExplanation": "This chart shows the amount of actions left to perform with main weapon after using sub 0-{{maxSubsToUse}} times. Max amount of consecutive subs to use with full ink tank is {{maxSubsToUse}}.", + "trackingSubDefExplanation": "Point Sensor, Ink Mine and Angle Shooter tracking times are calculated against an opponent with 0AP of Sub Power Up." +} diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 6db053eaa..8ab605b18 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -6,6 +6,7 @@ "pages.calendar": "Calendar", "pages.faq": "FAQ", "pages.builds": "Builds", + "pages.buildAnalyzer": "Build Analyzer", "header.profile": "Profile", "header.logout": "Log out", diff --git a/public/locales/en/gear.json b/public/locales/en/gear.json index 2437b7a51..aea12c12f 100644 --- a/public/locales/en/gear.json +++ b/public/locales/en/gear.json @@ -1,6 +1,7 @@ { "H_1": "White Headband", "H_1000": "Urchins Cap", + "C_1000": "White Tee", "S_1000": "Blue Lo-Tops", "C_1001": "Black Squideye", "H_1002": "Takoroka Mesh", @@ -24,12 +25,15 @@ "C_1021": "Black 8-Bit FishFry", "S_1021": "Wasabi Tabi", "S_1022": "Suede Basics", + "S_1023": "Ink-Black Clam 600s", "S_1024": "Suede Bosses", "H_1028": "Ink-Black Flap Cap", "C_1035": "White V-Neck Tee", "H_1036": "Wharfside Cap", "C_1062": "Tri-Shred Tee", + "C_1063": "Tentatek Tandem", "C_1066": "Annaki Choker Tee", + "C_1067": "Annaki Bracelet Tee", "C_1069": "Blue Retro Tee", "C_1070": "Tan Retro Tee", "C_1071": "Barazushi Wrap", @@ -44,9 +48,11 @@ "C_1084": "Vaporwave Tee", "C_1085": "Duskwave Tee", "C_1088": "Eelzebub Tee", + "C_1090": "Lime BlobMob Tee", "C_1091": "Berry BlobMob Tee", "S_2000": "Red Hi-Horses", "S_2001": "Zombie Hi-Horses", + "S_2003": "Purple Hi-Horses", "C_2004": "Zekko Baseball LS", "S_2004": "Hunter Hi-Tops", "S_2005": "Red Hi-Tops", @@ -58,10 +64,13 @@ "S_2043": "Tenya OctoReds", "S_2045": "Pearl 01STERs", "C_3000": "White Layered LS", + "S_3000": "Pink Trainers", "H_3001": "Splash Goggles", "C_3001": "Yellow Layered LS", "S_3001": "Orange Arrows", + "H_3002": "Pilot Goggles", "H_3003": "Tinted Shades", + "C_3004": "Zink Layered LS", "S_3004": "Cyan Trainers", "C_3006": "Choco Layered LS", "H_3008": "18K Aviators", @@ -74,18 +83,24 @@ "H_3016": "Swim Goggles", "S_3020": "U Jellys", "H_3021": "Ink-Tinted Goggles", + "H_3022": "Retro Framers", "S_3022": "Turbo Tabi Red", + "H_3023": "Glassless Glasses", "S_3023": "E-JECT 30XX", + "H_3024": "Triple-Deck Specs", "S_3024": "Slamgerine Slip-Ons", "H_3025": "Invisifloats", "S_3025": "Mako Bucket Hi-Tops", "H_3026": "Moto Shades", + "S_3026": "Blue Shrimpsiders", "H_3027": "Annaki Charms", + "H_3029": "Retro BluFocals", "S_4000": "Oyster Clogs", "S_4001": "Choco Clogs", "H_4004": "Bamboo Hat", "C_4004": "Black Polo", "C_4005": "Cycling Shirt", + "H_4006": "Classic Straw Boater", "S_4007": "Neon Delta Straps", "H_4008": "Bucket Hat", "S_4008": "Black Flip-Flops", @@ -94,14 +109,17 @@ "C_4010": "Rugby King 08", "S_4011": "Red FishFry Sandals", "S_4012": "Yellow FishFry Sandals", + "S_4014": "Cuttlefish Sandies", "H_4015": "Classic Bowler", "S_4015": "Arrow Toesies Blu", "H_4016": "Jean Dream Bucket", "S_4016": "BlobMob Flip-Flops", "H_4017": "Howdy Hat", "S_4017": "Orange Dadfoot Sandals", + "H_4019": "Beachcomber", "S_4021": "Pink Dadfoot Sandals", "S_4022": "Cyan Dadfoot Sandals", + "H_5000": "Studio Headphones", "C_5000": "Olive Ski Jacket", "S_5000": "Trail Boots", "H_5001": "Designer Headphones", @@ -133,7 +151,10 @@ "S_6007": "Punk Cherries", "C_6008": "Umibozu Home Jersey", "S_6012": "Hunting Boots", + "S_6020": "Skipjack Work Boots", "S_6021": "Arctic Duck Boots", + "S_6023": "Red Hammertreads", + "S_6025": "Punk Pinks", "C_7001": "Squidmark Sweat", "S_7002": "Squid-Stitch Slip-Ons", "H_7007": "Hockey Helmet", @@ -155,6 +176,7 @@ "S_8013": "Desert Chukkas", "H_8014": "BlobMob Mask", "S_8014": "Dark-Roast Boaties", + "H_8015": "Air Gills DX", "H_8016": "Squidbeak Shield", "C_8017": "Hula Punk Shirt", "C_8018": "Octobowler Shirt", @@ -173,6 +195,62 @@ "H_9009": "Squidband", "C_9010": "Khaki Ranger Vest", "C_9011": "Red Battlecrab Shell", + "C_9012": "Lime Battlecrab Shell", + "C_9013": "Distressed Vest", "C_10006": "Gray Hoodie", - "C_10012": "Sudadera Roja" + "C_10012": "Sudadera Roja", + "C_10014": "Sudadera Celeste", + "H_21010": "Bream-Brim Cap", + "H_25000": "Squid Hairclip", + "C_25000": "School Uniform A", + "S_25000": "School Shoes + Hi Socks", + "H_25001": "Samurai Helmet", + "C_25001": "Samurai Jacket", + "S_25001": "Samurai Shoes", + "H_25002": "Power Mask", + "C_25002": "Power Armor", + "S_25002": "Power Boots", + "H_25003": "Squid Clip-Ons", + "C_25003": "School Cardigan A", + "S_25003": "Baggy-Sock Fringe Loafs", + "H_25004": "Squinja Mask Mk II", + "C_25004": "Squinja Suit", + "S_25004": "Squinja Boots", + "H_25005": "Power Mask Mk I", + "C_25005": "Power Armor Mk I", + "S_25005": "Power Boots Mk I", + "H_25006": "Pearlescent Crown S", + "C_25006": "Pearlescent Hoodie", + "S_25006": "Pearlescent Kicks", + "H_25007": "Marinated Headphones", + "C_25007": "Marinated Top", + "S_25007": "Marinated Slip-Ons", + "H_25008": "Enchanted Hat", + "C_25008": "Enchanted Robe A", + "S_25008": "Enchanted Boots", + "H_25009": "Steel Helm", + "C_25009": "Steel Platemail", + "S_25009": "Steel Greaves", + "H_25010": "Fresh Fish Head", + "C_25010": "Fresh Fish Gloves", + "S_25010": "Fresh Fish Feet", + "C_25014": "School Uniform B", + "S_25014": "Base School Shoes", + "C_25015": "School Cardigan B", + "S_25015": "Base Fringed Loafers", + "H_25016": "Squinja Mask Mk I", + "H_25017": "Pearlescent Crown L", + "C_25017": "Enchanted Robe B", + "C_26000": "Splatfest Tee", + "H_27000": "Hero Headset Replica", + "C_27000": "Hero Jacket Replica", + "S_27000": "Hero Runner Replicas", + "H_27004": "Armor Helmet Replica", + "C_27004": "Armor Jacket Replica", + "S_27004": "Armor Boot Replicas", + "H_27109": "Teddy Band", + "H_27306": "Hero Mindset Replica", + "C_27306": "Hero Suit Replica", + "S_27306": "Hero Boot Replicas", + "H_28000": "Stay Crusty Cap" } diff --git a/public/locales/en/weapons.json b/public/locales/en/weapons.json index ba45a035a..c97cd67a1 100644 --- a/public/locales/en/weapons.json +++ b/public/locales/en/weapons.json @@ -1,55 +1,86 @@ { - "0": "Sploosh-o-matic", - "10": "Splattershot Jr.", - "20": "Splash-o-matic", - "30": "Aerospray MG", - "40": "Splattershot", - "50": ".52 Gal", - "60": "N-ZAP '85", - "70": "Splattershot Pro", - "80": ".96 Gal", - "90": "Jet Squelcher", - "200": "Luna Blaster", - "210": "Blaster", - "220": "Range Blaster", - "230": "Clash Blaster", - "240": "Rapid Blaster", - "250": "Rapid Blaster Pro", - "300": "L-3 Nozzlenose", - "310": "H-3 Nozzlenose", - "400": "Squeezer", - "1000": "Carbon Roller", - "1010": "Splat Roller", - "1020": "Dynamo Roller", - "1030": "Flingza Roller", - "1100": "Inkbrush", - "1110": "Octobrush", - "2000": "Classic Squiffer", - "2010": "Splat Charger", - "2020": "Splatterscope", - "2030": "E-liter 4K", - "2040": "E-liter 4K Scope", - "2050": "Bamboozler 14 Mk I", - "2060": "Goo Tuber", - "3000": "Slosher", - "3010": "Tri-Slosher", - "3020": "Sloshing Machine", - "3030": "Bloblobber", - "3040": "Explosher", - "4000": "Mini Splatling", - "4010": "Heavy Splatling", - "4020": "Hydra Splatling", - "4030": "Ballpoint Splatling", - "4040": "Nautilus 47", - "5000": "Dapple Dualies", - "5010": "Splat Dualies", - "5020": "Glooga Dualies", - "5030": "Dualie Squelchers", - "5040": "Dark Tetra Dualies", - "6000": "Splat Brella", - "6010": "Tenta Brella", - "6020": "Undercover Brella", - "7010": "Tri-Stringer", - "8000": "Splatana Stamper", - "8010": "Splatana Wiper" + "MAIN_250": "Rapid Blaster Pro", + "MAIN_230": "Clash Blaster", + "MAIN_240": "Rapid Blaster", + "MAIN_220": "Range Blaster", + "MAIN_210": "Blaster", + "MAIN_200": "Luna Blaster", + "MAIN_1100": "Inkbrush", + "MAIN_1110": "Octobrush", + "MAIN_2060": "Goo Tuber", + "MAIN_2050": "Bamboozler 14 Mk I", + "MAIN_2040": "E-liter 4K Scope", + "MAIN_2030": "E-liter 4K", + "MAIN_2020": "Splatterscope", + "MAIN_2010": "Splat Charger", + "MAIN_2000": "Classic Squiffer", + "MAIN_5030": "Dualie Squelchers", + "MAIN_5020": "Glooga Dualies", + "MAIN_5010": "Splat Dualies", + "MAIN_5000": "Dapple Dualies", + "MAIN_5040": "Dark Tetra Dualies", + "MAIN_1000": "Carbon Roller", + "MAIN_1020": "Dynamo Roller", + "MAIN_1030": "Flingza Roller", + "MAIN_1010": "Splat Roller", + "MAIN_8010": "Splatana Wiper", + "MAIN_8000": "Splatana Stamper", + "MAIN_6020": "Undercover Brella", + "MAIN_6000": "Splat Brella", + "MAIN_6010": "Tenta Brella", + "MAIN_30": "Aerospray MG", + "MAIN_70": "Splattershot Pro", + "MAIN_10": "Splattershot Jr.", + "MAIN_400": "Squeezer", + "MAIN_50": ".52 Gal", + "MAIN_80": ".96 Gal", + "MAIN_90": "Jet Squelcher", + "MAIN_40": "Splattershot", + "MAIN_45": "Hero Shot Replica", + "MAIN_20": "Splash-o-matic", + "MAIN_60": "N-ZAP '85", + "MAIN_0": "Sploosh-o-matic", + "MAIN_310": "H-3 Nozzlenose", + "MAIN_300": "L-3 Nozzlenose", + "MAIN_3030": "Bloblobber", + "MAIN_3010": "Tri-Slosher", + "MAIN_3020": "Sloshing Machine", + "MAIN_3000": "Slosher", + "MAIN_3040": "Explosher", + "MAIN_4030": "Ballpoint Splatling", + "MAIN_4020": "Hydra Splatling", + "MAIN_4000": "Mini Splatling", + "MAIN_4040": "Nautilus 47", + "MAIN_4010": "Heavy Splatling", + "MAIN_7010": "Tri-Stringer", + "MAIN_7020": "REEF-LUX 450", + "SUB_8": "Squid Beakon", + "SUB_6": "Curling Bomb", + "SUB_5": "Fizzy Bomb", + "SUB_2": "Burst Bomb", + "SUB_7": "Autobomb", + "SUB_0": "Splat Bomb", + "SUB_1": "Suction Bomb", + "SUB_13": "Torpedo", + "SUB_12": "Angle Shooter", + "SUB_9": "Point Sensor", + "SUB_11": "Toxic Mist", + "SUB_4": "Splash Wall", + "SUB_3": "Sprinkler", + "SUB_10": "Ink Mine", + "SPECIAL_8": "Ink Vac", + "SPECIAL_12": "Crab Tank", + "SPECIAL_15": "Tacticooler", + "SPECIAL_2": "Big Bubbler", + "SPECIAL_5": "Ink Storm", + "SPECIAL_10": "Inkjet", + "SPECIAL_9": "Killer Wail 5.1", + "SPECIAL_4": "Tenta Missiles", + "SPECIAL_6": "Booyah Bomb", + "SPECIAL_7": "Wave Breaker", + "SPECIAL_13": "Reefslider", + "SPECIAL_3": "Zipcaster", + "SPECIAL_14": "Triple Inkstrike", + "SPECIAL_1": "Trizooka", + "SPECIAL_11": "Ultra Stamp" } diff --git a/public/locales/es/analyzer.json b/public/locales/es/analyzer.json new file mode 100644 index 000000000..e89c84548 --- /dev/null +++ b/public/locales/es/analyzer.json @@ -0,0 +1,65 @@ +{ + "attribute.weight": "Peso:", + "attribute.weight.Fast": "Ligero", + "attribute.weight.Slow": "Pesado", + "attribute.weight.Normal": "Normal", + "stat.category.main": "Arma principal", + "stat.category.sub": "Arma secundaria", + "stat.category.special": "Arma especial", + "stat.category.actionsPerInkTank": "Acciones por tanque de tinta", + "stat.category.damage": "Daño", + "stat.category.movement": "Movilidad", + "stat.category.misc": "Misceláneos", + "stat.canopyHp": "Durabilidad del armazón", + "stat.fullChargeSeconds": "Tiempo de carga al máximo", + "stat.maxChargeHoldSeconds": "Tiempo máximo de retención de carga", + "stat.specialPoints": "Puntos para arma especial", + "stat.specialLost": "Especial perdido al ser reventado", + "stat.whiteInk": "Tiempo sin recuperar tinta después de uso", + "stat.squidFormInkRecoverySeconds": "Tiempo de recuperar completo el tanque de tinta (forma nadadora)", + "stat.quickRespawnTime": "Tiempo de regeneración rápida", + "stat.superJumpTimeGround": "Fotogramas vulnerables de supersalto", + "stat.superJumpTimeTotal": "Tiempo de supersalto (total)", + "stat.swimSpeed": "Velocidad de nado (unidades por fotograma)", + "stat.runSpeed": "Velocidad al correr (unidades por fotograma)", + "stat.runSpeedInEnemyInk": "Velocidad al correr sobre tinta rival", + "stat.framesBeforeTakingDamageInEnemyInk": "Fotogramas antes de daño de tinta rival", + "stat.damageTakenInEnemyInkPerSecond": "Daño de tinta rival por segundo", + "stat.enemyInkDamageLimit": "Daño maximo de tinta rival", + "stat.consumption.NORMAL": "Disparos", + "stat.consumption.SWING": "Barrido", + "stat.consumption.SLOSH": "Lanzos de tinta", + "stat.consumption.VERTICAL_SWING": "Barrido vertical", + "stat.consumption.HORIZONTAL_SWING": "Barrido horizontal", + "stat.consumption.TAP_SHOT": "Disparos rapidos", + "stat.consumption.FULL_CHARGE": "Disparos de carga completa", + "stat.consumption.SPLATLING_CHARGE": "Carga completa", + "stat.consumption.SHIELD_LAUNCH": "Lanzamiento de armazón", + "stat.consumption.DUALIE_ROLL": "Rodar", + "stat.sub.velocity": "Velocidad (decide rango)", + "stat.sub.firstPhaseDuration": "Duración de fase de poder máximo", + "stat.sub.secondPhaseDuration": "Duración de fase media", + "stat.sub.markingTimeInSeconds": "Duración del marcado", + "stat.sub.markingRadius": "Radio de marcado", + "stat.sub.hp": "Durabilidad", + "damage.header.type": "Tipo", + "damage.header.damage": "Daño", + "damage.header.distance": "Distancia", + "damage.toSplat": "{{count}} golpes para reventar", + "damage.NORMAL_MIN": "Mínimo", + "damage.NORMAL_MAX": "Máximo", + "damage.DIRECT": "Directo", + "damage.FULL_CHARGE": "Disparo de carga completa", + "damage.MAX_CHARGE": "Carga parcial máxima", + "damage.TAP_SHOT": "Disparo rapido", + "damage.DISTANCE": "Daño de salpicadura", + "suffix.seconds": "s", + "suffix.hp": "hp", + "base": "Base", + "value": "Valor", + "build": "Build", + "patch": "Parche:", + "abilityPoints": "Puntos de habilidad (AP)", + "abilityPoints.short": "AP", + "consumptionExplanation": "Este gráfico muestra la cantidad de acciones restantes con el arma principal después de usar un arma secundaria 0-{{maxSubsToUse}} veces. La cantidad máxima de armas secundarias consecutivas que se pueden usar con el tanque lleno es {{maxSubsToUse}}." +} diff --git a/public/locales/es/badges.json b/public/locales/es/badges.json new file mode 100644 index 000000000..68cf73f88 --- /dev/null +++ b/public/locales/es/badges.json @@ -0,0 +1,9 @@ +{ + "patreon": "Supporter de sendou.ink en Patreon", + "patreon+": "Supporter+ de sendou.ink en Patreon", + "tournament_one": "Recibido por ganar {{tournament}}", + "tournament_other": "Recibido por ganar {{tournament}} (×{{count}})", + "forYourEvent": "¿Insignia para tu evento?", + "madeBy": "Insignia por <2>borzoic", + "managedBy": "Administrado por {{users}}" +} diff --git a/public/locales/es/builds.json b/public/locales/es/builds.json new file mode 100644 index 000000000..5eb6d1894 --- /dev/null +++ b/public/locales/es/builds.json @@ -0,0 +1,15 @@ +{ + "addBuild": "Añadir build", + "noBuilds": "Aún no hay builds. ¡Agrega tu primer build!", + "buildCard.info": "Info", + "buildCard.edit": "Editar", + + "forms.title": "Título", + "forms.modes": "Modos", + "forms.weapons": "Armas", + "forms.gear.HEAD": "Accesorios", + "forms.gear.CLOTHES": "Ropa", + "forms.gear.SHOES": "Calzado", + + "deleteConfirm": "¿Borrar build '{{title}}'?" +} diff --git a/public/locales/es/calendar.json b/public/locales/es/calendar.json new file mode 100644 index 000000000..6629c36bc --- /dev/null +++ b/public/locales/es/calendar.json @@ -0,0 +1,52 @@ +{ + "inYourTimeZone": "Horas mostradas en tu zona local:", + "addNew": "Añadir nuevo", + "noEvents": "No hay eventos en la semana seleccionada", + "reportResults": "Puedes anunciar resultados:", + "day": "Día {{number}}", + "actions.reportWinners": "Anunciar ganadores", + "participatedCount": "{{count}} equipos participaron", + "members": "Miembros", + "results": "Resultados", + + "forms.dates": "Fechas", + "forms.bracketUrl": "Enlace de cuadros", + "forms.discordInvite": "Enlace de invitación a Discord", + "forms.tags": "Etiquetas", + "forms.tags.placeholder": "Elegir etiquetas", + "forms.tags.info": "Etiqueta \"Premios de insignia\" se agrega automáticamente si corresponde.", + "forms.badges": "Premios de insignia", + "forms.badges.placeholder": "Elige un premio de insignia", + + "forms.participantCount": "Participantes", + "forms.reportResultsHeader": "Anunciando resultados para {{eventName}}", + "forms.reportResultsInfo": "Tú decides cuántos resultados reportar. Puede ser solo el equipo ganador, los 3 primeros o lo que quieras.", + "forms.team.add": "Añadir equipo", + "forms.team.remove": "Remover equipo", + "forms.team.name": "Nombre de equipo", + "forms.team.placing": "Lugar", + + "forms.team.player.header": "Jugador {{number}}", + "forms.team.player.add": "Añadir jugador", + "forms.team.player.remove": "Remover jugador", + "forms.team.player.addAsUser": "Añadir como usuario (recomendado)", + "forms.team.player.addAsText": "Añadir solo texto", + + "forms.errors.uniqueTeamName": "Cada equipo requiere un nombre único.", + "forms.errors.duplicatePlayer": "No se puede tener el mismo jugador dos veces en el mismo equipo.", + "forms.errors.emptyTeam": "Cada equipo requiere por lo menos un jugador.", + + "week.this": "Esta semana", + "week.next": "Siguiente semana", + "week.last": "Semana pasada", + + "tag.desc.BADGE": "Ganador de este evento recibe una insignia de sendou.ink.", + "tag.desc.SPECIAL": "Reglas que difieren del estándar, por ejemplo: limite de armas que se pueden usar.", + "tag.desc.ART": "Puedes ganar arte jugando este torneo.", + "tag.desc.MONEY": "Puedes ganar dinero jugando este torneo.", + "tag.desc.REGION": "Limite de jugadores en este evento según su ubicación.", + "tag.desc.LOW": "Quién puede jugar en este evento es limitado por habilidad.", + "tag.desc.COUNT": "Hay un limite de equipos que pueden registrarse.", + "tag.desc.LAN": "Este evento se juega en un área local.", + "tag.desc.QUALIFIER": "Este torneo es clasificatorio para otro evento." +} diff --git a/public/locales/es/common.json b/public/locales/es/common.json new file mode 100644 index 000000000..b5c092f70 --- /dev/null +++ b/public/locales/es/common.json @@ -0,0 +1,44 @@ +{ + "pages.admin": "Administración", + "pages.badges": "Insignias", + "pages.plus": "Plus Server", + "pages.contributors": "Contribuidores", + "pages.calendar": "Calendario", + "pages.faq": "FAQ", + "pages.builds": "Builds", + "pages.buildAnalyzer": "Analizador the builds", + + "header.profile": "Perfil", + "header.logout": "Cerrar sesión", + "header.login": "Iniciar sesión", + + "footer.github.subtitle": "Código fuente", + "footer.twitter.subtitle": "Actualizaciones", + "footer.discord.subtitle": "Ayuda y comentarios", + "footer.patreon.subtitle": "Apoyar", + "footer.thanks": "Gracias a los Patrons por su apoyo", + + "actions.save": "Guardar", + "actions.saving": "Guardando...", + "actions.submit": "Finalizar", + "actions.edit": "Editar", + "actions.add": "Añadir", + "actions.remove": "Remover", + "actions.delete": "Borrar", + + "results": "Resultados", + + "forms.name": "Nombre", + "forms.description": "Descripción", + "forms.errors.title": "Los siguientes errores deben corregirse.", + + "tag.name.BADGE": "Premios de insignia", + "tag.name.SPECIAL": "Reglas especiales", + "tag.name.ART": "Premios de arte", + "tag.name.MONEY": "Premios de dinero", + "tag.name.REGION": "Region cerrada", + "tag.name.LOW": "Limite de habilidad", + "tag.name.COUNT": "Limite de entrada", + "tag.name.LAN": "LAN", + "tag.name.QUALIFIER": "Clasificatorio" +} diff --git a/public/locales/es/contributions.json b/public/locales/es/contributions.json new file mode 100644 index 000000000..557f6b800 --- /dev/null +++ b/public/locales/es/contributions.json @@ -0,0 +1,7 @@ +{ + "project": "Sendou.ink es un proyecto hecho por <2>Sendou con ayuda de contribuidores:", + "code": "Varios contribuidores ayudaron con el codigo", + "lean": "Ayudó a descubrir partes internas de Splatoon y creó el bot Lanista", + "borzoic": "Creó insignias, íconos y el arte de la página principal", + "uberu": "Dibujó el emoji the Justito abrazando un corazón" +} diff --git a/public/locales/es/faq.json b/public/locales/es/faq.json new file mode 100644 index 000000000..d0361b9d6 --- /dev/null +++ b/public/locales/es/faq.json @@ -0,0 +1,10 @@ +{ + "q1": "¿Qué es el Plus Server?", + "a1": "Plus Server es un servidor de Discord para jugadores occidentales de alto nivel que sirve para buscar personas con quien jugar o combatir. Fue fundado en septiembre de 2017. Es dividido en tres niveles, de los cuales +1 es el más alto. Obtienes acceso cuando un miembro del servidor te sugiere y pasas la votación mensual.\n\nDurante la votación, obtienes un porcentage basado en tu resultado. Un 0% significa que todos los participantes votaron en contra, mientras que 100% sería lo opuesto. Se requiere 50% para pasar el voto. Si un miembro recibe menos de 50%, baja un nivel o, en el caso de miembros en +3, serán expulsados.", + + "q2": "¿Cómo puedo obtener un premio de insignia para mi evento?", + "a2": "Puedes contratar a borzoic#1991 para hacer tu insignia. El precio es de 10-30€, dependiendo de lo complejo que sea. Despues, contacta a Sendou para añadirlo al sitio.\n\nCualquier torneo puede tener una insignia como premio. Si quieres entregar insignias por otras hazañas, es mejor consultar primero a Sendou sobre tu idea.", + + "q3": "¿Cómo puedo actualizar mi avatar o nombre de usuario?", + "a3": "Si actualizas tu nombre de usuario o avatar en Discord, no cambian de inmediato en sendou.ink. Para que eso suceda tienes dos opciones:\n\n1) Si eres miembro del Discord de este sitio o del Plus Server, simplemente puedes esperar. Hay una rutina diaria que se encarga de la actualización.\n\n2) Alternativamente, si deseas actualizarlos de inmediato, puede cerrar la sesión y reiniciarla en sendou.ink." +} diff --git a/public/locales/es/front.json b/public/locales/es/front.json new file mode 100644 index 000000000..b3e42465b --- /dev/null +++ b/public/locales/es/front.json @@ -0,0 +1,10 @@ +{ + "websiteSubtitle": "Sitio Central de Splatoon Competitivo", + "calendarGoTo": "Revisa todos los eventos pasados y próximos en el calendario", + "moreFeatures": "Más funciones", + "plus.description": "Revisa el historial de votos del Plus Server y más", + "badges.description": "Lista de todas las insignias que puedes ganar para tu perfil", + "recentWinners": "Ganadores recientes", + "upcomingEvents": "Eventos próximos", + "articleBy": "por {{author}}" +} diff --git a/public/locales/es/gear.json b/public/locales/es/gear.json index 111f077a2..9820ff91b 100644 --- a/public/locales/es/gear.json +++ b/public/locales/es/gear.json @@ -1,6 +1,7 @@ { "H_1": "Cinta blanca", "H_1000": "Gorra béisbol", + "C_1000": "Camiseta blanca", "S_1000": "Tenis azul", "C_1001": "Ojos calamar negra", "H_1002": "Gorra malla Sepioca", @@ -24,12 +25,15 @@ "C_1021": "Retrocamiseta negra", "S_1021": "Deportiva wasabi", "S_1022": "Tenis básica principiante", + "S_1023": "Deportiva almeja negra", "S_1024": "Tenis básica profesional", "H_1028": "Gorra orejeras negra", "C_1035": "Camiseta blanca pro", "H_1036": "Gorro de alta mar", "C_1062": "Camiseta rasgada blanca", + "C_1063": "Camiseta Arome tándem", "C_1066": "Camiseta Annak collar", + "C_1067": "Camiseta Annak brazaletes", "C_1069": "Camiseta reditada azul", "C_1070": "Camiseta reditada marrón", "C_1071": "Pañuelo Barazushi", @@ -44,9 +48,11 @@ "C_1084": "Camiseta degradado neón", "C_1085": "Camiseta degradado atardecer", "C_1088": "Camiseta ofídica", + "C_1090": "Camiseta glóbulos verde", "C_1091": "Camiseta glóbulos rosa", "S_2000": "Hipocampo-A roja", "S_2001": "Hipocampo-A zombi", + "S_2003": "Hipocampo-A morada", "C_2004": "Béisbol Ezko", "S_2004": "Bamba alta oliva", "S_2005": "Bamba alta roja", @@ -58,10 +64,13 @@ "S_2043": "Octodeportiva roja", "S_2045": "Bota ostra blanca", "C_3000": "Blanca doble", + "S_3000": "Deportiva rosa", "H_3001": "Gafas de buceo", "C_3001": "Mostaza doble", "S_3001": "Velcro naranja", + "H_3002": "Gafas de piloto", "H_3003": "Gafas tintadas", + "C_3004": "Tintaz doble", "S_3004": "Deportiva celeste", "C_3006": "Chocolate doble", "H_3008": "Gafas aviador oro", @@ -74,18 +83,24 @@ "H_3016": "Gafas de natación", "S_3020": "Zapatilla sashimi", "H_3021": "Gafas tinte abisal", + "H_3022": "Gafas montura retro", "S_3022": "Zapato con dedos rojo", + "H_3023": "Gafas sin cristales", "S_3023": "Deportiva AL-GA 30XX", + "H_3024": "Gafas triple protección", "S_3024": "Deportiva megatensión", "H_3025": "Gafas transparentes", "S_3025": "Deportiva aletas alta", "H_3026": "Gafas moteras", + "S_3026": "Deportiva camarón azul", "H_3027": "Gafas Annak cuadradas", + "H_3029": "Gafas redondas aurora", "S_4000": "Zueco gris", "S_4001": "Zueco chocolate", "H_4004": "Sombrero cónico", "C_4004": "Polo negro", "C_4005": "Maillot ciclista", + "H_4006": "Sombrero de paja clásico", "S_4007": "Sandalia delta neón", "H_4008": "Gorro de pesca", "S_4008": "Chancla negra", @@ -94,14 +109,17 @@ "C_4010": "Polo rugby extra 008", "S_4011": "Chancla roja", "S_4012": "Chancla amarilla", + "S_4014": "Sandalia raspa de pez", "H_4015": "Bombín clásico", "S_4015": "Sandalia flechas azul", "H_4016": "Sombrero de tela vaquera", "S_4016": "Chancla glóbulos", "H_4017": "Sombrero vaquero gemas", "S_4017": "Sandalia ultranaranja", + "H_4019": "Sombrero playero", "S_4021": "Sandalia ultrarrosa", "S_4022": "Sandalia ultraceleste", + "H_5000": "Auriculares pro", "C_5000": "Chubasquero lima", "S_5000": "Bota montaña", "H_5001": "Auriculares multicolor", @@ -133,7 +151,10 @@ "S_6007": "Bota clásica roja", "C_6008": "Umibozu local", "S_6012": "Bota impermeable", + "S_6020": "Bota piel grafitis", "S_6021": "Bota de pato ártica", + "S_6023": "Bota pez martillo roja", + "S_6025": "Bota clásica rosa", "C_7001": "Sudadera mostaza", "S_7002": "Playera bicolor", "H_7007": "Casco hockey", @@ -155,6 +176,7 @@ "S_8013": "Bota ante desértica", "H_8014": "Mascarilla glóbulos", "S_8014": "Náutico tostado", + "H_8015": "Máscara antitinta", "H_8016": "Protector de mandíbula", "C_8017": "Camisa estampada", "C_8018": "Camisa bolos", @@ -173,6 +195,62 @@ "H_9009": "Cinta tenis de mesa", "C_9010": "Chaleco bolsillos caqui", "C_9011": "Coraza cangrejo roja", + "C_9012": "Coraza cangrejo verde", + "C_9013": "Chaleco salpicadura", "C_10006": "Sudadera gris con capucha", - "C_10012": "Sudadera de jerga roja" + "C_10012": "Sudadera de jerga roja", + "C_10014": "Sudadera de jerga celeste", + "H_21010": "Gorra besugo dorado", + "H_25000": "Horquilla calamar", + "C_25000": "Uniforme escolar A", + "S_25000": "Mocasín escolar", + "H_25001": "Casco samurái", + "C_25001": "Armadura samurái", + "S_25001": "Sandalia samurái", + "H_25002": "Tecnomáscara", + "C_25002": "Tecnoarmadura", + "S_25002": "Tecnobota", + "H_25003": "Pendientes calamar", + "C_25003": "Traje escolar A", + "S_25003": "Zapato escolar", + "H_25004": "Máscara ninja (II)", + "C_25004": "Atuendo ninja", + "S_25004": "Bota ninja", + "H_25005": "Prototipo de tecnomáscara", + "C_25005": "Prototipo de tecnoarmadura", + "S_25005": "Prototipo de tecnobota", + "H_25006": "Corona perlífera (S)", + "C_25006": "Sudadera perlífera", + "S_25006": "Suela doble perlífera", + "H_25007": "Auriculares marínicos", + "C_25007": "Top marínico", + "S_25007": "Playera lazada marínica", + "H_25008": "Sombrero hechizado", + "C_25008": "Túnica hechizada A", + "S_25008": "Bota hechizada", + "H_25009": "Casco octoguerrero", + "C_25009": "Armadura octoguerrero", + "S_25009": "Escarpe octoguerrero", + "H_25010": "Máscara de muñecote", + "C_25010": "Guantes de muñecote", + "S_25010": "Zapato de muñecote", + "C_25014": "Uniforme escolar B", + "S_25014": "Mocasín escolar (básico)", + "C_25015": "Traje escolar B", + "S_25015": "Zapato escolar (básico)", + "H_25016": "Máscara ninja (I)", + "H_25017": "Corona perlífera (L)", + "C_25017": "Túnica hechizada B", + "C_26000": "Camiseta festiva", + "H_27000": "Auriculares de élite (réplica)", + "C_27000": "Sudadera de élite (réplica)", + "S_27000": "Deportiva de élite (réplica)", + "H_27004": "Casco reforzado (réplica)", + "C_27004": "Chaqueta reforzada (réplica)", + "S_27004": "Bota reforzada (réplica)", + "H_27109": "Diadema orejas de oso", + "H_27306": "Neurocascos élite (réplica)", + "C_27306": "Traje de élite (réplica)", + "S_27306": "Bota de élite (réplica)", + "H_28000": "Gorro de Adolfrito" } diff --git a/public/locales/es/user.json b/public/locales/es/user.json new file mode 100644 index 000000000..da1789a9d --- /dev/null +++ b/public/locales/es/user.json @@ -0,0 +1,10 @@ +{ + "country": "País", + "bio": "Biografía", + + "results.placing": "Lugar", + "results.team": "Equipo", + "results.tournament": "Torneo", + "results.date": "Fecha", + "results.mates": "Compañeros" +} diff --git a/public/locales/es/weapons.json b/public/locales/es/weapons.json index 69a3bd899..cf671de00 100644 --- a/public/locales/es/weapons.json +++ b/public/locales/es/weapons.json @@ -1,55 +1,86 @@ { - "0": "Marcador", - "10": "Lanzatintas novato", - "20": "Marcador fino", - "30": "Aerógrafo pro", - "40": "Lanzatintas", - "50": "Salpicadora 2000", - "60": "N-ZAP 85", - "70": "Lanzatintas plus", - "80": "Salpicadora 3000", - "90": "Megabarredora", - "200": "Ultradevastador", - "210": "Devastador", - "220": "Teledevastador", - "230": "Turbodevastador", - "240": "Devastador exprés", - "250": "Superdevastador", - "300": "Tintambor ligero", - "310": "Tintambor pesado", - "400": "Tintopresor", - "1000": "Rodillo de carbono", - "1010": "Rodillo básico", - "1020": "Dinamorrodillo", - "1030": "Rodillo versátil", - "1100": "Pincel", - "1110": "Brocha", - "2000": "Kalarrapid α", - "2010": "Cargatintas", - "2020": "Cargatintas con mira", - "2030": "Entintador 4K", - "2040": "Telentintador 4K", - "2050": "Bambufusil 14-I", - "2060": "Tubofusil", - "3000": "Derramatic", - "3010": "Derramatic triple", - "3020": "Derramatic centrífugo", - "3030": "Derramatic baño", - "3040": "Derramatic turbo", - "4000": "Tintralladora ligera", - "4010": "Tintralladora", - "4020": "Extintador", - "4030": "Ametrallógrafo", - "4040": "Subtralladora 47", - "5000": "Atomizador dual", - "5010": "Difusor dual", - "5020": "Fundidora 525 dual", - "5030": "Barredora dual", - "5040": "Motatrónic dual negro", - "6000": "Paratintas", - "6010": "Paratintas maxi", - "6020": "Paratintas clásico", - "7010": "Arcromatizador triple", - "8000": "Azotintador pro", - "8010": "Azotintador brisa" + "MAIN_250": "Superdevastador", + "MAIN_230": "Turbodevastador", + "MAIN_240": "Devastador exprés", + "MAIN_220": "Teledevastador", + "MAIN_210": "Devastador", + "MAIN_200": "Ultradevastador", + "MAIN_1100": "Pincel", + "MAIN_1110": "Brocha", + "MAIN_2060": "Tubofusil", + "MAIN_2050": "Bambufusil 14-I", + "MAIN_2040": "Telentintador 4K", + "MAIN_2030": "Entintador 4K", + "MAIN_2020": "Cargatintas con mira", + "MAIN_2010": "Cargatintas", + "MAIN_2000": "Kalarrapid α", + "MAIN_5030": "Barredora dual", + "MAIN_5020": "Fundidora 525 dual", + "MAIN_5010": "Difusor dual", + "MAIN_5000": "Atomizador dual", + "MAIN_5040": "Motatrónic dual negro", + "MAIN_1000": "Rodillo de carbono", + "MAIN_1020": "Dinamorrodillo", + "MAIN_1030": "Rodillo versátil", + "MAIN_1010": "Rodillo básico", + "MAIN_8010": "Azotintador brisa", + "MAIN_8000": "Azotintador pro", + "MAIN_6020": "Paratintas clásico", + "MAIN_6000": "Paratintas", + "MAIN_6010": "Paratintas maxi", + "MAIN_30": "Aerógrafo pro", + "MAIN_70": "Lanzatintas plus", + "MAIN_10": "Lanzatintas novato", + "MAIN_400": "Tintopresor", + "MAIN_50": "Salpicadora 2000", + "MAIN_80": "Salpicadora 3000", + "MAIN_90": "Megabarredora", + "MAIN_40": "Lanzatintas", + "MAIN_45": "Pistola de élite (réplica)", + "MAIN_20": "Marcador fino", + "MAIN_60": "N-ZAP 85", + "MAIN_0": "Marcador", + "MAIN_310": "Tintambor pesado", + "MAIN_300": "Tintambor ligero", + "MAIN_3030": "Derramatic baño", + "MAIN_3010": "Derramatic triple", + "MAIN_3020": "Derramatic centrífugo", + "MAIN_3000": "Derramatic", + "MAIN_3040": "Derramatic turbo", + "MAIN_4030": "Ametrallógrafo", + "MAIN_4020": "Extintador", + "MAIN_4000": "Tintralladora ligera", + "MAIN_4040": "Subtralladora 47", + "MAIN_4010": "Tintralladora", + "MAIN_7010": "Arcromatizador triple", + "MAIN_7020": "AR-CR0 450", + "SUB_8": "Baliza transportadora", + "SUB_6": "Bomba deslizante", + "SUB_5": "Bomba carbónica", + "SUB_2": "Bomba rápida", + "SUB_7": "Robobomba", + "SUB_0": "Bomba básica", + "SUB_1": "Bomba ventosa", + "SUB_13": "Torpedo", + "SUB_12": "Tiralíneas", + "SUB_9": "Rastreador", + "SUB_11": "Nebulizador", + "SUB_4": "Telón de tinta", + "SUB_3": "Aspersor", + "SUB_10": "Bomba trampa", + "SPECIAL_8": "Aspiratinta", + "SPECIAL_12": "Cangrejobot", + "SPECIAL_15": "Dispensabebidas", + "SPECIAL_2": "Megaburbuja", + "SPECIAL_5": "Atormentador", + "SPECIAL_10": "Propulsor", + "SPECIAL_9": "Tintófono 5.1", + "SPECIAL_4": "Lanzamisiles", + "SPECIAL_6": "Bola genializante", + "SPECIAL_7": "Emiteondas", + "SPECIAL_13": "Flotiburón", + "SPECIAL_3": "Gancho tentacular", + "SPECIAL_14": "Tornado triple", + "SPECIAL_1": "Tintazuca triple", + "SPECIAL_11": "Ultraselladora" } diff --git a/public/locales/fr/badges.json b/public/locales/fr/badges.json new file mode 100644 index 000000000..d5cb0789e --- /dev/null +++ b/public/locales/fr/badges.json @@ -0,0 +1,9 @@ +{ + "patreon": "Supporteur sur le patreon de sendou.ink", + "patreon+": "Supporteur+ sur le patreon de sendou.ink", + "tournament_one": "Récompense pour avoir gagné le {{tournament}}", + "tournament_other": "Récompense pour avoir gagné le {{tournament}} (×{{count}})", + "forYourEvent": "Un badge pour votre événement ?", + "madeBy": "Badges créés par <2>borzoic", + "managedBy": "Géré par {{users}}" +} diff --git a/public/locales/fr/builds.json b/public/locales/fr/builds.json new file mode 100644 index 000000000..7cdfe922c --- /dev/null +++ b/public/locales/fr/builds.json @@ -0,0 +1,15 @@ +{ + "addBuild": "Ajouter un set", + "noBuilds": "Pas de sets disponibles. N'hésitez pas à en créer un !", + "buildCard.info": "Informations", + "buildCard.edit": "Éditer", + + "forms.title": "Titre", + "forms.modes": "Modes", + "forms.weapons": "Armes", + "forms.gear.HEAD": "Équipement (tête)", + "forms.gear.CLOTHES": "Équipement (haut)", + "forms.gear.SHOES": "Équipement (chaussures)", + + "deleteConfirm": "Effacer le build '{{title}}' ?" +} diff --git a/public/locales/fr/calendar.json b/public/locales/fr/calendar.json new file mode 100644 index 000000000..9c21457a6 --- /dev/null +++ b/public/locales/fr/calendar.json @@ -0,0 +1,52 @@ +{ + "inYourTimeZone": "Times in your local time zone:", + "addNew": "Ajouter un événement", + "noEvents": "Aucun événement pour la semaine sélectionnée", + "reportResults": "Vous pouvez déclarer les résultats :", + "day": "Jour {{number}}", + "actions.reportWinners": "Déclarer les gagnants", + "participatedCount": "{{count}} équipes ont participé", + "members": "Membres", + "results": "Résultats", + + "forms.dates": "Dates", + "forms.bracketUrl": "Lien du bracket", + "forms.discordInvite": "Lien d'invitation du Discord", + "forms.tags": "Tags", + "forms.tags.placeholder": "Choisir un tag", + "forms.tags.info": "Le tag \"Badge à gagner\" est ajouté automatiquement si le tournoi est éligible", + "forms.badges": "Badge à gagner", + "forms.badges.placeholder": "Choose a badge prize", + + "forms.participantCount": "Nombre de participants", + "forms.reportResultsHeader": "Déclarer les résultats pour {{eventName}}", + "forms.reportResultsInfo": "Les résultats déclarés peuvent être personnalisés. Vous pouvez uniquement déclarer le gagnant, le top 3, ou tout ce que vous décidez.", + "forms.team.add": "Ajouter une équipe", + "forms.team.remove": "Retirer une équipe", + "forms.team.name": "Nom de l'équipe", + "forms.team.placing": "Position", + + "forms.team.player.header": "Joueur {{number}}", + "forms.team.player.add": "Ajouter un joueur", + "forms.team.player.remove": "Retirer un joueur", + "forms.team.player.addAsUser": "Ajouter en tant qu'utilisateur (recommandé)", + "forms.team.player.addAsText": "Ajouter en tant que texte", + + "forms.errors.uniqueTeamName": "Chaque équipe doit avoir un nom unique.", + "forms.errors.duplicatePlayer": "Il est impossible d'avoir le même joueur plusieurs fois dans la même équipe.", + "forms.errors.emptyTeam": "Chaque équipe doit au moins avoir un joueur.", + + "week.this": "Semaine Actuelle", + "week.next": "Semaine Suivante", + "week.last": "Semaine Précédente", + + "tag.desc.BADGE": "Le gagnant de cet événement gagnera un badge sendou.ink.", + "tag.desc.SPECIAL": "Le réglement peut différer du standard, par exemple avec une sélection limitée d'armes", + "tag.desc.ART": "Il est possible de gagner une illustration dans ce tournoi.", + "tag.desc.MONEY": "Il est possible de gagner de l'argent dans ce tournoi.", + "tag.desc.REGION": "Seules des personnes vivant dans certains pays peuvent participer à ce tournoi.", + "tag.desc.LOW": "Seules les personnes d'un certain niveau peuvent participer à ce tournoi.", + "tag.desc.COUNT": "Le nombre de places est limité.", + "tag.desc.LAN": "Cet événement est joué en local.", + "tag.desc.QUALIFIER": "Ce tournoi fait partie d'une qualification pour un autre événement." +} diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json new file mode 100644 index 000000000..2d0689286 --- /dev/null +++ b/public/locales/fr/common.json @@ -0,0 +1,43 @@ +{ + "pages.admin": "Admin", + "pages.badges": "Badges", + "pages.plus": "Plus Server", + "pages.contributors": "Contributeurs", + "pages.calendar": "Calendrier", + "pages.faq": "FAQ", + "pages.builds": "Builds", + + "header.profile": "Profil", + "header.logout": "Déconnexion", + "header.login": "Connexion", + + "footer.github.subtitle": "Code source", + "footer.twitter.subtitle": "Mises à jour", + "footer.discord.subtitle": "Aide & retours", + "footer.patreon.subtitle": "Soutenir le projet", + "footer.thanks": "Merci aux patrons pour le soutien", + + "actions.save": "Sauvegarder", + "actions.saving": "Sauvegarde...", + "actions.submit": "Envoyer", + "actions.edit": "Éditer", + "actions.add": "Ajouter", + "actions.remove": "Retirer", + "actions.delete": "Effacer", + + "results": "Résultats", + + "forms.name": "Nom", + "forms.description": "Description", + "forms.errors.title": "Les erreurs ci-dessous doivent être réglés", + + "tag.name.BADGE": "Badge à gagner", + "tag.name.SPECIAL": "Règles spéciales", + "tag.name.ART": "Illustration à gagner", + "tag.name.MONEY": "Argent à gagner", + "tag.name.REGION": "Region locked", + "tag.name.LOW": "Skill cap", + "tag.name.COUNT": "Entry limit", + "tag.name.LAN": "LAN", + "tag.name.QUALIFIER": "Qualifications" +} diff --git a/public/locales/fr/contributions.json b/public/locales/fr/contributions.json new file mode 100644 index 000000000..bdf0579df --- /dev/null +++ b/public/locales/fr/contributions.json @@ -0,0 +1,6 @@ +{ + "project": "Sendou.ink est un projet créé par <2>Sendou avec l'aide de contributeurs :", + "lean": "A aidé à découvrir les fonctionnements internes de Splatoon et a créé le bot Lanista", + "borzoic": "A créé les badges, les icônes et l'illustration de la page d'accueil", + "uberu": "A dessiné l'émote de Mini Charbitre portant un cœur" +} diff --git a/public/locales/fr/faq.json b/public/locales/fr/faq.json new file mode 100644 index 000000000..98e4e924a --- /dev/null +++ b/public/locales/fr/faq.json @@ -0,0 +1,10 @@ +{ + "q1": "Qu'est-ce que le Plus Server ?", + "a1": "Le Plus Server est un serveur Discord destiné aux joueurs occidentaux de haut niveau cherchant des gens avec qui jouer ensemble ou contre. Il a été fondé en Septembre 2017. Il est divisé en 3 tiers, avec le +1 étant le plus haut. Vous pouvez y avoir accès si un des membres du serveurs vous recommande et si vous passez le vote mensuel.\n\nPendant le vote, vous recevrez un pourcentage basé sur votre résultat. Si vous avez reçu 0%, cela veut dire que tout le monde a voté contre vous, si vous avez reçu 100%, cela signifie donc l'inverse. Si un membre reçoit un score inférieur à 50%, il descendra d'un tier, et dans le cas du +3, il sera expulsé.", + + "q2": "Comment obtenir un badge pour mon événement ?", + "a2": "Il vous faudra commissionner borzoic#1991 pour créer un badge. Le prix peut varier entre 10€ et 30€ en fonction de la complexité. Après ça, cantactez Sendou pour que le badge soit ajouté à la page web.\n\nTous les tournois peuvent avoir un badge pour récompense. Si vous voulez récompenser d'autres actions avec un badge, contactez tout d'abord Sendou avec votre idée", + + "q3": "Comment mettre à jour mon pseudo ou mon avatar ?", + "a3": "Mettre à jour son pseudo ou avatar sur Discord ne se reflète pas immédiatement sur sendou.ink. Pour voir ce changement, vous avez deux options :\n\n1) Si vous êtes un membre du Discord de sendou.ink ou du Plus Server, il vous suffit d'attendre. Le site se mettra à jour automatiquement dans les 24 heures.\n\n2) Alternativement, si vous voulez les mettre à jour immédiatement, vous pouvez vous déconnecter et vous reconnecter sur sendou.ink" +} diff --git a/public/locales/fr/front.json b/public/locales/fr/front.json new file mode 100644 index 000000000..3e4894bcd --- /dev/null +++ b/public/locales/fr/front.json @@ -0,0 +1,10 @@ +{ + "websiteSubtitle": "Hub du Splatoon Compétitif", + "calendarGoTo": "Regardez tous les événements passés et à venir sur la page du calendrier", + "moreFeatures": "Plus de fonctionnalités", + "plus.description": "Regardez l'historique de vote du Plus Server et d'autres informations", + "badges.description": "La liste de tous les badges que vous pouvez recevoir sur votre profil", + "recentWinners": "Gagnants récents", + "upcomingEvents": "Événements à venir", + "articleBy": "par {{author}}" +} diff --git a/public/locales/fr/gear.json b/public/locales/fr/gear.json index 9e5cdbce4..f18fa1b9b 100644 --- a/public/locales/fr/gear.json +++ b/public/locales/fr/gear.json @@ -1,6 +1,7 @@ { "H_1": "Bandeau blanc", "H_1000": "Casquette baseball", + "C_1000": "T-shirt blanc", "S_1000": "Tennis bleues", "C_1001": "T-shirt OculR noir", "H_1002": "Casquette filet Cubic", @@ -24,12 +25,15 @@ "C_1021": "T-shirt 8 bits noir", "S_1021": "Flexi-tabis wasabi", "S_1022": "Tennis suédine simples", + "S_1023": "Baskets palourde noires", "S_1024": "Tennis suédine pro", "H_1028": "Casquette à rabats noire", "C_1035": "T-shirt col en V blanc", "H_1036": "Bonnet de docker", "C_1062": "Tri-shirt déchiré", + "C_1063": "Tandem OculR", "C_1066": "T-shirt à collier Aroz", + "C_1067": "T-shirt bracelets Aroz", "C_1069": "T-shirt bleu rétro", "C_1070": "T-shirt beige rétro", "C_1071": "Écharpe Alpaj", @@ -44,9 +48,11 @@ "C_1084": "T-shirt dégradé vapeur", "C_1085": "T-shirt dégradé crépuscule", "C_1088": "T-shirt ophidien", + "C_1090": "T-shirt smiley limette", "C_1091": "T-shirt smiley framboise", "S_2000": "Hippo montantes rouges", "S_2001": "Hippo montantes zombi", + "S_2003": "Hippo montantes violettes", "C_2004": "Haut sportif Ezko", "S_2004": "Tennis montantes algue", "S_2005": "Tennis montantes rouges", @@ -58,10 +64,13 @@ "S_2043": "Octaskets rouges", "S_2045": "Bottes perle HU1T73", "C_3000": "Haut double blanc", + "S_3000": "Baskets roses", "H_3001": "Masque de plongée", "C_3001": "Haut double moutarde", "S_3001": "Flèches orange", + "H_3002": "Lunettes d'aviateur", "H_3003": "Lunettes colorées", + "C_3004": "Haut double Leviathus", "S_3004": "Baskets turquoise", "C_3006": "Haut double Cubic", "H_3008": "Lunettes de soleil 18 carats", @@ -74,18 +83,24 @@ "H_3016": "Lunettes de natation", "S_3020": "Baskets translux", "H_3021": "Verres teintés", + "H_3022": "Monture 8 bits", "S_3022": "Turbo-tabis rouges", + "H_3023": "Monture sans verres", "S_3023": "AL-GA 30XX", + "H_3024": "Lunettes 3-en-1", "S_3024": "Baskets mandarine", "H_3025": "Lunettes transparentes", "S_3025": "Tennis montantes mako", "H_3026": "Lunettes de moto", + "S_3026": "Baskets crevettes bleues", "H_3027": "Lunettes carrées Aroz", + "H_3029": "Lunettes rétro SV925", "S_4000": "Sabots huître", "S_4001": "Sabots chocolat", "H_4004": "Chapeau zen", "C_4004": "Polo noir Ezko", "C_4005": "Maillot de cycliste", + "H_4006": "Canotier sombre", "S_4007": "Sandales fluo", "H_4008": "Bob", "S_4008": "Tongs noires", @@ -94,14 +109,17 @@ "C_4010": "Haut quadri DUX 08", "S_4011": "Claquettes rouges Friture", "S_4012": "Claquettes jaunes Friture", + "S_4014": "Sandales arêtes", "H_4015": "Chapeau melon", "S_4015": "Flèches ouvertes bleues", "H_4016": "Bob en jean", "S_4016": "Tongs smiley", "H_4017": "Chapeau de cowboy orné", "S_4017": "Sandales chunky orange", + "H_4019": "Chapeau de plage", "S_4021": "Sandales chunky roses", "S_4022": "Sandales chunky cyan", + "H_5000": "Casque pro", "C_5000": "Anorak vert anis", "S_5000": "Chaussures rando", "H_5001": "Casque coloré", @@ -133,7 +151,10 @@ "S_6007": "Bottines punk grenat", "C_6008": "Maillot des Umibozu (dom.)", "S_6012": "Bottes de chasse", + "S_6020": "Bottes sécurité graffiti", "S_6021": "Bottes Palmi poudreuse", + "S_6023": "Bottes rouquin-marteau", + "S_6025": "Bottines punk roses", "C_7001": "Sweat jaune Kalamarus Rex", "S_7002": "Mocassins pied-de-poulpe", "H_7007": "Casque de hockey", @@ -155,6 +176,7 @@ "S_8013": "Chukkas sable", "H_8014": "Masque smiley", "S_8014": "Chaussures bateau café", + "H_8015": "Masque oxy-zen", "H_8016": "Écran facialamar", "C_8017": "Chemisette punk farniente", "C_8018": "Chemisette de bowling", @@ -173,6 +195,62 @@ "H_9009": "Bandeau de ping-pong", "C_9010": "Gilet forestier kaki", "C_9011": "Crustarapace rouge", + "C_9012": "Crustarapace limette", + "C_9013": "Gilet splash", "C_10006": "Sweat capuche gris", - "C_10012": "Sweat ethnique magma" + "C_10012": "Sweat ethnique magma", + "C_10014": "Sweat ethnique azur", + "H_21010": "Casquette dorade", + "H_25000": "Barrette seiche", + "C_25000": "Uniforme scolaire A", + "S_25000": "Mocassins scolaires d'hiver", + "H_25001": "Casque de samouraï", + "C_25001": "Haut de samouraï", + "S_25001": "Bottes de samouraï", + "H_25002": "Casque méca", + "C_25002": "Armure méca", + "S_25002": "Bottes méca", + "H_25003": "Boucles d'oreilles seiche", + "C_25003": "Gilet scolaire A", + "S_25003": "Mocassins à franges d'hiver", + "H_25004": "Masque de ninja Mk II", + "C_25004": "Tenue de ninja", + "S_25004": "Bottes de ninja", + "H_25005": "Casque méca Mk I", + "C_25005": "Armure méca Mk I", + "S_25005": "Bottes méca Mk I", + "H_25006": "Petite couronne princière", + "C_25006": "Sweat à capuche princier", + "S_25006": "Compensées princières", + "H_25007": "Casque coralien", + "C_25007": "Top coralien", + "S_25007": "Mocassins coraliens", + "H_25008": "Chapeau magique", + "C_25008": "Tunique magique A", + "S_25008": "Bottines magiques", + "H_25009": "Casque d'Octaguerrier", + "C_25009": "Armure d'Octaguerrier", + "S_25009": "Solerets d'Octaguerrier", + "H_25010": "Tête de mascotte", + "C_25010": "Mains de mascotte", + "S_25010": "Pieds de mascotte", + "C_25014": "Uniforme scolaire B", + "S_25014": "Mocassins scolaires", + "C_25015": "Gilet scolaire B", + "S_25015": "Mocassins à franges", + "H_25016": "Masque de ninja Mk I", + "H_25017": "Grande couronne princière", + "C_25017": "Tunique magique B", + "C_26000": "T-shirt festif", + "H_27000": "Casque héroïque (réplique)", + "C_27000": "Veste héroïque (réplique)", + "S_27000": "Baskets héroïques (répliques)", + "H_27004": "Casque encrifugé (réplique)", + "C_27004": "Anorak encrifugé (réplique)", + "S_27004": "Bottes encrifugées (répl.)", + "H_27109": "Serre-tête ourson", + "H_27306": "Neurocasque héroïque (répl.)", + "C_27306": "Panoplie héroïque (réplique)", + "S_27306": "Boots héroïques (répliques)", + "H_28000": "Casquette Omar" } diff --git a/public/locales/fr/user.json b/public/locales/fr/user.json new file mode 100644 index 000000000..deda734d2 --- /dev/null +++ b/public/locales/fr/user.json @@ -0,0 +1,10 @@ +{ + "country": "Pays", + "bio": "Bio", + + "results.placing": "Résultats", + "results.team": "Équipe", + "results.tournament": "Tournoi", + "results.date": "Date", + "results.mates": "Équipiers" +} diff --git a/public/locales/fr/weapons.json b/public/locales/fr/weapons.json index c6a374477..e8427db89 100644 --- a/public/locales/fr/weapons.json +++ b/public/locales/fr/weapons.json @@ -1,55 +1,86 @@ { - "0": "Marqueur lourd", - "10": "Liquidateur Jr.", - "20": "Marqueur léger", - "30": "Aérogun", - "40": "Liquidateur", - "50": "Calibre 2000", - "60": "N-ZAP 85", - "70": "Liquidateur pro", - "80": "Calibre 3000", - "90": "Nettoyeur XL", - "200": "Proxiblaster", - "210": "Éclablaster", - "220": "Éclablaster XL", - "230": "Rafablaster", - "240": "Turboblaster", - "250": "Turboblaster pro", - "300": "Arroseur léger", - "310": "Arroseur lourd", - "400": "Compresseur", - "1000": "Rouleau carbone", - "1010": "Rouleau", - "1020": "Dynamo-rouleau", - "1030": "Flexi-rouleau", - "1100": "Épinceau", - "1110": "Épinceau brosse", - "2000": "Décap'express Alpha", - "2010": "Concentraceur", - "2020": "Concentraceur zoom", - "2030": "Extraceur +", - "2040": "Extraceur + zoom", - "2050": "Bimbamboum Mk I", - "2060": "Détubeur", - "3000": "Seauceur", - "3010": "Dépoteur", - "3020": "Encrifugeur", - "3030": "Bassineur", - "3040": "Détoneur", - "4000": "Badigeonneur XS", - "4010": "Badigeonneur", - "4020": "Exteinteur", - "4030": "Badigeonneur stylo", - "4040": "Nautilus 47", - "5000": "Double moucheteur", - "5010": "Double encreur", - "5020": "Double Kelvin 525", - "5030": "Double nettoyeur", - "5040": "Double voltigeur noir", - "6000": "Para-encre", - "6010": "Para-encre XL", - "6020": "Para-encre espion", - "7010": "Trisperceur", - "8000": "Éclatana d'estampe", - "8010": "Éclatana Doto" + "MAIN_250": "Turboblaster pro", + "MAIN_230": "Rafablaster", + "MAIN_240": "Turboblaster", + "MAIN_220": "Éclablaster XL", + "MAIN_210": "Éclablaster", + "MAIN_200": "Proxiblaster", + "MAIN_1100": "Épinceau", + "MAIN_1110": "Épinceau brosse", + "MAIN_2060": "Détubeur", + "MAIN_2050": "Bimbamboum Mk I", + "MAIN_2040": "Extraceur + zoom", + "MAIN_2030": "Extraceur +", + "MAIN_2020": "Concentraceur zoom", + "MAIN_2010": "Concentraceur", + "MAIN_2000": "Décap'express Alpha", + "MAIN_5030": "Double nettoyeur", + "MAIN_5020": "Double Kelvin 525", + "MAIN_5010": "Double encreur", + "MAIN_5000": "Double moucheteur", + "MAIN_5040": "Double voltigeur noir", + "MAIN_1000": "Rouleau carbone", + "MAIN_1020": "Dynamo-rouleau", + "MAIN_1030": "Flexi-rouleau", + "MAIN_1010": "Rouleau", + "MAIN_8010": "Éclatana Doto", + "MAIN_8000": "Éclatana d'estampe", + "MAIN_6020": "Para-encre espion", + "MAIN_6000": "Para-encre", + "MAIN_6010": "Para-encre XL", + "MAIN_30": "Aérogun", + "MAIN_70": "Liquidateur pro", + "MAIN_10": "Liquidateur Jr.", + "MAIN_400": "Compresseur", + "MAIN_50": "Calibre 2000", + "MAIN_80": "Calibre 3000", + "MAIN_90": "Nettoyeur XL", + "MAIN_40": "Liquidateur", + "MAIN_45": "Lanceur héroïque (réplique)", + "MAIN_20": "Marqueur léger", + "MAIN_60": "N-ZAP 85", + "MAIN_0": "Marqueur lourd", + "MAIN_310": "Arroseur lourd", + "MAIN_300": "Arroseur léger", + "MAIN_3030": "Bassineur", + "MAIN_3010": "Dépoteur", + "MAIN_3020": "Encrifugeur", + "MAIN_3000": "Seauceur", + "MAIN_3040": "Détoneur", + "MAIN_4030": "Badigeonneur stylo", + "MAIN_4020": "Exteinteur", + "MAIN_4000": "Badigeonneur XS", + "MAIN_4040": "Nautilus 47", + "MAIN_4010": "Badigeonneur", + "MAIN_7010": "Trisperceur", + "MAIN_7020": "Coralux 450", + "SUB_8": "Balise de saut", + "SUB_6": "Bombe curling", + "SUB_5": "Bombe soda", + "SUB_2": "Bombe ballon", + "SUB_7": "Bombe robot", + "SUB_0": "Bombe splash", + "SUB_1": "Bombe gluante", + "SUB_13": "Bentorpille", + "SUB_12": "Ricocheur", + "SUB_9": "Détecteur", + "SUB_11": "Brume toxique", + "SUB_4": "Mur d'encre", + "SUB_3": "Fontaine", + "SUB_10": "Mine", + "SPECIAL_8": "Aspirencre", + "SPECIAL_12": "Crabe d'assaut", + "SPECIAL_15": "Districool", + "SPECIAL_2": "Super bouclier", + "SPECIAL_5": "Pluie d'encre", + "SPECIAL_10": "Chromo-jet", + "SPECIAL_9": "Haut-perceur 5.1", + "SPECIAL_4": "Multi-missile", + "SPECIAL_6": "Jolizator", + "SPECIAL_7": "Sonar paf", + "SPECIAL_13": "Cavalsquale", + "SPECIAL_3": "Super Mollusque", + "SPECIAL_14": "Trimissile tornade", + "SPECIAL_1": "Lance-rafales", + "SPECIAL_11": "Ultra-tamponneur" } diff --git a/public/locales/it/gear.json b/public/locales/it/gear.json index c3e088969..ebff60c4e 100644 --- a/public/locales/it/gear.json +++ b/public/locales/it/gear.json @@ -1,6 +1,7 @@ { "H_1": "Fascia bianca", "H_1000": "Berretto AS Riccidimare", + "C_1000": "T-shirt bianca", "S_1000": "Basse blu", "C_1001": "T-shirt neroseppia", "H_1002": "Berretto Sepia", @@ -24,12 +25,15 @@ "C_1021": "T-shirt 8 bit nera", "S_1021": "Sneaker senza lacci", "S_1022": "Scamosciate semplici", + "S_1023": "Vongosneaker nere", "S_1024": "Scamosciate boss", "H_1028": "Cappello paraorecchie nero", "C_1035": "T-shirt bianca ciclista", "H_1036": "Berretto da portuale", "C_1062": "Cala-shirt strappata", + "C_1063": "T-shirt bivalve Arome", "C_1066": "T-shirt Annak (collare)", + "C_1067": "T-shirt Annak (bracciali)", "C_1069": "T-shirt azzurra rétro", "C_1070": "T-shirt cachi rétro", "C_1071": "Scialle BaraS", @@ -44,9 +48,11 @@ "C_1084": "T-shirt vaporosa", "C_1085": "T-shirt crepuscolare", "C_1088": "T-shirt draganguilla", + "C_1090": "T-shirt SmileMob verde", "C_1091": "T-shirt SmileMob fucsia", "S_2000": "Alte biancorosse", "S_2001": "Alte zombie", + "S_2003": "Alte gialloviola", "C_2004": "Maglia Ezko", "S_2004": "Sneaker verde scuro", "S_2005": "Sneaker rosse", @@ -58,10 +64,13 @@ "S_2043": "Octosneaker rosse", "S_2045": "OSTR1K color perla", "C_3000": "A strati bianca", + "S_3000": "Runner rosa", "H_3001": "Maschera da sub", "C_3001": "A strati gialla", "S_3001": "Arrow arancioblu", + "H_3002": "Occhiali da pilota", "H_3003": "Occhiali colorati", + "C_3004": "A strati Totanic", "S_3004": "Runner verdeacqua", "C_3006": "A strati marrone", "H_3008": "Occhiali da sole 18K", @@ -74,18 +83,24 @@ "H_3016": "Occhialetti da nuoto", "S_3020": "Sneaker medusa", "H_3021": "Occhiali con lenti colorate", + "H_3022": "Occhiali pixellati", "S_3022": "Sneaker turbo rosse", + "H_3023": "Occhiali senza lenti", "S_3023": "AL-GA 30XX", + "H_3024": "Occhiali tripli", "S_3024": "Zeppe tangerine", "H_3025": "Occhiali discreti", "S_3025": "Sneaker predatrici", "H_3026": "Occhiali da motociclista", + "S_3026": "Sneakeretti blu", "H_3027": "Occhiali Annak", + "H_3029": "Occhiali blufocali rétro", "S_4000": "Zoccoli grigi", "S_4001": "Zoccoli marroni", "H_4004": "Cappello orientale", "C_4004": "Polo nera", "C_4005": "Maglia da ciclista", + "H_4006": "Cappello di paglia classico", "S_4007": "Sandali a strappo neon", "H_4008": "Cappello da pescatore", "S_4008": "Ciabatte da mare", @@ -94,14 +109,17 @@ "C_4010": "Maglia rugby 8", "S_4011": "Ciabatte rosse", "S_4012": "Ciabatte cool", + "S_4014": "Sandalisca di pesce", "H_4015": "Bombetta", "S_4015": "Open toe blu", "H_4016": "Cappello da pesca denim", "S_4016": "Ciabatte SmileMob", "H_4017": "Cappello da cowboy", "S_4017": "Fluosandali arancioni", + "H_4019": "Cappello di paglia", "S_4021": "Fluosandali rosa", "S_4022": "Fluosandali celesti", + "H_5000": "Cuffie pro", "C_5000": "Giacca da sci verde", "S_5000": "Scarpe da trekking", "H_5001": "Cuffie colorate", @@ -133,7 +151,10 @@ "S_6007": "Anfibi melanzana", "C_6008": "Maglia Umibozu", "S_6012": "Stivali da caccia", + "S_6020": "Scarponi SkipJack", "S_6021": "Anfibi artici", + "S_6023": "Stivali squalo martello", + "S_6025": "Anfibi rosa", "C_7001": "Maglione CalamaX", "S_7002": "Espadrillas hip-hop", "H_7007": "Casco da hockey", @@ -155,6 +176,7 @@ "S_8013": "Scarpe da deserto", "H_8014": "Mascherina SmileMob", "S_8014": "Scarpe da vela marroni", + "H_8015": "Respiratore", "H_8016": "Paramento rosso", "C_8017": "Camicia da turista", "C_8018": "Camicia da octobowling", @@ -173,6 +195,62 @@ "H_9009": "Fascia classica", "C_9010": "Gilet militare cachi", "C_9011": "Granchiorazza rossa", + "C_9012": "Granchiorazza verde", + "C_9013": "Maglia schizzata con gilet", "C_10006": "Felpa grigia con cappuccio", - "C_10012": "Maglia baja rossa" + "C_10012": "Maglia baja rossa", + "C_10014": "Maglia baja celeste", + "H_21010": "Cappello pescoso", + "H_25000": "Fermaglio calamaro", + "C_25000": "Uniforme scolastica A", + "S_25000": "Mocassini neri (calze)", + "H_25001": "Elmo da samurai", + "C_25001": "Armatura samurai", + "S_25001": "Calzature da samurai", + "H_25002": "Maschera hi-tech", + "C_25002": "Armatura hi-tech", + "S_25002": "Stivali hi-tech", + "H_25003": "Orecchini calamaro", + "C_25003": "Cardigan scolastico A", + "S_25003": "Mocassini con frangia (calze)", + "H_25004": "Maschera ninja II", + "C_25004": "Giacca ninja", + "S_25004": "Stivali ninja", + "H_25005": "Prototipo di maschera hi-tech", + "C_25005": "Prototipo di armatura hi-tech", + "S_25005": "Prototipo di stivali hi-tech", + "H_25006": "Corona di Alga (S)", + "C_25006": "Parka di Alga", + "S_25006": "Scarpe di Alga", + "H_25007": "Cuffie di Nori", + "C_25007": "Top di Nori", + "S_25007": "Scarpe di Nori", + "H_25008": "Cappello stregonesco", + "C_25008": "Vestito stregonesco A", + "S_25008": "Stivaletti stregoneschi", + "H_25009": "Elmo da octoguerriero", + "C_25009": "Corazza da octoguerriero", + "S_25009": "Calzari da octoguerriero", + "H_25010": "Testona da mascotte", + "C_25010": "Manone da mascotte", + "S_25010": "Piedoni da mascotte", + "C_25014": "Uniforme scolastica B", + "S_25014": "Mocassini neri (base)", + "C_25015": "Cardigan scolastico B", + "S_25015": "Mocassini con frangia (base)", + "H_25016": "Maschera ninja I", + "H_25017": "Corona di Alga (L)", + "C_25017": "vestito stregonesco B", + "C_26000": "T-shirt festival", + "H_27000": "Cuffie élite replica", + "C_27000": "Giubbino élite replica", + "S_27000": "Runner élite replica", + "H_27004": "Casco d'armatura replica", + "C_27004": "Giacca d'armatura replica", + "S_27004": "Stivali d'armatura replica", + "H_27109": "Orecchie da orso", + "H_27306": "Auricolari élite replica", + "C_27306": "Divisa élite replica", + "S_27306": "Stivali élite replica", + "H_28000": "Cuffia croc-stacea" } diff --git a/public/locales/it/weapons.json b/public/locales/it/weapons.json index 1ab3c3900..f3ba34bc1 100644 --- a/public/locales/it/weapons.json +++ b/public/locales/it/weapons.json @@ -1,55 +1,86 @@ { - "0": "Marker", - "10": "Sparacolore recluta", - "20": "Marker d'assalto", - "30": "Aerografo", - "40": "Splasher", - "50": "Calibro 2000", - "60": "N-ZAP85", - "70": "Splasher élite", - "80": "Calibro 3000", - "90": "Sweeper", - "200": "Blaster lunar", - "210": "Blaster", - "220": "Blaster a distanza", - "230": "Blaster da mischia", - "240": "Blaster rapido", - "250": "Blaster élite", - "300": "Triplete compatto", - "310": "Triplete", - "400": "Strizzer", - "1000": "Rullo di carbonio", - "1010": "Rullo splat", - "1020": "Rullo dinamo", - "1030": "Flexi-rullo", - "1100": "Calamaravaggio", - "1110": "Tinturicchio", - "2000": "Kalamarapid α", - "2010": "Splatter a carica", - "2020": "Splatter con mirino", - "2030": "Tinter a carica 4K", - "2040": "Tinter con mirino 4K", - "2050": "Bimbamboom 14-I", - "2060": "Tintubator", - "3000": "Secchiostro", - "3010": "Secchiostro triplo", - "3020": "Secchiostro centrifuga", - "3030": "Secchiostro vasca", - "3040": "Termosecchiostro", - "4000": "Mini splatling", - "4010": "Splatling a tanica", - "4020": "Idrante", - "4030": "Tetrapenna", - "4040": "Nautilus 47", - "5000": "Ripolpella duplo", - "5010": "Repolper duplo", - "5020": "Kelvin duplo 525", - "5030": "Sweeper duplo", - "5040": "Moscarpino duplo nero", - "6000": "Sparasole", - "6010": "Sparatenda", - "6020": "Bombrello", - "7010": "Tri-calamarco", - "8000": "Splattalama", - "8010": "Tergilama" + "MAIN_250": "Blaster élite", + "MAIN_230": "Blaster da mischia", + "MAIN_240": "Blaster rapido", + "MAIN_220": "Blaster a distanza", + "MAIN_210": "Blaster", + "MAIN_200": "Blaster lunar", + "MAIN_1100": "Calamaravaggio", + "MAIN_1110": "Tinturicchio", + "MAIN_2060": "Tintubator", + "MAIN_2050": "Bimbamboom 14-I", + "MAIN_2040": "Tinter con mirino 4K", + "MAIN_2030": "Tinter a carica 4K", + "MAIN_2020": "Splatter con mirino", + "MAIN_2010": "Splatter a carica", + "MAIN_2000": "Kalamarapid α", + "MAIN_5030": "Sweeper duplo", + "MAIN_5020": "Kelvin duplo 525", + "MAIN_5010": "Repolper duplo", + "MAIN_5000": "Ripolpella duplo", + "MAIN_5040": "Moscarpino duplo nero", + "MAIN_1000": "Rullo di carbonio", + "MAIN_1020": "Rullo dinamo", + "MAIN_1030": "Flexi-rullo", + "MAIN_1010": "Rullo splat", + "MAIN_8010": "Tergilama", + "MAIN_8000": "Splattalama", + "MAIN_6020": "Bombrello", + "MAIN_6000": "Sparasole", + "MAIN_6010": "Sparatenda", + "MAIN_30": "Aerografo", + "MAIN_70": "Splasher élite", + "MAIN_10": "Sparacolore recluta", + "MAIN_400": "Strizzer", + "MAIN_50": "Calibro 2000", + "MAIN_80": "Calibro 3000", + "MAIN_90": "Sweeper", + "MAIN_40": "Splasher", + "MAIN_45": "Pistola élite replica", + "MAIN_20": "Marker d'assalto", + "MAIN_60": "N-ZAP85", + "MAIN_0": "Marker", + "MAIN_310": "Triplete", + "MAIN_300": "Triplete compatto", + "MAIN_3030": "Secchiostro vasca", + "MAIN_3010": "Secchiostro triplo", + "MAIN_3020": "Secchiostro centrifuga", + "MAIN_3000": "Secchiostro", + "MAIN_3040": "Termosecchiostro", + "MAIN_4030": "Tetrapenna", + "MAIN_4020": "Idrante", + "MAIN_4000": "Mini splatling", + "MAIN_4040": "Nautilus 47", + "MAIN_4010": "Splatling a tanica", + "MAIN_7010": "Tri-calamarco", + "MAIN_7020": "ARCO-RAL 450", + "SUB_8": "Trasferitore", + "SUB_6": "Bomba curling", + "SUB_5": "Bomba a gassosa", + "SUB_2": "Granata", + "SUB_7": "Robo-bomba", + "SUB_0": "Bomba splash", + "SUB_1": "Appiccibomba", + "SUB_13": "Torpedinatore", + "SUB_12": "Sparalinee", + "SUB_9": "Cimice", + "SUB_11": "Nebbia tossica", + "SUB_4": "Muro di colore", + "SUB_3": "Spruzzatore", + "SUB_10": "Mina", + "SPECIAL_8": "Vampinchiostro", + "SPECIAL_12": "Granchio armato", + "SPECIAL_15": "Rinfrigorente", + "SPECIAL_2": "Gran bolla scudo", + "SPECIAL_5": "Pioggia di colore", + "SPECIAL_10": "Jet splat", + "SPECIAL_9": "Tintofono 5.1", + "SPECIAL_4": "Lanciarazzi", + "SPECIAL_6": "Granbotto", + "SPECIAL_7": "Sonar esplosivo", + "SPECIAL_13": "Motosqualo", + "SPECIAL_3": "Molluscatto", + "SPECIAL_14": "Triplo tornado", + "SPECIAL_1": "Ultraturbinator", + "SPECIAL_11": "Mega timbro" } diff --git a/public/locales/ja/gear.json b/public/locales/ja/gear.json index a711974d2..a4d31a92a 100644 --- a/public/locales/ja/gear.json +++ b/public/locales/ja/gear.json @@ -1,6 +1,7 @@ { "H_1": "ヘッドバンド ホワイト", "H_1000": "ウーニーズBBキャップ", + "C_1000": "イカホワイト", "S_1000": "グリッチョ ブルー", "C_1001": "イカノメT ブラック", "H_1002": "ヤコメッシュ", @@ -24,12 +25,15 @@ "C_1021": "ヤキフグ8bit ブラック", "S_1021": "NNJグリーン", "S_1022": "ザ・ベース ルーキー", + "S_1023": "クラム600 カンロ", "S_1024": "ザ・ベース ボス", "H_1028": "シェーディングキャップ スミ", "C_1035": "イカホワイトV", "H_1036": "フィッシャーマンキャップ", "C_1062": "サキイカホワイト", + "C_1063": "アロメT ゴブゴブ", "C_1066": "アナアキT チョーカー", + "C_1067": "アナアキT アシメブレス", "C_1069": "リイシューT ブルー", "C_1070": "リイシューT ブラウン", "C_1071": "バラズシ ノリマキ", @@ -44,9 +48,11 @@ "C_1084": "トワイライトグラデT", "C_1085": "サンセットグラデT", "C_1088": "ガブリエルT", + "C_1090": "スシズメブロブ ライム", "C_1091": "スシズメブロブ ベリー", "S_2000": "シーホースHi レッド", "S_2001": "シーホースHi ゾンビ", + "S_2003": "シーホースHi パープル", "C_2004": "エゾッコラグラン", "S_2004": "キャンバスHi モロヘイヤ", "S_2005": "キャンバスHi トマト", @@ -58,10 +64,13 @@ "S_2043": "テンヤ8 レッド", "S_2045": "01STER コハク", "C_3000": "レイヤード ホワイト", + "S_3000": "ピンクビーンズ", "H_3001": "スプラッシュゴーグル", "C_3001": "マスタードガサネ", "S_3001": "オレンジアローズ", + "H_3002": "パイロットゴーグル", "H_3003": "イロメガネ", + "C_3004": "アイロニックレイヤード", "S_3004": "シアンビーンズ", "C_3006": "チョコガサネ", "H_3008": "タレサン18K", @@ -74,18 +83,24 @@ "H_3016": "スイミングモーグル", "S_3020": "イカサシ スクランブル", "H_3021": "デメニギスゴーグル", + "H_3022": "8ビットフレーム", "S_3022": "MOVEレッド", + "H_3023": "ワイヤーグラス", "S_3023": "MODZ-9", + "H_3024": "サンサンサングラス", "S_3024": "シェルバシラWO", "H_3025": "フロート クリアグラス", "S_3025": "フカヒレニマイバ", "H_3026": "バイカーシェード", + "S_3026": "シャコナックル", "H_3027": "アナアキスクエアグラス", + "H_3029": "タマサンBC925", "S_4000": "オイスタークロッグ", "S_4001": "チョコクロッグ", "H_4004": "スゲ", "C_4004": "ピンポンポロ", "C_4005": "テッカサイクルシャツ", + "H_4006": "イカンカン クラシック", "S_4007": "デルタストラップ ネオン", "H_4008": "イカバケット", "S_4008": "BBサンダル", @@ -94,14 +109,17 @@ "C_4010": "キングラガー008", "S_4011": "ヤキフグシャワサン アカ", "S_4012": "ヤキフグシャワサン キ", + "S_4014": "フィッシュボーンワラチ", "H_4015": "ボーラークラシック", "S_4015": "アローズサンダル アオキ", "H_4016": "ステンシルデニムハット", "S_4016": "BSサンダル", "H_4017": "ホタテンガロン", "S_4017": "べリべリサン オレンジ", + "H_4019": "ストローハット", "S_4021": "べリべリサン マゼンタ", "S_4022": "べリべリサン シアン", + "H_5000": "スタジオヘッドホン", "C_5000": "マウンテンオリーブ", "S_5000": "トレッキングライト", "H_5001": "オーロラヘッドホン", @@ -133,7 +151,10 @@ "S_6007": "ロッキンチェリー", "C_6008": "ウミボーズ ホーム", "S_6012": "ハンティングブーツ", + "S_6020": "ヌバックブーツxSJ", "S_6021": "ダックブーツ スノウ", + "S_6023": "カセブカブーツ レッド", + "S_6025": "ロッキンピンク", "C_7001": "イカバッテン マスタード", "S_7002": "スリッポン チドリ", "H_7007": "イカロスHKメット", @@ -155,6 +176,7 @@ "S_8013": "チャッカブーツ サンド", "H_8014": "ブロブスマイルマスク", "S_8014": "デッキシューズ フカイリ", + "H_8015": "エラブリースマスク", "H_8016": "トンビシールドR255", "C_8017": "ピーターパンクシャツ", "C_8018": "タコボウラーシャツ", @@ -173,6 +195,62 @@ "H_9009": "ピンポンバンド", "C_9010": "ハンティングベストKK", "C_9011": "タカアシプロテクターレッド", + "C_9012": "タカアシプロテクターライム", + "C_9013": "スミチラシベスト", "C_10006": "ホタパーカー グレー", - "C_10012": "バハフーディー ロホ" + "C_10012": "バハフーディー ロホ", + "C_10014": "バハフーディー セレステ", + "H_21010": "イトヨリキャップ", + "H_25000": "イカパッチン", + "C_25000": "スクールブレザーL", + "S_25000": "スクールローファー ハイソ", + "H_25001": "サムライヘルメット", + "C_25001": "サムライジャケット", + "S_25001": "サムライシューズ", + "H_25002": "パワードマスク", + "C_25002": "パワードスーツ", + "S_25002": "パワードレッグス", + "H_25003": "イカクリップ", + "C_25003": "スクールカーデ リボン", + "S_25003": "キルトローファー ルーズ", + "H_25004": "イカカゲマスク乙", + "C_25004": "ニンジャスーツ", + "S_25004": "シノビアシ", + "H_25005": "パワードマスク オリジン", + "C_25005": "パワードスーツ オリジン", + "S_25005": "パワードレッグス オリジン", + "H_25006": "ヒメイトクラウンS", + "C_25006": "ヒメイトパーカー", + "S_25006": "ヒメイトスニーカー", + "H_25007": "イイダチヘッドホン", + "C_25007": "イイダチトップス", + "S_25007": "イイダチスリッポン", + "H_25008": "エンチャントハット", + "C_25008": "エンチャントローブS", + "S_25008": "エンチャントブーツ", + "H_25009": "タコティカルなヘルム", + "C_25009": "タコティカルなよろい", + "S_25009": "タコティカルなすねあて", + "H_25010": "ひれおくん", + "C_25010": "ひれおくんのて", + "S_25010": "ひれおくんのあし", + "C_25014": "スクールブレザーR", + "S_25014": "スクールローファー スゲソ", + "C_25015": "スクールカーデ ネクタイ", + "S_25015": "キルトローファー スゲソ", + "H_25016": "イカカゲマスク甲", + "H_25017": "ヒメイトクラウンL", + "C_25017": "エンチャントローブL", + "C_26000": "フェスT", + "H_27000": "ヒーローヘッズ レプリカ", + "C_27000": "ヒーロージャケット レプリカ", + "S_27000": "ヒーローキックス レプリカ", + "H_27004": "アーマーメット レプリカ", + "C_27004": "アーマージャケット レプリカ", + "S_27004": "アーマーブーツ レプリカ", + "H_27109": "クマノミミ", + "H_27306": "ヒーローブレイン レプリカ", + "C_27306": "ヒーロースーツ レプリカ", + "S_27306": "ヒーローブーツ レプリカ", + "H_28000": "ロブキャップ" } diff --git a/public/locales/ja/weapons.json b/public/locales/ja/weapons.json index 6cad717ba..0e27c7b7c 100644 --- a/public/locales/ja/weapons.json +++ b/public/locales/ja/weapons.json @@ -1,55 +1,86 @@ { - "0": "ボールドマーカー", - "10": "わかばシューター", - "20": "シャープマーカー", - "30": "プロモデラーMG", - "40": "スプラシューター", - "50": ".52ガロン", - "60": "N-ZAP85", - "70": "プライムシューター", - "80": ".96ガロン", - "90": "ジェットスイーパー", - "200": "ノヴァブラスター", - "210": "ホットブラスター", - "220": "ロングブラスター", - "230": "クラッシュブラスター", - "240": "ラピッドブラスター", - "250": "Rブラスターエリート", - "300": "L3リールガン", - "310": "H3リールガン", - "400": "ボトルガイザー", - "1000": "カーボンローラー", - "1010": "スプラローラー", - "1020": "ダイナモローラー", - "1030": "ヴァリアブルローラー", - "1100": "パブロ", - "1110": "ホクサイ", - "2000": "スクイックリンα", - "2010": "スプラチャージャー", - "2020": "スプラスコープ", - "2030": "リッター4K", - "2040": "4Kスコープ", - "2050": "14式竹筒銃・甲", - "2060": "ソイチューバー", - "3000": "バケットスロッシャー", - "3010": "ヒッセン", - "3020": "スクリュースロッシャー", - "3030": "オーバーフロッシャー", - "3040": "エクスプロッシャー", - "4000": "スプラスピナー", - "4010": "バレルスピナー", - "4020": "ハイドラント", - "4030": "クーゲルシュライバー", - "4040": "ノーチラス47", - "5000": "スパッタリー", - "5010": "スプラマニューバー", - "5020": "ケルビン525", - "5030": "デュアルスイーパー", - "5040": "クアッドホッパーブラック", - "6000": "パラシェルター", - "6010": "キャンピングシェルター", - "6020": "スパイガジェット", - "7010": "トライストリンガー", - "8000": "ジムワイパー", - "8010": "ドライブワイパー" + "MAIN_250": "Rブラスターエリート", + "MAIN_230": "クラッシュブラスター", + "MAIN_240": "ラピッドブラスター", + "MAIN_220": "ロングブラスター", + "MAIN_210": "ホットブラスター", + "MAIN_200": "ノヴァブラスター", + "MAIN_1100": "パブロ", + "MAIN_1110": "ホクサイ", + "MAIN_2060": "ソイチューバー", + "MAIN_2050": "14式竹筒銃・甲", + "MAIN_2040": "4Kスコープ", + "MAIN_2030": "リッター4K", + "MAIN_2020": "スプラスコープ", + "MAIN_2010": "スプラチャージャー", + "MAIN_2000": "スクイックリンα", + "MAIN_5030": "デュアルスイーパー", + "MAIN_5020": "ケルビン525", + "MAIN_5010": "スプラマニューバー", + "MAIN_5000": "スパッタリー", + "MAIN_5040": "クアッドホッパーブラック", + "MAIN_1000": "カーボンローラー", + "MAIN_1020": "ダイナモローラー", + "MAIN_1030": "ヴァリアブルローラー", + "MAIN_1010": "スプラローラー", + "MAIN_8010": "ドライブワイパー", + "MAIN_8000": "ジムワイパー", + "MAIN_6020": "スパイガジェット", + "MAIN_6000": "パラシェルター", + "MAIN_6010": "キャンピングシェルター", + "MAIN_30": "プロモデラーMG", + "MAIN_70": "プライムシューター", + "MAIN_10": "わかばシューター", + "MAIN_400": "ボトルガイザー", + "MAIN_50": ".52ガロン", + "MAIN_80": ".96ガロン", + "MAIN_90": "ジェットスイーパー", + "MAIN_40": "スプラシューター", + "MAIN_45": "ヒーローシューター レプリカ", + "MAIN_20": "シャープマーカー", + "MAIN_60": "N-ZAP85", + "MAIN_0": "ボールドマーカー", + "MAIN_310": "H3リールガン", + "MAIN_300": "L3リールガン", + "MAIN_3030": "オーバーフロッシャー", + "MAIN_3010": "ヒッセン", + "MAIN_3020": "スクリュースロッシャー", + "MAIN_3000": "バケットスロッシャー", + "MAIN_3040": "エクスプロッシャー", + "MAIN_4030": "クーゲルシュライバー", + "MAIN_4020": "ハイドラント", + "MAIN_4000": "スプラスピナー", + "MAIN_4040": "ノーチラス47", + "MAIN_4010": "バレルスピナー", + "MAIN_7010": "トライストリンガー", + "MAIN_7020": "LACT-450", + "SUB_8": "ジャンプビーコン", + "SUB_6": "カーリングボム", + "SUB_5": "タンサンボム", + "SUB_2": "クイックボム", + "SUB_7": "ロボットボム", + "SUB_0": "スプラッシュボム", + "SUB_1": "キューバンボム", + "SUB_13": "トーピード", + "SUB_12": "ラインマーカー", + "SUB_9": "ポイントセンサー", + "SUB_11": "ポイズンミスト", + "SUB_4": "スプラッシュシールド", + "SUB_3": "スプリンクラー", + "SUB_10": "トラップ", + "SPECIAL_8": "キューインキ", + "SPECIAL_12": "カニタンク", + "SPECIAL_15": "エナジースタンド", + "SPECIAL_2": "グレートバリア", + "SPECIAL_5": "アメフラシ", + "SPECIAL_10": "ジェットパック", + "SPECIAL_9": "メガホンレーザー5.1ch", + "SPECIAL_4": "マルチミサイル", + "SPECIAL_6": "ナイスダマ", + "SPECIAL_7": "ホップソナー", + "SPECIAL_13": "サメライド", + "SPECIAL_3": "ショクワンダー", + "SPECIAL_14": "トリプルトルネード", + "SPECIAL_1": "ウルトラショット", + "SPECIAL_11": "ウルトラハンコ" } diff --git a/public/locales/ko/gear.json b/public/locales/ko/gear.json index 8aa38c562..c5bed2fe3 100644 --- a/public/locales/ko/gear.json +++ b/public/locales/ko/gear.json @@ -1,6 +1,7 @@ { "H_1": "화이트 헤드밴드", "H_1000": "우니즈 BB 캡", + "C_1000": "화이트 오징어 T", "S_1000": "블루 로우톱", "C_1001": "블랙 오징어 눈 T", "H_1002": "라이즈 메시 캡", @@ -24,12 +25,15 @@ "C_1021": "블랙 8bit 복어구이", "S_1021": "그린 NNJ", "S_1022": "더 베이스 루키", + "S_1023": "다크 클램 600", "S_1024": "더 베이스 보스", "H_1028": "블랙 셰이딩 캡", "C_1035": "화이트 오징어 V", "H_1036": "피셔맨 캡", "C_1062": "화이트 오징어채 T", + "C_1063": "아로메 반반 T", "C_1066": "아나키 초커 T", + "C_1067": "아나키 브레이슬릿 T", "C_1069": "블루 리이슈 T", "C_1070": "브라운 리이슈 T", "C_1071": "화이트아웃 김말이 T", @@ -44,9 +48,11 @@ "C_1084": "트와일라이트 그러데이션 T", "C_1085": "선셋 그러데이션 T", "C_1088": "가브리엘 T", + "C_1090": "라임 블랍몹 T", "C_1091": "베리 블랍몹 T", "S_2000": "레드 시 호스 Hi", "S_2001": "좀비 시 호스 Hi", + "S_2003": "퍼플 시 호스 Hi", "C_2004": "제코 래글런 LS", "S_2004": "헌터 캔버스 Hi", "S_2005": "레드 캔버스 Hi", @@ -58,10 +64,13 @@ "S_2043": "레드 텐야 8", "S_2045": "호박 01STER", "C_3000": "화이트 레이어드 T", + "S_3000": "핑크 스니커즈", "H_3001": "스플래시 고글", "C_3001": "머스터드 레이어드 T", "S_3001": "오렌지 애로", + "H_3002": "파일럿 고글", "H_3003": "색안경", + "C_3004": "아이로닉 레이어드 T", "S_3004": "시안 스니커즈", "C_3006": "초콜릿 레이어드 T", "H_3008": "18K 보잉 선글라스", @@ -74,18 +83,24 @@ "H_3016": "물안경", "S_3020": "오징어회 스크램블", "H_3021": "데메니기스 고글", + "H_3022": "8bit 프레임", "S_3022": "레드 MOVE", + "H_3023": "와이어 글라스", "S_3023": "E-JECT 30XX", + "H_3024": "선선선글라스", "S_3024": "WO 조개관자", "H_3025": "플로트 클리어 글라스", "S_3025": "더블 샥스핀", "H_3026": "바이커 셰이드", + "S_3026": "갯가재 너클", "H_3027": "아나키 스퀘어 글라스", + "H_3029": "BC925 오로라 선글라스", "S_4000": "오이스터 클로그", "S_4001": "초콜릿 클로그", "H_4004": "삿갓", "C_4004": "핑퐁 폴로셔츠", "C_4005": "사이클링 셔츠", + "H_4006": "클래식 오징어 보터", "S_4007": "네온 델타 스트랩", "H_4008": "오징어 버킷 해트", "S_4008": "블랙 플립플롭", @@ -94,14 +109,17 @@ "C_4010": "킹 러거 008", "S_4011": "빨강 복어구이 슬리퍼", "S_4012": "노랑 복어구이 슬리퍼", + "S_4014": "피시 본 우라치", "H_4015": "클래식 볼러", "S_4015": "블루&옐로 애로 샌들", "H_4016": "스텐실 데님 해트", "S_4016": "BS 플립플롭", "H_4017": "가리비 텐 갤런", "S_4017": "오렌지 벨크로 샌들", + "H_4019": "스트로 해트", "S_4021": "마젠타 벨크로 샌들", "S_4022": "시안 벨크로 샌들", + "H_5000": "스튜디오 헤드폰", "C_5000": "올리브 마운틴 재킷", "S_5000": "라이트 하이킹 부츠", "H_5001": "오로라 헤드폰", @@ -133,7 +151,10 @@ "S_6007": "체리 펑크 부츠", "C_6008": "우미보즈(홈)", "S_6012": "헌팅 부츠", + "S_6020": "누벅 부츠xSJ", "S_6021": "스노 덕 부츠", + "S_6023": "레드 귀상어 부츠", + "S_6025": "핑크 펑크 부츠", "C_7001": "머스터드 오징어 엑스 스웨트", "S_7002": "물떼새 슬립온", "H_7007": "이카로스 HK 헬멧", @@ -155,6 +176,7 @@ "S_8013": "샌드 처커 부츠", "H_8014": "블랍 스마일 마스크", "S_8014": "다크 로스트 덱 슈즈", + "H_8015": "아가미 러블리 마스크", "H_8016": "오징어입 실드 R255", "C_8017": "그레이 펑크 셔츠", "C_8018": "문어 볼러 셔츠", @@ -173,6 +195,62 @@ "H_9009": "핑퐁 밴드", "C_9010": "카키 헌팅 베스트", "C_9011": "레드 거미게 프로텍터", + "C_9012": "라임 거미게 프로텍터", + "C_9013": "잉크 묻은 베스트", "C_10006": "호리비 그레이 후드", - "C_10012": "레드 바하 후드" + "C_10012": "레드 바하 후드", + "C_10014": "블루 바하 후드", + "H_21010": "실꼬리 캡", + "H_25000": "오징어 머리핀", + "C_25000": "스쿨 유니폼 L", + "S_25000": "니 삭스 스쿨 로퍼", + "H_25001": "일본 무사 헬멧", + "C_25001": "일본 무사 재킷", + "S_25001": "일본 무사 슈즈", + "H_25002": "파워드 마스크", + "C_25002": "파워드 슈트", + "S_25002": "파워드 레그", + "H_25003": "오징어 클립", + "C_25003": "스쿨 리본 카디건", + "S_25003": "루즈 삭스 킬트 로퍼", + "H_25004": "오징어 그림자 마스크 을", + "C_25004": "닌자 슈트", + "S_25004": "닌자 부츠", + "H_25005": "파워드 마스크 오리진", + "C_25005": "파워드 슈트 오리진", + "S_25005": "파워드 레그 오리진", + "H_25006": "히메이트 크라운 S", + "C_25006": "히메이트 후드", + "S_25006": "히메이트 스니커즈", + "H_25007": "이이다치 헤드폰", + "C_25007": "이이다치 톱스", + "S_25007": "이이다치 슬립온", + "H_25008": "인챈트 해트", + "C_25008": "인챈트 로브 S", + "S_25008": "인챈트 부츠", + "H_25009": "문어티컬한 헬름", + "C_25009": "문어티컬한 갑옷", + "S_25009": "문어티컬한 레그 가드", + "H_25010": "히레오 헤드", + "C_25010": "히레오 글로브", + "S_25010": "히레오 슈즈", + "C_25014": "스쿨 유니폼 R", + "S_25014": "맨발 스쿨 로퍼", + "C_25015": "스쿨 넥타이 카디건", + "S_25015": "맨발 킬트 로퍼", + "H_25016": "오징어 그림자 마스크 갑", + "H_25017": "히메이트 크라운 L", + "C_25017": "인챈트 로브 L", + "C_26000": "페스티벌 T", + "H_27000": "히어로 헤드 레플리카", + "C_27000": "히어로 재킷 레플리카", + "S_27000": "히어로 킥스 레플리카", + "H_27004": "아머 헬멧 레플리카", + "C_27004": "아머 재킷 레플리카", + "S_27004": "아머 부츠 레플리카", + "H_27109": "곰 머리띠", + "H_27306": "히어로 브레인 레플리카", + "C_27306": "히어로 슈트 레플리카", + "S_27306": "히어로 부츠 레플리카", + "H_28000": "롭 캡" } diff --git a/public/locales/ko/weapons.json b/public/locales/ko/weapons.json index 725d532b3..480ecd272 100644 --- a/public/locales/ko/weapons.json +++ b/public/locales/ko/weapons.json @@ -1,55 +1,86 @@ { - "0": "볼드 마커", - "10": "새싹 슈터", - "20": "샤프 마커", - "30": "프로모델러 MG", - "40": "스플랫 슈터", - "50": ".52 갤런", - "60": "N-ZAP85", - "70": "프라임 슈터", - "80": ".96 갤런", - "90": "제트 스위퍼", - "200": "노바 블래스터", - "210": "핫 블래스터", - "220": "롱 블래스터", - "230": "크래시 블래스터", - "240": "래피드 블래스터", - "250": "R 블래스터 엘리트", - "300": "L3 릴 건", - "310": "H3 릴 건", - "400": "보틀 가이저", - "1000": "카본 롤러", - "1010": "스플랫 롤러", - "1020": "다이너모 롤러", - "1030": "베리어블 롤러", - "1100": "파블로", - "1110": "호쿠사이", - "2000": "스퀵 클린 α", - "2010": "스플랫 차저", - "2020": "스플랫 스코프", - "2030": "리터 4K", - "2040": "4K 스코프", - "2050": "14식 대나무 총 갑", - "2060": "소이 튜버", - "3000": "버킷 슬로셔", - "3010": "물통", - "3020": "스크루 슬로셔", - "3030": "오버플로셔", - "3040": "익스플로셔", - "4000": "스플랫 스피너", - "4010": "배럴 스피너", - "4020": "하이드런트", - "4030": "쿠겔 슈라이버", - "4040": "노틸러스 47", - "5000": "스퍼터리", - "5010": "스플랫 머누버", - "5020": "켈빈 525", - "5030": "듀얼 스위퍼", - "5040": "블랙 쿼드 호퍼", - "6000": "파라 셸터", - "6010": "캠핑 셸터", - "6020": "스파이 가젯", - "7010": "트라이 스트링거", - "8000": "사무 와이퍼", - "8010": "드라이브 와이퍼" + "MAIN_250": "R 블래스터 엘리트", + "MAIN_230": "크래시 블래스터", + "MAIN_240": "래피드 블래스터", + "MAIN_220": "롱 블래스터", + "MAIN_210": "핫 블래스터", + "MAIN_200": "노바 블래스터", + "MAIN_1100": "파블로", + "MAIN_1110": "호쿠사이", + "MAIN_2060": "소이 튜버", + "MAIN_2050": "14식 대나무 총 갑", + "MAIN_2040": "4K 스코프", + "MAIN_2030": "리터 4K", + "MAIN_2020": "스플랫 스코프", + "MAIN_2010": "스플랫 차저", + "MAIN_2000": "스퀵 클린 α", + "MAIN_5030": "듀얼 스위퍼", + "MAIN_5020": "켈빈 525", + "MAIN_5010": "스플랫 머누버", + "MAIN_5000": "스퍼터리", + "MAIN_5040": "블랙 쿼드 호퍼", + "MAIN_1000": "카본 롤러", + "MAIN_1020": "다이너모 롤러", + "MAIN_1030": "베리어블 롤러", + "MAIN_1010": "스플랫 롤러", + "MAIN_8010": "드라이브 와이퍼", + "MAIN_8000": "사무 와이퍼", + "MAIN_6020": "스파이 가젯", + "MAIN_6000": "파라 셸터", + "MAIN_6010": "캠핑 셸터", + "MAIN_30": "프로모델러 MG", + "MAIN_70": "프라임 슈터", + "MAIN_10": "새싹 슈터", + "MAIN_400": "보틀 가이저", + "MAIN_50": ".52 갤런", + "MAIN_80": ".96 갤런", + "MAIN_90": "제트 스위퍼", + "MAIN_40": "스플랫 슈터", + "MAIN_45": "히어로 슈터 레플리카", + "MAIN_20": "샤프 마커", + "MAIN_60": "N-ZAP85", + "MAIN_0": "볼드 마커", + "MAIN_310": "H3 릴 건", + "MAIN_300": "L3 릴 건", + "MAIN_3030": "오버플로셔", + "MAIN_3010": "물통", + "MAIN_3020": "스크루 슬로셔", + "MAIN_3000": "버킷 슬로셔", + "MAIN_3040": "익스플로셔", + "MAIN_4030": "쿠겔 슈라이버", + "MAIN_4020": "하이드런트", + "MAIN_4000": "스플랫 스피너", + "MAIN_4040": "노틸러스 47", + "MAIN_4010": "배럴 스피너", + "MAIN_7010": "트라이 스트링거", + "MAIN_7020": "LACT-450", + "SUB_8": "점프 비컨", + "SUB_6": "컬링 밤", + "SUB_5": "탄산 밤", + "SUB_2": "퀵 밤", + "SUB_7": "로봇 밤", + "SUB_0": "스플래시 밤", + "SUB_1": "빨판 밤", + "SUB_13": "토피도", + "SUB_12": "라인 마커", + "SUB_9": "포인트 센서", + "SUB_11": "포이즌 미스트", + "SUB_4": "스플래시 실드", + "SUB_3": "스프링클러", + "SUB_10": "트랩", + "SPECIAL_8": "흡입기", + "SPECIAL_12": "크랩 탱크", + "SPECIAL_15": "에너지 스탠드", + "SPECIAL_2": "그레이트 배리어", + "SPECIAL_5": "먹구름", + "SPECIAL_10": "제트 팩", + "SPECIAL_9": "메가폰 레이저 5.1ch", + "SPECIAL_4": "멀티 미사일", + "SPECIAL_6": "나이스옥", + "SPECIAL_7": "홉 소나", + "SPECIAL_13": "샤크 라이드", + "SPECIAL_3": "쇼크 원더", + "SPECIAL_14": "트리플 토네이도", + "SPECIAL_1": "울트라 샷", + "SPECIAL_11": "울트라 스탬프" } diff --git a/public/locales/nl/gear.json b/public/locales/nl/gear.json index a39cabea0..fd3b396a8 100644 --- a/public/locales/nl/gear.json +++ b/public/locales/nl/gear.json @@ -1,6 +1,7 @@ { "H_1": "Witte hoofdband", "H_1000": "Honkbalpet", + "C_1000": "Wit T-shirt", "S_1000": "Blauwe Lo-Tops", "C_1001": "Zwart octopusoog-T-shirt", "H_1002": "Takoroka-pet", @@ -24,12 +25,15 @@ "C_1021": "Zwart pixel-T-shirt", "S_1021": "Wasabi-tabisneakers", "S_1022": "Witte suède sneakers", + "S_1023": "Zwarte mosselsneakers", "S_1024": "Zwarte suède sneakers", "H_1028": "Zwarte pet met flappen", "C_1035": "Wit T-shirt met V-hals", "H_1036": "Dokwerkerspet", "C_1062": "Verscheurd Tri-shirt", + "C_1063": "Combi-Tentatek-T-shirt", "C_1066": "Annaki-shirt en choker", + "C_1067": "Annaki-shirt en armbanden", "C_1069": "Blauw retro-T-shirt", "C_1070": "Beige retro-T-shirt", "C_1071": "Barazushi-shawl", @@ -44,9 +48,11 @@ "C_1084": "Avondtinten-T-shirt", "C_1085": "Ochtendtinten-T-shirt", "C_1088": "Aalzebub-T-shirt", + "C_1090": "Limetten-BlobMob-T-shirt", "C_1091": "Bessen-BlobMob-T-shirt", "S_2000": "Rode hoge sneakers", "S_2001": "Hoge zombiesneakers", + "S_2003": "Paarse Hi-Tops", "C_2004": "Zekko-honkbalshirt", "S_2004": "Groene Hi-Tops", "S_2005": "Rode Hi-Tops", @@ -58,10 +64,13 @@ "S_2043": "Rode basketbalschoenen", "S_2045": "Parelwitte 03ST3Rs", "C_3000": "Wit laagjesshirt", + "S_3000": "Roze sportschoenen", "H_3001": "Duikbril", "C_3001": "Geel laagjesshirt", "S_3001": "Oranje pijlsneakers", + "H_3002": "Pilotenbril", "H_3003": "Getinte zonnebril", + "C_3004": "Zink-laagjesshirt", "S_3004": "Turquoise sportschoenen", "C_3006": "Bruin laagjesshirt", "H_3008": "18K aviatorbril", @@ -74,18 +83,24 @@ "H_3016": "Zwembril", "S_3020": "Transparante sandalen", "H_3021": "Getinte bril", + "H_3022": "Pixelbril", "S_3022": "Rode turbo-tabisneakers", + "H_3023": "Bril zonder glazen", "S_3023": "A.L.G. 30XX", + "H_3024": "Driedubbeldekkerbril", "S_3024": "Oranje gespsneakers", "H_3025": "Stiekeme bril", "S_3025": "Haaienvinsneakers", "H_3026": "Motorzonnebril", + "S_3026": "Blauwe scampisneakers", "H_3027": "Hoekige Annaki-bril", + "H_3029": "Ronde bril met blauw glas", "S_4000": "Grijze klompen", "S_4001": "Bruine klompen", "H_4004": "Bamboehoed", "C_4004": "Zwarte polo", "C_4005": "Wielertrui", + "H_4006": "Klassieke strohoed", "S_4007": "Neon sandalen", "H_4008": "Vissershoed", "S_4008": "Zwarte teenslippers", @@ -94,14 +109,17 @@ "C_4010": "King-rugbyshirt 08", "S_4011": "Rode badslippers", "S_4012": "Gele badslippers", + "S_4014": "Sepiasandalen", "H_4015": "Bolhoed", "S_4015": "Blauwe pijlsandalen", "H_4016": "Spijkerstofvissershoed", "S_4016": "BlobMob-teenslippers", "H_4017": "Howdy-hoed", "S_4017": "Oranje plastic sandalen", + "H_4019": "Strandhoed", "S_4021": "Roze plastic sandalen", "S_4022": "Turquoise plastic sandalen", + "H_5000": "Studiokoptelefoon", "C_5000": "Olijfgroen ski-jack", "S_5000": "Wandelschoenen", "H_5001": "Designerkoptelefoon", @@ -133,7 +151,10 @@ "S_6007": "Rode punkschoenen", "C_6008": "Umibozu-jersey (thuis)", "S_6012": "Jachtlaarzen", + "S_6020": "Skipjack-werkschoenen", "S_6021": "Witte halfrubberen laarzen", + "S_6023": "Rode hamerhaailaarzen", + "S_6025": "Roze punkschoenen", "C_7001": "SquidForce-trui", "S_7002": "Instappers met patroon", "H_7007": "IJshockeyhelm", @@ -155,6 +176,7 @@ "S_8013": "Kaki hoge schoenen", "H_8014": "BlobMob-mondkapje", "S_8014": "Donkerbruine bootschoenen", + "H_8015": "Zuurstofmasker Pro", "H_8016": "Kraakcommando-schild", "C_8017": "Visaas-overhemd", "C_8018": "Octobowler-hemd", @@ -173,6 +195,62 @@ "H_9009": "Tafeltennishoofdband", "C_9010": "Kaki boswachteroverhemd", "C_9011": "Rood krabbenpantser", + "C_9012": "Groen krabbenpantser", + "C_9013": "Vlekkenvest", "C_10006": "Grijze hoody", - "C_10012": "Rode wereldse hoody" + "C_10012": "Rode wereldse hoody", + "C_10014": "Blauwe wereldse hoody", + "H_21010": "Snapperpet", + "H_25000": "Inktvishaarspeld", + "C_25000": "Schooluniform A", + "S_25000": "Schoolschoenen", + "H_25001": "Samoeraihelm", + "C_25001": "Samoeraitenue", + "S_25001": "Samoeraischoenen", + "H_25002": "Hightechhelm", + "C_25002": "Hightechpantser", + "S_25002": "Hightechschoenen", + "H_25003": "Inktvisoorbellen", + "C_25003": "Schoolvest A", + "S_25003": "Loafers met franje", + "H_25004": "Ninjamasker Ver. 2", + "C_25004": "Ninjapak", + "S_25004": "Ninjalaarzen", + "H_25005": "Hightechhelm (prototype)", + "C_25005": "Hightechpantser (prototype)", + "S_25005": "Hightechschoenen (prototype)", + "H_25006": "Loreleis kroon S", + "C_25006": "Loreleis hoody", + "S_25006": "Loreleis plateauschoenen", + "H_25007": "Mariana's koptelefoon", + "C_25007": "Mariana's topje", + "S_25007": "Mariana's instappers", + "H_25008": "Toverhoed", + "C_25008": "Tovergewaad A", + "S_25008": "Toverlaarzen", + "H_25009": "Octoridderhelm", + "C_25009": "Octoridderharnas", + "S_25009": "Octoridderlaarzen", + "H_25010": "Mascottehoofd", + "C_25010": "Mascottehandschoenen", + "S_25010": "Mascotteschoenen", + "C_25014": "Schooluniform B", + "S_25014": "Basisschoolschoenen", + "C_25015": "Schoolvest B", + "S_25015": "Basisloafers met franje", + "H_25016": "Ninjamasker Ver. 1", + "H_25017": "Loreleis kroon L", + "C_25017": "Tovergewaad B", + "C_26000": "Splatfest-T-shirt", + "H_27000": "Heldenheadset (replica)", + "C_27000": "Heldenjack (replica)", + "S_27000": "Heldenschoenen (replica)", + "H_27004": "Pantserhelm (replica)", + "C_27004": "Pantserjack (replica)", + "S_27004": "Pantserschoenen (replica)", + "H_27109": "Berenoortjes", + "H_27306": "Heldenneuroset (replica)", + "C_27306": "Heldenpak (replica)", + "S_27306": "Heldensneakers (replica)", + "H_28000": "Pelles pet" } diff --git a/public/locales/nl/weapons.json b/public/locales/nl/weapons.json index bd279818b..85762d05d 100644 --- a/public/locales/nl/weapons.json +++ b/public/locales/nl/weapons.json @@ -1,55 +1,86 @@ { - "0": "Spettertuit", - "10": "Superspetter jr.", - "20": "Spetterspuit", - "30": "Kladderwerper", - "40": "Superspetter", - "50": ".52 Kaliter", - "60": "N-ZAP '85", - "70": "Superspetter Pro", - "80": ".96 Kaliter", - "90": "Straalplonzer", - "200": "Lunablaster", - "210": "Klodderblaster", - "220": "Teleblaster", - "230": "Knalblaster", - "240": "Flitsblaster", - "250": "Flitsblaster Pro", - "300": "L-3 Stompsnuit", - "310": "H-3 Langsnuit", - "400": "Floeper", - "1000": "Carbonroller", - "1010": "Klodderroller", - "1020": "Dynamoroller", - "1030": "Flexroller", - "1100": "Inktkwast", - "1110": "Octokwast", - "2000": "Octopoets", - "2010": "Bloplader", - "2020": "Schelpschutter", - "2030": "E-liter 4K", - "2040": "E-liter 4K met vizier", - "2050": "Bamboem 14-A", - "2060": "Spetbuizer", - "3000": "Morser", - "3010": "Triomorser", - "3020": "Klotstrommel", - "3030": "Spatkuip", - "3040": "Kliederkachel", - "4000": "Mini-Spetling", - "4010": "Spetling", - "4020": "Blusling", - "4030": "Stylospetling", - "4040": "Nautilus 47", - "5000": "Dubbelspatters", - "5010": "Dubbelknallers", - "5020": "Kelvin 525", - "5030": "Dubbelplonzers", - "5040": "Quadhoppers Zwart", - "6000": "Plenzer", - "6010": "Kampeerplenzer", - "6020": "Paraplenzer", - "7010": "Triospanner", - "8000": "Stempelzwieper", - "8010": "Wisserbladzwieper" + "MAIN_250": "Flitsblaster Pro", + "MAIN_230": "Knalblaster", + "MAIN_240": "Flitsblaster", + "MAIN_220": "Teleblaster", + "MAIN_210": "Klodderblaster", + "MAIN_200": "Lunablaster", + "MAIN_1100": "Inktkwast", + "MAIN_1110": "Octokwast", + "MAIN_2060": "Spetbuizer", + "MAIN_2050": "Bamboem 14-A", + "MAIN_2040": "E-liter 4K met vizier", + "MAIN_2030": "E-liter 4K", + "MAIN_2020": "Schelpschutter", + "MAIN_2010": "Bloplader", + "MAIN_2000": "Octopoets", + "MAIN_5030": "Dubbelplonzers", + "MAIN_5020": "Kelvin 525", + "MAIN_5010": "Dubbelknallers", + "MAIN_5000": "Dubbelspatters", + "MAIN_5040": "Quadhoppers Zwart", + "MAIN_1000": "Carbonroller", + "MAIN_1020": "Dynamoroller", + "MAIN_1030": "Flexroller", + "MAIN_1010": "Klodderroller", + "MAIN_8010": "Wisserbladzwieper", + "MAIN_8000": "Stempelzwieper", + "MAIN_6020": "Paraplenzer", + "MAIN_6000": "Plenzer", + "MAIN_6010": "Kampeerplenzer", + "MAIN_30": "Kladderwerper", + "MAIN_70": "Superspetter Pro", + "MAIN_10": "Superspetter jr.", + "MAIN_400": "Floeper", + "MAIN_50": ".52 Kaliter", + "MAIN_80": ".96 Kaliter", + "MAIN_90": "Straalplonzer", + "MAIN_40": "Superspetter", + "MAIN_45": "Heldenspetter (replica)", + "MAIN_20": "Spetterspuit", + "MAIN_60": "N-ZAP '85", + "MAIN_0": "Spettertuit", + "MAIN_310": "H-3 Langsnuit", + "MAIN_300": "L-3 Stompsnuit", + "MAIN_3030": "Spatkuip", + "MAIN_3010": "Triomorser", + "MAIN_3020": "Klotstrommel", + "MAIN_3000": "Morser", + "MAIN_3040": "Kliederkachel", + "MAIN_4030": "Stylospetling", + "MAIN_4020": "Blusling", + "MAIN_4000": "Mini-Spetling", + "MAIN_4040": "Nautilus 47", + "MAIN_4010": "Spetling", + "MAIN_7010": "Triospanner", + "MAIN_7020": "RIF-LEX 450", + "SUB_8": "Springschotel", + "SUB_6": "Curlingbom", + "SUB_5": "Bomblikje", + "SUB_2": "Ballonbom", + "SUB_7": "Robobom", + "SUB_0": "Klodderbom", + "SUB_1": "Kleefbom", + "SUB_13": "Torpedobom", + "SUB_12": "Ketskogel", + "SUB_9": "Detector", + "SUB_11": "Gifmist", + "SUB_4": "Inktgordijn", + "SUB_3": "Inktsprinkler", + "SUB_10": "Inktmijn", + "SPECIAL_8": "Inktdief", + "SPECIAL_12": "Krabbentank", + "SPECIAL_15": "Reddingsbar", + "SPECIAL_2": "Joekelschild", + "SPECIAL_5": "Spetterbui", + "SPECIAL_10": "Inktjet", + "SPECIAL_9": "Megalofoon 5.1", + "SPECIAL_4": "Spetterraketten", + "SPECIAL_6": "Coole bom", + "SPECIAL_7": "Golfbeker", + "SPECIAL_13": "Opblaashaai", + "SPECIAL_3": "Tentakabel", + "SPECIAL_14": "Tri-tornado", + "SPECIAL_1": "Trizooka", + "SPECIAL_11": "Ultrastempel" } diff --git a/public/locales/ru/badges.json b/public/locales/ru/badges.json new file mode 100644 index 000000000..6e6775b24 --- /dev/null +++ b/public/locales/ru/badges.json @@ -0,0 +1,9 @@ +{ + "patreon": "Supporter для sendou.ink на Patreon", + "patreon+": "Supporter+ для sendou.ink на Patreon", + "tournament_one": "Награда за победу в {{tournament}}", + "tournament_other": "Награда за победу в {{tournament}} (×{{count}})", + "forYourEvent": "Значок для вашего события?", + "madeBy": "Значки от <2>borzoic", + "managedBy": "Выдаётся {{users}}" +} diff --git a/public/locales/ru/builds.json b/public/locales/ru/builds.json new file mode 100644 index 000000000..a2ecb6fb6 --- /dev/null +++ b/public/locales/ru/builds.json @@ -0,0 +1,15 @@ +{ + "addBuild": "Добавить сборку", + "noBuilds": "Сборок пока нет. Добавьте свою первую!", + "buildCard.info": "Инфо", + "buildCard.edit": "Изменить", + + "forms.title": "Название", + "forms.modes": "Режимы", + "forms.weapons": "Оружия", + "forms.gear.HEAD": "Снаряжение (аксессуары)", + "forms.gear.CLOTHES": "Снаряжение (одежда)", + "forms.gear.SHOES": "Снаряжение (обувь)", + + "deleteConfirm": "Удалить сборку '{{title}}'?" +} diff --git a/public/locales/ru/calendar.json b/public/locales/ru/calendar.json new file mode 100644 index 000000000..20407405a --- /dev/null +++ b/public/locales/ru/calendar.json @@ -0,0 +1,52 @@ +{ + "inYourTimeZone": "Время указано для вашего часового пояса:", + "addNew": "Добавить новое", + "noEvents": "Нет событий для выбранной недели", + "reportResults": "Вы можете указать результаты:", + "day": "День {{number}}", + "actions.reportWinners": "Указать победителя", + "participatedCount": "{{count}} команд приняло участие", + "members": "Участники", + "results": "Результаты", + + "forms.dates": "Даты", + "forms.bracketUrl": "URL сетки", + "forms.discordInvite": "URL приглашения на Discord-сервер", + "forms.tags": "Теги", + "forms.tags.placeholder": "Выберите тег", + "forms.tags.info": "Тег \"Призовые значки\" добавляется автоматически, если это возможно", + "forms.badges": "Призовые значки", + "forms.badges.placeholder": "Выберите призовой значок", + + "forms.participantCount": "Количество участников", + "forms.reportResultsHeader": "Указать результаты для {{eventName}}", + "forms.reportResultsInfo": "Вы можете указать столько результатов, сколько сочтёте нужным. Это может быть команда победителей, топ-3 или как вы сами захотите.", + "forms.team.add": "Добавить команду", + "forms.team.remove": "Убрать команду", + "forms.team.name": "Название команды", + "forms.team.placing": "Место", + + "forms.team.player.header": "Игрок {{number}}", + "forms.team.player.add": "Добавить игрока", + "forms.team.player.remove": "Убрать игрока", + "forms.team.player.addAsUser": "Добавить как пользователя (рекомендуется)", + "forms.team.player.addAsText": "Добавить как текст", + + "forms.errors.uniqueTeamName": "У каждой команды должно быть уникальное имя.", + "forms.errors.duplicatePlayer": "Нельзя иметь одного и того же участника дважды в одной команде.", + "forms.errors.emptyTeam": "Каждая команда должна иметь как минимум одного игрока.", + + "week.this": "Эта неделя", + "week.next": "Следующая неделя", + "week.last": "Прошлая неделя", + + "tag.desc.BADGE": "Победитель турнира получается значок на sendou.ink.", + "tag.desc.SPECIAL": "Набор правил, отличающийся от стандартных — например, ограниченный пул оружия.", + "tag.desc.ART": "Играя в этом турнире вы можете выиграть арт.", + "tag.desc.MONEY": "Играя в этом турнире вы можете выиграть денежный приз.", + "tag.desc.REGION": "Ограничение участников по местоположению", + "tag.desc.LOW": "Ограничение участников по навыкам игры", + "tag.desc.COUNT": "Может зарегистрироваться только ограниченное количество команд.", + "tag.desc.LAN": "Этот турнир играется локально.", + "tag.desc.QUALIFIER": "Этот турнир является квалификационным для другого." +} diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json new file mode 100644 index 000000000..57108bdaf --- /dev/null +++ b/public/locales/ru/common.json @@ -0,0 +1,43 @@ +{ + "pages.admin": "Админ", + "pages.badges": "Значки", + "pages.plus": "Plus Server", + "pages.contributors": "Помощники", + "pages.calendar": "Календарь", + "pages.faq": "FAQ", + "pages.builds": "Сборки", + + "header.profile": "Профиль", + "header.logout": "Выйти", + "header.login": "Войти", + + "footer.github.subtitle": "Исходный код", + "footer.twitter.subtitle": "Обновления", + "footer.discord.subtitle": "Помощь и обратная связь", + "footer.patreon.subtitle": "Поддержать", + "footer.thanks": "Спасибо меценатам за поддержку", + + "actions.save": "Сохранить", + "actions.saving": "Сохранение...", + "actions.submit": "Опубликовать", + "actions.edit": "Изменить", + "actions.add": "Добавить", + "actions.remove": "Убрать", + "actions.delete": "Удалить", + + "results": "Результаты", + + "forms.name": "Название", + "forms.description": "Описание", + "forms.errors.title": "Указанные ошибки должны быть исправлены", + + "tag.name.BADGE": "Призовые значки", + "tag.name.SPECIAL": "Особые правила", + "tag.name.ART": "Арт-призы", + "tag.name.MONEY": "Днежные призы", + "tag.name.REGION": "Ограничение по региону", + "tag.name.LOW": "Ограничение по скиллу", + "tag.name.COUNT": "Лимит участников", + "tag.name.LAN": "LAN", + "tag.name.QUALIFIER": "Квалификационный" +} diff --git a/public/locales/ru/contributions.json b/public/locales/ru/contributions.json new file mode 100644 index 000000000..7ed68f9dc --- /dev/null +++ b/public/locales/ru/contributions.json @@ -0,0 +1,7 @@ +{ + "project": "Sendou.ink это проект, созданный <2>Sendou с поддержкой помощников:", + "code": "Помощники, внесшие изменения в код", + "lean": "Помощь с исследованием внутренностей Splatoon и создатель бота Lanista", + "borzoic": "Создатель рисунка на главной странице, а также значков и иконок", + "uberu": "Нарисовал Судокотика, держащего эмодзи-сердце" +} diff --git a/public/locales/ru/faq.json b/public/locales/ru/faq.json new file mode 100644 index 000000000..fb1112148 --- /dev/null +++ b/public/locales/ru/faq.json @@ -0,0 +1,10 @@ +{ + "q1": "Что такое Plus Server?", + "a1": "Plus Server — это Discord-сервер для высокоуровных игроков западного региона для поиска как напарников, так и соперников. Он был основан в сентябре 2017 года. Разделен на три уровня, где +1 — самый высокий. Вы можете получить доступ к нему, если участник сервера предложит вас и вы пройдёте ежемесячное голосование.\n\nВ голосовании вы получаете процент в зависимости от его результата. 0% означает, что все проголосовали против вас, в то время как 100% означает ровно противоположное. Для прохождения требуется набрать минимум 50%. Если участник набрал меньше 50%, он опускается на уровень ниже, а если у него был +3 — то он покидает сервер.", + + "q2": "Как получить призовой значок для моего события?", + "a2": "Вы можете заказать значок у borzoic#1991. Цена — 10-30€ в зависимости от сложности. После этого связитесь с Sendou, чтобы добавить её на страницу.\n\nЛюбой турнир может иметь значок в качестве награды. Если вы хотите награждать значком за какие-то другие достижения — то лучше сначала обсудить эту идею с Sendou.", + + "q3": "Как обновить мой аватар или ник?", + "a3": "Обновление ника или аватара в Discord не сразу обновляет их на sendou.ink. Есть два варианта, когда это произойдёт:\n\n1) Если вы есть на Discord-сервере этого сайта или Plus Server, то вы можете просто подожать. Ежедневно запускается специальная процедура, которая занимается обновлением.\n\n2) Если вы хотите обновиться прямо сейчас, то вы можете разлогиниться и залогиниться обратно на sendou.ink." +} diff --git a/public/locales/ru/front.json b/public/locales/ru/front.json new file mode 100644 index 000000000..c4c73e7c8 --- /dev/null +++ b/public/locales/ru/front.json @@ -0,0 +1,10 @@ +{ + "websiteSubtitle": "Соревновательный Splatoon-хаб", + "calendarGoTo": "Посмотреть все прошлые и предстоящие события на странице календаря", + "moreFeatures": "Больше возможностей", + "plus.description": "Посмотреть историю голосования Plus Server (и не только)", + "badges.description": "Список всех значков, которые можно заработать для своего профиля", + "recentWinners": "Недавние победители", + "upcomingEvents": "Предстоящие события", + "articleBy": "от {{author}}" +} diff --git a/public/locales/ru/gear.json b/public/locales/ru/gear.json index 920526b7b..cd301af77 100644 --- a/public/locales/ru/gear.json +++ b/public/locales/ru/gear.json @@ -1,6 +1,7 @@ { "H_1": "Белая повязка", "H_1000": "Бейсболка БК «Ежи»", + "C_1000": "Белая майка", "S_1000": "Синие сникеры", "C_1001": "Черная кальмарка", "H_1002": "Тракер от «Рыбок»", @@ -24,12 +25,15 @@ "C_1021": "«Фугасик-ретро» черная", "S_1021": "Таби «Васаби»", "S_1022": "Полукеды «Нубик»", + "S_1023": "Темные устрокроссы", "S_1024": "Полукеды «Профи»", "H_1028": "Черная кепка с ушами", "C_1035": "Белая майка с вырезом", "H_1036": "Шапка-докер", "C_1062": "Майка «Рыба-пила»", + "C_1063": "Майка-дуо «Щуччи»", "C_1066": "«Чокер» от Панкасиуса", + "C_1067": "«Манжеты» от Панкасиуса", "C_1069": "Голубая ретро-майка", "C_1070": "Бежевая ретро-майка", "C_1071": "Шаль «Нори-ролл»", @@ -44,9 +48,11 @@ "C_1084": "Майка «Закат»", "C_1085": "Майка «Рассвет»", "C_1088": "Майка «У-гранж»", + "C_1090": "Лаймовая смайл-майка", "C_1091": "Ягодная смайл-майка", "S_2000": "Красные блинг-кеды", "S_2001": "Блинг-кеды «Зомби»", + "S_2003": "Лиловые блинг-кеды", "C_2004": "Футболка от «Йожко»", "S_2004": "Кеды «Охотник»", "S_2005": "Красные кеды", @@ -58,10 +64,13 @@ "S_2043": "Осьмокроссы «Рубин»", "S_2045": "Перл-кроссы «УС-3»", "C_3000": "Белая двойка", + "S_3000": "Розовые кроссовки", "H_3001": "Маска для ныряния", "C_3001": "Желтая двойка", "S_3001": "Оранжевые «Стрелы»", + "H_3002": "Очки пилота", "H_3003": "Солнцезащитные очки", + "C_3004": "Двойка от «Шпротус»", "S_3004": "Бирюзовые кроссовки", "C_3006": "Коричневая двойка", "H_3008": "Золотые «авиаторы»", @@ -74,18 +83,24 @@ "H_3016": "Очки для плавания", "S_3020": "Кроссы-желейки", "H_3021": "Очки «бочкоглазики»", + "H_3022": "Очки «8 бит»", "S_3022": "Турботаби «Лосось»", + "H_3023": "Очки-невидимки", "S_3023": "Кроссы «М-ЕХА»", + "H_3024": "Очки «Тройная 333ащита»", "S_3024": "Слип-кроссы «Оранж»", "H_3025": "Тактические очки", "S_3025": "«Акульи плавники»", "H_3026": "Мотоочки", + "S_3026": "Синие «креветки»", "H_3027": "Очки от Панкасиуса", + "H_3029": "Очки «Осьборн блю» BC925", "S_4000": "Серые клоги", "S_4001": "Коричневые клоги", "H_4004": "Вьетнамка", "C_4004": "Черное поло", "C_4005": "Веломайка", + "H_4006": "Шляпка «Классика»", "S_4007": "Неоновые сандалии", "H_4008": "Панама", "S_4008": "Черные шлепки", @@ -94,14 +109,17 @@ "C_4010": "Регбийка «Восьмерка»", "S_4011": "Шлепки «Фугасик»", "S_4012": "Желтые шлепки «Фугасик»", + "S_4014": "Сандалии «Рыбья кость»", "H_4015": "Классический котелок", "S_4015": "Синие «Стрелы-лайт»", "H_4016": "Джинсовая панама", "S_4016": "Шлепки со смайлом", "H_4017": "Ковбойская шляпа", "S_4017": "Оранжевые шлеподы", + "H_4019": "Пляжная шляпка", "S_4021": "Розовые шлеподы", "S_4022": "Бирюзовые шлеподы", + "H_5000": "Студийные наушники", "C_5000": "Зеленая лыжная куртка", "S_5000": "Горные ботинки", "H_5001": "Дизайнерские наушники", @@ -133,7 +151,10 @@ "S_6007": "Вишневые берцы", "C_6008": "«Умибодзу» (основной)", "S_6012": "Болотные ботинки", + "S_6020": "Рабочие боты «Граффити»", "S_6021": "Полярные уткоботы", + "S_6023": "Красные «Молотоголовы»", + "S_6025": "Розовые берцы", "C_7001": "Свитер «Боец»", "S_7002": "Слипоны со стрелками", "H_7007": "Шлем ХК «Барракуда»", @@ -155,6 +176,7 @@ "S_8013": "Светлые ботинки чукка", "H_8014": "Маска со смайлами", "S_8014": "Топ-сайдеры «Эспрессо»", + "H_8015": "Респиратор «Жабры 3000»", "H_8016": "Защитный экран «Спрут»", "C_8017": "Гавайка «Планк-панк»", "C_8018": "Поло «Осьмобоулинг»", @@ -173,6 +195,62 @@ "H_9009": "Повязка (пинг-понг)", "C_9010": "Полевой жилет «Хаки»", "C_9011": "Жилет «Краснопанцирь»", + "C_9012": "Жилет «Зеленый панцирь»", + "C_9013": "Безрукавка «Клякса»", "C_10006": "Серая толстовка", - "C_10012": "Вишневое этно-худи" + "C_10012": "Вишневое этно-худи", + "C_10014": "Лазурное этно-худи", + "H_21010": "Кепка «Лещик»", + "H_25000": "Заколка «Кальмарчик»", + "C_25000": "Школьная форма А", + "S_25000": "Школьные ботинки + чулки", + "H_25001": "Шлем самурая", + "C_25001": "Доспехи самурая", + "S_25001": "Самурайские сандалии", + "H_25002": "Силовой шлем", + "C_25002": "Силовые доспехи", + "S_25002": "Силовые боты", + "H_25003": "Клипсы Splatoon 2", + "C_25003": "Школьная кофта А", + "S_25003": "Лоферы с бахромой", + "H_25004": "Маска ниндзялинга М-2", + "C_25004": "Костюм ниндзялинга", + "S_25004": "Таби ниндзялинга", + "H_25005": "Силовой шлем М-1", + "C_25005": "Силовые доспехи М-1", + "S_25005": "Силовые боты М-1", + "H_25006": "Жем-корона (мини)", + "C_25006": "Жем-толстовка", + "S_25006": "Жем-кроссы", + "H_25007": "Риш-наушники", + "C_25007": "Риш-топик", + "S_25007": "Риш-слипоны", + "H_25008": "Шляпа колдуньи", + "C_25008": "Балахон колдуньи А", + "S_25008": "Сапоги колдуньи", + "H_25009": "Шлем осьморыцаря", + "C_25009": "Латы осьморыцаря", + "S_25009": "Сапоги осьморыцаря", + "H_25010": "Маска Плавнишки", + "C_25010": "Перчатки Плавнишки", + "S_25010": "Башмаки Плавнишки", + "C_25014": "Школьная форма Б", + "S_25014": "Простые школьные ботинки", + "C_25015": "Школьная кофта Б", + "S_25015": "Простые лоферы с бахромой", + "H_25016": "Маска ниндзялинга М-1", + "H_25017": "Жем-корона (макси)", + "C_25017": "Балахон колдуньи Б", + "C_26000": "Сплатфест-майка", + "H_27000": "Рация героя (клон)", + "C_27000": "Жилет героя (клон)", + "S_27000": "Кроссы героя (клон)", + "H_27004": "Бронешлем (клон)", + "C_27004": "Бронекуртка (клон)", + "S_27004": "Бронеботы (клон)", + "H_27109": "Медвежий ободок", + "H_27306": "Нейрофон героя (клон)", + "C_27306": "Костюм героя (клон)", + "S_27306": "Боты героя (клон)", + "H_28000": "Шапочка Ракки" } diff --git a/public/locales/ru/user.json b/public/locales/ru/user.json new file mode 100644 index 000000000..e0af3664b --- /dev/null +++ b/public/locales/ru/user.json @@ -0,0 +1,10 @@ +{ + "country": "Страна", + "bio": "О себе", + + "results.placing": "Место", + "results.team": "Команда", + "results.tournament": "Турнир", + "results.date": "Дата", + "results.mates": "Напарники" +} diff --git a/public/locales/ru/weapons.json b/public/locales/ru/weapons.json index e637b0bf6..43df4d123 100644 --- a/public/locales/ru/weapons.json +++ b/public/locales/ru/weapons.json @@ -1,55 +1,86 @@ { - "0": "Плюхотрон", - "10": "Каплестрел-У", - "20": "Плюхомет", - "30": "Аэроспрей", - "40": "Каплестрел", - "50": "Струевик .52", - "60": "N-ZAP 85", - "70": "Каплестрел ПРО", - "80": "Струевик .96", - "90": "Плескарь", - "200": "Лунобластер", - "210": "Бластер", - "220": "Дальнобластер", - "230": "Контрабластер", - "240": "Бластермат", - "250": "Бластермат ПРО", - "300": "Каплетрон-компакт", - "310": "Тяжелый каплетрон", - "400": "Бутылятор", - "1000": "Валик ЛАЙТ", - "1010": "Сплат-валик", - "1020": "Мотовалик", - "1030": "Омнивалик", - "1100": "Кисть", - "1110": "Арт-кисть", - "2000": "Стиратель", - "2010": "Сплатган", - "2020": "Снайпокрас", - "2030": "Э-литр 95", - "2040": "Снайп-э-литр 95", - "2050": "Бамбух 14-I", - "2060": "Трубастер", - "3000": "Ведроган", - "3010": "Ведроган 3 в 1", - "3020": "Центрифугер", - "3030": "Ваннаган", - "3040": "Шпарган", - "4000": "Брызгомет-М", - "4010": "Брызгомет XL", - "4020": "Брызгомет «Горыныч»", - "4030": "Кугельшрайбер", - "4040": "Наутилус-47", - "5000": "Импрессиометы", - "5010": "Спуртометы", - "5020": "Термоплюхи 525", - "5030": "Спурт-плескари", - "5040": "Черные спуртокроссы", - "6000": "Сплат-зонт", - "6010": "Зонтент", - "6020": "Шпионский зонт", - "7010": "Тритиватор", - "8000": "Сплат-печатель", - "8010": "Cплат-дворник" + "MAIN_250": "Бластермат ПРО", + "MAIN_230": "Контрабластер", + "MAIN_240": "Бластермат", + "MAIN_220": "Дальнобластер", + "MAIN_210": "Бластер", + "MAIN_200": "Лунобластер", + "MAIN_1100": "Кисть", + "MAIN_1110": "Арт-кисть", + "MAIN_2060": "Трубастер", + "MAIN_2050": "Бамбух 14-I", + "MAIN_2040": "Снайп-э-литр 95", + "MAIN_2030": "Э-литр 95", + "MAIN_2020": "Снайпокрас", + "MAIN_2010": "Сплатган", + "MAIN_2000": "Стиратель", + "MAIN_5030": "Спурт-плескари", + "MAIN_5020": "Термоплюхи 525", + "MAIN_5010": "Спуртометы", + "MAIN_5000": "Импрессиометы", + "MAIN_5040": "Черные спуртокроссы", + "MAIN_1000": "Валик ЛАЙТ", + "MAIN_1020": "Мотовалик", + "MAIN_1030": "Омнивалик", + "MAIN_1010": "Сплат-валик", + "MAIN_8010": "Cплат-дворник", + "MAIN_8000": "Сплат-печатель", + "MAIN_6020": "Шпионский зонт", + "MAIN_6000": "Сплат-зонт", + "MAIN_6010": "Зонтент", + "MAIN_30": "Аэроспрей", + "MAIN_70": "Каплестрел ПРО", + "MAIN_10": "Каплестрел-У", + "MAIN_400": "Бутылятор", + "MAIN_50": "Струевик .52", + "MAIN_80": "Струевик .96", + "MAIN_90": "Плескарь", + "MAIN_40": "Каплестрел", + "MAIN_45": "Каплестрел героя (клон)", + "MAIN_20": "Плюхомет", + "MAIN_60": "N-ZAP 85", + "MAIN_0": "Плюхотрон", + "MAIN_310": "Тяжелый каплетрон", + "MAIN_300": "Каплетрон-компакт", + "MAIN_3030": "Ваннаган", + "MAIN_3010": "Ведроган 3 в 1", + "MAIN_3020": "Центрифугер", + "MAIN_3000": "Ведроган", + "MAIN_3040": "Шпарган", + "MAIN_4030": "Кугельшрайбер", + "MAIN_4020": "Брызгомет «Горыныч»", + "MAIN_4000": "Брызгомет-М", + "MAIN_4040": "Наутилус-47", + "MAIN_4010": "Брызгомет XL", + "MAIN_7010": "Тритиватор", + "MAIN_7020": "КО-РАЛЛ 450", + "SUB_8": "Прыжковый маячок", + "SUB_6": "Керлинг-бомба", + "SUB_5": "Содовая бомба", + "SUB_2": "Разрывная бомба", + "SUB_7": "Робобомба", + "SUB_0": "Брызгающая бомба", + "SUB_1": "Бомба на присоске", + "SUB_13": "Торпедная бомба", + "SUB_12": "Углострел", + "SUB_9": "Маркер движения", + "SUB_11": "Едкий туман", + "SUB_4": "Чернильный занавес", + "SUB_3": "Распылятор", + "SUB_10": "Мина", + "SPECIAL_8": "Краскосос", + "SPECIAL_12": "Кработанк", + "SPECIAL_15": "Тоникулер", + "SPECIAL_2": "Шарощит", + "SPECIAL_5": "Туча краски", + "SPECIAL_10": "Красколет", + "SPECIAL_9": "Мегалофон 5.1", + "SPECIAL_4": "Каракатница", + "SPECIAL_6": "Йо-хо-плюхер", + "SPECIAL_7": "Волноплюхер", + "SPECIAL_13": "Мотокула", + "SPECIAL_3": "Краскотрос", + "SPECIAL_14": "Тройной торнадо", + "SPECIAL_1": "Гранатомет «Трезубец»", + "SPECIAL_11": "Припечать" } diff --git a/public/locales/zh/gear.json b/public/locales/zh/gear.json index ac95a224a..ab94c9335 100644 --- a/public/locales/zh/gear.json +++ b/public/locales/zh/gear.json @@ -1,6 +1,7 @@ { "H_1": "头带 白色", "H_1000": "海胆BB帽", + "C_1000": "鱿鱼T恤 白色", "S_1000": "低筒鞋 蓝色", "C_1001": "鱿鱼眼T恤 黑色", "H_1002": "暇古网帽", @@ -24,12 +25,15 @@ "C_1021": "烧河豚点阵T恤 黑色", "S_1021": "NNJ运动鞋 绿色", "S_1022": "基地训练鞋 入门", + "S_1023": "蛤蜊600 甘露酱油", "S_1024": "基地训练鞋 高手", "H_1028": "遮阳帽 墨黑", "C_1035": "鱿鱼V领T恤 白色", "H_1036": "瓜皮帽", "C_1062": "鱿鱼丝T恤 白色", + "C_1063": "艾洛眼T恤 五分袖", "C_1066": "无法无天T恤配颈链", + "C_1067": "无法无天T恤配手链", "C_1069": "再版T恤 蓝色", "C_1070": "再版T恤 棕色", "C_1071": "散寿司披肩 海苔卷", @@ -44,9 +48,11 @@ "C_1084": "暮光渐层T恤", "C_1085": "日落渐层T恤", "C_1088": "加百列T恤", + "C_1090": "密集水滴鱼上衣 莱姆绿", "C_1091": "密集水滴鱼上衣 莓果红", "S_2000": "高筒海马鞋 红色", "S_2001": "高筒海马鞋 僵尸", + "S_2003": "高筒海马鞋 紫色", "C_2004": "泽酷插肩袖上衣", "S_2004": "高筒帆布鞋 黄麻", "S_2005": "高筒帆布鞋 番茄", @@ -58,10 +64,13 @@ "S_2043": "天亚8篮球鞋 红色", "S_2045": "01STER 琥珀", "C_3000": "两件式长袖上衣 白色", + "S_3000": "糖果运动鞋 粉红色", "H_3001": "斯普拉护目镜", "C_3001": "两件式长袖上衣 芥末黄", "S_3001": "箭标鞋 橘色", + "H_3002": "飞行员护目镜", "H_3003": "有色眼镜", + "C_3004": "钢铁先锋两件式长袖上衣", "S_3004": "糖果运动鞋 蓝绿色", "C_3006": "两件式长袖上衣 巧克力色", "H_3008": "明星墨镜 18K", @@ -74,18 +83,24 @@ "H_3016": "竞技泳镜", "S_3020": "鱿鱼生鱼片 Scramble", "H_3021": "桶眼鱼护目镜", + "H_3022": "8-Bit 镜框", "S_3022": "MOVE跑鞋 红色", + "H_3023": "眼饰", "S_3023": "MODZ-9", + "H_3024": "墨墨墨镜", "S_3024": "贝壳柱WO", "H_3025": "浮法玻璃透明眼镜", "S_3025": "双鱼翅", "H_3026": "骑士偏光眼镜", + "S_3026": "虾蛄关节运动鞋", "H_3027": "无法无天方形眼镜", + "H_3029": "球形墨镜BC925", "S_4000": "鳄鱼鞋 牡蛎", "S_4001": "鳄鱼鞋 巧克力", "H_4004": "斗笠", "C_4004": "乒乓球Polo衫", "C_4005": "单车衫", + "H_4006": "经典鱿鱼草帽", "S_4007": "三角带运动凉鞋 霓虹", "H_4008": "鱿鱼渔夫帽", "S_4008": "BB拖鞋", @@ -94,14 +109,17 @@ "C_4010": "王者橄榄球衫008", "S_4011": "烧河豚浴室拖鞋 红色", "S_4012": "烧河豚浴室拖鞋 黄色", + "S_4014": "鱼骨编织凉鞋", "H_4015": "经典圆顶礼帽", "S_4015": "箭标拖鞋 蓝黄色", "H_4016": "模板喷画牛仔布帽", "S_4016": "BS拖鞋", "H_4017": "帆立贝牛仔帽", "S_4017": "非常非常拖鞋 橘色", + "H_4019": "草帽", "S_4021": "非常非常拖鞋 洋红色", "S_4022": "非常非常拖鞋 绿蓝色", + "H_5000": "工作室耳机", "C_5000": "登山外套 橄榄绿", "S_5000": "登山鞋 轻量", "H_5001": "极光耳机", @@ -133,7 +151,10 @@ "S_6007": "摇滚靴 樱桃", "C_6008": "海坊主坦克背心 主场", "S_6012": "狩猎靴", + "S_6020": "磨砂皮革靴xSJ", "S_6021": "猎鸭靴 白雪", + "S_6023": "双髻鲨靴 红色", + "S_6025": "摇滚靴 粉红色", "C_7001": "鱿鱼交叉套头衫 芥末黄", "S_7002": "懒人鞋 千鸟", "H_7007": "伊卡洛斯曲棍球安全帽", @@ -155,6 +176,7 @@ "S_8013": "查卡靴 三明治", "H_8014": "水滴鱼微笑面罩", "S_8014": "帆船鞋 深咖啡色", + "H_8015": "可爱鱼鳃面罩", "H_8016": "黑鸢防护面罩R255", "C_8017": "彼得朋克衬衫", "C_8018": "章鱼保龄球衫", @@ -173,6 +195,62 @@ "H_9009": "乒乓头带", "C_9010": "狩猎背心KK", "C_9011": "长腿护甲 红色", + "C_9012": "长腿护甲 莱姆绿", + "C_9013": "喷墨背心", "C_10006": "帆立连帽上衣 灰色", - "C_10012": "巴哈连帽上衣 红色" + "C_10012": "巴哈连帽上衣 红色", + "C_10014": "巴哈连帽上衣 天蓝色", + "H_21010": "金线鱼帽", + "H_25000": "鱿鱼发夹", + "C_25000": "学校制服外套L", + "S_25000": "学校乐福鞋 高级", + "H_25001": "武士头盔", + "C_25001": "武士外套", + "S_25001": "武士鞋", + "H_25002": "动力面罩", + "C_25002": "动力装", + "S_25002": "动力靴", + "H_25003": "鱿鱼回纹针", + "C_25003": "学校针织罩衫 蝴蝶结", + "S_25003": "流苏乐福鞋 宽松", + "H_25004": "鱿鱼影子面罩 乙", + "C_25004": "忍者装", + "S_25004": "忍者鞋", + "H_25005": "动力面罩 原型", + "C_25005": "动力装 原型", + "S_25005": "动力靴 原型", + "H_25006": "姬伴皇冠S", + "C_25006": "姬伴连帽上衣", + "S_25006": "姬伴运动鞋", + "H_25007": "饭友耳机", + "C_25007": "饭友上衣", + "S_25007": "饭友懒人鞋", + "H_25008": "魔力圆边帽", + "C_25008": "魔力长袍S", + "S_25008": "魔力靴", + "H_25009": "章鱼钢盔", + "C_25009": "章鱼铠甲", + "S_25009": "章鱼护腿鞋", + "H_25010": "鱼奇奇", + "C_25010": "鱼奇奇手套", + "S_25010": "鱼奇奇鞋", + "C_25014": "学校制服外套R", + "S_25014": "学校乐福鞋 醋鱿鱼须", + "C_25015": "学校针织罩衫 领带", + "S_25015": "流苏乐福鞋 醋鱿鱼须", + "H_25016": "鱿鱼影子面罩 甲", + "H_25017": "姬伴皇冠L", + "C_25017": "魔力长袍L", + "C_26000": "祭典T恤", + "H_27000": "英雄头部装备 复制", + "C_27000": "英雄外套 复制", + "S_27000": "英雄鞋 复制", + "H_27004": "盔甲头盔 复制", + "C_27004": "盔甲外套 复制", + "S_27004": "盔甲靴 复制", + "H_27109": "熊耳朵", + "H_27306": "英雄头饰装备 复制", + "C_27306": "英雄装 复制", + "S_27306": "英雄靴 复制", + "H_28000": "阿龙帽" } diff --git a/public/locales/zh/weapons.json b/public/locales/zh/weapons.json index 7a5ed2770..f643c9e15 100644 --- a/public/locales/zh/weapons.json +++ b/public/locales/zh/weapons.json @@ -1,55 +1,86 @@ { - "0": "广域标记枪", - "10": "新叶射击枪", - "20": "窄域标记枪", - "30": "专业模型枪MG", - "40": "斯普拉射击枪", - "50": ".52加仑", - "60": "N-ZAP85", - "70": "顶尖射击枪", - "80": ".96加仑", - "90": "喷射清洁枪", - "200": "新星爆破枪", - "210": "火热爆破枪", - "220": "远距爆破枪", - "230": "冲涂爆破枪", - "240": "快速爆破枪", - "250": "快速爆破枪 精英", - "300": "L3卷管枪", - "310": "H3卷管枪", - "400": "开瓶喷泉枪", - "1000": "碳纤维滚筒", - "1010": "斯普拉滚筒", - "1020": "电动马达滚筒", - "1030": "可变式滚筒", - "1100": "巴勃罗", - "1110": "北斋", - "2000": "鱿快洁α", - "2010": "斯普拉蓄力狙击枪", - "2020": "斯普拉准星枪", - "2030": "公升4K", - "2040": "4K准星枪", - "2050": "14式竹筒枪·甲", - "2060": "高压油管枪", - "3000": "飞溅泼桶", - "3010": "洗笔桶", - "3020": "回旋泼桶", - "3030": "满溢泡澡泼桶", - "3040": "爆炸泼桶", - "4000": "斯普拉旋转枪", - "4010": "桶装旋转枪", - "4020": "消防栓旋转枪", - "4030": "圆珠笔", - "4040": "鹦鹉螺号47", - "5000": "溅镀枪", - "5010": "斯普拉机动枪", - "5020": "开尔文525", - "5030": "双重清洁枪", - "5040": "四重弹跳手枪 黑", - "6000": "遮阳防空伞", - "6010": "露营防空伞", - "6020": "特工配件", - "7010": "三发猎鱼弓", - "8000": "工作刮水刀", - "8010": "雨刷刮水刀" + "MAIN_250": "快速爆破枪 精英", + "MAIN_230": "冲涂爆破枪", + "MAIN_240": "快速爆破枪", + "MAIN_220": "远距爆破枪", + "MAIN_210": "火热爆破枪", + "MAIN_200": "新星爆破枪", + "MAIN_1100": "巴勃罗", + "MAIN_1110": "北斋", + "MAIN_2060": "高压油管枪", + "MAIN_2050": "14式竹筒枪·甲", + "MAIN_2040": "4K准星枪", + "MAIN_2030": "公升4K", + "MAIN_2020": "斯普拉准星枪", + "MAIN_2010": "斯普拉蓄力狙击枪", + "MAIN_2000": "鱿快洁α", + "MAIN_5030": "双重清洁枪", + "MAIN_5020": "开尔文525", + "MAIN_5010": "斯普拉机动枪", + "MAIN_5000": "溅镀枪", + "MAIN_5040": "四重弹跳手枪 黑", + "MAIN_1000": "碳纤维滚筒", + "MAIN_1020": "电动马达滚筒", + "MAIN_1030": "可变式滚筒", + "MAIN_1010": "斯普拉滚筒", + "MAIN_8010": "雨刷刮水刀", + "MAIN_8000": "工作刮水刀", + "MAIN_6020": "特工配件", + "MAIN_6000": "遮阳防空伞", + "MAIN_6010": "露营防空伞", + "MAIN_30": "专业模型枪MG", + "MAIN_70": "顶尖射击枪", + "MAIN_10": "新叶射击枪", + "MAIN_400": "开瓶喷泉枪", + "MAIN_50": ".52加仑", + "MAIN_80": ".96加仑", + "MAIN_90": "喷射清洁枪", + "MAIN_40": "斯普拉射击枪", + "MAIN_45": "英雄射击枪 复制", + "MAIN_20": "窄域标记枪", + "MAIN_60": "N-ZAP85", + "MAIN_0": "广域标记枪", + "MAIN_310": "H3卷管枪", + "MAIN_300": "L3卷管枪", + "MAIN_3030": "满溢泡澡泼桶", + "MAIN_3010": "洗笔桶", + "MAIN_3020": "回旋泼桶", + "MAIN_3000": "飞溅泼桶", + "MAIN_3040": "爆炸泼桶", + "MAIN_4030": "圆珠笔", + "MAIN_4020": "消防栓旋转枪", + "MAIN_4000": "斯普拉旋转枪", + "MAIN_4040": "鹦鹉螺号47", + "MAIN_4010": "桶装旋转枪", + "MAIN_7010": "三发猎鱼弓", + "MAIN_7020": "LACT-450", + "SUB_8": "跳跃信标", + "SUB_6": "冰壶炸弹", + "SUB_5": "碳酸炸弹", + "SUB_2": "快速炸弹", + "SUB_7": "机器人炸弹", + "SUB_0": "斯普拉炸弹", + "SUB_1": "吸盘炸弹", + "SUB_13": "鱼雷", + "SUB_12": "标线器", + "SUB_9": "定点侦测器", + "SUB_11": "毒雾", + "SUB_4": "斯普拉防护墙", + "SUB_3": "洒墨器", + "SUB_10": "墨汁陷阱", + "SPECIAL_8": "吸墨机", + "SPECIAL_12": "螃蟹坦克", + "SPECIAL_15": "能量站", + "SPECIAL_2": "巨大防护罩", + "SPECIAL_5": "墨雨云", + "SPECIAL_10": "喷射背包", + "SPECIAL_9": "喇叭镭射5.1ch", + "SPECIAL_4": "多重导弹", + "SPECIAL_6": "赞气弹", + "SPECIAL_7": "弹跳声呐", + "SPECIAL_13": "鲨鱼坐骑", + "SPECIAL_3": "触手喷射", + "SPECIAL_14": "三重龙卷风", + "SPECIAL_1": "终极发射", + "SPECIAL_11": "终极印章" } diff --git a/scripts/create-analyzer-json.ts b/scripts/create-analyzer-json.ts new file mode 100644 index 000000000..6560a9a92 --- /dev/null +++ b/scripts/create-analyzer-json.ts @@ -0,0 +1,482 @@ +// To run this script you need from https://github.com/Leanny/leanny.github.io +// 1) WeaponInfoMain.json inside dicts +// 2) WeaponInfoSub.json inside dicts +// 3) WeaponInfoSpecial.json inside dicts +// 4) params (weapon folder) inside dicts + +import type { SpecialWeaponId } from "~/modules/in-game-lists"; +import { type SubWeaponId, subWeaponIds } from "~/modules/in-game-lists"; +import weapons from "./dicts/WeaponInfoMain.json"; +import subWeapons from "./dicts/WeaponInfoSub.json"; +import specialWeapons from "./dicts/WeaponInfoSpecial.json"; +import fs from "node:fs"; +import path from "node:path"; +import invariant from "tiny-invariant"; +import type { MainWeaponParams, SubWeaponParams } from "~/modules/analyzer"; +import type { ParamsJson } from "~/modules/analyzer/types"; +import { z } from "zod"; +import { LANG_JSONS_TO_CREATE, loadLangDicts } from "./utils"; + +const CURRENT_SEASON = 1; + +type MainWeapon = typeof weapons[number]; +type SubWeapon = typeof subWeapons[number]; +type SpecialWeapon = typeof specialWeapons[number]; +type TranslationArray = Array<{ language: string; key: string; value: string }>; + +async function main() { + const mainWeaponsResult: Record = {}; + const subWeaponsResult: Record = {}; + const translations: TranslationArray = []; + + const langDicts = await loadLangDicts(); + + for (const weapon of weapons) { + if (mainWeaponShouldBeSkipped(weapon)) continue; + + const rawParams = loadWeaponParamsObject(weapon); + const params = combineSwingsIfSame( + parametersToMainWeaponResult(weapon, rawParams) + ); + + translationsToArray({ + arr: translations, + internalName: weapon.__RowId, + weaponId: weapon.Id, + type: "Main", + translations: langDicts, + }); + + mainWeaponsResult[weapon.Id] = params; + } + + for (const subWeapon of subWeapons) { + if (subWeaponShouldBeSkipped(subWeapon)) continue; + + const rawParams = loadWeaponParamsObject(subWeapon); + const params = parametersToSubWeaponResult(rawParams); + + translationsToArray({ + arr: translations, + internalName: subWeapon.__RowId, + weaponId: subWeapon.Id, + type: "Sub", + translations: langDicts, + }); + + subWeaponsResult[subWeapon.Id] = params; + } + + for (const specialWeapon of specialWeapons) { + if (specialWeaponShouldBeSkipped(specialWeapon)) continue; + + translationsToArray({ + arr: translations, + internalName: specialWeapon.__RowId, + weaponId: specialWeapon.Id, + type: "Special", + translations: langDicts, + }); + } + + const toFile: ParamsJson = { + mainWeapons: mainWeaponsResult, + subWeapons: subWeaponsResult, + }; + + fs.writeFileSync( + path.join(__dirname, "output", `params.json`), + JSON.stringify(toFile, null, 2) + "\n" + ); + + writeTranslationsJsons(translations); + logWeaponIds(mainWeaponsResult); +} + +function parametersToMainWeaponResult( + weapon: MainWeapon, + params: any +): MainWeaponParams { + const isSplatling = + params["WeaponParam"]?.["$type"] === "spl__WeaponSpinnerParam"; + const isSlosher = + params["WeaponParam"]?.["$type"] === "spl__WeaponSlosherParam"; + + const InkConsume = + !isSplatling && !isSlosher + ? params["WeaponParam"]?.["InkConsume"] + : undefined; + const InkConsumeFullChargeSplatling = isSplatling + ? params["WeaponParam"]?.["InkConsume"] + : undefined; + + const InkConsumeSlosher = isSlosher + ? params["WeaponParam"]?.["InkConsume"] + : undefined; + + // for blasters these values are the same and represent damage caused by direct + const DamageParam_ValueDirect = + params["DamageParam"]?.["ValueMax"] && + params["DamageParam"]?.["ValueMax"] === params["DamageParam"]?.["ValueMin"] + ? params["DamageParam"]?.["ValueMax"] + : undefined; + + const DamageParam_ValueMax = () => { + if (DamageParam_ValueDirect) return undefined; + + return ( + params["DamageParam"]?.["ValueMax"] ?? + params["spl__BulletShelterShotgunParam"]?.["DamageEffectiveTotalMax"] + ); + }; + + const KeepChargeFullFrame = + params["WeaponKeepChargeParam"]?.["KeepChargeFullFrame"] ?? + params["spl__WeaponStringerParam"]?.["ChargeKeepParam"]?.[ + "KeepChargeFullFrame" + ]; + + return { + SpecialPoint: weapon.SpecialPoint, + subWeaponId: resolveSubWeaponId(weapon), + specialWeaponId: resolveSpecialWeaponId(weapon), + overwrites: resolveOverwrites(params), + TripleShotSpanFrame: params["WeaponParam"]?.["TripleShotSpanFrame"], + WeaponSpeedType: params["MainWeaponSetting"]?.["WeaponSpeedType"], + DamageParam_ValueMax: DamageParam_ValueMax(), + DamageParam_ValueMin: !DamageParam_ValueDirect + ? params["DamageParam"]?.["ValueMin"] + : undefined, + DamageParam_ValueDirect, + BlastParam_DistanceDamage: params["BlastParam"]?.["DistanceDamage"], + DamageParam_ValueFullCharge: params["DamageParam"]?.["ValueFullCharge"], + DamageParam_ValueMaxCharge: params["DamageParam"]?.["ValueMaxCharge"], + DamageParam_ValueMinCharge: params["DamageParam"]?.["ValueMinCharge"], + CanopyHP: params["spl__BulletShelterCanopyParam"]?.["CanopyHP"], + ChargeFrameFullCharge: + params["WeaponParam"]?.["ChargeFrameFullCharge"] ?? + params["spl__WeaponStringerParam"]?.["ChargeParam"]?.[ + "ChargeFrameFullCharge" + ], + KeepChargeFullFrame: + KeepChargeFullFrame !== 1 ? KeepChargeFullFrame : undefined, + InkRecoverStop: params["WeaponParam"]?.["InkRecoverStop"], + InkConsume, + InkConsumeSlosher, + InkConsumeFullCharge: params["WeaponParam"]?.["InkConsumeFullCharge"], + InkConsumeMinCharge: params["WeaponParam"]?.["InkConsumeMinCharge"], + InkConsumeFullChargeSplatling, + InkConsume_WeaponSwingParam: params["WeaponSwingParam"]?.["InkConsume"], + InkConsume_WeaponVerticalSwingParam: + params["WeaponVerticalSwingParam"]?.["InkConsume"], + InkConsume_WeaponWideSwingParam: + params["WeaponWideSwingParam"]?.["InkConsume"], + InkConsumeUmbrella_WeaponShelterCanopyParam: + params["spl__WeaponShelterCanopyParam"]?.["InkConsumeUmbrella"] !== 0 + ? params["spl__WeaponShelterCanopyParam"]?.["InkConsumeUmbrella"] + : undefined, + InkConsume_WeaponShelterShotgunParam: + params["spl__WeaponShelterShotgunParam"]?.["InkConsume"], + InkConsume_SideStepParam: params["SideStepParam"]?.["InkConsume"], + InkConsume_SwingParam: + params["spl__WeaponSaberParam"]?.["SwingParam"]?.["InkConsume"], + InkConsumeFullCharge_ChargeParam: + params["spl__WeaponSaberParam"]?.["ChargeParam"]?.[ + "InkConsumeFullCharge" + ] ?? + params["spl__WeaponStringerParam"]?.["ChargeParam"]?.[ + "InkConsumeFullCharge" + ], + }; +} + +function combineSwingsIfSame(params: MainWeaponParams): MainWeaponParams { + if ( + !params.InkConsume_WeaponVerticalSwingParam || + params.InkConsume_WeaponVerticalSwingParam !== + params.InkConsume_WeaponWideSwingParam + ) { + return params; + } + + return { + ...params, + InkConsume_WeaponSwingParam: params.InkConsume_WeaponVerticalSwingParam, + InkConsume_WeaponVerticalSwingParam: undefined, + InkConsume_WeaponWideSwingParam: undefined, + }; +} + +// const LEGAL_SUB_INK_SAVE_LV = [0, 1, 2, 3]; +function parametersToSubWeaponResult(params: any): SubWeaponParams { + const SubInkSaveLv = params["SubWeaponSetting"]?.["SubInkSaveLv"]; + // xxx: enable when all sub weapons have SubInkSaveLv's + // invariant( + // LEGAL_SUB_INK_SAVE_LV.includes(SubInkSaveLv), + // `Unknown SubInkSaveLv ${SubInkSaveLv} for ${subWeapon.__RowId}` + // ); + + return { + overwrites: resolveSubWeaponOverwrites(params), + SubInkSaveLv, + InkConsume: params["WeaponParam"]["InkConsume"], + InkRecoverStop: params["WeaponParam"]["InkRecoverStop"], + DistanceDamage: params["BlastParam"]?.["DistanceDamage"], + DistanceDamage_BlastParamMaxCharge: + params["BlastParamMaxCharge"]?.["DistanceDamage"], + DistanceDamage_BlastParamMinCharge: + params["BlastParamMinCharge"]?.["DistanceDamage"], + DirectDamage: + params["MoveParam"]?.["DirectDamage"] ?? + params["MoveParam"]?.["DamageDirectHit"], + DistanceDamage_BlastParamArray: params["MoveParam"]?.[ + "BlastParamArray" + ]?.map((b: any) => b.DistanceDamage), + DistanceDamage_BlastParamChase: + params["BlastParamChase"]?.["DistanceDamage"], + DistanceDamage_SplashBlastParam: + params["BlastParamChase"]?.["SplashBlastParam"]?.["DistanceDamage"], + }; +} + +function resolveSubWeaponId(weapon: MainWeapon) { + const codeName = weapon.SubWeapon.replace("Work/Gyml/", "").replace( + ".spl__WeaponInfoSub.gyml", + "" + ); + + const subWeaponObj = subWeapons.find((wpn) => codeName === wpn.__RowId); + invariant(subWeaponObj, `Could not find sub weapon for '${weapon.__RowId}'`); + invariant( + subWeaponIds.includes(subWeaponObj.Id as any), + `Invalid sub weapon id` + ); + + return subWeaponObj.Id as SubWeaponId; +} + +function resolveSpecialWeaponId(weapon: MainWeapon) { + const codeName = weapon.SpecialWeapon.replace("Work/Gyml/", "").replace( + ".spl__WeaponInfoSpecial.gyml", + "" + ); + + const specialWeaponObj = specialWeapons.find( + (wpn) => codeName === wpn.__RowId + ); + invariant( + specialWeaponObj, + `Could not find special weapon for '${codeName}'` + ); + + return specialWeaponObj.Id as SpecialWeaponId; +} + +const overwriteSchema = z.object({ + High: z.number().optional(), + Mid: z.number().optional(), + Low: z.number().optional(), +}); + +function resolveOverwrites(params: any) { + const result: MainWeaponParams["overwrites"] = {}; + + for (const [key, value] of Object.entries(params)) { + const parsed = overwriteSchema.safeParse(value); + + resolveOverwritesWithArbitraryKeys(result, value); + + // each object has a $type property which we ignore + if ( + key.includes("PlayerGearSkillParam") && + parsed.success && + Object.keys(parsed).length > 1 + ) { + const abilityKey = key.split("_").at(-1); + invariant(abilityKey, `Could not find ability key for '${key}'`); + + if (!parsed.data.High && !parsed.data.Mid && !parsed.data.Low) { + continue; + } + + result[abilityKey] = { + High: parsed.data.High, + Mid: parsed.data.Mid, + Low: parsed.data.Low, + }; + } + } + + if (Object.keys(result).length === 0) return; + + return result; +} + +function resolveOverwritesWithArbitraryKeys( + result: NonNullable, + paramsObj: unknown +) { + for (const [key, value] of Object.entries( + paramsObj as Record + )) { + if (!key.startsWith("Overwrite_")) continue; + + let abilityKey = key.replace("Overwrite_", ""); + + for (const type of ["High", "Mid", "Low"] as const) { + const suffix = `_${type}`; + if (!abilityKey.endsWith(suffix)) continue; + + abilityKey = abilityKey.replace(suffix, ""); + + if (!result[abilityKey]) result[abilityKey] = {}; + + result[abilityKey]![type] = value; + } + } +} + +function resolveSubWeaponOverwrites(params: any) { + const result: SubWeaponParams["overwrites"] = { + SpawnSpeedZSpecUp: params["MoveParam"]?.["SpawnSpeedZSpecUp"], + PeriodFirst: params["MoveParam"]?.["PeriodFirst"], + PeriodSecond: params["MoveParam"]?.["PeriodSecond"], + MarkingFrameSubSpec: + params["MoveParam"]?.["MarkingFrameSubSpec"] ?? + params["MoveParam"]?.["MarkingFrame"] ?? + params["AreaParam"]?.["MarkingFrameSubSpec"], + SensorRadius: params["MoveParam"]?.["SensorRadius"], + ExplosionRadius: params["AreaParam"]?.["Distance"], + MaxHP: params["MoveParam"]?.["MaxHP"], + }; + + return Object.fromEntries( + Object.entries(result).filter( + ([_key, value]) => + value && (value.High !== value.Mid || value.Low !== value.High) + ) + ); +} + +const WEAPON_TYPES_TO_IGNORE = [ + "Mission", + "Coop", + "Hero", + "Rival", + "SalmonBuddy", +]; + +const INTERNAL_WEAPON_NAMES_TO_IGNORE: readonly string[] = ["Free"] as const; +function mainWeaponShouldBeSkipped(mainWeapon: MainWeapon) { + if ( + WEAPON_TYPES_TO_IGNORE.includes(mainWeapon.Type) || + INTERNAL_WEAPON_NAMES_TO_IGNORE.includes(mainWeapon.__RowId) || + mainWeapon.Season > CURRENT_SEASON + ) { + return true; + } + + return false; +} + +function subWeaponShouldBeSkipped(subWeapon: SubWeapon) { + if (subWeapon.Id === 10000) return true; + if (WEAPON_TYPES_TO_IGNORE.some((val) => subWeapon.__RowId.includes(val))) { + return true; + } + + return false; +} + +function specialWeaponShouldBeSkipped(specialWeapon: SpecialWeapon) { + if (WEAPON_TYPES_TO_IGNORE.some((val) => specialWeapon.Type.includes(val))) { + return true; + } + if (specialWeapon.__RowId === "SpGachihoko") return true; + + return false; +} + +function loadWeaponParamsObject(weapon: MainWeapon | SubWeapon) { + return JSON.parse( + fs.readFileSync( + path.join(__dirname, "dicts", "weapon", weaponRowIdToFileName(weapon)), + "utf8" + ) + )["GameParameters"]; +} + +function weaponRowIdToFileName(weapon: MainWeapon | SubWeapon) { + const [category, codeName] = weapon.__RowId.split("_"); + invariant(category); + + return `Weapon${category}${codeName ?? ""}.game__GameParameterTable.json`; +} + +function translationsToArray({ + arr, + internalName, + weaponId, + type, + translations, +}: { + arr: TranslationArray; + internalName: string; + weaponId: number; + type: "Main" | "Sub" | "Special"; + translations: [ + langCode: string, + translations: Record> + ][]; +}) { + for (const langCode of LANG_JSONS_TO_CREATE) { + const translationOfLanguage = translations.find((t) => t[0] === langCode); + invariant( + translationOfLanguage, + `Could not find translation for '${langCode}'` + ); + + const value = + translationOfLanguage[1][`CommonMsg/Weapon/WeaponName_${type}`]?.[ + internalName + ]; + invariant(value, `Could not find translation for '${internalName}'`); + + arr.push({ + key: `${type.toUpperCase()}_${weaponId}`, + language: langCode, + value, + }); + } +} + +function writeTranslationsJsons(arr: TranslationArray) { + for (const langCode of LANG_JSONS_TO_CREATE) { + fs.writeFileSync( + path.join( + __dirname, + "..", + "public", + "locales", + langCode.slice(2), + `weapons.json` + ), + JSON.stringify( + Object.fromEntries( + arr + .filter((val) => val.language === langCode) + .map(({ key, value }) => [key, value]) + ), + null, + 2 + ) + "\n" + ); + } +} + +function logWeaponIds(weapons: Record) { + // eslint-disable-next-line no-console + console.log(JSON.stringify(Object.keys(weapons).map(Number))); +} + +void main(); diff --git a/scripts/create-gear-json.ts b/scripts/create-gear-json.ts index 73f1adb6e..02b8e6e32 100644 --- a/scripts/create-gear-json.ts +++ b/scripts/create-gear-json.ts @@ -7,13 +7,15 @@ import path from "node:path"; import invariant from "tiny-invariant"; import { LANG_JSONS_TO_CREATE, loadLangDicts } from "./utils"; -const CURRENT_SEASON = 0; +const CURRENT_SEASON = 1; const OUTPUT_DIR_PATH = path.join(__dirname, "output"); const LEAN_HEAD_CODE = "Hed"; const LEAN_CLOTHES_CODE = "Clt"; const LEAN_SHOES_CODE = "Shs"; +const AVAILABLE_SR_GEAR = [21010]; + async function main() { const allGear: Array<{ id: number; @@ -24,7 +26,11 @@ async function main() { const langDicts = await loadLangDicts(); for (const gear of [...head, ...clothes, ...shoes]) { - if (gear.Season > CURRENT_SEASON || gear.HowToGet !== "Shop") { + if (gear.Season > CURRENT_SEASON || gear.HowToGet === "Impossible") { + continue; + } + + if (gear.__RowId.includes("COP") && !AVAILABLE_SR_GEAR.includes(gear.Id)) { continue; } diff --git a/scripts/create-weapon-json.ts b/scripts/create-weapon-json.ts deleted file mode 100644 index ef8e566c3..000000000 --- a/scripts/create-weapon-json.ts +++ /dev/null @@ -1,84 +0,0 @@ -import weapons from "./dicts/WeaponInfoMain.json"; -import fs from "node:fs"; -import path from "node:path"; -import invariant from "tiny-invariant"; -import { LANG_JSONS_TO_CREATE, loadLangDicts } from "./utils"; - -const INTERNAL_NAMES_TO_IGNORE: readonly string[] = ["Free"] as const; -const OUTPUT_DIR_PATH = path.join(__dirname, "output"); -const LEAN_WEAPON_CATEGORY_KEY = "CommonMsg/Weapon/WeaponName_Main"; - -async function main() { - const result: Array<{ - id: number; - internalName: string; - translations: Array<{ language: string; name: string }>; - }> = []; - const langDicts = await loadLangDicts(); - - for (const weapon of weapons) { - if ( - weapon.Type === "Coop" || - INTERNAL_NAMES_TO_IGNORE.includes(weapon.__RowId) - ) { - continue; - } - - result.push({ - id: weapon.Id, - internalName: weapon.__RowId, - translations: langDicts.map(([langCode, translations]) => { - const name = translations[LEAN_WEAPON_CATEGORY_KEY]?.[weapon.__RowId]; - invariant(name); - - return { - language: langCode, - name, - }; - }), - }); - } - - result.sort((a, b) => a.id - b.id); - - const weaponIds = result.map((w) => w.id); - - fs.writeFileSync( - path.join(OUTPUT_DIR_PATH, "weapons.json"), - JSON.stringify(result, null, 2) - ); - fs.writeFileSync( - path.join(OUTPUT_DIR_PATH, "weapon-ids.json"), - JSON.stringify(weaponIds, null, 2) - ); - - for (const langCode of LANG_JSONS_TO_CREATE) { - const translationsMap = Object.fromEntries( - result.map((w) => { - const translation = w.translations.find( - (t) => t.language === langCode - )?.name; - invariant( - translation, - `No translation for ${w.internalName} in ${langCode}` - ); - - return [w.id, translation]; - }) - ); - - fs.writeFileSync( - path.join( - __dirname, - "..", - "public", - "locales", - langCode.slice(2), - `weapons.json` - ), - JSON.stringify(translationsMap, null, 2) + "\n" - ); - } -} - -void main(); diff --git a/scripts/replace-img-names.ts b/scripts/replace-img-names.ts index 60c38d9dd..1f6e6bb8c 100644 --- a/scripts/replace-img-names.ts +++ b/scripts/replace-img-names.ts @@ -3,13 +3,6 @@ import fs from "node:fs"; import path from "node:path"; import invariant from "tiny-invariant"; -const WEAPON_IMAGES_PATH = path.join( - __dirname, - "..", - "public", - "img", - "weapons" -); const GEAR_IMAGES_DIR_PATH = path.join( __dirname, "..", @@ -17,33 +10,9 @@ const GEAR_IMAGES_DIR_PATH = path.join( "img", "gear" ); -const WEAPONS_JSON_PATH = path.join(__dirname, "output", "weapons.json"); const GEAR_JSON_PATH = path.join(__dirname, "output", "gear.json"); async function main() { - const weapons = JSON.parse(fs.readFileSync(WEAPONS_JSON_PATH, "utf8")); - const files = await fs.promises.readdir(WEAPON_IMAGES_PATH); - - // weapons - for (const file of files) { - if (!file.startsWith("Path_Wst")) continue; - - const weaponInternalName = file - .replace(".png", "") - .replace("Path_Wst_", ""); - - const weaponId = weapons.find( - (w: any) => w.internalName === weaponInternalName - ).id; - invariant(typeof weaponId === "number", weaponInternalName + " has no id"); - - fs.renameSync( - path.join(WEAPON_IMAGES_PATH, file), - path.join(WEAPON_IMAGES_PATH, `${weaponId}.png`) - ); - } - - // gear const gear = JSON.parse(fs.readFileSync(GEAR_JSON_PATH, "utf8")); for (const gearSlot of ["head", "clothes", "shoes"] as const) { const gearSlotDirPath = path.join(GEAR_IMAGES_DIR_PATH, gearSlot); @@ -53,6 +22,7 @@ async function main() { gearSlot === "head" ? "Hed" : gearSlot === "shoes" ? "Shs" : "Clt"; for (const file of files) { + // did we already replace the name if ( !file.startsWith("Shs") && !file.startsWith("Clt") && @@ -61,13 +31,22 @@ async function main() { continue; } + if (file.endsWith(".webp")) { + fs.unlinkSync(path.join(gearSlotDirPath, file)); + continue; + } + const internalName = file.replace(".png", "").split("_")[1]; invariant(internalName); const gearId = gear.find( (g: any) => g.internalName === internalName && g.type === type )?.id; - invariant(typeof gearId === "number", internalName + " has no id"); + + if (typeof gearId !== "number") { + fs.unlinkSync(path.join(gearSlotDirPath, file)); + continue; + } fs.renameSync( path.join(gearSlotDirPath, file), diff --git a/types/react-i18next.d.ts b/types/react-i18next.d.ts index 00eab8b1e..607c96ac4 100644 --- a/types/react-i18next.d.ts +++ b/types/react-i18next.d.ts @@ -10,6 +10,7 @@ import type calendar from "../public/locales/en/calendar.json"; import type weapons from "../public/locales/en/weapons.json"; import type gear from "../public/locales/en/gear.json"; import type builds from "../public/locales/en/builds.json"; +import type analyzer from "../public/locales/en/analyzer.json"; declare module "react-i18next" { interface CustomTypeOptions { @@ -25,6 +26,7 @@ declare module "react-i18next" { weapons: typeof weapons; gear: typeof gear; builds: typeof builds; + analyzer: typeof analyzer; }; } }