Skip to content

Commit a0a4177

Browse files
committed
Merge branch 'catch-em-all-rework'
2 parents 20f5300 + 63f388c commit a0a4177

47 files changed

Lines changed: 3393 additions & 1029 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CATCH.md

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# Fursuit Catch-Em-All Game System Documentation
22

33
## System Overview
4+
45
The Catch-Em-All system is a **mobile-first gamified web app** for furry conventions. Fursuiters wear badges with unique 5-character codes, and attendees can "catch" them by entering these codes into the game, similar to a scavenger hunt with rarity levels, achievements, and leaderboards.
56

67
## New Architecture (2025 Redesign)
78

89
### Domain-Driven Design Structure
10+
911
```
1012
app/Domain/CatchEmAll/
1113
├── Controllers/GameController.php # Main game logic
@@ -22,69 +24,78 @@ app/Domain/CatchEmAll/
2224
```
2325

2426
### Database Tables
25-
- `user_catches` - Individual catches with **points_earned** field
26-
- `user_achievements` - Achievement progress and completion tracking
27-
- `user_catch_logs` - All catch attempts (includes anti-cheat detection)
28-
- `fursuits` - Fursuit records with `catch_em_all` boolean flag
29-
- `events` - Events with `catch_em_all_enabled` flag
27+
28+
- `user_achievements` - Achievement progress and completion tracking
29+
- `user_catch_logs` - All catch attempts (includes anti-cheat detection)
30+
- `fursuits` - Fursuit records with `catch_em_all` boolean flag
31+
- `events` - Events with `catch_em_all_enabled` flag
3032

3133
### Game Features
32-
- **Rarity System**: Species are categorized as Common (1pt) → Uncommon (2pts) → Rare (5pts) → Epic (10pts) → Legendary (25pts)
33-
- **Achievement System**: 10 different achievements including Legendary Master, Speed Demon, Social Butterfly
34-
- **Mobile App Interface**: Bottom navigation with YouTube-style tab layout, Lucide icons, no emojis
35-
- **Tab-Based Navigation**: Leaderboard, Achievements, **Catch!** (center), Collection, Profile
36-
- **Real-time Progress**: Live stats, collection tracking, and leaderboard updates
37-
- **Anti-Cheat**: Automated detection of suspicious behavior patterns
34+
35+
- **Rarity System**: Species are categorized as Common (1pt) → Uncommon (2pts) → Rare (5pts) → Epic (10pts) → Legendary (25pts)
36+
- **Achievement System**: 10 different achievements including Legendary Master, Speed Demon, Social Butterfly
37+
- **Mobile App Interface**: Bottom navigation with YouTube-style tab layout, Lucide icons, no emojis
38+
- **Tab-Based Navigation**: Leaderboard, Achievements, **Catch!** (center), Collection, Profile
39+
- **Real-time Progress**: Live stats, collection tracking, and leaderboard updates
40+
- **Anti-Cheat**: Automated detection of suspicious behavior patterns
3841

3942
### Routes (`/fcea/`)
40-
- `GET /` - Main game interface (`fcea.game`)
41-
- `POST /catch` - Submit catch code (`fcea.catch`)
42-
- `GET /collection` - Detailed collection view (`fcea.collection`)
43-
- `GET /achievements` - Achievement progress (`fcea.achievements`)
43+
44+
- `GET /` - Main game interface (`fcea.game`)
45+
- `POST /catch` - Submit catch code (`fcea.catch`)
46+
- `GET /collection` - Detailed collection view (`fcea.collection`)
47+
- `GET /achievements` - Achievement progress (`fcea.achievements`)
4448

4549
### UI/UX Design (2025 Mobile-First Redesign)
4650

4751
**Mobile App Navigation**:
48-
- **Bottom Tab Bar**: Fixed navigation like YouTube/Instagram with 5 tabs
49-
- **Central Catch Button**: Prominent, elevated with gradient background
50-
- **Lucide Icons**: Professional icon set instead of emojis
51-
- **Tab States**: Active tabs show colored background and icons
52+
53+
- **Bottom Tab Bar**: Fixed navigation like YouTube/Instagram with 5 tabs
54+
- **Central Catch Button**: Prominent, elevated with gradient background
55+
- **Lucide Icons**: Professional icon set instead of emojis
56+
- **Tab States**: Active tabs show colored background and icons
5257

