555 lines
17 KiB
Markdown
555 lines
17 KiB
Markdown
# Game Center Integration - Blackjack
|
||
|
||
This document outlines the Game Center achievements for Blackjack and the game-specific integration steps.
|
||
|
||
## Prerequisites
|
||
|
||
✅ Complete `CasinoKit/GAME_CENTER_PLAN.md` implementation first (shared infrastructure)
|
||
|
||
## Achievement Design Philosophy
|
||
|
||
Focus on **learning milestones** and **skill demonstration**, not bankroll/luck-based metrics.
|
||
|
||
Achievements celebrate:
|
||
- 📚 Learning basic strategy
|
||
- 🎓 Card counting practice
|
||
- 🎯 Gameplay milestones
|
||
- 💪 Persistence and mastery
|
||
|
||
## Blackjack Achievements
|
||
|
||
### 🎓 Learning & Strategy Category
|
||
|
||
#### 1. **First Hand**
|
||
- **ID:** `com.yourdomain.blackjack.first_hand`
|
||
- **Description:** Play your first hand of Blackjack
|
||
- **Progress:** Complete on first hand
|
||
- **Points:** 5
|
||
- **Icon:** `play.circle.fill`
|
||
- **Trigger:** After first `finishRound()` completes
|
||
|
||
#### 2. **Strategy Student**
|
||
- **ID:** `com.yourdomain.blackjack.strategy_student`
|
||
- **Description:** Play 50 hands following perfect basic strategy
|
||
- **Progress:** Incremental (0-50)
|
||
- **Points:** 10
|
||
- **Icon:** `book.fill`
|
||
- **Trigger:** Each hand where player follows all hint recommendations
|
||
- **Implementation Note:** Track in `GameState` when hint matches action taken
|
||
|
||
#### 3. **Strategy Master**
|
||
- **ID:** `com.yourdomain.blackjack.strategy_master`
|
||
- **Description:** Play 100 hands following perfect basic strategy
|
||
- **Progress:** Incremental (0-100)
|
||
- **Points:** 25
|
||
- **Icon:** `graduationcap.fill`
|
||
- **Trigger:** Same as Strategy Student, extended goal
|
||
|
||
#### 4. **Card Counter**
|
||
- **ID:** `com.yourdomain.blackjack.card_counter`
|
||
- **Description:** Play 25 hands using the Hi-Lo counting system
|
||
- **Progress:** Incremental (0-25)
|
||
- **Points:** 15
|
||
- **Icon:** `brain.head.profile`
|
||
- **Trigger:** When `settings.showCount` is enabled and hand completes
|
||
- **Implementation Note:** Must have counting enabled in settings
|
||
|
||
#### 5. **True Count Master**
|
||
- **ID:** `com.yourdomain.blackjack.true_count_master`
|
||
- **Description:** Make 10 correct betting decisions based on true count
|
||
- **Progress:** Incremental (0-10)
|
||
- **Points:** 20
|
||
- **Icon:** `chart.line.uptrend.xyaxis`
|
||
- **Trigger:** When player increases bet with positive true count (+2 or higher)
|
||
- **Implementation Note:** Track bet increases that align with count recommendations
|
||
|
||
### 🎯 Gameplay Milestones Category
|
||
|
||
#### 6. **Natural Talent**
|
||
- **ID:** `com.yourdomain.blackjack.natural_10`
|
||
- **Description:** Get 10 Blackjacks (natural 21)
|
||
- **Progress:** Incremental (0-10)
|
||
- **Points:** 10
|
||
- **Icon:** `star.fill`
|
||
- **Trigger:** When player hand is natural blackjack
|
||
|
||
#### 7. **Natural Legend**
|
||
- **ID:** `com.yourdomain.blackjack.natural_50`
|
||
- **Description:** Get 50 Blackjacks
|
||
- **Progress:** Incremental (0-50)
|
||
- **Points:** 25
|
||
- **Icon:** `star.circle.fill`
|
||
- **Trigger:** When player hand is natural blackjack (extended)
|
||
|
||
#### 8. **Split Decision**
|
||
- **ID:** `com.yourdomain.blackjack.split_wins_10`
|
||
- **Description:** Win with split hands 10 times
|
||
- **Progress:** Incremental (0-10)
|
||
- **Points:** 10
|
||
- **Icon:** `rectangle.split.2x1.fill`
|
||
- **Trigger:** When a split hand wins against dealer
|
||
|
||
#### 9. **Double Down Dynamo**
|
||
- **ID:** `com.yourdomain.blackjack.double_wins_15`
|
||
- **Description:** Win 15 hands after doubling down
|
||
- **Progress:** Incremental (0-15)
|
||
- **Points:** 15
|
||
- **Icon:** `arrow.down.circle.fill`
|
||
- **Trigger:** When player wins a hand after doubling down
|
||
|
||
#### 10. **Insurance Agent**
|
||
- **ID:** `com.yourdomain.blackjack.insurance_wins_5`
|
||
- **Description:** Win insurance bet 5 times
|
||
- **Progress:** Incremental (0-5)
|
||
- **Points:** 10
|
||
- **Icon:** `shield.checkered`
|
||
- **Trigger:** When dealer has blackjack and player took insurance
|
||
|
||
### 💪 Persistence & Mastery Category
|
||
|
||
#### 11. **Rookie**
|
||
- **ID:** `com.yourdomain.blackjack.hands_100`
|
||
- **Description:** Play 100 total hands
|
||
- **Progress:** Incremental (0-100)
|
||
- **Points:** 10
|
||
- **Icon:** `person.fill`
|
||
- **Trigger:** After each hand completes
|
||
|
||
#### 12. **Regular**
|
||
- **ID:** `com.yourdomain.blackjack.hands_500`
|
||
- **Description:** Play 500 total hands
|
||
- **Progress:** Incremental (0-500)
|
||
- **Points:** 25
|
||
- **Icon:** `person.2.fill`
|
||
- **Trigger:** After each hand completes
|
||
|
||
#### 13. **Veteran**
|
||
- **ID:** `com.yourdomain.blackjack.hands_1000`
|
||
- **Description:** Play 1,000 total hands
|
||
- **Progress:** Incremental (0-1000)
|
||
- **Points:** 50
|
||
- **Icon:** `person.3.fill`
|
||
- **Trigger:** After each hand completes
|
||
|
||
#### 14. **Comeback Kid**
|
||
- **ID:** `com.yourdomain.blackjack.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
|
||
|
||
#### 15. **Perfect Pair Player**
|
||
- **ID:** `com.yourdomain.blackjack.perfect_pairs_5`
|
||
- **Description:** Win Perfect Pairs side bet 5 times
|
||
- **Progress:** Incremental (0-5)
|
||
- **Points:** 10
|
||
- **Icon:** `suit.heart.fill`
|
||
- **Trigger:** When Perfect Pairs side bet wins
|
||
|
||
#### 16. **21+3 Champion**
|
||
- **ID:** `com.yourdomain.blackjack.twentyone_plus_three_5`
|
||
- **Description:** Win 21+3 side bet 5 times
|
||
- **Progress:** Incremental (0-5)
|
||
- **Points:** 10
|
||
- **Icon:** `suit.diamond.fill`
|
||
- **Trigger:** When 21+3 side bet wins
|
||
|
||
### 🏆 Elite Category
|
||
|
||
#### 17. **Side Bet Specialist**
|
||
- **ID:** `com.yourdomain.blackjack.side_bet_wins_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 (Perfect Pairs or 21+3)
|
||
|
||
#### 18. **Rule Breaker** (Hidden Achievement)
|
||
- **ID:** `com.yourdomain.blackjack.all_rule_variations`
|
||
- **Description:** Play at least 10 hands with each rule variation
|
||
- **Progress:** Incremental (0-40, 10 per variation × 4 variations)
|
||
- **Points:** 15
|
||
- **Icon:** `gearshape.2.fill`
|
||
- **Trigger:** Track which rule sets have been played
|
||
- **Implementation Note:** Vegas Strip, Atlantic City, European, Custom (10 hands each)
|
||
|
||
## Implementation Steps
|
||
|
||
### 1. Define Achievement Enum
|
||
|
||
**File:** `Blackjack/Blackjack/Models/BlackjackAchievement.swift` (new file)
|
||
|
||
```swift
|
||
import CasinoKit
|
||
import GameKit
|
||
|
||
enum BlackjackAchievement: String, AchievementDefinition {
|
||
case firstHand = "first_hand"
|
||
case strategyStudent = "strategy_student"
|
||
case strategyMaster = "strategy_master"
|
||
case cardCounter = "card_counter"
|
||
case trueCountMaster = "true_count_master"
|
||
case natural10 = "natural_10"
|
||
case natural50 = "natural_50"
|
||
case splitWins10 = "split_wins_10"
|
||
case doubleWins15 = "double_wins_15"
|
||
case insuranceWins5 = "insurance_wins_5"
|
||
case hands100 = "hands_100"
|
||
case hands500 = "hands_500"
|
||
case hands1000 = "hands_1000"
|
||
case comeback = "comeback"
|
||
case perfectPairs5 = "perfect_pairs_5"
|
||
case twentyOnePlusThree5 = "twentyone_plus_three_5"
|
||
case sideBetWins25 = "side_bet_wins_25"
|
||
case allRuleVariations = "all_rule_variations"
|
||
|
||
var identifier: String {
|
||
"com.yourdomain.blackjack.\(rawValue)"
|
||
}
|
||
|
||
var title: String {
|
||
switch self {
|
||
case .firstHand: return String(localized: "First Hand")
|
||
case .strategyStudent: return String(localized: "Strategy Student")
|
||
case .strategyMaster: return String(localized: "Strategy Master")
|
||
case .cardCounter: return String(localized: "Card Counter")
|
||
case .trueCountMaster: return String(localized: "True Count Master")
|
||
case .natural10: return String(localized: "Natural Talent")
|
||
case .natural50: return String(localized: "Natural Legend")
|
||
case .splitWins10: return String(localized: "Split Decision")
|
||
case .doubleWins15: return String(localized: "Double Down Dynamo")
|
||
case .insuranceWins5: return String(localized: "Insurance Agent")
|
||
case .hands100: return String(localized: "Rookie")
|
||
case .hands500: return String(localized: "Regular")
|
||
case .hands1000: return String(localized: "Veteran")
|
||
case .comeback: return String(localized: "Comeback Kid")
|
||
case .perfectPairs5: return String(localized: "Perfect Pair Player")
|
||
case .twentyOnePlusThree5: return String(localized: "21+3 Champion")
|
||
case .sideBetWins25: return String(localized: "Side Bet Specialist")
|
||
case .allRuleVariations: return String(localized: "Rule Breaker")
|
||
}
|
||
}
|
||
|
||
var description: String {
|
||
// Full descriptions for each achievement
|
||
}
|
||
|
||
var maxProgress: Int {
|
||
switch self {
|
||
case .firstHand, .comeback: return 1
|
||
case .insuranceWins5, .perfectPairs5, .twentyOnePlusThree5: return 5
|
||
case .splitWins10, .natural10: return 10
|
||
case .doubleWins15: return 15
|
||
case .cardCounter, .sideBetWins25, .strategyMaster: return 25
|
||
case .strategyStudent, .natural50: return 50
|
||
case .hands100: return 100
|
||
case .hands500: return 500
|
||
case .hands1000: return 1000
|
||
case .trueCountMaster: return 10
|
||
case .allRuleVariations: return 40
|
||
}
|
||
}
|
||
|
||
var isIncremental: Bool {
|
||
self != .firstHand && self != .comeback
|
||
}
|
||
|
||
var iconName: String {
|
||
switch self {
|
||
case .firstHand: return "play.circle.fill"
|
||
case .strategyStudent: return "book.fill"
|
||
case .strategyMaster: return "graduationcap.fill"
|
||
case .cardCounter: return "brain.head.profile"
|
||
case .trueCountMaster: return "chart.line.uptrend.xyaxis"
|
||
case .natural10: return "star.fill"
|
||
case .natural50: return "star.circle.fill"
|
||
case .splitWins10: return "rectangle.split.2x1.fill"
|
||
case .doubleWins15: return "arrow.down.circle.fill"
|
||
case .insuranceWins5: return "shield.checkered"
|
||
case .hands100: return "person.fill"
|
||
case .hands500: return "person.2.fill"
|
||
case .hands1000: return "person.3.fill"
|
||
case .comeback: return "arrow.up.right.circle.fill"
|
||
case .perfectPairs5: return "suit.heart.fill"
|
||
case .twentyOnePlusThree5: return "suit.diamond.fill"
|
||
case .sideBetWins25: return "plus.circle.fill"
|
||
case .allRuleVariations: return "gearshape.2.fill"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. Add Achievement Tracker to GameState
|
||
|
||
**File:** `Blackjack/Blackjack/Engine/GameState.swift`
|
||
|
||
```swift
|
||
import CasinoKit
|
||
|
||
@MainActor
|
||
@Observable
|
||
class GameState {
|
||
// ... existing properties ...
|
||
|
||
// NEW: Achievement tracking
|
||
private(set) var achievementTracker: AchievementTracker<BlackjackAchievement>
|
||
|
||
// Track session-specific metrics for achievements
|
||
private var sessionLowBalance: Int = 0
|
||
private var handsPlayedThisSession = 0
|
||
private var lastActionWasStrategyOptimal = false
|
||
|
||
init() {
|
||
// ... existing init ...
|
||
|
||
self.achievementTracker = AchievementTracker<BlackjackAchievement>()
|
||
self.sessionLowBalance = balance
|
||
}
|
||
|
||
// NEW: Achievement checking methods
|
||
func checkAchievements(after action: GameAction) {
|
||
// Called after each game action
|
||
// Check relevant achievements based on action type
|
||
}
|
||
|
||
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 `BlackjackEngine.swift` or `GameState.swift`:**
|
||
|
||
```swift
|
||
// After dealing initial cards
|
||
if playerHand.isBlackjack {
|
||
achievementTracker.increment(.natural10)
|
||
achievementTracker.increment(.natural50)
|
||
}
|
||
|
||
// After completing a hand
|
||
func finishRound() {
|
||
// ... existing logic ...
|
||
|
||
// First hand achievement
|
||
if totalHandsPlayed == 1 {
|
||
achievementTracker.complete(.firstHand)
|
||
}
|
||
|
||
// Persistence achievements
|
||
achievementTracker.increment(.hands100)
|
||
achievementTracker.increment(.hands500)
|
||
achievementTracker.increment(.hands1000)
|
||
|
||
// Check if strategy was followed
|
||
if lastActionWasStrategyOptimal {
|
||
achievementTracker.increment(.strategyStudent)
|
||
achievementTracker.increment(.strategyMaster)
|
||
}
|
||
|
||
// Card counting achievements
|
||
if settings.showCount {
|
||
achievementTracker.increment(.cardCounter)
|
||
|
||
// Check if bet was adjusted based on count
|
||
if betWasIncreasedWithPositiveCount {
|
||
achievementTracker.increment(.trueCountMaster)
|
||
}
|
||
}
|
||
|
||
updateSessionTracking()
|
||
}
|
||
|
||
// After winning with split
|
||
func checkSplitWin() {
|
||
if handWasSplit && playerWon {
|
||
achievementTracker.increment(.splitWins10)
|
||
}
|
||
}
|
||
|
||
// After winning with double down
|
||
func checkDoubleWin() {
|
||
if playerDoubledDown && playerWon {
|
||
achievementTracker.increment(.doubleWins15)
|
||
}
|
||
}
|
||
|
||
// After insurance win
|
||
func checkInsuranceWin() {
|
||
if insuranceBetWon {
|
||
achievementTracker.increment(.insuranceWins5)
|
||
}
|
||
}
|
||
|
||
// After side bet wins
|
||
func checkSideBetWins() {
|
||
if perfectPairsBetWon {
|
||
achievementTracker.increment(.perfectPairs5)
|
||
achievementTracker.increment(.sideBetWins25)
|
||
}
|
||
|
||
if twentyOnePlusThreeBetWon {
|
||
achievementTracker.increment(.twentyOnePlusThree5)
|
||
achievementTracker.increment(.sideBetWins25)
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. Add Game Center to Settings
|
||
|
||
**File:** `Blackjack/Blackjack/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()
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5. Optional: Add Game Center Access Point
|
||
|
||
**File:** `Blackjack/Blackjack/Views/Game/GameTableView.swift`
|
||
|
||
Add to top bar or as floating overlay:
|
||
|
||
```swift
|
||
TopBarView(
|
||
balance: state.balance,
|
||
// ... existing parameters ...
|
||
leadingButtons: [
|
||
TopBarButton(
|
||
icon: "gamecontroller.fill",
|
||
accessibilityLabel: "Game Center"
|
||
) {
|
||
GameCenterManager.shared.showGameCenterDashboard()
|
||
}
|
||
]
|
||
)
|
||
```
|
||
|
||
### 6. Initialize Game Center on App Launch
|
||
|
||
**File:** `Blackjack/Blackjack/BlackjackApp.swift`
|
||
|
||
```swift
|
||
import CasinoKit
|
||
|
||
@main
|
||
struct BlackjackApp: App {
|
||
init() {
|
||
// Authenticate with Game Center silently
|
||
Task {
|
||
await GameCenterManager.shared.authenticate()
|
||
}
|
||
}
|
||
|
||
// ... rest of app ...
|
||
}
|
||
```
|
||
|
||
### 7. Add Localized Strings
|
||
|
||
**File:** `Blackjack/Blackjack/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 Blackjack app
|
||
3. Go to Game Center → Achievements
|
||
4. Click "+" to add achievement
|
||
5. Configure:
|
||
- **Reference Name:** (internal only, e.g., "Strategy Student")
|
||
- **Achievement ID:** Must match enum identifier (e.g., `com.yourdomain.blackjack.strategy_student`)
|
||
- **Point Value:** As specified above
|
||
- **Hidden:** Set to "Yes" for hidden achievements (Rule Breaker)
|
||
- **Achievable More Than Once:** No for all
|
||
- **Pre-iOS 14 Gamers:** Leave unchecked
|
||
- **Localization:** Add EN, ES-MX, FR-CA with titles/descriptions
|
||
- **Images:** Upload 512x512 and 1024x1024 versions
|
||
|
||
### Achievement Icon Assets
|
||
|
||
Create icons matching the SF Symbols specified in the achievement enum. Use your app's color scheme (golds, blues, casino theme).
|
||
|
||
## Testing Checklist
|
||
|
||
- [ ] All achievements can be triggered in game
|
||
- [ ] Incremental achievements show progress correctly
|
||
- [ ] Achievements appear in Game Center dashboard
|
||
- [ ] Achievements work offline (queue and submit later)
|
||
- [ ] Achievement tracking persists across app launches
|
||
- [ ] Localization works for all three languages
|
||
- [ ] VoiceOver announces achievement unlocks
|
||
- [ ] Settings section shows correct Game Center status
|
||
- [ ] Strategy-based achievements verify correct play
|
||
- [ ] Card counting achievements only trigger when enabled
|
||
|
||
## Edge Cases to Handle
|
||
|
||
1. **Player resets game mid-session** - Session achievements (comeback) should reset
|
||
2. **Player changes rule variations** - Track separately for "Rule Breaker"
|
||
3. **Player disables hints** - Strategy achievements still trackable via engine logic
|
||
4. **Offline play** - Queue achievements, submit when online
|
||
5. **Multiple devices** - Game Center syncs achievement progress automatically
|
||
|
||
## Analytics to Track (Optional)
|
||
|
||
Consider adding local analytics to understand achievement engagement:
|
||
- Which achievements are earned most often?
|
||
- Average time to complete each achievement
|
||
- Percentage of players who enable card counting (for targeted education)
|
||
|
||
## Future Enhancements
|
||
|
||
- **Achievement notifications** - Show toast when unlocked (use CasinoKit's AchievementToast)
|
||
- **Progress tracking UI** - Show achievement progress in stats view
|
||
- **Suggested next achievement** - Guide players toward specific goals
|
||
|
||
---
|
||
|
||
## Summary
|
||
|
||
- ✅ 18 total achievements
|
||
- ✅ Focus on learning and skill, not luck/bankroll
|
||
- ✅ Incremental progress for most achievements
|
||
- ✅ Hidden achievement for exploring all rule variations
|
||
- ✅ Integration with existing GameState and statistics
|
||
- ✅ 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.*
|
||
|