onlyn00bs-badge

OnlyN00bs: a DEF CON 34 friend-finder badge. ESP32 firmware, Web Bluetooth setup app, printable case
git clone https://git.virtualshack.io/onlyn00bs-badge.git
Log | Files | Refs | README | LICENSE

pet.h (2219B)


      1 #pragma once
      2 #include <stdint.h>
      3 
      4 // The badge companion. A "pet" is a name + a face per state (short ASCII faces,
      5 // e.g. "(^_^)"). The active one is chosen on the PET view (double-tap to swap);
      6 // 3 ship built-in, with a 4th "custom" slot uploadable via the provisioning page
      7 // (see docs/provisioning.md).
      8 //
      9 // ─── NAMING: the user-facing word is "AVATAR"; the code says "pet" ───────────
     10 // Every string a recipient reads — the OLED's "Avatar:" row, the setup app, the
     11 // FAQ at badge.virtualshack.io — says *avatar*. Identifiers here (pet.h, PET_*,
     12 // g_pet_idx, OptView::pet, PET_UUID) deliberately still say *pet*. That split is
     13 // intentional, not leftover: renaming the identifiers buys a recipient nothing,
     14 // and one class of them CANNOT be renamed safely at all —
     15 //
     16 //     the NVS keys "pet", "petcust", "petc_ok" (main.cpp).
     17 //
     18 // Those are persisted on every badge already in the field. Changing a key does
     19 // not migrate the value, it orphans it: every custom avatar uploaded before the
     20 // change silently reverts to the built-in default, and the owner's selected slot
     21 // resets. If you rename anything here, leave the NVS keys and the BLE UUID alone.
     22 
     23 enum PetState {
     24   PET_IDLE = 0,    // resting
     25   PET_CONTACT,     // a new crew badge just came into range
     26   PET_MILESTONE,   // crossed a points milestone
     27   PET_LONELY,      // no crew in range
     28   PET_LOWBATT,     // battery low
     29   PET_STATE_COUNT
     30 };
     31 
     32 #define PET_NAME_MAX   12
     33 #define PET_FACE_MAX   16
     34 #define PET_BUILTIN_N  3
     35 
     36 struct Pet {
     37   char name[PET_NAME_MAX];
     38   char face[PET_STATE_COUNT][PET_FACE_MAX];   // indexed by PetState
     39 };
     40 
     41 // Built-in pets. Face order matches PetState: idle, contact, milestone, lonely, lowbatt.
     42 static const Pet PET_BUILTINS[PET_BUILTIN_N] = {
     43   { "ghost", { "(^_^)",   "(o_o)!",  "(^o^)",   "(-_-)z",  "(>_<)"   } },
     44   { "bot",   { "[o_o]",   "[O_O]!",  "[^o^]",   "[-_-]",   "[x_x]"   } },
     45   { "cat",   { "(=^.^=)", "(=o.o=)", "(=^o^=)", "(=-.-=)", "(=T.T=)" } },
     46 };
     47 
     48 // Active pet by index (clamped). Custom slot (index PET_BUILTIN_N) lands in Phase 3.
     49 static inline const Pet* pet_get(int idx) {
     50   if (idx < 0 || idx >= PET_BUILTIN_N) idx = 0;
     51   return &PET_BUILTINS[idx];
     52 }