Added dart_glitch_ever field
This commit is contained in:
parent
15e046fab4
commit
5ee47ecdcb
@ -2,6 +2,7 @@ import json
|
||||
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Q
|
||||
from django.shortcuts import render, HttpResponse
|
||||
from django.http import HttpResponseBadRequest, JsonResponse
|
||||
from django.views.generic import TemplateView
|
||||
@ -43,20 +44,24 @@ class LoadLevel(CSRFexemptTemplateView):
|
||||
|
||||
class RandomLevel(CSRFexemptTemplateView):
|
||||
def post(self, request, *args, **kwargs):
|
||||
level: Level = Level.objects.order_by("?").first()
|
||||
flashVars = level.get_flash_vars(seperator="&")
|
||||
|
||||
if request.user.is_authenticated:
|
||||
bloonsa_util.tag_player(request=request)
|
||||
player: Player = Player.objects.get(user=request.user)
|
||||
|
||||
level: Level = Level.objects.order_by("?").filter(~Q(played_by=player)).first()
|
||||
if not level:
|
||||
level: Level = Level.objects.order_by("?").first()
|
||||
|
||||
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)
|
||||
else:
|
||||
level: Level = Level.objects.order_by("?").first()
|
||||
|
||||
flashVars = level.get_flash_vars(seperator="&")
|
||||
return HttpResponse(flashVars)
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
@ -79,22 +84,42 @@ class CompleteLevel(CSRFexemptTemplateView):
|
||||
level: Level = Level.objects.get(level_id=level_id)
|
||||
player: Player = Player.objects.get(user=request.user)
|
||||
|
||||
prevScore = LevelScore.objects.filter(player=player,
|
||||
score = LevelScore.objects.filter(player=player,
|
||||
level=level).first()
|
||||
if prevScore is None \
|
||||
or pops > prevScore.pops \
|
||||
or pops == prevScore.pops and darts_left + int(dart_glitch) > prevScore.darts_left:
|
||||
clear = pops >= level.target
|
||||
|
||||
if score is None:
|
||||
score = LevelScore.objects.create(level=level,
|
||||
clear=True,
|
||||
clear=clear,
|
||||
darts_left=darts_left,
|
||||
dart_glitch=dart_glitch,
|
||||
dart_glitch_ever=dart_glitch,
|
||||
pops=pops)
|
||||
if prevScore:
|
||||
prevScore.delete()
|
||||
|
||||
player.bloonsa_level_scores.add(score)
|
||||
score.save()
|
||||
player.save()
|
||||
|
||||
# Check if score is an improvement
|
||||
elif any((
|
||||
pops > score.pops,
|
||||
pops == score.pops and darts_left + int(dart_glitch) > score.darts_left,
|
||||
clear and not score.clear
|
||||
)):
|
||||
# Has dart glitch ever been done in a score?
|
||||
dart_glitch_ever = bool(dart_glitch or score.dart_glitch_ever or score.dart_glitch)
|
||||
|
||||
score.update(commit=True,
|
||||
clear=clear,
|
||||
darts_left=darts_left,
|
||||
dart_glitch=dart_glitch,
|
||||
dart_glitch_ever=dart_glitch_ever,
|
||||
pops=pops)
|
||||
|
||||
# Check if we just did a dart glitch for fun
|
||||
elif dart_glitch:
|
||||
score.update(commit=True,
|
||||
dart_glitch_ever=True)
|
||||
|
||||
bloonsa_util.log(player=player,
|
||||
action=actions.bloonsa_submit_score,
|
||||
note=level.level_id)
|
||||
@ -137,22 +162,13 @@ class GetStatusData(CSRFexemptTemplateView):
|
||||
level_id = int(json.loads(request.body).get("level_id"))
|
||||
|
||||
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)
|
||||
level_plays = level.play_count
|
||||
level_wins = level.win_count
|
||||
level_win_percentage = 0.00 if level_wins == 0 else level_wins / level_plays
|
||||
dart_glitch_count = level.dart_glitch_count
|
||||
|
||||
jdata = {
|
||||
"bloonsa_levels_played": player.bloonsa_levels_played_count,
|
||||
"bloonsa_levels_beaten": player.bloonsa_levels_beaten_count,
|
||||
"bloonsa_total_levels": total_levels,
|
||||
|
||||
"level_author_name": level.author.name,
|
||||
"level_author_id": level.author.id,
|
||||
"level_title": level.title,
|
||||
@ -161,18 +177,30 @@ class GetStatusData(CSRFexemptTemplateView):
|
||||
"level_legacy_rating": level.rating,
|
||||
"level_darts": level.darts,
|
||||
"level_target": level.target,
|
||||
"level_cleared": level_cleared,
|
||||
"level_rating": level.stars,
|
||||
"level_plays": level_plays,
|
||||
"level_wins": level_wins,
|
||||
"level_win_percentage": level_win_percentage,
|
||||
"dart_glitch_count": dart_glitch_count,
|
||||
|
||||
}
|
||||
|
||||
if request.user.is_authenticated:
|
||||
player: Player = Player.objects.get(user=request.user)
|
||||
score: LevelScore = LevelScore.objects.filter(player=player,
|
||||
level=level).first()
|
||||
level_cleared = player.has_beaten_bloonsa_level(level=level)
|
||||
|
||||
jdata.update({
|
||||
"bloonsa_levels_played": player.bloonsa_levels_played_count,
|
||||
"bloonsa_levels_beaten": player.bloonsa_levels_beaten_count,
|
||||
"bloonsa_total_levels": total_levels,
|
||||
"level_cleared": level_cleared,
|
||||
})
|
||||
if score:
|
||||
jdata.update({
|
||||
"score_darts_left": score.darts_left,
|
||||
"score_dart_glitch": score.dart_glitch,
|
||||
"score_dart_glitch_ever": score.dart_glitch_ever,
|
||||
"score_pops": score.pops,
|
||||
})
|
||||
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.1.6 on 2025-02-17 23:35
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('bloonsa_game', '0022_alter_levelrating_level'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='levelscore',
|
||||
name='dart_glitch_ever',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@ -4,8 +4,17 @@ from django.db.models import Avg
|
||||
|
||||
from users.models import Player
|
||||
|
||||
class ModelWithUpdate(models.Model):
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
class Author(models.Model):
|
||||
def update(self, commit=False, **kwargs):
|
||||
for key, value in kwargs.items():
|
||||
setattr(self, key, value)
|
||||
if commit:
|
||||
self.save()
|
||||
|
||||
class Author(ModelWithUpdate):
|
||||
name = models.CharField(max_length=255)
|
||||
author_id = models.IntegerField()
|
||||
|
||||
@ -19,7 +28,7 @@ class Level(models.Model):
|
||||
darts = models.SmallIntegerField()
|
||||
target = models.SmallIntegerField()
|
||||
plays = models.IntegerField()
|
||||
beats = models.IntegerField() # TODO can be removed?
|
||||
beats = models.IntegerField()
|
||||
rating = models.FloatField(null=True, blank=True)
|
||||
data = models.CharField(max_length=288)
|
||||
|
||||
@ -35,7 +44,7 @@ class Level(models.Model):
|
||||
|
||||
@property
|
||||
def dart_glitch_count(self):
|
||||
return LevelScore.objects.filter(level=self, dart_glitch=True).count()
|
||||
return LevelScore.objects.filter(level=self, dart_glitch_ever=True).count()
|
||||
|
||||
@property
|
||||
def stars(self):
|
||||
@ -44,7 +53,7 @@ class Level(models.Model):
|
||||
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.author} - {self.title}"
|
||||
return f"{self.level_id}: {self.author.name} - {self.title}"
|
||||
|
||||
def get_flash_vars(self, seperator):
|
||||
flashVars = {
|
||||
@ -61,7 +70,7 @@ class Level(models.Model):
|
||||
return flashVarsStr
|
||||
|
||||
|
||||
class LevelRating(models.Model):
|
||||
class LevelRating(ModelWithUpdate):
|
||||
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="bloonsa_level_ratings", null=True)
|
||||
level = models.ForeignKey(Level, on_delete=models.CASCADE, related_name="bloonsa_level_ratings")
|
||||
rating = models.SmallIntegerField(validators=[MinValueValidator(1),
|
||||
@ -74,16 +83,18 @@ class LevelRating(models.Model):
|
||||
|
||||
# There should only be 1 score per player
|
||||
# Highest popcount wins
|
||||
class LevelScore(models.Model):
|
||||
class LevelScore(ModelWithUpdate):
|
||||
player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name="bloonsa_level_scores", null=True)
|
||||
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()
|
||||
dart_glitch = models.BooleanField(default=False) # This is triggered when the player lingers their last dart
|
||||
dart_glitch_ever = models.BooleanField(default=False) # If they ever performed dart glitch in the past
|
||||
pops = models.PositiveSmallIntegerField()
|
||||
|
||||
def __str__(self):
|
||||
clearState = "✅" if self.clear else "❌"
|
||||
scoreView = f"🎈{self.pops} | 🎯{self.darts_left} {'✏' if self.dart_glitch else ''}"
|
||||
clear_state = "✅" if self.clear else "❌"
|
||||
dart_glitch_state = "✏" if self.dart_glitch else "🖋" if self.dart_glitch_ever else ""
|
||||
score_view = f"🎈{self.pops} | 🎯{self.darts_left} {dart_glitch_state}"
|
||||
return (f"{self.player.user.username if self.player else ''}'s "
|
||||
f"{clearState} @ {self.level.title}: {scoreView}")
|
||||
f"{clear_state} @ {self.level}: {score_view}")
|
||||
5
app/bloonsa_game/static/bloonsa_game/css/game.css
Normal file
5
app/bloonsa_game/static/bloonsa_game/css/game.css
Normal file
@ -0,0 +1,5 @@
|
||||
#bloonsa-game {
|
||||
width: 640px;
|
||||
height: 480px;
|
||||
background-color: #20B0FF;
|
||||
}
|
||||
@ -87,19 +87,25 @@
|
||||
}
|
||||
|
||||
.filter-red {
|
||||
filter: invert(61%) sepia(72%) saturate(7291%) hue-rotate(338deg) brightness(108%) contrast(101%); // red
|
||||
filter: invert(61%) sepia(72%) saturate(7291%) hue-rotate(338deg) brightness(108%) contrast(101%);
|
||||
}
|
||||
.filter-grey {
|
||||
filter: invert(17%) sepia(2%) saturate(72%) hue-rotate(66deg) brightness(94%) contrast(89%); // grey
|
||||
filter: invert(17%) sepia(2%) saturate(72%) hue-rotate(66deg) brightness(94%) contrast(89%);
|
||||
}
|
||||
.filter-black {
|
||||
filter: invert(0%) sepia(96%) saturate(15%) hue-rotate(246deg) brightness(105%) contrast(105%); // black
|
||||
filter: invert(0%) sepia(96%) saturate(15%) hue-rotate(246deg) brightness(105%) contrast(105%);
|
||||
}
|
||||
.filter-softblue {
|
||||
filter: invert(53%) sepia(93%) saturate(488%) hue-rotate(182deg) brightness(103%) contrast(103%);
|
||||
}
|
||||
.filter-orange {
|
||||
filter: invert(75%) sepia(23%) saturate(6404%) hue-rotate(355deg) brightness(98%) contrast(107%) !important; // orange
|
||||
filter: invert(75%) sepia(23%) saturate(6404%) hue-rotate(355deg) brightness(98%) contrast(107%) !important;
|
||||
}
|
||||
.filter-purple {
|
||||
filter: invert(14%) sepia(92%) saturate(7496%) hue-rotate(299deg) brightness(91%) contrast(106%); !important;
|
||||
}
|
||||
.filter-pink {
|
||||
filter: invert(65%) sepia(38%) saturate(4716%) hue-rotate(268deg) brightness(102%) contrast(102%);
|
||||
}
|
||||
|
||||
.invisible {
|
||||
|
||||
@ -4,6 +4,9 @@ function bloonsa_new_level_started(level_id) {
|
||||
}
|
||||
|
||||
function bloonsa_level_completed(level_id) {
|
||||
if (document.getElementById("login_box") != null) {
|
||||
return
|
||||
}
|
||||
console.log("call to bloonsa_level_completed");
|
||||
bloonsa_update_data(level_id)
|
||||
}
|
||||
@ -13,8 +16,14 @@ function bloonsa_rated_level_success(level_id) {
|
||||
bloonsa_update_data(level_id)
|
||||
}
|
||||
|
||||
// TODO only update neccessary parts
|
||||
// eg: new_level_started -> level info box
|
||||
// level_completed -> all
|
||||
// level_rated -> level info box
|
||||
|
||||
|
||||
function bloonsa_update_data(level_id) {
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
console.log("call to update_data");
|
||||
xhr.open("POST", "/bloonsa_api/get_status_data", true);
|
||||
@ -70,6 +79,10 @@ function bloonsa_update_html(r) {
|
||||
document.getElementById("level-glitch-number").textContent = r.dart_glitch_count;
|
||||
|
||||
// Personal best
|
||||
if (document.getElementById("login_box") != null) {
|
||||
document.getElementById("level-pb").remove();
|
||||
return
|
||||
}
|
||||
var darts_img = document.getElementById("level-pb-darts-img");
|
||||
if ("score_pops" in r) {
|
||||
document.getElementById("level-pb-pops-number").textContent = r.score_pops;
|
||||
@ -77,7 +90,7 @@ function bloonsa_update_html(r) {
|
||||
document.getElementById("level-pb-darts-number").textContent = r.score_darts_left;
|
||||
document.getElementById("level-pb-darts-glitch").textContent = r.score_dart_glitch ? "+1": "";
|
||||
|
||||
if (r.score_dart_glitch) {
|
||||
if (r.score_dart_glitch | r.score_dart_glitch_ever) {
|
||||
darts_img.classList.add("filter-orange");
|
||||
} else {
|
||||
darts_img.classList.remove("filter-orange");
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
};</script>
|
||||
<script src="{% static 'bloonsa_game/misc/ruffle/ruffle.js' %}"></script>
|
||||
<script src="{% static 'bloonsa_game/js/flash_handler.js' %}"></script>
|
||||
<link rel="stylesheet" type="text/css" media="screen" href="{% static 'bloonsa_game/css/game.css' %}"/>
|
||||
{% endblock head %}
|
||||
|
||||
{% block content %}
|
||||
@ -34,7 +35,7 @@
|
||||
player.load({
|
||||
url: "{% static 'bloonsa_game/misc/bloons_unlimited.swf' %}?{{ flashVars | safe }}",
|
||||
allowScriptAccess: true,
|
||||
backgroundColor: "#000",
|
||||
// backgroundColor: "#000",
|
||||
});
|
||||
player.style.width = "640px";
|
||||
player.style.height = "480px";
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
{% extends 'game/base.html' %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
||||
codebase="{% static 'game/misc/swflash.cab' %}#version=7,0,19,0"
|
||||
width="640" height="480" title="Confusing">
|
||||
<param name="movie" value="{% static 'game/misc/bloons_unlimited.swf' %}">
|
||||
<param name="quality" value="high">
|
||||
<param name="FlashVars"
|
||||
value="&{{flashVars}}">
|
||||
<embed src="{% static 'game/misc/bloons_unlimited.swf' %}"
|
||||
quality="high"
|
||||
pluginspage="http://www.macromedia.com/go/getflashplayer"
|
||||
type="application/x-shockwave-flash"
|
||||
width="640" height="480" flashvars="&{{flashVars}}">
|
||||
</object>
|
||||
|
||||
|
||||
<div class="wide">
|
||||
Move the mouse to aim the arrow, and press and hold the left mouse button to select the power of your throw. Pop the minimum number of bloons to pass each level. You can rate the levels you play by clicking the 'rate level' button in the game screen. You can also go to another random level by clicking 'Go random' at any time.</div> <div class="wide centered">
|
||||
Copyright Kaiparasoft 2007, all rights reserved<br/>
|
||||
<a href="https://web.archive.org/web/20140327034910/http://www.ninjakiwi.com/">Ninjakiwi</a>
|
||||
- <a href="/web/20140327034910/http://www.bloonsworld.com/symfony/terms">Terms of Use</a>
|
||||
- <a href="/web/20140327034910/http://www.bloonsworld.com/symfony/contact_us">Contact Us</a>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
Loading…
Reference in New Issue
Block a user