""" hooks_data.py — данные о хуках и весах типов встреч. Содержит: - ENCOUNTER_TYPE_WEIGHTS: веса типов встреч по биому. - HOOK_WEIGHTS: веса хуков внутри каждого типа (универсальные). - HOOKS: схема субъектов для каждого хука. """ # ────────────────────────────────────────────────────────────────────────────── # Веса ТИПОВ встреч по биому/плану. # Добавление нового плана = одна новая строка здесь. # ────────────────────────────────────────────────────────────────────────────── ENCOUNTER_TYPE_WEIGHTS: dict[str, dict[str, int]] = { "arctic": {"PvP": 50, "PvE": 25, "PvX": 20, "PvSelf": 5}, "coastal": {"PvP": 45, "PvE": 20, "PvX": 30, "PvSelf": 5}, # 10 "desert": {"PvP": 45, "PvE": 30, "PvX": 20, "PvSelf": 5}, # 10 "forest": {"PvP": 50, "PvE": 20, "PvX": 25, "PvSelf": 5}, # 10 "grassland": {"PvP": 50, "PvE": 20, "PvX": 25, "PvSelf": 5}, # 10 "hill": {"PvP": 50, "PvE": 20, "PvX": 25, "PvSelf": 5}, # 10 "mountain": {"PvP": 40, "PvE": 30, "PvX": 25, "PvSelf": 5}, "swamp": {"PvP": 35, "PvE": 25, "PvX": 35, "PvSelf": 5}, "underdark": {"PvP": 50, "PvE": 15, "PvX": 30, "PvSelf": 5}, "underwater": {"PvP": 30, "PvE": 35, "PvX": 30, "PvSelf": 5}, "urban": {"PvP": 40, "PvE": 15, "PvX": 25, "PvSelf": 20}, # 45 # Планы — новые строки: "nine_hells": {"PvP": 55, "PvE": 25, "PvX": 15, "PvSelf": 5}, "astral_sea": {"PvP": 20, "PvE": 40, "PvX": 35, "PvSelf": 5}, "feywild": {"PvP": 35, "PvE": 25, "PvX": 30, "PvSelf": 10}, # 25 "plane_of_air": {"PvP": 35, "PvE": 30, "PvX": 30, "PvSelf": 5}, "plane_of_earth": {"PvP": 40, "PvE": 30, "PvX": 25, "PvSelf": 5}, "plane_of_fire": {"PvP": 45, "PvE": 25, "PvX": 25, "PvSelf": 5}, "plane_of_water": {"PvP": 35, "PvE": 30, "PvX": 30, "PvSelf": 5}, } # ────────────────────────────────────────────────────────────────────────────── # Веса ХУКОВ внутри каждого типа. # Универсальны — не зависят от биома или плана. # ────────────────────────────────────────────────────────────────────────────── HOOK_WEIGHTS: dict[str, dict[str, int]] = { "PvP": { "The Hunt": 18, # Охота, засада, набег "The Routine": 20, # Патруль, миграция, фуражирование "The Claim": 15, # Охрана территории/чека "The Social Event": 12, # Процессия, ритуал, состязание "The Interaction": 12, # Поиск контакта (торговля, помощь) "The Internal Conflict": 10, # Две группы дерутся "The Shadow": 7, # Скрытое наблюдение, шпионаж "The Chase": 5, "The Challenge": 1, }, "PvE": { "The Sudden Crisis": 28, # Сбежавшие животные, пожар, телега "The Obstacle": 25, # Блок пути (завал, айсберг, водоросли) "The Hazard": 18, # Опасная зона (водоворот, гейзер) "The Anomaly": 17, # Дикая магия, корабль-призрак "The Weather": 12, }, "PvX": { "The Landmark": 20, # Пустые руины, статуя, кораблекрушение "The Remnant": 25, # Трупы, следы, обломки "The Cache": 25, # Сокровище, жемчуг, магические ягоды "The Lair": 20, # Обитаемая пещера, логово "The Omen": 10, # Звуки, предзнаменования, эльфийская песня }, "PvSelf": { "The Plea": 30, # Выживший в воде, сирота "The Moral Crossroads": 35, # Задиры, произвол стражи, призыв "The Temptation": 22, # Теневая сделка, бесхозный лут "The Betrayal": 13, }, } # ────────────────────────────────────────────────────────────────────────────── # Схема субъектов для каждого хука. # # subject_sources — список слотов субъектов. Каждый слот: # source: "creatures" → get_monsters_or_animals() # "npc" → get_npc() # count: строка с dice-нотацией или "1" # role: роль в сцене (для нейросети): "primary", "aggressor", # "defender", "victim", "bystander" # optional: если True — слот появляется с вероятностью 50% # # latent_threat: True → существа могут появиться как следствие # провала броска Surprise (решается в encounter_generator) # ────────────────────────────────────────────────────────────────────────────── HOOKS: dict[str, dict[str, dict]] = { "PvP": { "The Hunt": { "description": "Целенаправленная атака, засада или поиск добычи (хищники, пираты, бандиты).", "subject_sources": [ {"source": "creatures", "count": "1d4+1", "role": "aggressor"}, ], "latent_threat": False, }, "The Routine": { "description": "Существа заняты своей жизнью: миграция, патруль, фуражирование, прогулка.", "subject_sources": [ {"source": "creatures", "count": "1d4+1", "role": "primary"}, ], "latent_threat": False, }, "The Claim": { "description": "Существа активно охраняют логово, проход, предмет или территорию.", "subject_sources": [ {"source": "creatures", "count": "1d4+1", "role": "defender"}, ], "latent_threat": False, }, "The Social Event": { "description": ( "Массовое или социальное действие существ. " "Мирные варианты: процессия, ярмарка, состязание, представление, " "глашатай зачитывает указ, свадьба гоблинов. " "Тёмные варианты: культисты призывают демона через ритуал жертвоприношения, " "кобольды пытаются оживить каменного идола, " "друиды проводят обряд плодородия — прервать можно, но опасно." ), "subject_sources": [ {"source": "npc", "count": "1d4+2", "role": "bystander"}, ], "latent_threat": False, }, "The Internal Conflict": { "description": "Две группы существ конфликтуют между собой: бунт, драка за добычу, политический протест/митинг, разборки между бандами, хищник - напавший на патруль.", "subject_sources": [ {"source": "creatures", "count": "1d4", "role": "aggressor"}, {"source": "creatures", "count": "1d4", "role": "defender"}, ], "latent_threat": False, }, "The Shadow": { "description": "Существа скрытно наблюдают, крадутся следом, пытаются обокрасть кого-то или совершают тайное действие.", "subject_sources": [ {"source": "creatures", "count": "1d3", "role": "primary"}, ], "latent_threat": False, }, "The Interaction": { "description": ( "Существа или NPC инициативно ищут контакта с героями. " "Диапазон от мирного (торговцы, проводники, пьяный с байками) " "до условного (медуза предлагает пропуск в обмен на историю, " "хаг торгуется за услугу, дьявол — за душу, " "культист вербует в орден)." ), "subject_sources": [ {"source": "npc", "count": "1d3", "role": "primary"}, ], "latent_threat": False, }, "The Chase": { "description": ( "Динамичное преследование или гонка, требующие проверок навыков, " "а не прямого боя. " "Примеры: конная погоня за курьером с секретным письмом, " "скачки на грифонах над городом, гонки на лодках по подземной реке, " "беглый преступник петляет по рыночным рядам, " "гарпии преследуют торговый корабль." ), "subject_sources": [ {"source": "creatures", "count": "1d3", "role": "aggressor"}, {"source": "npc", "count": "1", "role": "victim"}, ], "latent_threat": False, }, "The Challenge": { "description": ( "Прямой вызов на состязание, дуэль или испытание навыков без цели убить. " "Примеры: дворянин требует сатисфакции за оскорбление, варвар вызывает на " "кулачный бой у костра, эльфийский следопыт предлагает пари на точность стрельбы, " "монах вызывает на испытание воли (кто дольше простоит под ледяным водопадом)." ), "subject_sources": [ {"source": "npc", "count": "1", "role": "aggressor"}, {"source": "npc", "count": "1d4", "role": "bystander", "optional": True}, ], "latent_threat": False, }, }, "PvE": { "The Sudden Crisis": { "description": "Динамичная, срочная проблема среды (пожар, сбежавшая телега/животное, обвал, обрушение конструкции, землетрясение, тонущее судно, паника на рынке, т.п.).", "subject_sources": [ {"source": "npc", "count": "1", "role": "victim", "optional": True}, ], "latent_threat": False, }, "The Obstacle": { "description": "Масштабная преграда, блокирующая путь (завал на лесной тропе, айсберг, заросли, пропасть, запертые ворота).", "subject_sources": [], "latent_threat": False, }, "The Hazard": { "description": "Пассивная опасная зона или ловушка (водоворот, гейзер, ядовитые споры, зыбучие пески).", "subject_sources": [], "latent_threat": True, }, "The Anomaly": { "description": "Сложное природное или магическое явление (мираж, корабль-призрак, зона дикой магии, парящие острова, светящиеся туманы, портал).", "subject_sources": [], "latent_threat": True, }, "The Weather": { "description": ( "Экстремальное погодное явление, меняющее условия всей зоны встречи. " "Примеры: внезапная метель обнуляет видимость и замедляет движение, " "пылевая буря на равнине, ураган у побережья, " "кислотный дождь в Nine Hells разъедает снаряжение, " "густой туман скрывает всё дальше 10 футов, " "магическая гроза бьёт молниями случайно." ), "subject_sources": [], "latent_threat": True, # в буре может скрываться хищник }, }, "PvX": { "The Landmark": { "description": ( "Заметный объект инфраструктуры, древности или магии. " "Пассивные: пустые руины, статуя героя, монолит с надписями, " "кораблекрушение, каменный круг. " "Интерактивные (Puzzle): древняя дверь с загадкой на трёх языках, " "магический замок с шифром из созвездий, " "каменная плита с рунами, требующими правильного порядка нажатий, " "зеркало, отражающее иное место." ), "subject_sources": [], "latent_threat": True, }, "The Remnant": { "description": ( "Свидетельства недавних или давних событий. " "Краткосрочные следы: трупы, сломанные повозки, плавающие обломки, " "остатки лагеря, брошенные вещи, сожжённая роща. " "Долгосрочные последствия (Fallout): отравленная река после битвы армий, " "выжженная земля проклятием личей, " "зона некротической энергии — земля мертва уже десять лет, " "пепелище деревни с ловушками мародёров." ), "subject_sources": [], "latent_threat": True, }, "The Cache": { "description": "Находка, имеющая ценность (магическое растение, утерянный груз, схрон, жемчуг, сундук с сокровищами, полезный предмет на тротуаре).", "subject_sources": [], "latent_threat": True, }, "The Lair": { "description": "Место обитания монстров, героев может ждать хозяин дома (грот осьминога, заселенные руины, гнездо грифона, бандитский притон, т.п.).", "subject_sources": [ {"source": "creatures", "count": "1d6", "role": "primary"}, ], "latent_threat": False, }, "The Omen": { "description": ( "Информационный сигнал из среды — от неясного до конкретного. " "Знамения: странная мелодия из тумана, дым трёх цветов на горизонте, " "все птицы разом умолкли, мертвая рыба плывёт по реке вверх. " "Сообщения (Message): послание в бутылке с зашифрованными координатами, " "магический камень с записью голоса мёртвого мага, " "надпись на стене древним языком («они уже внутри»), " "застывший в янтаре свиток с предупреждением." ), "subject_sources": [], "latent_threat": True, }, }, "PvSelf": { "The Plea": { "description": ( "Кто-то молит о помощи или ситуация требует самопожертвования. " "Просьба о действии: выживший на обломках судна, " "раненый рыцарь у дороги, пленник в клетке, " "умоляющий купец («они убьют мою семью»). " "Просьба об отказе (Sacrifice): сломай магический меч — снимешь проклятие с деревни, " "сожги эти записи — они единственное доказательство твоей невиновности, " "потеряй память о прошлом, чтобы пройти через врата богов." ), "subject_sources": [ {"source": "npc", "count": "1", "role": "victim"}, ], "latent_threat": False, }, "The Moral Crossroads": { "description": "Столкновение с явной несправедливостью или злоупотреблением (задиры, произвол стражи или налоговика, несправедливый арест, жестокое обращение с животными, лорд приказывает выдать беглого слугу, т.п.).", "subject_sources": [ {"source": "npc", "count": "1d3+", "role": "aggressor"}, {"source": "npc", "count": "1", "role": "victim"}, ], "latent_threat": False, }, "The Temptation": { "description": "Соблазн получить выгоду сомнительным путем (теневая сделка, бесхозный кошелёк или груз на дороге, возможность украсть у пьяного, забытые в храме деньги, т.п.).", "subject_sources": [ {"source": "npc", "count": "1", "role": "primary", "optional": True}, ], "latent_threat": False, }, "The Betrayal": { "description": ( "Герой обнаруживает, что союзник, друг или заказчик предал его. " "Примеры: контрактник сбежал с авансом и уликами на героев, " "NPC которого спасли — оказывается осведомителем врага, " "заказчик нанимал, зная что посылает на верную смерть, " "проводник ведёт прямо в засаду, " "союзный маг тайно работает на гильдию убийц." ), "subject_sources": [ {"source": "npc", "count": "1", "role": "traitor"}, ], "latent_threat": False, }, }, }