---
title: "DMG versus dndR"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{DMG versus dndR}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r setup, include = FALSE}
knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
```

```{r libs, echo = FALSE, message = FALSE}
# devtools::install_github("njlyon0/dndR", force = TRUE)
library(dndR); library(ggplot2); library(magrittr); library(dplyr); library(tidyr)
```

## `dndR` versus DMG Comparisons

See below for some comparisons between my functions and the Dungeon Master's Guide statistics they attempt to recapitulate.

### `cr_convert` vs. DMG

`cr_convert` is embedded in the `monster_stats` function and is what allows that function to handle both CR and XP inputs. The DMG specifies the XP value of a monster of any CR from 0 to 30 so `cr_convert` uses the formula of that line to avoid querying the table for this conversion.

Below is the comparison of the DMG's XP-to-CR curve and the one produced by `cr_convert`.

```{r cr-convert-plot, echo = F, warning = F, error = F, fig.height = 4, fig.width = 4, fig.align = "center"}
cr_actual <- data.frame(
  "cr" = c(0, 0.125, 0.25, 0.5, 1:30),
  "dmg_xp" = c(0, 25, 50, 100, 200, 450, 700, 1100, 1800, 2300, 2900,
               3900, 5000, 5900, 7200, 8400, 10000, 11500, 13000, 15000,
               18000, 20000, 22000, 25000, 33000, 41000, 50000, 62000,
               75000, 90000, 105000, 120000, 135000, 155000) ) %>%
  # For each row...
  dplyr::rowwise() %>%
  # Calculate XP for a given CR using `cr_convert`
  dplyr::mutate("calc_xp" = dndR::cr_convert(cr = cr)) %>%
  # Pivot to long format
  tidyr::pivot_longer(cols = dplyr::contains('_xp'),
                      names_to = "authority",
                      values_to = "xp") %>%
  # And clean up the entries of the source column
  dplyr::mutate(source = base::ifelse(test = (authority == "calc_xp"),
                                      yes = "dndR", no = "DMG"))

# Creat the plot comparison
ggplot(cr_actual, aes(x = cr, y = xp, shape = source)) +
  geom_point(aes(fill = source), color = 'black', size = 3, alpha = 0.8,
             pch = rep(x = c(21, 24), times = 34),
             position = position_dodge(width = 0.5)) +
  geom_smooth(aes(color = source), method = 'loess',
              formula = 'y ~ x', se = FALSE) +
  # geom_smooth(formula = 'y ~ x', method = 'loess', se = F) +
  labs(x = "Challenge Rating (CR)", y = "Experience Points (XP)") +
  scale_color_manual(values = c("#c51b7d", "#4d9221")) +
  scale_fill_manual(values = c("#c51b7d", "#4d9221")) +
  theme_classic() +
  theme(legend.position = c(0.2, 0.9),
        legend.title = element_blank(),
        axis.text.y = element_text(size = 12),
        axis.text.x = element_text(size = 14),
        axis.title = element_text(size = 16))
```

### `xp_pool` vs. DMG

The DMG specifies the XP threshold *per player* for a given difficulty while my function asks for the *average* player level and the party size. This difference keeps the function streamlined and flexible for parties of any size. If average party level is an integer, the DMG's table for the encounter XP to player level is used. Otherwise, `xp_pool` uses the formula for the line defining the XP-party level curve implicit in the DMG's table. This has the benefit of being able to handle parties where not all players are the same level.

Below is a comparison of the DMG's XP-to-party level curve versus the one obtained by `xp_pool`.

```{r xp-pool-plot, echo = F, warning = F, error = F, fig.height = 4, fig.width = 4, fig.align = "center"}
xp_df <- data.frame('pc_level' = 1:20,
                    'easy_xp' = c(25, 50, 75, 125, 250, 300, 350, 450,
                                  550, 600, 800, 1000, 1100, 1250, 1400, 
                                  1600, 2000, 2100, 2400, 2800)) %>%
  # For each row...
  dplyr::rowwise() %>%
  # Calculate the XP for that party level using my function
  dplyr::mutate(calc_xp = dndR::xp_pool(party_level = pc_level,
                                        party_size = 1,
                                        difficulty = 'easy')) %>%
  # Rename a column more intuitively
  dplyr::rename(book_xp = easy_xp) %>%
  # Pivot longer for ease of plotting
  tidyr::pivot_longer(cols = -pc_level, 
                      names_to = 'calc_method',
                      values_to = 'xp') %>%
  # Change the entries of the calc_method column
  dplyr::mutate(authority = base::ifelse(test = (calc_method == "book_xp"),
                             yes = "DMG", no = "dndR"))

# Create the plot
ggplot2::ggplot(xp_df, aes(x = pc_level, y = xp, shape = authority))  +
  geom_point(aes(fill = authority), color = 'black', size = 3, alpha = 0.8,
             pch = rep(x = c(21, 24), times = 20),
             position = position_dodge(width = 0.5)) +
  geom_smooth(aes(color = authority), method = 'loess',
              formula = 'y ~ x', se = FALSE) +
  labs(x = "Party Level", y = "Experience Points (XP)") +
  scale_color_manual(values = c("#f46d43", "#74add1")) +
  scale_fill_manual(values = c("#f46d43", "#74add1")) +
  theme_classic() +
  theme(legend.position = c(0.15, 0.9),
        legend.title = element_blank(),
        axis.text.y = element_text(angle = 90, hjust = 0.5),
        axis.text = element_text(size = 14),
        axis.title = element_text(size = 16))
```
