55 Commits

Author SHA1 Message Date
6782cfcd87 Merge branch 'feat/sync-parent-meta' 2026-04-09 10:58:42 +03:00
eaf84ad605 Скрипт синхронизации parent meta переведен на загрузку из git 2026-04-09 10:58:18 +03:00
65e3f5b48e Добавлены action и скрипт синхронизации parent meta, уточнены правила подтверждения 2026-04-09 10:54:30 +03:00
9519b92771 Уточнил правило смены ветки: останавливать выполнение до явного решения пользователя 2026-04-09 10:37:19 +03:00
6257027a13 Обновлено описание мода в meta.lsx 2026-04-09 10:34:23 +03:00
cde9194ed5 Разделил правила AGENTS.md на общие и проектные 2026-04-09 08:58:43 +03:00
1c8cf13f67 Уточнен принцип сжатия правил: оптимизация под AI-агента 2026-04-09 08:53:27 +03:00
74a8942999 Уточнен формат ссылки на релиз: [version](url) 2026-04-09 08:51:14 +03:00
7f8f09a3ac Исправлен set-version: обновление только ModuleInfo.Version64 и сужены правила в AGENTS
All checks were successful
Build Mod Package / build (push) Successful in 9s
2026-04-09 08:47:39 +03:00
70f93c3d29 Обновлен перевод russian.xml по upstream: добавлены новые строки и синхронизирована Метка охотника
All checks were successful
Build Mod Package / build (push) Successful in 10s
2026-04-09 08:33:59 +03:00
4aa2e136b2 Уточнить поведение при отсутствии совпадения action 2026-04-09 08:26:40 +03:00
3ae30a5263 Добавить и оптимизировать внутренний ранбук ACTIONS.md 2026-04-09 08:15:43 +03:00
4da26911fe Уточнить политику веток: предлагать ветку в начале и MR/merge в конце 2026-04-09 07:53:33 +03:00
df1daee6ab Перенести комментарий о CI-особенности Divine в build.ps1 2026-04-09 07:49:11 +03:00
9d1a26c8e0 Сжать AGENTS.md и убрать дубли правил публикации 2026-04-09 07:46:53 +03:00
8a4970742c Упростить правила публикации и обновлять только ModuleInfo/Version64 2026-04-09 07:37:55 +03:00
b50a6a2f95 Зафиксировать изменения meta.lsx из BG3 Toolkit и правило релизного тега
All checks were successful
Build Mod Package / build (push) Successful in 2s
2026-04-09 07:29:24 +03:00
4646b51459 Подготовить версию v0.2.1 в meta.lsx
All checks were successful
Build Mod Package / build (push) Successful in 3s
2026-04-09 07:03:15 +03:00
a72b7bc1e1 Добавить скрипт обновления версии meta.lsx перед выпуском 2026-04-09 07:00:35 +03:00
7aca648396 Добавить правило про ссылки на архивы релизов
All checks were successful
Build Mod Package / build (push) Successful in 4s
2026-04-08 23:48:58 +03:00
36129b15d1 Дополнить русскую локализацию по оригинальному english.xml
All checks were successful
Build Mod Package / build (push) Successful in 4s
2026-04-08 23:43:31 +03:00
97ca95ba16 Исправлена кодировка описания мода
All checks were successful
Build Mod Package / build (push) Successful in 15s
2026-04-08 23:23:49 +03:00
ad129e15d5 chore: add metadata.lsf for DnD 5.5e AIO Russian mod GUI 2026-04-08 23:19:00 +03:00
c8371a3fec Обновлена локализация по глоссарию, дополнены черты происхождения и добавлен логотип публикации
All checks were successful
Build Mod Package / build (push) Successful in 55s
2026-04-08 22:20:13 +03:00
321fef2f63 Уточнены ориентиры для перевода в AGENTS.md 2026-04-08 22:06:59 +03:00
eb9ba5eefa Добавлен перевод новых строк локализации для голиафа и стрелка
All checks were successful
Build Mod Package / build (push) Successful in 30s
2026-04-08 21:52:36 +03:00
c0524832d0 Добавлен BOM для meta.lsx в сборке и уточнён перевод " Расщепление разума\
All checks were successful
Build Mod Package / build (push) Successful in 35s
2026-04-08 21:31:40 +03:00
e78610c702 Update Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml
All checks were successful
Build Mod Package / build (push) Successful in 28s
2026-04-08 21:17:13 +03:00
5c0a44a71e Update Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml
All checks were successful
Build Mod Package / build (push) Successful in 49s
2026-04-08 21:16:39 +03:00
c859ddc50c Update Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml 2026-04-08 21:16:20 +03:00
5f3ca9ae0d Update Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml 2026-04-08 21:14:33 +03:00
782879d73e Update Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml
All checks were successful
Build Mod Package / build (push) Successful in 46s
2026-04-08 21:12:06 +03:00
d5cd0300da revert 85a7ec546c
revert Исправлен перевод CSV и обновлены правила коммита
2026-04-08 20:40:54 +03:00
85a7ec546c Исправлен перевод CSV и обновлены правила коммита 2026-04-08 20:37:02 +03:00
37d34f8406 Merge pull request 'fix: синхронизировать термины russian.xml с глоссарием' (#2) from fix/translation-glossary-sync-20260408 into main
All checks were successful
Build Mod Package / build (push) Successful in 8s
Reviewed-on: mikhail/bg3-dnd55e-russian-localization#2
2026-04-08 20:10:29 +03:00
fba22ac1aa Merge branch 'main' into fix/translation-glossary-sync-20260408 2026-04-08 20:10:19 +03:00
0d42f9ca34 fix: синхронизировать термины russian.xml с глоссарием 2026-04-08 20:06:26 +03:00
7a410d4124 Merge branch 'main' of https://git.shahovalov.ru/mikhail/bg3-dnd55e-russian-localization
All checks were successful
Build Mod Package / build (push) Successful in 23s
2026-04-08 19:55:46 +03:00
945ede2583 Исправлена работа Invoke-WebRequest на Windows PowerShell 2026-04-08 19:53:47 +03:00
469cd8bc37 docs: add glossary file reference to AGENTS.md 2026-04-08 19:53:10 +03:00
c1ca11ab25 Update Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml
Some checks failed
Build Mod Package / build (push) Failing after 6s
2026-04-08 19:50:19 +03:00
042b1fb43b Update Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml 2026-04-08 16:40:10 +03:00
c49ff67d51 Merge pull request 'feat: обновить глоссарий под BG3' (#1) from feat/glossary-bg3-aligned into main
Reviewed-on: mikhail/bg3-dnd55e-russian-localization#1
2026-04-08 15:09:05 +03:00
2324bf0c26 Merge branch 'main' into feat/glossary-bg3-aligned 2026-04-08 15:08:50 +03:00
4148e8b861 Уточнены требования к формулировке сообщений коммитов 2026-04-08 15:06:57 +03:00
3c893cd0d9 Дополнить AGENTS.md правилом повторной отправки 2026-04-08 15:04:52 +03:00
2a7b6d9395 Дополнить AGENTS.md правилом про предложение нового релиза 2026-04-08 15:01:53 +03:00
f04d14dcf1 feat: обновить глоссарий под BG3 2026-04-08 14:20:23 +03:00
4bb64d35da Добавить AGENTS.md с правилами работы по проекту 2026-04-08 12:39:58 +03:00
cb92587449 feat: add Russian glossary for D&D terminology 2026-04-08 11:42:39 +03:00
84c9baa2d5 chore: delete build script for BG3 Russian package 2026-04-08 01:30:22 +03:00
a60aa56477 Run CI only for tags and manual dispatch
All checks were successful
Build Mod Package / build (push) Successful in 18s
2026-04-08 01:16:56 +03:00
6d1186b60a Derive mod version from release tag during build
Some checks failed
Build Mod Package / build (push) Failing after 11s
2026-04-08 01:10:17 +03:00
83dcb77425 Stage package sources in temp directory
All checks were successful
Build Mod Package / build (push) Successful in 6s
2026-04-08 00:58:51 +03:00
e67c7e6093 Add fallback package source strategies to build script
Some checks failed
Build Mod Package / build (push) Failing after 5s
2026-04-08 00:56:22 +03:00
12 changed files with 1788 additions and 267 deletions

View File

@@ -2,9 +2,6 @@ name: Build Mod Package
on: on:
push: push:
branches:
- main
- master
tags: tags:
- "v*" - "v*"
workflow_dispatch: workflow_dispatch:
@@ -62,7 +59,7 @@ jobs:
throw "Could not find a downloadable LSLib zip asset in the latest release." throw "Could not find a downloadable LSLib zip asset in the latest release."
} }
Invoke-WebRequest -Uri $asset.browser_download_url -OutFile ".tools/lslib/lslib.zip" Invoke-WebRequest -UseBasicParsing -Uri $asset.browser_download_url -OutFile ".tools/lslib/lslib.zip"
Expand-Archive -LiteralPath ".tools/lslib/lslib.zip" -DestinationPath ".tools/lslib" -Force Expand-Archive -LiteralPath ".tools/lslib/lslib.zip" -DestinationPath ".tools/lslib" -Force
- name: Build .pak - name: Build .pak
@@ -160,4 +157,4 @@ jobs:
Accept = "application/json" Accept = "application/json"
} }
Invoke-WebRequest -Method Post -Uri "$apiBase/releases/$($release.id)/assets?name=$([uri]::EscapeDataString($assetName))" -Headers $uploadHeaders -ContentType "application/octet-stream" -InFile $zipPath Invoke-WebRequest -UseBasicParsing -Method Post -Uri "$apiBase/releases/$($release.id)/assets?name=$([uri]::EscapeDataString($assetName))" -Headers $uploadHeaders -ContentType "application/octet-stream" -InFile $zipPath

