Setup

library(qualtRics)   # read_survey()
library(tidyverse)
library(psych)       # alpha(), describeBy()
library(effectsize)  # cohens_d(), eta_squared()
library(lme4)        # (if needed for mixed models later)
library(interactions) # interact_plot()
library(ggpubr)      # publication-ready plots
library(knitr)
library(kableExtra)

Load & Clean Data

# read_survey() handles the Qualtrics two-header row structure and
# imports numeric values (not labels) automatically
raw <- read_survey("~/Google drive/My Drive/YEAR 3/PROJECTS/DANIEL/Competitive Jungle/competitive jungle game: easy v. hard (260611)_June 15, 2026_07.51.csv")

# Keep only finished, non-preview responses
d <- raw %>%
  filter(Finished == TRUE, DistributionChannel != "preview") %>%
  # Condition as factor
  mutate(
    cond = factor(cond, levels = c("easy", "hard"),
                  labels = c("Easy", "Hard")),
    # Recode reversed items (R suffix = reverse-scored on 7-pt scale)
    Belonging_1  = 8 - Belonging_1R,
    Belonging_2  = 8 - Belonging_2R,
    Belonging_3  = 8 - Belonging_3R,
    SelfEsteem_4 = 8 - SelfEsteem_4R,
    Meaning_1    = 8 - Meaning_1R,
    Meaning_2    = 8 - Meaning_2R,
    Meaning_3    = 8 - Meaning_3R,
    Control_4    = 8 - Control_4R,
    Control_5    = 8 - Control_5R,
    strength_2   = 8 - strength_2R,
    # TIPI reversed items (7-pt)
    Agreeable_2  = 8 - Agreeable_2R,
    EmoStability_4 = 8 - EmoStability_4R,
    Extraversion_6 = 8 - Extraversion_6R,
    Conscientious_8 = 8 - Conscientious_8R,
    Open_10      = 8 - Open_10R,
    # PANAS positive & negative affect subscales
    PANAS_PA = rowMeans(across(c(PANAS_1, PANAS_3, PANAS_5, PANAS_9, PANAS_10,
                                  PANAS_12, PANAS_14, PANAS_16, PANAS_17, PANAS_19)),
                        na.rm = TRUE),
    PANAS_NA = rowMeans(across(c(PANAS_2, PANAS_4, PANAS_6, PANAS_7, PANAS_8,
                                  PANAS_11, PANAS_13, PANAS_15, PANAS_18, PANAS_20)),
                        na.rm = TRUE),
    # Needs composites (after reversals above)
    Belonging  = rowMeans(across(c(Belonging_1, Belonging_2, Belonging_3,
                                    Belonging_4, Belonging_5)), na.rm = TRUE),
    SelfEsteem = rowMeans(across(c(SelfEsteem_1, SelfEsteem_2, SelfEsteem_3,
                                    SelfEsteem_4, SelfEsteem_5)), na.rm = TRUE),
    Meaning    = rowMeans(across(c(Meaning_1, Meaning_2, Meaning_3,
                                    Meaning_4, Meaning_5)), na.rm = TRUE),
    Control    = rowMeans(across(c(Control_1, Control_2, Control_3,
                                    Control_4, Control_5)), na.rm = TRUE),
    # Big Five (TIPI) — average two items per trait
    Extraversion      = rowMeans(across(c(Extraversion_1, Extraversion_6)),  na.rm = TRUE),
    Agreeableness     = rowMeans(across(c(Agreeable_7,    Agreeable_2)),     na.rm = TRUE),
    Conscientiousness = rowMeans(across(c(Conscientious_3, Conscientious_8)), na.rm = TRUE),
    EmotionalStability = rowMeans(across(c(EmoStability_9, EmoStability_4)), na.rm = TRUE),
    Openness          = rowMeans(across(c(Open_5, Open_10)),                 na.rm = TRUE),
    # Appraisals: threat and challenge (coping = challenge appraisal)
    threat_ap    = threat,
    challenge_ap = coping,
    # Center continuous moderators for interactions
    across(c(Extraversion, Agreeableness, Conscientiousness,
             EmotionalStability, Openness, threat_ap, challenge_ap),
           ~ scale(.x, scale = FALSE)[,1],
           .names = "{.col}_c")
  )

cat("N =", nrow(d), "\n")
## N = 200
table(d$cond)
## 
## Easy Hard 
##   98  102

Removing potential bots

table(is.na(d$Q_RecaptchaScore))
## 
## FALSE 
##   200
summary(d$Q_RecaptchaScore)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##   0.700   1.000   1.000   0.981   1.000   1.000
d %>% filter(Q_RecaptchaScore < 0.5)  # common threshold
# No one scored under .5 so we should be ok

Removing people who couldn’t get the game to work

could_not_play <- c(
  "R_6n1JFLSArseuXN8",
  "R_18ThM3TdbaCII1Z",
  "R_5LcWLd4U2RKfujT",
  "R_1ZILwaWBlsqec81",
  "R_7PWGG7eaznkaE8N",
  "R_7dZ95xzj8IqjghH",
  "R_3V84hDDYc2S1BbX",
  "R_7rws9kOT8q8Whrr",
  "R_6qOL9xPyKF9xwG2",
  "R_7Qyz2bLzTXDg7l8",
  "R_5uUHIAmYxD6sLBl",
  "R_7CO85bLTD2Brpf0",  # nothing was happening
  "R_7Cqr9jP1m4BfHf1",  # no fruit, players didn't move
  "R_6lS8RxNL1glHPW1",  # no fruit to take
  "R_7XiH9miDd65g0Iu",  # no fruit to catch
  "R_5oAu14wrGofKbWo",  # couldn't find any fruit
  "R_5eUPfMptpIpFCZR",  # wandering aimlessly, couldn't find fruit
  "R_3yIJldcUUJc0dOx"    # couldn't see any fruit on screen
)

d <- d %>%
  mutate(flag_no_game = ResponseId %in% could_not_play)

d_clean <- d %>% filter(!flag_no_game)

cat("Excluded:", sum(d$flag_no_game), "\n")
## Excluded: 18
cat("Remaining N:", nrow(d_clean), "\n")
## Remaining N: 182
d <- d_clean

Descriptive Statistics

d %>%
  group_by(cond) %>%
  summarise(
    n            = n(),
    across(c(difficulty, PANAS_PA, PANAS_NA,
             Belonging, SelfEsteem, Meaning, Control,
             threat_ap, challenge_ap),
           list(M = ~ mean(.x, na.rm = TRUE),
                SD = ~ sd(.x, na.rm = TRUE)))
  ) %>%
  pivot_longer(-c(cond, n),
               names_to = c("var", ".value"),
               names_pattern = "(.+)_(M|SD)") %>%
  mutate(across(where(is.numeric), ~ round(.x, 2))) %>%
  kable(caption = "Means and SDs by Condition") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
Means and SDs by Condition
cond n var M SD
Easy 90 difficulty 5.41 1.44
Easy 90 PANAS_PA 3.01 0.85
Easy 90 PANAS_NA 1.62 0.64
Easy 90 Belonging 4.00 1.20
Easy 90 SelfEsteem 3.64 1.22
Easy 90 Meaning 4.39 1.35
Easy 90 Control 3.50 1.35
Easy 90 threat_ap 2.36 1.54
Easy 90 challenge_ap 4.08 1.68
Hard 92 difficulty 5.95 1.41
Hard 92 PANAS_PA 2.82 0.91
Hard 92 PANAS_NA 1.81 0.72
Hard 92 Belonging 3.78 1.27
Hard 92 SelfEsteem 3.26 1.45
Hard 92 Meaning 4.01 1.32
Hard 92 Control 2.87 1.33
Hard 92 threat_ap 2.33 1.68
Hard 92 challenge_ap 3.21 1.78

Section 1: Manipulation Check

Did participants in the hard condition rate the game as more difficult?

t_manip <- t.test(difficulty ~ cond, data = d, var.equal = FALSE)
d_manip  <- cohens_d(difficulty ~ cond, data = d)

print(t_manip)
## 
##  Welch Two Sample t-test
## 
## data:  difficulty by cond
## t = -2.526, df = 179.6, p-value = 0.0124
## alternative hypothesis: true difference in means between group Easy and group Hard is not equal to 0
## 95 percent confidence interval:
##  -0.9521169 -0.1169652
## sample estimates:
## mean in group Easy mean in group Hard 
##           5.411111           5.945652
print(d_manip)
## Cohen's d |         95% CI
## --------------------------
## -0.37     | [-0.67, -0.08]
## 
## - Estimated using pooled SD.

NOTE: Easy condition was still perceived as hard!!!

d %>%
  group_by(cond) %>%
  summarise(M = mean(difficulty, na.rm = TRUE),
            SE = sd(difficulty, na.rm = TRUE) / sqrt(n())) %>%
  ggplot(aes(x = cond, y = M, fill = cond)) +
  geom_col(width = 0.5, alpha = 0.85) +
  geom_errorbar(aes(ymin = M - SE, ymax = M + SE), width = 0.15) +
  geom_jitter(data = d, aes(x = cond, y = difficulty, fill = cond),
              inherit.aes = FALSE, width = 0.12, alpha = 0.3, size = 1.5, shape = 21) +
  scale_fill_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  scale_y_continuous(limits = c(1, 7), breaks = 1:7,
                     labels = c("1\nExtremely easy","2","3","4","5","6","7\nExtremely difficult")) +
  labs(title = "Manipulation Check: Perceived Difficulty",
       x = "Condition", y = "Difficulty Rating") +
  theme_pubr() +
  theme(legend.position = "none")
