implement rank system

This commit is contained in:
Walter 2025-02-24 15:07:38 +01:00
parent 65c924c3a8
commit 93a9ffb268
11 changed files with 187 additions and 23 deletions

View File

@ -51,7 +51,6 @@ class Level(models.Model):
result = list(self.bloonsa_level_ratings.aggregate(Avg("rating")).values())[0] result = list(self.bloonsa_level_ratings.aggregate(Avg("rating")).values())[0]
return 0 if result is None else round(result) return 0 if result is None else round(result)
def __str__(self): def __str__(self):
return f"{self.level_id}: {self.author.name} - {self.title}" return f"{self.level_id}: {self.author.name} - {self.title}"

View File

@ -109,3 +109,10 @@
.invisible { .invisible {
visibility: hidden; visibility: hidden;
} }
#global-leaderboard-iframe {
height: 629px;
width: 160px;
overflow: hidden;
}

View File

@ -0,0 +1,72 @@
#glb-global {
height: 629px;
width: 160px;
font-family: "Comic Sans MS", "Comic Sans", cursive;
color: white;
font-size: 13px;
text-align: left;
white-space: nowrap;
margin: 0;
}
.rowa {
background-color: #563EAB;
}
.rowb {
background-color: #6B0047;
}
.glb-position {
color: #ffcf24;
}
.glb-username {
z-index: 100;
position: relative;
}
.glb-entry {
height: 56px;
width: 160px;
display: flex;
flex-direction: row;
}
.glb-main-info {
display: flex;
flex-direction: column;
width: 62px;
}
.glb-rank-box {
display: flex;
flex-direction: column;
}
.glb-avatar {
height: 48px;
width: 48px;
margin: 2px;
border-style: solid;
border-width: 2px;
border-color: black;
}
.glb-wins-img, .glb-darts-img {
height: 15px;
width: 15px;
margin: 0;
}
.glb-volforce {
font-size: 15px;
color: #FF00AA;
text-align: left;
}
.glb-rank-icon {
}
body {
margin: 0;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

View File

@ -27,6 +27,7 @@
<link rel="stylesheet" type="text/css" media="screen" href="{% static 'bloonsa_game/css/main.css' %}"/> <link rel="stylesheet" type="text/css" media="screen" href="{% static 'bloonsa_game/css/main.css' %}"/>
<link rel="stylesheet" type="text/css" media="screen" href="{% static 'bloonsa_game/css/append.css' %}"/> <link rel="stylesheet" type="text/css" media="screen" href="{% static 'bloonsa_game/css/append.css' %}"/>
{% block head %}{% endblock head %} {% block head %}{% endblock head %}
</head> </head>
@ -47,6 +48,13 @@
</div> </div>
<div class="skyscraper" id="skyscraper-l"> <div class="skyscraper" id="skyscraper-l">
<iframe id="global-leaderboard-iframe"
frameborder="0"
scrolling="no"
sandbox="allow-same-origin"
onload="this.style.height=(this.contentWindow.document.body.scrollHeight+20)+'px';"
src="{% url 'bloonsa_game:leaderboard_global' %}"></iframe>
{% include 'bloonsa_game/modules/leaderboard_global.html' %}
</div> </div>
<div id="content"> <div id="content">
{% block content %}{% endblock content %} {% block content %}{% endblock content %}
@ -77,19 +85,9 @@
</div> </div>
</div> </div>
</div> </div>
<div id="adholder1"> <div id="adholder1"></div>
<script type="text/javascript"><!--
e9 = new Object();
e9.size = "728x90";
//--></script>
</div>
<div id="adholder2"></div> <div id="adholder2"></div>
<div id="adholder3"> <div id="adholder3"></div>
<script type="text/javascript"><!--
e9 = new Object();
e9.size = "160x600";
//--></script></div>
<script type="text/javascript"> <script type="text/javascript">
document.getElementById('adslot1').appendChild(document.getElementById('adholder1')); document.getElementById('adslot1').appendChild(document.getElementById('adholder1'));

View File

@ -0,0 +1,38 @@
{% load static %}
{% load bloonsa_game_tags %}
<link rel="stylesheet" type="text/css" media="screen" href="{% static 'bloonsa_game/css/leaderboard_global.css' %}"/>
<link rel="stylesheet" type="text/css" media="screen" href="{% static 'bloonsa_game/css/append.css' %}"/>
<div id="glb-global">
{% for player in players %}
<div class="rowa glb-entry">
<div class="glb-avatar-box">
<img class="glb-avatar" src="{{ player.avatar.url }}" height=48px width=48px>
</div>
<div class="glb-main-info">
<div class="glb-user">
<span class="glb-position">#{{ forloop.counter }}</span>
<span class="glb-username">{{ player.user.username }}</span>
</div>
<div class="glb-wins-box">
<object data="{% static 'bloonsa_game/img/levelinfo/wins.svg' %}"
class="filter-orange glb-wins-img"
type="image/svg+xml"></object>
<span>{{ player.bloonsa_levels_beaten_count }}</span>
</div>
<div class="glb-gdarts-box">
<object data="{% static 'bloonsa_game/img/levelinfo/dart.svg' %}"
class="filter-orange glb-darts-img"
type="image/svg+xml"></object>
<span>{{ player.bloonsa_dart_glitch_count }}</span>
</div>
</div>
<div class="glb-rank-box">
<img src="{% static 'bloonsa_game/img/ranks/'|concat:player.bloonsa_rank|concat:'.png' %}"
height=36px width=36px
class="glb-rank-icon">
<span class="glb-volforce">{{ player.bloonsa_volforce_rating }}</span>
</div>
</div>
{% endfor %}
</div>

View File

@ -12,3 +12,7 @@ def dummy(text):
@register.simple_tag(name="bloonsa_total_levels") @register.simple_tag(name="bloonsa_total_levels")
def total_levels(): def total_levels():
return int(Level.objects.count()) return int(Level.objects.count())
@register.filter
def concat(arg1, arg2):
return str(arg1) + str(arg2)

View File

@ -1,14 +1,15 @@
from django.urls import path, include from django.urls import path, include
from django.views.generic import RedirectView from django.views.generic import RedirectView
from bloonsa_game.views import IndexView, TermsView, GameView, WIPView from bloonsa_game.views import IndexView, TermsView, GameView, LeaderboardGlobalView
app_name = "bloonsa_game" app_name = "bloonsa_game"
urlpatterns = [ urlpatterns = [
path("", RedirectView.as_view(pattern_name="bloonsa_game:game", permanent=False), name="index"), path("", RedirectView.as_view(pattern_name="bloonsa_game:game", permanent=False), name="index"),
path("game", GameView.as_view(), name="game"), path("game", GameView.as_view(), name="game"),
path("game/<int:pk>", GameView.as_view(), name="gameSelect"), path("game/<int:pk>", GameView.as_view(), name="game_select"),
path("leaderboard_global", LeaderboardGlobalView.as_view(), name="leaderboard_global")
# path("terms", TermsView.as_view(), name="terms"), # path("terms", TermsView.as_view(), name="terms"),
# path("contact", WIPView.as_view(), name="contact"), # path("contact", WIPView.as_view(), name="contact"),
] ]

View File

@ -1,7 +1,10 @@
from django.db.models import F, BooleanField, IntegerField, ExpressionWrapper, Count, Sum, DecimalField
from django.db.models.functions import Cast
from django.shortcuts import render from django.shortcuts import render
from django.views.generic import TemplateView from django.views.generic import TemplateView
from bloonsa_game.models import Level from bloonsa_game.models import Level
from users.models import Player
from users.util import bloonsa_util, actions from users.util import bloonsa_util, actions
@ -33,13 +36,28 @@ class GameView(TemplateView):
"total_levels": total_levels, "total_levels": total_levels,
"flashVars": level.get_flash_vars(seperator="&"), "flashVars": level.get_flash_vars(seperator="&"),
}) })
return render(request, "bloonsa_game/game.html",
r = render(request, "bloonsa_game/game.html",
context={"total_levels": total_levels,}) context={"total_levels": total_levels,})
r["x-frame-options"] = "sameorigin"
return r
class WIPView(TemplateView):
class LeaderboardGlobalView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return render(request, "bloonsa_game/error.html", context={}) # Get top 100 best players
players = Player.objects.annotate(
def post(self, request, *args, **kwargs): clears=Count(F("bloonsa_level_scores__clear")),
return render(request, "bloonsa_game/error.html", context={}) golds=Count(F("bloonsa_level_scores__dart_glitch_ever"))
).annotate(
volforce=F("clears") + F("golds")
).order_by("-volforce")[:100]
for player in players:
print(player.bloonsa_volforce_rating)
r = render(request, "bloonsa_game/modules/leaderboard_global.html",
context={
"players": players
})
r["x-frame-options"] = "sameorigin"
return r

View File

@ -1,3 +1,5 @@
import math
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from django.contrib.auth.models import User from django.contrib.auth.models import User
@ -50,6 +52,31 @@ class Player(models.Model):
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).exists()) return bool(self.bloonsa_level_scores.filter(clear=True, level=level).exists())
@property
def bloonsa_dart_glitch_count(self):
return self.bloonsa_level_scores.filter(dart_glitch_ever=True).count()
@property
def bloonsa_volforce_rating(self):
total_levels = 66396
beaten_levels = self.bloonsa_levels_beaten_count
gold_levels = self.bloonsa_dart_glitch_count
estimated_limit = total_levels + ((total_levels / 100) * 20)
estimated_max_rank = 80.00
player_score = beaten_levels + gold_levels
player_volforce = player_score * (estimated_max_rank / estimated_limit)
import random
player_volforce = random.randint(100, 2700) / 100
return "{:.2f}".format(player_volforce)
@property
def bloonsa_rank(self):
return math.floor(float(self.bloonsa_volforce_rating) / 100) + 1
def __str__(self): def __str__(self):
statesDict = { statesDict = {
"cheater": "😈" if self.suspected_cheater else "", "cheater": "😈" if self.suspected_cheater else "",

Binary file not shown.