-
-+ +
diff --git a/app/bloonsa_api/views.py b/app/bloonsa_api/views.py index ba0ac7d..4237695 100644 --- a/app/bloonsa_api/views.py +++ b/app/bloonsa_api/views.py @@ -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) - level.played_by.add(player) + + 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) \ No newline at end of file diff --git a/app/bloonsa_game/admin.py b/app/bloonsa_game/admin.py index 1cbc983..0405576 100644 --- a/app/bloonsa_game/admin.py +++ b/app/bloonsa_game/admin.py @@ -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) \ No newline at end of file +admin.site.register(Author) \ No newline at end of file diff --git a/app/bloonsa_game/migrations/0019_levelscore_dart_glitch.py b/app/bloonsa_game/migrations/0019_levelscore_dart_glitch.py new file mode 100644 index 0000000..a805397 --- /dev/null +++ b/app/bloonsa_game/migrations/0019_levelscore_dart_glitch.py @@ -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), + ), + ] diff --git a/app/bloonsa_game/migrations/0020_alter_levelscore_darts_left_alter_levelscore_player_and_more.py b/app/bloonsa_game/migrations/0020_alter_levelscore_darts_left_alter_levelscore_player_and_more.py new file mode 100644 index 0000000..afbd797 --- /dev/null +++ b/app/bloonsa_game/migrations/0020_alter_levelscore_darts_left_alter_levelscore_player_and_more.py @@ -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, + ), + ] diff --git a/app/bloonsa_game/models.py b/app/bloonsa_game/models.py index b2d75b6..8feaa80 100644 --- a/app/bloonsa_game/models.py +++ b/app/bloonsa_game/models.py @@ -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}") \ No newline at end of file diff --git a/app/bloonsa_game/static/bloonsa_game/css/append.css b/app/bloonsa_game/static/bloonsa_game/css/append.css index a0d7234..5a530b1 100644 --- a/app/bloonsa_game/static/bloonsa_game/css/append.css +++ b/app/bloonsa_game/static/bloonsa_game/css/append.css @@ -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 { } \ No newline at end of file diff --git a/app/bloonsa_game/static/bloonsa_game/js/flash_handler.js b/app/bloonsa_game/static/bloonsa_game/js/flash_handler.js index 2ce2274..70e7ece 100644 --- a/app/bloonsa_game/static/bloonsa_game/js/flash_handler.js +++ b/app/bloonsa_game/static/bloonsa_game/js/flash_handler.js @@ -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}`; diff --git a/app/bloonsa_game/static/bloonsa_game/misc/bloons_unlimited.swf b/app/bloonsa_game/static/bloonsa_game/misc/bloons_unlimited.swf index 487ff00..8a76161 100644 Binary files a/app/bloonsa_game/static/bloonsa_game/misc/bloons_unlimited.swf and b/app/bloonsa_game/static/bloonsa_game/misc/bloons_unlimited.swf differ diff --git a/app/bloonsa_game/templates/bloonsa_game/base.html b/app/bloonsa_game/templates/bloonsa_game/base.html index cd3e669..4c08920 100644 --- a/app/bloonsa_game/templates/bloonsa_game/base.html +++ b/app/bloonsa_game/templates/bloonsa_game/base.html @@ -68,10 +68,10 @@
-
-