Perceived Difficulty by Condition

Perceived Difficulty by Condition

Interpretation: The manipulation was successful. Hard-condition participants (M = 5.95) rated the game as significantly harder than easy-condition participants (M = 5.41), t(179.6) = -2.53, p = 0.012, d = -0.37.


Section 2: Condition → PANAS & Needs

2a. PANAS (Positive & Negative Affect)

cat("--- PANAS Positive Affect (α) ---\n")
## --- PANAS Positive Affect (α) ---
alpha(d[, paste0("PANAS_", c(1,3,5,9,10,12,14,16,17,19))])$total$raw_alpha %>% round(3) %>% print()
## [1] 0.903
cat("\n--- PANAS Negative Affect (α) ---\n")
## 
## --- PANAS Negative Affect (α) ---
alpha(d[, paste0("PANAS_", c(2,4,6,7,8,11,13,15,18,20))])$total$raw_alpha %>% round(3) %>% print()
## [1] 0.874
run_ttest <- function(var, label, data = d) {
  fmla <- as.formula(paste(var, "~ cond"))
  tt   <- t.test(fmla, data = data, var.equal = FALSE)
  cd   <- cohens_d(fmla, data = data)
  tibble(
    Outcome = label,
    M_Easy  = round(mean(data[[var]][data$cond == "Easy"], na.rm = TRUE), 2),
    M_Hard  = round(mean(data[[var]][data$cond == "Hard"], na.rm = TRUE), 2),
    t       = round(tt$statistic, 2),
    df      = round(tt$parameter, 1),
    p       = round(tt$p.value, 3),
    d       = round(cd$Cohens_d, 2)
  )
}

panas_results <- bind_rows(
  run_ttest("PANAS_PA", "Positive Affect"),
  run_ttest("PANAS_NA", "Negative Affect")
)

panas_results %>%
  kable(caption = "Condition Differences in PANAS") %>%
  kable_styling(bootstrap_options = c("striped", "hover"))
Condition Differences in PANAS
Outcome M_Easy M_Hard t df p d
Positive Affect 3.01 2.82 1.48 179.7 0.142 0.22
Negative Affect 1.62 1.81 -1.87 178.2 0.064 -0.28
d %>%
  select(cond, PANAS_PA, PANAS_NA) %>%
  pivot_longer(-cond, names_to = "subscale", values_to = "score") %>%
  mutate(subscale = recode(subscale,
                           PANAS_PA = "Positive Affect",
                           PANAS_NA = "Negative Affect")) %>%
  group_by(cond, subscale) %>%
  summarise(M  = mean(score, na.rm = TRUE),
            SE = sd(score, na.rm = TRUE) / sqrt(n()), .groups = "drop") %>%
  ggplot(aes(x = subscale, y = M, color = cond, group = cond)) +
  geom_point(position = position_dodge(0.4), size = 4) +
  geom_errorbar(aes(ymin = M - SE, ymax = M + SE),
                position = position_dodge(0.4), width = 0.15) +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  scale_y_continuous(limits = c(1, 5)) +
  labs(title = "PANAS by Condition", x = NULL,
       y = "Mean Score (1–5)", color = "Condition") +
  theme_pubr()
PANAS by Condition

PANAS by Condition

2b. Psychological Needs

needs_items <- list(
  Belonging  = c("Belonging_1", "Belonging_2", "Belonging_3", "Belonging_4", "Belonging_5"),
  SelfEsteem = c("SelfEsteem_1","SelfEsteem_2","SelfEsteem_3","SelfEsteem_4","SelfEsteem_5"),
  Meaning    = c("Meaning_1","Meaning_2","Meaning_3","Meaning_4","Meaning_5"),
  Control    = c("Control_1","Control_2","Control_3","Control_4","Control_5")
)

cat("Internal consistency (Cronbach's α) for Needs subscales:\n")
## Internal consistency (Cronbach's α) for Needs subscales:
imap(needs_items, function(items, name) {
  a <- alpha(d[, items])$total$raw_alpha
  cat(sprintf("  %-12s α = %.3f\n", name, a))
})
##   Belonging    α = 0.717
##   SelfEsteem   α = 0.849
##   Meaning      α = 0.821
##   Control      α = 0.835
## $Belonging
## NULL
## 
## $SelfEsteem
## NULL
## 
## $Meaning
## NULL
## 
## $Control
## NULL
invisible(NULL)
needs_results <- bind_rows(
  run_ttest("Belonging",  "Belonging"),
  run_ttest("SelfEsteem", "Self-Esteem"),
  run_ttest("Meaning",    "Meaning"),
  run_ttest("Control",    "Control")
)

needs_results %>%
  kable(caption = "Condition Differences in Psychological Needs") %>%
  kable_styling(bootstrap_options = c("striped", "hover"))
Condition Differences in Psychological Needs
Outcome M_Easy M_Hard t df p d
Belonging 4.00 3.78 1.24 179.8 0.215 0.18
Self-Esteem 3.64 3.26 1.93 176.4 0.055 0.29
Meaning 4.39 4.01 1.92 179.6 0.056 0.29
Control 3.50 2.87 3.14 179.7 0.002 0.47
d %>%
  select(cond, Belonging, SelfEsteem, Meaning, Control) %>%
  pivot_longer(-cond, names_to = "need", values_to = "score") %>%
  group_by(cond, need) %>%
  summarise(M  = mean(score, na.rm = TRUE),
            SE = sd(score, na.rm = TRUE) / sqrt(n()), .groups = "drop") %>%
  ggplot(aes(x = need, y = M, color = cond, group = cond)) +
  geom_point(position = position_dodge(0.4), size = 4) +
  geom_errorbar(aes(ymin = M - SE, ymax = M + SE),
                position = position_dodge(0.4), width = 0.15) +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  coord_cartesian(ylim = c(1, 7)) +
  labs(title = "Psychological Needs by Condition", x = NULL,
       y = "Mean Score (1–7)", color = "Condition") +
  theme_pubr()
Psychological Needs by Condition

Psychological Needs by Condition


Section 3: Moderation Analyses

The condition variable is dummy-coded (Easy = 0, Hard = 1). Continuous moderators are mean-centered. Each model tests: Outcome ~ cond_dummy * Moderator.

d <- d %>%
  mutate(cond_d = ifelse(cond == "Hard", 1, 0))

Helper function

run_moderation <- function(outcome, moderator, data = d,
                           outcome_label = outcome, mod_label = moderator) {
  fmla <- as.formula(
    paste(outcome, "~ cond_d *", moderator)
  )
  m <- lm(fmla, data = data)
  s <- summary(m)
  
  cat("\n====================================================\n")
  cat(sprintf("Outcome: %s | Moderator: %s\n", outcome_label, mod_label))
  cat("====================================================\n")
  print(s)
  
  # Extract interaction row
  int_row  <- grep("cond_d:", rownames(coef(s)), value = TRUE)
  int_p    <- coef(s)[int_row, "Pr(>|t|)"]
  int_b    <- coef(s)[int_row, "Estimate"]
  
  list(model = m, interaction_b = int_b, interaction_p = int_p)
}

3a. Big Five Personality as Moderator

outcomes   <- c("PANAS_PA", "PANAS_NA",
                "Belonging", "SelfEsteem", "Meaning", "Control")
out_labels <- c("Positive Affect", "Negative Affect",
                "Belonging", "Self-Esteem", "Meaning", "Control")

personality_mods <- c("Extraversion_c", "Agreeableness_c",
                       "Conscientiousness_c", "EmotionalStability_c", "Openness_c")
pers_labels      <- c("Extraversion", "Agreeableness",
                       "Conscientiousness", "Emotional Stability", "Openness")

# Collect significant interactions
sig_personality <- list()

for (i in seq_along(outcomes)) {
  for (j in seq_along(personality_mods)) {
    res <- run_moderation(outcomes[i], personality_mods[j],
                          outcome_label = out_labels[i],
                          mod_label = pers_labels[j])
    if (!is.na(res$interaction_p) && res$interaction_p < .05) {
      sig_personality[[length(sig_personality) + 1]] <- list(
        outcome = outcomes[i], mod = personality_mods[j],
        outcome_label = out_labels[i], mod_label = pers_labels[j],
        model = res$model
      )
    }
  }
}

==================================================== Outcome: Positive Affect | Moderator: Extraversion ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -1.9084 -0.5923 -0.1007 0.6282 2.3030

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.01106 0.09197 32.741 <2e-16 *** cond_d -0.18360 0.12941 -1.419 0.1577
Extraversion_c 0.09403 0.05265 1.786 0.0758 .
cond_d:Extraversion_c -0.00945 0.07379 -0.128 0.8982
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.8724 on 178 degrees of freedom Multiple R-squared: 0.04344, Adjusted R-squared: 0.02732 F-statistic: 2.695 on 3 and 178 DF, p-value: 0.04752

==================================================== Outcome: Positive Affect | Moderator: Agreeableness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.1385 -0.6324 -0.0688 0.6686 2.0696

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.01865 0.09101 33.170 <2e-16 *** cond_d -0.20066 0.12797 -1.568 0.1187
Agreeableness_c 0.14062 0.07629 1.843 0.0669 .
cond_d:Agreeableness_c 0.06754 0.11161 0.605 0.5459
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.8629 on 178 degrees of freedom Multiple R-squared: 0.06411, Adjusted R-squared: 0.04834 F-statistic: 4.065 on 3 and 178 DF, p-value: 0.007998