5358
**Visual Design**:
54-
- **Clean Header**: App icon, title, and settings in top bar
55-
- **Card-Based Layout**: Each section in clean white cards with subtle shadows
56-
- **Gradient Accents**: Blue-to-purple gradients for primary actions
57-
- **Responsive Stats**: Visual progress bars, circular icons, grid layouts
58-
- **Touch-Friendly**: Large buttons, adequate spacing, tap feedback
59+
60+
- **Clean Header**: App icon, title, and settings in top bar
61+
- **Card-Based Layout**: Each section in clean white cards with subtle shadows
62+
- **Gradient Accents**: Blue-to-purple gradients for primary actions
63+
- **Responsive Stats**: Visual progress bars, circular icons, grid layouts
64+
- **Touch-Friendly**: Large buttons, adequate spacing, tap feedback
5965

6066
**Content Organization**:
61-
- **Catch Tab**: Stats overview, code input, event filter (default active)
62-
- **Leaderboard Tab**: Top players with rank icons and points
63-
- **Achievements Tab**: Progress tracking with completion states
64-
- **Collection Tab**: Species collection with rarity indicators
65-
- **Profile Tab**: Future user profile section (placeholder)
67+
68+
- **Catch Tab**: Stats overview, code input, event filter (default active)
69+
- **Leaderboard Tab**: Top players with rank icons and points
70+
- **Achievements Tab**: Progress tracking with completion states
71+
- **Collection Tab**: Species collection with rarity indicators
72+
- **Profile Tab**: Future user profile section (placeholder)
6673

6774
## Recent Optimizations (Completed)
6875

6976
### 1. ✅ Fixed Event Selection Logic
70-
- **Solution**: Simplified logic to always default to current event (EF29)
71-
- **Location**: `DashboardController::index()` lines 36-43
72-
- **Impact**: Users now see current event leaderboard by default
77+
78+
- **Solution**: Simplified logic to always default to current event (EF29)
79+
- **Location**: `DashboardController::index()` lines 36-43
80+
- **Impact**: Users now see current event leaderboard by default
7381

7482
### 2. ✅ Added Scheduled Ranking Updates
75-
- **Solution**: Created `RefreshFceaRankingsCommand` with scheduled execution
76-
- **Location**: `routes/console.php` - runs every 15 minutes during convention hours
77-
- **Impact**: Rankings stay fresh without requiring user actions
83+
84+
- **Solution**: Created `RefreshFceaRankingsCommand` with scheduled execution
85+
- **Location**: `routes/console.php` - runs every 15 minutes during convention hours
86+
- **Impact**: Rankings stay fresh without requiring user actions
7887

7988
### 3. ✅ Improved Performance & Caching
80-
- **Solution**: Optimized cache keys, increased TTL, specific cache clearing
81-
- **Location**: `DashboardController` cache methods
82-
- **Impact**: Faster dashboard loads, reduced database queries
89+
90+
- **Solution**: Optimized cache keys, increased TTL, specific cache clearing
91+
- **Location**: `DashboardController` cache methods
92+
- **Impact**: Faster dashboard loads, reduced database queries
8393

8494
### 4. Current Architecture Limitations
85-
- **Issue**: Separate user/fursuit ranking systems sharing same table
86-
- **Location**: `UserCatchRanking` model and `DashboardController::refresh*` methods
87-
- **Future**: Consider splitting into separate models for better maintainability
95+
96+
- **Issue**: Separate user/fursuit ranking systems sharing same table
97+
- **Location**: `UserCatchRanking` model and `DashboardController::refresh*` methods
98+
- **Future**: Consider splitting into separate models for better maintainability
8899

89100
## Key Files and Their Purpose
90101

