knitr::opts_chunk$set(collapse = TRUE, comment = "#>")
# devtools::install_github("njlyon0/dndR", force = TRUE) library(dndR); library(ggplot2); library(magrittr); library(dplyr); library(tidyr)
dndR
versus DMG ComparisonsSee below for some comparisons between my functions and the Dungeon Master's Guide statistics they attempt to recapitulate.
cr_convert
vs. DMGcr_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
.
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. DMGThe 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. Rather than embedding the DMG's table for encounter XP, xp_pool
actually uses the formula for the line defining the XP-party level curve implicit in the DMG. This has the added benefit of being able to handle non-integer values for average party_level.
Below is a comparison of the DMG's XP-to-party level curve versus the one obtained by xp_pool
.
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))
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.