---
title: "Orthogonality Study 7"
author: "Jim A.C. Everett"
date: "`r format(Sys.time(), '%B %d, %Y')`"
output:
  html_document:
    theme: flatly
    code_folding: hide
    toc: true
    toc_depth: 3
    toc_float: 
      collapsed: TRUE
---

```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
options(knitr.kable.NA = '')
```

***

# Description

***

In Study 7 we had all participants read about a human or AI agent who is described as initially low in intelligence but has now been augmented and we measured, explicitly, how people expect each agent's different traits to change, given this augmentation. For example, participants were asked “As a result of this new breakthrough, how do you think this affected OmegaAI’s level of motivation to help others?” (-50 = drastically reduced; 0 = remains the same; 50 = drastically increased). This means we only have a between subjects factor of Agent (Human vs AI). 

***

# Setup

***


Before doing any analyses, we just need to load the data file and do some initial basis preparation.

```{r, results='hide', message=FALSE, warning=FALSE}
library(readr)
library(psych)
library(car)
library(tidyverse)
library(knitr)
library(kableExtra)
library(jmv)
library(BayesFactor)
library(effectsize)
library(gtsummary)
library(rempsyc)
library(see)
library(correlation)
library(lavaan)
library(emmeans)
library(ggnewscale)
library(patchwork)
library(lme4)
library(lmerTest)
library(broom)
library(broom.mixed)
```

We'll load the data and make sure the conditions are set as factors.

```{r}
# Load in data
df <- read.csv("Study_7_Data.csv", header=TRUE, stringsAsFactors=FALSE)

# set conditions as factors
df$Agent <- as.factor(df$Agent)

# relevel factors
df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))

```

***

We can just see the numbers per condition. In total, we have `r nrow(df)` participants.

```{r}
condition_table <- df %>%
  count(Agent) %>%
  arrange(Agent)


kable(condition_table,
      format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

Sometimes we'll need to just look at participants in the human condition, or the AI condition.

```{r}
df_human <- df  %>% filter(Agent == "Human")
df_AI <- df  %>% filter(Agent == "AI")
```


As outlined in the pre-reg, three of the items were about moral competence and three were about moral motivation, so we can report the Cronbach's alpha reliability.

```{r, message=FALSE, warning=FALSE}
# Moral Competence
alpha_competence <- psych::alpha(df %>% select(Moral_Knowledge, Moral_Predict, Moral_Explain))

# Moral Motivation
alpha_motivation <- psych::alpha(df %>% select(Moral_Help, Moral_Harm, Moral_Fair))

alpha_table <- tibble(
  Scale = c(
    "Moral_Competence",
    "Moral_Motivation"),
  Cronbach_Alpha = c(
    alpha_competence$total$raw_alpha,
    alpha_motivation$total$raw_alpha)
)

kable(alpha_table, format = "html", digits = 3, row.names = FALSE) %>%
  kable_styling(bootstrap_options = "striped", full_width = FALSE, position = "left")
```


***

We can get participant age for the reporting.

```{r}
# Summarize age
age_table <- df %>%
  summarise(
    mean_age = mean(Age, na.rm = TRUE),
    sd_age = sd(Age, na.rm = TRUE),
    min_age = min(Age, na.rm = TRUE),
    max_age = max(Age, na.rm = TRUE)
  )

kable(age_table, format = "html",
            row.names = FALSE, digits = 2) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

And report gender.

```{r}
df$Gender <- as.factor(df$Gender)

kable(table(df$Gender), format = "html",
            row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Manipulation Check

We start looking at our manipulation check, looking at whether ratings of intelligence differ from 0 (i.e. stay the same)

***

```{r}
# T-test
results <- t.test(df$Intelligent, mu = 0)

# Rounding
t_val <- round(results$statistic, 2)
df_val <- sprintf("%.2f", results$parameter)
p_val <- if (results$p.value < 0.001) "<0.001" else sprintf("%.3f", results$p.value)

# Effect size (Cohen's d for one-sample)
d_val <- round(cohens_d(df$Intelligent, mu = 0)$Cohens_d, 2)

# Bayes Factor (one-sample)
bf_result <- ttestBF(x = df$Intelligent, mu = 0)
bf_numeric <- as.numeric(exp(bf_result@bayesFactor$bf))
bf_exponent <- floor(log10(bf_numeric))
bf_mantissa <- bf_numeric / (10^bf_exponent)
bf_apa <- paste0(sprintf("%.2f", bf_mantissa), " × 10^", bf_exponent)

# Combine into a table
final_table <- data.frame(
  `_t_` = t_val,
  `df` = df_val,
  `_p_` = p_val,
  `Bayes Factor` = format(bf_numeric, scientific = TRUE, digits = 6),
  `Bayes Factor APA` = bf_apa,
  `Cohen's _d_` = d_val,
  check.names = FALSE
)

# Output formatted table
kable(final_table, 
      format = "html", 
      row.names = FALSE) %>%
  kable_styling(bootstrap_options = "striped", 
                full_width = FALSE, position = "left")
```

Because we'll do this analysis a lot, we'll create a function. 

```{r}
one.sample.t.test.bf <- function(var, data, mu = 0, labeldv = "DV") {
  
  # Clean the data: remove rows with NA or Inf
  clean_data <- data[!is.na(data[[var]]) & is.finite(data[[var]]), ]
  x <- clean_data[[var]]
  
  # One-sample t-test
  results <- t.test(x, mu = mu)

  # Format t-test output
  t_val <- round(results$statistic, 2)
  df_val <- as.integer(round(results$parameter))
  p_val <- if (results$p.value < 0.001) "<0.001" else sprintf("%.3f", results$p.value)

  # Effect size (Cohen's d for one-sample)
  effect_size <- cohens_d(x, mu = mu)
  d_val <- round(effect_size$Cohens_d, 2)

  # Bayes Factor (one-sample)
  bf_result <- ttestBF(x = x, mu = mu)
  bf_numeric <- as.numeric(exp(bf_result@bayesFactor$bf))
  bf_exponent <- floor(log10(bf_numeric))
  bf_mantissa <- bf_numeric / (10^bf_exponent)
  bf_apa <- paste0(sprintf("%.2f", bf_mantissa), " × 10^", bf_exponent)

  # Combine into final table
  final_table <- data.frame(
    `DV` = labeldv,
    `_t_` = t_val,
    `df` = df_val,
    `_p_` = p_val,
    `Bayes Factor` = format(bf_numeric, scientific = TRUE, digits = 6),
    `Bayes Factor APA` = bf_apa,
    `Cohen's _d_` = d_val,
    check.names = FALSE
  )

  return(final_table)
}
```

```{r}
intelligence <- one.sample.t.test.bf("Intelligent", df, mu = 0, labeldv = "Intelligent")

