NPCs
This commit is contained in:
parent
11292774f2
commit
a9648c12b8
|
@ -1,5 +1,6 @@
|
||||||
|
from typing import Any
|
||||||
from django import forms
|
from django import forms
|
||||||
from guild.models import PlaySession, Character, Reward
|
from guild.models import NPC, PlaySession, Character, Reward
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,14 +12,22 @@ class PlaySessionCharacterForm(forms.ModelMultipleChoiceField):
|
||||||
return character.name
|
return character.name
|
||||||
|
|
||||||
|
|
||||||
|
class PlaySessionNPCForm(forms.ModelMultipleChoiceField):
|
||||||
|
def label_from_instance(self, npc):
|
||||||
|
return npc.name
|
||||||
|
|
||||||
|
|
||||||
class PlaySessionForm(forms.ModelForm):
|
class PlaySessionForm(forms.ModelForm):
|
||||||
characters = PlaySessionCharacterForm(
|
characters = PlaySessionCharacterForm(
|
||||||
queryset=Character.objects.all(), widget=forms.CheckboxSelectMultiple
|
queryset=Character.objects.all(), widget=forms.CheckboxSelectMultiple
|
||||||
)
|
)
|
||||||
|
npcs = PlaySessionNPCForm(
|
||||||
|
queryset=NPC.objects.all(), widget=forms.CheckboxSelectMultiple, required=False
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PlaySession
|
model = PlaySession
|
||||||
fields = ["date", "characters", "summary"]
|
fields = ["date", "characters", "summary", "npcs"]
|
||||||
# set date wideget to type="date"
|
# set date wideget to type="date"
|
||||||
widgets = {
|
widgets = {
|
||||||
"date": forms.DateInput(attrs={"type": "date"}),
|
"date": forms.DateInput(attrs={"type": "date"}),
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
# Generated by Django 4.2.1 on 2023-08-25 18:41
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("guild", "0012_alter_character_options_alter_character_picture"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="NPC",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.BigAutoField(
|
||||||
|
auto_created=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
verbose_name="ID",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("name", models.CharField(max_length=255)),
|
||||||
|
("description", models.TextField()),
|
||||||
|
(
|
||||||
|
"picture",
|
||||||
|
models.ImageField(
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
upload_to="uploads/",
|
||||||
|
verbose_name="NPC Picture",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"created_at",
|
||||||
|
models.DateTimeField(auto_now_add=True, verbose_name="created at"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"updated_at",
|
||||||
|
models.DateTimeField(auto_now=True, verbose_name="updated at"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "npc",
|
||||||
|
"verbose_name_plural": "npcs",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="playsession",
|
||||||
|
name="npcs",
|
||||||
|
field=models.ManyToManyField(to="guild.npc", verbose_name="npcs"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 4.2.1 on 2023-08-25 18:52
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("guild", "0013_npc_playsession_npcs"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="playsession",
|
||||||
|
name="npcs",
|
||||||
|
field=models.ManyToManyField(
|
||||||
|
blank=True, to="guild.npc", verbose_name="npcs"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -116,6 +116,7 @@ class PlaySession(models.Model):
|
||||||
"Adventure", verbose_name=_("adventure"), on_delete=models.CASCADE
|
"Adventure", verbose_name=_("adventure"), on_delete=models.CASCADE
|
||||||
)
|
)
|
||||||
characters = models.ManyToManyField("Character", verbose_name=_("characters"))
|
characters = models.ManyToManyField("Character", verbose_name=_("characters"))
|
||||||
|
npcs = models.ManyToManyField("NPC", verbose_name=_("npcs"), blank=True)
|
||||||
|
|
||||||
summary = models.TextField()
|
summary = models.TextField()
|
||||||
|
|
||||||
|
@ -199,3 +200,25 @@ class Reward(models.Model):
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("guild:reward_detail", kwargs={"pk": self.pk})
|
return reverse("guild:reward_detail", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
|
||||||
|
class NPC(models.Model):
|
||||||
|
name = models.CharField(max_length=255)
|
||||||
|
description = models.TextField()
|
||||||
|
|
||||||
|
picture = models.ImageField(
|
||||||
|
_("NPC Picture"), null=True, blank=True, upload_to="uploads/"
|
||||||
|
)
|
||||||
|
|
||||||
|
created_at = models.DateTimeField(_("created at"), auto_now_add=True)
|
||||||
|
updated_at = models.DateTimeField(_("updated at"), auto_now=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
verbose_name = _("npc")
|
||||||
|
verbose_name_plural = _("npcs")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name
|
||||||
|
|
||||||
|
def get_absolute_url(self):
|
||||||
|
return reverse("guild:npc_detail", kwargs={"pk": self.pk})
|
||||||
|
|
|
@ -8,11 +8,13 @@
|
||||||
<div class="column column-75">
|
<div class="column column-75">
|
||||||
<hrgroup>
|
<hrgroup>
|
||||||
<h1>Adventure: {{ adventure.name }}</h1>
|
<h1>Adventure: {{ adventure.name }}</h1>
|
||||||
|
{% if adventure.master %}
|
||||||
<h4>Mastered by:
|
<h4>Mastered by:
|
||||||
<a href="{% url 'guild:player_detail' adventure.master.id %}">
|
<a href="{% url 'guild:player_detail' adventure.master.id %}">
|
||||||
{{ adventure.master }}
|
{{ adventure.master }}
|
||||||
</a>
|
</a>
|
||||||
</h4>
|
</h4>
|
||||||
|
{% endif %}
|
||||||
</hrgroup>
|
</hrgroup>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
|
|
|
@ -55,6 +55,25 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="column column-75">
|
||||||
|
<h2>NPCs</h2>
|
||||||
|
</div>
|
||||||
|
<div class="column column-25">
|
||||||
|
<a class="button button-outline" href="{% url 'guild:create_npc' %}">Create New NPC</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for npc in npcs %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'guild:npc_detail' npc.id %}">
|
||||||
|
{{ npc.name }}
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="column column-75">
|
<div class="column column-75">
|
||||||
<h2>Players</h2>
|
<h2>Players</h2>
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<h1>Session Delete</h1>
|
||||||
|
|
||||||
|
<p>Are you sure you want to delete <strong>{{ character.name}}</strong>?</p>
|
||||||
|
|
||||||
|
<form action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
<input type="submit" value="Delete Character">
|
||||||
|
</form>
|
||||||
|
{% endblock content %}
|
|
@ -0,0 +1,52 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% load guild_extras %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="column column-75">
|
||||||
|
<hrgroup>
|
||||||
|
<h1>NPCs: {{ npc.name }}</h1>
|
||||||
|
<h4>
|
||||||
|
{{ npc.get_status_display }}
|
||||||
|
</h4>
|
||||||
|
</hrgroup>
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
<a class="button button-outline" href="{% url 'guild:npc_update' npc.id %}">Edit</a>
|
||||||
|
</div>
|
||||||
|
<div class="column">
|
||||||
|
<a class="button button-clear" href="{% url 'guild:npc_delete' npc.id %}">Delete</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
</div>
|
||||||
|
{% if npc.picture %}
|
||||||
|
<a href="{{npc.picture.url}}" style="float:left;margin-right:10px;margin-bottom:10px;">
|
||||||
|
<img src="{{npc.picture.url}}" width="300"/>
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
|
<p>{{npc.description|md|safe}}</p>
|
||||||
|
<div class="column">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<h2>Session History</h2>
|
||||||
|
|
||||||
|
{% if not npc.playsession_set.count %}
|
||||||
|
<p>No appearance yet.</p>
|
||||||
|
{% else %}
|
||||||
|
<ul>
|
||||||
|
{% for session in npc.playsession_set.all %}
|
||||||
|
<li>
|
||||||
|
<a href="{% url 'guild:adventure_detail' session.adventure.id %}">
|
||||||
|
{{session.date}} - {{ session.adventure.name }}
|
||||||
|
</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% endblock content %}
|
|
@ -0,0 +1,13 @@
|
||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<form action="" method="post" enctype="multipart/form-data" >
|
||||||
|
{% csrf_token %}
|
||||||
|
{{ form.as_p }}
|
||||||
|
{% if object %}
|
||||||
|
<input type="submit" value="Update NPC">
|
||||||
|
{% else %}
|
||||||
|
<input type="submit" value="Create NPC">
|
||||||
|
{% endif %}
|
||||||
|
</form>
|
||||||
|
{% endblock content %}
|
|
@ -74,4 +74,14 @@
|
||||||
|
|
||||||
<p>{{playsession.summary|md|safe}}</p>
|
<p>{{playsession.summary|md|safe}}</p>
|
||||||
|
|
||||||
|
|
||||||
|
<h3>NPC Appearances</h3>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{% for npc in playsession.npcs.all %}
|
||||||
|
<li><a href="{% url 'guild:npc_detail' npc.id %}">{{ npc.name }}</a></li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
{% endblock content %}
|
{% endblock content %}
|
|
@ -2,6 +2,7 @@ from django.urls import path
|
||||||
import guild.views as views
|
import guild.views as views
|
||||||
import guild.views.player as player_views
|
import guild.views.player as player_views
|
||||||
import guild.views.character as character_views
|
import guild.views.character as character_views
|
||||||
|
import guild.views.npc as npc_views
|
||||||
import guild.views.adventure as adventure_views
|
import guild.views.adventure as adventure_views
|
||||||
import guild.views.playsession as playsession_views
|
import guild.views.playsession as playsession_views
|
||||||
import guild.views.settings as settings_views
|
import guild.views.settings as settings_views
|
||||||
|
@ -137,4 +138,24 @@ urlpatterns = [
|
||||||
resource_views.ResourceUpdateView.as_view(),
|
resource_views.ResourceUpdateView.as_view(),
|
||||||
name="resource_update",
|
name="resource_update",
|
||||||
),
|
),
|
||||||
|
path(
|
||||||
|
"npcs/create/",
|
||||||
|
npc_views.CreateNPCView.as_view(),
|
||||||
|
name="create_npc",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"npcs/<int:pk>/",
|
||||||
|
npc_views.NPCDetailView.as_view(),
|
||||||
|
name="npc_detail",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"npcs/<int:pk>/update/",
|
||||||
|
npc_views.NPCUpdateView.as_view(),
|
||||||
|
name="npc_update",
|
||||||
|
),
|
||||||
|
path(
|
||||||
|
"npcs/<int:pk>/delete/",
|
||||||
|
npc_views.NPCDeleteView.as_view(),
|
||||||
|
name="npc_delete",
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -5,7 +5,7 @@ from django.views.generic.edit import CreateView
|
||||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.forms import UserCreationForm
|
from django.contrib.auth.forms import UserCreationForm
|
||||||
from guild.models import Adventure, Character, Player, Reward
|
from guild.models import NPC, Adventure, Character, Player, Reward
|
||||||
|
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
@ -23,6 +23,7 @@ class HomeView(LoginRequiredMixin, TemplateView):
|
||||||
context["adventures"] = advs
|
context["adventures"] = advs
|
||||||
context["players"] = Player.objects.all()
|
context["players"] = Player.objects.all()
|
||||||
context["characters"] = Character.objects.all()
|
context["characters"] = Character.objects.all()
|
||||||
|
context["npcs"] = NPC.objects.all()
|
||||||
|
|
||||||
context["rewards"] = Reward.objects.filter(character=None).order_by(
|
context["rewards"] = Reward.objects.filter(character=None).order_by(
|
||||||
"-playsession__date"
|
"-playsession__date"
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
from django.views.generic import TemplateView, ListView, DetailView
|
||||||
|
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||||
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
from guild.models import NPC
|
||||||
|
|
||||||
|
|
||||||
|
class NPCListView(LoginRequiredMixin, ListView):
|
||||||
|
model = NPC
|
||||||
|
context_object_name = "NPCs"
|
||||||
|
|
||||||
|
|
||||||
|
class CreateNPCView(LoginRequiredMixin, CreateView):
|
||||||
|
model = NPC
|
||||||
|
fields = ["name", "picture", "description"]
|
||||||
|
|
||||||
|
|
||||||
|
class NPCDetailView(LoginRequiredMixin, DetailView):
|
||||||
|
model = NPC
|
||||||
|
|
||||||
|
|
||||||
|
class NPCUpdateView(LoginRequiredMixin, UpdateView):
|
||||||
|
model = NPC
|
||||||
|
fields = ["name", "picture", "description"]
|
||||||
|
|
||||||
|
|
||||||
|
class NPCDeleteView(LoginRequiredMixin, DeleteView):
|
||||||
|
model = NPC
|
||||||
|
success_url = "/"
|
Loading…
Reference in New Issue