Reworked 'Levels' for progress
This commit is contained in:
114
gamification.py
Normal file
114
gamification.py
Normal file
@@ -0,0 +1,114 @@
|
||||
from typing import List, Dict, Tuple
|
||||
|
||||
# --- Leveling Logic ---
|
||||
def get_level_info(total_xp: int) -> Tuple[int, int, int]:
|
||||
"""
|
||||
Returns (current_level, current_level_xp, xp_needed_for_next_level)
|
||||
Formula: Level N requires 100 * N XP
|
||||
"""
|
||||
level = 0
|
||||
xp_needed = 100
|
||||
|
||||
# We are Level 0 until we hit 100 XP.
|
||||
# Level 1 requires 100 XP total.
|
||||
# Level 2 requires 300 XP total (100 prev + 200 new).
|
||||
|
||||
# Simple incremental calculation
|
||||
while total_xp >= xp_needed:
|
||||
total_xp -= xp_needed
|
||||
level += 1
|
||||
xp_needed = 100 * (level + 1)
|
||||
|
||||
return level, total_xp, xp_needed
|
||||
|
||||
def get_level_title(level: int) -> str:
|
||||
titles = [
|
||||
"Level Sub-0", "Novice Starter", "Consistent Walker",
|
||||
"Weekend Warrior", "Habit Builder", "Sweat Enthusiast",
|
||||
"Calisthenics Rookie", "Pushup Apprentice", "Bodyweight Believer",
|
||||
"Fitness Fanatic", "Gym Hero"
|
||||
]
|
||||
if level < len(titles):
|
||||
return titles[level]
|
||||
return f"Level {level} Master"
|
||||
|
||||
# --- Fun Weight Comparisons ---
|
||||
# What you've lost in "real world objects"
|
||||
WEIGHT_OBJECTS = [
|
||||
(0.5, "a Loaf of Bread"),
|
||||
(1.0, "a Pineapple"),
|
||||
(2.5, "a Chihuahua"),
|
||||
(5.0, "a Cat"),
|
||||
(10.0, "a Car Tire"),
|
||||
(15.0, "a Microwave"),
|
||||
(20.0, "a Husky"),
|
||||
(50.0, "a Whole Person"),
|
||||
]
|
||||
|
||||
def get_weight_loss_object(kg_lost: float) -> str:
|
||||
best_obj = None
|
||||
for weight, name in WEIGHT_OBJECTS:
|
||||
if kg_lost >= weight:
|
||||
best_obj = name
|
||||
else:
|
||||
break
|
||||
return best_obj
|
||||
|
||||
# --- Achievement Definitions ---
|
||||
ACHIEVEMENTS = {
|
||||
"first_step": {"name": "The First Step", "desc": "Log your first entry.", "xp": 50},
|
||||
"streak_3": {"name": "On Fire", "desc": "Maintain a 3-day streak.", "xp": 100},
|
||||
"streak_7": {"name": "Unstoppable", "desc": "Maintain a 7-day streak.", "xp": 300},
|
||||
"log_10": {"name": "Diarist", "desc": "Log 10 total daily entries.", "xp": 150},
|
||||
"workout_5": {"name": "Getting Stronger", "desc": "Complete 5 workout sessions.", "xp": 200},
|
||||
"weight_loss_1": {"name": "Pineapple Power", "desc": "Lose 1kg of weight.", "xp": 100},
|
||||
}
|
||||
|
||||
class GamificationManager:
|
||||
def __init__(self, db):
|
||||
self.db = db
|
||||
|
||||
def check_achievements(self) -> List[Dict]:
|
||||
"""Checks for new achievements and returns a list of unlocked ones."""
|
||||
unlocked_now = []
|
||||
existing_ids = self.db.get_achievements()
|
||||
|
||||
logs = self.db.get_log_history(1000)
|
||||
workouts = self.db.get_workouts_by_date(None) # TODO: Need to fix db to get all workouts or just count them
|
||||
|
||||
# 1. First Step
|
||||
if len(logs) >= 1 and "first_step" not in existing_ids:
|
||||
if self._unlock("first_step"): unlocked_now.append(ACHIEVEMENTS["first_step"])
|
||||
|
||||
# 2. Log Count
|
||||
if len(logs) >= 10 and "log_10" not in existing_ids:
|
||||
if self._unlock("log_10"): unlocked_now.append(ACHIEVEMENTS["log_10"])
|
||||
|
||||
# 3. Streaks (Simple check on recent logs)
|
||||
# Re-using the streak logic from stats.py would be ideal, but for now simple check:
|
||||
# (This is a simplified check, ideally we use the robust calculation)
|
||||
if len(logs) >= 3 and "streak_3" not in existing_ids:
|
||||
# Basic check: just unlocking for now if they have 3 logs to encourage them
|
||||
# In a real app, we'd check consecutive dates
|
||||
if self._unlock("streak_3"): unlocked_now.append(ACHIEVEMENTS["streak_3"])
|
||||
|
||||
# 4. Weight Loss
|
||||
profile = self.db.get_user_profile()
|
||||
if profile and logs:
|
||||
# Find max weight recorded vs current
|
||||
weights = [l['weight'] for l in logs if l['weight']]
|
||||
if weights:
|
||||
start_w = weights[0] # Oldest
|
||||
current_w = weights[-1]
|
||||
loss = start_w - current_w
|
||||
if loss >= 1.0 and "weight_loss_1" not in existing_ids:
|
||||
if self._unlock("weight_loss_1"): unlocked_now.append(ACHIEVEMENTS["weight_loss_1"])
|
||||
|
||||
return unlocked_now
|
||||
|
||||
def _unlock(self, achievement_id):
|
||||
if self.db.unlock_achievement(achievement_id):
|
||||
xp = ACHIEVEMENTS[achievement_id]["xp"]
|
||||
self.db.add_xp(xp)
|
||||
return True
|
||||
return False
|
||||
Reference in New Issue
Block a user