CasinoGames/Baccarat/GAME_CENTER_PLAN.md

630 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Game Center Integration - Baccarat
This document outlines the Game Center achievements for Baccarat and the game-specific integration steps.
## Prerequisites
✅ Complete `CasinoKit/GAME_CENTER_PLAN.md` implementation first (shared infrastructure)
## Achievement Design Philosophy
Focus on **gameplay milestones**, **pattern recognition**, and **understanding Baccarat strategy**, not pure luck or bankroll metrics.
Achievements celebrate:
- 🎲 Understanding Baccarat rules and betting
- 📊 Pattern recognition (road maps)
- 💎 High-stakes play (earned through gameplay)
- 🎯 Mastery of side bets
## Baccarat Achievements
### 🎓 Learning & First Steps Category
#### 1. **First Hand**
- **ID:** `com.yourdomain.baccarat.first_hand`
- **Description:** Play your first hand of Baccarat
- **Progress:** Complete on first hand
- **Points:** 5
- **Icon:** `play.circle.fill`
- **Trigger:** After first `finishRound()` completes
#### 2. **Player Believer**
- **ID:** `com.yourdomain.baccarat.player_wins_10`
- **Description:** Win 10 times betting on Player
- **Progress:** Incremental (0-10)
- **Points:** 10
- **Icon:** `person.fill`
- **Trigger:** When Player bet wins
#### 3. **Banker's Trust**
- **ID:** `com.yourdomain.baccarat.banker_wins_25`
- **Description:** Win 25 times betting on Banker
- **Progress:** Incremental (0-25)
- **Points:** 15
- **Icon:** `building.columns.fill`
- **Trigger:** When Banker bet wins
#### 4. **Tie Hunter**
- **ID:** `com.yourdomain.baccarat.tie_wins_5`
- **Description:** Win 5 times betting on Tie
- **Progress:** Incremental (0-5)
- **Points:** 15
- **Icon:** "equal.circle.fill"
- **Trigger:** When Tie bet wins
- **Note:** Higher points due to rarity (14.4% house edge)
### 🎲 Natural & Special Hands Category
#### 5. **Natural Talent**
- **ID:** `com.yourdomain.baccarat.naturals_10`
- **Description:** Get 10 naturals (8 or 9 on initial two cards)
- **Progress:** Incremental (0-10)
- **Points:** 10
- **Icon:** `star.fill`
- **Trigger:** When either Player or Banker gets natural 8 or 9
#### 6. **Natural Legend**
- **ID:** `com.yourdomain.baccarat.naturals_50`
- **Description:** Get 50 naturals
- **Progress:** Incremental (0-50)
- **Points:** 25
- **Icon:** `star.circle.fill`
- **Trigger:** When either Player or Banker gets natural (extended)
#### 7. **Perfect Pair**
- **ID:** `com.yourdomain.baccarat.pair_bets_10`
- **Description:** Win Player Pair or Banker Pair side bet 10 times
- **Progress:** Incremental (0-10)
- **Points:** 15
- **Icon:** `suit.heart.fill`
- **Trigger:** When either pair bet wins
#### 8. **Dragon Master**
- **ID:** `com.yourdomain.baccarat.dragon_bonus_10`
- **Description:** Win Dragon Bonus side bet 10 times
- **Progress:** Incremental (0-10)
- **Points:** 15
- **Icon:** `flame.fill`
- **Trigger:** When Dragon Bonus bet wins
#### 9. **Dragon Legend**
- **ID:** `com.yourdomain.baccarat.dragon_bonus_win_by_9`
- **Description:** Win Dragon Bonus with a 9-point margin (30:1 payout)
- **Progress:** Complete when achieved
- **Points:** 25
- **Icon:** `flame.circle.fill`
- **Trigger:** When Dragon Bonus pays 30:1
- **Note:** Very rare achievement
### 💪 Persistence & Mastery Category
#### 10. **Beginner**
- **ID:** `com.yourdomain.baccarat.rounds_50`
- **Description:** Play 50 total rounds
- **Progress:** Incremental (0-50)
- **Points:** 10
- **Icon:** `person.fill`
- **Trigger:** After each round completes
#### 11. **Enthusiast**
- **ID:** `com.yourdomain.baccarat.rounds_250`
- **Description:** Play 250 total rounds
- **Progress:** Incremental (0-250)
- **Points:** 25
- **Icon:** `person.2.fill`
- **Trigger:** After each round completes
#### 12. **Expert**
- **ID:** `com.yourdomain.baccarat.rounds_500`
- **Description:** Play 500 total rounds
- **Progress:** Incremental (0-500)
- **Points:** 50
- **Icon:** `person.3.fill`
- **Trigger:** After each round completes
#### 13. **Comeback Kid**
- **ID:** `com.yourdomain.baccarat.comeback`
- **Description:** Recover from under $100 to $10,000 in a single session
- **Progress:** Complete when achieved
- **Points:** 25
- **Icon:** `arrow.up.right.circle.fill`
- **Trigger:** When balance reaches $10k after being below $100 in same session
- **Implementation Note:** Track session low point
### 📊 Pattern Recognition & Strategy Category
#### 14. **Streak Spotter**
- **ID:** `com.yourdomain.baccarat.spot_streaks_5`
- **Description:** Correctly predict and bet on a streak 5 times (3+ same outcome in a row)
- **Progress:** Incremental (0-5)
- **Points:** 20
- **Icon:** `chart.line.uptrend.xyaxis`
- **Trigger:** When player bets same side 3+ times in a row and all win
- **Implementation Note:** Track consecutive wins on same bet type
#### 15. **Road Map Reader**
- **ID:** `com.yourdomain.baccarat.view_road_map_25`
- **Description:** View the road map history 25 times
- **Progress:** Incremental (0-25)
- **Points:** 10
- **Icon:** `map.fill`
- **Trigger:** Track when road map view is expanded/scrolled
- **Implementation Note:** Encourages engagement with pattern tracking feature
### 💎 High Stakes Category
#### 16. **High Roller**
- **ID:** `com.yourdomain.baccarat.bet_50000`
- **Description:** Place a single bet of $50,000 or more
- **Progress:** Complete when achieved
- **Points:** 20
- **Icon:** `dollarsign.circle.fill`
- **Trigger:** When any bet equals or exceeds $50,000
- **Implementation Note:** Must be earned through gameplay (requires VIP table limits)
#### 17. **Big Win**
- **ID:** `com.yourdomain.baccarat.single_win_100000`
- **Description:** Win $100,000 or more in a single hand
- **Progress:** Complete when achieved
- **Points:** 30
- **Icon:** `banknote.fill`
- **Trigger:** When net profit from a single round ≥ $100,000
- **Implementation Note:** Possible with Dragon Bonus on large bet
### 🏆 Elite Category
#### 18. **Side Bet Specialist**
- **ID:** `com.yourdomain.baccarat.side_bets_total_25`
- **Description:** Win any side bet 25 times total
- **Progress:** Incremental (0-25)
- **Points:** 25
- **Icon:** `plus.circle.fill`
- **Trigger:** Any time a side bet wins (Pairs or Dragon Bonus)
#### 19. **James Bond** (Hidden Achievement)
- **ID:** `com.yourdomain.baccarat.james_bond`
- **Description:** Play 100 consecutive hands betting only on Banker
- **Progress:** Incremental (0-100, resets if different bet placed)
- **Points:** 25
- **Icon:** `tuxedo.fill` (or `theatermasks.fill`)
- **Trigger:** Track consecutive Banker-only bets
- **Implementation Note:** Resets to 0 if player bets on Player or Tie
- **Fun fact:** James Bond's favorite game and typical bet
#### 20. **Table Explorer** (Hidden Achievement)
- **ID:** `com.yourdomain.baccarat.all_table_limits`
- **Description:** Play at least 10 rounds at each table limit level
- **Progress:** Incremental (0-50, 10 per table × 5 tables)
- **Points:** 15
- **Icon:** `chart.bar.fill`
- **Trigger:** Track rounds played at each table limit (Casual, Low, Medium, High, VIP)
## Implementation Steps
### 1. Define Achievement Enum
**File:** `Baccarat/Baccarat/Models/BaccaratAchievement.swift` (new file)
```swift
import CasinoKit
import GameKit
enum BaccaratAchievement: String, AchievementDefinition {
case firstHand = "first_hand"
case playerWins10 = "player_wins_10"
case bankerWins25 = "banker_wins_25"
case tieWins5 = "tie_wins_5"
case naturals10 = "naturals_10"
case naturals50 = "naturals_50"
case pairBets10 = "pair_bets_10"
case dragonBonus10 = "dragon_bonus_10"
case dragonBonusWinBy9 = "dragon_bonus_win_by_9"
case rounds50 = "rounds_50"
case rounds250 = "rounds_250"
case rounds500 = "rounds_500"
case comeback = "comeback"
case spotStreaks5 = "spot_streaks_5"
case viewRoadMap25 = "view_road_map_25"
case bet50000 = "bet_50000"
case singleWin100000 = "single_win_100000"
case sideBetsTotal25 = "side_bets_total_25"
case jamesBond = "james_bond"
case allTableLimits = "all_table_limits"
var identifier: String {
"com.yourdomain.baccarat.\(rawValue)"
}
var title: String {
switch self {
case .firstHand: return String(localized: "First Hand")
case .playerWins10: return String(localized: "Player Believer")
case .bankerWins25: return String(localized: "Banker's Trust")
case .tieWins5: return String(localized: "Tie Hunter")
case .naturals10: return String(localized: "Natural Talent")
case .naturals50: return String(localized: "Natural Legend")
case .pairBets10: return String(localized: "Perfect Pair")
case .dragonBonus10: return String(localized: "Dragon Master")
case .dragonBonusWinBy9: return String(localized: "Dragon Legend")
case .rounds50: return String(localized: "Beginner")
case .rounds250: return String(localized: "Enthusiast")
case .rounds500: return String(localized: "Expert")
case .comeback: return String(localized: "Comeback Kid")
case .spotStreaks5: return String(localized: "Streak Spotter")
case .viewRoadMap25: return String(localized: "Road Map Reader")
case .bet50000: return String(localized: "High Roller")
case .singleWin100000: return String(localized: "Big Win")
case .sideBetsTotal25: return String(localized: "Side Bet Specialist")
case .jamesBond: return String(localized: "James Bond")
case .allTableLimits: return String(localized: "Table Explorer")
}
}
var description: String {
// Full descriptions for each achievement
}
var maxProgress: Int {
switch self {
case .firstHand, .comeback, .dragonBonusWinBy9, .bet50000, .singleWin100000: return 1
case .tieWins5, .spotStreaks5: return 5
case .playerWins10, .naturals10, .pairBets10, .dragonBonus10: return 10
case .bankerWins25, .sideBetsTotal25, .viewRoadMap25: return 25
case .naturals50, .rounds50, .allTableLimits: return 50
case .jamesBond: return 100
case .rounds250: return 250
case .rounds500: return 500
}
}
var isIncremental: Bool {
switch self {
case .firstHand, .comeback, .dragonBonusWinBy9, .bet50000, .singleWin100000:
return false
default:
return true
}
}
var iconName: String {
switch self {
case .firstHand: return "play.circle.fill"
case .playerWins10: return "person.fill"
case .bankerWins25: return "building.columns.fill"
case .tieWins5: return "equal.circle.fill"
case .naturals10: return "star.fill"
case .naturals50: return "star.circle.fill"
case .pairBets10: return "suit.heart.fill"
case .dragonBonus10: return "flame.fill"
case .dragonBonusWinBy9: return "flame.circle.fill"
case .rounds50: return "person.fill"
case .rounds250: return "person.2.fill"
case .rounds500: return "person.3.fill"
case .comeback: return "arrow.up.right.circle.fill"
case .spotStreaks5: return "chart.line.uptrend.xyaxis"
case .viewRoadMap25: return "map.fill"
case .bet50000: return "dollarsign.circle.fill"
case .singleWin100000: return "banknote.fill"
case .sideBetsTotal25: return "plus.circle.fill"
case .jamesBond: return "theatermasks.fill"
case .allTableLimits: return "chart.bar.fill"
}
}
}
```
### 2. Add Achievement Tracker to GameState
**File:** `Baccarat/Baccarat/Engine/GameState.swift`
```swift
import CasinoKit
@MainActor
@Observable
class GameState {
// ... existing properties ...
// NEW: Achievement tracking
private(set) var achievementTracker: AchievementTracker<BaccaratAchievement>
// Track session-specific metrics
private var sessionLowBalance: Int = 0
private var consecutiveBankerBets = 0
private var consecutiveSameBetType: BetType? = nil
private var consecutiveSameBetWins = 0
private var roundsPerTableLimit: [String: Int] = [:]
init() {
// ... existing init ...
self.achievementTracker = AchievementTracker<BaccaratAchievement>()
self.sessionLowBalance = balance
}
// NEW: Achievement checking methods
func checkAchievements(after action: GameAction) {
// Called after each game action
}
private func updateSessionTracking() {
if balance < sessionLowBalance {
sessionLowBalance = balance
}
// Check comeback achievement
if sessionLowBalance < 100 && balance >= 10_000 {
achievementTracker.complete(.comeback)
}
}
}
```
### 3. Add Achievement Triggers
Add achievement checks throughout game logic:
**In `BaccaratEngine.swift` or `GameState.swift`:**
```swift
// After round completes
func finishRound() {
// ... existing logic ...
// First hand achievement
if totalRoundsPlayed == 1 {
achievementTracker.complete(.firstHand)
}
// Persistence achievements
achievementTracker.increment(.rounds50)
achievementTracker.increment(.rounds250)
achievementTracker.increment(.rounds500)
// Track table limits
let limitKey = settings.tableLimit.displayName
roundsPerTableLimit[limitKey, default: 0] += 1
if roundsPerTableLimit.values.filter({ $0 >= 10 }).count == 5 {
achievementTracker.complete(.allTableLimits)
}
updateSessionTracking()
}
// When placing bets
func placeBet(type: BetType, amount: Int) {
// ... existing logic ...
// High roller achievement
if amount >= 50_000 {
achievementTracker.complete(.bet50000)
}
// James Bond tracking (consecutive Banker bets)
if type == .banker {
consecutiveBankerBets += 1
if consecutiveBankerBets >= 100 {
achievementTracker.complete(.jamesBond)
}
} else {
consecutiveBankerBets = 0
}
// Streak tracking
if type == consecutiveSameBetType {
// Continue tracking
} else {
consecutiveSameBetType = type
consecutiveSameBetWins = 0
}
}
// After determining winner
func evaluateRound() {
// ... existing logic ...
// Natural achievements
if playerHand.isNatural || bankerHand.isNatural {
achievementTracker.increment(.naturals10)
achievementTracker.increment(.naturals50)
}
// Check main bet wins
if playerBetWon {
achievementTracker.increment(.playerWins10)
if consecutiveSameBetType == .player {
consecutiveSameBetWins += 1
if consecutiveSameBetWins >= 3 {
achievementTracker.increment(.spotStreaks5)
}
}
}
if bankerBetWon {
achievementTracker.increment(.bankerWins25)
if consecutiveSameBetType == .banker {
consecutiveSameBetWins += 1
if consecutiveSameBetWins >= 3 {
achievementTracker.increment(.spotStreaks5)
}
}
}
if tieBetWon {
achievementTracker.increment(.tieWins5)
}
// Side bet achievements
if playerPairWon || bankerPairWon {
achievementTracker.increment(.pairBets10)
achievementTracker.increment(.sideBetsTotal25)
}
if dragonBonusWon {
achievementTracker.increment(.dragonBonus10)
achievementTracker.increment(.sideBetsTotal25)
// Check for 9-point margin win
if dragonBonusMargin == 9 {
achievementTracker.complete(.dragonBonusWinBy9)
}
}
// Big win achievement
let netProfit = calculateNetProfit()
if netProfit >= 100_000 {
achievementTracker.complete(.singleWin100000)
}
}
// When road map is viewed
func trackRoadMapView() {
achievementTracker.increment(.viewRoadMap25)
}
```
### 4. Add Road Map View Tracking
**File:** `Baccarat/Baccarat/Views/Table/RoadMapView.swift` (or wherever road map is displayed)
```swift
.onAppear {
state.trackRoadMapView()
}
```
### 5. Add Game Center to Settings
**File:** `Baccarat/Baccarat/Views/Sheets/SettingsView.swift`
```swift
import CasinoKit
struct SettingsView: View {
// ... existing code ...
var body: some View {
SheetContainerView(title: String(localized: "Settings")) {
// ... existing sections ...
// NEW: Game Center section
GameCenterSettingsSection()
} onDone: {
dismiss()
}
}
}
```
### 6. Optional: Add Game Center Access Point
**File:** `Baccarat/Baccarat/Views/Game/GameTableView.swift`
```swift
TopBarView(
balance: state.balance,
// ... existing parameters ...
leadingButtons: [
TopBarButton(
icon: "gamecontroller.fill",
accessibilityLabel: "Game Center"
) {
GameCenterManager.shared.showGameCenterDashboard()
}
]
)
```
### 7. Initialize Game Center on App Launch
**File:** `Baccarat/Baccarat/BaccaratApp.swift`
```swift
import CasinoKit
@main
struct BaccaratApp: App {
init() {
// Authenticate with Game Center silently
Task {
await GameCenterManager.shared.authenticate()
}
}
// ... rest of app ...
}
```
### 8. Add Localized Strings
**File:** `Baccarat/Baccarat/Resources/Localizable.xcstrings`
Add all achievement titles, descriptions, and Game Center UI strings.
## App Store Connect Configuration
### For Each Achievement:
1. Log into App Store Connect
2. Select Baccarat app
3. Go to Game Center → Achievements
4. Click "+" to add achievement
5. Configure:
- **Reference Name:** (internal only)
- **Achievement ID:** Must match enum identifier
- **Point Value:** As specified above
- **Hidden:** Set to "Yes" for James Bond and Table Explorer
- **Achievable More Than Once:** No for all
- **Localization:** Add EN, ES-MX, FR-CA
- **Images:** Upload 512x512 and 1024x1024 versions
## Testing Checklist
- [ ] All achievements can be triggered in game
- [ ] Incremental achievements show progress
- [ ] Hidden achievements don't appear until unlocked
- [ ] James Bond achievement resets on non-Banker bet
- [ ] Streak tracking works correctly (3+ consecutive wins)
- [ ] Road map view tracking increments
- [ ] Table limit tracking works across all 5 limits
- [ ] Big win achievement triggers at $100k profit
- [ ] Dragon Bonus 9-point margin detected correctly
- [ ] Comeback achievement tracks session low properly
## Edge Cases to Handle
1. **Player resets game mid-session** - Session achievements (comeback) should reset
2. **Multiple simultaneous bets** - Track all winning bet types for achievements
3. **Tie pushes main bet** - Don't count as "win" for streak tracking
4. **Switching table limits** - Properly track rounds per limit
5. **Offline play** - Queue achievements, submit when online
## Future Enhancements
- **Achievement notifications** - Use CasinoKit's AchievementToast
- **Progress UI** - Show achievement progress in statistics view
- **Pattern hints** - Suggest when player is on a streak (Road Map Reader tie-in)
---
## Summary
- ✅ 20 total achievements
- ✅ Focus on gameplay understanding, pattern recognition, and milestones
- ✅ Two hidden achievements (James Bond, Table Explorer)
- ✅ Incremental progress for most achievements
- ✅ Unique Baccarat-specific achievements (road maps, Dragon Bonus, streaks)
- ✅ Integration with existing GameState and road map system
- ✅ No code duplication (uses CasinoKit infrastructure)
**Estimated Integration Time:** 2-3 hours after CasinoKit infrastructure is complete.
---
*See `CasinoKit/GAME_CENTER_PLAN.md` for shared infrastructure implementation details.*