==================================================== Outcome: Positive Affect | Moderator: Conscientiousness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -1.97618 -0.66774 -0.04536 0.64263 2.15445

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.01643 0.09221 32.712 <2e-16 *** cond_d -0.20823 0.12972 -1.605 0.11
Conscientiousness_c 0.04954 0.07873 0.629 0.53
cond_d:Conscientiousness_c 0.14967 0.11900 1.258 0.21
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.8736 on 178 degrees of freedom Multiple R-squared: 0.04091, Adjusted R-squared: 0.02475 F-statistic: 2.531 on 3 and 178 DF, p-value: 0.0587

==================================================== Outcome: Positive Affect | Moderator: Emotional Stability ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.14174 -0.63816 -0.06648 0.71622 1.94860

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.02564 0.09033 33.495 <2e-16 *** cond_d -0.22401 0.12693 -1.765 0.0793 .
EmotionalStability_c 0.09566 0.06153 1.555 0.1218
cond_d:EmotionalStability_c 0.08501 0.08122 1.047 0.2967
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.8537 on 178 degrees of freedom Multiple R-squared: 0.0841, Adjusted R-squared: 0.06866 F-statistic: 5.448 on 3 and 178 DF, p-value: 0.001318

==================================================== Outcome: Positive Affect | Moderator: Openness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.0648 -0.5776 -0.0540 0.6368 1.9352

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.01719 0.09178 32.875 <2e-16 *** cond_d -0.22865 0.12926 -1.769 0.0786 .
Openness_c 0.03150 0.07416 0.425 0.6715
cond_d:Openness_c 0.16904 0.10191 1.659 0.0989 .
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.8664 on 178 degrees of freedom Multiple R-squared: 0.05651, Adjusted R-squared: 0.04061 F-statistic: 3.554 on 3 and 178 DF, p-value: 0.01557

==================================================== Outcome: Negative Affect | Moderator: Extraversion ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -0.9342 -0.5475 -0.1296 0.4013 2.2011

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.61740 0.07201 22.460 <2e-16 *** cond_d 0.18383 0.10134 1.814 0.0714 .
Extraversion_c -0.03023 0.04122 -0.733 0.4644
cond_d:Extraversion_c -0.02206 0.05778 -0.382 0.7031
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.6831 on 178 degrees of freedom Multiple R-squared: 0.03092, Adjusted R-squared: 0.01458 F-statistic: 1.893 on 3 and 178 DF, p-value: 0.1324

==================================================== Outcome: Negative Affect | Moderator: Agreeableness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -1.1404 -0.5363 -0.1451 0.3806 1.9903

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.616834 0.070096 23.066 < 2e-16 * cond_d 0.191429 0.098570 1.942 0.05371 .
Agreeableness_c 0.004429 0.058758 0.075 0.94000
cond_d:Agreeableness_c -0.224931 0.085968 -2.616 0.00965
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.6647 on 178 degrees of freedom Multiple R-squared: 0.08258, Adjusted R-squared: 0.06712 F-statistic: 5.341 on 3 and 178 DF, p-value: 0.001516

==================================================== Outcome: Negative Affect | Moderator: Conscientiousness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -0.9657 -0.5484 -0.1303 0.4052 2.1907

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.61325 0.07209 22.377 <2e-16 *** cond_d 0.19752 0.10142 1.948 0.053 .
Conscientiousness_c -0.05462 0.06155 -0.887 0.376
cond_d:Conscientiousness_c -0.03083 0.09304 -0.331 0.741
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.683 on 178 degrees of freedom Multiple R-squared: 0.03136, Adjusted R-squared: 0.01504 F-statistic: 1.921 on 3 and 178 DF, p-value: 0.1278

==================================================== Outcome: Negative Affect | Moderator: Emotional Stability ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -1.0225 -0.4709 -0.0917 0.3101 2.1438

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.59647 0.06691 23.859 < 2e-16 cond_d 0.22767 0.09403 2.421 0.01647
EmotionalStability_c -0.15707 0.04558 -3.446 0.00071
* cond_d:EmotionalStability_c -0.02046 0.06017 -0.340 0.73422
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.6323 on 178 degrees of freedom Multiple R-squared: 0.1696, Adjusted R-squared: 0.1556 F-statistic: 12.12 on 3 and 178 DF, p-value: 2.959e-07

==================================================== Outcome: Negative Affect | Moderator: Openness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -0.9460 -0.5339 -0.1621 0.3597 2.2132

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.62578 0.07029 23.128 < 2e-16 cond_d 0.20841 0.09900 2.105 0.03668
Openness_c 0.07436 0.05680 1.309 0.19216
cond_d:Openness_c -0.25393 0.07805 -3.253 0.00136
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.6636 on 178 degrees of freedom Multiple R-squared: 0.08552, Adjusted R-squared: 0.07011 F-statistic: 5.549 on 3 and 178 DF, p-value: 0.001157

==================================================== Outcome: Belonging | Moderator: Extraversion ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.78079 -0.91536 0.05014 0.87004 2.92854

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.001622 0.129460 30.910 <2e-16 *** cond_d -0.215569 0.182172 -1.183 0.238
Extraversion_c 0.116800 0.074108 1.576 0.117
cond_d:Extraversion_c 0.006932 0.103878 0.067 0.947
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.228 on 178 degrees of freedom Multiple R-squared: 0.03756, Adjusted R-squared: 0.02134 F-statistic: 2.315 on 3 and 178 DF, p-value: 0.0774

==================================================== Outcome: Belonging | Moderator: Agreeableness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.88005 -0.98366 0.02888 0.94380 2.91995

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.00625 0.13012 30.789 <2e-16 *** cond_d -0.23295 0.18298 -1.273 0.205
Agreeableness_c 0.04792 0.10907 0.439 0.661
cond_d:Agreeableness_c 0.16905 0.15958 1.059 0.291
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.234 on 178 degrees of freedom Multiple R-squared: 0.02849, Adjusted R-squared: 0.01212 F-statistic: 1.74 on 3 and 178 DF, p-value: 0.1605

==================================================== Outcome: Belonging | Moderator: Conscientiousness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.92627 -0.93135 -0.02881 0.93170 2.87373

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.01054 0.12978 30.903 <2e-16 *** cond_d -0.25051 0.18257 -1.372 0.172
Conscientiousness_c 0.09746 0.11080 0.880 0.380
cond_d:Conscientiousness_c 0.15955 0.16749 0.953 0.342
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.229 on 178 degrees of freedom Multiple R-squared: 0.03539, Adjusted R-squared: 0.01913 F-statistic: 2.177 on 3 and 178 DF, p-value: 0.0924

==================================================== Outcome: Belonging | Moderator: Emotional Stability ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -3.0366 -0.7693 0.1035 0.7876 2.8852

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.01848 0.12418 32.361 <2e-16 ** cond_d -0.27770 0.17449 -1.592 0.1133
EmotionalStability_c 0.10912 0.08458 1.290 0.1987
cond_d:EmotionalStability_c 0.22613 0.11166 2.025 0.0443

— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.173 on 178 degrees of freedom Multiple R-squared: 0.1212, Adjusted R-squared: 0.1063 F-statistic: 8.18 on 3 and 178 DF, p-value: 3.936e-05

==================================================== Outcome: Belonging | Moderator: Openness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.94144 -0.83303 0.05856 0.80971 3.06405

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.02123 0.12168 33.047 < 2e-16 * cond_d -0.32592 0.17137 -1.902 0.05881 .
Openness_c 0.13700 0.09832 1.393 0.16524
cond_d:Openness_c 0.36753 0.13511 2.720 0.00717
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.149 on 178 degrees of freedom Multiple R-squared: 0.1579, Adjusted R-squared: 0.1437 F-statistic: 11.13 on 3 and 178 DF, p-value: 9.933e-07

==================================================== Outcome: Self-Esteem | Moderator: Extraversion ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.8690 -0.9225 -0.1269 1.0466 3.1304

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.64082 0.13742 26.494 <2e-16 *** cond_d -0.36156 0.19337 -1.870 0.0632 .
Extraversion_c 0.14979 0.07866 1.904 0.0585 .
cond_d:Extraversion_c 0.07863 0.11027 0.713 0.4767
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.304 on 178 degrees of freedom Multiple R-squared: 0.08391, Adjusted R-squared: 0.06847 F-statistic: 5.435 on 3 and 178 DF, p-value: 0.001342

==================================================== Outcome: Self-Esteem | Moderator: Agreeableness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.7050 -1.0027 -0.0550 0.8995 3.1890

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.64589 0.14011 26.021 <2e-16 *** cond_d -0.38868 0.19703 -1.973 0.0501 .
Agreeableness_c 0.03838 0.11745 0.327 0.7442
cond_d:Agreeableness_c 0.24644 0.17184 1.434 0.1533
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.329 on 178 degrees of freedom Multiple R-squared: 0.04841, Adjusted R-squared: 0.03237 F-statistic: 3.018 on 3 and 178 DF, p-value: 0.03126

==================================================== Outcome: Self-Esteem | Moderator: Conscientiousness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.8211 -0.9504 -0.0385 0.7879 3.3023

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.6533 0.1382 26.433 <2e-16 ** cond_d -0.4178 0.1944 -2.149 0.033
Conscientiousness_c 0.1413 0.1180 1.198 0.233
cond_d:Conscientiousness_c 0.2657 0.1784 1.490 0.138
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.309 on 178 degrees of freedom Multiple R-squared: 0.0758, Adjusted R-squared: 0.06022 F-statistic: 4.866 on 3 and 178 DF, p-value: 0.002811

