mirror of
https://github.com/Crocmagnon/charasheet.git
synced 2024-11-22 14:38:03 +01:00
Allow GM to increase/decrese battle effects rounds
This commit is contained in:
parent
27afcc7791
commit
ad5e690e21
6 changed files with 146 additions and 20 deletions
|
@ -1,5 +1,5 @@
|
|||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.db.models import F, Q
|
||||
from django.urls import reverse
|
||||
from django_extensions.db.models import TimeStampedModel
|
||||
|
||||
|
@ -69,9 +69,28 @@ class Party(UniquelyNamedModel, TimeStampedModel, models.Model):
|
|||
character.reset_stats()
|
||||
|
||||
|
||||
class BattleEffectQuerySet(models.QuerySet):
|
||||
def increase_rounds(self):
|
||||
self.temporary().update(remaining_rounds=F("remaining_rounds") + 1)
|
||||
|
||||
def decrease_rounds(self):
|
||||
self.active().update(remaining_rounds=F("remaining_rounds") - 1)
|
||||
|
||||
def active(self):
|
||||
return self.filter(remaining_rounds__gt=0)
|
||||
|
||||
def terminated(self):
|
||||
return self.filter(remaining_rounds=0)
|
||||
|
||||
def permanent(self):
|
||||
return self.filter(remaining_rounds=-1)
|
||||
|
||||
def temporary(self):
|
||||
return self.exclude(remaining_rounds=-1)
|
||||
|
||||
|
||||
class BattleEffectManager(models.Manager):
|
||||
def decrease_all_remaining_rounds(self):
|
||||
pass
|
||||
pass
|
||||
|
||||
|
||||
class BattleEffect(TimeStampedModel, models.Model):
|
||||
|
@ -99,7 +118,7 @@ class BattleEffect(TimeStampedModel, models.Model):
|
|||
verbose_name="créé par",
|
||||
)
|
||||
|
||||
objects = BattleEffectManager()
|
||||
objects = BattleEffectManager.from_queryset(BattleEffectQuerySet)()
|
||||
|
||||
@property
|
||||
def remaining_percent(self) -> float:
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
{% block content %}
|
||||
<h1>{{ party.name }}</h1>
|
||||
<p>MJ : {{ party.game_master.get_full_name|default:party.game_master.username }}</p>
|
||||
<p>
|
||||
<a href="{% url "party:reset_stats" pk=party.pk %}" id="reset-stats">Réinitialiser
|
||||
les stats</a>
|
||||
</p>
|
||||
{% if party.game_master == request.user %}
|
||||
<p>
|
||||
<a href="{% url "party:reset_stats" pk=party.pk %}" id="reset-stats">Réinitialiser
|
||||
les stats</a>
|
||||
</p>
|
||||
{% endif %}
|
||||
<h2 class="mt-4">Personnages</h2>
|
||||
<div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 row-cols-xl-4 g-4">
|
||||
{% for character in party.characters.all %}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{% load character_extras %}
|
||||
<div id="effects">
|
||||
<div id="effects-form">
|
||||
<button
|
||||
|
@ -8,6 +9,26 @@
|
|||
id="add-effect"
|
||||
class="btn btn-primary"><i class="fa-solid fa-plus"></i> Ajouter un effet
|
||||
</button>
|
||||
{% if party.game_master == request.user %}
|
||||
<div class="btn-group">
|
||||
<button
|
||||
hx-get="{% url "party:increase_rounds" pk=party.pk %}"
|
||||
hx-target="#effects"
|
||||
hx-swap="outerHTML"
|
||||
type="button"
|
||||
id="increase-rounds"
|
||||
class="btn btn-outline-secondary"> <i class="fa-solid fa-plus"></i> tours
|
||||
</button>
|
||||
<button
|
||||
hx-get="{% url "party:decrease_rounds" pk=party.pk %}"
|
||||
hx-target="#effects"
|
||||
hx-swap="outerHTML"
|
||||
type="button"
|
||||
id="decrease-rounds"
|
||||
class="btn btn-outline-secondary"> <i class="fa-solid fa-minus"></i> tours
|
||||
</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="effects-cards" class="row mt-1 row-cols-1 row-cols-sm-2 row-cols-md-3 row-cols-lg-4 g-4">
|
||||
{% for effect in party.effects.all %}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import random
|
||||
|
||||
import pytest
|
||||
from django.urls import reverse
|
||||
from model_bakery import baker
|
||||
|
@ -137,13 +139,8 @@ def test_player_can_add_effect_to_group(
|
|||
)
|
||||
remaining_rounds = "8"
|
||||
|
||||
login(selenium, live_server, user, password)
|
||||
|
||||
url = reverse("party:details", kwargs={"pk": party.pk})
|
||||
selenium.get(live_server.url + url)
|
||||
|
||||
go_to_party(selenium, live_server, party, user, password)
|
||||
fill_effect(selenium, name, description, target, remaining_rounds)
|
||||
|
||||
assert_effect_is_created(name, description, target, remaining_rounds)
|
||||
# Todo: assert effect is displayed
|
||||
|
||||
|
@ -170,13 +167,8 @@ def test_gm_can_add_effect_to_group(
|
|||
)
|
||||
remaining_rounds = "-1"
|
||||
|
||||
login(selenium, live_server, user, password)
|
||||
|
||||
url = reverse("party:details", kwargs={"pk": party.pk})
|
||||
selenium.get(live_server.url + url)
|
||||
|
||||
go_to_party(selenium, live_server, party, user, password)
|
||||
fill_effect(selenium, name, description, target, remaining_rounds)
|
||||
|
||||
assert_effect_is_created(name, description, target, remaining_rounds)
|
||||
# Todo: assert effect is displayed
|
||||
|
||||
|
@ -186,6 +178,59 @@ def test_gm_can_change_remaining_rounds(
|
|||
selenium: WebDriver, live_server: LiveServer, initial_data: None
|
||||
):
|
||||
"""The GM of a group can increase or decrease the remaining rounds of effects."""
|
||||
user, password = "gm", "password"
|
||||
gm = User.objects.create_user(user, password=password)
|
||||
party = baker.make(Party, game_master=gm)
|
||||
|
||||
active_not_nearly_terminated = baker.make( # noqa: F841
|
||||
BattleEffect,
|
||||
_quantity=7,
|
||||
remaining_rounds=lambda: random.randint(2, 12),
|
||||
party=party,
|
||||
)
|
||||
active_nearly_terminated = baker.make( # noqa: F841
|
||||
BattleEffect, _quantity=3, remaining_rounds=1, party=party
|
||||
)
|
||||
terminated = baker.make( # noqa: F841
|
||||
BattleEffect, _quantity=5, remaining_rounds=0, party=party
|
||||
)
|
||||
permanent = baker.make( # noqa: F841
|
||||
BattleEffect, _quantity=2, remaining_rounds=-1, party=party
|
||||
)
|
||||
not_party = baker.make(BattleEffect, _quantity=4, remaining_rounds=55) # noqa: F841
|
||||
|
||||
go_to_party(selenium, live_server, party, user, password)
|
||||
selenium.find_element(By.ID, "increase-rounds").click()
|
||||
assert BattleEffect.objects.filter(party=party).permanent().count() == 2
|
||||
assert (
|
||||
BattleEffect.objects.filter(party=party, remaining_rounds__gt=1).count() == 10
|
||||
)
|
||||
assert BattleEffect.objects.filter(party=party, remaining_rounds=1).count() == 5
|
||||
assert BattleEffect.objects.filter(party=party).terminated().count() == 0
|
||||
assert (
|
||||
BattleEffect.objects.exclude(party=party).filter(remaining_rounds=55).count()
|
||||
== 4
|
||||
)
|
||||
|
||||
selenium.find_element(By.ID, "decrease-rounds").click()
|
||||
assert BattleEffect.objects.filter(party=party).permanent().count() == 2
|
||||
assert BattleEffect.objects.filter(party=party, remaining_rounds__gt=1).count() == 7
|
||||
assert BattleEffect.objects.filter(party=party, remaining_rounds=1).count() == 3
|
||||
assert BattleEffect.objects.filter(party=party).terminated().count() == 5
|
||||
assert (
|
||||
BattleEffect.objects.exclude(party=party).filter(remaining_rounds=55).count()
|
||||
== 4
|
||||
)
|
||||
|
||||
selenium.find_element(By.ID, "decrease-rounds").click()
|
||||
assert BattleEffect.objects.filter(party=party).permanent().count() == 2
|
||||
assert BattleEffect.objects.filter(party=party).active().count() == 7
|
||||
assert BattleEffect.objects.filter(party=party, remaining_rounds=1).count() == 0
|
||||
assert BattleEffect.objects.filter(party=party).terminated().count() == 8
|
||||
assert (
|
||||
BattleEffect.objects.exclude(party=party).filter(remaining_rounds=55).count()
|
||||
== 4
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
|
@ -234,3 +279,9 @@ def assert_effect_is_created(name, description, target, remaining_rounds):
|
|||
assert effect.target == target
|
||||
assert effect.description == description
|
||||
assert str(effect.remaining_rounds) == remaining_rounds
|
||||
|
||||
|
||||
def go_to_party(selenium, live_server, party, user, password):
|
||||
login(selenium, live_server, user, password)
|
||||
url = reverse("party:details", kwargs={"pk": party.pk})
|
||||
selenium.get(live_server.url + url)
|
||||
|
|
|
@ -11,6 +11,12 @@ urlpatterns = [
|
|||
path("<int:pk>/delete/", views.party_delete, name="delete"),
|
||||
path("<int:pk>/reset_stats/", views.party_reset_stats, name="reset_stats"),
|
||||
path("<int:pk>/add_effect/", views.party_add_effect, name="add_effect"),
|
||||
path(
|
||||
"<int:pk>/increase_rounds/", views.party_increase_rounds, name="increase_rounds"
|
||||
),
|
||||
path(
|
||||
"<int:pk>/decrease_rounds/", views.party_decrease_rounds, name="decrease_rounds"
|
||||
),
|
||||
path("<int:pk>/leave/<int:character_pk>/", views.party_leave, name="leave"),
|
||||
path("<int:pk>/join/<int:character_pk>/", views.party_join, name="join"),
|
||||
path("<int:pk>/refuse/<int:character_pk>/", views.party_refuse, name="refuse"),
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
from django.contrib import messages
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.shortcuts import get_object_or_404, redirect, render
|
||||
from django.views.decorators.http import require_GET, require_http_methods
|
||||
|
||||
from character.models import Character, HarmfulState
|
||||
from party.forms import BattleEffectForm, PartyForm
|
||||
from party.models import Party
|
||||
|
||||
|
||||
@require_GET
|
||||
@login_required
|
||||
def parties_list(request):
|
||||
context = {
|
||||
|
@ -17,6 +19,7 @@ def parties_list(request):
|
|||
return render(request, "party/parties_list.html", context)
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
def party_create(request):
|
||||
if request.method == "GET":
|
||||
|
@ -33,6 +36,7 @@ def party_create(request):
|
|||
return render(request, "party/party_form.html", context)
|
||||
|
||||
|
||||
@require_GET
|
||||
@login_required
|
||||
def party_details(request, pk):
|
||||
party = get_object_or_404(Party.objects.related_to(request.user), pk=pk)
|
||||
|
@ -43,6 +47,7 @@ def party_details(request, pk):
|
|||
return render(request, "party/party_details.html", context)
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
def party_delete(request, pk):
|
||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||
|
@ -55,6 +60,7 @@ def party_delete(request, pk):
|
|||
return render(request, "party/party_delete.html", context)
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
def party_reset_stats(request, pk):
|
||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||
|
@ -68,6 +74,7 @@ def party_reset_stats(request, pk):
|
|||
return render(request, "party/party_reset_stats.html", context)
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
def party_add_effect(request, pk):
|
||||
party = get_object_or_404(Party.objects.played_or_mastered_by(request.user), pk=pk)
|
||||
|
@ -86,6 +93,23 @@ def party_add_effect(request, pk):
|
|||
return render(request, "party/snippets/add_effect_form.html", context)
|
||||
|
||||
|
||||
@require_GET
|
||||
@login_required
|
||||
def party_increase_rounds(request, pk):
|
||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||
party.effects.increase_rounds()
|
||||
return render(request, "party/snippets/effects.html", {"party": party})
|
||||
|
||||
|
||||
@require_GET
|
||||
@login_required
|
||||
def party_decrease_rounds(request, pk):
|
||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||
party.effects.decrease_rounds()
|
||||
return render(request, "party/snippets/effects.html", {"party": party})
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
def party_change(request, pk):
|
||||
party = get_object_or_404(Party.objects.managed_by(request.user), pk=pk)
|
||||
|
@ -102,6 +126,7 @@ def party_change(request, pk):
|
|||
return render(request, "party/party_form.html", context)
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
@login_required
|
||||
def party_leave(request, pk, character_pk):
|
||||
party = get_object_or_404(Party.objects.played_by(request.user).distinct(), pk=pk)
|
||||
|
@ -116,6 +141,7 @@ def party_leave(request, pk, character_pk):
|
|||
return render(request, "party/party_leave.html", context)
|
||||
|
||||
|
||||
@require_GET
|
||||
@login_required
|
||||
def party_join(request, pk, character_pk):
|
||||
party = get_object_or_404(Party.objects.invited_to(request.user).distinct(), pk=pk)
|
||||
|
@ -128,6 +154,7 @@ def party_join(request, pk, character_pk):
|
|||
return redirect("party:list")
|
||||
|
||||
|
||||
@require_GET
|
||||
@login_required
|
||||
def party_refuse(request, pk, character_pk):
|
||||
party = get_object_or_404(Party.objects.invited_to(request.user).distinct(), pk=pk)
|
||||
|
|
Loading…
Reference in a new issue