39004-vm/core/views.py
2026-03-05 11:04:00 +00:00

240 lines
8.3 KiB
Python
Raw Permalink 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.

import random
from django.shortcuts import get_object_or_404, redirect, render
from .forms import CharacterCreateForm, ChoiceForm
from .models import Character, Choice, InventoryItem, Item, Quest, Scene, StoryEntry
BACKGROUND_STATS = {
Character.BACKGROUND_WARDEN: {"vigor": 5, "focus": 3, "alchemy": 2},
Character.BACKGROUND_SCOUR: {"vigor": 4, "focus": 4, "alchemy": 2},
Character.BACKGROUND_ALCHEMIST: {"vigor": 2, "focus": 4, "alchemy": 5},
}
def get_active_character(request):
character_id = request.session.get("active_character_id")
if character_id:
try:
return Character.objects.get(id=character_id)
except Character.DoesNotExist:
request.session.pop("active_character_id", None)
return None
def home(request):
character = get_active_character(request)
quests = character.quests.all()[:3] if character else []
inventory = character.inventory.select_related("item")[:3] if character else []
context = {
"page_title": "Темная тропа — интерактивная RPG",
"page_description": "Мрачное текстовое RPG-приключение в духе ведьмачьих саг: выбор, проверки навыков, журнал заданий и лут.",
"character": character,
"quests": quests,
"inventory": inventory,
}
return render(request, "core/index.html", context)
def character_create(request):
if request.method == "POST":
form = CharacterCreateForm(request.POST)
if form.is_valid():
background = form.cleaned_data["background"]
stats = BACKGROUND_STATS.get(background, {"vigor": 3, "focus": 3, "alchemy": 3})
starting_scene = Scene.objects.first()
character = Character.objects.create(
name=form.cleaned_data["name"],
background=background,
vigor=stats["vigor"],
focus=stats["focus"],
alchemy=stats["alchemy"],
current_scene=starting_scene,
)
request.session["active_character_id"] = character.id
starter_item = Item.objects.first()
if starter_item:
InventoryItem.objects.create(
character=character, item=starter_item, equipped=True
)
Quest.objects.create(
character=character,
title="Шепот Чёрной Трясины",
summary="Разузнать, кто тревожит болота и почему местные боятся ночи.",
)
return redirect("character_detail", pk=character.id)
else:
form = CharacterCreateForm()
return render(
request,
"core/character_create.html",
{
"form": form,
"page_title": "Создать героя",
"page_description": "Соберите персонажа и начните мрачное приключение.",
},
)
def character_detail(request, pk):
character = get_object_or_404(Character, pk=pk)
request.session["active_character_id"] = character.id
equipped = character.inventory.select_related("item").filter(equipped=True)
recent_entries = character.story_entries.select_related("scene")[:4]
return render(
request,
"core/character_detail.html",
{
"character": character,
"equipped": equipped,
"recent_entries": recent_entries,
"page_title": f"{character.name} — профиль героя",
"page_description": "Профиль персонажа, характеристики и недавние выборы.",
},
)
def story_view(request):
character = get_active_character(request)
if not character:
return redirect("character_create")
scene = character.current_scene or Scene.objects.first()
if not scene:
return render(
request,
"core/story.html",
{
"character": character,
"scene": None,
"form": None,
"page_title": "Сюжет",
"page_description": "Пока нет сцен. Добавьте их через админку.",
},
)
last_entry_id = request.session.pop("last_entry_id", None)
last_entry = None
if last_entry_id:
last_entry = StoryEntry.objects.filter(
id=last_entry_id, character=character
).select_related("scene").first()
if request.method == "POST":
form = ChoiceForm(request.POST, choice_queryset=scene.choices.all())
if form.is_valid():
choice = form.cleaned_data["choice"]
outcome = StoryEntry.OUTCOME_NEUTRAL
roll = None
total = None
next_scene = choice.next_scene or scene
if choice.required_skill and choice.difficulty:
roll = random.randint(1, 20)
skill_value = getattr(character, choice.required_skill, 0)
total = roll + skill_value
success = total >= choice.difficulty
outcome = StoryEntry.OUTCOME_SUCCESS if success else StoryEntry.OUTCOME_FAIL
next_scene = choice.success_scene if success else choice.fail_scene
next_scene = next_scene or choice.next_scene or scene
entry = StoryEntry.objects.create(
character=character,
scene=scene,
choice_text=choice.text,
outcome=outcome,
roll=roll,
total=total,
)
if choice.reward_item and outcome != StoryEntry.OUTCOME_FAIL:
InventoryItem.objects.get_or_create(
character=character, item=choice.reward_item
)
character.current_scene = next_scene
character.save(update_fields=["current_scene"])
request.session["last_entry_id"] = entry.id
return redirect("story")
else:
form = ChoiceForm(choice_queryset=scene.choices.all())
return render(
request,
"core/story.html",
{
"character": character,
"scene": scene,
"form": form,
"last_entry": last_entry,
"page_title": "Сюжет",
"page_description": "Выбирайте действия и наблюдайте последствия.",
},
)
def quest_list(request):
character = get_active_character(request)
quests = character.quests.all() if character else []
return render(
request,
"core/quest_list.html",
{
"character": character,
"quests": quests,
"page_title": "Журнал заданий",
"page_description": "Список текущих и завершённых заданий.",
},
)
def quest_detail(request, pk):
character = get_active_character(request)
quest = get_object_or_404(Quest, pk=pk)
return render(
request,
"core/quest_detail.html",
{
"character": character,
"quest": quest,
"page_title": quest.title,
"page_description": "Детали задания и его статус.",
},
)
def inventory_view(request):
character = get_active_character(request)
items = (
character.inventory.select_related("item") if character else InventoryItem.objects.none()
)
return render(
request,
"core/inventory.html",
{
"character": character,
"items": items,
"page_title": "Инвентарь",
"page_description": "Лут, экипировка и свойства предметов.",
},
)
def item_detail(request, pk):
character = get_active_character(request)
inventory_item = get_object_or_404(InventoryItem, pk=pk)
return render(
request,
"core/item_detail.html",
{
"character": character,
"inventory_item": inventory_item,
"page_title": inventory_item.item.name,
"page_description": "Подробности предмета и его эффектов.",
},
)