==================================================== Outcome: Self-Esteem | Moderator: Emotional Stability ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.84222 -0.89003 -0.00256 0.87248 3.05693

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.67895 0.12777 28.793 < 2e-16 cond_d -0.46439 0.17954 -2.587 0.01049
EmotionalStability_c 0.26830 0.08703 3.083 0.00238
cond_d:EmotionalStability_c 0.17136 0.11489 1.492 0.13759
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.207 on 178 degrees of freedom Multiple R-squared: 0.214, Adjusted R-squared: 0.2007 F-statistic: 16.15 on 3 and 178 DF, p-value: 2.492e-09

==================================================== Outcome: Self-Esteem | Moderator: Openness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.9843 -0.8527 -0.0466 0.8138 2.7446

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.64175 0.13262 27.460 < 2e-16 cond_d -0.46697 0.18678 -2.500 0.013318
Openness_c -0.02198 0.10716 -0.205 0.837727
cond_d:Openness_c 0.55967 0.14725 3.801 0.000198
* — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.252 on 178 degrees of freedom Multiple R-squared: 0.155, Adjusted R-squared: 0.1408 F-statistic: 10.88 on 3 and 178 DF, p-value: 1.338e-06

==================================================== Outcome: Meaning | Moderator: Extraversion ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -3.1212 -0.9773 0.1604 0.9696 2.8016

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.38440 0.13942 31.447 <2e-16 *** cond_d -0.36641 0.19619 -1.868 0.0635 .
Extraversion_c 0.09388 0.07981 1.176 0.2410
cond_d:Extraversion_c 0.04849 0.11187 0.433 0.6652
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.323 on 178 degrees of freedom Multiple R-squared: 0.04527, Adjusted R-squared: 0.02918 F-statistic: 2.814 on 3 and 178 DF, p-value: 0.04075

==================================================== Outcome: Meaning | Moderator: Agreeableness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -3.0110 -1.0212 0.1754 1.0344 2.9060

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.3891 0.1405 31.241 <2e-16 *** cond_d -0.3848 0.1976 -1.947 0.053 .
Agreeableness_c 0.0657 0.1178 0.558 0.578
cond_d:Agreeableness_c 0.1003 0.1723 0.582 0.561
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.332 on 178 degrees of freedom Multiple R-squared: 0.03133, Adjusted R-squared: 0.015 F-statistic: 1.919 on 3 and 178 DF, p-value: 0.1282

==================================================== Outcome: Meaning | Moderator: Conscientiousness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -3.09327 -0.93808 0.07729 0.98135 2.95659

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.39200 0.13937 31.513 <2e-16 ** cond_d -0.40392 0.19607 -2.060 0.0408
Conscientiousness_c 0.08528 0.11899 0.717 0.4745
cond_d:Conscientiousness_c 0.20983 0.17987 1.167 0.2449
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.32 on 178 degrees of freedom Multiple R-squared: 0.04849, Adjusted R-squared: 0.03246 F-statistic: 3.024 on 3 and 178 DF, p-value: 0.03103

==================================================== Outcome: Meaning | Moderator: Emotional Stability ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.9892 -0.9535 0.2494 0.8557 2.7237

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.41572 0.13393 32.969 <2e-16 ** cond_d -0.44162 0.18820 -2.346 0.0201
EmotionalStability_c 0.22592 0.09123 2.476 0.0142 *
cond_d:EmotionalStability_c 0.08184 0.12043 0.680 0.4977
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.266 on 178 degrees of freedom Multiple R-squared: 0.1256, Adjusted R-squared: 0.1108 F-statistic: 8.52 on 3 and 178 DF, p-value: 2.56e-05

==================================================== Outcome: Meaning | Moderator: Openness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -3.1653 -0.9432 0.1361 0.9192 2.5664

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.37518 0.13426 32.586 < 2e-16 cond_d -0.44215 0.18910 -2.338 0.020486
Openness_c -0.09377 0.10849 -0.864 0.388550
cond_d:Openness_c 0.55280 0.14908 3.708 0.000279
* — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.267 on 178 degrees of freedom Multiple R-squared: 0.1231, Adjusted R-squared: 0.1083 F-statistic: 8.331 on 3 and 178 DF, p-value: 3.253e-05

==================================================== Outcome: Control | Moderator: Extraversion ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.4745 -0.9549 -0.0218 0.7692 3.7567

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.49466 0.14131 24.731 < 2e-16 * cond_d -0.61393 0.19884 -3.088 0.00234 Extraversion_c 0.03724 0.08089 0.460 0.64579
cond_d:Extraversion_c 0.07432 0.11338 0.655 0.51304
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.34 on 178 degrees of freedom Multiple R-squared: 0.06334, Adjusted R-squared: 0.04755 F-statistic: 4.012 on 3 and 178 DF, p-value: 0.008565

==================================================== Outcome: Control | Moderator: Agreeableness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.4935 -1.0588 -0.0436 0.7244 3.8847

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.49457 0.14204 24.603 < 2e-16 * cond_d -0.62389 0.19974 -3.124 0.00209 Agreeableness_c -0.02603 0.11907 -0.219 0.82718
cond_d:Agreeableness_c 0.10875 0.17420 0.624 0.53325
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.347 on 178 degrees of freedom Multiple R-squared: 0.05435, Adjusted R-squared: 0.03841 F-statistic: 3.41 on 3 and 178 DF, p-value: 0.01878

==================================================== Outcome: Control | Moderator: Conscientiousness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.3704 -0.9621 -0.0176 0.8186 3.9049

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.4851 0.1409 24.742 < 2e-16 * cond_d -0.6251 0.1982 -3.154 0.00189 Conscientiousness_c -0.1669 0.1203 -1.388 0.16691
cond_d:Conscientiousness_c 0.3540 0.1818 1.947 0.05308 .
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.334 on 178 degrees of freedom Multiple R-squared: 0.07172, Adjusted R-squared: 0.05607 F-statistic: 4.584 on 3 and 178 DF, p-value: 0.004062

==================================================== Outcome: Control | Moderator: Emotional Stability ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.5731 -0.9554 -0.0456 0.7396 3.5428

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.5151 0.1364 25.773 < 2e-16 cond_d -0.6751 0.1916 -3.523 0.000543 EmotionalStability_c 0.1517 0.0929 1.633 0.104309
cond_d:EmotionalStability_c 0.1502 0.1226 1.224 0.222420
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.289 on 178 degrees of freedom Multiple R-squared: 0.134, Adjusted R-squared: 0.1194 F-statistic: 9.179 on 3 and 178 DF, p-value: 1.116e-05

==================================================== Outcome: Control | Moderator: Openness ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.4556 -0.9682 -0.0706 0.7894 3.5144

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.4711 0.1376 25.218 < 2e-16 cond_d -0.6537 0.1939 -3.372 0.000914 Openness_c -0.2000 0.1112 -1.798 0.073823 .
cond_d:Openness_c 0.5400 0.1528 3.533 0.000523 *** — Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.299 on 178 degrees of freedom Multiple R-squared: 0.1198, Adjusted R-squared: 0.105 F-statistic: 8.079 on 3 and 178 DF, p-value: 4.474e-05

Significant Personality Interactions

if (length(sig_personality) == 0) {
  cat("No personality × condition interactions reached *p* < .05.\n")
} else {
  for (item in sig_personality) {
    cat(sprintf("\n**%s × Condition on %s**\n\n",
                item$mod_label, item$outcome_label))
    p <- interact_plot(item$model,
                       pred = cond_d,
                       modx = !!sym(item$mod),
                       interval = TRUE,
                       x.label = "Condition (0=Easy, 1=Hard)",
                       y.label = item$outcome_label,
                       legend.main = item$mod_label,
                       colors = c("#2196F3", "#9C27B0", "#F44336")) +
      theme_pubr()
    print(p)
  }
}
## 
## **Agreeableness × Condition on Negative Affect**

## 
## **Openness × Condition on Negative Affect**

## 
## **Emotional Stability × Condition on Belonging**

## 
## **Openness × Condition on Belonging**

## 
## **Openness × Condition on Self-Esteem**

## 
## **Openness × Condition on Meaning**

## 
## **Openness × Condition on Control**

3b. Challenge Appraisal (Coping) as Moderator

“How able were you to cope with the demands of the game?” — higher = more challenge appraisal.

sig_challenge <- list()

for (i in seq_along(outcomes)) {
  res <- run_moderation(outcomes[i], "challenge_ap_c",
                        outcome_label = out_labels[i],
                        mod_label = "Challenge Appraisal")
  if (!is.na(res$interaction_p) && res$interaction_p < .05) {
    sig_challenge[[length(sig_challenge) + 1]] <- list(
      outcome = outcomes[i], outcome_label = out_labels[i],
      model = res$model
    )
  }
}

==================================================== Outcome: Positive Affect | Moderator: Challenge Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.32478 -0.51491 0.01724 0.66665 2.01906

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 2.95868 0.09263 31.942 <2e-16 ** cond_d -0.06659 0.12872 -0.517 0.6056
challenge_ap_c 0.10658 0.05288 2.015 0.0454

cond_d:challenge_ap_c 0.09270 0.07250 1.279 0.2027
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.8402 on 178 degrees of freedom Multiple R-squared: 0.1127, Adjusted R-squared: 0.09772 F-statistic: 7.534 on 3 and 178 DF, p-value: 8.96e-05

==================================================== Outcome: Negative Affect | Moderator: Challenge Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -1.0190 -0.4269 -0.1297 0.3676 2.0722

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.66606 0.07048 23.638 <2e-16 ** cond_d 0.07594 0.09795 0.775 0.4392
challenge_ap_c -0.09632 0.04024 -2.394 0.0177

