Add states

This commit is contained in:
Gabriel Augendre 2022-11-02 21:41:06 +01:00
parent 4564e71d7d
commit 4664ae0d9d
14 changed files with 194 additions and 5 deletions

View file

@ -138,6 +138,7 @@ class CharacterAdmin(admin.ModelAdmin):
"attack_melee",
"attack_range",
"attack_magic",
"states",
]
},
),
@ -182,6 +183,7 @@ class CharacterAdmin(admin.ModelAdmin):
filter_horizontal = [
"capabilities",
"weapons",
"states",
]
form = CharacterAdminForm
@ -196,3 +198,9 @@ class CharacterAdmin(admin.ModelAdmin):
class WeaponAdmin(admin.ModelAdmin):
list_display = ["name", "damage"]
search_fields = ["name", "special", "damage"]
@admin.register(models.HarmfulState)
class HarmfulStateAdmin(admin.ModelAdmin):
list_display = ["name", "description"]
search_fields = ["name"]

View file

@ -0,0 +1,39 @@
from django.core.management import BaseCommand
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement
from character.models.character import HarmfulState
class Command(BaseCommand):
def handle(self, *args, **options) -> None:
url = "https://www.co-drs.org/fr/jeu/etats-prejudiciables"
self.setup_selenium()
self.selenium.get(url)
states = self.selenium.find_elements(By.CSS_SELECTOR, "tbody tr")
for state in states:
try:
self.import_race(url, state)
except Exception as e:
print(f"{type(e)}: {e}")
self.stdout.write(f"Finished processing {len(states)} states.")
def import_race(self, url: str, state_row: WebElement) -> None:
name = state_row.find_element(By.CLASS_NAME, "views-field-name").text.strip()
description = state_row.find_element(
By.CLASS_NAME, "views-field-description__value"
).text.strip()
icon_url = state_row.find_element(
By.CSS_SELECTOR, ".views-field-field-svg-icon img"
).get_attribute("src")
state, _ = HarmfulState.objects.update_or_create(
name=name,
defaults={"description": description, "url": url, "icon_url": icon_url},
)
self.stdout.write(self.style.SUCCESS(f"Created/updated state {state}"))
def setup_selenium(self) -> None:
options = webdriver.FirefoxOptions()
options.add_argument("-headless")
self.selenium = webdriver.Firefox(options=options)

View file

@ -0,0 +1,51 @@
# Generated by Django 4.1.2 on 2022-11-02 20:00
import django_extensions.db.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("character", "0027_character_initiative_misc"),
]
operations = [
migrations.CreateModel(
name="HarmfulState",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"name",
models.CharField(max_length=100, unique=True, verbose_name="nom"),
),
("url", models.URLField(blank=True, verbose_name="url")),
(
"created",
django_extensions.db.fields.CreationDateTimeField(
auto_now_add=True, verbose_name="created"
),
),
(
"modified",
django_extensions.db.fields.ModificationDateTimeField(
auto_now=True, verbose_name="modified"
),
),
("description", models.TextField()),
("icon_url", models.URLField()),
],
options={
"verbose_name": "État préjudiciable",
"verbose_name_plural": "États préjudiciables",
},
),
]

View file

@ -0,0 +1,20 @@
# Generated by Django 4.1.2 on 2022-11-02 20:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("character", "0028_harmfulstate"),
]
operations = [
migrations.AddField(
model_name="character",
name="states",
field=models.ManyToManyField(
related_name="characters", to="character.harmfulstate"
),
),
]

View file

@ -0,0 +1,20 @@
# Generated by Django 4.1.2 on 2022-11-02 20:05
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("character", "0029_character_states"),
]
operations = [
migrations.AlterField(
model_name="character",
name="states",
field=models.ManyToManyField(
blank=True, related_name="characters", to="character.harmfulstate"
),
),
]

View file

@ -1 +1 @@
0027_character_initiative_misc
0030_alter_character_states

View file

