Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ef44030a6c |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -20,7 +20,8 @@ from django.conf import settings
|
||||
from django.conf.urls.static import static
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
path('admin/', admin.site.urls),
|
||||
path('accounts/', include('django.contrib.auth.urls')),
|
||||
path("", include("core.urls")),
|
||||
]
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
63
core/migrations/0001_initial.py
Normal file
63
core/migrations/0001_initial.py
Normal file
@ -0,0 +1,63 @@
|
||||
# Generated by Django 5.2.7 on 2026-03-05 10:42
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Item',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=100)),
|
||||
('description', models.TextField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Quest',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=100)),
|
||||
('description', models.TextField()),
|
||||
('is_active', models.BooleanField(default=False)),
|
||||
('is_completed', models.BooleanField(default=False)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Scene',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=200)),
|
||||
('content', models.TextField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PlayerProfile',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('level', models.IntegerField(default=1)),
|
||||
('inventory', models.ManyToManyField(blank=True, to='core.item')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
('quests', models.ManyToManyField(blank=True, to='core.quest')),
|
||||
('current_scene', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.scene')),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Choice',
|
||||
fields=[
|
||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('text', models.CharField(max_length=200)),
|
||||
('next_scene', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='incoming_choices', to='core.scene')),
|
||||
('scene', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='choices', to='core.scene')),
|
||||
],
|
||||
),
|
||||
]
|
||||
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
BIN
core/migrations/__pycache__/0001_initial.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
@ -1,3 +1,43 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
# Create your models here.
|
||||
class Item(models.Model):
|
||||
name = models.CharField(max_length=100)
|
||||
description = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Quest(models.Model):
|
||||
title = models.CharField(max_length=100)
|
||||
description = models.TextField()
|
||||
is_active = models.BooleanField(default=False)
|
||||
is_completed = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class Scene(models.Model):
|
||||
title = models.CharField(max_length=200)
|
||||
content = models.TextField()
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class Choice(models.Model):
|
||||
scene = models.ForeignKey(Scene, related_name='choices', on_delete=models.CASCADE)
|
||||
text = models.CharField(max_length=200)
|
||||
next_scene = models.ForeignKey(Scene, related_name='incoming_choices', on_delete=models.SET_NULL, null=True, blank=True)
|
||||
|
||||
def __str__(self):
|
||||
return self.text
|
||||
|
||||
class PlayerProfile(models.Model):
|
||||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||||
current_scene = models.ForeignKey(Scene, on_delete=models.SET_NULL, null=True, blank=True)
|
||||
inventory = models.ManyToManyField(Item, blank=True)
|
||||
quests = models.ManyToManyField(Quest, blank=True)
|
||||
level = models.IntegerField(default=1)
|
||||
|
||||
def __str__(self):
|
||||
return self.user.username
|
||||
@ -3,23 +3,33 @@
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %}Knowledge Base{% endblock %}</title>
|
||||
{% if project_description %}
|
||||
<meta name="description" content="{{ project_description }}">
|
||||
<meta property="og:description" content="{{ project_description }}">
|
||||
<meta property="twitter:description" content="{{ project_description }}">
|
||||
{% endif %}
|
||||
{% if project_image_url %}
|
||||
<meta property="og:image" content="{{ project_image_url }}">
|
||||
<meta property="twitter:image" content="{{ project_image_url }}">
|
||||
{% endif %}
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Witcher RPG{% endblock %}</title>
|
||||
{% load static %}
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v={{ deployment_timestamp }}">
|
||||
<!-- Google Fonts for Cinzel and Inter -->
|
||||
<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;700&family=Inter:wght@400;700&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="{% static 'css/custom.css' %}?v=1.0">
|
||||
{% block head %}{% endblock %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% block content %}{% endblock %}
|
||||
<body style="background-color: #0F1310; color: #E0E0E0; font-family: 'Inter', sans-serif; margin: 0; padding: 0;">
|
||||
|
||||
<header style="padding: 20px; border-bottom: 2px solid #333;">
|
||||
<h1 style="font-family: 'Cinzel', serif; color: #B68D4C; margin: 0;">Witcher RPG</h1>
|
||||
<nav>
|
||||
<a href="{% url 'core:home' %}" style="color: #D4B26A; margin-right: 15px;">Home</a>
|
||||
<a href="{% url 'core:current_scene' %}" style="color: #D4B26A; margin-right: 15px;">Play</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main style="padding: 20px;">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<footer style="padding: 20px; text-align: center; color: #88938C; font-size: 0.8em; margin-top: 50px;">
|
||||
© 2026 Dark Fantasy RPG Engine
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
36
core/templates/core/scene_detail.html
Normal file
36
core/templates/core/scene_detail.html
Normal file
@ -0,0 +1,36 @@
|
||||
{% extends "base.html" %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<h1>{{ scene.title }}</h1>
|
||||
<p>{{ scene.content }}</p>
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
{% for choice in scene.choices.all %}
|
||||
<a href="{% url 'core:choose_action' choice.id %}" class="btn btn-accent" style="display: block; margin-bottom: 10px;">{{ choice.text }}</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<div class="card" style="background-color: #1C2320; border: 1px solid #333; padding: 15px;">
|
||||
<h2 style="color: #B68D4C; font-size: 1.2em;">Character Status</h2>
|
||||
<p>Level: {{ player.level }}</p>
|
||||
<h3 style="color: #B68D4C; font-size: 1.1em;">Quests</h3>
|
||||
<ul>
|
||||
{% for quest in player.quests.all %}
|
||||
<li>{{ quest.title }} - {{ quest.is_completed|yesno:"Completed,Active" }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<h3 style="color: #B68D4C; font-size: 1.1em;">Inventory</h3>
|
||||
<ul>
|
||||
{% for item in player.inventory.all %}
|
||||
<li>{{ item.name }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
34
core/templates/registration/login.html
Normal file
34
core/templates/registration/login.html
Normal file
@ -0,0 +1,34 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Sign In | Witcher RPG{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<section style="max-width: 480px; margin: 40px auto; background: #1C2320; border: 1px solid #2F3A34; border-radius: 12px; padding: 28px; box-shadow: 0 12px 30px rgba(0,0,0,0.35);">
|
||||
<h2 style="font-family: 'Cinzel', serif; color: #D4B26A; margin-top: 0;">Sign in to continue</h2>
|
||||
<p style="color: #A8B1AA; margin-bottom: 24px;">Enter your credentials to resume your journey.</p>
|
||||
|
||||
{% if form.non_field_errors %}
|
||||
<div style="background: rgba(190, 64, 64, 0.15); border: 1px solid #8C3B3B; color: #F2B8B5; padding: 12px; border-radius: 8px; margin-bottom: 16px;">
|
||||
{{ form.non_field_errors }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" style="display: grid; gap: 16px;">
|
||||
{% csrf_token %}
|
||||
|
||||
<label style="display: grid; gap: 6px; color: #D4B26A;">
|
||||
<span>Username</span>
|
||||
{{ form.username }}
|
||||
</label>
|
||||
|
||||
<label style="display: grid; gap: 6px; color: #D4B26A;">
|
||||
<span>Password</span>
|
||||
{{ form.password }}
|
||||
</label>
|
||||
|
||||
<button type="submit" style="background: linear-gradient(135deg, #B68D4C, #D4B26A); color: #0F1310; border: none; padding: 12px 18px; border-radius: 10px; font-weight: 700; cursor: pointer;">
|
||||
Sign In
|
||||
</button>
|
||||
</form>
|
||||
</section>
|
||||
{% endblock %}
|
||||
10
core/urls.py
10
core/urls.py
@ -1,7 +1,11 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
from .views import home
|
||||
app_name = 'core'
|
||||
|
||||
urlpatterns = [
|
||||
path("", home, name="home"),
|
||||
]
|
||||
path('', views.home, name='home'),
|
||||
path('scene/<int:scene_id>/', views.scene_view, name='scene_detail'),
|
||||
path('scene/', views.scene_view, name='current_scene'),
|
||||
path('choose/<int:choice_id>/', views.choose_action, name='choose_action'),
|
||||
]
|
||||
@ -1,25 +1,36 @@
|
||||
import os
|
||||
import platform
|
||||
|
||||
from django import get_version as django_version
|
||||
from django.shortcuts import render
|
||||
from django.utils import timezone
|
||||
|
||||
from django.shortcuts import render, get_object_or_404, redirect
|
||||
from .models import Scene, Choice, PlayerProfile
|
||||
from django.contrib.auth.decorators import login_required
|
||||
|
||||
def home(request):
|
||||
"""Render the landing screen with loader and environment details."""
|
||||
host_name = request.get_host().lower()
|
||||
agent_brand = "AppWizzy" if host_name == "appwizzy.com" else "Flatlogic"
|
||||
now = timezone.now()
|
||||
return render(request, "core/index.html")
|
||||
|
||||
context = {
|
||||
"project_name": "New Style",
|
||||
"agent_brand": agent_brand,
|
||||
"django_version": django_version(),
|
||||
"python_version": platform.python_version(),
|
||||
"current_time": now,
|
||||
"host_name": host_name,
|
||||
"project_description": os.getenv("PROJECT_DESCRIPTION", ""),
|
||||
"project_image_url": os.getenv("PROJECT_IMAGE_URL", ""),
|
||||
}
|
||||
return render(request, "core/index.html", context)
|
||||
@login_required
|
||||
def scene_view(request, scene_id=None):
|
||||
player = request.user.playerprofile
|
||||
if scene_id:
|
||||
scene = get_object_or_404(Scene, id=scene_id)
|
||||
player.current_scene = scene
|
||||
player.save()
|
||||
else:
|
||||
scene = player.current_scene
|
||||
if not scene:
|
||||
first_scene = Scene.objects.first()
|
||||
if first_scene:
|
||||
player.current_scene = first_scene
|
||||
player.save()
|
||||
scene = first_scene
|
||||
else:
|
||||
return render(request, "core/empty.html")
|
||||
|
||||
return render(request, "core/scene_detail.html", {"scene": scene, "player": player})
|
||||
|
||||
@login_required
|
||||
def choose_action(request, choice_id):
|
||||
choice = get_object_or_404(Choice, id=choice_id)
|
||||
player = request.user.playerprofile
|
||||
if choice.next_scene:
|
||||
player.current_scene = choice.next_scene
|
||||
player.save()
|
||||
return redirect('core:scene_detail', scene_id=choice.next_scene.id)
|
||||
return redirect('core:current_scene')
|
||||
@ -1,4 +1,26 @@
|
||||
/* Custom styles for the application */
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
background-color: #0F1310;
|
||||
color: #E0E0E0;
|
||||
font-family: 'Inter', sans-serif;
|
||||
}
|
||||
|
||||
h1, h2, h3 {
|
||||
font-family: 'Cinzel', serif;
|
||||
color: #B68D4C;
|
||||
}
|
||||
|
||||
.btn-accent {
|
||||
background-color: #B68D4C;
|
||||
color: #0F1310;
|
||||
border: none;
|
||||
padding: 10px 20px;
|
||||
text-transform: uppercase;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card {
|
||||
background-color: #1C2320;
|
||||
border: 1px solid #333;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user