Added dart_glitch field
This commit is contained in:
parent
c200728f51
commit
dec147f0ff
@ -49,7 +49,10 @@ class RandomLevel(CSRFexemptTemplateView):
|
|||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
bloonsa_util.tag_player(request=request)
|
bloonsa_util.tag_player(request=request)
|
||||||
player: Player = Player.objects.get(user=request.user)
|
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.played_by.add(player)
|
||||||
|
level.save()
|
||||||
bloonsa_util.log(player=player,
|
bloonsa_util.log(player=player,
|
||||||
action=actions.bloonsa_load_random_level,
|
action=actions.bloonsa_load_random_level,
|
||||||
note=level.level_id)
|
note=level.level_id)
|
||||||
@ -69,18 +72,21 @@ class CompleteLevel(CSRFexemptTemplateView):
|
|||||||
bloonsa_util.tag_player(request=request)
|
bloonsa_util.tag_player(request=request)
|
||||||
level_id = int(request.POST.get("level_id"))
|
level_id = int(request.POST.get("level_id"))
|
||||||
darts_left = int(request.POST.get("darts_left"))
|
darts_left = int(request.POST.get("darts_left"))
|
||||||
|
dart_glitch = bool(request.POST.get("dart_glitch"))
|
||||||
pops = int(request.POST.get("pops"))
|
pops = int(request.POST.get("pops"))
|
||||||
|
|
||||||
level: Level = Level.objects.get(level_id=level_id)
|
level: Level = Level.objects.get(level_id=level_id)
|
||||||
player: Player = Player.objects.get(user=request.user)
|
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 \
|
if prevScore is None \
|
||||||
or pops > prevScore.pops \
|
or pops > prevScore.pops \
|
||||||
or pops == prevScore.pops and darts_left > prevScore.darts_left:
|
or pops == prevScore.pops and darts_left > prevScore.darts_left:
|
||||||
score = LevelScore.objects.create(level=level,
|
score = LevelScore.objects.create(level=level,
|
||||||
clear=True,
|
clear=True,
|
||||||
darts_left=darts_left,
|
darts_left=darts_left,
|
||||||
|
dart_glitch=dart_glitch,
|
||||||
pops=pops)
|
pops=pops)
|
||||||
if prevScore:
|
if prevScore:
|
||||||
player.bloonsa_level_scores.remove(prevScore)
|
player.bloonsa_level_scores.remove(prevScore)
|
||||||
@ -123,14 +129,15 @@ class RateLevel(CSRFexemptTemplateView):
|
|||||||
return HttpResponse(content="OK", status=200)
|
return HttpResponse(content="OK", status=200)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class GetStatusData(CSRFexemptTemplateView):
|
class GetStatusData(CSRFexemptTemplateView):
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
bloonsa_util.tag_player(request=request)
|
bloonsa_util.tag_player(request=request)
|
||||||
level_id = int(json.loads(request.body).get("level_id"))
|
level_id = int(json.loads(request.body).get("level_id"))
|
||||||
level = Level.objects.get(level_id=level_id)
|
level: Level = Level.objects.get(level_id=level_id)
|
||||||
player = Player.objects.get(user=request.user)
|
player: Player = Player.objects.get(user=request.user)
|
||||||
|
score: LevelScore = LevelScore.objects.filter(player=player,
|
||||||
|
level=level).first()
|
||||||
total_levels = Level.objects.count()
|
total_levels = Level.objects.count()
|
||||||
level_cleared = player.has_beaten_bloonsa_level(level=level)
|
level_cleared = player.has_beaten_bloonsa_level(level=level)
|
||||||
|
|
||||||
@ -148,4 +155,11 @@ class GetStatusData(CSRFexemptTemplateView):
|
|||||||
"level_rating": level.rating,
|
"level_rating": level.rating,
|
||||||
"level_cleared": level_cleared,
|
"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)
|
return JsonResponse(jdata)
|
||||||
@ -1,7 +1,14 @@
|
|||||||
from django.contrib import admin
|
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(Level)
|
||||||
admin.site.register(Author)
|
admin.site.register(Author)
|
||||||
admin.site.register(LevelScore)
|
|
||||||
18
app/bloonsa_game/migrations/0019_levelscore_dart_glitch.py
Normal file
18
app/bloonsa_game/migrations/0019_levelscore_dart_glitch.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -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,
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -53,19 +53,20 @@ class LevelRating(models.Model):
|
|||||||
MaxValueValidator(10)])
|
MaxValueValidator(10)])
|
||||||
|
|
||||||
def __str__(self):
|
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}]")
|
f" - [<{int(self.rating) * '★'}> - {self.level.title}]")
|
||||||
|
|
||||||
# There should only be 1 score per player
|
# There should only be 1 score per player
|
||||||
# Highest popcount wins
|
# Highest popcount wins
|
||||||
class LevelScore(models.Model):
|
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)
|
level = models.ForeignKey(Level, on_delete=models.CASCADE)
|
||||||
clear = models.BooleanField(default=True) # This is for if we ever submit scores for failed attempts
|
clear = models.BooleanField(default=True) # This is for if we ever submit scores for failed attempts
|
||||||
darts_left = models.PositiveSmallIntegerField(null=True)
|
darts_left = models.PositiveSmallIntegerField()
|
||||||
pops = models.PositiveSmallIntegerField(null=True)
|
dart_glitch = models.BooleanField(default=False) # This is triggered when the player lingers their last dart
|
||||||
|
pops = models.PositiveSmallIntegerField()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
clearState = "✅" if self.clear else "❌"
|
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}")
|
f"🎈{self.pops} | 🎯{self.darts_left}")
|
||||||
@ -28,23 +28,23 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
#level-title,
|
#level_title,
|
||||||
#level-id,
|
#level_id,
|
||||||
#level-author,
|
#level_author,
|
||||||
#level-author-id
|
#level_author-id
|
||||||
#level-clear-state {
|
#level_clear_state {
|
||||||
white-space: break-spaces;
|
white-space: break-spaces;
|
||||||
float: left;
|
float: left;
|
||||||
padding-left: 0px;
|
padding-left: 0px;
|
||||||
padding-right: 10px;
|
padding-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#level-id,
|
#level_id,
|
||||||
#level-author-id {
|
#level_author_id {
|
||||||
color: #59b1ff;
|
color: #59b1ff;
|
||||||
}
|
}
|
||||||
|
|
||||||
#current-level-container {
|
#current_level_container {
|
||||||
height: 110px;
|
height: 110px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -61,6 +61,6 @@
|
|||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#level-clear-state {
|
#level_clear_state {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -30,12 +30,14 @@ function bloonsa_update_data(level_id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function bloonsa_update_html(r) {
|
function bloonsa_update_html(r) {
|
||||||
document.getElementById("level-title").textContent = r.level_title;
|
document.getElementById("level_title").textContent = r.level_title;
|
||||||
document.getElementById("level-id").textContent = `(${r.level_id})`;
|
document.getElementById("level_id").textContent = `(${r.level_id})`;
|
||||||
document.getElementById("level-author").textContent = `by ${r.level_author_name}`;
|
document.getElementById("level_author").textContent = `by ${r.level_author_name}`;
|
||||||
document.getElementById("level-author-id").textContent = `(${r.level_author_id})`;
|
document.getElementById("level_author_id").textContent = `(${r.level_author_id})`;
|
||||||
if (r.level_cleared) {
|
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_played").textContent = `${r.bloonsa_levels_played}`;
|
||||||
document.getElementById("levels_beaten").textContent = `${r.bloonsa_levels_beaten}`;
|
document.getElementById("levels_beaten").textContent = `${r.bloonsa_levels_beaten}`;
|
||||||
|
|||||||
Binary file not shown.
@ -68,10 +68,10 @@
|
|||||||
<div id="content">
|
<div id="content">
|
||||||
{% block content %}{% endblock content %}
|
{% block content %}{% endblock content %}
|
||||||
|
|
||||||
<div id="current-level-container" class="wide left">
|
<div id="current_level_container" class="wide left">
|
||||||
<p>
|
<p>
|
||||||
<h1 id="level-title"></h1><h1 id="level-id"></h1><h1 id="level-clear-state"></h1><h1></h1>
|
<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>
|
<h3 id="level_author"></h3><h3 id="level_author_id"></h3><br>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
{% endblock title %}
|
{% endblock title %}
|
||||||
|
|
||||||
{% block head %}
|
{% block head %}
|
||||||
|
|
||||||
{% endblock head %}
|
{% endblock head %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
|||||||
@ -2,17 +2,5 @@ from django.contrib import admin
|
|||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
|
|
||||||
from .models import Player, Log
|
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)
|
admin.site.register(Log)
|
||||||
|
|||||||
21
app/users/migrations/0023_alter_player_user.py
Normal file
21
app/users/migrations/0023_alter_player_user.py
Normal 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),
|
||||||
|
),
|
||||||
|
]
|
||||||
@ -3,7 +3,7 @@ from django.utils import timezone
|
|||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|
||||||
class Player(models.Model):
|
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
|
# Logging
|
||||||
creation_ip = models.GenericIPAddressField()
|
creation_ip = models.GenericIPAddressField()
|
||||||
latest_ip = models.GenericIPAddressField()
|
latest_ip = models.GenericIPAddressField()
|
||||||
@ -26,7 +26,7 @@ class Player(models.Model):
|
|||||||
return self.bloonsa_level_scores.filter(clear=True).count()
|
return self.bloonsa_level_scores.filter(clear=True).count()
|
||||||
|
|
||||||
def has_beaten_bloonsa_level(self, level):
|
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):
|
def __str__(self):
|
||||||
statesDict = {
|
statesDict = {
|
||||||
|
|||||||
BIN
dev/designs/designs.free
Normal file
BIN
dev/designs/designs.free
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user