Added dart_glitch field

This commit is contained in:
Walter 2025-02-14 22:21:18 +01:00
parent c200728f51
commit dec147f0ff
14 changed files with 127 additions and 45 deletions

View File

@ -49,7 +49,10 @@ class RandomLevel(CSRFexemptTemplateView):
if request.user.is_authenticated:
bloonsa_util.tag_player(request=request)
player: Player = Player.objects.get(user=request.user)
if not player.bloonsa_levels_played.filter(pk=level.pk).exists():
level.played_by.add(player)
level.save()
bloonsa_util.log(player=player,
action=actions.bloonsa_load_random_level,
note=level.level_id)
@ -69,18 +72,21 @@ class CompleteLevel(CSRFexemptTemplateView):
bloonsa_util.tag_player(request=request)
level_id = int(request.POST.get("level_id"))
darts_left = int(request.POST.get("darts_left"))
dart_glitch = bool(request.POST.get("dart_glitch"))
pops = int(request.POST.get("pops"))
level: Level = Level.objects.get(level_id=level_id)
player: Player = Player.objects.get(user=request.user)
prevScore = player.bloonsa_level_scores.first()
prevScore = LevelScore.objects.filter(player=player,
level=level).first()
if prevScore is None \
or pops > prevScore.pops \
or pops == prevScore.pops and darts_left > prevScore.darts_left:
score = LevelScore.objects.create(level=level,
clear=True,
darts_left=darts_left,
dart_glitch=dart_glitch,
pops=pops)
if prevScore:
player.bloonsa_level_scores.remove(prevScore)
@ -123,14 +129,15 @@ class RateLevel(CSRFexemptTemplateView):
return HttpResponse(content="OK", status=200)
class GetStatusData(CSRFexemptTemplateView):
def post(self, request, *args, **kwargs):
bloonsa_util.tag_player(request=request)
level_id = int(json.loads(request.body).get("level_id"))
level = Level.objects.get(level_id=level_id)
player = Player.objects.get(user=request.user)
level: Level = Level.objects.get(level_id=level_id)
player: Player = Player.objects.get(user=request.user)
score: LevelScore = LevelScore.objects.filter(player=player,
level=level).first()
total_levels = Level.objects.count()
level_cleared = player.has_beaten_bloonsa_level(level=level)
@ -148,4 +155,11 @@ class GetStatusData(CSRFexemptTemplateView):
"level_rating": level.rating,
"level_cleared": level_cleared,
}
if score:
jdata.update({
"score_darts_left": score.darts_left,
"score_dart_glitch": score.dart_glitch,
"score_pops": score.pops,
})
return JsonResponse(jdata)

View File

@ -1,7 +1,14 @@
from django.contrib import admin
from .models import Level, Author, LevelScore
from .models import Level, Author, LevelScore, LevelRating
@admin.register(LevelRating)
class LevelRatingAdmin(admin.ModelAdmin):
exclude = ("level",)
@admin.register(LevelScore)
class LevelScoreAdmin(admin.ModelAdmin):
exclude = ("level",)
admin.site.register(Level)
admin.site.register(Author)
admin.site.register(LevelScore)

View File

@ -0,0 +1,18 @@
# Generated by Django 5.1.6 on 2025-02-14 18:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bloonsa_game', '0018_rename_authorid_author_author_id_and_more'),
]
operations = [
migrations.AddField(
model_name='levelscore',
name='dart_glitch',
field=models.BooleanField(default=False),
),
]

View File

@ -0,0 +1,32 @@
# Generated by Django 5.1.6 on 2025-02-14 20:46
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('bloonsa_game', '0019_levelscore_dart_glitch'),
('users', '0023_alter_player_user'),
]
operations = [
migrations.AlterField(
model_name='levelscore',
name='darts_left',
field=models.PositiveSmallIntegerField(default=0),
preserve_default=False,
),
migrations.AlterField(
model_name='levelscore',
name='player',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bloonsa_level_scores', to='users.player'),
),
migrations.AlterField(
model_name='levelscore',
name='pops',
field=models.PositiveSmallIntegerField(default=0),
preserve_default=False,
),
]

View File