cond_d:challenge_ap_c -0.08065 0.05516 -1.462 0.1455
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.6393 on 178 degrees of freedom Multiple R-squared: 0.1511, Adjusted R-squared: 0.1368 F-statistic: 10.56 on 3 and 178 DF, p-value: 1.988e-06

==================================================== Outcome: Belonging | Moderator: Challenge Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.4557 -0.7164 0.0992 0.8006 2.5051

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.918386 0.124176 31.555 <2e-16 ** cond_d -0.002624 0.172567 -0.015 0.9879
challenge_ap_c 0.167827 0.070894 2.367 0.0190

cond_d:challenge_ap_c 0.221806 0.097190 2.282 0.0237 *
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.126 on 178 degrees of freedom Multiple R-squared: 0.1903, Adjusted R-squared: 0.1766 F-statistic: 13.94 on 3 and 178 DF, p-value: 3.324e-08

==================================================== Outcome: Self-Esteem | Moderator: Challenge Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.78457 -0.71264 -0.06703 0.80763 3.14174

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.45537 0.12528 27.581 < 2e-16 cond_d -0.03161 0.17410 -0.182 0.856
challenge_ap_c 0.36873 0.07152 5.155 6.69e-07
cond_d:challenge_ap_c 0.08565 0.09805 0.874 0.384
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.136 on 178 degrees of freedom Multiple R-squared: 0.3037, Adjusted R-squared: 0.292 F-statistic: 25.88 on 3 and 178 DF, p-value: 6.051e-14

==================================================== Outcome: Meaning | Moderator: Challenge Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.76473 -0.73213 0.08489 0.86511 2.26787

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.17646 0.12605 33.133 < 2e-16 cond_d -0.02898 0.17518 -0.165 0.869
challenge_ap_c 0.40995 0.07197 5.696 4.98e-08
cond_d:challenge_ap_c -0.01675 0.09866 -0.170 0.865
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.143 on 178 degrees of freedom Multiple R-squared: 0.2864, Adjusted R-squared: 0.2743 F-statistic: 23.81 on 3 and 178 DF, p-value: 5.29e-13

==================================================== Outcome: Control | Moderator: Challenge Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -3.2016 -0.9375 0.0196 0.7389 2.7385

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.27105 0.12803 25.550 < 2e-16 cond_d -0.27364 0.17792 -1.538 0.126
challenge_ap_c 0.43782 0.07309 5.990 1.13e-08
cond_d:challenge_ap_c -0.08727 0.10020 -0.871 0.385
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.161 on 178 degrees of freedom Multiple R-squared: 0.2969, Adjusted R-squared: 0.2851 F-statistic: 25.05 on 3 and 178 DF, p-value: 1.43e-13

Significant Challenge Appraisal Interactions

if (length(sig_challenge) == 0) {
  cat("No challenge appraisal × condition interactions reached *p* < .05.\n")
} else {
  for (item in sig_challenge) {
    cat(sprintf("\n**Challenge Appraisal × Condition on %s**\n\n",
                item$outcome_label))
    p <- interact_plot(item$model,
                       pred = cond_d,
                       modx = challenge_ap_c,
                       interval = TRUE,
                       x.label = "Condition (0=Easy, 1=Hard)",
                       y.label = item$outcome_label,
                       legend.main = "Challenge Appraisal",
                       colors = c("#2196F3", "#9C27B0", "#F44336")) +
      theme_pubr()
    print(p)
  }
}
## 
## **Challenge Appraisal × Condition on Belonging**

3c. Threat Appraisal as Moderator

“How threatening did you find the game?” — higher = more threat appraisal.

sig_threat <- list()

for (i in seq_along(outcomes)) {
  res <- run_moderation(outcomes[i], "threat_ap_c",
                        outcome_label = out_labels[i],
                        mod_label = "Threat Appraisal")
  if (!is.na(res$interaction_p) && res$interaction_p < .05) {
    sig_threat[[length(sig_threat) + 1]] <- list(
      outcome = outcomes[i], outcome_label = out_labels[i],
      model = res$model
    )
  }
}

==================================================== Outcome: Positive Affect | Moderator: Threat Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -1.84939 -0.64664 -0.04127 0.65061 2.07366

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.00238 0.09204 32.622 <2e-16 ** cond_d -0.17686 0.12938 -1.367 0.1734
threat_ap_c 0.12094 0.06006 2.014 0.0455

cond_d:threat_ap_c -0.20064 0.08107 -2.475 0.0143 *
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.8716 on 178 degrees of freedom Multiple R-squared: 0.04517, Adjusted R-squared: 0.02908 F-statistic: 2.807 on 3 and 178 DF, p-value: 0.04111

==================================================== Outcome: Negative Affect | Moderator: Threat Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -1.2238 -0.3322 -0.1054 0.2762 2.2946

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.59587 0.05974 26.712 < 2e-16 cond_d 0.19430 0.08399 2.313 0.0218
threat_ap_c 0.22964 0.03899 5.890 1.88e-08
* cond_d:threat_ap_c 0.02030 0.05262 0.386 0.7002
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 0.5658 on 178 degrees of freedom Multiple R-squared: 0.3352, Adjusted R-squared: 0.324 F-statistic: 29.92 on 3 and 178 DF, p-value: 1.034e-15

==================================================== Outcome: Belonging | Moderator: Threat Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.57478 -0.83564 -0.04129 0.76839 2.62522

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.0292 0.1198 33.620 < 2e-16 cond_d -0.2317 0.1685 -1.375 0.170832
threat_ap_c -0.2732 0.0782 -3.493 0.000602
cond_d:threat_ap_c -0.0776 0.1056 -0.735 0.463216
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.135 on 178 degrees of freedom Multiple R-squared: 0.1779, Adjusted R-squared: 0.1641 F-statistic: 12.84 on 3 and 178 DF, p-value: 1.237e-07

==================================================== Outcome: Self-Esteem | Moderator: Threat Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.38183 -0.96961 -0.06954 0.81817 2.94668

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.66698 0.13431 27.302 < 2e-16 cond_d -0.38804 0.18881 -2.055 0.04133
threat_ap_c -0.24889 0.08765 -2.840 0.00504
cond_d:threat_ap_c -0.04705 0.11831 -0.398 0.69132
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.272 on 178 degrees of freedom Multiple R-squared: 0.1278, Adjusted R-squared: 0.1131 F-statistic: 8.69 on 3 and 178 DF, p-value: 2.064e-05

==================================================== Outcome: Meaning | Moderator: Threat Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -3.04136 -0.87822 0.04424 0.83638 2.65210

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 4.40368 0.13560 32.476 <2e-16 ** cond_d -0.38071 0.19062 -1.997 0.0473
threat_ap_c -0.18789 0.08848 -2.123 0.0351 *
cond_d:threat_ap_c -0.08140 0.11944 -0.682 0.4964
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.284 on 178 degrees of freedom Multiple R-squared: 0.09993, Adjusted R-squared: 0.08476 F-statistic: 6.588 on 3 and 178 DF, p-value: 0.0003017

==================================================== Outcome: Control | Moderator: Threat Appraisal ====================================================

Call: lm(formula = fmla, data = data)

Residuals: Min 1Q Median 3Q Max -2.2488 -1.0526 -0.0526 0.6183 3.7474

Coefficients: Estimate Std. Error t value Pr(>|t|)
(Intercept) 3.50169 0.14114 24.810 < 2e-16 * cond_d -0.62161 0.19841 -3.133 0.00202 threat_ap_c -0.06769 0.09210 -0.735 0.46331
cond_d:threat_ap_c -0.06872 0.12432 -0.553 0.58110
— Signif. codes: 0 ‘’ 0.001 ’’ 0.01 ’’ 0.05 ‘.’ 0.1 ’ ’ 1

Residual standard error: 1.337 on 178 degrees of freedom Multiple R-squared: 0.06864, Adjusted R-squared: 0.05294 F-statistic: 4.373 on 3 and 178 DF, p-value: 0.00535

Significant Threat Appraisal Interactions

if (length(sig_threat) == 0) {
  cat("No threat appraisal × condition interactions reached *p* < .05.\n")
} else {
  for (item in sig_threat) {
    cat(sprintf("\n**Threat Appraisal × Condition on %s**\n\n",
                item$outcome_label))
    p <- interact_plot(item$model,
                       pred = cond_d,
                       modx = threat_ap_c,
                       interval = TRUE,
                       x.label = "Condition (0=Easy, 1=Hard)",
                       y.label = item$outcome_label,
                       legend.main = "Threat Appraisal",
                       colors = c("#2196F3", "#9C27B0", "#F44336")) +
      theme_pubr()
    print(p)
  }
}
## 
## **Threat Appraisal × Condition on Positive Affect**


Section 4: Summary Table of All Main Effects

all_results <- bind_rows(panas_results, needs_results) %>%
  mutate(
    sig = case_when(
      p < .001 ~ "***",
      p < .01  ~ "**",
      p < .05  ~ "*",
      p < .10  ~ "†",
      TRUE     ~ ""
    )
  )

