Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Cribbage Scorer.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 15.6;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.affolk.cribbage;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand Down Expand Up @@ -316,7 +316,7 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/Frameworks";
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 15.6;
MARKETING_VERSION = 2.0.0;
MARKETING_VERSION = 2.1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.affolk.cribbage;
PRODUCT_NAME = "$(TARGET_NAME)";
REGISTER_APP_GROUPS = YES;
Expand Down
53 changes: 50 additions & 3 deletions Cribbage Scorer/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class GameViewModel: ObservableObject {
@Published var showConfetti = false
@Published var showSkunk = false
@Published var winner: String?
@Published var skunkedPlayer: Int? // 1 or 2, the player who got skunked

let winningScore = 121
let skunkDifference = 30
Expand Down Expand Up @@ -81,9 +82,12 @@ class GameViewModel: ObservableObject {
if winnerScore - loserScore > skunkDifference {
showSkunk = true
showConfetti = false
// Track which player got skunked (the loser)
skunkedPlayer = playerNumber == 1 ? 2 : 1
} else {
showSkunk = false
showConfetti = true
skunkedPlayer = nil
}

showWinnerModal = true
Expand All @@ -99,6 +103,7 @@ class GameViewModel: ObservableObject {
showConfetti = false
showSkunk = false
winner = nil
skunkedPlayer = nil
}
}

Expand All @@ -107,6 +112,18 @@ struct ContentView: View {
@StateObject private var viewModel = GameViewModel()
@State private var showResetConfirmation = false

// Danger color for when player is 30+ points behind (#EE0000)
let dangerColor = Color(red: 0xEE / 255.0, green: 0x00 / 255.0, blue: 0x00 / 255.0)

// Check if players are in danger of being skunked
var player1InDanger: Bool {
viewModel.player2MainScore - viewModel.player1MainScore >= 30
}

var player2InDanger: Bool {
viewModel.player1MainScore - viewModel.player2MainScore >= 30
}

var body: some View {
ZStack {
VStack(spacing: 0) {
Expand All @@ -115,7 +132,7 @@ struct ContentView: View {
mainScore: viewModel.player1MainScore,
floatingScore: viewModel.player1FloatingScore,
backgroundColor: .black,
foregroundColor: .white,
foregroundColor: player1InDanger ? dangerColor : .white,
isRotated: true,
onScoreButtonTap: { value in
viewModel.addToFloatingScore(player: 1, value: value)
Expand All @@ -128,12 +145,40 @@ struct ContentView: View {
}
)

// Progress bars at the middle divider
VStack(spacing: 0) {
// Top player's white progress bar
GeometryReader { geometry in
HStack(spacing: 0) {
Rectangle()
.fill(player1InDanger ? dangerColor : Color.white)
.frame(width: geometry.size.width * CGFloat(min(viewModel.player1MainScore, 121)) / 121.0)
Spacer(minLength: 0)
}
}
.frame(height: 10)
.background(Color.black)

// Bottom player's black progress bar
GeometryReader { geometry in
HStack(spacing: 0) {
Rectangle()
.fill(player2InDanger ? dangerColor : Color.black)
.frame(width: geometry.size.width * CGFloat(min(viewModel.player2MainScore, 121)) / 121.0)
Spacer(minLength: 0)
}
}
.frame(height: 10)
.background(Color.white)
}
.frame(height: 20)

// Bottom Player (Player 2)
PlayerSection(
mainScore: viewModel.player2MainScore,
floatingScore: viewModel.player2FloatingScore,
backgroundColor: .white,
foregroundColor: .black,
foregroundColor: player2InDanger ? dangerColor : .black,
isRotated: false,
onScoreButtonTap: { value in
viewModel.addToFloatingScore(player: 2, value: value)
Expand All @@ -157,7 +202,7 @@ struct ContentView: View {

// SKUNK overlay
if viewModel.showSkunk {
SkunkView()
SkunkView(skunkedPlayer: viewModel.skunkedPlayer ?? 2)
.ignoresSafeArea()
.allowsHitTesting(false)
}
Expand Down Expand Up @@ -524,6 +569,7 @@ struct DiscoEmojiView: View {

// MARK: - SKUNK ATTACK 🦨
struct SkunkView: View {
let skunkedPlayer: Int // 1 = top player, 2 = bottom player
@State private var skunks: [SpinningSkunk] = []
@State private var rainbowHue: Double = 0
@State private var skunkTextScale: CGFloat = 0.1
Expand Down Expand Up @@ -566,6 +612,7 @@ struct SkunkView: View {
.rotationEffect(.degrees(skunkTextRotation))
.position(x: geometry.size.width / 2, y: geometry.size.height / 2)
}
.rotationEffect(.degrees(skunkedPlayer == 1 ? 180 : 0))
.onAppear {
startSkunkAttack(in: geometry.size)
}
Expand Down