85
ACTIONS.md Normal file
View File

@@ -0,0 +1,85 @@
# ACTIONS.md
VERSION: 2
MODE: machine-first
LANG: ru
ROUTING:
- match_user_request_to_action_id: true
- if_match: propose_action
- if_no_match: ignore_actions_md
- if_no_match_user_message: none
PROPOSE_RULE:
- prompt_template: "Приступить к выполнению '{action_id}'?"
- require_user_confirmation: true
- execute_without_confirmation: false
EXECUTION_BASELINE:
- enforce_agents_md: true
- minimal_non_breaking_changes: true
- steps_count_range: [3, 7]
- before_commit_push: request_user_approval
REPORT_FORMAT:
- done
- changed_files
- checks
- remaining
ACTIONS:
translation:update:
intent: sync_ru_translation_with_upstream
inputs:
- Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml
- glossary/glossary.normalized.json
- AGENTS.md::Canonical Paths::Upstream English reference
plan:
- compare_en_vs_ru_by_keys
- classify_diff_into_new_changed_stale_candidate
- update_ru_for_new_and_changed_using_glossary
- validate_xml_structure_and_service_attributes
- prepare_delta_summary_counts
checks:
- xml_valid
- glossary_consistency
- scope_limited_to_localization_and_allowed_metadata
outputs:
- Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml
- optional: Mods/DnD 5.5e AIO Russian/meta.lsx (release-only)
action:report:
intent: unified_task_report
inputs:
- task_context
- modified_files
- verification_results
plan:
- summarize_done
- list_changed_files
- list_checks
- list_remaining
checks:
- concise
- factual
- no_unverified_claims
outputs:
- final_user_report
meta:sync-parent:
intent: sync_dependency_moduleshortdesc_from_parent_meta
inputs:
- parent_meta_git_url (optional; defaults to upstream)
- Mods/DnD 5.5e AIO Russian/meta.lsx
plan:
- read_parent_moduleinfo_fields
- validate_required_fields_folder_md5_name_publishhandle_uuid_version64
- update_target_dependencies_moduleshortdesc_fields
- validate_xml_structure
- report_changed_fields
checks:
- xml_valid
- required_parent_fields_present
- only_dependencies_moduleshortdesc_changed
outputs:
- Mods/DnD 5.5e AIO Russian/meta.lsx

87
AGENTS.md Normal file
View File

@@ -0,0 +1,87 @@
# AGENTS.md
## General Rules (MUST)
### Git Collaboration Policy (General)
- Ask user permission before commit.
- After approval: commit and push immediately.
- At the start of each new fix/feature task: pause task execution, propose switching to a dedicated `fix/*` or `feat/*` branch, and continue only after explicit user decision on branch change necessity.
- After finishing work in `fix/*` or `feat/*`: propose either
1. creating an MR into `main`, or
2. merging to `main` immediately and deleting the `fix/*`/`feat/*` branch.
- If push fails: retry up to 2 more times with 3s pause.
- Never auto-commit/auto-push without explicit user approval.
- Approval prompts for pending actions: short direct question in imperative form, no soft/opening phrases.
- If multiple actions or combinations are possible: provide a numbered options list so user can reply with a number.
### Cleanup (General)
- Do not leave temporary/debug artifacts in repo.
- Remove additional debug/temp dirs unless user asked to keep them.
### Rules Maintenance (General)
- For changes to rules files (`AGENTS.md`, `ACTIONS.md`): prefer optimized, compressed edits for AI-agent execution (machine-readable, unambiguous).
- Keep rule updates minimal and non-duplicative: merge overlapping points, remove redundancy, preserve intent.
## Project-Specific Rules (MUST)
### Scope
- Repository purpose: standalone Russian localization mod only.
- Allowed domain: localization content + packaging/release metadata.
- Forbidden: gameplay logic, Script Extender content, unrelated assets.
- Keep repository source-only.
- Never commit `.pak` or temporary build artifacts.
### Canonical Paths
- Mod sources: `Mods/DnD 5.5e AIO Russian`
- Russian localization: `Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml`
- Mod metadata: `Mods/DnD 5.5e AIO Russian/meta.lsx`
- Build script (single source of build truth): `scripts/build.ps1`
- CI workflow: `.gitea/workflows/build.yml`
- Glossary (primary terminology reference): `glossary/glossary.normalized.json`
- Action catalog and command playbooks: `ACTIONS.md`
- Upstream English reference: `https://github.com/Yoonmoonsik/dnd55e/blob/main/Mods/DnD2024_897914ef-5c96-053c-44af-0be823f895fe/Localization/English/english.xml`
### Packaging Invariants
- `.pak` must contain only BG3 mod structure under `Mods/...`.
- Required content in `.pak`:
- `Mods/DnD 5.5e AIO Russian/meta.lsx`
- `Mods/DnD 5.5e AIO Russian/Localization/Russian/russian.xml`
- Must not leak into `.pak`: `.git`, `.gitea`, `scripts`, `tools`, `.tools`, `build`, staging dirs.
- Staging for packaging must be in `%TEMP%`, not in dot-prefixed repo dirs.
### Build/CI Contract
- CI workflow stays thin:
1. prepare workspace
2. download Divine
3. call `scripts/build.ps1`
4. publish tag archive
- Expected build outputs:
- `build/DnD 5.5e AIO Russian.pak`
- `build/info.json`
- `build/DnD 5.5e AIO Russian <tag>.zip` (for tag builds)
- Release ZIP must include only `.pak` + `info.json`.
- CI triggers: tag `v*` and manual dispatch; not every push to `main`.
### Version/Release Rules
- Read release version only from `save/region/node[@id="ModuleSettings"]/children/node[@id="ModuleInfo"]/attribute[@id="Version64"]` via explicit XML parsing.
- `PublishVersion` must not be changed during release preparation.
- Release tag must match the source-of-truth version.
- Decision logic before tagging:
1. If `ModuleInfo/Version64` was manually changed (e.g. BG3 Toolkit), use matching tag and release.
2. If `ModuleInfo/Version64` equals latest released version, bump version first (e.g. `scripts/set-version.ps1 -VersionTag <tag>`), commit, then create/push tag.
- `scripts/build.ps1` derives release `Version64` from tag and writes it to generated `info.json` and staged `meta.lsx`.
### info.json Contract
- Top-level keys: `Mods`, `MD5`.
- Per-mod keys: `Author`, `Name`, `Folder`, `Version`, `Description`, `UUID`, `Created`, `Dependencies`, `Group`.
- `Dependencies` is an array of UUIDs.
- Current dependency UUID: `897914ef-5c96-053c-44af-0be823f895fe`.
### Git Collaboration Policy (Project-Specific)
- Commit messages and comments: Russian.
- Commit message content: what was done (not what should be done).
- If changes affect `.pak` contents or build/release flow: propose releasing next version.
- For released versions in user-facing messages: provide direct archive link in Markdown format `[version](url)` when derivable (acceptable immediately after tag push, even before CI finishes).
### Cleanup (Project-Specific)
- Ignored/temp patterns include: `build/`, `build-stage*`, `.tools/`, `*.pak`.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@@ -4,37 +4,70 @@
<region id="Config"> <region id="Config">
<node id="root"> <node id="root">
<children> <children>
<node id="Conflicts"/>
<node id="Dependencies"> <node id="Dependencies">
<children> <children>
<node id="ModuleShortDesc"> <node id="ModuleShortDesc">
<attribute id="Folder" type="LSString" value=""/> <attribute id="Folder" type="LSString" value="DnD2024_897914ef-5c96-053c-44af-0be823f895fe"/>
<attribute id="MD5" type="LSString" value=""/> <attribute id="MD5" type="LSString" value="4bd42ca93f895d1ec521a286bea09ef2"/>
<attribute id="Name" type="LSString" value="DnD 5.5e All-in-One BEYOND"/> <attribute id="Name" type="LSString" value="DnD 5.5e All-in-One BEYOND"/>
<attribute id="PublishHandle" type="uint64" value="0"/> <attribute id="PublishHandle" type="uint64" value="4419649"/>
<attribute id="UUID" type="guid" value="897914ef-5c96-053c-44af-0be823f895fe"/> <attribute id="UUID" type="guid" value="897914ef-5c96-053c-44af-0be823f895fe"/>
<attribute id="Version64" type="int64" value="36028797018963968"/> <attribute id="Version64" type="int64" value="144396675937468416"/>
</node> </node>
</children> </children>
</node> </node>
<node id="ModuleInfo"> <node id="ModuleInfo">
<attribute id="Author" type="LSString" value="MikhailRaw"/> <attribute id="Author" type="LSString" value="MikhailRaw"/>
<attribute id="CharacterCreationLevelName" type="FixedString" value=""/> <attribute id="CharacterCreationLevelName" type="FixedString" value=""/>
<attribute id="Description" type="LSString" value="Русская локализация мода, который добавляет и обновляет контент в соответствии с правилами DnD 5.5e и другими источниками, включая предыстории, классы, таланты, расы, заклинания и многое другое. Это отдельный мод локализации и он требует установленный оригинальный мод."/> <attribute id="Description" type="LSString" value="Русский перевод мода DnD 5.5e All-in-One BEYOND. Перевод ещё в разработке: AI помогает быстро обновлять тексты, а финальные правки и качество мы проверяем вручную."/>
<attribute id="FileSize" type="uint64" value="0"/> <attribute id="FileSize" type="uint64" value="2488095"/>
<attribute id="Folder" type="LSString" value="DnD 5.5e AIO Russian"/> <attribute id="Folder" type="LSString" value="DnD 5.5e AIO Russian"/>
<attribute id="LobbyLevelName" type="FixedString" value=""/> <attribute id="LobbyLevelName" type="FixedString" value=""/>
<attribute id="MD5" type="LSString" value=""/> <attribute id="MD5" type="LSString" value="c0a8f3412870277331306e0719fc6f77"/>
<attribute id="MenuLevelName" type="FixedString" value=""/> <attribute id="MenuLevelName" type="FixedString" value=""/>
<attribute id="Name" type="LSString" value="DnD 5.5e All-in-One BEYOND Russian Localization"/> <attribute id="Name" type="LSString" value="DnD 5.5e All-in-One BEYOND Russian Localization"/>
<attribute id="NumPlayers" type="uint8" value="4"/> <attribute id="NumPlayers" type="uint8" value="4"/>
<attribute id="PhotoBooth" type="FixedString" value=""/> <attribute id="PhotoBooth" type="FixedString" value=""/>
<attribute id="PublishHandle" type="uint64" value="0"/> <attribute id="PublishHandle" type="uint64" value="5965149"/>
<attribute id="StartupLevelName" type="FixedString" value=""/> <attribute id="StartupLevelName" type="FixedString" value=""/>
<attribute id="UUID" type="FixedString" value="6401e84d-daf2-416d-adeb-99c03a2487a6"/> <attribute id="UUID" type="FixedString" value="6401e84d-daf2-416d-adeb-99c03a2487a6"/>
<attribute id="Version64" type="int64" value="36028797018963968"/> <attribute id="Version64" type="int64" value="281477124194307"/>
<children> <children>
<node id="PublishVersion"> <node id="PublishVersion">
<attribute id="Version64" type="int64" value="36028797018963968"/> <attribute id="Version64" type="int64" value="281477124194304"/>
</node>
<node id="Scripts">
<children>
<node id="Script">
<attribute id="UUID" type="FixedString" value="1953f77d-a201-45d7-a194-9b84c34b8461"/>
<children>
<node id="Parameters">
<children>
<node id="Parameter">
<attribute id="MapKey" type="FixedString" value="HardcoreOnly"/>
<attribute id="Type" type="int32" value="1"/>
<attribute id="Value" type="LSString" value="0"/>
</node>
</children>
</node>
</children>
</node>
<node id="Script">
<attribute id="UUID" type="FixedString" value="0d6510f5-50a3-4ecd-83d8-134c9a640324"/>
<children>
<node id="Parameters">
<children>
<node id="Parameter">
<attribute id="MapKey" type="FixedString" value="HardcoreOnly"/>
<attribute id="Type" type="int32" value="1"/>
<attribute id="Value" type="LSString" value="0"/>
</node>
</children>
</node>
</children>
</node>
</children>
</node> </node>
</children> </children>
</node> </node>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View File