all_results %>%
  kable(caption = "Summary: Condition Differences (Easy vs. Hard) on All Outcomes",
        col.names = c("Outcome", "M (Easy)", "M (Hard)",
                      "t", "df", "p", "Cohen's d", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001")
Summary: Condition Differences (Easy vs. Hard) on All Outcomes
Outcome M (Easy) M (Hard) t df p Cohen’s d Sig.
Positive Affect 3.01 2.82 1.48 179.7 0.142 0.22
Negative Affect 1.62 1.81 -1.87 178.2 0.064 -0.28
Belonging 4.00 3.78 1.24 179.8 0.215 0.18
Self-Esteem 3.64 3.26 1.93 176.4 0.055 0.29
Meaning 4.39 4.01 1.92 179.6 0.056 0.29
Control 3.50 2.87 3.14 179.7 0.002 0.47 **
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001

Section 5: Exploratory — What Drives Needs Within the Competitive Experience?

5a. Condition Effects on Game Experience Measures

# Reverse-score strength_2R and create composites
d <- d %>%
  mutate(
    strength_2  = 8 - strength_2R,
    strength    = rowMeans(across(c(strength_1, strength_2)), na.rm = TRUE),
    opponent    = rowMeans(across(c(opponent_1, opponent_2, 
                                    opponent_3, opponent_4)), na.rm = TRUE)
  )

# t-tests for game experience measures by condition
game_exp_results <- bind_rows(
  run_ttest("difficulty",  "Difficulty"),
  run_ttest("coping",      "Coping (Challenge Appraisal)"),
  run_ttest("threat",      "Threat Appraisal"),
  run_ttest("strength",    "Perceived Strength"),
  run_ttest("opponent_1",  "Opponents: Unfair"),
  run_ttest("opponent_2",  "Opponents: Mean"),
  run_ttest("opponent_3",  "Opponents: Breaking Rules"),
  run_ttest("opponent_4",  "Opponents: Ganged Up"),
  run_ttest("opponent",    "Opponent Perception (composite)")
) %>%
  mutate(sig = case_when(
    p < .001 ~ "***", p < .01 ~ "**",
    p < .05  ~ "*",   p < .10 ~ "†",
    TRUE     ~ ""
  ))

game_exp_results %>%
  kable(caption = "Condition Differences on Game Experience Measures",
        col.names = c("Measure", "M (Easy)", "M (Hard)",
                      "t", "df", "p", "Cohen's d", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001")
Condition Differences on Game Experience Measures
Measure M (Easy) M (Hard) t df p Cohen’s d Sig.
Difficulty 5.41 5.95 -2.53 179.6 0.012 -0.37
Coping (Challenge Appraisal) 4.08 3.21 3.40 179.8 0.001 0.50 **
Threat Appraisal 2.36 2.33 0.12 179.3 0.902 0.02
Perceived Strength 3.71 2.76 3.88 179.5 0.000 0.58 ***
Opponents: Unfair 4.38 4.90 -1.87 178.6 0.063 -0.28
Opponents: Mean 4.53 4.72 -0.69 172.1 0.489 -0.10
Opponents: Breaking Rules 2.48 3.23 -3.17 171.5 0.002 -0.47 **
Opponents: Ganged Up 4.93 4.98 -0.17 180.0 0.868 -0.02
Opponent Perception (composite) 4.08 4.46 -1.80 174.5 0.074 -0.27
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001

5b. Correlations: Game Experience → Needs

predictors  <- c("strength", "opponent", "coping", "threat", "PANAS_PA", "PANAS_NA")
pred_labels <- c("Strength", "Opponent Perception", "Coping", 
                 "Threat", "Positive Affect", "Negative Affect")
outcomes    <- c("Belonging", "SelfEsteem", "Meaning", "Control")

cor_results <- map2_dfr(predictors, pred_labels, function(pred, plabel) {
  map_dfr(outcomes, function(out) {
    ct <- cor.test(d[[pred]], d[[out]], use = "complete.obs")
    tibble(
      Predictor = plabel,
      Outcome   = out,
      r         = round(ct$estimate, 2),
      p         = round(ct$p.value, 3),
      sig       = case_when(
        ct$p.value < .001 ~ "***", ct$p.value < .01 ~ "**",
        ct$p.value < .05  ~ "*",   ct$p.value < .10 ~ "†",
        TRUE ~ ""
      )
    )
  })
})

cor_results %>%
  pivot_wider(names_from = Outcome, 
              values_from = c(r, p, sig),
              names_glue = "{Outcome}_{.value}") %>%
  select(Predictor,
         starts_with("Belonging"), starts_with("SelfEsteem"),
         starts_with("Meaning"),   starts_with("Control")) %>%
  kable(caption = "Correlations Between Game Experience and Psychological Needs") %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001")
Correlations Between Game Experience and Psychological Needs
Predictor Belonging_r Belonging_p Belonging_sig SelfEsteem_r SelfEsteem_p SelfEsteem_sig Meaning_r Meaning_p Meaning_sig Control_r Control_p Control_sig
Strength 0.48 0 *** 0.61 0 *** 0.60 0 *** 0.74 0.000 ***
Opponent Perception -0.49 0 *** -0.43 0 *** -0.31 0 *** -0.40 0.000 ***
Coping 0.41 0 *** 0.55 0 *** 0.53 0 *** 0.53 0.000 ***
Threat -0.41 0 *** -0.33 0 *** -0.28 0 *** -0.12 0.103
Positive Affect 0.32 0 *** 0.50 0 *** 0.44 0 *** 0.43 0.000 ***
Negative Affect -0.49 0 *** -0.53 0 *** -0.45 0 *** -0.36 0.000 ***
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001

5c. Visualising the Two Pathways

# Strength pathway
p1 <- d %>%
  select(cond, strength, SelfEsteem, Meaning, Control) %>%
  pivot_longer(c(SelfEsteem, Meaning, Control),
               names_to = "need", values_to = "score") %>%
  ggplot(aes(x = strength, y = score, color = cond)) +
  geom_point(alpha = 0.3, size = 1.5) +
  geom_smooth(method = "lm", se = TRUE) +
  facet_wrap(~ need) +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  labs(title = "Strength Pathway",
       x = "Perceived Strength", y = "Need Satisfaction",
       color = "Condition") +
  theme_pubr(base_size = 11) +
  theme(legend.position = "bottom")

# Opponent pathway
p2 <- d %>%
  select(cond, opponent, Belonging, SelfEsteem, Meaning, Control) %>%
  pivot_longer(c(Belonging, SelfEsteem, Meaning, Control),
               names_to = "need", values_to = "score") %>%
  ggplot(aes(x = opponent, y = score, color = cond)) +
  geom_point(alpha = 0.3, size = 1.5) +
  geom_smooth(method = "lm", se = TRUE) +
  facet_wrap(~ need) +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  labs(title = "Opponent Perception Pathway",
       x = "Opponent Perception (higher = more negative)",
       y = "Need Satisfaction", color = "Condition") +
  theme_pubr(base_size = 11) +
  theme(legend.position = "bottom")

ggarrange(p1, p2, ncol = 2, common.legend = TRUE, legend = "bottom")

5d. Regression: Do Strength and Opponent Perceptions Explain Needs

Beyond Condition?

run_regression <- function(outcome) {
  m <- lm(as.formula(paste(outcome, 
          "~ cond_d + strength + opponent")), data = d)
  tidy(m) %>%
    mutate(outcome = outcome,
           across(where(is.numeric), ~ round(.x, 3)))
}

library(broom)

reg_results <- map_dfr(c("Belonging", "SelfEsteem", "Meaning", "Control"),
                       run_regression)

reg_results %>%
  filter(term != "(Intercept)") %>%
  mutate(sig = case_when(
    p.value < .001 ~ "***", p.value < .01 ~ "**",
    p.value < .05  ~ "*",   p.value < .10 ~ "†",
    TRUE ~ ""
  )) %>%
  select(outcome, term, estimate, std.error, statistic, p.value, sig) %>%
  kable(caption = "Predicting Needs from Condition, Strength, and Opponent Perception",
        col.names = c("Outcome", "Predictor", "B", "SE", "t", "p", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  collapse_rows(columns = 1, valign = "top") %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001")
Predicting Needs from Condition, Strength, and Opponent Perception
Outcome Predictor B SE t p Sig.
Belonging cond_d 0.136 0.157 0.866 0.388
strength 0.261 0.049 5.269 0.000 ***
opponent -0.314 0.057 -5.465 0.000 ***
SelfEsteem cond_d 0.097 0.160 0.607 0.545
strength 0.422 0.051 8.340 0.000 ***
opponent -0.219 0.059 -3.724 0.000 ***
Meaning cond_d 0.077 0.167 0.460 0.646
strength 0.448 0.053 8.513 0.000 ***
opponent -0.090 0.061 -1.484 0.140
Control cond_d -0.056 0.142 -0.397 0.692
strength 0.545 0.045 12.191 0.000 ***
opponent -0.140 0.052 -2.709 0.007 **
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001

Section 6: Objective Performance (Fruit Collected) and Its Role

6a. Fruit Collected as a Manipulation Check

d <- d %>%
  mutate(fruit_collected = as.numeric(fruit_collected))

# Compare to perceived difficulty as manipulation checks
fruit_manip <- run_ttest("fruit_collected", "Fruit Collected")
diff_manip   <- run_ttest("difficulty",      "Perceived Difficulty")

bind_rows(fruit_manip, diff_manip) %>%
  mutate(sig = case_when(
    p < .001 ~ "***", p < .01 ~ "**",
    p < .05  ~ "*",   p < .10 ~ "†",
    TRUE ~ ""
  )) %>%
  kable(caption = "Manipulation Checks: Objective Performance vs. Perceived Difficulty",
        col.names = c("Measure", "M (Easy)", "M (Hard)",
                      "t", "df", "p", "Cohen's d", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001")
Manipulation Checks: Objective Performance vs. Perceived Difficulty
Measure M (Easy) M (Hard) t df p Cohen’s d Sig.
Fruit Collected 1.38 0.24 6.80 92.1 0.000 1.08 ***
Perceived Difficulty 5.41 5.95 -2.53 179.6 0.012 -0.37
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001
d %>%
  filter(!is.na(fruit_collected)) %>%
  ggplot(aes(x = fruit_collected, fill = cond)) +
  geom_histogram(binwidth = 1, position = position_dodge(0.9),
                 alpha = 0.85, color = "white") +
  scale_fill_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  scale_x_continuous(breaks = 0:6) +
  labs(title = "Fruit Collected by Condition",
       x = "Fruit Collected", y = "Count", fill = "Condition") +
  theme_pubr()
Distribution of Fruit Collected by Condition

Distribution of Fruit Collected by Condition

6b. Fruit Collected vs. Opponent Perception as Predictors of Needs

cor_comparison <- map_dfr(
  c("Belonging", "SelfEsteem", "Meaning", "Control"),
  function(need) {
    r_fruit <- cor.test(d$fruit_collected, d[[need]], use = "complete.obs")
    r_opp   <- cor.test(d$opponent,        d[[need]], use = "complete.obs")
    
    # Extract values explicitly before passing to tibble
    rf_est <- as.numeric(r_fruit$estimate)
    rf_p   <- as.numeric(r_fruit$p.value)
    ro_est <- as.numeric(r_opp$estimate)
    ro_p   <- as.numeric(r_opp$p.value)
    
    tibble(
      Need         = need,
      r_fruit      = round(rf_est, 2),
      p_fruit      = round(rf_p,   3),
      sig_fruit    = case_when(
        rf_p < .001 ~ "***", rf_p < .01 ~ "**",
        rf_p < .05  ~ "*",   rf_p < .10 ~ "†",
        TRUE ~ ""),
      r_opponent   = round(ro_est, 2),
      p_opponent   = round(ro_p,   3),
      sig_opponent = case_when(
        ro_p < .001 ~ "***", ro_p < .01 ~ "**",
        ro_p < .05  ~ "*",   ro_p < .10 ~ "†",
        TRUE ~ "")
    )
  }
)

cor_comparison %>%
  kable(caption = "Fruit Collected vs. Opponent Perception as Predictors of Needs",
        col.names = c("Need",
                      "r (Fruit)", "p", "Sig.",
                      "r (Opponent)", "p", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  add_header_above(c(" " = 1,
                     "Fruit Collected" = 3,
                     "Opponent Perception" = 3)) %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001.
           Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.")
Fruit Collected vs. Opponent Perception as Predictors of Needs
Fruit Collected
Opponent Perception
Need r (Fruit) p Sig. r (Opponent) p Sig.
Belonging 0.30 0 *** -0.49 0 ***
SelfEsteem 0.29 0 *** -0.43 0 ***
Meaning 0.38 0 *** -0.31 0 ***
Control 0.49 0 *** -0.40 0 ***
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001.
Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.
d %>%
  mutate(cond_label = "Overall") %>%
  bind_rows(d %>% mutate(cond_label = as.character(cond))) %>%
  group_by(cond_label) %>%
  summarise(
    n    = n(),
    across(c(opponent_1, opponent_2, opponent_3, opponent_4, opponent),
           list(M  = ~ round(mean(.x, na.rm = TRUE), 2),
                SD = ~ round(sd(.x,   na.rm = TRUE), 2)))
  ) %>%
  pivot_longer(-c(cond_label, n),
               names_to  = c("item", ".value"),
               names_pattern = "(.+)_(M|SD)") %>%
  mutate(item = recode(item,
                       opponent_1 = "Acting unfairly",
                       opponent_2 = "Were mean",
                       opponent_3 = "Breaking rules",
                       opponent_4 = "Ganged up on me",
                       opponent   = "Composite")) %>%
  arrange(cond_label, item) %>%
  kable(caption = "Opponent Perception: Overall and by Condition",
        col.names = c("Group", "n", "Item", "M", "SD")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  collapse_rows(columns = 1:2, valign = "top") %>%
  footnote(general = "Items rated on a 1–7 scale. Higher = more negative opponent perception.")
Opponent Perception: Overall and by Condition
Group n Item M SD
Easy 90 Acting unfairly 4.38 1.78
Breaking rules 2.48 1.39
Composite 4.08 1.26
Ganged up on me 4.93 1.80
Were mean 4.53 1.57
Hard 92 Acting unfairly 4.90 1.99
Breaking rules 3.23 1.79
Composite 4.46 1.55
Ganged up on me 4.98 1.85
Were mean 4.72 1.99
Overall 182 Acting unfairly 4.64 1.91
Breaking rules 2.86 1.64
Composite 4.27 1.42
Ganged up on me 4.96 1.82
Were mean 4.63 1.79
Note:
Items rated on a 1–7 scale. Higher = more negative opponent perception.

6c. Do Opponents Feel Unfair Beyond Objective Performance?

# Show fruit and opponent are largely independent
r_fo <- cor.test(d$fruit_collected, d$opponent, use = "complete.obs")
cat(sprintf("Correlation between fruit collected and opponent perception: r = %.2f, p = %.3f\n",
            r_fo$estimate, r_fo$p.value))
## Correlation between fruit collected and opponent perception: r = -0.18, p = 0.022
# Regress each need on both fruit collected and opponent perception
# Key test: does opponent perception predict belonging over and above actual performance?

run_fruit_regression <- function(outcome) {
  m <- lm(as.formula(paste(outcome,
          "~ fruit_collected + opponent")), 
          data = d %>% filter(!is.na(fruit_collected)))
  tidy(m) %>%
    mutate(outcome = outcome,
           across(where(is.numeric), ~ round(.x, 3)))
}

fruit_reg_results <- map_dfr(
  c("Belonging", "SelfEsteem", "Meaning", "Control"),
  run_fruit_regression
)

fruit_reg_results %>%
  filter(term != "(Intercept)") %>%
  mutate(
    term = recode(term,
                  fruit_collected = "Fruit Collected",
                  opponent        = "Opponent Perception"),
    sig = case_when(
      p.value < .001 ~ "***", p.value < .01 ~ "**",
      p.value < .05  ~ "*",   p.value < .10 ~ "†",
      TRUE ~ ""
    )
  ) %>%
  select(outcome, term, estimate, std.error, statistic, p.value, sig) %>%
  kable(caption = "Predicting Needs from Objective Performance and Opponent Perception",
        col.names = c("Outcome", "Predictor", "B", "SE", "t", "p", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  collapse_rows(columns = 1, valign = "top") %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001.
           Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.")
Predicting Needs from Objective Performance and Opponent Perception
Outcome Predictor B SE t p Sig.
Belonging Fruit Collected 0.220 0.069 3.197 0.002 **
Opponent Perception -0.425 0.061 -6.955 0.000 ***
SelfEsteem Fruit Collected 0.254 0.081 3.153 0.002 **
Opponent Perception -0.349 0.071 -4.882 0.000 ***
Meaning Fruit Collected 0.368 0.081 4.561 0.000 ***
Opponent Perception -0.219 0.072 -3.058 0.003 **
Control Fruit Collected 0.502 0.076 6.587 0.000 ***
Opponent Perception -0.310 0.068 -4.582 0.000 ***
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001.
Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.
# Visualise the two predictors side by side for Belonging (your key DV)
p_fruit <- d %>%
  filter(!is.na(fruit_collected)) %>%
  ggplot(aes(x = fruit_collected, y = Belonging, color = cond)) +
  geom_jitter(alpha = 0.4, width = 0.15, size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "black") +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  scale_x_continuous(breaks = 0:6) +
  labs(title = "Objective Performance → Belonging",
       x = "Fruit Collected", y = "Belonging",
       color = "Condition") +
  theme_pubr() +
  theme(legend.position = "bottom")

p_opp <- d %>%
  filter(!is.na(fruit_collected)) %>%
  ggplot(aes(x = opponent, y = Belonging, color = cond)) +
  geom_jitter(alpha = 0.4, width = 0.08, size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "black") +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  labs(title = "Opponent Perception → Belonging",
       x = "Opponent Perception (higher = more unfair)",
       y = "Belonging", color = "Condition") +
  theme_pubr() +
  theme(legend.position = "bottom")

ggarrange(p_fruit, p_opp, ncol = 2, common.legend = TRUE, legend = "bottom")
Opponent Perception Predicts Belonging Beyond Objective Performance

Opponent Perception Predicts Belonging Beyond Objective Performance

6d. Dichotimizing score given the skew

d <- d %>%
  mutate(scored = ifelse(fruit_collected > 0, 1, 0))

# Check the split
table(d$scored, d$cond, useNA = "ifany")
##       
##        Easy Hard
##   0      26   60
##   1      53   19
##   <NA>   11   13
# Rerun regressions with dichotomized performance
run_scored_regression <- function(outcome) {
  m <- lm(as.formula(paste(outcome,
          "~ scored + opponent")),
          data = d %>% filter(!is.na(scored)))
  tidy(m) %>%
    mutate(outcome = outcome,
           across(where(is.numeric), ~ round(.x, 3)))
}

scored_reg_results <- map_dfr(
  c("Belonging", "SelfEsteem", "Meaning", "Control"),
  run_scored_regression
)

scored_reg_results %>%
  filter(term != "(Intercept)") %>%
  mutate(
    term = recode(term,
                  scored   = "Scored (vs. Did Not Score)",
                  opponent = "Opponent Perception"),
    sig = case_when(
      p.value < .001 ~ "***", p.value < .01 ~ "**",
      p.value < .05  ~ "*",   p.value < .10 ~ "†",
      TRUE ~ ""
    )
  ) %>%
  select(outcome, term, estimate, std.error, statistic, p.value, sig) %>%
  kable(caption = "Predicting Needs from Scoring Success and Opponent Perception",
        col.names = c("Outcome", "Predictor", "B", "SE", "t", "p", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  collapse_rows(columns = 1, valign = "top") %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001.
           Scored = collected at least one fruit during the game.
           Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.")
Predicting Needs from Scoring Success and Opponent Perception
Outcome Predictor B SE t p Sig.
Belonging Scored (vs. Did Not Score) 0.449 0.166 2.707 0.008 **
Opponent Perception -0.432 0.061 -7.028 0.000 ***
SelfEsteem Scored (vs. Did Not Score) 0.415 0.195 2.125 0.035
Opponent Perception -0.364 0.073 -5.017 0.000 ***
Meaning Scored (vs. Did Not Score) 0.783 0.195 4.011 0.000 ***
Opponent Perception -0.229 0.072 -3.164 0.002 **
Control Scored (vs. Did Not Score) 0.955 0.191 4.997 0.000 ***
Opponent Perception -0.331 0.071 -4.670 0.000 ***
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001.
Scored = collected at least one fruit during the game.
Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.
p_scored <- d %>%
  filter(!is.na(scored)) %>%
  mutate(scored_label = factor(scored, levels = c(0, 1),
                               labels = c("Did Not Score", "Scored"))) %>%
  group_by(cond, scored_label) %>%
  summarise(M  = mean(Belonging, na.rm = TRUE),
            SE = sd(Belonging, na.rm = TRUE) / sqrt(n()),
            .groups = "drop") %>%
  ggplot(aes(x = scored_label, y = M, color = cond, group = cond)) +
  geom_point(position = position_dodge(0.3), size = 4) +
  geom_errorbar(aes(ymin = M - SE, ymax = M + SE),
                position = position_dodge(0.3), width = 0.15) +
  geom_line(position = position_dodge(0.3), linetype = "dashed") +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  coord_cartesian(ylim = c(1, 7)) +
  labs(title = "Scoring Success → Belonging",
       x = NULL, y = "Belonging", color = "Condition") +
  theme_pubr() +
  theme(legend.position = "bottom")

p_opp <- d %>%
  filter(!is.na(scored)) %>%
  ggplot(aes(x = opponent, y = Belonging, color = cond)) +
  geom_point(alpha = 0.4, size = 2) +
  geom_smooth(method = "lm", se = TRUE, color = "black") +
  scale_color_manual(values = c("Easy" = "#2196F3", "Hard" = "#F44336")) +
  coord_cartesian(ylim = c(1, 7)) +
  labs(title = "Opponent Perception → Belonging",
       x = "Opponent Perception (higher = more unfair)",
       y = "Belonging", color = "Condition") +
  theme_pubr() +
  theme(legend.position = "bottom")

ggarrange(p_scored, p_opp, ncol = 2, common.legend = TRUE, legend = "bottom")

Does condition matter at all?

run_full_regression <- function(outcome) {
  m <- lm(as.formula(paste(outcome,
          "~ cond_d + scored + opponent")),
          data = d %>% filter(!is.na(scored)))
  tidy(m) %>%
    mutate(outcome = outcome,
           across(where(is.numeric), ~ round(.x, 3)))
}

full_reg_results <- map_dfr(
  c("Belonging", "SelfEsteem", "Meaning", "Control"),
  run_full_regression
)

full_reg_results %>%
  filter(term != "(Intercept)") %>%
  mutate(
    term = recode(term,
                  cond_d   = "Condition (Hard vs. Easy)",
                  scored   = "Scored (vs. Did Not Score)",
                  opponent = "Opponent Perception"),
    sig = case_when(
      p.value < .001 ~ "***", p.value < .01 ~ "**",
      p.value < .05  ~ "*",   p.value < .10 ~ "†",
      TRUE ~ ""
    )
  ) %>%
  select(outcome, term, estimate, std.error, statistic, p.value, sig) %>%
  kable(caption = "Predicting Needs from Condition, Scoring Success, and Opponent Perception",
        col.names = c("Outcome", "Predictor", "B", "SE", "t", "p", "Sig.")) %>%
  kable_styling(bootstrap_options = c("striped", "hover", "condensed")) %>%
  collapse_rows(columns = 1, valign = "top") %>%
  footnote(general = "† p < .10, * p < .05, ** p < .01, *** p < .001.
           Condition coded 0 = Easy, 1 = Hard.
           Scored = collected at least one fruit during the game.
           Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.")
Predicting Needs from Condition, Scoring Success, and Opponent Perception
Outcome Predictor B SE t p Sig.
Belonging Condition (Hard vs. Easy) 0.132 0.181 0.730 0.466
Scored (vs. Did Not Score) 0.504 0.183 2.761 0.006 **
Opponent Perception -0.436 0.062 -7.053 0.000 ***
SelfEsteem Condition (Hard vs. Easy) -0.160 0.214 -0.748 0.456
Scored (vs. Did Not Score) 0.348 0.215 1.615 0.108
Opponent Perception -0.359 0.073 -4.931 0.000 ***
Meaning Condition (Hard vs. Easy) 0.002 0.214 0.010 0.992
Scored (vs. Did Not Score) 0.784 0.216 3.636 0.000 ***
Opponent Perception -0.229 0.073 -3.144 0.002 **
Control Condition (Hard vs. Easy) -0.186 0.209 -0.889 0.375
Scored (vs. Did Not Score) 0.877 0.211 4.166 0.000 ***
Opponent Perception -0.326 0.071 -4.578 0.000 ***
Note:
† p < .10, * p < .05, ** p < .01, *** p < .001.
Condition coded 0 = Easy, 1 = Hard.
Scored = collected at least one fruit during the game.
Higher opponent perception = opponents perceived as more unfair/mean/rule-breaking.

Session Info

sessionInfo()
## R version 4.6.0 (2026-04-24)
## Platform: aarch64-apple-darwin23
## Running under: macOS Ventura 13.3
## 
## Matrix products: default
## BLAS:   /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRblas.0.dylib 
## LAPACK: /Library/Frameworks/R.framework/Versions/4.6/Resources/lib/libRlapack.dylib;  LAPACK version 3.12.1
## 
## locale:
## [1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
## 
## time zone: America/New_York
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
##  [1] broom_1.0.13       kableExtra_1.4.0   knitr_1.51         ggpubr_0.6.3      
##  [5] interactions_1.2.0 lme4_2.0-1         Matrix_1.7-5       effectsize_1.0.2  
##  [9] psych_2.6.5        lubridate_1.9.5    forcats_1.0.1      stringr_1.6.0     
## [13] dplyr_1.2.1        purrr_1.2.2        readr_2.2.0        tidyr_1.3.2       
## [17] tibble_3.3.1       ggplot2_4.0.3      tidyverse_2.0.0    qualtRics_3.2.2   
## 
## loaded via a namespace (and not attached):
##  [1] Rdpack_2.6.6        mnormt_2.1.2        gridExtra_2.3      
##  [4] rlang_1.2.0         magrittr_2.0.5      furrr_0.4.0        
##  [7] otel_0.2.0          compiler_4.6.0      mgcv_1.9-4         
## [10] systemfonts_1.3.2   vctrs_0.7.3         pkgconfig_2.0.3    
## [13] crayon_1.5.3        fastmap_1.2.0       backports_1.5.1    
## [16] labeling_0.4.3      pander_0.6.6        rmarkdown_2.31     
## [19] tzdb_0.5.0          nloptr_2.2.1        bit_4.6.0          
## [22] xfun_0.58           cachem_1.1.0        jsonlite_2.0.0     
## [25] parallel_4.6.0      R6_2.6.1            bslib_0.11.0       
## [28] stringi_1.8.7       RColorBrewer_1.1-3  parallelly_1.47.0  
## [31] car_3.1-5           boot_1.3-32         jquerylib_0.1.4    
## [34] Rcpp_1.1.1-1.1      parameters_0.29.1   splines_4.6.0      
## [37] timechange_0.4.0    tidyselect_1.2.1    rstudioapi_0.19.0  
## [40] abind_1.4-8         yaml_2.3.12         codetools_0.2-20   
## [43] sjlabelled_1.2.0    listenv_0.10.1      lattice_0.22-9     
## [46] withr_3.0.2         bayestestR_0.18.1   S7_0.2.2           
## [49] evaluate_1.0.5      future_1.70.0       xml2_1.5.2         
## [52] jtools_2.3.1        pillar_1.11.1       carData_3.0-6      
## [55] reformulas_0.4.4    insight_1.5.1       generics_0.1.4     
## [58] vroom_1.7.1         hms_1.1.4           scales_1.4.0       
## [61] minqa_1.2.8         globals_0.19.1      glue_1.8.1         
## [64] tools_4.6.0         ggsignif_0.6.4      cowplot_1.2.0      
## [67] grid_4.6.0          rbibutils_2.4.1     datawizard_1.3.1   
## [70] nlme_3.1-169        Formula_1.2-5       cli_3.6.6          
## [73] textshaping_1.0.5   viridisLite_0.4.3   svglite_2.2.2      
## [76] gtable_0.3.6        broom.mixed_0.2.9.7 rstatix_0.7.3      
## [79] sass_0.4.10         digest_0.6.39       farver_2.1.2       
## [82] htmltools_0.5.9     lifecycle_1.0.5     bit64_4.8.2        
## [85] MASS_7.3-65