@@ -118,13 +129,14 @@ database/
118129
```
119130

120131
## Configuration
121-
- `FURSUIT_CATCH_CODE_LENGTH=5` - Length of catch codes
122-
- `FURSUIT_CATCH_ATTEMPTS_PER_MINUTE=20` - Rate limiting
132+
133+
- `FURSUIT_CATCH_CODE_LENGTH=5` - Length of catch codes
134+
- `FURSUIT_CATCH_ATTEMPTS_PER_MINUTE=20` - Rate limiting
123135

124136
## Optimization Opportunities
125137

126138
1. **Simplify Event Logic**: Always show current event data unless explicitly filtered
127139
2. **Add Scheduled Jobs**: Periodic ranking updates via console scheduling
128140
3. **Improve Caching**: Better cache keys and longer TTLs for stable data
129141
4. **Optimize Queries**: Reduce N+1 queries and complex joins
130-
5. **Separate Ranking Models**: Split user/fursuit rankings into separate tables
142+
5. **Separate Ranking Models**: Split user/fursuit rankings into separate tables
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace App\Domain\CatchEmAll\Achievements;
4+
5+
use App\Domain\CatchEmAll\Interface\Achievement;
6+
use App\Domain\CatchEmAll\Models\AchievementUpdateContext;
7+
8+
class Archivist implements Achievement
9+
{
10+
public function getId(): string
11+
{
12+
return 'archivist';
13+
}
14+
15+
public function getTile(): string
16+
{
17+
return 'Archivist';
18+
}
19+
20+
public function getDescription(): string
21+
{
22+
return 'Your dedication is clear.';
23+
}
24+
25+
public function getIcon(): string
26+
{
27+
return '📚';
28+
}
29+
30+
public function getMaxProgress(): int
31+
{
32+
return 100;
33+
}
34+
35+
public function isSecret(): bool
36+
{
37+
return false;
38+
}
39+
40+
public function isOptional(): bool
41+
{
42+
return false;
43+
}
44+
45+
public function isHidden(): bool
46+
{
47+
return false;
48+
}
49+
50+
public function updateAchievementProgress(AchievementUpdateContext $context): int
51+
{
52+
// Only trigger on actual catches, not special codes
53+
if (!$context->hasCatch()) {
54+
return -1; // Ignore this update
55+
}
56+
57+
// Return current progress based on user's total catches
58+
$currentProgress = min($context->userTotalCatches, $this->getMaxProgress());
59+
60+
return $currentProgress;
61+
}
62+
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<?php
2+
3+
namespace App\Domain\CatchEmAll\Achievements;
4+
5+
use App\Domain\CatchEmAll\Enums\SpecialCodeType;
6+
use App\Domain\CatchEmAll\Interface\SpecialAchievement;
7+
use App\Domain\CatchEmAll\Models\AchievementUpdateContext;
8+
9+
class BugBountyHunter implements SpecialAchievement
10+
{
11+
12+
public function getId(): string
13+
{
14+
return 'bug_bounty_hunter';
15+
}
16+
17+
18+
public function getTile(): string
19+
{
20+
return 'Bug Bounty Hunter';
21+
}
22+
23+
24+
public function getDescription(): string
25+
{
26+
return 'Thanks for the QA! Your contribution is noted.';
27+
}
28+
29+
30+
public function getIcon(): string
31+
{
32+
return '🐛';
33+
}
34+
35+
36+
public function getMaxProgress(): int
37+
{
38+
return 1;
39+
}
40+
41+
42+
public function isSecret(): bool
43+
{
44+
return true;
45+
}
46+
47+
48+
public function isOptional(): bool
49+
{
50+
return true;
51+
}
52+
53+
54+
public function isHidden(): bool
55+
{
56+
return false;
57+
}
58+
59+
60+
public function updateAchievementProgress(AchievementUpdateContext $context): int
61+
{
62+
// This achievement can only be triggered by special code, not by catches
63+
if (!$context->isSpecialCodeTrigger() || $context->specialCodeType !== SpecialCodeType::BUG_BOUNTY) {
64+
return -1; // Ignore this update
65+
}
66+
67+
// Return completion progress - achievement granting is handled by AchievementService
68+
return $this->getMaxProgress(); // Return 1 (completed)
69+
}
70+
71+
72+
public function getSpecialCode(): SpecialCodeType
73+
{
74+
return SpecialCodeType::BUG_BOUNTY;
75+
}
76+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<?php
2+
3+
namespace App\Domain\CatchEmAll\Achievements;
4+
5+
use App\Domain\CatchEmAll\Interface\Achievement;
6+
use App\Domain\CatchEmAll\Models\AchievementUpdateContext;
7+
8+
class Collector implements Achievement
9+
{
10+
public function getId(): string
11+
{
12+
return 'collector';
13+
}
14+
15+
public function getTile(): string
16+
{
17+
return 'Collector';
18+
}
19+
20+
public function getDescription(): string
21+
{
22+
return 'You are an aspiring collector.';
23+
}
24+
25+
public function getIcon(): string
26+
{
27+
return '📦';
28+
}
29+
30+
public function getMaxProgress(): int
31+
{
32+
return 10;
33+
}
34+
35+
public function isSecret(): bool
36+
{
37+
return false;
38+
}
39+
40+
public function isOptional(): bool
41+
{
42+
return false;
43+
}
44+
45+
public function isHidden(): bool
46+
{
47+
return false;
48+
}
49+
50+
public function updateAchievementProgress(AchievementUpdateContext $context): int
51+
{
52+
// Only trigger on actual catches, not special codes
53+
if (!$context->hasCatch()) {
54+
return -1; // Ignore this update
55+
}
56+
57+
// Return current progress based on user's total catches
58+
$currentProgress = min($context->userTotalCatches, $this->getMaxProgress());
59+
60+
return $currentProgress;
61+
}
62+
}

0 commit comments

Comments
 (0)