From 0fde5c7f269358bb86fe0c89c80ee53a327bbc26 Mon Sep 17 00:00:00 2001 From: Denis Ranneft Date: Wed, 1 Apr 2026 17:06:41 +0300 Subject: [PATCH] npc logic update --- .../000028_town_merchant_buy_prices.sql | 13 ++ docs/i18n-display-rules.md | 42 +++++ frontend/src/i18n/quests.en.yml | 172 ++++++++++++++++++ frontend/src/i18n/quests.ru.yml | 172 ++++++++++++++++++ 4 files changed, 399 insertions(+) create mode 100644 backend/migrations/000028_town_merchant_buy_prices.sql create mode 100644 docs/i18n-display-rules.md create mode 100644 frontend/src/i18n/quests.en.yml create mode 100644 frontend/src/i18n/quests.ru.yml diff --git a/backend/migrations/000028_town_merchant_buy_prices.sql b/backend/migrations/000028_town_merchant_buy_prices.sql new file mode 100644 index 0000000..51e7cbb --- /dev/null +++ b/backend/migrations/000028_town_merchant_buy_prices.sql @@ -0,0 +1,13 @@ +-- Town merchant buy pricing: higher gold costs, ±15% roll per offer (see tuning Defaults / RollTownMerchantOfferGold). +-- Sell-to-vendor remains autoSell* in runtime_config (unchanged). + +UPDATE public.runtime_config +SET + payload = payload || jsonb_build_object( + 'merchantTownGearCostBase', 180, + 'merchantTownGearCostPerTownLevel', 40, + 'merchantTownGearPricePerIlvl', 115, + 'merchantTownGearPriceVariancePct', 15 + ), + updated_at = now() +WHERE id = true; diff --git a/docs/i18n-display-rules.md b/docs/i18n-display-rules.md new file mode 100644 index 0000000..84d01f0 --- /dev/null +++ b/docs/i18n-display-rules.md @@ -0,0 +1,42 @@ +# Display names and locale rules (AutoHero) + +## Town names on Russian UI + +For locale `ru`, **town names are not translated by meaning**. They use **pragmatic Cyrillic transliteration** of the English fantasy names (the same names shown in `en`). This keeps a single world identity across languages and avoids awkward calques (for example, not «Зола-крепость» for Cinderkeep). + +Guidelines: + +1. **Read like the English name**: consonants and vowels map so a Russian player can recognize the original (Willowdale → Виллоудейл, Cinderkeep → Синдеркип). +2. **Keep word boundaries** where the English has them (Thorn + watch → Торнвотч; Red + cliff → Редклифф). +3. **Do not translate semantic meaning** of the compound (no «красная скала», «звездопад», etc.) for these labels. +4. **Stable keys**: DB/API use `towns.name_key` (e.g. `town.cinderkeep.v1`); only the `ru` string in `contentLabels` / UI bundle changes. + +Current Russian labels (transliteration target): + +| `name_key` | English | Russian (UI) | +|------------|---------|----------------| +| `town.willowdale.v1` | Willowdale | Виллоудейл | +| `town.thornwatch.v1` | Thornwatch | Торнвотч | +| `town.ashengard.v1` | Ashengard | Ашенгард | +| `town.redcliff.v1` | Redcliff | Редклифф | +| `town.boghollow.v1` | Boghollow | Богхоллоу | +| `town.cinderkeep.v1` | Cinderkeep | Синдеркип | +| `town.starfall.v1` | Starfall | Старфолл | +| `town.mossharbor.v1` | Mossharbor | Моссхарбор | +| `town.emberwell.v1` | Emberwell | Эмбервелл | +| `town.frostmark.v1` | Frostmark | Фростмарк | +| `town.duskwatch.v1` | Duskwatch | Дасквотч | + +Quest descriptions in Russian should use **these same spellings** when they mention a town. + +## Quest copy + +- Server stores English `title` / `description` on `quests` (authoring and fallback). +- Client resolves text by `quests.quest_key` using `frontend/src/i18n/quests.en.yml` and `quests.ru.yml` (loaded in `loadLocales.ts` together with `en.yml` / `ru.yml`). Keys must match `quest_key` in the database; EN and RU files must have the same set of keys (validated at startup). +- If a key is missing in YAML, the client falls back to the server string (usually English). +- For `visit_town` rows, the API includes `quest.targetTownId`. The quest log uses `townDisplayById()` so the destination city name follows the town transliteration rules above, not the raw English `targetTownName` from SQL. + +## Related files + +- Town labels and `towns.id` map: `frontend/src/i18n/contentLabels.ts` +- Quest strings: `frontend/src/i18n/quests.en.yml`, `frontend/src/i18n/quests.ru.yml`, `localizedQuestText` in `frontend/src/i18n/loadLocales.ts` diff --git a/frontend/src/i18n/quests.en.yml b/frontend/src/i18n/quests.en.yml new file mode 100644 index 0000000..8b5a4f5 --- /dev/null +++ b/frontend/src/i18n/quests.en.yml @@ -0,0 +1,172 @@ +# Quest copy: keys MUST match quests.quest_key in DB. English matches server seed. +'quest.1': + title: Wolf Cull + description: The wolves near Willowdale are getting bolder. Thin their numbers. +'quest.2': + title: Boar Hunt + description: Wild boars are trampling the crops. Take care of them. +'quest.3': + title: Deliver to Thornwatch + description: Carry this supply manifest to Guard Halric in Thornwatch. +'quest.4': + title: Spider Infestation + description: Cave spiders have overrun the logging trails. Clear them out. +'quest.5': + title: Spider Fang Collection + description: We need spider fangs for antivenom. Collect them from slain spiders. +'quest.6': + title: Forest Patrol + description: Slay any 15 creatures along the forest road to keep it safe. +'quest.7': + title: Undead Purge + description: The ruins are crawling with undead. Destroy the zombies. +'quest.8': + title: Ancient Relics + description: Search fallen enemies for fragments of the old kingdom. +'quest.9': + title: Report to Redcliff + description: Warn Foreman Brak about the growing undead threat. +'quest.10': + title: Orc Raider Cleanup + description: Orc warriors are raiding the mine carts. Stop them. +'quest.11': + title: Ore Samples + description: Collect glowing ore fragments from defeated enemies near the canyon. +'quest.12': + title: Swamp Creatures + description: The swamp beasts grow more aggressive by the day. Cull 25. +'quest.13': + title: Venomous Harvest + description: Collect venom sacs from swamp creatures for my brews. +'quest.14': + title: Message to Cinderkeep + description: The forgemaster needs to know about the corruption spreading here. +'quest.15': + title: Demon Slayer + description: Fire demons are emerging from the vents. Destroy them. +'quest.16': + title: Infernal Cores + description: Retrieve smoldering cores from defeated fire demons. +'quest.17': + title: "Titan's Challenge" + description: The Lightning Titans must be stopped before they breach the gate. +'quest.18': + title: Void Fragments + description: Gather crystallized void energy from the astral enemies. +'quest.19': + title: Full Circle + description: Return to Willowdale and tell Elder Maren of your journey. +'quest.mossharbor_skeleton_cull.v1': + title: Harborbone Sweep + description: Clear risen bones stalking the docks and tide paths. +'quest.mossharbor_letter_willowdale.v1': + title: Letter for Willowdale + description: Carry this sealed letter to Elder Maren in Willowdale. +'quest.mossharbor_road_tolls.v1': + title: Road Tolls + description: Bandits are shaking down travelers on the meadow road. Stop them. +'quest.mossharbor_contraband.v1': + title: Contraband Pouches + description: Recover marked pouches from fallen bandits for the harbor tally. +'quest.emberwell_cultist_dispersal.v1': + title: Cultist Dispersal + description: A splinter sect is burning waymarkers. Cut their numbers. +'quest.emberwell_elemental_disturbance.v1': + title: Elemental Disturbance + description: Rogue elementals are destabilizing the treeline. Banish them. +'quest.emberwell_scout_ashengard.v1': + title: Scout Ashengard + description: Deliver Ranger Kess's field notes to Scholar Orin in Ashengard. +'quest.emberwell_spell_ash.v1': + title: Spell Ash Samples + description: Collect ash-touched reagents from defeated cultists. +'quest.emberwell_perimeter.v1': + title: Ember Perimeter + description: Thin any hostile creatures pressing the Emberwell outskirts. +'quest.frostmark_golem_breakers.v1': + title: Golem Breakers + description: Animated rubble blocks old trade cuts. Smash the golems. +'quest.frostmark_wraith_tide.v1': + title: Wraith Tide + description: Cold wraiths cling to the ruins road. Send them on. +'quest.frostmark_shade_reagents.v1': + title: Shade Reagents + description: Alchemists need slow-essence cores from shades. +'quest.frostmark_word_boghollow.v1': + title: Word to Boghollow + description: Carry Torvik's warning about the mist to Witch Nessa. +'quest.frostmark_kingless_dead.v1': + title: Kingless Dead + description: Bone sovereigns rally the lesser dead. Strike the heads first. +'quest.duskwatch_fen_titans.v1': + title: Titans in the Fen + description: Titans wade the deep bog where lesser things fear to go. +'quest.duskwatch_heartwood.v1': + title: Heartwood Banishing + description: Treant roots poison the stilts. Cut them back. +'quest.duskwatch_warden_due.v1': + title: "Warden's Due" + description: Forest wardens claim the marsh as their grove. Prove otherwise. +'quest.duskwatch_starfall_ride.v1': + title: Ride to Starfall + description: Sister Morah needs omen-salts from Seer Aelith at Starfall. +'quest.willowdale_mossharbor_run.v1': + title: Mossharbor Run + description: Finn wants you to confirm the harbor is still trading. +'quest.willowdale_wolf_pelts.v1': + title: Wolf Pelts for Market + description: Bring back presentable pelts from wolves along the road. +'quest.thornwatch_scaleback_cull.v1': + title: Scaleback Cull + description: Battle lizards sun themselves on the bluffs. Reduce their packs. +'quest.thornwatch_spider_glands.v1': + title: Spider Glands + description: The infirmary needs fresh glands for trail antidotes. +'quest.thornwatch_emberwell_resupply.v1': + title: Emberwell Resupply + description: Bring this crate of resin vials to Ranger Kess in Emberwell. +'quest.ashengard_rattling_ranks.v1': + title: Rattling Ranks + description: Skeleton patrols pace the breach. Break their line. +'quest.ashengard_royal_marrow.v1': + title: Royal Marrow + description: Fetch marrow shards from bone sovereigns for Orin's rite. +'quest.ashengard_redcliff_errand.v1': + title: Redcliff Errand + description: Carry the sealed rubbings to Foreman Brak in Redcliff. +'quest.redcliff_wyvern_coast.v1': + title: Wyvern on the Coast + description: Wyverns circle the lift crags. Drive them off. +'quest.redcliff_orc_caches.v1': + title: Orc Ritual Caches + description: Search slain orc raiders for carved tokens the miners saw. +'quest.redcliff_summit_courier.v1': + title: Summit Courier + description: Brak needs these manifests delivered to Warden Torvik in Frostmark. +'quest.boghollow_marsh_harpies.v1': + title: Marsh Harpies + description: Harpies pick off ferry ropes. Ground them. +'quest.boghollow_manticore_quota.v1': + title: Manticore Quota + description: The village needs proof you can handle the deep marsh alphas. +'quest.boghollow_duskwatch_warning.v1': + title: Duskwatch Warning + description: Tell Sister Morah the eastern pools are boiling. +'quest.cinderkeep_sovereign_ash.v1': + title: Sovereign Ash + description: Elite demons leave ash that still whispers. Collect it. +'quest.cinderkeep_infernal_line.v1': + title: Infernal Line + description: 'Hold the lava veins: cull demons before they crest the berm.' +'quest.cinderkeep_starfall_prelude.v1': + title: Starfall Prelude + description: Kael wants a reading of the astral veil from Seer Aelith. +'quest.starfall_shade_erasure.v1': + title: Shade Erasure + description: Shades pool where the road thins into void. Erase them. +'quest.starfall_manticore_spines.v1': + title: Manticore Crown Spines + description: Gather intact crown spines for Aelith's focus circles. +'quest.starfall_cinder_echo.v1': + title: Cinder Echo + description: Return a stabilized echo-crystal to Forge-master Kael. diff --git a/frontend/src/i18n/quests.ru.yml b/frontend/src/i18n/quests.ru.yml new file mode 100644 index 0000000..e4d0ba2 --- /dev/null +++ b/frontend/src/i18n/quests.ru.yml @@ -0,0 +1,172 @@ +# Ключи как в БД. Названия городов — транслитерация (см. docs/i18n-display-rules.md). +'quest.1': + title: Резня волков + description: Волки у Виллоудейла стали смелее. Уменьши их стаю. +'quest.2': + title: Охота на кабанов + description: Дикие кабаны топчут посевы. Разберись с ними. +'quest.3': + title: Доставка в Торнвотч + description: Отнеси этот манифест поставок страже Халрику в Торнвотч. +'quest.4': + title: Паучье нашествие + description: Пещерные пауки заполонили тропы лесорубов. Зачисти тропы. +'quest.5': + title: Сбор паучьих клыков + description: Для противоядия нужны клыки пауков. Добудь их у убитых тварей. +'quest.6': + title: Лесной патруль + description: Убей любых 15 тварей на лесной дороге, чтобы её прочистить. +'quest.7': + title: Чистка нежити + description: По руинам ползут мертвецы. Уничтожь зомби. +'quest.8': + title: Древние реликвии + description: Ищи у поверженных врагов осколки старого королевства. +'quest.9': + title: Донесение в Редклифф + description: Предупреди бригадира Брака о росте угрозы со стороны нежити. +'quest.10': + title: Разборка с налётчиками + description: Орки-налётчики грабят вагонетки у шахт. Останови их. +'quest.11': + title: Образцы руды + description: Собери светящиеся осколки руды с поверженных врагов у каньона. +'quest.12': + title: Болотные твари + description: Болотные звери злее с каждым днём. Убей 25. +'quest.13': + title: Ядовитый урожай + description: Собери мешочки с ядом с болотных тварей для моих зелий. +'quest.14': + title: Весть в Синдеркип + description: Кузнецу-наставнику нужно знать о расползающейся порче здесь. +'quest.15': + title: Истребитель демонов + description: Из жерл выползают огненные демоны. Уничтожь их. +'quest.16': + title: Инфернальные ядра + description: Достань тлеющие ядра с поверженных огненных демонов. +'quest.17': + title: Испытание титанов + description: Титаны молний должны быть остановлены, пока не прорвали врата. +'quest.18': + title: Осколки пустоты + description: Собери кристаллизованную энергию пустоты с астральных врагов. +'quest.19': + title: Полный круг + description: Вернись в Виллоудейл и доложи старейшине Марен о пути. +'quest.mossharbor_skeleton_cull.v1': + title: Зачистка Гавани костей + description: Прогони ожившие кости, что шатаются у причалов и на отмелях. +'quest.mossharbor_letter_willowdale.v1': + title: Письмо для Виллоудейла + description: Отнеси запечатанное письмо старейшине Марену в Виллоудейл. +'quest.mossharbor_road_tolls.v1': + title: Дорожные поборы + description: Разбойники грабят путников на луговой дороге. Останови их. +'quest.mossharbor_contraband.v1': + title: Мешки контрабанды + description: Верни помеченные мешки с павших разбойников для гаванской опись. +'quest.emberwell_cultist_dispersal.v1': + title: Разгон культистов + description: Отщепенцы жгут путевые столбы. Урежь их число. +'quest.emberwell_elemental_disturbance.v1': + title: Беспорядок элементалей + description: Элементали-изгои рушат опору лесной кромки. Изгони их. +'quest.emberwell_scout_ashengard.v1': + title: Разведка в Ашенгард + description: Передай полевые записки лесничего Кесса учёному Орину в Ашенгарде. +'quest.emberwell_spell_ash.v1': + title: Образцы пепла заклинаний + description: Собери пепельные реагенты с побеждённых культистов. +'quest.emberwell_perimeter.v1': + title: Периметр Эмбервелла + description: Прореди любых враждебных тварей, что подступают к окраинам Эмбервелла. +'quest.frostmark_golem_breakers.v1': + title: Крушители големов + description: Оживший щебень перекрыл старые торговые прорези. Разнеси големов. +'quest.frostmark_wraith_tide.v1': + title: Прилив призраков + description: Холодные призраки цепляются за дорогу руин. Отправь их по адресу. +'quest.frostmark_shade_reagents.v1': + title: Реагенты теней + description: Алхимикам нужны ядра медленной сущности с теней. +'quest.frostmark_word_boghollow.v1': + title: Слово в Богхоллоу + description: Отнеси предупреждение Торвика о тумане ведьме Нессе. +'quest.frostmark_kingless_dead.v1': + title: Мёртвые без короля + description: Владыки костей собирают младшую нежить. Бей в первую очередь по ним. +'quest.duskwatch_fen_titans.v1': + title: Титаны на трясине + description: Титаны бродят по глубокому болоту, куда мелочь не сунется. +'quest.duskwatch_heartwood.v1': + title: Изгнание с сердцевины + description: Корни древней отравляют сваи. Подрежь их. +'quest.duskwatch_warden_due.v1': + title: Долг лесных стражей + description: Лесные стражи объявляют топь своей рощей. Докажи обратное. +'quest.duskwatch_starfall_ride.v1': + title: Выезд в Старфолл + description: Сестре Море нужны соли-предзнаменования у провидицы Эйлит в Старфолле. +'quest.willowdale_mossharbor_run.v1': + title: Забег в Моссхарбор + description: Финн хочет убедиться, что гавань всё ещё торгует. +'quest.willowdale_wolf_pelts.v1': + title: Волчьи шкуры на рынок + description: Принеси презентабельные шкуры с волков с дороги. +'quest.thornwatch_scaleback_cull.v1': + title: Резня чешуеспинов + description: Боевые ящеры греются на уступах. Уменьши их стаи. +'quest.thornwatch_spider_glands.v1': + title: Паучьи железы + description: Лазарету нужны свежие железы для следовых противоядий. +'quest.thornwatch_emberwell_resupply.v1': + title: Пополнение Эмбервелла + description: Отнеси ящик смоляных склянок лесничему Кессу в Эмбервелл. +'quest.ashengard_rattling_ranks.v1': + title: Дрожащие ряды + description: Скелетные патрули ходят у пролома. Разомкни их линию. +'quest.ashengard_royal_marrow.v1': + title: Королевский костный мозг + description: Достань осколки костного мозга у владык костей для обряда Орина. +'quest.ashengard_redcliff_errand.v1': + title: Поручение в Редклифф + description: Отнеси запечатанные снимки бригадиру Браку в Редклифф. +'quest.redcliff_wyvern_coast.v1': + title: Виверны у берега + description: Виверны крутятся над подъёмными утёсами. Прогони их. +'quest.redcliff_orc_caches.v1': + title: Орочьи ритуальные тайники + description: Обыщи убитых орков-налётчиков за резными жетонами, что видели шахтёры. +'quest.redcliff_summit_courier.v1': + title: Курьер на вершину + description: Браку нужно доставить эти манифесты стражу Торвику во Фростмарк. +'quest.boghollow_marsh_harpies.v1': + title: Болотные гарпии + description: Гарпии перегрызают паромные канаты. Приземли их. +'quest.boghollow_manticore_quota.v1': + title: Квота на мантикор + description: Селу нужно доказательство, что ты справишься с альфами глубокого болота. +'quest.boghollow_duskwatch_warning.v1': + title: Предупреждение для Дасквотча + description: Скажи сестре Море, что восточные пуды кипят. +'quest.cinderkeep_sovereign_ash.v1': + title: Пепел владык + description: У элитных демонов остаётся пепел, что ещё шепчет. Собери его. +'quest.cinderkeep_infernal_line.v1': + title: Инфернальный рубеж + description: 'Держи лавовые жилы: истреби демонов, пока они не перешли вал.' +'quest.cinderkeep_starfall_prelude.v1': + title: Прелюдия Старфолла + description: Кейлу нужно прочтение астральной завесы у провидицы Эйлит. +'quest.starfall_shade_erasure.v1': + title: Стирать тени + description: Тени скапливаются, где дорога редеет в пустоту. Сотри их. +'quest.starfall_manticore_spines.v1': + title: Коронные шипы мантикор + description: Собери целые шипы с короны для фокус-кругов Эйлит. +'quest.starfall_cinder_echo.v1': + title: Угольное эхо + description: Верни стабилизированный эхо-кристалл кузнецу-наставнику Кейлу.