refactor: separate settlements in regions.py, integrate symspellpy fuzzy location matching into WWN faction tools, and add tests
This commit is contained in:
parent
0ab91a6b94
commit
f819946d1c
|
|
@ -8,8 +8,14 @@
|
||||||
scripts/
|
scripts/
|
||||||
├── dice_roller/ # Скрипты для бросков кубиков
|
├── dice_roller/ # Скрипты для бросков кубиков
|
||||||
├── faction_turns/ # Система ходов фракций (WWN)
|
├── faction_turns/ # Система ходов фракций (WWN)
|
||||||
|
│ ├── propose_faction_turn.py # Генерация доступных действий
|
||||||
|
│ ├── resolve_faction_turn.py # Применение ходов фракций
|
||||||
|
│ ├── faction_utils.py # Вспомогательные функции фракций
|
||||||
|
│ ├── wwn_mechanics.py # Механики системы
|
||||||
|
│ └── wwn_assets_data.py # Данные активов
|
||||||
├── generate_encounter/ # Генераторы столкновений и энкаунтеров
|
├── generate_encounter/ # Генераторы столкновений и энкаунтеров
|
||||||
├── generate_npc/ # Генерация NPC (био, классы, характеристики)
|
├── generate_npc/ # Генерация NPC (био, классы, характеристики)
|
||||||
|
│ └── regions.py # Региональные данные и symspellpy (населенные пункты)
|
||||||
├── generate_trap/ # Генерация ловушек
|
├── generate_trap/ # Генерация ловушек
|
||||||
├── generate_treasure/ # Генерация лута и сокровищ
|
├── generate_treasure/ # Генерация лута и сокровищ
|
||||||
├── time/ # Управление временем кампании
|
├── time/ # Управление временем кампании
|
||||||
|
|
|
||||||
48
TASKS.md
48
TASKS.md
|
|
@ -1,36 +1,20 @@
|
||||||
# План работ по рефакторингу API и расширению тестов
|
# Задачи по рефакторингу локаций и тулов фракций WWN
|
||||||
|
|
||||||
## 1. Рефакторинг vault_utils.py
|
- [x] **Этап 1: Обновление regions.py**
|
||||||
- [x] Заменить единый `vault_query` с хардкодом строк на экспортируемые прямые функции.
|
- [x] Вынести часть населённых пунктов из REGIONAL_OVERWRITES в SETTLEMENTS_OVERWRITES (`D:/Work/Software_Development/Projects/ttrpg-obsidian-vault/scripts/generate_npc/regions.py`)
|
||||||
- [x] Обновить XML-doc (docstrings) для всех методов.
|
- [x] Настроить динамическое вливание SETTLEMENTS_OVERWRITES в `REGIONAL_OVERWRITES` (добавление в `aliases`)
|
||||||
- [x] Добавить универсальную функцию `get_recent_files` (на базе JsonLogic).
|
- [x] Сформировать словари `WORLD_SETTLEMENTS` и функцию коррекции локаций через `symspellpy`
|
||||||
|
- [x] Полностью перенести все населенные пункты из `REGIONAL_OVERWRITES` в `SETTLEMENTS_OVERWRITES` без исключений. В `aliases` оставить только синонимы регионов и подрегионы.
|
||||||
|
|
||||||
## 2. Рефакторинг faction_utils.py
|
- [x] **Этап 2: Обновление faction_turns (propose_faction_turn & resolve_faction_turn)**
|
||||||
- [x] Перевести вызовы с `vault_query(...)` на прямые вызовы API.
|
- [x] Обновить `propose_faction_turn.py` (`world` + `location` вместо `location_wikilink` + коррекция через `symspellpy`)
|
||||||
- [x] Переписать `get_all_factions` и `get_recent_events` как обёртки вокруг `get_recent_files`.
|
- [x] Обновить `resolve_faction_turn.py` (`world` + `location` вместо `location_wikilink` + коррекция через `symspellpy`)
|
||||||
|
- [x] Проверить и синхронизировать `faction_utils.py` (существующая логика совместима)
|
||||||
|
|
||||||
## 3. Рефакторинг time_utils.py
|
- [x] **Этап 3: Обновление README.md**
|
||||||
- [x] Обновить импорты из `vault_utils`.
|
- [x] Обновить структуру и добавить блок для ИИ-агентов (уже присутствует)
|
||||||
- [x] Заменить `vault_query` на прямые методы (`get_file`, `write_file`).
|
|
||||||
|
|
||||||
## 4. Исследование Obsidian Local REST API
|
- [x] **Этап 4: Тестирование**
|
||||||
- [x] Добавить примеры JSONLogic-запросов и PowerShell-скрипт с сортировкой.
|
- [x] Добавить тесты для `generate_npc` (написаны).
|
||||||
- [x] Очистить документацию от сбоев форматирования Markdown ссылок.
|
- [x] Добавить тесты для `generate_encounter` (написаны).
|
||||||
|
- [x] Добавить тесты для функции нечеткого сопоставления локаций (`match_location`).
|
||||||
## 5. Расширение тестов фракций
|
|
||||||
- [x] Дописать интеграционные тесты для `get_recent_events`, `get_location` и работы с активами.
|
|
||||||
- [x] Расширить тесты логики ходов фракций в `test_wwn_mechanics.py`.
|
|
||||||
- [x] Добавлены setup-тесты для перезаписи тестовых файлов фракций (frontmatter и контент) для детерминированности среды.
|
|
||||||
- [x] Убедиться, что текущий набор pytest проходит без ошибок (`pytest -v`).
|
|
||||||
# План работ и задачи
|
|
||||||
|
|
||||||
## Исправление ошибок импорта фракций
|
|
||||||
- [x] Удалить импорт `vault_query` в `D:/Work/Software_Development/Projects/ttrpg-obsidian-vault/scripts/faction_turns/resolve_faction_turn.py`
|
|
||||||
- [x] Удалить импорт `vault_query` в `D:/Work/Software_Development/Projects/ttrpg-obsidian-vault/scripts/faction_turns/propose_faction_turn.py`
|
|
||||||
- [x] Заменить вызов `vault_query` на прямые вызовы функций в `D:/Work/Software_Development/Projects/ttrpg-obsidian-vault/scripts/faction_turns/tests/verify_factions.py`
|
|
||||||
|
|
||||||
## Исправления логики фракций
|
|
||||||
- [x] Починить логику `Repair Asset` для ремонта `Base of Influence` (цель может не иметь точного совпадения имени) в файле `resolve_faction_turn.py`
|
|
||||||
- [x] Сделать генерацию названий файлов событий (Event files) более читаемой, убрать длинные подчеркивания и дефисы.
|
|
||||||
- [✓] Добавить тесты исцеления Base of Influence для обычной и мощной фракций (D:/Work/Software_Development/Projects/ttrpg-obsidian-vault/scripts/faction_turns/tests/test_repair_boi.py)
|
|
||||||
- [✓] Запустить и проверить прохождение тестов `pytest`
|
|
||||||
|
|
@ -68,17 +68,22 @@ from wwn_mechanics import (
|
||||||
# TypedDict
|
# TypedDict
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from generate_npc.regions import match_location
|
||||||
|
|
||||||
class FactionTurnProposalRequest(TypedDict, total=False):
|
class FactionTurnProposalRequest(TypedDict, total=False):
|
||||||
"""
|
"""
|
||||||
Параметры одного запроса на генерацию хода фракций.
|
Параметры одного запроса на генерацию хода фракций.
|
||||||
|
|
||||||
Поля:
|
Поля:
|
||||||
location_wikilink: Имя локации на русском языке в формате Obsidian wikilink.
|
world: Космологический уровень сцены (англ.). Прайм-мир
|
||||||
Обязательное поле.
|
("Toril", "Krynn", "Oerth") ЛИБО план существования.
|
||||||
КРИТИЧЕСКИ ВАЖНО: Копируй название буква в букву из запроса,
|
По умолчанию: "Toril".
|
||||||
СТРОГО в именительном падеже. ЗАПРЕЩЕНО склонять, менять
|
|
||||||
окончания, переводить или придумывать буквы.
|
location: Имя локации на русском/английском языке.
|
||||||
Пример: "[[Даггерфорд]]", "[[Калимшан]]", название локации на русском.
|
Обязательное поле. Автоматически корректируется symspellpy.
|
||||||
|
Пример: "Даггерфорд", "Калимшан", "Waterdeep".
|
||||||
|
|
||||||
|
location_wikilink: Оставлено для обратной совместимости.
|
||||||
|
|
||||||
factions_folder: Путь к папке с файлами фракций внутри vault.
|
factions_folder: Путь к папке с файлами фракций внутри vault.
|
||||||
По умолчанию: "Фракции".
|
По умолчанию: "Фракции".
|
||||||
|
|
@ -94,7 +99,9 @@ class FactionTurnProposalRequest(TypedDict, total=False):
|
||||||
Допустимы: 1–20.
|
Допустимы: 1–20.
|
||||||
По умолчанию: 5.
|
По умолчанию: 5.
|
||||||
"""
|
"""
|
||||||
location_wikilink: str # wikilink локации, обязательно: "[[Уотердип]]"
|
world: str # "Toril", "Krynn", "Oerth", ...
|
||||||
|
location: str # "Waterdeep"
|
||||||
|
location_wikilink: str # fallback
|
||||||
factions_folder: str # default "Фракции"
|
factions_folder: str # default "Фракции"
|
||||||
events_folder: str # default "События"
|
events_folder: str # default "События"
|
||||||
game_date: str # default: today
|
game_date: str # default: today
|
||||||
|
|
@ -108,7 +115,8 @@ class FactionTurnProposalRequest(TypedDict, total=False):
|
||||||
def _get_default_request() -> FactionTurnProposalRequest:
|
def _get_default_request() -> FactionTurnProposalRequest:
|
||||||
"""Возвращает запрос с дефолтными значениями."""
|
"""Возвращает запрос с дефолтными значениями."""
|
||||||
return {
|
return {
|
||||||
"location_wikilink": "[[Unknown Location]]",
|
"world": "Toril",
|
||||||
|
"location": "Unknown Location",
|
||||||
"factions_folder": "Фракции",
|
"factions_folder": "Фракции",
|
||||||
"events_folder": "События",
|
"events_folder": "События",
|
||||||
"game_date": date.today().strftime("%d %B %Y"),
|
"game_date": date.today().strftime("%d %B %Y"),
|
||||||
|
|
@ -770,7 +778,20 @@ def propose_faction_turn(
|
||||||
|
|
||||||
for i, raw_req in enumerate(requests, start=1):
|
for i, raw_req in enumerate(requests, start=1):
|
||||||
req = _merge_with_defaults(raw_req)
|
req = _merge_with_defaults(raw_req)
|
||||||
location_wikilink = req["location_wikilink"]
|
world = req.get("world", "Toril")
|
||||||
|
|
||||||
|
# Поддержка обратной совместимости с location_wikilink
|
||||||
|
raw_location = req.get("location")
|
||||||
|
if raw_location == "Unknown Location" and req.get("location_wikilink") != "[[Unknown Location]]":
|
||||||
|
raw_location = req.get("location_wikilink", "Unknown Location")
|
||||||
|
|
||||||
|
# Очистка от скобок wikilink, если они есть
|
||||||
|
raw_location = raw_location.strip("[]")
|
||||||
|
|
||||||
|
# Сопоставление локации через symspellpy
|
||||||
|
matched_location = match_location(world, raw_location)
|
||||||
|
location_wikilink = f"[[{matched_location}]]"
|
||||||
|
|
||||||
factions_folder = req["factions_folder"]
|
factions_folder = req["factions_folder"]
|
||||||
events_folder = req["events_folder"]
|
events_folder = req["events_folder"]
|
||||||
game_date = req["game_date"]
|
game_date = req["game_date"]
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,8 @@ from wwn_mechanics import (
|
||||||
# TypedDict
|
# TypedDict
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
from generate_npc.regions import match_location
|
||||||
|
|
||||||
class FactionAction(TypedDict, total=False):
|
class FactionAction(TypedDict, total=False):
|
||||||
"""
|
"""
|
||||||
Параметры одного действия одной фракции за ход.
|
Параметры одного действия одной фракции за ход.
|
||||||
|
|
@ -92,9 +94,12 @@ class FactionAction(TypedDict, total=False):
|
||||||
"Expand Influence", "Create Asset", "Hide Asset", "Sell Asset".
|
"Expand Influence", "Create Asset", "Hide Asset", "Sell Asset".
|
||||||
Обязательное поле.
|
Обязательное поле.
|
||||||
|
|
||||||
location: Локация на русском в формате Obsidian wikilink.
|
world: Космологический уровень сцены (англ.).
|
||||||
|
По умолчанию: "Toril".
|
||||||
|
|
||||||
|
location: Имя локации на английском языке.
|
||||||
Обязательное поле.
|
Обязательное поле.
|
||||||
Пример: "[[Уотердип]]", "[[Невервинтер]]", название локации на русском.
|
Пример: "Waterdeep", "Neverwinter".
|
||||||
|
|
||||||
attacking_asset: Имя атакующего актива (для Attack).
|
attacking_asset: Имя атакующего актива (для Attack).
|
||||||
Пример: "Organization Moles".
|
Пример: "Organization Moles".
|
||||||
|
|
@ -128,7 +133,8 @@ class FactionAction(TypedDict, total=False):
|
||||||
"""
|
"""
|
||||||
faction_file: str # имя файла без .md, обязательно
|
faction_file: str # имя файла без .md, обязательно
|
||||||
action_type: str # "Attack"|"Move Asset"|"Repair Asset"|"Expand Influence"|"Create Asset"|"Hide Asset"|"Sell Asset"
|
action_type: str # "Attack"|"Move Asset"|"Repair Asset"|"Expand Influence"|"Create Asset"|"Hide Asset"|"Sell Asset"
|
||||||
location: str # "[[Уотердип]]"
|
world: str # "Toril", "Krynn"...
|
||||||
|
location: str # "Waterdeep"
|
||||||
attacking_asset: str # для Attack
|
attacking_asset: str # для Attack
|
||||||
target_faction: str # имя файла цели без .md, для Attack
|
target_faction: str # имя файла цели без .md, для Attack
|
||||||
target_asset: str # имя целевого актива, для Attack
|
target_asset: str # имя целевого актива, для Attack
|
||||||
|
|
@ -1062,6 +1068,20 @@ def resolve_faction_turn(
|
||||||
|
|
||||||
faction_files_needed = set()
|
faction_files_needed = set()
|
||||||
for action in actions:
|
for action in actions:
|
||||||
|
# Обработка location через symspellpy
|
||||||
|
world = action.get("world", "Toril")
|
||||||
|
raw_loc = action.get("location", "")
|
||||||
|
if raw_loc:
|
||||||
|
clean_loc = raw_loc.strip("[]")
|
||||||
|
matched_loc = match_location(world, clean_loc)
|
||||||
|
action["location"] = f"[[{matched_loc}]]"
|
||||||
|
|
||||||
|
raw_exp_loc = action.get("expand_location", "")
|
||||||
|
if raw_exp_loc:
|
||||||
|
clean_exp_loc = raw_exp_loc.strip("[]")
|
||||||
|
matched_exp_loc = match_location(world, clean_exp_loc)
|
||||||
|
action["expand_location"] = f"[[{matched_exp_loc}]]"
|
||||||
|
|
||||||
faction_files_needed.add(action.get("faction_file", ""))
|
faction_files_needed.add(action.get("faction_file", ""))
|
||||||
if action.get("action_type") == "Attack":
|
if action.get("action_type") == "Attack":
|
||||||
faction_files_needed.add(action.get("target_faction", ""))
|
faction_files_needed.add(action.get("target_faction", ""))
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ from get_npc_races import get_npc_races
|
||||||
|
|
||||||
# Импортируем функцию из соседней папки.
|
# Импортируем функцию из соседней папки.
|
||||||
# Поскольку в sys.path есть npc_folder, можно импортировать напрямую из файла
|
# Поскольку в sys.path есть npc_folder, можно импортировать напрямую из файла
|
||||||
from generate_npc import generate_npc as get_npc
|
from gen_npc import generate_npc as get_npc
|
||||||
|
|
||||||
|
|
||||||
# Множество планов существования (не прайм-миры).
|
# Множество планов существования (не прайм-миры).
|
||||||
60
generate_encounter/tests/test_generate_encounter.py
Normal file
60
generate_encounter/tests/test_generate_encounter.py
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
scripts_path = Path(__file__).resolve().parent.parent.parent
|
||||||
|
if str(scripts_path) not in sys.path:
|
||||||
|
sys.path.insert(0, str(scripts_path))
|
||||||
|
|
||||||
|
enc_path = Path(__file__).resolve().parent.parent
|
||||||
|
if str(enc_path) not in sys.path:
|
||||||
|
sys.path.insert(0, str(enc_path))
|
||||||
|
|
||||||
|
from gen_encounter import generate_encounter
|
||||||
|
|
||||||
|
# ----------------------------------------------- Тесты Генерации Энкаунтеров ------------------------------------------------------------
|
||||||
|
|
||||||
|
def test_encounter_default():
|
||||||
|
"""
|
||||||
|
Проверяет базовую генерацию случайной встречи с настройками по умолчанию.
|
||||||
|
Возвращает непустую строку-отчет.
|
||||||
|
"""
|
||||||
|
result = generate_encounter("тест", [{}])
|
||||||
|
assert isinstance(result, str)
|
||||||
|
assert "Встреча №1" in result
|
||||||
|
assert "**Уровень группы:** 1" in result
|
||||||
|
|
||||||
|
def test_encounter_specific_biome():
|
||||||
|
"""
|
||||||
|
Проверяет генерацию встречи для конкретного биома, уровня и типа PvP.
|
||||||
|
Гарантирует, что параметры запроса применяются корректно.
|
||||||
|
"""
|
||||||
|
req = {
|
||||||
|
"environment": "urban",
|
||||||
|
"level": 5,
|
||||||
|
"encounter_type": "PvP"
|
||||||
|
}
|
||||||
|
result = generate_encounter("тест", [req])
|
||||||
|
assert isinstance(result, str)
|
||||||
|
assert "**Биом:** Urban" in result
|
||||||
|
assert "**Тип встречи:** PvP" in result
|
||||||
|
assert "**Уровень группы:** 5" in result
|
||||||
|
|
||||||
|
def test_encounter_planar_world():
|
||||||
|
"""
|
||||||
|
Проверяет планарные миры. Биом должен игнорироваться при выборе таблиц.
|
||||||
|
Вывод должен содержать информацию о мире/плане.
|
||||||
|
"""
|
||||||
|
req = {
|
||||||
|
"world": "feywild",
|
||||||
|
"level": 8
|
||||||
|
}
|
||||||
|
result = generate_encounter("тест", [req])
|
||||||
|
assert isinstance(result, str)
|
||||||
|
assert "**Мир/План:** feywild" in result
|
||||||
|
assert "**Уровень группы:** 8" in result
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_encounter_default()
|
||||||
|
test_encounter_specific_biome()
|
||||||
|
test_encounter_planar_world()
|
||||||
|
print("Все тесты generate_encounter успешно пройдены!")
|
||||||
|
|
@ -235,7 +235,7 @@ def _generate_single_npc(
|
||||||
subrace_name = _weighted_pick(region_subs)
|
subrace_name = _weighted_pick(region_subs)
|
||||||
elif "subraces" in race_data and race_data["subraces"]:
|
elif "subraces" in race_data and race_data["subraces"]:
|
||||||
sub_pool = _normalize_chances(
|
sub_pool = _normalize_chances(
|
||||||
{s: d["chance"] for s, d in race_data["subraces"].items()}
|
{s: d.get("chance", 10.0) for s, d in race_data["subraces"].items()}
|
||||||
)
|
)
|
||||||
subrace_name = _weighted_pick(sub_pool)
|
subrace_name = _weighted_pick(sub_pool)
|
||||||
race_obj = {"race": race_name, "subrace": subrace_name}
|
race_obj = {"race": race_name, "subrace": subrace_name}
|
||||||
|
|
@ -11,8 +11,7 @@
|
||||||
REGIONAL_OVERWRITES: dict = {
|
REGIONAL_OVERWRITES: dict = {
|
||||||
"Toril": {
|
"Toril": {
|
||||||
"sword_coast_north": {
|
"sword_coast_north": {
|
||||||
"aliases": ["Sword Coast North", "Savage Frontier", "Frozenfar",
|
"aliases": ["Sword Coast North", "Savage Frontier", "Frozenfar"],
|
||||||
"Luskan", "Neverwinter", "Port Llast", "Mirabar"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 58.0, "subraces": {"Illuskan": 70.0, "Damaran": 20.0, "Chondathan": 10.0}},
|
"Human": {"chance": 58.0, "subraces": {"Illuskan": 70.0, "Damaran": 20.0, "Chondathan": 10.0}},
|
||||||
"Dwarf": {"chance": 14.0, "subraces": {"Shield/Mountain": 90.0, "Gold/Hill": 10.0}},
|
"Dwarf": {"chance": 14.0, "subraces": {"Shield/Mountain": 90.0, "Gold/Hill": 10.0}},
|
||||||
|
|
@ -26,8 +25,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"silver_marches": {
|
"silver_marches": {
|
||||||
"aliases": ["Silver Marches", "Luruar", "Silverymoon", "Sundabar",
|
"aliases": ["Silver Marches", "Luruar"],
|
||||||
"Mithral Hall", "Everlund", "Citadel Adbar"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 42.0, "subraces": {"Illuskan": 50.0, "Chondathan": 40.0, "Damaran": 10.0}},
|
"Human": {"chance": 42.0, "subraces": {"Illuskan": 50.0, "Chondathan": 40.0, "Damaran": 10.0}},
|
||||||
"Dwarf": {"chance": 22.0, "subraces": {"Shield/Mountain": 95.0, "Gold/Hill": 5.0}},
|
"Dwarf": {"chance": 22.0, "subraces": {"Shield/Mountain": 95.0, "Gold/Hill": 5.0}},
|
||||||
|
|
@ -40,8 +38,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"western_heartlands": {
|
"western_heartlands": {
|
||||||
"aliases": ["Western Heartlands", "Elturgard", "Elturel", "Beregost",
|
"aliases": ["Western Heartlands", "Elturgard", "Sunset Mountains"],
|
||||||
"Candlekeep", "Sunset Mountains", "Scornubel"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 72.0, "subraces": {"Chondathan": 55.0, "Tethyrian": 35.0, "Calishite": 7.0, "Illuskan": 3.0}},
|
"Human": {"chance": 72.0, "subraces": {"Chondathan": 55.0, "Tethyrian": 35.0, "Calishite": 7.0, "Illuskan": 3.0}},
|
||||||
"Halfling": {"chance": 9.0, "subraces": {"Lightfoot": 85.0, "Ghostwise": 10.0, "Stout": 5.0}},
|
"Halfling": {"chance": 9.0, "subraces": {"Lightfoot": 85.0, "Ghostwise": 10.0, "Stout": 5.0}},
|
||||||
|
|
@ -53,7 +50,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"waterdeep": {
|
"waterdeep": {
|
||||||
"aliases": ["Waterdeep", "City of Splendors", "Crown of North"],
|
"aliases": ["Crown of North"],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 60.0, "subraces": {"Illuskan": 35.0, "Tethyrian": 30.0, "Chondathan": 25.0, "Calishite": 5.0, "Shou": 5.0}},
|
"Human": {"chance": 60.0, "subraces": {"Illuskan": 35.0, "Tethyrian": 30.0, "Chondathan": 25.0, "Calishite": 5.0, "Shou": 5.0}},
|
||||||
"Half-Elf": {"chance": 9.0, "subraces": {"Moon": 75.0, "Sun": 15.0, "Wood": 10.0}},
|
"Half-Elf": {"chance": 9.0, "subraces": {"Moon": 75.0, "Sun": 15.0, "Wood": 10.0}},
|
||||||
|
|
@ -67,7 +64,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"baldurs_gate": {
|
"baldurs_gate": {
|
||||||
"aliases": ["Baldur's Gate", "Gate", "Baldurs Gate"],
|
"aliases": [],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 68.0, "subraces": {"Tethyrian": 45.0, "Chondathan": 30.0, "Calishite": 15.0, "Illuskan": 7.0, "Damaran": 3.0}},
|
"Human": {"chance": 68.0, "subraces": {"Tethyrian": 45.0, "Chondathan": 30.0, "Calishite": 15.0, "Illuskan": 7.0, "Damaran": 3.0}},
|
||||||
"Half-Elf": {"chance": 7.0, "subraces": {"Moon": 70.0, "Wood": 30.0}},
|
"Half-Elf": {"chance": 7.0, "subraces": {"Moon": 70.0, "Wood": 30.0}},
|
||||||
|
|
@ -81,8 +78,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"cormyr": {
|
"cormyr": {
|
||||||
"aliases": ["Cormyr", "Forest Kingdom", "Suzail", "Marsember",
|
"aliases": ["Cormyr", "Forest Kingdom", "Purple Dragons"],
|
||||||
"Arabel", "Wheloon", "Purple Dragons"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 78.0, "subraces": {"Chondathan": 80.0, "Tethyrian": 12.0, "Damaran": 5.0, "Illuskan": 3.0}},
|
"Human": {"chance": 78.0, "subraces": {"Chondathan": 80.0, "Tethyrian": 12.0, "Damaran": 5.0, "Illuskan": 3.0}},
|
||||||
"Half-Elf": {"chance": 6.0, "subraces": {"Moon": 80.0, "Sun": 20.0}},
|
"Half-Elf": {"chance": 6.0, "subraces": {"Moon": 80.0, "Sun": 20.0}},
|
||||||
|
|
@ -94,8 +90,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"amn": {
|
"amn": {
|
||||||
"aliases": ["Amn", "Athkatla", "Crimmor", "Eshpurta",
|
"aliases": ["Amn", "Merchant's Domain"],
|
||||||
"Purskul", "Trademeet", "Merchant's Domain"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 78.0, "subraces": {"Tethyrian": 45.0, "Calishite": 38.0, "Chondathan": 12.0, "Illuskan": 5.0}},
|
"Human": {"chance": 78.0, "subraces": {"Tethyrian": 45.0, "Calishite": 38.0, "Chondathan": 12.0, "Illuskan": 5.0}},
|
||||||
"Halfling": {"chance": 8.0, "subraces": {"Lightfoot": 85.0, "Stout": 15.0}},
|
"Halfling": {"chance": 8.0, "subraces": {"Lightfoot": 85.0, "Stout": 15.0}},
|
||||||
|
|
@ -107,8 +102,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"tethyr": {
|
"tethyr": {
|
||||||
"aliases": ["Tethyr", "Zazesspur", "Darromar", "Myratma",
|
"aliases": ["Tethyr", "Country of Purple Marches"],
|
||||||
"Ithmong", "Saradush", "Riatavin", "Country of Purple Marches"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 74.0, "subraces": {"Tethyrian": 70.0, "Calishite": 18.0, "Chondathan": 8.0, "Illuskan": 4.0}},
|
"Human": {"chance": 74.0, "subraces": {"Tethyrian": 70.0, "Calishite": 18.0, "Chondathan": 8.0, "Illuskan": 4.0}},
|
||||||
"Halfling": {"chance": 9.0, "subraces": {"Lightfoot": 80.0, "Stout": 20.0}},
|
"Halfling": {"chance": 9.0, "subraces": {"Lightfoot": 80.0, "Stout": 20.0}},
|
||||||
|
|
@ -120,7 +114,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"calimshan": {
|
"calimshan": {
|
||||||
"aliases": ["Calimshan", "Calimport", "Memnon", "Almraiven", "Keltar"],
|
"aliases": ["Calimshan"],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 82.0, "subraces": {"Calishite": 88.0, "Tethyrian": 8.0, "Chondathan": 4.0}},
|
"Human": {"chance": 82.0, "subraces": {"Calishite": 88.0, "Tethyrian": 8.0, "Chondathan": 4.0}},
|
||||||
"Genasi": {"chance": 8.0, "subraces": {"Fire": 35.0, "Air": 35.0, "Earth": 15.0, "Water": 15.0}},
|
"Genasi": {"chance": 8.0, "subraces": {"Fire": 35.0, "Air": 35.0, "Earth": 15.0, "Water": 15.0}},
|
||||||
|
|
@ -131,7 +125,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"chult": {
|
"chult": {
|
||||||
"aliases": ["Chult", "Port Nyanzaru", "Mezro", "Chultan Peninsula", "Omu"],
|
"aliases": ["Chult", "Chultan Peninsula"],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 68.0, "subraces": {"Chultan": 90.0, "Tethyrian": 6.0, "Calishite": 4.0}},
|
"Human": {"chance": 68.0, "subraces": {"Chultan": 90.0, "Tethyrian": 6.0, "Calishite": 4.0}},
|
||||||
"Tabaxi": {"chance": 14.0},
|
"Tabaxi": {"chance": 14.0},
|
||||||
|
|
@ -144,8 +138,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
"unapproachable_east": {
|
"unapproachable_east": {
|
||||||
"aliases": ["Unapproachable East", "Aglarond border",
|
"aliases": ["Unapproachable East", "Aglarond border",
|
||||||
"Thesk", "Great Dale", "Bezantur", "Two Stars",
|
"Thesk", "Great Dale"],
|
||||||
"Phsant", "Milvarune"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 78.0, "subraces": {"Mulan": 50.0, "Rashemi": 25.0, "Damaran": 20.0, "Chondathan": 5.0}},
|
"Human": {"chance": 78.0, "subraces": {"Mulan": 50.0, "Rashemi": 25.0, "Damaran": 20.0, "Chondathan": 5.0}},
|
||||||
"Half-Orc": {"chance": 7.0},
|
"Half-Orc": {"chance": 7.0},
|
||||||
|
|
@ -157,8 +150,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"rashemen": {
|
"rashemen": {
|
||||||
"aliases": ["Rashemen", "Mulsantir", "Immilmar", "Urling",
|
"aliases": ["Rashemen", "Land of Berserkers",
|
||||||
"Citadel Rashemar", "Mulptan", "Land of Berserkers",
|
|
||||||
"Ashenwood", "Witches of Rashemen"],
|
"Ashenwood", "Witches of Rashemen"],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 84.0, "subraces": {"Rashemi": 80.0, "Damaran": 12.0, "Mulan": 8.0}},
|
"Human": {"chance": 84.0, "subraces": {"Rashemi": 80.0, "Damaran": 12.0, "Mulan": 8.0}},
|
||||||
|
|
@ -171,9 +163,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"thay": {
|
"thay": {
|
||||||
"aliases": ["Thay", "Red Wizards", "Eltabbar", "Tyraturos",
|
"aliases": ["Thay", "Red Wizards", "Thaymount", "High Thay"],
|
||||||
"Amruthar", "Pyarados", "Surthay", "Nethjet",
|
|
||||||
"Thaymount", "High Thay"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 82.0, "subraces": {"Mulan": 55.0, "Rashemi": 30.0, "Chondathan": 8.0, "Damaran": 7.0}},
|
"Human": {"chance": 82.0, "subraces": {"Mulan": 55.0, "Rashemi": 30.0, "Chondathan": 8.0, "Damaran": 7.0}},
|
||||||
"Half-Orc": {"chance": 5.0},
|
"Half-Orc": {"chance": 5.0},
|
||||||
|
|
@ -186,8 +176,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"underdark": {
|
"underdark": {
|
||||||
"aliases": ["Underdark", "Menzoberranzan", "Blingdenstone",
|
"aliases": ["Underdark", "Deep Realm"],
|
||||||
"Gracklstugh", "Deep Realm", "Sshamath", "Ched Nasad"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Elf": {"chance": 46.0, "subraces": {"Drow": 100.0}},
|
"Elf": {"chance": 46.0, "subraces": {"Drow": 100.0}},
|
||||||
"Dwarf": {"chance": 20.0, "subraces": {"Duergar": 100.0}},
|
"Dwarf": {"chance": 20.0, "subraces": {"Duergar": 100.0}},
|
||||||
|
|
@ -201,8 +190,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"moonsea": {
|
"moonsea": {
|
||||||
"aliases": ["Moonsea", "Zhentil Keep", "Melvaunt", "Hillsfar",
|
"aliases": ["Moonsea", "Sembia border"],
|
||||||
"Mulmaster", "Phlan", "Thentia", "Sembia border"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 74.0, "subraces": {"Chondathan": 45.0, "Damaran": 35.0, "Illuskan": 12.0, "Mulan": 8.0}},
|
"Human": {"chance": 74.0, "subraces": {"Chondathan": 45.0, "Damaran": 35.0, "Illuskan": 12.0, "Mulan": 8.0}},
|
||||||
"Half-Orc": {"chance": 7.0},
|
"Half-Orc": {"chance": 7.0},
|
||||||
|
|
@ -214,8 +202,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"dalelands": {
|
"dalelands": {
|
||||||
"aliases": ["Dalelands", "Shadowdale", "Mistledale", "Deepingdale",
|
"aliases": ["Dalelands"],
|
||||||
"Battledale", "Daggerdale", "Archendale"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 70.0, "subraces": {"Chondathan": 70.0, "Damaran": 20.0, "Illuskan": 10.0}},
|
"Human": {"chance": 70.0, "subraces": {"Chondathan": 70.0, "Damaran": 20.0, "Illuskan": 10.0}},
|
||||||
"Half-Elf": {"chance": 9.0, "subraces": {"Moon": 65.0, "Wood": 35.0}},
|
"Half-Elf": {"chance": 9.0, "subraces": {"Moon": 65.0, "Wood": 35.0}},
|
||||||
|
|
@ -227,8 +214,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"sembia": {
|
"sembia": {
|
||||||
"aliases": ["Sembia", "Selgaunt", "Ordulin", "Saerloon",
|
"aliases": ["Sembia"],
|
||||||
"Yhaunn", "Daerlun", "Urmlaspyr"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 80.0, "subraces": {"Chondathan": 65.0, "Damaran": 20.0, "Tethyrian": 8.0, "Shou": 7.0}},
|
"Human": {"chance": 80.0, "subraces": {"Chondathan": 65.0, "Damaran": 20.0, "Tethyrian": 8.0, "Shou": 7.0}},
|
||||||
"Half-Elf": {"chance": 6.0, "subraces": {"Moon": 75.0, "Wood": 25.0}},
|
"Half-Elf": {"chance": 6.0, "subraces": {"Moon": 75.0, "Wood": 25.0}},
|
||||||
|
|
@ -240,8 +226,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"vast": {
|
"vast": {
|
||||||
"aliases": ["Vast", "Ravens Bluff", "Tantras", "Calaunt",
|
"aliases": ["Vast"],
|
||||||
"Procampur", "Sarbreen"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 72.0, "subraces": {"Chondathan": 50.0, "Damaran": 30.0, "Illuskan": 12.0, "Mulan": 8.0}},
|
"Human": {"chance": 72.0, "subraces": {"Chondathan": 50.0, "Damaran": 30.0, "Illuskan": 12.0, "Mulan": 8.0}},
|
||||||
"Dwarf": {"chance": 8.0, "subraces": {"Shield/Mountain": 75.0, "Gold/Hill": 25.0}},
|
"Dwarf": {"chance": 8.0, "subraces": {"Shield/Mountain": 75.0, "Gold/Hill": 25.0}},
|
||||||
|
|
@ -253,8 +238,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"vilhon_reach": {
|
"vilhon_reach": {
|
||||||
"aliases": ["Vilhon Reach", "Turmish", "Chondath", "Hlondeth",
|
"aliases": ["Vilhon Reach", "Turmish", "Chondath"],
|
||||||
"Alaghon", "Arrabar", "Sespech", "Nimpeth"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 74.0, "subraces": {"Chondathan": 60.0, "Turami": 25.0, "Tethyrian": 10.0, "Mulan": 5.0}},
|
"Human": {"chance": 74.0, "subraces": {"Chondathan": 60.0, "Turami": 25.0, "Tethyrian": 10.0, "Mulan": 5.0}},
|
||||||
"Half-Elf": {"chance": 6.0, "subraces": {"Wood": 60.0, "Moon": 40.0}},
|
"Half-Elf": {"chance": 6.0, "subraces": {"Wood": 60.0, "Moon": 40.0}},
|
||||||
|
|
@ -280,8 +264,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"old_empires": {
|
"old_empires": {
|
||||||
"aliases": ["Old Empires", "Mulhorand", "Unther", "Chessenta",
|
"aliases": ["Old Empires", "Mulhorand", "Unther", "Chessenta"],
|
||||||
"Skuld", "Messemprar", "Cimbar", "Soorenar"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 80.0, "subraces": {"Mulan": 70.0, "Chondathan": 15.0, "Turami": 10.0, "Chessentan": 5.0}},
|
"Human": {"chance": 80.0, "subraces": {"Mulan": 70.0, "Chondathan": 15.0, "Turami": 10.0, "Chessentan": 5.0}},
|
||||||
"Half-Orc": {"chance": 5.0},
|
"Half-Orc": {"chance": 5.0},
|
||||||
|
|
@ -317,8 +300,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"moonshae_isles": {
|
"moonshae_isles": {
|
||||||
"aliases": ["Moonshae Isles", "Moonshaes", "Gwynneth", "Alaron",
|
"aliases": ["Moonshae Isles", "Moonshaes", "Gwynneth", "Alaron", "Snowdown", "Norland"],
|
||||||
"Snowdown", "Norland", "Callidyrr", "Corwell"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 72.0, "subraces": {"Ffolk": 60.0, "Northlander": 30.0, "Illuskan": 10.0}},
|
"Human": {"chance": 72.0, "subraces": {"Ffolk": 60.0, "Northlander": 30.0, "Illuskan": 10.0}},
|
||||||
"Half-Elf": {"chance": 8.0, "subraces": {"Moon": 60.0, "Wood": 40.0}},
|
"Half-Elf": {"chance": 8.0, "subraces": {"Moon": 60.0, "Wood": 40.0}},
|
||||||
|
|
@ -370,8 +352,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"impiltur_and_bloodstone": {
|
"impiltur_and_bloodstone": {
|
||||||
"aliases": ["Impiltur", "Damara", "Bloodstone Lands", "Narfell",
|
"aliases": ["Impiltur", "Damara", "Bloodstone Lands", "Narfell", "Vaasa"],
|
||||||
"Vaasa", "Lyrabar", "Heliogabalus"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 78.0, "subraces": {"Damaran": 75.0, "Chondathan": 15.0, "Rashemi": 10.0}},
|
"Human": {"chance": 78.0, "subraces": {"Damaran": 75.0, "Chondathan": 15.0, "Rashemi": 10.0}},
|
||||||
"Dwarf": {"chance": 8.0, "subraces": {"Shield/Mountain": 85.0, "Gold/Hill": 15.0}},
|
"Dwarf": {"chance": 8.0, "subraces": {"Shield/Mountain": 85.0, "Gold/Hill": 15.0}},
|
||||||
|
|
@ -384,8 +365,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"anauroch": {
|
"anauroch": {
|
||||||
"aliases": ["Anauroch", "Great Sand Sea", "Bedine", "Sword of North",
|
"aliases": ["Anauroch", "Great Sand Sea", "Bedine", "Sword of North", "Plain of Standing Stones", "Hidden Lake"],
|
||||||
"Plain of Standing Stones", "Hidden Lake", "Shade Enclave"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 80.0, "subraces": {"Bedine": 55.0, "Netherese": 25.0, "Illuskan": 12.0, "Damaran": 8.0}},
|
"Human": {"chance": 80.0, "subraces": {"Bedine": 55.0, "Netherese": 25.0, "Illuskan": 12.0, "Damaran": 8.0}},
|
||||||
"Genasi": {"chance": 6.0, "subraces": {"Earth": 40.0, "Air": 30.0, "Fire": 30.0}},
|
"Genasi": {"chance": 6.0, "subraces": {"Earth": 40.0, "Air": 30.0, "Fire": 30.0}},
|
||||||
|
|
@ -397,8 +377,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"aglarond": {
|
"aglarond": {
|
||||||
"aliases": ["Aglarond", "Altumbel", "Velprintalar", "Yeshelmaar",
|
"aliases": ["Aglarond", "Altumbel", "Umbergoth"],
|
||||||
"Umbergoth", "Emmech"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Half-Elf": {"chance": 40.0, "subraces": {"Wood": 70.0, "Moon": 30.0}},
|
"Half-Elf": {"chance": 40.0, "subraces": {"Wood": 70.0, "Moon": 30.0}},
|
||||||
"Human": {"chance": 38.0, "subraces": {"Aglarondan": 60.0, "Damaran": 25.0, "Chondathan": 15.0}},
|
"Human": {"chance": 38.0, "subraces": {"Aglarondan": 60.0, "Damaran": 25.0, "Chondathan": 15.0}},
|
||||||
|
|
@ -410,7 +389,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"lantan": {
|
"lantan": {
|
||||||
"aliases": ["Lantan", "Lantanna", "Supai", "Sambar", "Adaerglass"],
|
"aliases": ["Lantan", "Lantanna", "Supai"],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 68.0, "subraces": {"Lantanese": 80.0, "Chondathan": 12.0, "Calishite": 8.0}},
|
"Human": {"chance": 68.0, "subraces": {"Lantanese": 80.0, "Chondathan": 12.0, "Calishite": 8.0}},
|
||||||
"Gnome": {"chance": 20.0, "subraces": {"Rock": 85.0, "Forest": 15.0}},
|
"Gnome": {"chance": 20.0, "subraces": {"Rock": 85.0, "Forest": 15.0}},
|
||||||
|
|
@ -421,9 +400,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"sea_of_fallen_stars": {
|
"sea_of_fallen_stars": {
|
||||||
"aliases": ["Sea of Fallen Stars", "Inner Sea", "Pirate Isles",
|
"aliases": ["Sea of Fallen Stars", "Inner Sea", "Pirate Isles", "Dragonmere", "Sea of Swords bound", "Whamite Isles"],
|
||||||
"Dragonmere", "Sea of Swords bound", "Immurk's Hold",
|
|
||||||
"Whamite Isles"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 66.0, "subraces": {"Chondathan": 35.0, "Illuskan": 25.0, "Tethyrian": 20.0, "Turami": 12.0, "Mulan": 8.0}},
|
"Human": {"chance": 66.0, "subraces": {"Chondathan": 35.0, "Illuskan": 25.0, "Tethyrian": 20.0, "Turami": 12.0, "Mulan": 8.0}},
|
||||||
"Half-Orc": {"chance": 8.0},
|
"Half-Orc": {"chance": 8.0},
|
||||||
|
|
@ -436,9 +413,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"sword_coast_central": {
|
"sword_coast_central": {
|
||||||
"aliases": ["Sword Coast Central", "Daggerford", "Trade Way",
|
"aliases": ["Sword Coast Central", "Trade Way", "Delimbiyr Vale", "Misty Forest bound"],
|
||||||
"Delimbiyr Vale", "Secomber", "Boareskyr Bridge",
|
|
||||||
"Misty Forest bound"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 70.0, "subraces": {"Tethyrian": 40.0, "Chondathan": 35.0, "Illuskan": 20.0, "Calishite": 5.0}},
|
"Human": {"chance": 70.0, "subraces": {"Tethyrian": 40.0, "Chondathan": 35.0, "Illuskan": 20.0, "Calishite": 5.0}},
|
||||||
"Halfling": {"chance": 8.0, "subraces": {"Lightfoot": 80.0, "Stout": 20.0}},
|
"Halfling": {"chance": 8.0, "subraces": {"Lightfoot": 80.0, "Stout": 20.0}},
|
||||||
|
|
@ -451,8 +426,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"maztica": {
|
"maztica": {
|
||||||
"aliases": ["Maztica", "True World", "Nexal", "Payit", "Kultaka",
|
"aliases": ["Maztica", "True World", "Nexal", "Payit", "Kultaka", "Huacli", "Far Payit"],
|
||||||
"Huacli", "Far Payit", "Helmsport", "Ulatos"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 80.0, "subraces": {"Nexalan": 65.0, "Payit": 20.0, "Calishite": 10.0, "Tethyrian": 5.0}},
|
"Human": {"chance": 80.0, "subraces": {"Nexalan": 65.0, "Payit": 20.0, "Calishite": 10.0, "Tethyrian": 5.0}},
|
||||||
"Lizardfolk": {"chance": 6.0},
|
"Lizardfolk": {"chance": 6.0},
|
||||||
|
|
@ -465,10 +439,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"icewind_dale": {
|
"icewind_dale": {
|
||||||
"aliases": ["Icewind Dale", "Ten Towns", "Bryn Shander", "Targos",
|
"aliases": ["Icewind Dale", "Reghed Glacier", "Kelvin's Cairn", "Reghedmen"],
|
||||||
"Lonelywood", "Easthaven", "Termalaine", "Caer-Dineval",
|
|
||||||
"Caer-Konig", "Dougan's Hole", "Good Mead", "Reghed Glacier",
|
|
||||||
"Kelvin's Cairn", "Reghedmen"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 55.0, "subraces": {"Illuskan": 60.0, "Reghed": 30.0, "Damaran": 10.0}},
|
"Human": {"chance": 55.0, "subraces": {"Illuskan": 60.0, "Reghed": 30.0, "Damaran": 10.0}},
|
||||||
"Dwarf": {"chance": 16.0, "subraces": {"Shield/Mountain": 95.0, "Gold/Hill": 5.0}},
|
"Dwarf": {"chance": 16.0, "subraces": {"Shield/Mountain": 95.0, "Gold/Hill": 5.0}},
|
||||||
|
|
@ -480,8 +451,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"evermeet": {
|
"evermeet": {
|
||||||
"aliases": ["Evermeet", "Island of Evermeet", "Green Isle",
|
"aliases": ["Evermeet", "Island of Evermeet", "Green Isle", "Isle of Evermeet"],
|
||||||
"Isle of Evermeet", "Leuthilspar"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Elf": {"chance": 88.0, "subraces": {"Sun": 50.0, "Moon": 42.0, "Avariel": 5.0, "Eladrin": 3.0}},
|
"Elf": {"chance": 88.0, "subraces": {"Sun": 50.0, "Moon": 42.0, "Avariel": 5.0, "Eladrin": 3.0}},
|
||||||
"Half-Elf": {"chance": 8.0, "subraces": {"Sun": 60.0, "Moon": 40.0}},
|
"Half-Elf": {"chance": 8.0, "subraces": {"Sun": 60.0, "Moon": 40.0}},
|
||||||
|
|
@ -490,9 +460,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"myth_drannor": {
|
"myth_drannor": {
|
||||||
"aliases": ["Myth Drannor", "City of Song", "Cormanthyr",
|
"aliases": ["Myth Drannor", "City of Song", "Cormanthyr", "Cormanthor", "Elven Court"],
|
||||||
"Cormanthor", "Semberholme", "Tangled Trees",
|
|
||||||
"Elven Court"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Elf": {"chance": 50.0, "subraces": {"Moon": 45.0, "Sun": 30.0, "Wood": 20.0, "Eladrin": 5.0}},
|
"Elf": {"chance": 50.0, "subraces": {"Moon": 45.0, "Sun": 30.0, "Wood": 20.0, "Eladrin": 5.0}},
|
||||||
"Human": {"chance": 22.0, "subraces": {"Chondathan": 70.0, "Damaran": 20.0, "Illuskan": 10.0}},
|
"Human": {"chance": 22.0, "subraces": {"Chondathan": 70.0, "Damaran": 20.0, "Illuskan": 10.0}},
|
||||||
|
|
@ -504,9 +472,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"tashalar_and_shaar": {
|
"tashalar_and_shaar": {
|
||||||
"aliases": ["Tashalar", "Tashluta", "Lapaliiya", "Thindol",
|
"aliases": ["Tashalar", "Lapaliiya", "Thindol", "Samarach", "Shaar", "Great Rift", "Channath Vale"],
|
||||||
"Samarach", "Shaar", "Great Rift", "Channath Vale",
|
|
||||||
"Sheirtalar"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 55.0, "subraces": {"Chultan": 45.0, "Shaaran": 25.0, "Tethyrian": 20.0, "Calishite": 10.0}},
|
"Human": {"chance": 55.0, "subraces": {"Chultan": 45.0, "Shaaran": 25.0, "Tethyrian": 20.0, "Calishite": 10.0}},
|
||||||
"Yuan-ti Pureblood": {"chance": 16.0},
|
"Yuan-ti Pureblood": {"chance": 16.0},
|
||||||
|
|
@ -519,8 +485,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"nimbral": {
|
"nimbral": {
|
||||||
"aliases": ["Nimbral", "Nimbral Isles", "Immurk's Hold south",
|
"aliases": ["Nimbral", "Nimbral Isles", "Immurk's Hold south", "Land of Flying Hunt"],
|
||||||
"Land of Flying Hunt", "Cathtyr"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 80.0, "subraces": {"Halruaan": 45.0, "Tethyrian": 30.0, "Illuskan": 15.0, "Calishite": 10.0}},
|
"Human": {"chance": 80.0, "subraces": {"Halruaan": 45.0, "Tethyrian": 30.0, "Illuskan": 15.0, "Calishite": 10.0}},
|
||||||
"Half-Elf": {"chance": 7.0, "subraces": {"Moon": 100.0}},
|
"Half-Elf": {"chance": 7.0, "subraces": {"Moon": 100.0}},
|
||||||
|
|
@ -535,8 +500,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
|
|
||||||
"Krynn": {
|
"Krynn": {
|
||||||
"abanasinia": {
|
"abanasinia": {
|
||||||
"aliases": ["Abanasinia", "Solace", "Haven", "Que-Shu",
|
"aliases": ["Abanasinia", "Crystalmir Lake", "Sancrist bound"],
|
||||||
"Crystalmir Lake", "Sancrist bound"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 72.0, "subraces": {"Plainsfolk": 45.0, "Abanasinian": 45.0, "Solamnic": 10.0}},
|
"Human": {"chance": 72.0, "subraces": {"Plainsfolk": 45.0, "Abanasinian": 45.0, "Solamnic": 10.0}},
|
||||||
"Half-Elf": {"chance": 8.0, "subraces": {"Qualinesti": 100.0}},
|
"Half-Elf": {"chance": 8.0, "subraces": {"Qualinesti": 100.0}},
|
||||||
|
|
@ -548,8 +512,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"solamnia": {
|
"solamnia": {
|
||||||
"aliases": ["Solamnia", "Palanthas", "Vingaard", "Kalaman",
|
"aliases": ["Solamnia", "Sancrist", "Knights of Solamnia", "Solamnic Plains"],
|
||||||
"Sancrist", "Knights of Solamnia", "Solamnic Plains"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 82.0, "subraces": {"Solamnic": 80.0, "Abanasinian": 12.0, "Plainsfolk": 8.0}},
|
"Human": {"chance": 82.0, "subraces": {"Solamnic": 80.0, "Abanasinian": 12.0, "Plainsfolk": 8.0}},
|
||||||
"Dwarf": {"chance": 5.0, "subraces": {"Hylar": 60.0, "Neidar": 40.0}},
|
"Dwarf": {"chance": 5.0, "subraces": {"Hylar": 60.0, "Neidar": 40.0}},
|
||||||
|
|
@ -561,7 +524,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"silvanesti": {
|
"silvanesti": {
|
||||||
"aliases": ["Silvanesti", "Silvanost", "Silvamori", "Elven Home"],
|
"aliases": ["Silvanesti", "Elven Home"],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Elf": {"chance": 90.0, "subraces": {"Silvanesti": 90.0, "Kagonesti": 10.0}},
|
"Elf": {"chance": 90.0, "subraces": {"Silvanesti": 90.0, "Kagonesti": 10.0}},
|
||||||
"Half-Elf": {"chance": 6.0, "subraces": {"Silvanesti": 100.0}},
|
"Half-Elf": {"chance": 6.0, "subraces": {"Silvanesti": 100.0}},
|
||||||
|
|
@ -570,7 +533,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"qualinesti": {
|
"qualinesti": {
|
||||||
"aliases": ["Qualinesti", "Qualinost", "Pax Tharkas bound"],
|
"aliases": ["Qualinesti", "Pax Tharkas bound"],
|
||||||
"chances": {
|
"chances": {
|
||||||
"Elf": {"chance": 85.0, "subraces": {"Qualinesti": 85.0, "Kagonesti": 15.0}},
|
"Elf": {"chance": 85.0, "subraces": {"Qualinesti": 85.0, "Kagonesti": 15.0}},
|
||||||
"Half-Elf": {"chance": 8.0, "subraces": {"Qualinesti": 100.0}},
|
"Half-Elf": {"chance": 8.0, "subraces": {"Qualinesti": 100.0}},
|
||||||
|
|
@ -580,8 +543,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"thorbardin": {
|
"thorbardin": {
|
||||||
"aliases": ["Thorbardin", "Mount Cloudseeker", "Hylar Halls",
|
"aliases": ["Thorbardin", "Mount Cloudseeker", "Hylar Halls", "Kingdom of Dwarves"],
|
||||||
"Kingdom of Dwarves", "Zhakar"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Dwarf": {"chance": 88.0, "subraces": {"Hylar": 40.0, "Daewar": 25.0, "Klar": 15.0, "Theiwar": 15.0, "Daergar": 5.0}},
|
"Dwarf": {"chance": 88.0, "subraces": {"Hylar": 40.0, "Daewar": 25.0, "Klar": 15.0, "Theiwar": 15.0, "Daergar": 5.0}},
|
||||||
"Gnome": {"chance": 6.0, "subraces": {"Tinker": 100.0}},
|
"Gnome": {"chance": 6.0, "subraces": {"Tinker": 100.0}},
|
||||||
|
|
@ -604,8 +566,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"goodlund_and_balifor": {
|
"goodlund_and_balifor": {
|
||||||
"aliases": ["Goodlund", "Balifor", "Kendermore", "Port Balifor",
|
"aliases": ["Goodlund", "Balifor", "Flotsam bound", "Kenderhome"],
|
||||||
"Flotsam bound", "Kenderhome"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Kender": {"chance": 62.0},
|
"Kender": {"chance": 62.0},
|
||||||
"Human": {"chance": 22.0, "subraces": {"Plainsfolk": 60.0, "Abanasinian": 25.0, "Solamnic": 15.0}},
|
"Human": {"chance": 22.0, "subraces": {"Plainsfolk": 60.0, "Abanasinian": 25.0, "Solamnic": 15.0}},
|
||||||
|
|
@ -629,8 +590,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"neraka_and_taman_busuk": {
|
"neraka_and_taman_busuk": {
|
||||||
"aliases": ["Neraka", "Taman Busuk", "Sanction", "Dargaard",
|
"aliases": ["Neraka", "Taman Busuk", "Dargaard", "Estwilde", "Dargaard Keep bound"],
|
||||||
"Estwilde", "Dargaard Keep bound"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 60.0, "subraces": {"Solamnic": 40.0, "Plainsfolk": 35.0, "Abanasinian": 25.0}},
|
"Human": {"chance": 60.0, "subraces": {"Solamnic": 40.0, "Plainsfolk": 35.0, "Abanasinian": 25.0}},
|
||||||
"Half-Ogre": {"chance": 14.0},
|
"Half-Ogre": {"chance": 14.0},
|
||||||
|
|
@ -643,8 +603,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"nordmaar_and_khur": {
|
"nordmaar_and_khur": {
|
||||||
"aliases": ["Nordmaar", "Khur", "North Keep", "Willik",
|
"aliases": ["Nordmaar", "Khur", "Khurish nomads"],
|
||||||
"Wendle", "Kernaghan", "Khurish nomads"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 78.0, "subraces": {"Plainsfolk": 55.0, "Abanasinian": 25.0, "Solamnic": 20.0}},
|
"Human": {"chance": 78.0, "subraces": {"Plainsfolk": 55.0, "Abanasinian": 25.0, "Solamnic": 20.0}},
|
||||||
"Half-Elf": {"chance": 6.0, "subraces": {"Kagonesti": 100.0}},
|
"Half-Elf": {"chance": 6.0, "subraces": {"Kagonesti": 100.0}},
|
||||||
|
|
@ -659,8 +618,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
|
|
||||||
"Oerth": {
|
"Oerth": {
|
||||||
"greyhawk_city": {
|
"greyhawk_city": {
|
||||||
"aliases": ["Greyhawk", "City of Greyhawk", "Free City of Greyhawk",
|
"aliases": ["Free City of Greyhawk", "Gem of Flanaess"],
|
||||||
"Gem of Flanaess"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 66.0, "subraces": {"Oeridian": 40.0, "Suel": 25.0, "Flan": 20.0, "Baklunish": 15.0}},
|
"Human": {"chance": 66.0, "subraces": {"Oeridian": 40.0, "Suel": 25.0, "Flan": 20.0, "Baklunish": 15.0}},
|
||||||
"Half-Elf": {"chance": 8.0, "subraces": {"Gray": 60.0, "High": 40.0}},
|
"Half-Elf": {"chance": 8.0, "subraces": {"Gray": 60.0, "High": 40.0}},
|
||||||
|
|
@ -673,8 +631,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"keoland_and_sheldomar": {
|
"keoland_and_sheldomar": {
|
||||||
"aliases": ["Keoland", "Sheldomar Valley", "Niole Dra",
|
"aliases": ["Keoland", "Sheldomar Valley", "Gran March", "Bissel", "Ulek", "Yeomanry"],
|
||||||
"Gran March", "Bissel", "Ulek", "Yeomanry"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 70.0, "subraces": {"Suel": 45.0, "Oeridian": 40.0, "Flan": 15.0}},
|
"Human": {"chance": 70.0, "subraces": {"Suel": 45.0, "Oeridian": 40.0, "Flan": 15.0}},
|
||||||
"Dwarf": {"chance": 9.0, "subraces": {"Hill": 55.0, "Mountain": 45.0}},
|
"Dwarf": {"chance": 9.0, "subraces": {"Hill": 55.0, "Mountain": 45.0}},
|
||||||
|
|
@ -686,8 +643,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"furyondy_and_shield_lands": {
|
"furyondy_and_shield_lands": {
|
||||||
"aliases": ["Furyondy", "Chendl", "Shield Lands", "Veluna",
|
"aliases": ["Furyondy", "Shield Lands", "Veluna"],
|
||||||
"Dyvers", "Willip"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 74.0, "subraces": {"Oeridian": 55.0, "Suel": 25.0, "Flan": 20.0}},
|
"Human": {"chance": 74.0, "subraces": {"Oeridian": 55.0, "Suel": 25.0, "Flan": 20.0}},
|
||||||
"Dwarf": {"chance": 7.0, "subraces": {"Hill": 60.0, "Mountain": 40.0}},
|
"Dwarf": {"chance": 7.0, "subraces": {"Hill": 60.0, "Mountain": 40.0}},
|
||||||
|
|
@ -699,8 +655,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"pomarj_and_wild_coast": {
|
"pomarj_and_wild_coast": {
|
||||||
"aliases": ["Pomarj", "Wild Coast", "Highport", "Suderham",
|
"aliases": ["Pomarj", "Wild Coast", "Slave Lords bound"],
|
||||||
"Slave Lords bound"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 40.0, "subraces": {"Oeridian": 40.0, "Suel": 35.0, "Flan": 25.0}},
|
"Human": {"chance": 40.0, "subraces": {"Oeridian": 40.0, "Suel": 35.0, "Flan": 25.0}},
|
||||||
"Orc": {"chance": 20.0},
|
"Orc": {"chance": 20.0},
|
||||||
|
|
@ -727,8 +682,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
|
|
||||||
"great_kingdom_of_aerdy": {
|
"great_kingdom_of_aerdy": {
|
||||||
"aliases": ["Great Kingdom", "Aerdy", "Rauxes", "North Province",
|
"aliases": ["Great Kingdom", "Aerdy", "North Province", "South Province", "Ahlissa", "North Kingdom"],
|
||||||
"South Province", "Ahlissa", "North Kingdom", "Rel Astra"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 74.0, "subraces": {"Oeridian": 65.0, "Suel": 20.0, "Flan": 15.0}},
|
"Human": {"chance": 74.0, "subraces": {"Oeridian": 65.0, "Suel": 20.0, "Flan": 15.0}},
|
||||||
"Dwarf": {"chance": 7.0, "subraces": {"Hill": 55.0, "Mountain": 45.0}},
|
"Dwarf": {"chance": 7.0, "subraces": {"Hill": 55.0, "Mountain": 45.0}},
|
||||||
|
|
@ -741,8 +695,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"nyrond_and_urnsts": {
|
"nyrond_and_urnsts": {
|
||||||
"aliases": ["Nyrond", "Rel Mord", "County of Urnst", "Duchy of Urnst",
|
"aliases": ["Nyrond", "County of Urnst", "Duchy of Urnst", "Almor", "Innspa bound"],
|
||||||
"Womtham", "Almor", "Innspa bound"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 72.0, "subraces": {"Oeridian": 50.0, "Suel": 30.0, "Flan": 20.0}},
|
"Human": {"chance": 72.0, "subraces": {"Oeridian": 50.0, "Suel": 30.0, "Flan": 20.0}},
|
||||||
"Dwarf": {"chance": 8.0, "subraces": {"Hill": 60.0, "Mountain": 40.0}},
|
"Dwarf": {"chance": 8.0, "subraces": {"Hill": 60.0, "Mountain": 40.0}},
|
||||||
|
|
@ -754,8 +707,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"baklunish_west": {
|
"baklunish_west": {
|
||||||
"aliases": ["Baklunish West", "Ket", "Tusmit", "Ekbir", "Zeif",
|
"aliases": ["Baklunish West", "Ket", "Tusmit", "Ekbir", "Zeif", "Ull", "Paynims", "Plains of Paynims"],
|
||||||
"Ull", "Paynims", "Plains of Paynims", "Lopolla"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 82.0, "subraces": {"Baklunish": 80.0, "Oeridian": 12.0, "Suel": 8.0}},
|
"Human": {"chance": 82.0, "subraces": {"Baklunish": 80.0, "Oeridian": 12.0, "Suel": 8.0}},
|
||||||
"Half-Orc": {"chance": 5.0},
|
"Half-Orc": {"chance": 5.0},
|
||||||
|
|
@ -767,8 +719,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"iuz_and_horned_society": {
|
"iuz_and_horned_society": {
|
||||||
"aliases": ["Iuz", "Empire of Iuz", "Horned Society", "Molag",
|
"aliases": ["Iuz", "Empire of Iuz", "Horned Society", "Bandit lands of Iuz", "Land of Iuz"],
|
||||||
"Dorakaa", "Bandit lands of Iuz", "Land of Iuz"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 50.0, "subraces": {"Flan": 45.0, "Oeridian": 35.0, "Baklunish": 20.0}},
|
"Human": {"chance": 50.0, "subraces": {"Flan": 45.0, "Oeridian": 35.0, "Baklunish": 20.0}},
|
||||||
"Orc": {"chance": 16.0},
|
"Orc": {"chance": 16.0},
|
||||||
|
|
@ -781,8 +732,7 @@ REGIONAL_OVERWRITES: dict = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"sea_barons_and_isles": {
|
"sea_barons_and_isles": {
|
||||||
"aliases": ["Sea Barons", "Lordship of Isles", "Asperdi",
|
"aliases": ["Sea Barons", "Lordship of Isles", "Aerdi Sea", "Spindrift Isles", "Densac Gulf"],
|
||||||
"Duxchan", "Aerdi Sea", "Spindrift Isles", "Densac Gulf"],
|
|
||||||
"chances": {
|
"chances": {
|
||||||
"Human": {"chance": 70.0, "subraces": {"Oeridian": 40.0, "Suel": 35.0, "Flan": 25.0}},
|
"Human": {"chance": 70.0, "subraces": {"Oeridian": 40.0, "Suel": 35.0, "Flan": 25.0}},
|
||||||
"Half-Orc": {"chance": 8.0},
|
"Half-Orc": {"chance": 8.0},
|
||||||
|
|
@ -923,10 +873,77 @@ PLANAR_OVERWRITES: dict = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# ─── Индекс алиасов для symspellpy ───────────────────────────────────────────
|
# ─── Населенные пункты ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
# Структура: Мир -> Регион -> [Список населенных пунктов]
|
||||||
|
SETTLEMENTS_OVERWRITES: dict = {
|
||||||
|
"Toril": {
|
||||||
|
"sword_coast_north": ["Luskan", "Neverwinter", "Port Llast", "Mirabar"],
|
||||||
|
"silver_marches": ["Silverymoon", "Sundabar", "Mithral Hall", "Everlund", "Citadel Adbar"],
|
||||||
|
"western_heartlands": ["Elturel", "Beregost", "Candlekeep", "Scornubel"],
|
||||||
|
"waterdeep": ["Waterdeep", "City of Splendors"],
|
||||||
|
"baldurs_gate": ["Baldur's Gate", "Gate", "Baldurs Gate"],
|
||||||
|
"cormyr": ["Suzail", "Marsember", "Arabel", "Wheloon"],
|
||||||
|
"amn": ["Athkatla", "Crimmor", "Eshpurta", "Purskul", "Trademeet"],
|
||||||
|
"tethyr": ["Zazesspur", "Darromar", "Myratma", "Ithmong", "Saradush", "Riatavin"],
|
||||||
|
"calimshan": ["Calimport", "Memnon", "Almraiven", "Keltar"],
|
||||||
|
"chult": ["Port Nyanzaru", "Mezro", "Omu"],
|
||||||
|
"unapproachable_east": ["Bezantur", "Two Stars", "Phsant", "Milvarune"],
|
||||||
|
"rashemen": ["Mulsantir", "Immilmar", "Urling", "Citadel Rashemar", "Mulptan"],
|
||||||
|
"thay": ["Eltabbar", "Tyraturos", "Amruthar", "Pyarados", "Surthay", "Nethjet"],
|
||||||
|
"underdark": ["Menzoberranzan", "Blingdenstone", "Gracklstugh", "Sshamath", "Ched Nasad"],
|
||||||
|
"moonsea": ["Zhentil Keep", "Melvaunt", "Hillsfar", "Mulmaster", "Phlan", "Thentia"],
|
||||||
|
"dalelands": ["Shadowdale", "Mistledale", "Deepingdale", "Battledale", "Daggerdale", "Archendale"],
|
||||||
|
"sembia": ["Selgaunt", "Ordulin", "Saerloon", "Yhaunn", "Daerlun", "Urmlaspyr"],
|
||||||
|
"vast": ["Ravens Bluff", "Tantras", "Calaunt", "Procampur", "Sarbreen"],
|
||||||
|
"vilhon_reach": ["Hlondeth", "Alaghon", "Arrabar", "Sespech", "Nimpeth"],
|
||||||
|
"old_empires": ["Skuld", "Messemprar", "Cimbar", "Soorenar"],
|
||||||
|
"icewind_dale": ["Ten Towns", "Bryn Shander", "Targos", "Lonelywood", "Easthaven", "Termalaine", "Caer-Dineval", "Caer-Konig", "Dougan's Hole", "Good Mead"],
|
||||||
|
"evermeet": ["Leuthilspar"],
|
||||||
|
"myth_drannor": ["Myth Drannor", "Semberholme", "Tangled Trees"],
|
||||||
|
"moonshae_isles": ["Callidyrr", "Corwell"],
|
||||||
|
"impiltur_and_bloodstone": ["Lyrabar", "Heliogabalus"],
|
||||||
|
"anauroch": ["Shade Enclave"],
|
||||||
|
"aglarond": ["Velprintalar", "Yeshelmaar", "Emmech"],
|
||||||
|
"lantan": ["Sambar", "Adaerglass"],
|
||||||
|
"sea_of_fallen_stars": ["Immurk's Hold"],
|
||||||
|
"sword_coast_central": ["Daggerford", "Secomber", "Boareskyr Bridge"],
|
||||||
|
"maztica": ["Helmsport", "Ulatos"],
|
||||||
|
"tashalar_and_shaar": ["Tashluta", "Sheirtalar"],
|
||||||
|
"nimbral": ["Cathtyr"],
|
||||||
|
},
|
||||||
|
"Krynn": {
|
||||||
|
"abanasinia": ["Solace", "Haven", "Que-Shu"],
|
||||||
|
"solamnia": ["Palanthas", "Vingaard", "Kalaman"],
|
||||||
|
"silvanesti": ["Silvanost", "Silvamori"],
|
||||||
|
"qualinesti": ["Qualinost"],
|
||||||
|
"thorbardin": ["Zhakar"],
|
||||||
|
"neraka_and_taman_busuk": ["Sanction"],
|
||||||
|
"nordmaar_and_khur": ["North Keep", "Willik", "Wendle", "Kernaghan"],
|
||||||
|
"goodlund_and_balifor": ["Kendermore", "Port Balifor"],
|
||||||
|
|
||||||
|
},
|
||||||
|
"Oerth": {
|
||||||
|
"greyhawk_city": ["Greyhawk", "City of Greyhawk"],
|
||||||
|
"keoland_and_sheldomar": ["Niole Dra"],
|
||||||
|
"furyondy_and_shield_lands": ["Chendl", "Dyvers", "Willip"],
|
||||||
|
"pomarj_and_wild_coast": ["Highport", "Suderham"],
|
||||||
|
"great_kingdom_of_aerdy": ["Rauxes", "Rel Astra"],
|
||||||
|
"nyrond_and_urnsts": ["Rel Mord", "Womtham"],
|
||||||
|
"baklunish_west": ["Lopolla"],
|
||||||
|
"iuz_and_horned_society": ["Molag", "Dorakaa"],
|
||||||
|
"sea_barons_and_isles": ["Asperdi", "Duxchan"],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ─── Индекс алиасов и symspellpy ───────────────────────────────────────────
|
||||||
|
|
||||||
|
import os
|
||||||
|
import symspellpy
|
||||||
|
|
||||||
_ARTICLES = {"the", "a", "an", "of", "and"}
|
_ARTICLES = {"the", "a", "an", "of", "and"}
|
||||||
|
|
||||||
|
# ----------------------------------------------- Core Dictionary Logic ------------------------------------------------------------
|
||||||
|
|
||||||
def _clean(text: str) -> str:
|
def _clean(text: str) -> str:
|
||||||
"""Нижний регистр, удаление артиклей и апострофов, схлопывание пробелов."""
|
"""Нижний регистр, удаление артиклей и апострофов, схлопывание пробелов."""
|
||||||
|
|
@ -934,13 +951,34 @@ def _clean(text: str) -> str:
|
||||||
words = [w for w in text.split() if w not in _ARTICLES]
|
words = [w for w in text.split() if w not in _ARTICLES]
|
||||||
return " ".join(words)
|
return " ".join(words)
|
||||||
|
|
||||||
|
def _merge_settlements():
|
||||||
|
"""Вливает SETTLEMENTS_OVERWRITES в REGIONAL_OVERWRITES и создает плоский список."""
|
||||||
|
world_settlements = {}
|
||||||
|
|
||||||
|
for world_name, regions in SETTLEMENTS_OVERWRITES.items():
|
||||||
|
world_settlements[world_name] = []
|
||||||
|
|
||||||
|
if world_name not in REGIONAL_OVERWRITES:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for region_key, settlements in regions.items():
|
||||||
|
if region_key in REGIONAL_OVERWRITES[world_name]:
|
||||||
|
# Вливаем нас. пункты в aliases региона
|
||||||
|
REGIONAL_OVERWRITES[world_name][region_key]["aliases"].extend(settlements)
|
||||||
|
|
||||||
|
# Формируем плоский список
|
||||||
|
world_settlements[world_name].extend(settlements)
|
||||||
|
|
||||||
|
return world_settlements
|
||||||
|
|
||||||
|
WORLD_SETTLEMENTS = _merge_settlements()
|
||||||
|
|
||||||
|
|
||||||
def _build_alias_index() -> tuple[dict, dict]:
|
def _build_alias_index() -> tuple[dict, dict]:
|
||||||
"""
|
"""
|
||||||
Возвращает два индекса:
|
Возвращает два индекса:
|
||||||
world_index: {"toril": "Toril", "avernus": "lower_planes_le", ...}
|
world_index: {"toril": "Toril", "avernus": "lower_planes_le", ...}
|
||||||
region_index: {(scope, cleaned_alias): region_key}
|
region_index: {(scope, cleaned_alias): region_key}
|
||||||
scope — имя мира ("Toril") либо "__planes__".
|
|
||||||
"""
|
"""
|
||||||
world_index: dict[str, str] = {}
|
world_index: dict[str, str] = {}
|
||||||
region_index: dict[tuple[str, str], str] = {}
|
region_index: dict[tuple[str, str], str] = {}
|
||||||
|
|
@ -952,7 +990,6 @@ def _build_alias_index() -> tuple[dict, dict]:
|
||||||
region_index[(world_name, _clean(alias))] = region_key
|
region_index[(world_name, _clean(alias))] = region_key
|
||||||
|
|
||||||
for plane_key, data in PLANAR_OVERWRITES.items():
|
for plane_key, data in PLANAR_OVERWRITES.items():
|
||||||
# Планы адресуются и как world, и как region
|
|
||||||
for alias in data["aliases"]:
|
for alias in data["aliases"]:
|
||||||
world_index[_clean(alias)] = plane_key
|
world_index[_clean(alias)] = plane_key
|
||||||
region_index[("__planes__", _clean(alias))] = plane_key
|
region_index[("__planes__", _clean(alias))] = plane_key
|
||||||
|
|
@ -960,5 +997,46 @@ def _build_alias_index() -> tuple[dict, dict]:
|
||||||
|
|
||||||
return world_index, region_index
|
return world_index, region_index
|
||||||
|
|
||||||
|
|
||||||
WORLD_INDEX, REGION_INDEX = _build_alias_index()
|
WORLD_INDEX, REGION_INDEX = _build_alias_index()
|
||||||
|
|
||||||
|
|
||||||
|
# ----------------------------------------------- SymSpell Logic ------------------------------------------------------------
|
||||||
|
|
||||||
|
def _init_symspell_for_worlds():
|
||||||
|
"""Создает экземпляры SymSpell для каждого мира на основе плоского списка населенных пунктов."""
|
||||||
|
symspells = {}
|
||||||
|
for world, settlements in WORLD_SETTLEMENTS.items():
|
||||||
|
sym = symspellpy.SymSpell(max_dictionary_edit_distance=2, prefix_length=7)
|
||||||
|
for settlement in settlements:
|
||||||
|
# Добавляем в словарь оригинальное название и очищенное
|
||||||
|
clean_name = _clean(settlement)
|
||||||
|
if clean_name:
|
||||||
|
sym.create_dictionary_entry(clean_name, 1)
|
||||||
|
symspells[world] = sym
|
||||||
|
return symspells
|
||||||
|
|
||||||
|
WORLD_SYMSPELLS = _init_symspell_for_worlds()
|
||||||
|
|
||||||
|
|
||||||
|
def match_location(world: str, location: str) -> str:
|
||||||
|
"""
|
||||||
|
Сопоставляет введенную локацию со словарем населенных пунктов мира.
|
||||||
|
Возвращает скорректированное название или оригинальное, если совпадений нет.
|
||||||
|
"""
|
||||||
|
world_key = world.strip().title()
|
||||||
|
if world_key not in WORLD_SYMSPELLS:
|
||||||
|
return location
|
||||||
|
|
||||||
|
clean_loc = _clean(location)
|
||||||
|
sym = WORLD_SYMSPELLS[world_key]
|
||||||
|
|
||||||
|
# Ищем исправления с максимальной дистанцией 2
|
||||||
|
suggestions = sym.lookup(clean_loc, symspellpy.Verbosity.CLOSEST, max_edit_distance=2)
|
||||||
|
if suggestions:
|
||||||
|
best_match_clean = suggestions[0].term
|
||||||
|
# Ищем оригинальное написание по очищенному ключу
|
||||||
|
for settlement in WORLD_SETTLEMENTS.get(world_key, []):
|
||||||
|
if _clean(settlement) == best_match_clean:
|
||||||
|
return settlement
|
||||||
|
|
||||||
|
return location
|
||||||
|
|
|
||||||
60
generate_npc/tests/test_generate_npc.py
Normal file
60
generate_npc/tests/test_generate_npc.py
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
scripts_path = Path(__file__).resolve().parent.parent.parent
|
||||||
|
if str(scripts_path) not in sys.path:
|
||||||
|
sys.path.insert(0, str(scripts_path))
|
||||||
|
|
||||||
|
npc_path = Path(__file__).resolve().parent.parent
|
||||||
|
if str(npc_path) not in sys.path:
|
||||||
|
sys.path.insert(0, str(npc_path))
|
||||||
|
|
||||||
|
from gen_npc import generate_npc
|
||||||
|
|
||||||
|
# ----------------------------------------------- Тесты Генерации NPC ------------------------------------------------------------
|
||||||
|
|
||||||
|
def test_generate_npc_default():
|
||||||
|
"""
|
||||||
|
Проверяет базовую генерацию NPC с пустыми ограничениями.
|
||||||
|
Убеждается, что возвращается непустая строка с результатом.
|
||||||
|
"""
|
||||||
|
result = generate_npc("тест", [{}])
|
||||||
|
assert isinstance(result, str)
|
||||||
|
assert len(result) > 0
|
||||||
|
assert "lvl 1" in result
|
||||||
|
|
||||||
|
def test_generate_npc_with_region():
|
||||||
|
"""
|
||||||
|
Проверяет генерацию NPC с указанием прайм-мира и конкретного региона.
|
||||||
|
Проверяет срабатывание региональных перезаписей.
|
||||||
|
"""
|
||||||
|
req = {
|
||||||
|
"world": "Toril",
|
||||||
|
"region": "Waterdeep",
|
||||||
|
"count": 2,
|
||||||
|
"level": 3
|
||||||
|
}
|
||||||
|
result = generate_npc("тест", [req])
|
||||||
|
assert isinstance(result, str)
|
||||||
|
assert "lvl 3" in result
|
||||||
|
assert "#2 —" in result
|
||||||
|
|
||||||
|
def test_generate_npc_planar():
|
||||||
|
"""
|
||||||
|
Проверяет генерацию NPC для планарных миров (без региона).
|
||||||
|
Гарантирует корректную маршрутизацию к планарным шансам.
|
||||||
|
"""
|
||||||
|
req = {
|
||||||
|
"world": "lower_planes_le",
|
||||||
|
"count": 1,
|
||||||
|
"level": 5
|
||||||
|
}
|
||||||
|
result = generate_npc("тест", [req])
|
||||||
|
assert isinstance(result, str)
|
||||||
|
assert "lvl 5" in result
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_generate_npc_default()
|
||||||
|
test_generate_npc_with_region()
|
||||||
|
test_generate_npc_planar()
|
||||||
|
print("Все тесты generate_npc успешно пройдены!")
|
||||||
45
generate_npc/tests/test_regions.py
Normal file
45
generate_npc/tests/test_regions.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Добавляем родительскую папку в sys.path для импорта
|
||||||
|
scripts_path = Path(__file__).resolve().parent.parent
|
||||||
|
if str(scripts_path) not in sys.path:
|
||||||
|
sys.path.insert(0, str(scripts_path))
|
||||||
|
|
||||||
|
from regions import match_location
|
||||||
|
|
||||||
|
# ----------------------------------------------- Тесты Fuzzy Matcher ------------------------------------------------------------
|
||||||
|
|
||||||
|
def test_match_exact():
|
||||||
|
"""
|
||||||
|
Проверяет точное совпадение локации.
|
||||||
|
"""
|
||||||
|
assert match_location("Toril", "Waterdeep") == "Waterdeep"
|
||||||
|
assert match_location("Toril", "Neverwinter") == "Neverwinter"
|
||||||
|
|
||||||
|
def test_match_fuzzy():
|
||||||
|
"""
|
||||||
|
Проверяет коррекцию опечаток (fuzzy matching).
|
||||||
|
"""
|
||||||
|
assert match_location("Toril", "Watterdeep") == "Waterdeep"
|
||||||
|
assert match_location("Toril", "Neverwintar") == "Neverwinter"
|
||||||
|
assert match_location("Toril", "baldur gate") == "Baldur's Gate"
|
||||||
|
|
||||||
|
def test_match_unknown_world():
|
||||||
|
"""
|
||||||
|
Проверяет поведение при передаче неизвестного мира.
|
||||||
|
"""
|
||||||
|
assert match_location("Unknown", "Waterdeep") == "Waterdeep"
|
||||||
|
|
||||||
|
def test_match_no_correction_needed():
|
||||||
|
"""
|
||||||
|
Проверяет поведение для локаций, которых нет в словаре.
|
||||||
|
"""
|
||||||
|
assert match_location("Toril", "Some Random City") == "Some Random City"
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_match_exact()
|
||||||
|
test_match_fuzzy()
|
||||||
|
test_match_unknown_world()
|
||||||
|
test_match_no_correction_needed()
|
||||||
|
print("Все тесты match_location успешно пройдены!")
|
||||||
|
|
@ -1,2 +1,3 @@
|
||||||
PyYaml
|
PyYaml
|
||||||
pathspec
|
pathspec
|
||||||
|
symspellpy # для тестов
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user