kable(intelligence, 
      format = "html", 
      row.names = FALSE) %>%
  kable_styling(bootstrap_options = "striped", 
                full_width = FALSE, position = "left")
```

These show the same results so we can just use the function for future.

***

# One Sample T-Tests (Difference from 0 - "Remains the Same").

***

### Descriptives

Here we look at descriptives for the variables by agent condition. 

```{r}
summary_table <- df %>%
  select(Agent, Intelligent, 
         Moral_Competence, Moral_Motivation, 
         Trust, Danger) %>%
  pivot_longer(-Agent, names_to = "Variable", values_to = "Value") %>%
  mutate(Variable = factor(Variable, 
                           levels = c("Intelligent", "Moral_Competence", "Moral_Motivation", 
                                      "Trust", "Danger"))) %>%
  group_by(Variable, Agent) %>%
summarise(
  min = round(min(Value, na.rm = TRUE), 2),
  max = round(max(Value, na.rm = TRUE), 2),
  mean = round(mean(Value, na.rm = TRUE), 2),
  sd = round(sd(Value, na.rm = TRUE), 2),
  .groups = "drop"
)
 
kable(summary_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Descriptive Statistics by Agent</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

Now we can do the one-sample t-tests, for each agent condition seperately.

## AI Conditions

```{r}
intelligence <- one.sample.t.test.bf("Intelligent", 
                                     df_AI, mu = 0, labeldv = "Intelligent")

moral_competence <- one.sample.t.test.bf("Moral_Competence", 
                                     df_AI, mu = 0, labeldv = "Moral Competence")

moral_motivation <- one.sample.t.test.bf("Moral_Motivation", 
                                     df_AI, mu = 0, labeldv = "Moral Motivation")

trust <- one.sample.t.test.bf("Trust", 
                                     df_AI, mu = 0, labeldv = "Trust")

danger <- one.sample.t.test.bf("Danger", 
                                     df_AI, mu = 0, labeldv = "Danger")

# Add a DV label column to each
intelligence$DV <- "Intelligence"
moral_competence$DV <- "Moral Competence"
moral_motivation$DV <- "Moral Motivation"
trust$DV <- "Trust"
danger$DV <- "Danger"

# Combine into a single data frame
combined_results <- rbind(intelligence,
                          moral_competence,moral_motivation,
                          trust,danger)

# Move DV column to the front
combined_results <- combined_results[, c("DV", setdiff(names(combined_results), "DV"))]

kable(combined_results,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>One Sample T-Test on DVs (AI Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

## Human Conditions

```{r}
intelligence <- one.sample.t.test.bf("Intelligent", 
                                     df_human, mu = 0, labeldv = "Intelligent")

moral_competence <- one.sample.t.test.bf("Moral_Competence", 
                                     df_human, mu = 0, labeldv = "Moral Competence")

moral_motivation <- one.sample.t.test.bf("Moral_Motivation", 
                                     df_human, mu = 0, labeldv = "Moral Motivation")

trust <- one.sample.t.test.bf("Trust", 
                                     df_human, mu = 0, labeldv = "Trust")

danger <- one.sample.t.test.bf("Danger", 
                                     df_human, mu = 0, labeldv = "Danger")

# Add a DV label column to each
intelligence$DV <- "Intelligence"
moral_competence$DV <- "Moral Competence"
moral_motivation$DV <- "Moral Motivation"
trust$DV <- "Trust"
danger$DV <- "Danger"

# Combine into a single data frame
combined_results <- rbind(intelligence,
                          moral_competence,moral_motivation,
                          trust,danger)

# Move DV column to the front
combined_results <- combined_results[, c("DV", setdiff(names(combined_results), "DV"))]

kable(combined_results,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>One Sample T-Test on DVs (Human Only)</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

# Independent Samples T-Tests (Difference Between Human and AI).

Above we looked, for the AI and human conditions seperately, whether there was a difference from 0 - did people expect increased intelligence to reduce, increase, or leave the same morality, trust, and danger. 

Here we instead look at differences between the AI and human conditions - do people expect higher degree of change from zero for human or AI. We're using Welch's independent samples t test again, like in previous studies.

First we'll just present descriptives again, so in one place, and then we create a function.

```{r}
summary_table <- df %>%
  select(Agent, Intelligent, 
         Moral_Competence, Moral_Motivation, 
         Trust, Danger) %>%
  pivot_longer(-Agent, names_to = "Variable", values_to = "Value") %>%
  mutate(Variable = factor(Variable, 
                           levels = c("Intelligent", "Moral_Competence", "Moral_Motivation", 
                                      "Trust", "Danger"))) %>%
  group_by(Variable, Agent) %>%
summarise(
  min = round(min(Value, na.rm = TRUE), 2),
  max = round(max(Value, na.rm = TRUE), 2),
  mean = round(mean(Value, na.rm = TRUE), 2),
  sd = round(sd(Value, na.rm = TRUE), 2),
  .groups = "drop"
)
 
kable(summary_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Descriptive Statistics by Agent</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

```{r}
welch.t.test.bf <- function(DV, IV, data, labeliv = "IV", labeldv = "DV") {
  # Build formula from strings
  formula <- as.formula(paste(DV, "~", IV))

  # Welch's t-test
  results <- t.test(formula, data = data, var.equal = FALSE)
  
  # Format test results
  results_table <- data.frame(
    t = round(results$statistic, 2),
    df = sprintf("%.2f", results$parameter),
    p <- if (results$p.value < 0.001) "<0.001" else sprintf("%.3f", results$p.value)
  )

  # Effect size
  effect_size <- cohens_d(formula, data = data)
  cohen_d <- round(effect_size$Cohens_d, 2)

  # Bayes Factor
  bf_result <- ttestBF(formula = formula, data = data)
  bf_numeric <- exp(bf_result@bayesFactor$bf)
  bf_numeric <- as.numeric(exp(bf_result@bayesFactor$bf))
  bf_exponent <- floor(log10(bf_numeric))
  bf_mantissa <- bf_numeric / (10^bf_exponent)
  bf_apa <- paste0(sprintf("%.2f", bf_mantissa), " × 10^", bf_exponent)

  # Combine into final table
  final_table <- data.frame(
    "_t_" = results_table$t,
    "df" = results_table$df,
    "_p_" = results_table$p,
    "Bayes Factor" = bf_numeric,
    "Bayes Factor APA" = bf_apa,
    "Cohen's _d_" = cohen_d,
    check.names = FALSE
  )

  return(final_table)
}
```

```{r}
intelligence <- welch.t.test.bf(data = df, 
                                DV = "Intelligent", IV = "Agent", 
                                labeliv = "Agent", labeldv = "Intelligence")

moral_competence <- welch.t.test.bf(data = df, 
                                DV = "Moral_Competence", IV = "Agent", 
                                labeliv = "Agent", labeldv = "Moral Competence")


moral_motivation <- welch.t.test.bf(data = df, 
                                DV = "Moral_Motivation", IV = "Agent", 
                                labeliv = "Agent", labeldv = "Moral Motivation")

trust <- welch.t.test.bf(data = df, 
                         DV = "Trust", IV = "Agent", 
                         labeliv = "Agent", labeldv = "Trust")

danger <- welch.t.test.bf(data = df, 
                          DV = "Danger", IV = "Agent", 
                          labeliv = "Agent", labeldv = "Danger")

# Add a DV label column to each
intelligence$DV <- "Intelligence"
moral_competence$DV <- "Moral Competence"
moral_motivation$DV <- "Moral Motivation"
trust$DV <- "Trust"
danger$DV <- "Danger"

# Combine into a single data frame
combined_results <- rbind(intelligence,
                          moral_competence, moral_motivation,
                          trust,danger)

# Move DV column to the front
combined_results <- combined_results[, c("DV", setdiff(names(combined_results), "DV"))]

kable(combined_results,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Difference between Human and AI</span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

# Mixed Model with Moral Motivation and Competence

***

We have measured both moral motivation and moral competence, and we can plot both side-by-side here below. 

Then, as outlined in the pre-reg we'll analyse whether the degree of expected change (difference from 0) is stronger for moral competence than moral motivation (or vice versa), and whether this differs by agent.

***

First, we'll just present a figure with ratings of moral motivation and competence by agent type.

```{r, fig.height=4, fig.width=4.5, message=FALSE, warning=FALSE}
# Create dataframe for figure
df_long <- df %>%
  pivot_longer(
    cols = c(Moral_Competence, Moral_Motivation),
    names_to = "Outcome",
    values_to = "Rating")  %>%
  mutate(
    Outcome = factor(Outcome, levels = c("Moral_Competence", "Moral_Motivation")),
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- fill_colors

moral_plot <- ggplot(df_long, aes(x = Outcome, y = Rating, fill = Agent)) +
  
  # Raw jittered data
  geom_jitter(
    shape = 21,
    size = 2,
    stroke = 0.1,
    color = "gray80",
    alpha = 0.15,
    position = position_jitterdodge(dodge.width = 0.6, jitter.width = 0.25, jitter.height = 0.25)
  ) +

  # Mean + CI
  stat_summary(
    aes(color = Agent),
    fun.data = mean_cl_normal,
    geom = "pointrange",
    shape = 21,
    size = 1.2,
    stroke = 1.2,
    fatten = 3,
    position = position_dodge(width = 0.6)
  ) +

  # Baseline reference
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray60", linewidth = 0.7) +
  

  # Color scales
  scale_fill_manual(values = fill_colors) +
  scale_color_manual(values = line_colors) +


  # Labels
  labs(
    x = NULL,
    y = expression(atop("Expected Change", "Reduced \u2194 Increased")),
    fill = NULL,
    color = NULL
  ) +
  coord_cartesian(ylim = c(-50, 50)) +
  scale_y_continuous(breaks = c(-50, -25, 0, 25, 50)) +
  
  scale_x_discrete(labels = c(
      "Moral_Competence" = "Moral Competence",
      "Moral_Motivation" = "Moral Motivation"
    )) +
  
  # Theme
  theme_classic() +
  theme(
    text = element_text(size = 12),
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 12),
    axis.title.x = element_text(margin = margin(t = 10)),
    plot.title = element_text(size = 12, hjust = 0.5, margin = margin(b = 10)),
    legend.position = "bottom",
    legend.direction = "horizontal",
    legend.justification = "center",
    legend.box.margin = margin(t = -5),
    legend.key.height = unit(1.2, "lines"),
    legend.key.width = unit(1.2, "lines"),
    legend.text = element_text(size = 12)
  )

# Define the subfolder name
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save both versions
ggsave((file.path(folder, "Study 7 Moral Competence and Motivation.pdf")), plot = moral_plot,
       width = 4.2, height = 3.5, units = "in", dpi = 300)

moral_plot
```

```{r}
# Create model for preparation
df_long <- df %>%
  pivot_longer(
    cols = c(Moral_Competence, Moral_Motivation),
    names_to = "Outcome",
    values_to = "Rating")  %>%
  mutate(
    Outcome = factor(Outcome, levels = c("Moral_Competence", "Moral_Motivation")),
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set contrasts
contrasts(df_long$Agent) <- contr.treatment
contrasts(df_long$Outcome) <- contr.treatment

# Model with random intercept by participant and slope for trait/outcome type
#model <- lmer(
 # Rating ~ Outcome * Agent + (1 + Outcome | Participant),
 # data = df_long,
  #control = lmerControl(optimizer = "bobyqa", optCtrl = list(maxfun = 200000))
#)


# Model with random intercept only:
model <- lmer(
  Rating ~ Outcome * Agent + (1 | Participant),
  data = df_long,
)


# Tidy and format results
formatted_table <- broom.mixed::tidy(model, effects = "fixed") %>%
  mutate(
    Term = case_when(
      # Intercept
      term == "(Intercept)" ~ "Intercept",

      # Main effects
      term == "OutcomeMoral_Motivation" ~ "Moral Motivation vs Competence [Motivation]",
      term == "AgentAI" ~ "Agent [AI]",

      # Two-way interactions
      term == "OutcomeMoral_Motivation:AgentAI" ~ "Agent × Moral Outcome",

      # Fallback
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = round(df, 1),
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    )
  ) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,       
      format = "html",
      caption = "<span style='color:black; font-weight:bold;
      '>The interactive effect of agent type and trait type (moral motivation vs competence) on expected change </span>",
      row.names = FALSE) %>%
      kable_styling(bootstrap_options = "striped",full_width = FALSE, position = "left")
```


***

# Predictors of Trust and Danger

***

Next, we can ask whether trust is shaped by ratings of moral competence and moral motivation, and whether these relationships depend on Agent.

***

## Trust

***

### Moral Motivation 

This looks at the effect of perceived moral motivation on trust. 

```{r}
# Centre the predictors
df <- df %>%
  mutate(
    Moral_Motivation_c = scale(Moral_Motivation, center = TRUE, scale = FALSE) %>% as.numeric()
  )

# Just make sure factors are correct, again, just to always check
df$Agent <- as.factor(df$Agent)
df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))

# Check contrasts (we use cont.treatment for all the regressions)
contrasts(df$Agent) <- contr.treatment

# Do the model
model <- lm(
  Trust ~ Moral_Motivation_c * Agent,
  data = df
)

df_resid <- df.residual(model)  # get residuals for reporting in APA

# Tidy, relabel, reorder, and format
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      # Main effects
      term == "(Intercept)" ~ "Intercept",
      term == "Moral_Motivation_c" ~ "Moral Motivation (Centered)",
      term == "AgentAI" ~ "Agent [AI]",

      # Two-way interactions
      term == "Moral_Motivation_c:AgentAI" ~ "Moral Motivation × Agent",
      
      # Fallback
      TRUE ~ term
    ),

    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),

    order = factor(Term, levels = c(
      "Intercept",

      # Main effects
      "Moral Motivation (Centered)", "Agent [AI]",

      # 2-way
      "Moral Motivation × Agent"
    ))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


# Display the formatted results table
kable(formatted_table,      
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Interactive Effects of Moral Motivation on Trust</span>",
      row.names = FALSE) %>%
  kable_styling(
    bootstrap_options = "striped",
    full_width = FALSE,
    position = "left"
  )
```

***

### Moral Competence 

This looks at the effect of perceived moral competence on trust.

```{r}
# Centre the predictors
df <- df %>%
  mutate(
    Moral_Competence_c = scale(Moral_Competence, center = TRUE, scale = FALSE) %>% as.numeric()
  )

# Just make sure factors are correct, again, just to always check
df$Agent <- as.factor(df$Agent)
df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))

# Check contrasts (we use cont.treatment for all the regressions)
contrasts(df$Agent) <- contr.treatment

# Do the model
model <- lm(
  Trust ~ Moral_Competence_c * Agent,
  data = df
)

df_resid <- df.residual(model)  # get residuals for reporting in APA

# Tidy, relabel, reorder, and format
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      # Main effects
      term == "(Intercept)" ~ "Intercept",
      term == "Moral_Competence_c" ~ "Moral Competence (Centered)",
      term == "AgentAI" ~ "Agent [AI]",

      # Two-way interactions
      term == "Moral_Competence_c:AgentAI" ~ "Moral Competence × Agent",
      
      # Fallback
      TRUE ~ term
    ),

    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),

    order = factor(Term, levels = c(
      "Intercept",

      # Main effects
      "Moral Competence (Centered)", "Agent [AI]",

      # 2-way
      "Moral Competence × Agent"
    ))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


# Display the formatted results table
kable(formatted_table,      
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Interactive Effects of Moral Competence on Trust</span>",
      row.names = FALSE) %>%
  kable_styling(
    bootstrap_options = "striped",
    full_width = FALSE,
    position = "left"
  )
```

***

We'll make a figure to show this.

```{r, warning=FALSE, message=FALSE}
# Pivot data to long form
df_long <- df %>%
  pivot_longer(
    cols = c(Moral_Competence, Moral_Motivation),
    names_to = "Predictor",
    values_to = "Predictor_Value"
  )

# Set up colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- fill_colors

# Create label data for custom x-axis annotations
x_labels <- data.frame(
  Predictor = c("Moral_Motivation", "Moral_Competence"),
  x = 0,
  y = -75,
  label = c(
  "Reduced \u2194 Increased",
  "Reduced \u2194 Increased"
  )
)

# Filter data
df_motivation <- df_long %>% filter(Predictor == "Moral_Motivation")
df_competence <- df_long %>% filter(Predictor == "Moral_Competence")

# Shared base theme
base_theme <- theme_classic() +
  theme(
    text = element_text(size = 12),
    plot.title = element_text(size = 12, hjust = 0.5),
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 12),
    axis.title.x = element_blank(),
    plot.margin = margin(t = 10, r = 5, b = 60, l = 5),
    legend.position = "none"
  )

x_limits <- c(-50, 50)
y_limits <- c(-50, 50)

# Moral Motivation plot
plot_motivation <- ggplot(df_motivation, aes(x = Predictor_Value, y = Trust, color = Agent, fill = Agent)) +
  geom_jitter(
    shape = 21, size = 2, stroke = 0.1,
    color = "gray80", alpha = 0.15,
    position = position_jitter(width = 1.5, height = 0.5)
  ) +
  geom_smooth(method = "lm", se = TRUE, alpha = 0.2, linewidth = 1.2) +
  geom_text(
    data = x_labels %>% filter(Predictor == "Moral_Motivation"),
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE,
    size = 4, fontface = "plain"
  ) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  coord_cartesian(xlim = x_limits, ylim = y_limits, clip = "off") +
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +
  labs(
    title = "Moral Motivation",
    y = expression(atop("Trustworthiness", "Reduced \u2194 Increased"),
    x = NULL)
  ) +
  base_theme

# Moral Competence plot
plot_competence <- ggplot(df_competence, aes(x = Predictor_Value, y = Trust, color = Agent, fill = Agent)) +
  geom_jitter(
    shape = 21, size = 2, stroke = 0.1,
    color = "gray80", alpha = 0.15,
    position = position_jitter(width = 1.5, height = 0.5)
  ) +
  geom_smooth(method = "lm", se = TRUE, alpha = 0.2, linewidth = 1.2) +
  geom_text(
    data = x_labels %>% filter(Predictor == "Moral_Competence"),
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE,
    size = 4, fontface = "plain"
  ) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  coord_cartesian(xlim = x_limits, ylim = y_limits, clip = "off") +
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +
  labs(
    title = "Moral Competence",
    y = NULL,
    x = NULL
  ) +
  base_theme +
  theme(
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank()
  )

# Combine with shared legend
combined_trust_plot <- plot_motivation + plot_competence +
  plot_layout(guides = "collect") &
  theme(
    legend.position = "bottom",
    legend.title = element_blank(),                  
    legend.text = element_text(size = 12),           
    legend.box.margin = margin(t = 10, b = -30),
    legend.margin = margin(t = 15, b = -30)
  )

# Define the subfolder name
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save
ggsave((file.path(folder, "Study 7 Moral Competence and Moral Motivation on Trust.pdf")), plot = combined_trust_plot,
       width = 7, height = 4, units = "in", dpi = 300)

combined_trust_plot
```

***

### Interactive Effect of Motivation and Competence

Here we look at the interactive effect of moral competence and moral motivation (centered) with agent type on trust. This looks at both together, as outlined in the pre-registration.

```{r}
# Centre the predictors
df <- df %>%
  mutate(
    Moral_Competence_c = scale(Moral_Competence, center = TRUE, scale = FALSE) %>% as.numeric(),
    Moral_Motivation_c = scale(Moral_Motivation, center = TRUE, scale = FALSE) %>% as.numeric()
  )

# Just make sure factors are correct, again, just to always check
df$Agent <- as.factor(df$Agent)
df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))

# Check contrasts (we use cont.treatment for all the regressions)
contrasts(df$Agent) <- contr.treatment

# Do the model
model <- lm(
  Trust ~ Moral_Competence_c * Moral_Motivation_c * Agent,
  data = df
)

df_resid <- df.residual(model)  # get residuals for reporting in APA

# Tidy, relabel, reorder, and format
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      # Main effects
      term == "(Intercept)" ~ "Intercept",
      term == "Moral_Competence_c" ~ "Moral Competence (Centered)",
      term == "Moral_Motivation_c" ~ "Moral Motivation (Centered)",
      term == "AgentAI" ~ "Agent [AI]",

      # Two-way interactions
      term == "Moral_Competence_c:Moral_Motivation_c" ~ "Moral Competence × Moral Motivation",
      term == "Moral_Competence_c:AgentAI" ~ "Moral Competence × Agent",
      term == "Moral_Motivation_c:AgentAI" ~ "Moral Motivation × Agent",
      
      # Three-way interactions
      term == "Moral_Competence_c:Moral_Motivation_c:AgentAI" ~ "Moral Competence × Moral Motivation x Agent",

      # Fallback
      TRUE ~ term
    ),

    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),

    order = factor(Term, levels = c(
      "Intercept",

      # Main effects
      "Moral Competence (Centered)", "Moral Motivation (Centered)", "Agent [AI]",

      # 2-way
      "Moral Competence × Moral Motivation",
      "Moral Competence × Agent",
      "Moral Motivation × Agent",
      
      # 3-way
      "Moral Competence × Moral Motivation x Agent"
    ))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


# Display the formatted results table
kable(formatted_table,      
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Interactive Effects of Moral Competence and Moral Motivation on Trust</span>",
      row.names = FALSE) %>%
  kable_styling(
    bootstrap_options = "striped",
    full_width = FALSE,
    position = "left"
  )
```


***

## Danger

***

### Moral Motivation 

This looks at the effect of perceived moral motivation on danger 

```{r}
# Centre the predictors
df <- df %>%
  mutate(
    Moral_Motivation_c = scale(Moral_Motivation, center = TRUE, scale = FALSE) %>% as.numeric()
  )

# Just make sure factors are correct, again, just to always check
df$Agent <- as.factor(df$Agent)
df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))

# Check contrasts (we use cont.treatment for all the regressions)
contrasts(df$Agent) <- contr.treatment

# Do the model
model <- lm(
  Danger ~ Moral_Motivation_c * Agent,
  data = df
)

df_resid <- df.residual(model)  # get residuals for reporting in APA

# Tidy, relabel, reorder, and format
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      # Main effects
      term == "(Intercept)" ~ "Intercept",
      term == "Moral_Motivation_c" ~ "Moral Motivation (Centered)",
      term == "AgentAI" ~ "Agent [AI]",

      # Two-way interactions
      term == "Moral_Motivation_c:AgentAI" ~ "Moral Motivation × Agent",
      
      # Fallback
      TRUE ~ term
    ),

    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),

    order = factor(Term, levels = c(
      "Intercept",

      # Main effects
      "Moral Motivation (Centered)", "Agent [AI]",

      # 2-way
      "Moral Motivation × Agent"
    ))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


# Display the formatted results table
kable(formatted_table,      
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Interactive Effects of Moral Motivation on Danger</span>",
      row.names = FALSE) %>%
  kable_styling(
    bootstrap_options = "striped",
    full_width = FALSE,
    position = "left"
  )
```

***

### Moral Competence 

This looks at the effect of perceived moral competence on danger

```{r}
# Centre the predictors
df <- df %>%
  mutate(
    Moral_Competence_c = scale(Moral_Competence, center = TRUE, scale = FALSE) %>% as.numeric()
  )

# Just make sure factors are correct, again, just to always check
df$Agent <- as.factor(df$Agent)
df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))

# Check contrasts (we use cont.treatment for all the regressions)
contrasts(df$Agent) <- contr.treatment

# Do the model
model <- lm(
  Danger ~ Moral_Competence_c * Agent,
  data = df
)

df_resid <- df.residual(model)  # get residuals for reporting in APA

# Tidy, relabel, reorder, and format
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      # Main effects
      term == "(Intercept)" ~ "Intercept",
      term == "Moral_Competence_c" ~ "Moral Competence (Centered)",
      term == "AgentAI" ~ "Agent [AI]",

      # Two-way interactions
      term == "Moral_Competence_c:AgentAI" ~ "Moral Competence × Agent",
      
      # Fallback
      TRUE ~ term
    ),

    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),

    order = factor(Term, levels = c(
      "Intercept",

      # Main effects
      "Moral Competence (Centered)", "Agent [AI]",

      # 2-way
      "Moral Competence × Agent"
    ))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


# Display the formatted results table
kable(formatted_table,      
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Interactive Effects of Moral Competence on Danger</span>",
      row.names = FALSE) %>%
  kable_styling(
    bootstrap_options = "striped",
    full_width = FALSE,
    position = "left"
  )
```

We'll make a figure to show this.

```{r, warning=FALSE, message=FALSE}
library(patchwork)

# Set up colors
fill_colors <- c("Human" = "#E69F00", "AI" = "#56B4E9")
line_colors <- fill_colors

# Create label data for custom x-axis annotations
x_labels <- data.frame(
  Predictor = c("Moral_Motivation", "Moral_Competence"),
  x = 0,
  y = -75,
  label = c(
  "Reduced \u2194 Increased",
  "Reduced \u2194 Increased"
  )
)

# Filter data
df_motivation <- df_long %>% filter(Predictor == "Moral_Motivation")
df_competence <- df_long %>% filter(Predictor == "Moral_Competence")

# Shared base theme
base_theme <- theme_classic() +
  theme(
    text = element_text(size = 12),
    plot.title = element_text(size = 12, hjust = 0.5),
    axis.title = element_text(size = 12),
    axis.text = element_text(size = 12),
    axis.title.x = element_blank(),
    plot.margin = margin(t = 10, r = 5, b = 60, l = 5),
    legend.position = "none"
  )

x_limits <- c(-50, 50)
y_limits <- c(-50, 50)

# Moral Motivation plot
plot_motivation <- ggplot(df_motivation, aes(x = Predictor_Value, y = Danger, color = Agent, fill = Agent)) +
  geom_jitter(
    shape = 21, size = 2, stroke = 0.1,
    color = "gray80", alpha = 0.15,
    position = position_jitter(width = 1.5, height = 0.5)
  ) +
  geom_smooth(method = "lm", se = TRUE, alpha = 0.2, linewidth = 1.2) +
  geom_text(
    data = x_labels %>% filter(Predictor == "Moral_Motivation"),
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE,
    size = 4, fontface = "plain"
  ) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  coord_cartesian(xlim = x_limits, ylim = y_limits, clip = "off") +
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +
  labs(
    title = "Moral Motivation",
    y = expression(atop("Danger", "Reduced \u2194 Increased"),
    x = NULL)
  ) +
  base_theme

# Moral Competence plot
plot_competence <- ggplot(df_competence, aes(x = Predictor_Value, y = Danger, color = Agent, fill = Agent)) +
  geom_jitter(
    shape = 21, size = 2, stroke = 0.1,
    color = "gray80", alpha = 0.15,
    position = position_jitter(width = 1.5, height = 0.5)
  ) +
  geom_smooth(method = "lm", se = TRUE, alpha = 0.2, linewidth = 1.2) +
  geom_text(
    data = x_labels %>% filter(Predictor == "Moral_Competence"),
    aes(x = x, y = y, label = label),
    inherit.aes = FALSE,
    size = 4, fontface = "plain"
  ) +
  geom_hline(yintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  geom_vline(xintercept = 0, linetype = "dashed", color = "gray70", linewidth = 0.7) +
  coord_cartesian(xlim = x_limits, ylim = y_limits, clip = "off") +
  scale_color_manual(values = line_colors) +
  scale_fill_manual(values = fill_colors) +
  labs(
    title = "Moral Competence",
    y = NULL,
    x = NULL
  ) +
  base_theme +
  theme(
    axis.text.y = element_blank(),
    axis.ticks.y = element_blank()
  )

# Combine with shared legend
combined_danger_plot <- plot_motivation + plot_competence +
  plot_layout(guides = "collect") &
  theme(
    legend.position = "bottom",
    legend.title = element_blank(),                  
    legend.text = element_text(size = 12),           
    legend.box.margin = margin(t = 10, b = -30),
    legend.margin = margin(t = 15, b = -30)
  )

# Define the subfolder name
folder <- "figures"

# Create the folder if it doesn't already exist
if (!dir.exists(folder)) {
  dir.create(folder)
}

# Save
ggsave((file.path(folder, "Study 7 Moral Competence and Moral Motivation on Danger.pdf")), plot = combined_danger_plot,
       width = 7, height = 4, units = "in", dpi = 300)

combined_danger_plot
```

***

### Interactive Effect of Motivation and Competence

Here we look at the interactive effect of moral competence and moral motivation (centered) with agent type on danger. This looks at both together, as outlined in the pre-registration.

```{r}
# Pivot data to long form
df_long <- df %>%
  pivot_longer(
    cols = c(Moral_Competence, Moral_Motivation),
    names_to = "Predictor",
    values_to = "Predictor_Value"
  )

# Centre the predictors
df <- df %>%
  mutate(
    Moral_Competence_c = scale(Moral_Competence, center = TRUE, scale = FALSE) %>% as.numeric(),
    Moral_Motivation_c = scale(Moral_Motivation, center = TRUE, scale = FALSE) %>% as.numeric()
  )

# Just make sure factors are correct, again, just to always check
df$Agent <- as.factor(df$Agent)
df$Agent <- 
  factor(df$Agent, 
         levels = c("Human", "AI"))

# Check contrasts (we use cont.treatment for all the regressions)
contrasts(df$Agent) <- contr.treatment

# Do the model
model <- lm(
  Danger ~ Moral_Competence_c * Moral_Motivation_c * Agent,
  data = df
)

df_resid <- df.residual(model)  # get residuals for reporting in APA

# Tidy, relabel, reorder, and format
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      # Main effects
      term == "(Intercept)" ~ "Intercept",
      term == "Moral_Competence_c" ~ "Moral Competence (Centered)",
      term == "Moral_Motivation_c" ~ "Moral Motivation (Centered)",
      term == "AgentAI" ~ "Agent [AI]",

      # Two-way interactions
      term == "Moral_Competence_c:Moral_Motivation_c" ~ "Moral Competence × Moral Motivation",
      term == "Moral_Competence_c:AgentAI" ~ "Moral Competence × Agent",
      term == "Moral_Motivation_c:AgentAI" ~ "Moral Motivation × Agent",
      
      # Three-way interactions
      term == "Moral_Competence_c:Moral_Motivation_c:AgentAI" ~ "Moral Competence × Moral Motivation x Agent",

      # Fallback
      TRUE ~ term
    ),

    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),

    order = factor(Term, levels = c(
      "Intercept",

      # Main effects
      "Moral Competence (Centered)", "Moral Motivation (Centered)", "Agent [AI]",

      # 2-way
      "Moral Competence × Moral Motivation",
      "Moral Competence × Agent",
      "Moral Motivation × Agent",
      
      # 3-way
      "Moral Competence × Moral Motivation x Agent"
    ))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


# Display the formatted results table
kable(formatted_table,      
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Interactive Effects of Moral Competence and Moral Motivation on Danger</span>",
      row.names = FALSE) %>%
  kable_styling(
    bootstrap_options = "striped",
    full_width = FALSE,
    position = "left"
  )
```

***

# Correlations

***

We'll look, across conditions, the correlation between participants ratings of intelligence and morality. We can use a quick custom function to make this easy.

```{r}
# Individual correlation 
jim.correlation <- function(DV_A, DV_B, Item) {
  
test <- cor.test(DV_A, DV_B, method = "pearson")

correlation <- test$estimate
correlation <- round(correlation, digits = 2)
df_val <- sprintf("%.0f", test$parameter)  # APA style: no decimals for df

p_raw <- test$p.value
p_formatted <- ifelse(
  is.na(p_raw), NA,
  ifelse(p_raw < .001, "< .001", paste0("= ", sub("^0", "", sprintf("%.3f", p_raw))))
)

combined <- data.frame(
    df = df_val,
    r = correlation,
    p = p_formatted,
    row.names = Item,
    check.names = FALSE
  )

  return(combined)
}

```

***

We first look at the highest level with the correlation between general intelligence, general moral competence, and general moral motivation.

```{r}
intelligence_moral_competence_corr <- jim.correlation(DV_A = df$Intelligent, 
                                              DV_B = df$Moral_Competence,
                                              Item = "Intelligence + Moral Competence")

intelligence_moral_motivation_corr <- jim.correlation(DV_A = df$Intelligent, 
                                              DV_B = df$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation")

# Bind together
correlation_summary <- bind_rows(
  intelligence_moral_competence_corr,
  intelligence_moral_motivation_corr
)

kable(correlation_summary, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

We'll also look at this main correlations broken down by conditions.

```{r}
# AI agent
intelligence_moral_competence_AI <- jim.correlation(DV_A = df_AI$Intelligent, 
                                              DV_B = df_AI$Moral_Competence,
                                              Item = "Intelligence + Moral Competence (AI)")

intelligence_moral_motivation_AI <- jim.correlation(DV_A = df_AI$Intelligent, 
                                              DV_B = df_AI$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation (AI)")

# Human agent
intelligence_moral_competence_human <- jim.correlation(DV_A = df_human$Intelligent, 
                                              DV_B = df_human$Moral_Competence,
                                              Item = "Intelligence + Moral Competence (Human)")

intelligence_moral_motivation_human <- jim.correlation(DV_A = df_human$Intelligent, 
                                              DV_B = df_human$Moral_Motivation,
                                              Item = "Intelligence + Moral Motivation (Human)")

# Bind together
correlation_summary <- bind_rows(
intelligence_moral_competence_AI,
intelligence_moral_motivation_AI,
intelligence_moral_competence_human,
intelligence_moral_motivation_human
)

kable(correlation_summary, format = "html",
            row.names = TRUE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")

```

***

# Familiarity

***

Just as an exploratory test, we can look at whether familiarity influences these results. This is the distribution of familiarity scores.

```{r, fig.width=4, fig.height=4}
ggplot(df, aes(x = Familiarity)) +
  geom_histogram(binwidth = 1, fill = "#0072B2", color = "white") +
  scale_x_continuous(breaks = 0:6) +
  labs(
    title = "Distribution of Familiarity Ratings",
    x = "Familiarity",
    y = "Number of Participants"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5)
  )
```

***

## Intelligence

We here look at the effects of familiarity (centered) and agent

```{r, message=FALSE}
# Centre familiarity and set factor levels
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric(),
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set  contrasts
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Intelligent ~ Familiarity_c * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Familiarity_c:Agent1" ~ "Familiarity × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Agent [AI]", 
      "Familiarity × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived intelligence by participant AI familiarity and agent type </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Moral Competence

```{r, message=FALSE}
# Centre familiarity and set factor levels
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric(),
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set contrasts
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Competence ~ Familiarity_c * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Familiarity_c:AgentAI" ~ "Familiarity × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Agent [AI]", 
      "Familiarity × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral competence by participant AI familiarity and agent type </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Moral Motivation

```{r, message=FALSE}
# Centre familiarity and set factor levels
df <- df %>%
  mutate(
    Familiarity_c = scale(Familiarity, center = TRUE, scale = FALSE) %>% as.numeric(),
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set contrasts
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Motivation ~ Familiarity_c * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Familiarity_c" ~ "Familiarity (Centred)",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Familiarity_c:AgentAI" ~ "Familiarity × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "Familiarity (Centred)", 
      "Agent [AI]", 
      "Familiarity × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)

kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral motivation by participant AI familiarity and agent type </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

# AI Accuracy (PEW)

***

Now we look at the questions where participants were given different questions about AI taken from PEW, to get a more "objective" measure of AI knowledge to complement the self-report familiarity measure. 

***

We can first just look at the distributions.

```{r}
# Create summary table
pew_summary <- df %>%
  count(Pew_Correct) %>%
  mutate(
    Pew_Correct = ifelse(is.na(Pew_Correct), "NA", as.character(Pew_Correct)),
    Percent = round(100 * n / sum(n), 1)
  )

# Show summary
kable(pew_summary, format = "html", col.names = c("Pew_Correct Score", "Count", "Percent")) %>%
  kable_styling(
    bootstrap_options = c("striped"),
    full_width = FALSE,
    position = "left"
  )
```

```{r, message = FALSE}
ggplot(df, aes(x = Pew_Correct)) +
  geom_histogram(binwidth = 1, fill = "#0072B2", color = "white") +
  scale_x_continuous(breaks = 0:6) +
  labs(
    title = "Distribution of Pew AI Knowledge Scores",
    x = "Pew_Correct Score (0–6)",
    y = "Number of Participants"
  ) +
  theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", hjust = 0.5)
  )
```

***

## Intelligence

We here look at the effects of PEW AI knowledge (centered) and agent, and we use `contr.sum` contrasts because of the categorical predictor and interaction. 

```{r}
# Centre PEW
df <- df %>%
  mutate(
    Pew_Correct_c = scale(Pew_Correct, center = TRUE, scale = FALSE) %>% as.numeric(),,
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set sum contrasts
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Intelligent ~ Pew_Correct_c * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Pew_Correct_c" ~ "PEW AI Knowledge (Centered)",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Pew_Correct_c:AgentAI" ~ "PEW × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "PEW AI Knowledge (centered)", 
      "Agent [AI]", 
      "PEW × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived intelligence by participant AI knowledge and agent type </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```



***

## Moral Competence

```{r, message=FALSE}
# Centre PEW
df <- df %>%
  mutate(
    Pew_Correct_c = scale(Pew_Correct, center = TRUE, scale = FALSE) %>% as.numeric(),,
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set contrasts
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Competence ~ Pew_Correct_c * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Pew_Correct_c" ~ "PEW AI Knowledge (centered)",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Pew_Correct_c:AgentAI" ~ "PEW × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "PEW AI Knowledge (Centered)", 
      "Agent [AI]", 
      "PEW × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral competence by participant AI knowledge and agent type </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```

***

## Moral Motivation

```{r, message=FALSE}
# Centre PEW
df <- df %>%
  mutate(
    Pew_Correct_c = scale(Pew_Correct, center = TRUE, scale = FALSE) %>% as.numeric(),,
    Agent = factor(Agent, levels = c("Human", "AI"))
  )

# Set contrasts
contrasts(df$Agent) <- contr.treatment

# Fit model
model <- lm(Moral_Motivation ~ Pew_Correct_c * Agent, data = df)

# Get degrees of freedom
df_resid <- df.residual(model)

# Format nicely
formatted_table <- broom::tidy(model) %>%
  mutate(
    Term = case_when(
      term == "(Intercept)" ~ "Intercept",
      term == "Pew_Correct_c" ~ "PEW AI Knowledge (centered)",
      term == "AgentAI" ~ "Agent [AI]",
      term == "Pew_Correct_c:AgentAI" ~ "PEW × Agent",
      TRUE ~ term
    ),
    Estimate = round(estimate, 2),
    SE = round(std.error, 2),
    df = df_resid,
    t = round(statistic, 2),
    p = ifelse(
      is.na(p.value), NA,
      ifelse(p.value < .001, "<.001", paste0("= ", sub("^0", "", sprintf("%.3f", p.value))))
    ),
    order = factor(Term, levels = c(
      "Intercept", 
      "PEW AI Knowledge (centered)", 
      "Agent [Human vs AI]", 
      "PEW × Agent"))
  ) %>%
  arrange(order) %>%
  select(Term, Estimate, SE, df, t, p)


kable(formatted_table,
      format = "html", 
      caption = "<span style='color:black; font-weight:bold;
      '>Perceived moral motivation by participant AI knowledge and agent type </span>",
       row.names = FALSE) %>%
        kable_styling(bootstrap_options = "striped", 
                      full_width = FALSE, position = "left")
```