@@ -0,0 +1,862 @@
{
"AC": "КБ",
"Ability": "характеристика",
"Ability Check": "проверка характеристики",
"Ability Checks": "проверки характеристик",
"Acid Splash": "Всплеск кислоты",
"Acid splash": "Всплеск кислоты",
"Acolyte": "Послушник",
"Acrobatics": "Акробатика",
"Actor": "Артистичный",
"Advantage": "преимущество",
"Aid": "Помощь",
"Alarm": "Сигнал тревоги",
"Alert": "Бдительный",
"Alter self": "Смена обличья",
"Animal Friendship": "Дружба с животными",
"Animal Handling": "Дрессировка",
"Animal friendship": "Дружба с животными",
"Animal messenger": "Почтовое животное",
"Animal shapes": "Превращение в животных",
"Animate dead": "Восставший труп",
"Animate objects": "Оживление вещей",
"Antilife shell": "Преграда жизни",
"Antimagic field": "Преграда магии",
"Antipathy/sympathy": "Антипатия/симпатия",
"Arcana": "Магия",
"Arcane Vigor": "Мистическая бодрость",
"Arcane eye": "Магический глаз",
"Arcane gate": "Магические врата",
"Arcane lock": "Волшебный замок",
"Armor": "броня",
"Armor Class": "класс брони",
"Armor of Agathys": "Броня Агафиса",
"Armour": "броня",
"Armour Class": "класс брони",
"Arms of Hadar": "Руки Хадара",
"Astral projection": "Проекция в астрал",
"Athlete": "Атлетичный",
"Athletics": "Атлетика",
"Attack": "атака",
"Attack Action": "действие Атака",
"Attack Roll": "бросок атаки",
"Attack Rolls": "броски атаки",
"Augury": "Гадание",
"Aura of Vitality": "Аура жизненной силы",
"Aura of life": "Аура жизни",
"Aura of purity": "Аура очищения",
"Aura of vitality": "Аура живучести",
"Awaken": "Пробуждение разума",
"Background": "происхождение",
"Backgrounds": "происхождения",
"Bane": "Порча",
"Banishing smite": "Изгоняющая кара",
"Banishment": "Изгнание",
"Barbarian": "варвар",
"Bard": "бард",
"Bardic Inspiration": "Бардовское вдохновение",
"Bardic Inspiration die": "Заряд Бардовского вдохновения",
"Barkskin": "Дубовая кора",
"Battle Inspiration": "Боевое вдохновение",
"Battleaxe": "Боевой топор",
"Beacon of hope": "Маяк надежды",
"Beast sense": "Животные чувства",
"Beguiling Magic": "Чарующая магия",
"Bestow Curse": "Проклятие",
"Bestow Curse: Additional Damage": "Наложение проклятия: Дополнительный урон",
"Bestow Curse: Attack Disadvantage": "Наложение проклятия: Помеха атакам",
"Bestow Curse: Charisma Disadvantage": "Наложение проклятия: Помеха Харизме",
"Bestow Curse: Constitution Disadvantage": "Наложение проклятия: Помеха Телосложению",
"Bestow Curse: Dexterity Disadvantage": "Наложение проклятия: Помеха Ловкости",
"Bestow Curse: Dread": "Наложение проклятия: Ужас",
"Bestow Curse: Intelligence Disadvantage": "Наложение проклятия: Помеха Интеллекту",
"Bestow Curse: Strength Disadvantage": "Наложение проклятия: Помеха Силе",
"Bestow Curse: Wisdom Disadvantage": "Наложение проклятия: Помеха Мудрости",
"Bestow curse": "Проклятие",
"Bigbys hand": "Длань Бигби",
"Blade Ward": "Оберег от оружия",
"Blade barrier": "Стена клинков",
"Blade ward": "Защита от оружия",
"Bless": "Благословение",
"Blessed Healer": "Благословенный целитель",
"Blessed Strikes": "Благословенные удары",
"Blight": "Усыхание",
"Blinded": "Ослеплённый",
"Blinding smite": "Ослепляющая кара",
"Blindness/deafness": "Глухота/слепота",
"Blink": "Мерцание",
"Blowgun": "Духовая трубка",
"Blur": "Размытый образ",
"Bonus Action": "бонусное действие",
"Bonus Unarmed Strike": "Бонусная безоружная атака",
"Booming Blade": "Громовой клинок",
"Branding smite": "Клеймящая кара",
"Brutal Strike": "Жестокий удар",
"Burning hands": "Огненные ладони",
"Bursting Sinew": "Взрыв сухожилий",
"Call lightning": "Призыв молнии",
"Calm emotions": "Умиротворение",
"Cantrip": "фокус",
"Cantrips": "фокусы",
"Chain lightning": "Пляшущая молния",
"Channel Divinity": "Направление божественной энергии",
"Charger": "Налётчик",
"Charisma": "Харизма",
"Charlatan": "Шарлатан",
"Charm Person": "Приворот гуманоида",
"Charm person": "Приворот гуманоида",
"Charmed": "Очарованный",
"Chill Touch": "Пробирающий до костей холод",
"Chill touch": "Леденящее прикосновение",
"Chromatic Orb": "Хроматический шар",
"Chromatic Orb: Acid": "Хроматический шар: кислота",
"Chromatic Orb: Cold": "Хроматический шар: холод",
"Chromatic Orb: Fire": "Хроматический шар: огонь",
"Chromatic Orb: Lightning": "Хроматический шар: молния",
"Chromatic Orb: Poison": "Хроматический шар: яд",
"Chromatic Orb: Thunder": "Хроматический шар: гром",
"Chromatic orb": "Цветной шарик",
"Circle Forms": "Облики круга",
"Circle of death": "Круг смерти",
"Circle of power": "Круг силы",
"Circle of the Moon Spells": "Заклинания круга Луны",
"Clairvoyance": "Подсматривание",
"Class": "класс",
"Cleave": "Рассечение",
"Cleric": "жрец",
"Clone": "Двойник",
"Cloud of Daggers": "Облако кинжалов",
"Cloud of daggers": "Облако кинжалов",
"Cloudkill": "Облако смерти",
"Club": "Дубинка",
"College of Lore": "Коллегия Знаний",
"College of Swords": "Коллегия Мечей",
"College of Valor": "Коллегия Отваги",
"College of Valour": "Коллегия Отваги",
"Color Spray": "Цветные брызги",
"Color spray": "Сверкающие брызги",
"Colour Spray": "Цветные брызги",
"Command": "Приказ",
"Commune": "Общение",
"Commune with nature": "Общение с природой",
"Compelled duel": "Вызов на дуэль",
"Comprehend languages": "Понимание языков",
"Compulsion": "Принуждение",
"Concentration": "концентрация",
"Condition": "Состояние",
"Cone of Cold": "Конус холода",
"Cone of cold": "Конус холода",
"Confusion": "Смятение",
"Conjure animals": "Призыв животных",
"Conjure barrage": "Призыв заграждения",
"Conjure celestial": "Призыв небожителя",
"Conjure elemental": "Призыв элементаля",
"Conjure fey": "Призыв феи",
"Conjure minor elementals": "Призыв малых элементалей",
"Conjure volley": "Призыв залпа",
"Conjure woodland beings": "Призыв лесных обитателей",
"Constitution": "Выносливость",
"Contact other plane": "Связь с иным миром",
"Contagion": "Заражение",
"Contagion: Blinding Sickness": "Заражение: Ослепляющая болезнь",
"Contagion: Filth Fever": "Заражение: Грязная лихорадка",
"Contagion: Flesh Rot": "Заражение: Гниль плоти",
"Contagion: Mindfire": "Заражение: Огонь разума",
"Contagion: Seizure": "Заражение: Припадок",
"Contagion: Slimy Doom": "Заражение: Склизкая гибель",
"Contingency": "Предосторожность",
"Continual flame": "Вечный огонь",
"Control water": "Власть над водами",
"Control weather": "Власть над погодой",
"Cordon of arrows": "Завеса стрел",
"Countercharm": "Контрчары",
"Counterspell": "Контрзаклинание",
"Cover": "укрытие",
"Create Water": "Создание воды",
"Create food and water": "Сотворение пищи и воды",
"Create or destroy water": "Сотворение или уничтожение воды",
"Create undead": "Сотворение нежити",
"Creation": "Сотворение",
"Creature": "Существо",
"Criminal": "Преступник",
"Crossbow Expert": "Эксперт в арбалетах",
"Crossbow, hand": "Арбалет, ручной",
"Crossbow, heavy": "Арбалет, тяжёлый",
"Crossbow, light": "Арбалет, лёгкий",
"Crown of madness": "Корона безумия",
"Crusader's mantle": "Мантия крестоносца",
"Cure Wounds": "Исцеление ран",
"Cure wounds": "Лечение ран",
"Cutting Words": "Острые слова",
"D20 Test": "проверка к20",
"Dagger": "Кинжал",
"Damage": "урон",
"Damage Roll": "бросок урона",
"Dancing Lights": "Пляшущие огоньки",
"Dancing lights": "Пляшущие огоньки",
"Danger Sense": "Чувство опасности",
"Darkness": "Тьма",
"Darkvision": "Ночное зрение",
"Dart": "Дротик",
"Dash": "Рывок",
"Daylight": "Дневной свет",
"Deafened": "Оглохший",
"Death Saving Throw": "спасбросок от смерти",
"Death Saving Throws": "спасброски от смерти",
"Death ward": "Защита от смерти",
"Deception": "Обман",
"Defensive Duelist": "Оборонительный дуэлянт",
"Deflect Attacks": "Отклонение атак",
"Delayed blast fireball": "Замедленный огненный шар",
"Demiplane": "Демиплан",
"Destructive wave": "Разрушительная волна",
"Detect evil and good": "Обнаружение добра и зла",
"Detect magic": "Обнаружение магии",
"Detect poison and disease": "Обнаружение болезней и яда",
"Detect thoughts": "Обнаружение мыслей",
"Dexterity": "Ловкость",
"Difficulty Class": "сложность",
"Dimension door": "Переносящая дверь",
"Disadvantage": "помеха",
"Disciple of Life": "Ученик жизни",
"Disengage": "Отступление",
"Disguise self": "Маскировка",
"Disintegrate": "Распад",
"Dispel evil and good": "Рассеивание добра и зла",
"Dispel magic": "Рассеивание магии",
"Dissonant Whispers": "Диссонирующий шепот",
"Dissonant whisper": "Диссонирующий шёпот",
"Divination": "Предсказание",
"Divine Order": "Божественный приказ",
"Divine Spark": "Божественная искра",
"Divine favor": "Божественное благоволение",
"Divine word": "Божественное слово",
"Dodge": "Уклонение",
"Dominate beast": "Подчинение зверя",
"Dominate monster": "Подчинение чудовища",
"Dominate person": "Подчинение личности",
"Dragonborn": "драконорождённый",
"Drawmijs instant summons": "Дромиджево появление",
"Dream": "Вещий сон",
"Druid": "друид",
"Druidcraft": "Искусство друидов",
"Druidic": "Друидический",
"Dual Wielder": "Двойное оружие",
"Dungeon Delver": "Исследователь подземелий",
"Durable": "Стойкий",
"Dwarf": "дварф",
"Earthquake": "Землетрясение",
"Eldritch Blast": "Потусторонний разряд",
"Eldritch Hex": "Потусторонний сглаз",
"Eldritch Hexed: Charisma": "Потусторонний сглаз: Харизма",
"Eldritch Hexed: Constitution": "Потусторонний сглаз: Телосложение",
"Eldritch Hexed: Dexterity": "Потусторонний сглаз: Ловкость",
"Eldritch Hexed: Intelligence": "Потусторонний сглаз: Интеллект",
"Eldritch Hexed: Strength": "Потусторонний сглаз: Сила",
"Eldritch Hexed: Wisdom": "Потусторонний сглаз: Мудрость",
"Eldritch Strike": "Мистический удар",
"Eldritch blast": "Мистический заряд",
"Elemental Adept": "Стихийный адепт",
"Elemental Fury": "Стихийная ярость",
"Elemental weapon": "Стихийное оружие",
"Elf": "эльф",
"Empowered Strikes": "Усиленные удары",
"Enemy": "Враг",
"Enhance Ability": "Усиление характеристики",
"Enhance ability": "Улучшение характеристики",
"Enlarge/reduce": "Увеличение/уменьшение",
"Ensnaring strike": "Опутывающий удар",
"Entangle": "Опутывание",
"Entertainer": "Артист",
"Enthrall": "Речь златоуста",
"Etherealness": "Эфирность",
"Evard's black tentacles": "Эвардовы чёрные щупальца",
"Evasion": "Ускользание",
"Exhaustion": "истощение",
"Expeditious retreat": "Поспешное отступление",
"Expertise": "Мастерство",
"Extra Attack": "Дополнительная атака",
"Eyebite": "Разящее око",
"Fabricate": "Изготовление",
"Faerie Fire": "Фейское сияние",
"Faerie fire": "Огонь фей",
"Faithful Steed": "Верный скакун",
"False Life": "Ложная жизнь",
"False life": "Ложная жизнь",
"Fear": "Ужас",
"Feat": "черта",
"Feat: Fade Away": "Черта: Исчезновение",
"Feat: Fey Touched": "Черта: Затронутый феями",
"Feather Fall": "Плавное падение",
"Feather fall": "Падение пёрышком",
"Feats": "черты",
"Feature": "особенность",
"Features": "особенности",
"Feeblemind": "Слабоумие",
"Feign death": "Притворная смерть",
"Fighter": "воин",
"Find Familiar": "Призыв фамильяра",
"Find Steed": "Обретение скакуна",
"Find familiar": "Поиск фамильяра",
"Find steed": "Поиск скакуна",
"Find the path": "Поиск пути",
"Find traps": "Поиск ловушек",
"Finesse": "фехтовальное",
"Finger of death": "Перст смерти",
"Fire Bolt": "Огненный снаряд",
"Fire bolt": "Огненный снаряд",
"Fire shield": "Огненный щит",
"Fire storm": "Огненная буря",
"Fireball": "Огненный шар",
"Flail": "Цеп",
"Flame Blade": "Горящий клинок",
"Flame blade": "Горящий клинок",
"Flame strike": "Небесный огонь",
"Flaming Sphere": "Пылающая сфера",
"Flaming sphere": "Пылающий шар",
"Flesh to stone": "Окаменение",
"Fly": "Полёт",
"Fog Cloud": "Облако тумана",
"Fog cloud": "Туманное облако",
"Folk Hero": "Народный герой",
"Font of Inspiration": "Источник вдохновения",
"Forbiddance": "Запрет",
"Forcecage": "Узилище",
"Forceful Blow": "Мощный удар",
"Foresight": "Предвидение",
"Fount of Moonlight": "Источник лунного света",
"Freedom of movement": "Свобода перемещения",
"Frenzy": "Неистовство",
"Friends": "Дружба",
"Frightened": "Испуганный",
"Gaseous form": "Газообразная форма",
"Gate": "Врата",
"Geas": "Обет",
"Gentle repose": "Нетленные останки",
"Giant insect": "Гигантское насекомое",
"Glaive": "Глефа",
"Glibness": "Находчивость",
"Globe of invulnerability": "Сфера неуязвимости",
"Glyph of warding": "Охранные руны",
"Gnome": "гном",
"Goodberry": "Вкусные ягоды",
"Grapple": "захват",
"Grappled": "Схваченный",
"Grappler": "Борец",
"Grasping vine": "Цепкая лоза",
"Graze": "Задевание",
"Grease": "Скольжение",
"Great Weapon Master": "Мастер большого оружия",
"Greataxe": "Секира",
"Greatclub": "Палица",
"Greater invisibility": "Высшая невидимость",
"Greater restoration": "Высшее восстановление",
"Greatsword": "Двуручный меч",
"Green-Flame Blade": "Клинок зелёного пламени",
"Guardian of faith": "Страж веры",
"Guards and wards": "Стражи",
"Guidance": "Наставление",
"Guiding Bolt": "Направляющий луч",
"Guiding bolt": "Направленный снаряд",
"Guild Artisan": "Гильдейский ремесленник",
"Gust of Wind": "Порыв ветра",
"Gust of wind": "Порыв ветра",
"HP": "ОЗ",
"Hail of Thorns": "Град шипов",
"Hail of thorns": "Град шипов",
"Halberd": "Алебарда",
"Half-Elf": "полуэльф",
"Half-Orc": "полуорк",
"Halfling": "полурослик",
"Hallow": "Святилище",
"Hallucinatory terrain": "Мираж",
"Hamstring Blow": "Удар по сухожилиям",
"Handaxe": "Ручной топор",
"Harm": "Поражение",
"Haste": "Ускорение",
"Heal": "Полное исцеление",
"Healer": "Лекарь",
"Healing": "лечение",
"Healing Word": "Исцеляющее слово",
"Healing word": "Лечащее слово",
"Heat metal": "Раскалённый металл",
"Heavily Armored": "Знаток тяжёлых доспехов",
"Heavy": "тяжёлое",
"Heavy Armor": "тяжёлые доспехи",
"Heavy Armor Master": "Мастер тяжёлых доспехов",
"Heightened Focus": "Обострённый фокус",
"Hellish rebuke": "Адское возмездие",
"Help": "Помощь",
"Heroes feast": "Пир героев",
"Heroic Inspiration": "Героическое вдохновение",
"Heroic Warrior": "Героический воин",
"Heroism": "Героизм",
"Hex": "Сглаз",
"Hex (Charisma)": "Сглаз (Харизма)",
"Hex (Constitution)": "Сглаз (Телосложение)",
"Hex (Dexterity)": "Сглаз (Ловкость)",
"Hex (Intelligence)": "Сглаз (Интеллект)",
"Hex (Strength)": "Сглаз (Сила)",
"Hex (Wisdom)": "Сглаз (Мудрость)",
"Hide": "Спрятаться",
"History": "История",
"Hit Dice": "кости хитов",
"Hit Die": "кость хитов",
"Hit Point": "ОЗ",
"Hit Points": "ОЗ",
"Hold Person": "Паралич гуманоида",
"Hold monster": "Удержание чудовища",
"Hold person": "Удержание личности",
"Holy aura": "Аура святости",
"Human": "человек",
"Hunger of Hadar": "Голод Хадара",
"Hunter's Mark": "Метка охотника",
"Hunter's mark": "Метка охотника",
"Hypnotic pattern": "Гипнотический узор",
"Ice Knife": "Ледяной нож",
"Ice storm": "Град",
"Identify": "Опознание",
"Illusory script": "Невидимое письмо",
"Imprisonment": "Заточение",
"Improved Combat Superiority": "Усовершенствованное превосходство в бою",
"Improved Warding Flare": "Улучшенная защитная вспышка",
"Incapacitated": "Недееспособный",
"Incendiary cloud": "Воспламеняющаяся туча",
"Indomitable": "Несгибаемая воля",
"Inflict Wounds": "Нанесение ран",
"Inflict wounds": "Нанесение ран",
"Initiative": "инициатива",
"Insect plague": "Нашествие насекомых",
"Insight": "Проницательность",
"Inspiring Leader": "Воодушевляющий лидер",
"Instinctive Pounce": "Интуитивный рывок",
"Intelligence": "Интеллект",
"Intimidation": "Запугивание",
"Investigation": "Расследование",
"Invisibility": "Невидимость",
"Invisible": "Невидимый",
"Invoke Duplicity": "Призыв двойника",
"Jack of All Trades": "Мастер на все руки",
"Jack-of-all-Trades": "Мастер на все руки",
"Javelin": "Метательное копьё",
"Jump": "Прыжок",
"Keen Mind": "Отличная память",
"Knock": "Стук",
"Lance": "Длинное копьё",
"Legend lore": "Знание легенд",
"Leomunds secret chest": "Леомундов потайной сундук",
"Leomunds tiny hut": "Леомундова хижина",
"Lesser Restoration": "Низшее восстановление",
"Lesser restoration": "Малое восстановление",
"Level": "уровень",
"Levitate": "Левитация",
"Light": "Свет",
"Light hammer": "Лёгкий молот",
"Lightly Armored": "Знаток лёгких доспехов",
"Lightning arrow": "Молниевая стрела",
"Lightning bolt": "Молния",
"Linguist": "Языковед",
"Locate animals or plants": "Поиск животных или растений",
"Locate creature": "Поиск существа",
"Locate object": "Поиск предмета",
"Long Rest": "долгий отдых",
"Longbow": "Длинный лук",
"Longstrider": "Скороход",
"Longsword": "Длинный меч",
"Lucky": "Везунчик",
"Mace": "Булава",
"Mage Armor": "Магический доспех",
"Mage Armour": "Магический доспех",
"Mage Hand": "Магическая рука",
"Mage Slayer": "Убийца магов",
"Mage armor": "Доспехи мага",
"Mage hand": "Магическая рука",
"Magic Action": "действие Магия",
"Magic Initiate": "Посвящённый в магию",
"Magic Initiate (Cleric)": "Посвященный в магию: жрец",
"Magic Initiate (Sorcerer)": "Посвященный в магию: чародей",
"Magic Initiate (Warlock)": "Посвященный в магию: колдун",
"Magic Initiate (Wizard)": "Посвященный в магию: волшебник",
"Magic Missile": "Волшебная стрела",
"Magic Weapon": "Волшебное оружие",
"Magic action": "действие Магия",
"Magic circle": "Магический круг",
"Magic jar": "Волшебный сосуд",
"Magic missile": "Волшебная стрела",
"Magic mouth": "Волшебные уста",
"Magic weapon": "Магическое оружие",
"Magician": "Маг",
"Major image": "Образ",
"Mantle of Inspiration": "Мантия вдохновения",
"Martial Adept": "Воинский адепт",
"Martial Arts": "Боевые искусства",
"Martial weapons": "воинское оружие",
"Mass Healing Word": "Массовое исцеляющее слово",
"Mass cure wounds": "Множественное лечение ран",
"Mass heal": "Множественное полное исцеление",
"Mass healing word": "Множественное лечащее слово",
"Mass suggestion": "Множественное внушение",
"Mastery Properties": "свойства мастерства",
"Mastery Properties: Cleave": "Свойства мастерства: Рассечение",
"Mastery Properties: Graze": "Свойства мастерства: Скользящий удар",
"Mastery Properties: Nick": "Свойства мастерства: Надрез",
"Mastery Properties: Push": "Свойства мастерства: Толчок",
"Mastery Properties: Sap": "Свойства мастерства: Истощение",
"Mastery Properties: Slow": "Свойства мастерства: Замедление",
"Mastery Properties: Topple": "Свойства мастерства: Опрокидывание",
"Mastery Properties: Vex": "Свойства мастерства: Отвлечение",
"Maul": "Молот",
"Maze": "Лабиринт",
"Medicine": "Медицина",
"Medium Armor": "средние доспехи",
"Medium Armor Master": "Мастер средних доспехов",
"Meld into stone": "Слияние с камнем",
"Melee Attack": "рукопашная атака",
"Melf's Acid Arrow": "Кислотная стрела Мелфа",
"Melf's acid arrow": "Кислотная стрела Мелфа",
"Mending": "Починка",
"Message": "Сообщение",
"Meteor swarm": "Метеоритный дождь",
"Mind Magic": "Магия разума",
"Mind Sliver": "Расщепление разума",
"Mind Spike": "Пронзание разума",
"Mind blank": "Сокрытие разума",
"Mindless Rage": "Безрассудная ярость",
"Minor Illusion": "Малая иллюзия",
"Minor illusion": "Малая иллюзия",
"Mirage arcane": "Таинственный мираж",
"Mirror Image": "Зеркальное отражение",
"Mirror image": "Отражения",
"Mislead": "Фальшивый двойник",
"Misty step": "Туманный шаг",
"Mobile": "Подвижный",
"Moderately Armored": "Знаток средних доспехов",
"Modify memory": "Изменение памяти",
"Monk": "монах",
"Moonbeam": "Лунный свет",
"Moonlight Step": "Лунный шаг",
"Moonlight Step Charge": "заряд «Лунного шага»",
"Mordenkainens faithful hound": "Верный пёс Морденкайнена",
"Mordenkainens magnificent mansion": "Великолепный особняк Морденкайнена",
"Mordenkainens private sanctum": "Кабинет Морденкайнена",
"Mordenkainens sword": "Меч Морденкайнена",
"Morningstar": "Моргенштерн",
"Mounted Combatant": "Верховой боец",
"Move earth": "Движение почвы",
"Nature": "Природа",
"Necrotic Damage": "урон некротической энергией",
"Net": "Сеть",
"Nick": "Надрез",
"Noble": "Дворянин",
"Nondetection": "Необнаружимость",
"Nystuls magic aura": "Нистулова ложная аура",
"Observant": "Внимательный",
"Opportunity Attack": "внеочередная атака",
"Opportunity Attacks": "внеочередные атаки",
"Origin Feat: Alert": "Черта происхождения: Бдительный",
"Origin Feat: Magic Initiate (Cleric)": "Черта происхождения: Посвященный в магию (Жрец)",
"Origin Feat: Magic Initiate (Wizard)": "Черта происхождения: Посвященный в магию (Волшебник)",
"Origin Feat: Magic Initiate (Druid)": "Черта происхождения: Посвященный в магию (Друид)",
"Origin Feat: Healer": "Черта происхождения: Лекарь",
"Origin Feat: Lucky": "Черта происхождения: Везунчик",
"Origin Feat: Tavern Brawler": "Черта происхождения: Драчун",
"Origin Feat: Musician": "Черта происхождения: Музыкант",
"Origin Feat: Savage Attacker": "Черта происхождения: Дикий атакующий",
"Origin Feat: Skilled": "Черта происхождения: Одаренный",
"Origin Feat: Tough": "Черта происхождения: Крепкий",
"Otilukes freezing sphere": "Отилюков ледяной шар",
"Otilukes resilient sphere": "Отилюков упругий шар",
"Ottos irresistible dance": "Неудержимая пляска Отто",
"Outlander": "Чужеземец",
"Paladin": "паладин",
"Paralyzed": "Парализованный",
"Pass without Trace": "Бесследный шаг",
"Pass without trace": "Бесследное передвижение",
"Passwall": "Создание прохода",
"Patient Defense": "Терпеливая оборона",
"Perception": "Внимание",
"Performance": "Исполнение",
"Persuasion": "Убеждение",
"Petrified": "Окаменевший",
"Phantasmal Force": "Сила фантазма",
"Phantasmal force": "Воображаемая сила",
"Phantasmal killer": "Воображаемый убийца",
"Phantom Steed": "Призрачный скакун",
"Phantom steed": "Призрачный скакун",
"Pike": "Пика",
"Planar ally": "Планарный союзник",
"Planar binding": "Планарные узы",
"Plane shift": "Уход в иной мир",
"Plant growth": "Рост растений",
"Poison Spray": "Брызги яда",
"Poison spray": "Ядовитые брызги",
"Poisoned": "Отравленный",
"Polearm Master": "Мастер древкового оружия",
"Polymorph": "Превращение",
"Potent Spellcasting": "Мощное заклинание",
"Power word heal": "Слово Силы: исцеление",
"Power word kill": "Слово Силы: смерть",
"Power word stun": "Слово Силы: оглушение",
"Prayer of Healing": "Исцеляющий молебен",
"Prayer of healing": "Молебен лечения",
"Preserve Life": "Сохранение жизни",
"Prestidigitation": "Фокусы",
"Primal Knowledge": "Первозданное знание",
"Primal Order": "Изначальный приказ",
"Primal Strike": "Первобытный удар",
"Prismatic spray": "Радужные брызги",
"Prismatic wall": "Радужная стена",
"Produce Flame": "Создание пламени",
"Produce flame": "Сотворение пламени",
"Proficiency": "умение",
"Proficiency Bonus": "бонус умения",
"Proficient": "владение",
"Programmed illusion": "Заданная иллюзия",
"Project image": "Проекция",
"Prone": "Сбитый с ног",
"Protection from Evil and Good": "Защита от зла и добра",
"Protection from energy": "Защита от энергии",
"Protection from evil and good": "Защита от добра и зла",
"Protection from poison": "Защита от яда",
"Protector": "Защитник",
"Purify food and drink": "Очищение пищи и питья",
"Purity of Body": "Чистота тела",
"Push": "Отталкивание",
"Quarterstaff": "Боевой посох",
"Radiant Damage": "урон излучением",
"Rage": "Ярость",
"Raise dead": "Оживление",
"Ranged Attack": "дальнобойная атака",
"Ranger": "следопыт",
"Rapier": "Рапира",
"Rarys telepathic bond": "Ментальная связь Рэри",
"Ray of Sickness": "Луч болезни",
"Ray of enfeeblement": "Луч слабости",
"Ray of frost": "Луч холода",
"Ray of sickness": "Луч болезни",
"Reaction": "реакция",
"Reapply Hex": "Повторно наложить Сглаз",
"Reapply Hex (Charisma)": "Повторно наложить Сглаз (Харизма)",
"Reapply Hex (Constitution)": "Повторно наложить Сглаз (Телосложение)",
"Reapply Hex (Dexterity)": "Повторно наложить Сглаз (Ловкость)",
"Reapply Hex (Intelligence)": "Повторно наложить Сглаз (Интеллект)",
"Reapply Hex (Strength)": "Повторно наложить Сглаз (Сила)",
"Reapply Hex (Wisdom)": "Повторно наложить Сглаз (Мудрость)",
"Reckless Attack": "Безрассудная атака",
"Redirect Attacks": "Перенаправление атак",
"Regenerate": "Регенерация",
"Reincarnate": "Реинкарнация",
"Relentless Rage": "Неудержимая ярость",
"Religion": "Религия",
"Remarkable Athlete": "Выдающийся атлет",
"Remove Curse": "Снятие проклятия",
"Remove curse": "Снятие проклятья",
"Resilient": "Устойчивый",
"Resistance": "Сопротивление",
"Restrained": "Опутанный",
"Resurrection": "Воскрешение",
"Retaliation": "Возмездие",
"Reverse gravity": "Изменение тяготения",
"Revivify": "Возрождение",
"Ritual Caster": "Ритуальный заклинатель",
"Rogue": "плут",
"Rope trick": "Трюк с верёвкой",
"Rule: One Spell with a Spell Slot per Turn": "Правило: одно заклинание с ячейкой за ход",
"Sacred Flame": "Священное пламя",
"Sacred flame": "Священное пламя",
"Sage": "Мудрец",
"Sanctuary": "Убежище",
"Sap": "Утомление",
"Savage Attacker": "Дикий атакующий",
"Saving Throw": "испытание",
"Saving Throw DC": "КС испытания",
"Saving Throws": "испытания",
"Scimitar": "Скимитар",
"Scorching Ray": "Опаляющий луч",
"Scorching ray": "Палящий луч",
"Scrying": "Наблюдение",
"Sear Undead": "Выжигание нежити",
"Searing smite": "Палящая кара",
"Second Wind": "Второе дыхание",
"See Invisibility": "Видение невидимого",
"See invisibility": "Видение невидимого",
"Seeming": "Притворство",
"Self-Restoration": "Самоисцеление",
"Sending": "Послание",
"Sentinel": "Страж",
"Sequester": "Изоляция",
"Shapechange": "Полное превращение",
"Sharpshooter": "Меткий стрелок",
"Shatter": "Разбивающий звук",
"Shield": "Щит",
"Shield Master": "Мастер щитов",
"Shield of Faith": "Щит веры",
"Shield of faith": "Щит веры",
"Shillelagh": "Шиллейла",
"Shocking Grasp": "Шоковое прикосновение",
"Shocking grasp": "Электрошок",
"Short Rest": "короткий отдых",
"Shortbow": "Короткий лук",
"Shortsword": "Короткий меч",
"Sickle": "Серп",
"Silence": "Тишина",
"Silent image": "Безмолвный образ",
"Simulacrum": "Подобие",
"Skilled": "Одаренный",
"Skilled: Acrobatics": "Одаренный: Акробатика",
"Skilled: Animal Handling": "Одаренный: Уход за животными",
"Skilled: Arcana": "Одаренный: Магия",
"Skilled: Athletics": "Одаренный: Атлетика",
"Skilled: Deception": "Одаренный: Обман",
"Skilled: History": "Одаренный: История",
"Skilled: Insight": "Одаренный: Проницательность",
"Skilled: Intimidation": "Одаренный: Запугивание",
"Skilled: Investigation": "Одаренный: Расследование",
"Skilled: Medicine": "Одаренный: Медицина",
"Skilled: Nature": "Одаренный: Природа",
"Skilled: Perception": "Одаренный: Восприятие",
"Skilled: Performance": "Одаренный: Выступление",
"Skilled: Persuasion": "Одаренный: Убеждение",
"Skilled: Religion": "Одаренный: Религия",
"Skilled: Sleight of Hand": "Одаренный: Ловкость рук",
"Skilled: Stealth": "Одаренный: Скрытность",
"Skilled: Survival": "Одаренный: Выживание",
"Skulker": "Проныра",
"Sleep": "Сон",
"Sleet storm": "Метель",
"Sleight of Hand": "Ловкость рук",
"Sling": "Праща",
"Slow": "Замедление",
"Slow Fall": "Замедление падения",
"Snilloc's Snowball Swarm": "Снежный шквал Сниллока",
"Soldier": "Солдат",
"Sorcerer": "чародей",
"Sorcerous Burst": "Чародейский выброс",
"Spare the Dying": "Уход за умирающим",
"Spare the dying": "Уход за умирающим",
"Speak with Animals": "Разговор с животными",
"Speak with Dead": "Разговор с мертвым",
"Speak with animals": "Разговор с животными",
"Speak with dead": "Разговор с мёртвыми",
"Speak with plants": "Разговор с растениями",
"Spear": "Копьё",
"Spell Save DC": "КС испытаний против заклинаний",
"Spell Slot": "ячейка заклинания",
"Spell Sniper": "Меткие заклинания",
"Spellcasting": "накладывание заклинаний",
"Spider climb": "Паук",
"Spike growth": "Шипы",
"Spirit Guardians": "Призрачные стражи",
"Spirit guardians": "Духовные стражи",
"Spiritual Weapon": "Призрачное оружие",
"Spiritual weapon": "Божественное оружие",
"Stable": "Стабилизированный",
"Staggering smite": "Оглушающая кара",
"Starry Wisp": "Звёздная искра",
"Stealth": "Скрытность",
"Steed Action Point": "Очко действия скакуна",
"Steed Attack": "Атака скакуна",
"Steel Wind Strike": "Удар стального ветра",
"Step of the Wind": "Поступь ветра",
"Stinking Cloud": "Смрадное облако",
"Stinking cloud": "Зловонное облако",
"Stone shape": "Изменение формы камня",
"Stoneskin": "Каменная кожа",
"Storm of vengeance": "Гроза гнева",
"Strength": "Сила",
"Stunned": "Ошеломлённый",
"Suggestion": "Внушение",
"Sunbeam": "Солнечный луч",
"Sunburst": "Солнечный ожог",
"Survival": "Выживание",
"Swift quiver": "Быстрый колчан",
"Sword Burst": "Вспышка мечей",
"Symbol": "Знак",
"Synaptic Static": "Синаптический разряд",
"Tactical Master": "Мастер тактики",
"Tactical Mind": "Тактический ум",
"Tactical Shift": "Тактический манёвр",
"Tasha's Hideous Laughter": "Отвратительный смех Таши",
"Tasha's Mind Whip": "Психическая плеть Таши",
"Tasha's hideous laughter": "Отвратительный смех Таши",
"Tavern Brawler": "Драчун",
"Telekinesis": "Телекинез",
"Telepathy": "Телепатия",
"Teleport": "Телепортация",
"Teleportation circle": "Круг телепортации",
"Temporary Hit Point": "временный ОЗ",
"Temporary Hit Points": "временные ОЗ",
"Tensers floating disk": "Тензеров парящий диск",
"Thaumaturge": "Чудотворец",
"Thaumaturgy": "Тавматургия",
"Thorn Whip": "Терновый хлыст",
"Thorn whip": "Терновый кнут",
"Throw": "Метнуть",
"Thunderclap": "Раскат грома",
"Thunderous smite": "Громовая кара",
"Thunderwave": "Громовая волна",
"Tiefling": "тифлинг",
"Time stop": "Остановка времени",
"Toll the Dead": "Погребальный звон",
"Tongues": "Языки",
"Topple": "Опрокидывание",
"Tough": "Крепкий",
"Transport via plants": "Путешествие через растения",
"Tree stride": "Древесный путь",
"Tricksters Transposition": "Перемещение обманщика",
"Trident": "Трезубец",
"True Strike": "Верный удар",
"True polymorph": "Истинное превращение",
"True resurrection": "Истинное воскрешение",
"True seeing": "Истинное зрение",
"True strike": "Верный удар",
"Tsunami": "Цунами",
"Unarmored Defense": "Защита без доспехов",
"Unarmored Movement": "Движение без доспехов",
"Unarmoured Defence": "Защита без доспехов",
"Unarmoured Movement": "Движение без доспехов",
"Uncanny Metabolism": "Необычный метаболизм",
"Unconscious": "Бессознательный",
"Unfettered Mind": "Свободный разум",
"Unseen servant": "Невидимый слуга",
"Urchin": "Беспризорник",
"Vampiric Touch": "Касание вампира",
"Vampiric touch": "Прикосновение вампира",
"Vex": "Досада",
"Vicious Mockery": "Язвительная насмешка",
"Vicious mockery": "Злая насмешка",
"Vitriolic Sphere": "Едкий шар",
"Wall of fire": "Огненная стена",
"Wall of force": "Силовая стена",
"Wall of ice": "Ледяная стена",
"Wall of stone": "Каменная стена",
"Wall of thorns": "Терновая стена",
"War Caster": "Боевой заклинатель",
"War pick": "Боевая кирка",
"Warden": "Страж",
"Warding Flare": "Защитная вспышка",
"Warding bond": "Охраняющая связь",
"Warhammer": "Боевой молот",
"Warlock": "колдун",
"Water breathing": "Подводное дыхание",
"Water walk": "Хождение по воде",
"Weapon Master": "Мастер оружия",
"Weapon Mastery": "Мастерство владения оружием",
"Web": "Паутина",
"Weird": "Смертный ужас",
"Whip": "Кнут",
"Wild Resurgence": "Возрождение дикого облика",
"Wild Shape": "Дикий облик",
"Wild Shape Charge": "заряд «Дикого облика»",
"Wind walk": "Хождение по ветру",
"Wind wall": "Стена ветров",
"Wisdom": "Мудрость",
"Wish": "Исполнение желаний",
"Witch Bolt": "Ведьмовской разряд",
"Witch bolt": "Ведьмин снаряд",
"Wizard": "волшебник",
"Word of Radiance": "Слово сияния",
"Word of recall": "Слово возврата",
"Wrathful smite": "Гневная кара",
"Zone of truth": "Область истины"
}