@ -53,19 +53,20 @@ class LevelRating(models.Model):
MaxValueValidator(10)])
def __str__(self):
return (f"{self.player.user.username}"
return (f"{self.player.user.username if self.player else ''}"
f" - [<{int(self.rating) * ''}> - {self.level.title}]")
# There should only be 1 score per player
# Highest popcount wins
class LevelScore(models.Model):
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="bloonsa_level_scores", null=True)
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="bloonsa_level_scores")
level = models.ForeignKey(Level, on_delete=models.CASCADE)
clear = models.BooleanField(default=True) # This is for if we ever submit scores for failed attempts
darts_left = models.PositiveSmallIntegerField(null=True)
pops = models.PositiveSmallIntegerField(null=True)
darts_left = models.PositiveSmallIntegerField()
dart_glitch = models.BooleanField(default=False) # This is triggered when the player lingers their last dart
pops = models.PositiveSmallIntegerField()
def __str__(self):
clearState = "" if self.clear else ""
return (f"{self.player.user.username}'s {clearState} @ {self.level.title}: "
return (f"{self.player.user.username if self.player else ''}'s {clearState} @ {self.level.title}: "
f"🎈{self.pops} | 🎯{self.darts_left}")

View File

@ -28,23 +28,23 @@
white-space: nowrap;
}
#level-title,
#level-id,
#level-author,
#level-author-id
#level-clear-state {
#level_title,
#level_id,
#level_author,
#level_author-id
#level_clear_state {
white-space: break-spaces;
float: left;
padding-left: 0px;
padding-right: 10px;
}
#level-id,
#level-author-id {
#level_id,
#level_author_id {
color: #59b1ff;
}
#current-level-container {
#current_level_container {
height: 110px;
}
@ -61,6 +61,6 @@
font-size: 24px;
}
#level-clear-state {
#level_clear_state {
}

View File

@ -30,12 +30,14 @@ function bloonsa_update_data(level_id) {
}
function bloonsa_update_html(r) {
document.getElementById("level-title").textContent = r.level_title;
document.getElementById("level-id").textContent = `(${r.level_id})`;
document.getElementById("level-author").textContent = `by ${r.level_author_name}`;
document.getElementById("level-author-id").textContent = `(${r.level_author_id})`;
document.getElementById("level_title").textContent = r.level_title;
document.getElementById("level_id").textContent = `(${r.level_id})`;
document.getElementById("level_author").textContent = `by ${r.level_author_name}`;
document.getElementById("level_author_id").textContent = `(${r.level_author_id})`;
if (r.level_cleared) {
document.getElementById("level-clear-state").textContent = ``;
document.getElementById("level_clear_state").textContent = ``;
} else {
document.getElementById("level_clear_state").textContent = ``;
}
document.getElementById("levels_played").textContent = `${r.bloonsa_levels_played}`;
document.getElementById("levels_beaten").textContent = `${r.bloonsa_levels_beaten}`;

View File

@ -68,10 +68,10 @@
<div id="content">
{% block content %}{% endblock content %}
<div id="current-level-container" class="wide left">
<div id="current_level_container" class="wide left">
<p>
<h1 id="level-title"></h1><h1 id="level-id"></h1><h1 id="level-clear-state"></h1><h1></h1>
<h3 id="level-author"></h3><h3 id="level-author-id"></h3><br>
<h1 id="level_title"></h1><h1 id="level_id"></h1><h1 id="level_clear_state"></h1><h1></h1>
<h3 id="level_author"></h3><h3 id="level_author_id"></h3><br>
</p>
</div>
</div>

View File

@ -6,7 +6,6 @@
{% endblock title %}
{% block head %}
{% endblock head %}
{% block content %}

View File

@ -2,17 +2,5 @@ from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import Player, Log
from bloonsa_game.models import LevelRating
@admin.register(Player)
class PlayerAdmin(admin.ModelAdmin):
# list_display = ("id", "user")
# These lag too much
# exclude = ("bloonsa_levels_played", "bloonsa_levels_beaten")
def get_played_levels(self, obj):
return obj.bloonsa_levels_played.all()
admin.site.register(LevelRating)
admin.site.register(Log)

View File

@ -0,0 +1,21 @@
# Generated by Django 5.1.6 on 2025-02-14 20:46
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('users', '0022_rename_creationdate_player_creation_date_and_more'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterField(
model_name='player',
name='user',
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='player', to=settings.AUTH_USER_MODEL),
),
]

View File

@ -3,7 +3,7 @@ from django.utils import timezone
from django.contrib.auth.models import User
class Player(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True, related_name="player")
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="player")
# Logging
creation_ip = models.GenericIPAddressField()
latest_ip = models.GenericIPAddressField()
@ -26,7 +26,7 @@ class Player(models.Model):
return self.bloonsa_level_scores.filter(clear=True).count()
def has_beaten_bloonsa_level(self, level):
return bool(self.bloonsa_level_scores.filter(clear=True, level=level).first())
return bool(self.bloonsa_level_scores.filter(clear=True, level=level).exists())
def __str__(self):
statesDict = {

BIN
dev/designs/designs.free Normal file

Binary file not shown.