dnd5-scripts/time/set_campaign_time.py

226 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
set_campaign_time.py — изменение игрового времени.
Экспортирует функцию set_campaign_time(debug_description, requests), которую вызывает тул с фронта.
requests — список объектов вида:
{
"mode": "absolute" | "shift", # режим: absolute установка, shift сдвиг (default "shift")
"year": 1492, # при absolute год, при shift сдвиг лет
"month": 1, # при absolute месяц (число 1-12 или русское название), при shift сдвиг месяцев (число)
"day": 1, # при absolute день, при shift сдвиг дней
"hour": 0, # при absolute час, при shift сдвиг часов
}
При mode="absolute" можно передать только часть полей, остальные останутся без изменений.
Поле month при mode="absolute" принимает:
- целое число от 1 до 12
- строку, содержащую число (например "3")
- русское название месяца (регистр не важен):
1: Хаммер
2: Алтуриак
3: Чес
4: Тарсак
5: Миртул
6: Киторн
7: Флеймрул
8: Элейнт (допускается "Элизис")
9: Элесиас
10: Марпенот
11: Уктар (допускается "Укта")
12: Найтол
При mode="shift" month должен быть числом (целым, может быть отрицательным).
Возвращает строку в формате Markdown с результатом изменения и списком праздников на неделю.
"""
from typing import TypedDict
try:
from typing_extensions import TypedDict
except ImportError:
from typing import TypedDict
from time_utils import (
get_campaign_time as get_time,
set_campaign_time as set_time_absolute,
shift_campaign_time,
MONTH_NAMES_RU,
parse_month,
get_week_holidays,
get_holiday,
is_leap_year,
)
class TimeChangeRequest(TypedDict, total=False):
"""
Запрос на изменение игрового времени.
Поля:
mode: Режим операции: "absolute" установить абсолютное время (используются year, month, day, hour как новые значения);
"shift" сдвинуть текущее время на указанные значения (year, month, day, hour интерпретируются как дельты).
По умолчанию: "shift".
year: При mode="absolute" год (целое >0). При mode="shift" сдвиг в годах (может быть отрицательным).
month: При mode="absolute" месяц (число 1-12 или русское название). При mode="shift" сдвиг в месяцах (целое, может быть отрицательным).
Допустимые русские названия (регистр не важен):
1: Хаммер
2: Алтуриак
3: Чес
4: Тарсак
5: Миртул
6: Киторн
7: Флеймрул
8: Элейнт (также принимается "Элизис")
9: Элесиас
10: Марпенот
11: Уктар (также принимается "Укта")
12: Найтол
day: При mode="absolute" день (130). При mode="shift" сдвиг в днях (может быть отрицательным).
hour: При mode="absolute" час (023). При mode="shift" сдвиг в часах (может быть отрицательным).
"""
mode: str # "absolute" | "shift", default "shift"
year: int
month: int | str
day: int
hour: int
def _format_time(year: int, month: int, day: int, hour: int) -> str:
month_name = MONTH_NAMES_RU.get(month, str(month))
return f"{day} {month_name} {year} DR, {hour:02d}:00"
def _format_holidays_section(year: int, month: int, day: int) -> str:
holidays = get_week_holidays(year, month, day)
if not holidays:
return "📅 **Ближайшие праздники:** нет"
lines = ["📅 **Ближайшие праздники:**"]
for m, d, desc, when in holidays:
month_name = MONTH_NAMES_RU.get(m, str(m))
lines.append(f"- **{when}** ({d} {month_name}): {desc}")
return "\n".join(lines)
def set_campaign_time(debug_description: str, requests: list[TimeChangeRequest]) -> str:
if not requests:
requests = [{}]
sections = []
for idx, req in enumerate(requests, start=1):
mode = req.get("mode", "shift")
old_time = get_time()
old_str = _format_time(old_time["year"], old_time["month"], old_time["day"], old_time["hour"])
if mode == "absolute":
new_year = old_time["year"]
new_month = old_time["month"]
new_day = old_time["day"]
new_hour = old_time["hour"]
if "year" in req:
new_year = req["year"]
if "month" in req:
try:
new_month = parse_month(req["month"])
except (ValueError, TypeError) as e:
sections.append(f"### ❌ Ошибка в запросе #{idx}\n{e}")
continue
if "day" in req:
new_day = req["day"]
if "hour" in req:
new_hour = req["hour"]
if new_year <= 0:
sections.append(f"### ❌ Ошибка в запросе #{idx}\nГод должен быть > 0, получено {new_year}.")
continue
if not (1 <= new_month <= 12):
sections.append(f"### ❌ Ошибка в запросе #{idx}\nМесяц должен быть 1-12, получено {new_month}.")
continue
if not (1 <= new_day <= 30):
sections.append(f"### ❌ Ошибка в запросе #{idx}\nДень должен быть 1-30, получено {new_day}.")
continue
if not (0 <= new_hour <= 23):
sections.append(f"### ❌ Ошибка в запросе #{idx}\nЧас должен быть 0-23, получено {new_hour}.")
continue
success = set_time_absolute(new_year, new_month, new_day, new_hour)
if success:
new_time = get_time()
new_str = _format_time(new_time["year"], new_time["month"], new_time["day"], new_time["hour"])
sections.append(
f"### 📅 Установка времени #{idx}\n"
f"- Старое: {old_str}\n"
f"- **Новое:** {new_str}"
)
else:
sections.append(f"### ❌ Ошибка записи времени #{idx}")
else: # shift
delta_year = req.get("year", 0)
delta_month = req.get("month", 0)
delta_day = req.get("day", 0)
delta_hour = req.get("hour", 0)
if "month" in req:
try:
delta_month = int(req["month"])
except (ValueError, TypeError):
sections.append(f"### ❌ Ошибка в запросе #{idx}\nПри mode='shift' month должен быть числом, получено {req['month']}.")
continue
if delta_year == 0 and delta_month == 0 and delta_day == 0 and delta_hour == 0:
current = get_time()
current_str = _format_time(current["year"], current["month"], current["day"], current["hour"])
sections.append(
f"### 🕰️ Текущее время #{idx}\n"
f"**Время:** {current_str}"
)
else:
new_time = shift_campaign_time(delta_year, delta_month, delta_day, delta_hour)
new_str = _format_time(new_time["year"], new_time["month"], new_time["day"], new_time["hour"])
parts = []
if delta_year:
parts.append(f"{delta_year:+d} лет")
if delta_month:
parts.append(f"{delta_month:+d} месяцев")
if delta_day:
parts.append(f"{delta_day:+d} дней")
if delta_hour:
parts.append(f"{delta_hour:+d} часов")
shift_desc = ", ".join(parts) if parts else "0"
sections.append(
f"### ⏳ Сдвиг времени #{idx}\n"
f"- Сдвиг: {shift_desc}\n"
f"- Старое: {old_str}\n"
f"- **Новое:** {new_str}"
)
final_time = get_time()
holidays_section = _format_holidays_section(
final_time["year"],
final_time["month"],
final_time["day"]
)
result = "\n\n---\n\n".join(sections)
result += f"\n\n---\n\n{holidays_section}"
return result
if __name__ == "__main__":
import sys
if hasattr(sys.stdout, 'reconfigure'):
sys.stdout.reconfigure(encoding='utf-8')
result = set_campaign_time("тест", [
{"mode": "shift", "day": 1, "hour": 5},
{"mode": "absolute", "year": 1492, "month": 1, "day": 1, "hour": 0},
{"mode": "absolute", "hour": 12},
{"mode": "absolute", "month": "Миртул", "day": 15},
{"mode": "absolute", "month": "Укта"},
{},
])
print(result)