AstraOS Ver. 1.37:
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
All checks were successful
Deploy AstraOS Panel / deploy (push) Successful in 12s
- AyranTracker bearbeitet (smurf score hinzugefügt)
This commit is contained in:
parent
d3ecd7deb9
commit
a0246e9f6b
|
|
@ -30,6 +30,7 @@
|
||||||
<div id="profileSection" class="w-full hidden">
|
<div id="profileSection" class="w-full hidden">
|
||||||
|
|
||||||
<div class="bg-slate-950/60 border border-purple-900/30 rounded-2xl p-6 flex flex-col md:flex-row justify-between items-center gap-6 mb-6 backdrop-blur-md">
|
<div class="bg-slate-950/60 border border-purple-900/30 rounded-2xl p-6 flex flex-col md:flex-row justify-between items-center gap-6 mb-6 backdrop-blur-md">
|
||||||
|
|
||||||
<div class="flex items-center space-x-4 text-center md:text-left flex-col md:flex-row">
|
<div class="flex items-center space-x-4 text-center md:text-left flex-col md:flex-row">
|
||||||
<div id="playerCard" class="w-20 h-20 bg-purple-950 border border-purple-500/30 rounded-xl flex items-center justify-center text-2xl font-bold text-purple-300">VAL</div>
|
<div id="playerCard" class="w-20 h-20 bg-purple-950 border border-purple-500/30 rounded-xl flex items-center justify-center text-2xl font-bold text-purple-300">VAL</div>
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -41,16 +42,34 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bg-slate-900/80 border border-purple-900/40 p-4 rounded-xl flex items-center space-x-4 min-w-[240px]">
|
<div class="flex flex-col sm:flex-row gap-4 w-full md:w-auto items-center">
|
||||||
<div id="rankImageContainer" class="w-12 h-12 flex items-center justify-center bg-purple-950/40 border border-purple-900/20 rounded-lg p-1">
|
|
||||||
<img id="displayRankImage" src="" alt="Rank Icon" class="hidden w-full h-full object-contain">
|
<div id="smurfCard" class="bg-slate-900/80 border p-4 rounded-xl flex flex-col justify-center min-w-[240px] transition-all duration-300">
|
||||||
<span id="rankFallbackIcon" class="text-xl">🏆</span>
|
<div class="flex justify-between items-center mb-1">
|
||||||
|
<p class="text-[10px] uppercase tracking-widest font-bold text-slate-400">Smurf Detection</p>
|
||||||
|
<span id="smurfBadge" class="text-[9px] font-black uppercase px-1.5 py-0.5 rounded tracking-wide">Analysing</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-baseline space-x-1.5">
|
||||||
|
<span id="displaySmurfScore" class="text-2xl font-black">0%</span>
|
||||||
|
<span class="text-xs text-slate-500 font-semibold">Wahrscheinlichkeit</span>
|
||||||
|
</div>
|
||||||
|
<div class="w-full bg-slate-950 h-1.5 rounded-full overflow-hidden mt-2">
|
||||||
|
<div id="smurfProgressBar" class="h-full bg-slate-700 transition-all duration-500" style="width: 0%"></div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
|
||||||
<p class="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Rank</p>
|
<div class="bg-slate-900/80 border border-purple-900/40 p-4 rounded-xl flex items-center space-x-4 min-w-[240px]">
|
||||||
<p id="displayRank" class="text-lg font-black text-purple-300">Loading...</p>
|
<div id="rankImageContainer" class="w-12 h-12 flex items-center justify-center bg-purple-950/40 border border-purple-900/20 rounded-lg p-1">
|
||||||
<p id="displayRR" class="text-xs text-slate-500">-- RR</p>
|
<img id="displayRankImage" src="" alt="Rank Icon" class="hidden w-full h-full object-contain">
|
||||||
|
<span id="rankFallbackIcon" class="text-xl">🏆</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p class="text-[10px] text-slate-400 uppercase tracking-widest font-bold">Rank</p>
|
||||||
|
<p id="displayRank" class="text-lg font-black text-purple-300">Loading...</p>
|
||||||
|
<p id="displayRR" class="text-xs text-slate-500">-- RR</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -124,7 +143,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||||
|
|
||||||
<div class="bg-slate-900/30 border border-purple-950/40 p-4 rounded-xl">
|
<div class="bg-slate-900/30 border border-purple-950/40 p-4 rounded-xl">
|
||||||
<h4 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Zielgenauigkeit (Hit-Zonen)</h4>
|
<h4 class="text-xs font-bold text-slate-400 uppercase tracking-wider mb-3">Zielgenauigkeit (Hit-Zonen)</h4>
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
|
|
@ -162,13 +180,12 @@
|
||||||
<span id="modalMulti" class="font-bold text-slate-300">3K: 0 | 4K: 0 | 5K: 0</span>
|
<span id="modalMulti" class="font-bold text-slate-300">3K: 0 | 4K: 0 | 5K: 0</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
let currentMatchesCache = []; // Globaler Cache für Match-Klicks
|
let currentMatchesCache = [];
|
||||||
|
|
||||||
function openMatchReport(index) {
|
function openMatchReport(index) {
|
||||||
const match = currentMatchesCache[index];
|
const match = currentMatchesCache[index];
|
||||||
|
|
@ -185,12 +202,10 @@
|
||||||
document.getElementById('modalKDA').innerText = `${match.kills} / ${match.deaths} / ${match.assists}`;
|
document.getElementById('modalKDA').innerText = `${match.kills} / ${match.deaths} / ${match.assists}`;
|
||||||
document.getElementById('modalACS').innerText = match.details.combat_score;
|
document.getElementById('modalACS').innerText = match.details.combat_score;
|
||||||
|
|
||||||
// Hitbox-Daten binden
|
|
||||||
document.getElementById('modalHSRate').innerText = match.details.hs_rate;
|
document.getElementById('modalHSRate').innerText = match.details.hs_rate;
|
||||||
document.getElementById('modalHSBar').style.width = match.details.hs_rate;
|
document.getElementById('modalHSBar').style.width = match.details.hs_rate;
|
||||||
document.getElementById('modalHitsCount').innerText = `${match.details.headshots} Head / ${match.details.bodyshots} Body / ${match.details.legshots} Legs`;
|
document.getElementById('modalHitsCount').innerText = `${match.details.headshots} Head / ${match.details.bodyshots} Body / ${match.details.legshots} Legs`;
|
||||||
|
|
||||||
// Gefechtsmetriken binden
|
|
||||||
document.getElementById('modalFB').innerText = match.details.first_bloods;
|
document.getElementById('modalFB').innerText = match.details.first_bloods;
|
||||||
document.getElementById('modalEcon').innerText = match.details.avg_spent;
|
document.getElementById('modalEcon').innerText = match.details.avg_spent;
|
||||||
document.getElementById('modalBadges').innerText = match.details.is_team_mvp ? "⭐ TEAM MVP" : "Keine Titel";
|
document.getElementById('modalBadges').innerText = match.details.is_team_mvp ? "⭐ TEAM MVP" : "Keine Titel";
|
||||||
|
|
@ -240,6 +255,36 @@
|
||||||
document.getElementById('displayRank').innerText = data.rank.current_tier_name;
|
document.getElementById('displayRank').innerText = data.rank.current_tier_name;
|
||||||
document.getElementById('displayRR').innerText = `${data.rank.ranking_in_tier} RR`;
|
document.getElementById('displayRR').innerText = `${data.rank.ranking_in_tier} RR`;
|
||||||
|
|
||||||
|
// === DYNAMISCHES SMURF SCORE STYLING BINDEN ===
|
||||||
|
const sScore = data.smurf_analyzer.score;
|
||||||
|
const sStatus = data.smurf_analyzer.status;
|
||||||
|
|
||||||
|
document.getElementById('displaySmurfScore').innerText = `${sScore}%`;
|
||||||
|
document.getElementById('smurfProgressBar').style.width = `${sScore}%`;
|
||||||
|
|
||||||
|
const sCard = document.getElementById('smurfCard');
|
||||||
|
const sBadge = document.getElementById('smurfBadge');
|
||||||
|
sBadge.innerText = sStatus;
|
||||||
|
|
||||||
|
// Farbthemen basierend auf dem Score zuweisen
|
||||||
|
if(sScore >= 70) {
|
||||||
|
sCard.className = "bg-rose-950/40 border-rose-500/60 p-4 rounded-xl flex flex-col justify-center min-w-[240px]";
|
||||||
|
sBadge.className = "text-[9px] font-black uppercase px-1.5 py-0.5 rounded tracking-wide bg-rose-500 text-black shadow-lg shadow-rose-500/20";
|
||||||
|
document.getElementById('displaySmurfScore').className = "text-2xl font-black text-rose-400";
|
||||||
|
document.getElementById('smurfProgressBar').className = "h-full bg-rose-500 animate-pulse";
|
||||||
|
} else if(sScore >= 40) {
|
||||||
|
sCard.className = "bg-amber-950/30 border-amber-500/40 p-4 rounded-xl flex flex-col justify-center min-w-[240px]";
|
||||||
|
sBadge.className = "text-[9px] font-black uppercase px-1.5 py-0.5 rounded tracking-wide bg-amber-500 text-black";
|
||||||
|
document.getElementById('displaySmurfScore').className = "text-2xl font-black text-amber-400";
|
||||||
|
document.getElementById('smurfProgressBar').className = "h-full bg-amber-500";
|
||||||
|
} else {
|
||||||
|
sCard.className = "bg-slate-900/80 border-slate-800 p-4 rounded-xl flex flex-col justify-center min-w-[240px]";
|
||||||
|
sBadge.className = "text-[9px] font-black uppercase px-1.5 py-0.5 rounded tracking-wide bg-emerald-500/10 text-emerald-400 border border-emerald-500/20";
|
||||||
|
document.getElementById('displaySmurfScore').className = "text-2xl font-black text-emerald-400";
|
||||||
|
document.getElementById('smurfProgressBar').className = "h-full bg-emerald-500";
|
||||||
|
}
|
||||||
|
// ===============================================
|
||||||
|
|
||||||
const rankImg = document.getElementById('displayRankImage');
|
const rankImg = document.getElementById('displayRankImage');
|
||||||
const rankFallback = document.getElementById('rankFallbackIcon');
|
const rankFallback = document.getElementById('rankFallbackIcon');
|
||||||
if (data.rank.rank_image_url) {
|
if (data.rank.rank_image_url) {
|
||||||
|
|
@ -258,9 +303,8 @@
|
||||||
cardDiv.innerText = '';
|
cardDiv.innerText = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Globale Profildaten binden
|
|
||||||
document.getElementById('calcWinrate').innerText = data.calculated_stats.win_rate;
|
document.getElementById('calcWinrate').innerText = data.calculated_stats.win_rate;
|
||||||
document.getElementById('calcHSPercentage').innerText = data.calculated_stats.avg_hs_percentage; // Bindung der neuen Statistik
|
document.getElementById('calcHSPercentage').innerText = data.calculated_stats.avg_hs_percentage;
|
||||||
document.getElementById('calcKD').innerText = data.calculated_stats.kd_ratio;
|
document.getElementById('calcKD').innerText = data.calculated_stats.kd_ratio;
|
||||||
document.getElementById('calcBestAgent').innerText = data.calculated_stats.best_agent;
|
document.getElementById('calcBestAgent').innerText = data.calculated_stats.best_agent;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1552,12 +1552,15 @@ def get_valorant_stats(name, tag):
|
||||||
|
|
||||||
acc_data = acc_res.json().get('data', {}) or {}
|
acc_data = acc_res.json().get('data', {}) or {}
|
||||||
region = acc_data.get("region", "eu")
|
region = acc_data.get("region", "eu")
|
||||||
|
account_level = acc_data.get('account_level', 1) or 1
|
||||||
|
|
||||||
# 2. Aktueller Rang (MMR v1)
|
# 2. Aktueller Rang (MMR v1)
|
||||||
mmr_res = requests.get(f"{VALORANT_API_BASE}/v1/mmr/{region}/{name}/{tag}", headers=headers, timeout=10)
|
mmr_res = requests.get(f"{VALORANT_API_BASE}/v1/mmr/{region}/{name}/{tag}", headers=headers, timeout=10)
|
||||||
mmr_data = mmr_res.json().get('data', {}) if mmr_res.status_code == 200 else {}
|
mmr_data = mmr_res.json().get('data', {}) if mmr_res.status_code == 200 else {}
|
||||||
if not mmr_data: mmr_data = {}
|
if not mmr_data: mmr_data = {}
|
||||||
|
|
||||||
|
current_tier = mmr_data.get('currenttier', 0) or 0 # Tier ID für die Smurf-Gewichtung
|
||||||
|
|
||||||
# 3. RR-Verlauf (MMR History)
|
# 3. RR-Verlauf (MMR History)
|
||||||
rr_history = {}
|
rr_history = {}
|
||||||
if match_mode == 'competitive':
|
if match_mode == 'competitive':
|
||||||
|
|
@ -1569,7 +1572,7 @@ def get_valorant_stats(name, tag):
|
||||||
if m_id:
|
if m_id:
|
||||||
rr_history[m_id] = h_item.get('mmr_change_to_last_game', 0)
|
rr_history[m_id] = h_item.get('mmr_change_to_last_game', 0)
|
||||||
|
|
||||||
# 4. Match Historie abrufen (Wichtig: Erzwingt das Limit auf size=20)
|
# 4. Match Historie abrufen (size=20)
|
||||||
matches_res = requests.get(f"{VALORANT_API_BASE}/v3/matches/{region}/{name}/{tag}?size=20&mode={match_mode}",
|
matches_res = requests.get(f"{VALORANT_API_BASE}/v3/matches/{region}/{name}/{tag}?size=20&mode={match_mode}",
|
||||||
headers=headers, timeout=10)
|
headers=headers, timeout=10)
|
||||||
matches_list = matches_res.json().get('data', []) if matches_res.status_code == 200 else []
|
matches_list = matches_res.json().get('data', []) if matches_res.status_code == 200 else []
|
||||||
|
|
@ -1579,10 +1582,10 @@ def get_valorant_stats(name, tag):
|
||||||
total_kills = 0
|
total_kills = 0
|
||||||
total_deaths = 0
|
total_deaths = 0
|
||||||
total_assists = 0
|
total_assists = 0
|
||||||
|
|
||||||
# Variablen für globale Headshot-Berechnung
|
|
||||||
global_headshots = 0
|
global_headshots = 0
|
||||||
global_total_hits = 0
|
global_total_hits = 0
|
||||||
|
total_mvps = 0
|
||||||
|
total_first_bloods = 0
|
||||||
|
|
||||||
agent_stats = {}
|
agent_stats = {}
|
||||||
processed_matches = []
|
processed_matches = []
|
||||||
|
|
@ -1593,11 +1596,9 @@ def get_valorant_stats(name, tag):
|
||||||
match_id = metadata.get('matchid')
|
match_id = metadata.get('matchid')
|
||||||
players = match.get('players', {}).get('all_players', [])
|
players = match.get('players', {}).get('all_players', [])
|
||||||
|
|
||||||
# Spielerabgleich
|
|
||||||
me = next((p for p in players if
|
me = next((p for p in players if
|
||||||
p.get('name', '').lower() == name.lower() and p.get('tag', '').lower() == tag.lower()), None)
|
p.get('name', '').lower() == name.lower() and p.get('tag', '').lower() == tag.lower()), None)
|
||||||
if not me:
|
if not me: continue
|
||||||
continue
|
|
||||||
|
|
||||||
match_count += 1
|
match_count += 1
|
||||||
agent_name = me.get('character', 'Unknown') or 'Unknown'
|
agent_name = me.get('character', 'Unknown') or 'Unknown'
|
||||||
|
|
@ -1612,10 +1613,8 @@ def get_valorant_stats(name, tag):
|
||||||
total_deaths += m_deaths
|
total_deaths += m_deaths
|
||||||
total_assists += m_assists
|
total_assists += m_assists
|
||||||
|
|
||||||
# Agenten-Statistiken sammeln
|
|
||||||
if agent_name not in agent_stats:
|
if agent_name not in agent_stats:
|
||||||
agent_stats[agent_name] = {"count": 0, "kills": 0, "deaths": 0, "assists": 0}
|
agent_stats[agent_name] = {"count": 0, "kills": 0, "deaths": 0, "assists": 0}
|
||||||
|
|
||||||
agent_stats[agent_name]["count"] += 1
|
agent_stats[agent_name]["count"] += 1
|
||||||
agent_stats[agent_name]["kills"] += m_kills
|
agent_stats[agent_name]["kills"] += m_kills
|
||||||
agent_stats[agent_name]["deaths"] += m_deaths
|
agent_stats[agent_name]["deaths"] += m_deaths
|
||||||
|
|
@ -1626,60 +1625,48 @@ def get_valorant_stats(name, tag):
|
||||||
my_team_data = teams.get(my_team_color, {})
|
my_team_data = teams.get(my_team_color, {})
|
||||||
|
|
||||||
has_won = my_team_data.get('has_won') is True
|
has_won = my_team_data.get('has_won') is True
|
||||||
if has_won:
|
if has_won: wins += 1
|
||||||
wins += 1
|
|
||||||
|
|
||||||
red_rounds = teams.get('red', {}).get('rounds_won', 0) or 0
|
red_rounds = teams.get('red', {}).get('rounds_won', 0) or 0
|
||||||
blue_rounds = teams.get('blue', {}).get('rounds_won', 0) or 0
|
blue_rounds = teams.get('blue', {}).get('rounds_won', 0) or 0
|
||||||
rounds_played = red_rounds + blue_rounds
|
rounds_played = red_rounds + blue_rounds
|
||||||
|
|
||||||
if my_team_color == 'red':
|
score_str = f"{red_rounds} : {blue_rounds}" if my_team_color == 'red' else f"{blue_rounds} : {red_rounds}"
|
||||||
score_str = f"{red_rounds} : {blue_rounds}"
|
|
||||||
else:
|
|
||||||
score_str = f"{blue_rounds} : {red_rounds}"
|
|
||||||
|
|
||||||
# Wirtschaft ausrechnen
|
|
||||||
economy = me.get('economy', {})
|
economy = me.get('economy', {})
|
||||||
spent_spent = economy.get('spent', {}).get('overall', 0) or 0
|
spent_spent = economy.get('spent', {}).get('overall', 0) or 0
|
||||||
avg_spent = round(spent_spent / rounds_played, 0) if rounds_played > 0 else 0
|
avg_spent = round(spent_spent / rounds_played, 0) if rounds_played > 0 else 0
|
||||||
|
|
||||||
# Hit-Zonen auswerten (Match)
|
|
||||||
headshots = stats.get('headshots', 0) or 0
|
headshots = stats.get('headshots', 0) or 0
|
||||||
bodyshots = stats.get('bodyshots', 0) or 0
|
bodyshots = stats.get('bodyshots', 0) or 0
|
||||||
legshots = stats.get('legshots', 0) or 0
|
legshots = stats.get('legshots', 0) or 0
|
||||||
total_hits = headshots + bodyshots + legshots
|
total_hits = headshots + bodyshots + legshots
|
||||||
hs_rate = round((headshots / total_hits) * 100, 1) if total_hits > 0 else 0
|
hs_rate = round((headshots / total_hits) * 100, 1) if total_hits > 0 else 0
|
||||||
|
|
||||||
# Für globale Statistik aufsummieren
|
|
||||||
global_headshots += headshots
|
global_headshots += headshots
|
||||||
global_total_hits += total_hits
|
global_total_hits += total_hits
|
||||||
|
|
||||||
# First Bloods & Multi-Kills
|
|
||||||
first_bloods = 0
|
first_bloods = 0
|
||||||
kills_per_round = {3: 0, 4: 0, 5: 0}
|
kills_per_round = {3: 0, 4: 0, 5: 0}
|
||||||
round_data = match.get('rounds', []) or []
|
round_data = match.get('rounds', []) or []
|
||||||
|
|
||||||
for r in round_data:
|
for r in round_data:
|
||||||
player_stats_round = r.get('player_stats', []) or []
|
|
||||||
kill_events = r.get('kill_events', []) or []
|
kill_events = r.get('kill_events', []) or []
|
||||||
|
if kill_events and kill_events[0].get('killer_name', '').lower() == name.lower():
|
||||||
|
first_bloods += 1
|
||||||
|
total_first_bloods += 1
|
||||||
|
|
||||||
if kill_events:
|
for ps in r.get('player_stats', []) or []:
|
||||||
first_kill = kill_events[0]
|
|
||||||
if first_kill.get('killer_name', '').lower() == name.lower():
|
|
||||||
first_bloods += 1
|
|
||||||
|
|
||||||
for ps in player_stats_round:
|
|
||||||
if ps.get('player_name', '').lower() == name.lower():
|
if ps.get('player_name', '').lower() == name.lower():
|
||||||
k_count = ps.get('kills', 0) or 0
|
k_count = ps.get('kills', 0) or 0
|
||||||
if k_count in kills_per_round:
|
if k_count in kills_per_round:
|
||||||
kills_per_round[k_count] += 1
|
kills_per_round[k_count] += 1
|
||||||
|
|
||||||
# Team MVP Check
|
|
||||||
is_team_mvp = True
|
is_team_mvp = True
|
||||||
for p in players:
|
for p in players:
|
||||||
if p.get('team', '').lower() == my_team_color:
|
if p.get('team', '').lower() == my_team_color and (p.get('stats', {}).get('score', 0) or 0) > m_score:
|
||||||
if (p.get('stats', {}).get('score', 0) or 0) > m_score:
|
is_team_mvp = False
|
||||||
is_team_mvp = False
|
if is_team_mvp: total_mvps += 1
|
||||||
|
|
||||||
mmr_change = rr_history.get(match_id, 0) if match_mode == 'competitive' else None
|
mmr_change = rr_history.get(match_id, 0) if match_mode == 'competitive' else None
|
||||||
map_name = metadata.get('map', 'Unknown')
|
map_name = metadata.get('map', 'Unknown')
|
||||||
|
|
@ -1707,39 +1694,70 @@ def get_valorant_stats(name, tag):
|
||||||
"avg_spent": f"{int(avg_spent)} ¥",
|
"avg_spent": f"{int(avg_spent)} ¥",
|
||||||
"first_bloods": first_bloods,
|
"first_bloods": first_bloods,
|
||||||
"is_team_mvp": is_team_mvp,
|
"is_team_mvp": is_team_mvp,
|
||||||
"multikills": {
|
"multikills": {"3k": kills_per_round[3], "4k": kills_per_round[4], "5k": kills_per_round[5]}
|
||||||
"3k": kills_per_round[3],
|
|
||||||
"4k": kills_per_round[4],
|
|
||||||
"5k": kills_per_round[5]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
# Berechnungen für globale Profile-Stats
|
# Globale Berechnungen
|
||||||
kd_calculated = round(total_kills / total_deaths, 2) if total_deaths > 0 else total_kills
|
kd_calculated = round(total_kills / total_deaths, 2) if total_deaths > 0 else total_kills
|
||||||
winrate_calculated = round((wins / match_count) * 100, 1) if match_count > 0 else 0
|
winrate_calculated = round((wins / match_count) * 100, 1) if match_count > 0 else 0
|
||||||
global_hs_calculated = round((global_headshots / global_total_hits) * 100, 1) if global_total_hits > 0 else 0
|
global_hs_calculated = round((global_headshots / global_total_hits) * 100, 1) if global_total_hits > 0 else 0
|
||||||
|
|
||||||
|
# ================= SMURF SCORE ENGINE =================
|
||||||
|
smurf_points = 0
|
||||||
|
|
||||||
|
# 1. Hebel: Account Level im Verhältnis zum Rang (Niedriges Level + Hoher Rang = Kritisch)
|
||||||
|
if account_level < 25 and current_tier >= 12: # Unter Level 25 und Gold+
|
||||||
|
smurf_points += 35
|
||||||
|
elif account_level < 50 and current_tier >= 15: # Unter Level 50 und Platin+
|
||||||
|
smurf_points += 25
|
||||||
|
elif account_level < 80 and current_tier >= 18: # Unter Level 80 und Diamond+
|
||||||
|
smurf_points += 15
|
||||||
|
elif account_level < 15: # Generell extrem frischer Account
|
||||||
|
smurf_points += 10
|
||||||
|
|
||||||
|
# 2. Hebel: K/D Ratio Performance
|
||||||
|
if kd_calculated >= 1.4:
|
||||||
|
smurf_points += 30
|
||||||
|
elif kd_calculated >= 1.25:
|
||||||
|
smurf_points += 20
|
||||||
|
elif kd_calculated >= 1.12:
|
||||||
|
smurf_points += 10
|
||||||
|
|
||||||
|
# 3. Hebel: Win Rate Dominanz
|
||||||
|
if winrate_calculated >= 65:
|
||||||
|
smurf_points += 20
|
||||||
|
elif winrate_calculated >= 56:
|
||||||
|
smurf_points += 10
|
||||||
|
|
||||||
|
# 4. Hebel: MVP & First Blood Anteil
|
||||||
|
if match_count > 0:
|
||||||
|
mvp_rate = (total_mvps / match_count) * 100
|
||||||
|
fb_per_match = total_first_bloods / match_count
|
||||||
|
if mvp_rate >= 40: smurf_points += 10 # In fast jedem zweiten Match Team-MVP
|
||||||
|
if fb_per_match >= 2.5: smurf_points += 5 # Extrem aggressiver Opening-Fragger
|
||||||
|
|
||||||
|
smurf_score = min(smurf_points, 100) # Maximal 100%
|
||||||
|
|
||||||
|
# Einstufungstext ermitteln
|
||||||
|
if smurf_score >= 70:
|
||||||
|
smurf_status = "Höchstverdächtig (Smurf)"
|
||||||
|
elif smurf_score >= 40:
|
||||||
|
smurf_status = "Auffällige Performance"
|
||||||
|
else:
|
||||||
|
smurf_status = "Unauffälliger Main Account"
|
||||||
|
# ======================================================
|
||||||
|
|
||||||
all_agents = []
|
all_agents = []
|
||||||
best_agent_name = "Keiner"
|
best_agent_name = "Keiner"
|
||||||
highest_agent_kda = -1.0
|
highest_agent_kda = -1.0
|
||||||
|
|
||||||
for name_key, data in agent_stats.items():
|
for name_key, data in agent_stats.items():
|
||||||
a_kills = data["kills"]
|
a_kda = round((data["kills"] + data["assists"]) / data["deaths"], 2) if data["deaths"] > 0 else float(
|
||||||
a_deaths = data["deaths"]
|
data["kills"] + data["assists"])
|
||||||
a_assists = data["assists"]
|
all_agents.append({"name": name_key, "count": data["count"], "kda": a_kda})
|
||||||
a_kda = round((a_kills + a_assists) / a_deaths, 2) if a_deaths > 0 else float(a_kills + a_assists)
|
|
||||||
|
|
||||||
all_agents.append({
|
|
||||||
"name": name_key,
|
|
||||||
"count": data["count"],
|
|
||||||
"kda": a_kda
|
|
||||||
})
|
|
||||||
|
|
||||||
if a_kda > highest_agent_kda:
|
if a_kda > highest_agent_kda:
|
||||||
highest_agent_kda = a_kda
|
highest_agent_kda = a_kda
|
||||||
best_agent_name = name_key
|
best_agent_name = name_key
|
||||||
|
|
||||||
all_agents = sorted(all_agents, key=lambda x: x["count"], reverse=True)
|
all_agents = sorted(all_agents, key=lambda x: x["count"], reverse=True)
|
||||||
|
|
||||||
return jsonify({
|
return jsonify({
|
||||||
|
|
@ -1747,7 +1765,7 @@ def get_valorant_stats(name, tag):
|
||||||
"account": {
|
"account": {
|
||||||
"name": acc_data.get('name'),
|
"name": acc_data.get('name'),
|
||||||
"tag": acc_data.get('tag'),
|
"tag": acc_data.get('tag'),
|
||||||
"level": acc_data.get('account_level'),
|
"level": account_level,
|
||||||
"card_url": acc_data.get('card', {}).get('small') if acc_data.get('card') else None
|
"card_url": acc_data.get('card', {}).get('small') if acc_data.get('card') else None
|
||||||
},
|
},
|
||||||
"rank": {
|
"rank": {
|
||||||
|
|
@ -1755,9 +1773,13 @@ def get_valorant_stats(name, tag):
|
||||||
"ranking_in_tier": mmr_data.get('ranking_in_tier', 0) or 0,
|
"ranking_in_tier": mmr_data.get('ranking_in_tier', 0) or 0,
|
||||||
"rank_image_url": mmr_data.get('images', {}).get('small') if mmr_data.get('images') else None
|
"rank_image_url": mmr_data.get('images', {}).get('small') if mmr_data.get('images') else None
|
||||||
},
|
},
|
||||||
|
"smurf_analyzer": {
|
||||||
|
"score": smurf_score,
|
||||||
|
"status": smurf_status
|
||||||
|
},
|
||||||
"calculated_stats": {
|
"calculated_stats": {
|
||||||
"win_rate": f"{winrate_calculated}%",
|
"win_rate": f"{winrate_calculated}%",
|
||||||
"avg_hs_percentage": f"{global_hs_calculated}%", # Neue API-Rückgabe
|
"avg_hs_percentage": f"{global_hs_calculated}%",
|
||||||
"kd_ratio": str(kd_calculated),
|
"kd_ratio": str(kd_calculated),
|
||||||
"best_agent": best_agent_name,
|
"best_agent": best_agent_name,
|
||||||
"matches_analyzed": match_count
|
"matches_analyzed": match_count
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue