0x2688…36e6

All memos sent from and to 0x2688…36e6.

V# { "Depends": "py-genlayer:1jb45aa8ynh2a9c9xn3b7qqh8sm5q93hwfp7jqmwsfhh8jpz09h6" } from genlayer import * import json # ─── Constants ──────────────────────────────────────────────────────────────── XP_PER_LEVEL = 100 MAX_LEVEL = 100 STAT_POINTS_START = 5 # bonus points on first registration STAT_POINTS_PER_WIN = 3 # bonus points per win class PlayerProfiles(gl.Contract): """ Sky Flock Arena — PlayerProfiles Persistent on-chain player identity store. Replaces localStorage as the source of truth for: username, pigeon_type, xp, level, stat_points, wins, losses """ profiles: TreeMap[str, str] # wallet_address (lower) → JSON profile def __init__(self): self.profiles = TreeMap() # ── Helpers ─────────────────────────────────────────────────────────────── @staticmethod def _calc_level(xp: int) -> int: return min(MAX_LEVEL, xp // XP_PER_LEVEL) # ── Write: Register new player ──────────────────────────────────────────── @gl.public.write def register_player( self, wallet_address: str, username: str, pigeon_type: str, ) -> str: key = wallet_address.lower() if key in self.profiles: existing = json.loads(self.profiles[key]) return json.dumps({ "ok": False, "error": "already_registered", "profile": existing, }) clean_name = username.strip()[:20] or "Pombo" profile = { "wallet": key, "username": clean_name, "pigeon_type": pigeon_type, "xp": 0, "level": 0, "stat_points": STAT_POINTS_START, "wins": 0, "losses": 0, } self.profiles[key] = json.dumps(profile) return json.dumps({"ok": True, "profile": profile}) # ── Write: Update XP + win/loss after a match ───────────────────────────── @gl.public.write def update_stats_after_match( self, wallet_address: str, xp_gained: int, is_win: bool, ) -> str: key = wallet_address.lower() if key not in self.profiles: return json.dumps({"ok": False, "error": "not_registered"}) profile = json.loads(self.profiles[key]) old_level = profile["level"] profile["xp"] += max(0, int(xp_gained)) if is_win: profile["wins"] += 1 else: profile["losses"] += 1 new_level = self._calc_level(profile["xp"]) profile["level"] = new_level levels_gained = new_level - old_level if levels_gained > 0: profile["stat_points"] += levels_gained * 2 if is_win: profile["stat_points"] += STAT_POINTS_PER_WIN self.profiles[key] = json.dumps(profile) return json.dumps({ "ok": True, "profile": profile, "levels_gained": levels_gained, }) # ── Write: Update pigeon class (after evolution) ────────────────────────── @gl.public.write def update_pigeon(self, wallet_address: str, pigeon_type: str) -> str: key = wallet_address.lower() if key not in self.profiles: return json.dumps({"ok": False, "error": "not_registered"}) profile = json.loads(self.profiles[key]) profile["pigeon_type"] = pigeon_type self.profiles[key] = json.dumps(profile) return json.dumps({"ok": True, "profile": profile}) # ── Write: Spend one stat point ─────────────────────────────────────────── @gl.public.write def spend_stat_point(self, wallet_address: str) -> str: key = wallet_address.lower() if key not in self.profiles: return json.dumps({"ok": False, "error": "not_registered"}) profile = json.loads(self.profiles[key]) if profile["stat_points"] <= 0: return json.dumps({"ok": False, "error": "no_stat_points"}) profile["stat_points"] -= 1 self.profiles[key] = json.dumps(profile) return json.dumps({"ok": True, "stat_points": profile["stat_points"]}) # ── View: Get profile ───────────────────────────────────────────────────── @gl.public.view def get_profile(self, wallet_address: str) -> str: key = wallet_address.lower() if key not in self.profiles: return json.dumps({"ok": False, "error": "not_found"}) profile = json.loads(self.profiles[key]) return json.dumps({"ok": True, "profile": profile}) # ── View: Meta ──────────────────────────────────────────────────────────── @gl.public.view def get_version(self) -> str: return "1.0.0" @gl.public.view def total_players(self) -> int: return len(self.profiles)