Hello everyone !
I created a WebApp to generate NPC for a TTRPG (you can look it up here)
Works great and all but I wanted to make it so that users would be able to select how many NPC they want to create at once and the app would generate them all (possibly in several tabs to make it clearer and more aesthetically pleasing).
Thing is... I'm a complete noob. The fact that the app is already working right now is short of a miracle but I'm honestly stuck on this part. I've tried making lists and lists of lists and dataframe but I'm either getting various type of errors, text with no formatting at all or ... just nothing. Like no error, but nothing is rendered.
If any of you with way more knowledge and skills wouldn't mind taking a look and help, that would be awesome !
I'm putting up my code here for you to look at, but since it relies on several data files containing all the description and stuff, if you want to run it, I can send you the whole folder.
Thank in advance people
library(shiny)
library(shinyjs)
library(tidyverse)
library(shinythemes)
# Mise en place -----------------------------------------------------------
list_names <- read.csv2("list_names.csv",
fileEncoding = "Windows-1252",
check.names=F)
list_techniques<- read.csv2("list_techniques.csv",
fileEncoding = "Windows-1252",
check.names=F)
list_principles_drives <- read.csv2("list_principles_drives.csv",
fileEncoding="Windows-1252",
check.names=F)
list_caracteristics <- read.csv2("list_caracteristics.csv",
fileEncoding="Windows-1252",
check.names=F)
list_hair <- read.csv2("list_hair.csv",
fileEncoding="Windows-1252",
check.names=F)
# Define UI for application ----
ui <- fluidPage(theme=shinytheme("journal"),
# Application title
titlePanel("Avatar Legends - NPC Generator (V2.2) "),
# Topbar with selections
fluidRow(shinyjs::useShinyjs(),
id = "side-panel",
column(2,radioButtons("choice_type","NPC Types", c("Minor NPC",
"Major NPC",
"Master NPC",
"Group")),
sliderInput("num_npc","Number of NPC",value=1,min = 1, max = 15),
offset=1),
column(2,radioButtons("choice_gender", "Gender", c("He/Him",
"She/Her",
"They/Them",
"Random"))),
column(2,selectInput("choice_nation", "Nation", c("Air Nomads",
"Earth Kingdom",
"Fire Nation",
"Republic City",
"Water Tribe",
"Random"))),
column(2,selectInput("choice_training", "Training", c("Airbending",
"Earthbending",
"Firebending",
"Martial Art",
"Technology",
"Universal",
"Waterbending",
"Group",
"No Training",
"Random"))),
column(2, sliderInput("num_tech","Number of techniques",value=1,
min = 1, max = 5),
selectInput("special_tech","Specialized Bending", c("---",
"Bloodbending",
"Combustionbending",
"Healing",
"Lavabending",
"Lightningbending",
"Metalbending",
"Seismic Sense")),
selectInput("rare_tech","Rare Techniques",c("No", "Yes"))),
fluidRow(column(2,actionButton("generate","Generate"),
offset= 4),
column(2,actionButton("generate_random","Randomize")),
column(2,actionButton("reset_input", "Reset")))),
mainPanel(fluidRow(htmlOutput("NPC")),
fluidRow(htmlOutput("tech")),
fluidRow(htmlOutput("NPC_random")),
fluidRow(htmlOutput("tech_random")),
offset=5
)
)
# Define server logic ----
server <- function(input, output) {
NPC <- eventReactive(input$generate,{
type <- input$choice_type
fatigue <- case_when(type=="Minor NPC" ~ sample(2:6, 1),
type=="Major NPC"~ sample(5:9, 1),
type=="Master NPC"~ sample(8:13, 1),
type=="Group" ~ sample (2:13, 1))
principle <- list_principles_drives %>%
select(Principles) %>%
sample_n(1) %>%
pull(Principles)
drive <- list_principles_drives %>%
select(Drives) %>%
sample_n(1) %>%
pull(Drives)
number_tech <- input$num_tech
if(type!="Group"){
gender <- case_when(input$choice_gender == "He/Him" ~ "He/Him",
input$choice_gender == "She/Her" ~ "She/Her",
input$choice_gender == "They/Them" ~ "They/Them",
input$choice_gender == "Random" ~ sample(c("He/Him",
"She/Her",
"They/Them"),1))
nation <- case_when(input$choice_nation == "Air Nomads" ~ "Air Nomads" ,
input$choice_nation == "Earth Kingdom" ~ "Earth Kingdom",
input$choice_nation == "Fire Nation" ~ "Fire Nation",
input$choice_nation == "Republic City" ~ "Republic City",
input$choice_nation == "Water Tribe" ~ "Water Tribe",
input$choice_nation == "Random" ~ sample(c("Air Nomads",
"Earth Kingdom",
"Fire Nation",
"Republic City",
"Water Tribe"),1))
name <- list_names %>%
filter(Gender==gender) %>%
sample_n(1) %>%
pull(nation)
age<- sample(c(10:80),1)
background <- sample(c("Military","Monastic", "Outlaw",
"Privileged","Urban","Wilderness"), 2)
size <- c(round(runif(n=1, min=1.2, max=2),2), "m, ")
weight<-c(sample(50:130, 1), "kg,")
hair <- list_hair %>%
select(Hair) %>%
sample_n(1)
facial_hair <- if(gender=="She/Her"){
c(" ")
}
else{
if(age > 17){list_hair %>%
select(Facial_Hair) %>%
sample_n(1)
}}
demeanor1<-list_caracteristics[1:100,] %>%
select(Demeanor) %>%
slice_sample(n=1)
demeanor2<-list_caracteristics[101:200,] %>%
select(Demeanor) %>%
slice_sample(n=1)
physical_quirk <- list_caracteristics %>%
select(Physical_quirk) %>%
sample_n(1)
behavior_quirk <-list_caracteristics %>%
select(Behavior_quirk) %>%
sample_n(1)
accessories <- list_caracteristics %>%
select(Accessories) %>%
sample_n(1)
paste("<h2>",name," - ", nation,"</h2>",
"<h4>",type,"</h4>",
"<p><b>Gender :</b>", gender,
"<br><b>Age :</b>", age,
"<p> <b>Principle :</b>", principle,
"<br> <b>Drive :</b>", drive,
"<br> <b>Conditions :</b>", "<br>Afraid",
"<br>Angry",
"<br>Guilty",
"<br>Insecure",
"<br>Troubled",
"<p> <b>Background :</b>", background[1],"/",background[2],
"<br><b>Demeanor :</b>", demeanor1,"/", demeanor2,
"<p><b>Hair :</b>", hair, facial_hair,
"<br><b>Physique :</b>", size[1],size[2],weight[1],weight[2],physical_quirk,
"<br><b>Quirk :</b>",behavior_quirk,
"<br><b>Accessory :</b>",accessories,
"<p> <b>Fatigue :</b>", fatigue,
"<h3>Technique(s)</h3>")}
else{
paste("<h3>",type,"</h3>",
"<p> <b>Principle :</b>", principle,
"<br> <b>Drive :</b>", drive,
"<br> <b>Conditions :</b>", "<br>Afraid",
"<br>Angry",
"<br>Guilty",
"<br>Insecure",
"<br>Troubled",
"<p> <b>Fatigue :</b>", fatigue,
"<h3>Technique(s)</h3>")
}
})
output$NPC <- renderText({
NPC()
})
tech<-eventReactive(input$generate,{
training_choice <- case_when(input$choice_training == "Airbending" ~ "Airbending" ,
input$choice_training == "Earthbending" ~ "Earthbending",
input$choice_training == "Firebending" ~ "Firebending",
input$choice_training == "Martial Art" ~ "Martial Art",
input$choice_training == "Waterbending" ~ "Waterbending",
input$choice_training == "Technology" ~ "Technology",
input$choice_training == "Universal" ~ "Universal",
input$choice_training == "No Training" ~ "No Training",
input$choice_training == "Group" ~ "Group",
input$choice_training == "Random" ~ sample(c("Airbending",
"Earthbending",
"Firebending",
"Martial Art",
"Technology",
"Universal",
"Waterbending",
"No Training"),1))
if(input$rare_tech == "No"){
techniques <- list_techniques %>%
filter(Training %in% training_choice,
Specialized==input$special_tech | Specialized=="---",
Rare!="Yes") %>%
slice_sample(n=input$num_tech) %>%
pull(Technique)
paste(techniques)
}
else{
techniques <- list_techniques %>%
filter(Training %in% training_choice,
Specialized==input$special_tech | Specialized=="---") %>%
slice_sample(n=input$num_tech) %>%
pull(Technique)
paste(techniques)}
})
output$tech <- renderText({
tech()
})
NPC_random <- eventReactive(input$generate_random,{
type <- input$choice_type
gender <- sample(c("He/Him","She/Her","They/Them"),1)
nation <- sample(c("Air Nomads",
"Earth Kingdom",
"Fire Nation",
"Republic City",
"Water Tribe"),1)
number_tech <- input$num_tech
name <- list_names %>%
filter(Gender==gender) %>%
sample_n(1) %>%
pull(nation)
age<- sample(c(10:80),1)
fatigue <- case_when(type=="Minor NPC" ~ sample(2:6, 1),
type=="Major NPC"~ sample(5:9, 1),
type=="Master NPC"~ sample(8:13, 1))
principle <- list_principles_drives %>%
select(Principles) %>%
sample_n(1) %>%
pull(Principles)
drive <- list_principles_drives %>%
select(Drives) %>%
sample_n(1) %>%
pull(Drives)
background <- sample(c("Military","Monastic", "Outlaw",
"Privileged","Urban","Wilderness"), 2)
size <- c(round(runif(n=1, min=1.2, max=2),2), "m")
weight<-c(sample(50:130, 1), "kg")
hair <- list_hair %>%
select(Hair) %>%
sample_n(1)
facial_hair <- if(gender=="She/Her"){
c(" ")
}
else{
list_hair %>%
select(Facial_Hair) %>%
sample_n(1)
}
demeanor1<-list_caracteristics[1:100,] %>%
select(Demeanor) %>%
slice_sample(n=1)
demeanor2<-list_caracteristics[101:200,] %>%
select(Demeanor) %>%
slice_sample(n=1)
physical_quirk <- list_caracteristics %>%
select(Physical_quirk) %>%
sample_n(1)
behavior_quirk <- list_caracteristics %>%
select(Behavior_quirk) %>%
sample_n(1)
accessories <- list_caracteristics %>%
select(Accessories) %>%
sample_n(1)
paste(paste("<h2>",name," - ", nation,"</h2>",
"<h4>",type,"</h4>",
"<p><b>Gender :</b>", gender,
"<br><b>Age :</b>", age,
"<p> <b>Principle :</b>", principle,
"<br> <b>Drive :</b>", drive,
"<br> <b>Conditions :</b>", "<br>Afraid",
"<br>Angry",
"<br>Guilty",
"<br>Insecure",
"<br>Troubled",
"<p> <b>Background :</b>", background[1],"/",background[2],
"<br><b>Demeanor :</b>", demeanor1,"/",demeanor2,
"<p><b>Hair :</b>", hair, facial_hair,
"<br><b>Physique :</b>", size[1],size[2],weight[1],weight[2],physical_quirk,
"<br><b>Quirk :</b>",behavior_quirk,
"<br><b>Accessory :</b>",accessories,
"<p> <b>Fatigue :</b>", fatigue,
"<h3>Technique(s)</h3>"))
})
output$NPC_random <- renderText({
NPC_random()
})
tech_random<-eventReactive(input$generate_random,{
training_choice <- sample(c("Airbending",
"Earthbending",
"Firebending",
"Martial Art",
"Technology",
"Universal",
"Waterbending",
"No Training"),1)
number <- input$num_tech
if(input$rare_tech == "No"){
techniques_random <- list_techniques %>%
filter(Training %in% training_choice,
Specialized==input$special_tech | Specialized=="---",
Rare!="Yes") %>%
slice_sample(n=input$num_tech, replace=TRUE) %>%
pull(Technique)
paste(techniques_random)
}
else{
techniques_random <- list_techniques %>%
filter(Training %in% training_choice,
Specialized==input$special_tech | Specialized=="---") %>%
slice_sample(n=input$num_tech, replace=TRUE) %>%
pull(Technique)
paste(techniques_random)}
})
output$tech_random <- renderText({
tech_random()
})
observeEvent(input$reset_input, {
shinyjs::reset("side-panel")
shinyjs::hide("NPC")
shinyjs::hide("tech")
shinyjs::hide("NPC_random")
shinyjs::hide("tech_random")
})
observeEvent(input$generate, {
shinyjs::show("NPC")
shinyjs::show("tech")
shinyjs::hide("NPC_random")
shinyjs::hide("tech_random")
})
observeEvent(input$generate_random, {
shinyjs::show("NPC_random")
shinyjs::show("tech_random")
shinyjs::hide("NPC")
shinyjs::hide("tech")
})
}
# Run the application ----
shinyApp(ui = ui, server = server)