@ -1,5 +1,5 @@
from .capabilities import Capability, Path, RacialCapability
from .character import Character, Profile, Race
from .character import Character, HarmfulState, Profile, Race
from .equipment import Weapon
__all__ = [
@ -7,6 +7,7 @@ __all__ = [
"Path",
"RacialCapability",
"Character",
"HarmfulState",
"Profile",
"Race",
"Weapon",

View file

@ -49,6 +49,15 @@ class Race(DocumentedModel, UniquelyNamedModel, TimeStampedModel, models.Model):
verbose_name_plural = "Races"
class HarmfulState(DocumentedModel, UniquelyNamedModel, TimeStampedModel, models.Model):
description = models.TextField()
icon_url = models.URLField()
class Meta:
verbose_name = "État préjudiciable"
verbose_name_plural = "États préjudiciables"
def modifier(value: int) -> int:
if not value:
return 0
@ -177,6 +186,8 @@ class Character(models.Model):
notes = models.TextField(blank=True, verbose_name="notes", default=DEFAULT_NOTES)
damage_reduction = models.TextField(blank=True, verbose_name="réduction de dégâts")
states = models.ManyToManyField(HarmfulState, blank=True, related_name="characters")
objects = CharacterManager()
class Meta:

View file

@ -0,0 +1,15 @@
<p id="states">
États :
{% for state in character.states.all %}
<img src="{{ state.icon_url }}" alt="{{ state.name }}" height="25" width="25"
data-bs-toggle="tooltip"
data-bs-placement="top"
data-bs-title="{{ state.name }} : {{ state.description }}"
hx-get="{% url "character:remove_state" pk=character.pk state_pk=state.pk %}"
hx-target="#states"
hx-swap="outerHTML"
>
{% empty %}
Aucun
{% endfor %}
</p>

View file

@ -16,6 +16,7 @@
{{ character.race.name }} {{ character.profile.name }} niv. {{ character.level }}<br>
{{ character.get_gender_display }}, {{ character.age }} ans, {{ character.height_m }}m, {{ character.weight }}kg (IMC: {{ character.imc|floatformat }})
</p>
{% include "character/states.html" %}
<div class="row">
<div class="col-sm-12 col-md-6 col-lg-6 col-xl">
<table id="fight-table" class="table table-hover table-sm">

View file

@ -69,4 +69,7 @@ urlpatterns = [
name="remove_last_in_path",
),
path("<int:pk>/add_path/", views.add_path, name="add_path"),
path(
"<int:pk>/remove_state/<int:state_pk>/", views.remove_state, name="remove_state"
),
]

View file

@ -4,7 +4,7 @@ from django.shortcuts import get_object_or_404, redirect, render
from django_htmx.http import trigger_client_event
from character.forms import AddPathForm, EquipmentForm
from character.models import Capability, Character, Path
from character.models import Capability, Character, HarmfulState, Path
from character.templatetags.character_extras import modifier
@ -265,3 +265,15 @@ def remove_last_in_path(request, character_pk: int, path_pk: int):
"add_path_form": AddPathForm(character),
}
return render(request, "character/paths_and_capabilities.html", context)
@login_required
def remove_state(request, pk: int, state_pk: int):
character: Character = get_object_or_404(
Character.objects.filter(player=request.user), pk=pk
)
state = get_object_or_404(HarmfulState, pk=state_pk)
character.states.remove(state)
context = {"character": character}
response = render(request, "character/states.html", context)
return trigger_client_event(response, "refresh_tooltips", {})

View file

@ -42,8 +42,15 @@
{% endif %}
<script src="{% static "vendor/bootstrap-5.2.2/bootstrap.bundle.min.js" %}"></script>
<script type="application/javascript" defer>
const tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
const tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
let tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
let tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
addEventListener("refresh_tooltips", function (event) {
tooltipList.forEach(tooltip => tooltip.dispose());
setTimeout(() => {
tooltipTriggerList = document.querySelectorAll('[data-bs-toggle="tooltip"]');
tooltipList = [...tooltipTriggerList].map(tooltipTriggerEl => new bootstrap.Tooltip(tooltipTriggerEl));
}, 50);
});
</script>
</body>
</html>

View file

@ -127,6 +127,7 @@ def import_from_co_drs(ctx):
ctx.run("./manage.py import_profiles", pty=True, echo=True)
ctx.run("./manage.py import_paths", pty=True, echo=True)
ctx.run("./manage.py import_capabilities", pty=True, echo=True)
ctx.run("./manage.py import_harmful_states", pty=True, echo=True)
@task(pre=[import_from_co_drs, dump_initial])