diff --git a/app/bloonsa_game/models.py b/app/bloonsa_game/models.py
index 20ccc67..a379e02 100644
--- a/app/bloonsa_game/models.py
+++ b/app/bloonsa_game/models.py
@@ -42,4 +42,4 @@ class LevelRating(models.Model):
rating = models.SmallIntegerField()
def __str__(self):
- return f"<{self.rating}> {self.level}"
\ No newline at end of file
+ return f"{self.player.first()} - [<{int(self.rating) * '★'}> - {self.level}]"
\ 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 8a6739e..a52b493 100644
--- a/app/bloonsa_game/static/bloonsa_game/css/append.css
+++ b/app/bloonsa_game/static/bloonsa_game/css/append.css
@@ -12,4 +12,14 @@
#horizontal_header {
background: #96d3ff;
+}
+
+#profile_box {
+ background-color: #28B2FF;
+ display: block;
+ float: right;
+ text-align: center;
+ margin: 10px;
+ height: 90px;
+ width: 244px;
}
\ 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
new file mode 100644
index 0000000..715dd29
--- /dev/null
+++ b/app/bloonsa_game/static/bloonsa_game/js/flash_handler.js
@@ -0,0 +1,3 @@
+function as3_new_level_started(id) {
+ console.log(id)
+}
\ No newline at end of file
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 6b78839..6fdb344 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/static/bloonsa_game/misc/bloons_unlimited_edit5.swf b/app/bloonsa_game/static/bloonsa_game/misc/bloons_unlimited_edit5.swf
new file mode 100644
index 0000000..6b78839
Binary files /dev/null and b/app/bloonsa_game/static/bloonsa_game/misc/bloons_unlimited_edit5.swf differ
diff --git a/app/bloonsa_game/templates/bloonsa_game/base.html b/app/bloonsa_game/templates/bloonsa_game/base.html
index 5f9cf23..78d5da8 100644
--- a/app/bloonsa_game/templates/bloonsa_game/base.html
+++ b/app/bloonsa_game/templates/bloonsa_game/base.html
@@ -25,8 +25,19 @@
-
+
+
+ {% if head %}
+ {{ head }}
+ {% endif %}
diff --git a/app/bloonsa_game/templates/bloonsa_game/game.html b/app/bloonsa_game/templates/bloonsa_game/game.html
index c1d2e6e..590d29a 100644
--- a/app/bloonsa_game/templates/bloonsa_game/game.html
+++ b/app/bloonsa_game/templates/bloonsa_game/game.html
@@ -5,15 +5,37 @@
{{ levelTitle }} by {{ levelAuthor }}
{% endblock title %}
+{% block head %}
+
+{% endblock head %}
+
{% block content %}
-
+ width="640" height="480" allowScriptAccess=true>
+-->
+
+
+
{% endblock content %}
\ No newline at end of file
diff --git a/app/bloonsa_game/templates/bloonsa_game/profilebox.html b/app/bloonsa_game/templates/bloonsa_game/profilebox.html
index 207e051..2402b81 100644
--- a/app/bloonsa_game/templates/bloonsa_game/profilebox.html
+++ b/app/bloonsa_game/templates/bloonsa_game/profilebox.html
@@ -1,4 +1,7 @@
+{% load bloonsa_game_tags %}
-
Welcome back {{ user }}!
+
{{ user }}
+
Levels played: {{ player.levels_played }}
+ Levels beaten: {{ player.levels_beaten }} / {{ player.total_levels }}
\ No newline at end of file
diff --git a/app/bloonsa_game/templatetags/bloonsa_game_tags.py b/app/bloonsa_game/templatetags/bloonsa_game_tags.py
new file mode 100644
index 0000000..92527b6
--- /dev/null
+++ b/app/bloonsa_game/templatetags/bloonsa_game_tags.py
@@ -0,0 +1,9 @@
+from django import template
+
+from users.models import Player
+
+register = template.Library()
+
+@register.filter
+def dummy(text):
+ return f"dummy {text}"
\ No newline at end of file
diff --git a/app/bloonsa_game/views.py b/app/bloonsa_game/views.py
index 2b08d6f..1218c15 100644
--- a/app/bloonsa_game/views.py
+++ b/app/bloonsa_game/views.py
@@ -25,19 +25,20 @@ class GameView(TemplateView):
def get(self, request, *args, **kwargs):
tag_player(request=request)
# This init is for accounts made with 'createsuperuser' or originating from bloonsb
- init_player(request=request)
+ player = init_player(request=request)
# TODO get player object here with init_player to use in html template03.3.005
if type(kwargs.get("pk")) is int:
level = Level.objects.get(id=kwargs["pk"])
if level:
return render(request, "bloonsa_game/level.html", context={
+ "player": player,
"flashVars": level.getFlashVars(seperator="&"),
"levelTitle": level.title,
"levelAuthor": level.author,
})
- return render(request, "bloonsa_game/game.html", context={})
+ return render(request, "bloonsa_game/game.html", context={"player": player})
class WIPView(TemplateView):
diff --git a/app/users/migrations/0012_alter_player_bloonsa_levelratings.py b/app/users/migrations/0012_alter_player_bloonsa_levelratings.py
new file mode 100644
index 0000000..49ee427
--- /dev/null
+++ b/app/users/migrations/0012_alter_player_bloonsa_levelratings.py
@@ -0,0 +1,19 @@
+# Generated by Django 5.1.6 on 2025-02-12 20:45
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('bloonsa_game', '0011_levelrating'),
+ ('users', '0011_player_bloonsa_levelratings_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='player',
+ name='bloonsa_levelRatings',
+ field=models.ManyToManyField(blank=True, related_name='player', to='bloonsa_game.levelrating'),
+ ),
+ ]
diff --git a/app/users/migrations/0013_alter_player_user.py b/app/users/migrations/0013_alter_player_user.py
new file mode 100644
index 0000000..7ac84a9
--- /dev/null
+++ b/app/users/migrations/0013_alter_player_user.py
@@ -0,0 +1,21 @@
+# Generated by Django 5.1.6 on 2025-02-12 21:52
+
+import django.db.models.deletion
+from django.conf import settings
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('users', '0012_alter_player_bloonsa_levelratings'),
+ migrations.swappable_dependency(settings.AUTH_USER_MODEL),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='player',
+ name='user',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='player', to=settings.AUTH_USER_MODEL),
+ ),
+ ]
diff --git a/app/users/models.py b/app/users/models.py
index 5ddc573..56b0ca7 100644
--- a/app/users/models.py
+++ b/app/users/models.py
@@ -6,23 +6,45 @@ from bloonsa_game.models import Level, LevelRating
class Player(models.Model):
- user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
+ user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True, related_name="player")
# Savedata
bloonsa_levelsPlayed = models.ManyToManyField(Level, blank=True, related_name="levelsPlayed")
bloonsa_levelsBeaten = models.ManyToManyField(Level, blank=True, related_name="levelsBeaten")
- bloonsa_levelRatings = models.ManyToManyField(LevelRating, blank=True, related_name="levelRatings")
+ bloonsa_levelRatings = models.ManyToManyField(LevelRating, blank=True, related_name="player")
# Logging
creationIP = models.GenericIPAddressField()
latestIP = models.GenericIPAddressField()
creationDate = models.DateTimeField(default=timezone.now)
latestActivity = models.DateTimeField(default=timezone.now)
- suspectedCheater = models.BooleanField(default=False)
+ suspectedCheater = models.BooleanField(default=False) # This should be set when tripping the anti-cheat
# States
- suspended = models.BooleanField(default=False)
- banned = models.BooleanField(default=False)
- admin = models.BooleanField(default=False)
+ suspended = models.BooleanField(default=False) # This is a shadow-ban, stats will still save but not all will show up on leaderboards
+ banned = models.BooleanField(default=False) # Account gets logged out upon logging in
+ admin = models.BooleanField(default=False) # Ability to suspend/ban other players
+
+ @property
+ def levels_played(self):
+ return self.bloonsa_levelsPlayed.count()
+
+ @property
+ def levels_beaten(self):
+ return self.bloonsa_levelsBeaten.count()
+
+ @property
+ def total_levels(self):
+ return Level.objects.all().count()
def __str__(self):
- return f"{self.user} - {self.latestIP}"
+ statesDict = {
+ "cheater": "😈" if self.suspectedCheater else "",
+ "suspended": "🔒" if self.suspended else "",
+ "banned": "❌" if self.banned else "",
+ "admin": "👑" if self.admin else "",
+ }
+ states = "".join(statesDict.values())
+ if states:
+ states += " "
+
+ return f"{states}{self.user} - {self.latestIP}"
diff --git a/app/users/util.py b/app/users/util.py
index f79085b..00781d6 100644
--- a/app/users/util.py
+++ b/app/users/util.py
@@ -1,3 +1,4 @@
+from django.contrib.auth import logout
from django.utils import timezone
from users.models import Player
@@ -18,12 +19,13 @@ def init_player(request):
return
player = Player.objects.filter(user=request.user).first()
if player:
- return
+ return player
ip = get_ip(request=request)
player = Player(user=request.user,
creationIP=ip,
latestIP=ip)
player.save()
+ return player
# Update activity timestamp and IP
def tag_player(request):
@@ -34,6 +36,13 @@ def tag_player(request):
player = Player.objects.filter(user=request.user).first()
if not player:
init_player(request=request)
+ if player.banned:
+ # TODO message popup?
+ logout(request)
+ return
+
player.latestActivity = timezone.now()
player.latestIP = get_ip(request=request)
- player.save()
\ No newline at end of file
+ player.save()
+
+