View File

@@ -8,7 +8,7 @@ param(
[string]$ModName = "DnD 5.5e All-in-One BEYOND Russian Localization", [string]$ModName = "DnD 5.5e All-in-One BEYOND Russian Localization",
[string]$ModUuid = "6401e84d-daf2-416d-adeb-99c03a2487a6", [string]$ModUuid = "6401e84d-daf2-416d-adeb-99c03a2487a6",
[string]$ModAuthor = "MikhailRaw", [string]$ModAuthor = "MikhailRaw",
[string]$ModDescription = "Russian Localization", [string]$ModDescription = "Русская локализация мода, который добавляет и обновляет контент в соответствии с правилами DnD 5.5e и другими источниками, включая предыстории, классы, таланты, расы, заклинания и многое другое. Это отдельный мод локализации и он требует установленный оригинальный мод.",
[string]$ModVersion64 = "36028797018963968", [string]$ModVersion64 = "36028797018963968",
[string]$ModGroup = "6401e84d-daf2-416d-adeb-99c03a2487a6", [string]$ModGroup = "6401e84d-daf2-416d-adeb-99c03a2487a6",
[string]$DependencyUuid = "897914ef-5c96-053c-44af-0be823f895fe", [string]$DependencyUuid = "897914ef-5c96-053c-44af-0be823f895fe",
@@ -17,11 +17,40 @@ param(
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
function Convert-VersionTagToVersion64 {
param(
[string]$Tag,
[string]$FallbackVersion64
)
if (-not $Tag) {
return [int64]$FallbackVersion64
}
$normalized = $Tag
if ($normalized.StartsWith("v")) {
$normalized = $normalized.Substring(1)
}
if ($normalized -notmatch '^\d+(\.\d+){0,3}$') {
return [int64]$FallbackVersion64
}
$parts = $normalized.Split(".")
$numbers = @(0, 0, 0, 0)
for ($i = 0; $i -lt $parts.Length; $i++) {
$numbers[$i] = [int]$parts[$i]
}
return ([int64]$numbers[0] -shl 55) -bor ([int64]$numbers[1] -shl 47) -bor ([int64]$numbers[2] -shl 31) -bor [int64]$numbers[3]
}
$workspacePath = [System.IO.Path]::GetFullPath($Workspace) $workspacePath = [System.IO.Path]::GetFullPath($Workspace)
$modsPath = Join-Path $workspacePath "Mods" $modsPath = Join-Path $workspacePath "Mods"
$modPath = Join-Path $modsPath $ModFolder $modPath = Join-Path $modsPath $ModFolder
$buildPath = Join-Path $workspacePath "build" $buildPath = Join-Path $workspacePath "build"
$stagingPath = Join-Path $workspacePath "build-stage" $stagingRoot = Join-Path $env:TEMP "bg3-dnd55e-russian-localization-stage"
$stagingPath = Join-Path $stagingRoot "build-stage"
$packagePath = Join-Path $buildPath $PackageName $packagePath = Join-Path $buildPath $PackageName
$tempPackagePath = Join-Path $env:TEMP $PackageName $tempPackagePath = Join-Path $env:TEMP $PackageName
$archiveName = $ArchiveBaseName $archiveName = $ArchiveBaseName
@@ -30,6 +59,7 @@ if ($VersionTag) {
} }
$zipPath = Join-Path $buildPath "$archiveName.zip" $zipPath = Join-Path $buildPath "$archiveName.zip"
$infoJsonPath = Join-Path $buildPath "info.json" $infoJsonPath = Join-Path $buildPath "info.json"
$resolvedVersion64 = Convert-VersionTagToVersion64 -Tag $VersionTag -FallbackVersion64 $ModVersion64
if (-not (Test-Path -LiteralPath $DivinePath)) { if (-not (Test-Path -LiteralPath $DivinePath)) {
$resolvedCommand = Get-Command $DivinePath -ErrorAction SilentlyContinue $resolvedCommand = Get-Command $DivinePath -ErrorAction SilentlyContinue
@@ -59,13 +89,67 @@ foreach ($path in @($stagingPath, $tempPackagePath, $packagePath, $zipPath, $inf
} }
} }
New-Item -ItemType Directory -Path $stagingPath | Out-Null if (Test-Path -LiteralPath $stagingRoot) {
Remove-Item -LiteralPath $stagingRoot -Recurse -Force
}
New-Item -ItemType Directory -Path $stagingPath -Force | Out-Null
Copy-Item -LiteralPath $modsPath -Destination $stagingPath -Recurse Copy-Item -LiteralPath $modsPath -Destination $stagingPath -Recurse
& $DivinePath -a create-package -g bg3 -s $stagingPath -d $tempPackagePath $stagedMetaPath = Join-Path $stagingPath "Mods\\$ModFolder\\meta.lsx"
if (-not (Test-Path -LiteralPath $stagedMetaPath)) {
throw "Staged meta.lsx was not found: '$stagedMetaPath'."
}
if (-not (Test-Path -LiteralPath $tempPackagePath)) { $stagedMetaContent = Get-Content -LiteralPath $stagedMetaPath -Raw
throw "Temporary package was not created." $stagedMetaContent = $stagedMetaContent -replace '(<attribute id="Version64" type="int64" value=")\d+("/>)', "`${1}$resolvedVersion64`${2}"
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($stagedMetaPath, $stagedMetaContent, $utf8Bom)
Write-Host "[build.ps1] Staged source tree:"
Get-ChildItem -Recurse $stagingPath | Select-Object FullName, Length | Format-Table -AutoSize
if (Test-Path -LiteralPath $tempPackagePath) {
Remove-Item -LiteralPath $tempPackagePath -Force
}
# CI quirk: Divine can occasionally emit a broken ~48-byte package for some source roots.
# Mitigation: try staged/mods/workspace sources and accept only outputs that look valid by size.
$packageAttempts = @(
[ordered]@{ Name = "staging-root"; Source = $stagingPath },
[ordered]@{ Name = "mods-root"; Source = $modsPath },
[ordered]@{ Name = "workspace-root"; Source = $workspacePath }
)
$successfulAttempt = $null
foreach ($attempt in $packageAttempts) {
if (Test-Path -LiteralPath $tempPackagePath) {
Remove-Item -LiteralPath $tempPackagePath -Force
}
Write-Host "[build.ps1] Trying Divine source '$($attempt.Name)': $($attempt.Source)"
& $DivinePath -a create-package -g bg3 -s $attempt.Source -d $tempPackagePath
if (-not (Test-Path -LiteralPath $tempPackagePath)) {
Write-Host "[build.ps1] No package created for attempt '$($attempt.Name)'."
continue
}
$attemptPackage = Get-Item -LiteralPath $tempPackagePath
Write-Host "[build.ps1] Attempt '$($attempt.Name)' produced $($attemptPackage.Length) bytes."
if ($attemptPackage.Length -ge 1024) {
$successfulAttempt = $attempt
break
}
}
if (-not $successfulAttempt) {
$lastSize = "missing"
if (Test-Path -LiteralPath $tempPackagePath) {
$lastSize = (Get-Item -LiteralPath $tempPackagePath).Length
}
throw "Package looks invalid after all attempts. Last output '$tempPackagePath' size: $lastSize bytes."
} }
Move-Item -LiteralPath $tempPackagePath -Destination $packagePath Move-Item -LiteralPath $tempPackagePath -Destination $packagePath
@@ -75,9 +159,7 @@ if (-not (Test-Path -LiteralPath $packagePath)) {
} }
$packageFile = Get-Item -LiteralPath $packagePath $packageFile = Get-Item -LiteralPath $packagePath
if ($packageFile.Length -lt 1024) { Write-Host "[build.ps1] Using package from attempt '$($successfulAttempt.Name)'."
throw "Package looks invalid: '$packagePath' is only $($packageFile.Length) bytes."
}
$packageMd5 = (Get-FileHash -LiteralPath $packagePath -Algorithm MD5).Hash.ToLowerInvariant() $packageMd5 = (Get-FileHash -LiteralPath $packagePath -Algorithm MD5).Hash.ToLowerInvariant()
$createdAt = (Get-Date).ToString("o") $createdAt = (Get-Date).ToString("o")
@@ -88,7 +170,7 @@ $infoJson = [ordered]@{
Author = $ModAuthor Author = $ModAuthor
Name = $ModName Name = $ModName
Folder = $ModFolder Folder = $ModFolder
Version = $ModVersion64 Version = [string]$resolvedVersion64
Description = $ModDescription Description = $ModDescription
UUID = $ModUuid UUID = $ModUuid
Created = $createdAt Created = $createdAt

View File

@@ -1,5 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
mkdir -p build
Divine -a create-package -g bg3 -s Mods -d "build/DnD 5.5e AIO Russian.pak"

63
scripts/set-version.ps1 Normal file
View File

@@ -0,0 +1,63 @@
param(
[Parameter(Mandatory = $true)]
[string]$VersionTag,
[string]$MetaPath = "Mods/DnD 5.5e AIO Russian/meta.lsx"
)
$ErrorActionPreference = "Stop"
function Convert-VersionTagToVersion64 {
param(
[string]$Tag
)
$normalized = $Tag
if ($normalized.StartsWith("v")) {
$normalized = $normalized.Substring(1)
}
if ($normalized -notmatch '^\d+(\.\d+){0,3}$') {
throw "Version tag '$Tag' is invalid. Expected format: vX.Y.Z or X.Y.Z"
}
$parts = $normalized.Split(".")
$numbers = @(0, 0, 0, 0)
for ($i = 0; $i -lt $parts.Length; $i++) {
$numbers[$i] = [int]$parts[$i]
}
return ([int64]$numbers[0] -shl 55) -bor ([int64]$numbers[1] -shl 47) -bor ([int64]$numbers[2] -shl 31) -bor [int64]$numbers[3]
}
$resolvedMetaPath = [System.IO.Path]::GetFullPath($MetaPath)
if (-not (Test-Path -LiteralPath $resolvedMetaPath)) {
throw "meta.lsx was not found: '$resolvedMetaPath'."
}
$resolvedVersion64 = Convert-VersionTagToVersion64 -Tag $VersionTag
$metaContent = Get-Content -LiteralPath $resolvedMetaPath -Raw
[xml]$metaXml = $metaContent
# Explicitly target ModuleInfo/Version64 via XML path to avoid touching Dependencies/PublishVersion.
$moduleInfoVersionNode = $metaXml.SelectSingleNode('/save/region/node/children/node[@id="ModuleInfo"]/attribute[@id="Version64" and @type="int64"]')
if ($null -eq $moduleInfoVersionNode) {
throw "ModuleInfo/Version64 attribute was not found in '$resolvedMetaPath'."
}
# Replace only the Version64 attribute that appears inside ModuleInfo before its <children> block.
$moduleInfoVersionPattern = '(?s)(<node id="ModuleInfo">\s*(?:(?!<children>).)*?<attribute id="Version64" type="int64" value=")\d+("/>)'
if ($metaContent -notmatch $moduleInfoVersionPattern) {
throw "ModuleInfo/Version64 attribute was not found in '$resolvedMetaPath'."
}
$updatedMeta = [regex]::Replace(
$metaContent,
$moduleInfoVersionPattern,
"`${1}$resolvedVersion64`${2}",
1
)
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($resolvedMetaPath, $updatedMeta, $utf8Bom)
Write-Host "[set-version.ps1] Updated '$resolvedMetaPath' to Version64=$resolvedVersion64 (from tag '$VersionTag')."

View File

@@ -0,0 +1,91 @@
param(
[string]$ParentMetaUrl = "https://raw.githubusercontent.com/Yoonmoonsik/dnd55e/main/Mods/DnD2024_897914ef-5c96-053c-44af-0be823f895fe/meta.lsx",
[string]$TargetMetaPath = "Mods/DnD 5.5e AIO Russian/meta.lsx"
)
$ErrorActionPreference = "Stop"
$resolvedTargetMetaPath = [System.IO.Path]::GetFullPath($TargetMetaPath)
if (-not (Test-Path -LiteralPath $resolvedTargetMetaPath)) {
throw "Target meta.lsx was not found: '$resolvedTargetMetaPath'."
}
if ([string]::IsNullOrWhiteSpace($ParentMetaUrl)) {
throw "ParentMetaUrl must not be empty."
}
try {
$parentResponse = Invoke-WebRequest -Uri $ParentMetaUrl -UseBasicParsing -TimeoutSec 60
} catch {
throw "Failed to download parent meta.lsx from '$ParentMetaUrl': $($_.Exception.Message)"
}
$parentRaw = $parentResponse.Content
$targetRaw = Get-Content -LiteralPath $resolvedTargetMetaPath -Raw
[xml]$parentXml = $parentRaw
[xml]$targetXml = $targetRaw
$parentModuleInfo = $parentXml.SelectSingleNode('/save/region/node/children/node[@id="ModuleInfo"]')
if ($null -eq $parentModuleInfo) {
throw "ModuleInfo node was not found in parent meta downloaded from '$ParentMetaUrl'."
}
$requiredFields = @("Folder", "MD5", "Name", "PublishHandle", "UUID", "Version64")
$sourceValues = @{}
foreach ($field in $requiredFields) {
$node = $parentModuleInfo.SelectSingleNode("attribute[@id='$field']")
if ($null -eq $node) {
throw "Required parent ModuleInfo attribute '$field' is missing in meta downloaded from '$ParentMetaUrl'."
}
$value = $node.GetAttribute("value")
if ([string]::IsNullOrWhiteSpace($value)) {
throw "Required parent ModuleInfo attribute '$field' has empty value in meta downloaded from '$ParentMetaUrl'."
}
$sourceValues[$field] = $value
}
$targetDependencyNode = $targetXml.SelectSingleNode('/save/region/node/children/node[@id="Dependencies"]/children/node[@id="ModuleShortDesc"]')
if ($null -eq $targetDependencyNode) {
throw "Dependencies/ModuleShortDesc node was not found in target meta: '$resolvedTargetMetaPath'."
}
$changedFields = @()
foreach ($field in $requiredFields) {
$targetAttr = $targetDependencyNode.SelectSingleNode("attribute[@id='$field']")
if ($null -eq $targetAttr) {
throw "Target Dependencies/ModuleShortDesc attribute '$field' is missing in '$resolvedTargetMetaPath'."
}
$currentValue = $targetAttr.GetAttribute("value")
$newValue = [string]$sourceValues[$field]
if ($currentValue -ne $newValue) {
$targetAttr.SetAttribute("value", $newValue)
$changedFields += $field
}
}
if ($changedFields.Count -eq 0) {
Write-Host "[sync-parent-meta.ps1] No changes needed. Target dependency data is already up to date."
} else {
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
$settings = New-Object System.Xml.XmlWriterSettings
$settings.Encoding = $utf8Bom
$settings.Indent = $true
$settings.IndentChars = " "
$settings.NewLineChars = "`n"
$settings.NewLineHandling = [System.Xml.NewLineHandling]::Replace
$writer = [System.Xml.XmlWriter]::Create($resolvedTargetMetaPath, $settings)
try {
$targetXml.WriteTo($writer)
} finally {
$writer.Dispose()
}
Write-Host ("[sync-parent-meta.ps1] Updated fields: " + ($changedFields -join ", "))
}