226 lines
10 KiB
Python
226 lines
10 KiB
Python
"""
|
||
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" – день (1–30). При mode="shift" – сдвиг в днях (может быть отрицательным).
|
||
hour: При mode="absolute" – час (0–23). При 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) |