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": "Подробности предмета и его эффектов.", }, )