├── .gitignore
├── README.md
├── screenshots
├── card-bad.png
├── card-choice.gif
├── card-good.png
├── card-special.png
├── current-task.png
├── gameover.png
├── karma.png
├── map-high.png
├── map-low.png
├── metrics.png
├── restartingtutorial.gif
├── shiny-decisions-large.png
└── startscreen.png
├── shiny.decisions.Rproj
└── src
├── app.R
└── app
├── data
└── options.xlsx
├── global.R
├── google-analytics.html
├── logic
├── dataManager.R
├── deckManager.R
├── gameManager.R
├── mapManager.R
├── metricsManager.R
└── stateManager.R
├── server.R
├── styles
├── main.scss
├── modules
│ ├── _animations.scss
│ ├── _config.scss
│ └── _static.scss
└── partials
│ ├── _cards.scss
│ ├── _layout.scss
│ ├── _map.scss
│ ├── _metrics.scss
│ └── _modals.scss
├── ui.R
└── www
├── assets
├── cards
│ ├── beekeeper-1.png
│ ├── blacksmith-1.png
│ ├── blank.png
│ ├── boy-1.png
│ ├── boy-2.png
│ ├── boy-3.png
│ ├── boy-4.png
│ ├── boy-5.png
│ ├── boy-6.png
│ ├── boy-7.png
│ ├── chef-1.png
│ ├── doctor-1.png
│ ├── farmer-1.png
│ ├── girl-1.png
│ ├── girl-2.png
│ ├── girl-3.png
│ ├── girl-4.png
│ ├── hunter-1.png
│ ├── man-1.png
│ ├── man-10.png
│ ├── man-11.png
│ ├── man-12.png
│ ├── man-13.png
│ ├── man-14.png
│ ├── man-15.png
│ ├── man-16.png
│ ├── man-17.png
│ ├── man-18.png
│ ├── man-19.png
│ ├── man-2.png
│ ├── man-20.png
│ ├── man-21.png
│ ├── man-22.png
│ ├── man-23.png
│ ├── man-24.png
│ ├── man-25.png
│ ├── man-26.png
│ ├── man-27.png
│ ├── man-28.png
│ ├── man-29.png
│ ├── man-3.png
│ ├── man-30.png
│ ├── man-31.png
│ ├── man-32.png
│ ├── man-33.png
│ ├── man-34.png
│ ├── man-35.png
│ ├── man-36.png
│ ├── man-37.png
│ ├── man-4.png
│ ├── man-5.png
│ ├── man-6.png
│ ├── man-7.png
│ ├── man-8.png
│ ├── man-9.png
│ ├── nun-1.png
│ ├── pirate-1.png
│ ├── pirate-2.png
│ ├── sailor-1.png
│ ├── santa-1.png
│ ├── scientist-1.png
│ ├── shady-1.png
│ ├── shady-2.png
│ ├── shady-3.png
│ ├── woman-1.png
│ ├── woman-10.png
│ ├── woman-11.png
│ ├── woman-12.png
│ ├── woman-13.png
│ ├── woman-14.png
│ ├── woman-16.png
│ ├── woman-17.png
│ ├── woman-18.png
│ ├── woman-19.png
│ ├── woman-2.png
│ ├── woman-20.png
│ ├── woman-21.png
│ ├── woman-22.png
│ ├── woman-23.png
│ ├── woman-24.png
│ ├── woman-25.png
│ ├── woman-26.png
│ ├── woman-6.png
│ ├── woman-7.png
│ ├── woman-8.png
│ └── woman-9.png
├── map
│ ├── cold.png
│ ├── fire.png
│ ├── house.png
│ ├── house_broken.png
│ ├── mad.png
│ ├── mask.png
│ ├── office.png
│ ├── sick.png
│ ├── smile.png
│ ├── stareyes.png
│ ├── thunder.png
│ ├── tornado.png
│ ├── tree.png
│ ├── tree_large.png
│ └── tree_small.png
└── ui
│ ├── author.png
│ ├── icons
│ ├── evil.png
│ ├── friend.png
│ ├── gold.png
│ ├── halo.png
│ └── salad.png
│ └── pause.png
├── scripts
├── analytics-events.js
├── card_stack.js
├── filter-toggler.js
├── hammer.min.js
└── update_map_style.js
└── styles
└── sass.min.css
/.gitignore:
--------------------------------------------------------------------------------
1 | .Rproj.user
2 | .Rhistory
3 | .RData
4 | .Ruserdata
5 | .httr-oauth
6 | rsconnect
7 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # shiny.decisions
2 | A game about making the best of terrible choices
3 |
4 | In shiny decisions your goal is to last as long as possible while making decisions that affect the wealth, population and environment quality in the world.
5 |
6 | If any of those metrics reaches zero, its game over! How long can you last?
7 |
8 | Live version: https://sparktuga.shinyapps.io/ShinyDecisions/
9 |
10 | 
11 |
12 | ---
13 |
14 | # Installation
15 | Some of the packages included in this project are currently only available on github. This includes `shiny.grid` and `shiny.blank`. To install them locally remember to run on your machine the following commands:
16 |
17 | ```
18 | library(devtools)
19 | install.packages(devtools)
20 | devtools::install_github('pedrocoutinhosilva/shiny.grid')
21 | devtools::install_github('pedrocoutinhosilva/shiny.blank')
22 | ```
23 |
24 | ---
25 |
26 | # Starting a game
27 | From the start game screen you will be able to start a new in any difficulty (Easy, medium or hard).
28 | 
29 |
30 | You can also toggle the tutorial on and of if you already know the basics of the game.
31 | 
32 |
33 | ---
34 |
35 | # During the game
36 | The game UI has 3 main areas:
37 |
38 | #### Metrics
39 | Displays the current value of the different metrics you need to manage. Those metrics include:
40 | - **Karma:** Being too bad or too good wont lose you the game, but might have some hidden effects...
41 | - **Wealth:** Things cost money. No money no fun :/
42 | - **Public opinion:** If no one likes you, you probably wont last long in power!
43 | - **Environment:** If the world is beyond saving, whats the point?
44 |
45 | The game metrics:
46 | 
47 |
48 | The karma meter:
49 | 
50 |
51 | #### Map
52 | A visual representation of what effects your actions are having in the world. Icons and the map color with change depending on how high or low some metrics are.
53 |
54 | Low metrics:
55 | 
56 |
57 | High metrics:
58 | 
59 |
60 |
61 | #### current task
62 | Your next task and the way you can move forward in the game. Above the task you can also see the current week in game. Every task you complete will move the game forward 1 week.
63 | 
64 |
65 | Card colors reflect the card pool and severity of the current card. The darker the card the more severe the task is, and more change it will have on the metrics. Currently 3 cards pools are implemented:
66 |
67 | Bad cards (Cards that will have mostly negative consequences, red background):
68 | 
69 |
70 | Good cards (Cards that will have mostly good consequences, green background):
71 | 
72 |
73 | Special cards (Cards that will have unique consequences, purple background):
74 | 
75 |
76 | If you want to know more about all the possible cards and options available, you can check the google spreadsheet containing all possibilities at:
77 | https://docs.google.com/spreadsheets/d/1LwIPKAxbKvuGyMKktcTVuYZbTda0WMQxmNMhxqaQhGg
78 |
79 | #### Card stack
80 | Each task as 2 possible decisions, left or right. Simply drag and hold the card to each side to see what decisions you can take. while holding the card the names of the metrics that will be affected by that decision will also blink. Drag and release to commit to your decision.
81 | 
82 |
83 | #### Game end
84 | when one of the metrics reaches zero, the game is over and you will be taken to the end game screen. Here you can see how many weeks you lasted, as well as return to the initial screen in case you want to go again.
85 | 
86 |
87 | ---
88 |
89 | # Code Structure
90 | Shiny.decisions takes full advantage of modules and R6 classes for managing the code complexity.
91 | Most of the project is broken down into R6 managers that take care of specific parts of the workflow:
92 |
93 | ### Game Manager
94 | The brain being the game flow. It manages all game dependencies and is responsible for high level actions that drive the state of the game.
95 |
96 | ### Data Manager
97 | Connects and exposes all external data required by the app. This includes the main data storage regarding task cards, game options and game modes loaded from a google spreadsheet.
98 |
99 | Most options and cards can be added or tweaked without code changes directly on the spreadsheets.
100 |
101 | The current live spreadsheet can be found at:
102 | https://docs.google.com/spreadsheets/d/1LwIPKAxbKvuGyMKktcTVuYZbTda0WMQxmNMhxqaQhGg
103 |
104 | ### State Manager
105 | Stores information regarding the current state of the game. This includes the current value of the different metrics, map markers and state checks for specific game phases.
106 |
107 | ### Metrics Manager
108 | Responsible for displaying the current state metrics on the UI.
109 |
110 | ### Map Manager
111 | Responsible for displaying map information according to the the current state metrics on the UI.
112 |
113 | ### Deck Manager
114 | Responsible for creating cards according to the game state and switching between card pools depending on the current game phase.
115 |
116 | ---
117 |
118 | # Future improvements
119 | A lot of ideas are still floating around on how to improve this application:
120 |
121 | - Leader board;
122 | - More cards!;
123 | - Special game modes with different decks and objectives;
124 | - Map interactions;
125 | - Power up modifiers;
126 |
127 | Got any more ideas, questions or feedback? Feel free to get in touch!
128 | - Twitter: https://twitter.com/sparktuga
129 | - linkedin: https://www.linkedin.com/in/pedrocoutinhosilva
130 |
131 | ---
132 |
133 | # Links
134 | #### Useful references
135 | - Modules: https://shiny.rstudio.com/articles/modules.html
136 | - R6 classes: https://adv-r.hadley.nz/r6.html
137 | - SASS: https://github.com/rstudio/sass
138 |
139 | #### Assets
140 | - Images: https://opengameart.org/
141 | - NES.css framework: https://nostalgic-css.github.io/NES.css/
142 |
143 | #### Dependencies
144 | - Shiny.grid: https://github.com/pedrocoutinhosilva/shiny.grid
145 | - Shiny.blank: https://github.com/pedrocoutinhosilva/shiny.blank
146 | - Hammer.js: https://hammerjs.github.io/
147 | - Swipe cards: https://github.com/simonepm/likecarousel
148 | - Leaflet for R: https://rstudio.github.io/leaflet/
149 |
150 | #### Data
151 | - Google spreadsheet database: https://docs.google.com/spreadsheets/d/1LwIPKAxbKvuGyMKktcTVuYZbTda0WMQxmNMhxqaQhGg
152 | - World cities dataset: https://simplemaps.com/data/world-cities
153 | - World capitals dataset: https://www.kaggle.com/nikitagrec/world-capitals-gps
154 |
--------------------------------------------------------------------------------
/screenshots/card-bad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/card-bad.png
--------------------------------------------------------------------------------
/screenshots/card-choice.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/card-choice.gif
--------------------------------------------------------------------------------
/screenshots/card-good.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/card-good.png
--------------------------------------------------------------------------------
/screenshots/card-special.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/card-special.png
--------------------------------------------------------------------------------
/screenshots/current-task.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/current-task.png
--------------------------------------------------------------------------------
/screenshots/gameover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/gameover.png
--------------------------------------------------------------------------------
/screenshots/karma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/karma.png
--------------------------------------------------------------------------------
/screenshots/map-high.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/map-high.png
--------------------------------------------------------------------------------
/screenshots/map-low.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/map-low.png
--------------------------------------------------------------------------------
/screenshots/metrics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/metrics.png
--------------------------------------------------------------------------------
/screenshots/restartingtutorial.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/restartingtutorial.gif
--------------------------------------------------------------------------------
/screenshots/shiny-decisions-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/shiny-decisions-large.png
--------------------------------------------------------------------------------
/screenshots/startscreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/screenshots/startscreen.png
--------------------------------------------------------------------------------
/shiny.decisions.Rproj:
--------------------------------------------------------------------------------
1 | Version: 1.0
2 |
3 | RestoreWorkspace: Default
4 | SaveWorkspace: Default
5 | AlwaysSaveHistory: Default
6 |
7 | EnableCodeIndexing: Yes
8 | UseSpacesForTab: Yes
9 | NumSpacesForTab: 2
10 | Encoding: UTF-8
11 |
12 | RnwWeave: Sweave
13 | LaTeX: pdfLaTeX
14 |
--------------------------------------------------------------------------------
/src/app.R:
--------------------------------------------------------------------------------
1 | library(shiny)
2 |
3 | shinyAppDir("app")
4 |
--------------------------------------------------------------------------------
/src/app/data/options.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/data/options.xlsx
--------------------------------------------------------------------------------
/src/app/global.R:
--------------------------------------------------------------------------------
1 | library(shiny)
2 | library(shiny.grid)
3 | library(shiny.blank)
4 | library(htmltools)
5 | library(tidyr)
6 | library(leaflet)
7 | library(R6)
8 | library(googlesheets)
9 | library(glue)
10 | library(utils)
11 | library(dplyr)
12 | library(jsonlite)
13 | library(modules)
14 | library(sass)
15 | library(readxl)
16 |
17 | # Remember to install github packages if you dont have them already.
18 | # install.packages('devtools')
19 | # library(devtools)
20 | # devtools::install_github('pedrocoutinhosilva/shiny.grid')
21 | # devtools::install_github('pedrocoutinhosilva/shiny.blank')
22 |
23 | # Process and minify styles
24 | sass(
25 | sass::sass_file("styles/main.scss"),
26 | options = sass_options(output_style = "compressed"),
27 | output = "www/styles/sass.min.css"
28 | )
29 |
30 | # Generic gameManager to initialize ui elements
31 | gameManager <- use("logic/gameManager.R")$gameManager$new()
32 |
--------------------------------------------------------------------------------
/src/app/google-analytics.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/src/app/logic/dataManager.R:
--------------------------------------------------------------------------------
1 | import("R6")
2 | import("googlesheets")
3 | import("tidyr")
4 | import("glue")
5 |
6 | export("DataManager")
7 |
8 | # Deals with external data
9 | DataManager <- R6Class("DataManager",
10 | private = list(
11 | data = NULL,
12 | cities = NULL,
13 | options = NULL,
14 | settings = NULL,
15 |
16 | cards = list(),
17 | decks = list(),
18 |
19 | cardTypes = c("Tutorial", "Bad", "Good", "Special", "Death")
20 | ),
21 |
22 | public = list(
23 | initialize = function(sheetId, force_update = FALSE) {
24 | if (force_update) {
25 | print("Updating from online data")
26 |
27 | sheet_metadata <- googlesheets::gs_url(
28 | glue::glue("https://docs.google.com/spreadsheets/d/{sheetId}"),
29 | visibility = "public",
30 | lookup = FALSE
31 | )
32 | gs_download(sheet_metadata, to = "data/options.xlsx", overwrite = TRUE)
33 | }
34 |
35 | private$settings <- readxl::read_xlsx("data/options.xlsx", "Game Settings")
36 | private$decks <- readxl::read_xlsx("data/options.xlsx", "Decks")
37 | private$options <- readxl::read_xlsx("data/options.xlsx", "Options")
38 | private$cities <- readxl::read_xlsx("data/options.xlsx", "Map Cities")
39 |
40 | lapply(private$cardTypes, function(type) {
41 | private$cards[[type]] <- readxl::read_xlsx("data/options.xlsx", sheet = type)
42 | })
43 | },
44 |
45 | getCities = function() {
46 | return(private$cities)
47 | },
48 |
49 | getSettings = function(gameType) {
50 | return(private$settings[which(private$settings$`Game Type` == gameType), ])
51 | },
52 |
53 | getOptions = function(attribute) {
54 | return(drop_na(private$options[attribute]))
55 | },
56 |
57 | getDeckOptions = function(name) {
58 | decks <- private$decks
59 | return(decks[which(decks$`Deck Name` == name), ])
60 | },
61 |
62 | getCards = function() {
63 | return(private$cards)
64 | }
65 | )
66 | )
67 |
--------------------------------------------------------------------------------
/src/app/logic/deckManager.R:
--------------------------------------------------------------------------------
1 | import("R6")
2 | import("utils")
3 | import("jsonlite")
4 | import("glue")
5 | import("dplyr")
6 | import("utils")
7 | import("htmltools")
8 |
9 | export("deckManager")
10 |
11 | cleanCardMessage <- function(string) {
12 | stringr::str_replace_all(
13 | string,
14 | c("\\{" = "{`", "\\}" = "`}")
15 | )
16 | }
17 |
18 | ui <- function(inputId = "card_stack") {
19 | tagList(
20 | div(
21 | id = glue::glue("{inputId}_wrapper"),
22 | div(id = inputId)
23 | ),
24 | tags$script(src = "scripts/hammer.min.js"),
25 | tags$script(src = "scripts/card_stack.js")
26 | )
27 | }
28 |
29 | deckManager <- R6Class("deckManager",
30 | private = list(
31 | gameSettings = NULL,
32 | dataManager = NULL,
33 | stateManager = NULL,
34 |
35 | gameFlow = NULL,
36 | currentDeck = NULL,
37 |
38 | getCardType = function(pool, prob, saving_grace) {
39 |
40 | # Get random card type
41 | cardType <- sample(
42 | pool,
43 | size = 1,
44 | prob = prob,
45 | replace = TRUE
46 | )
47 |
48 | if (!(cardType %in% c("Tutorial", "Death"))) {
49 | # roll aditional checks based on karma
50 | # If karma is low, double roll for bad cards based on how low
51 | if (saving_grace < 50 && cardType != "Bad") {
52 | save_roll <- sample( c(1:1000), size = 1)
53 | # if the save roll fails, card type is automatically set to bad
54 | if (save_roll < 100 - saving_grace) {
55 | cardType <- "Bad"
56 | }
57 | }
58 | # If karma is high, double roll for good kards based on how high
59 | if (saving_grace > 50 && cardType == "Bad") {
60 | grace_roll <- sample( c(1:1000), size = 1)
61 | # if the grace roll passes, card type is automatically set to good
62 | if (grace_roll < saving_grace) {
63 | cardType <- "Good"
64 | }
65 | }
66 | }
67 |
68 | return(cardType)
69 | },
70 |
71 | generateTemplateCard = function() {
72 | deckOptions <- private$gameFlow[[private$currentDeck]]
73 |
74 | cardType <- private$getCardType(
75 | strsplit(deckOptions$`Card Pool`, ", ")[[1]],
76 | strsplit(deckOptions$`Pool Weight`, ", ")[[1]],
77 | private$stateManager$state$karma
78 | )
79 |
80 | if (private$gameFlow[[private$currentDeck]]$`Order Fixed`) {
81 | deckLimit <- nrow(private$dataManager$getCards()[[cardType]])
82 | deckSize <- as.numeric(private$gameFlow[[private$currentDeck]]$`Deck Size`)
83 | currentCardRow <- deckLimit - deckSize
84 | cardTemplate <- private$dataManager$getCards()[[cardType]][currentCardRow, ]
85 | } else {
86 | cardTemplate <- sample_n(private$dataManager$getCards()[[cardType]], 1)
87 | }
88 |
89 | state_min_intensity <- max(deckOptions$`Min Intensity`, cardTemplate$`Min Intensity`)
90 | state_max_intensity <- min(deckOptions$`Max Intensity`, cardTemplate$`Max Intensity`)
91 |
92 | if(state_min_intensity == state_max_intensity)
93 | state_max_intensity <- state_max_intensity + 1
94 |
95 | # Get random intensity level
96 | intensity_level <- sample(
97 | c(state_min_intensity:state_max_intensity),
98 | size = 1,
99 | prob = c(state_max_intensity:state_min_intensity),
100 | replace = TRUE
101 | )
102 | intensityMultiplier <- 1 + ((intensity_level - 1) / 20)
103 |
104 | # Generate random options
105 | options <- vector("list", length(names(private$dataManager$getOptions())))
106 | names(options) <- names(private$dataManager$getOptions())
107 | for ( option in names(options)){
108 | options[option] <- sample_n(private$dataManager$getOptions(option), 1)
109 | }
110 |
111 | options <- modifyList(options, list(
112 | `Danger Level` = private$dataManager$getOptions("Danger Level")[intensity_level, ],
113 | `Prosperity Level` = private$dataManager$getOptions("Prosperity Level")[intensity_level, ]
114 | ))
115 |
116 | color_scale <- private$dataManager$getOptions(
117 | as.character(glue::glue("{cardType} Color Scale"))
118 | )
119 |
120 | background_colors <- list(
121 | left = as.character(color_scale[((intensity_level * 2) - 1), ]),
122 | right = as.character(color_scale[(intensity_level * 2), ])
123 | )
124 |
125 | background_image <- ifelse (
126 | cardTemplate$`Image` == "random",
127 | paste0(sample(list.files('www/assets/cards'), 1)),
128 | glue::glue("{cardTemplate$`Image`}.png")
129 | )
130 |
131 | # Fills in any potential glue string options
132 | options <- as.list(sapply(names(options), function(option) {
133 | do.call(glue::glue, modifyList(list(cleanCardMessage(options[[option]])), options))
134 | }, USE.NAMES = TRUE))
135 |
136 | left_values = list(
137 | message = do.call(
138 | glue::glue,
139 | modifyList(list(cleanCardMessage(cardTemplate$`Left Message`)), options)
140 | ),
141 | delta = list(
142 | karma = cardTemplate$`Left Karma` * intensityMultiplier,
143 | wealth = cardTemplate$`Left Wealth` * intensityMultiplier,
144 | opinion = cardTemplate$`Left Opinion` * intensityMultiplier,
145 | environment = cardTemplate$`Left Environment` * intensityMultiplier
146 | )
147 | )
148 | right_values = list(
149 | message = do.call(
150 | glue::glue,
151 | modifyList(list(cleanCardMessage(cardTemplate$`Right Message`)), options)
152 | ),
153 | delta = list(
154 | karma = cardTemplate$`Right Karma` * intensityMultiplier,
155 | wealth = cardTemplate$`Right Wealth` * intensityMultiplier,
156 | opinion = cardTemplate$`Right Opinion` * intensityMultiplier,
157 | environment = cardTemplate$`Right Environment` * intensityMultiplier
158 | )
159 | )
160 |
161 | # To spice things up, randomly switches left and right values half of the time
162 | if (!(cardType %in% c("Tutorial", "Death"))) {
163 | if(sample( c(TRUE, FALSE), size = 1)) {
164 | temp <- left_values
165 | left_values <- right_values
166 | right_values <- temp
167 | }
168 | }
169 |
170 | card <- list(
171 | background = list(
172 | image = glue::glue("assets/cards/{background_image}"),
173 | color_left = background_colors$left,
174 | color_right = background_colors$right
175 | ),
176 | message = list (
177 | task = do.call(
178 | glue::glue,
179 | modifyList(list(cleanCardMessage(cardTemplate$`Template`)), options)
180 | ),
181 | left = left_values$message,
182 | right = right_values$message,
183 | week = switch(
184 | cardType,
185 | "Tutorial" = list(
186 | text = "Tutorial",
187 | increment = 0
188 | ),
189 | "Death" = list(
190 | text = "Afterlife",
191 | increment = 0
192 | ),
193 | list(
194 | text = paste0("Week ", private$stateManager$state$week),
195 | increment = 1
196 | )
197 | )
198 | ),
199 | delta = list(
200 | left = left_values$delta,
201 | right = right_values$delta
202 | )
203 | )
204 |
205 | return (card)
206 | }
207 | ),
208 |
209 | public = list(
210 | ui = ui,
211 | getCurrentDeck = function() { private$currentDeck },
212 |
213 | triggerDeathPhase = function() {
214 | private$currentDeck = "Death"
215 | },
216 |
217 | resetState = function(gameType = "Medium",
218 | skipTutorial = FALSE,
219 | dataManager,
220 | stateManager) {
221 | private$dataManager <- dataManager
222 | private$stateManager <- stateManager
223 |
224 | private$gameSettings <- private$dataManager$getSettings(gameType)
225 |
226 | private$gameFlow <- list()
227 | specialDecks <- strsplit(private$gameSettings$`Special Decks`, ", ")[[1]]
228 | gameTypeDecks <- strsplit(private$gameSettings$`Fixed Decks`, ", ")[[1]]
229 | gameDeckSizes <- strsplit(private$gameSettings$`Deck Sizes`, ", ")[[1]]
230 |
231 | lapply(gameTypeDecks, function(deckName) {
232 | options <- private$dataManager$getDeckOptions(deckName)
233 |
234 | deckIndex <- which(gameTypeDecks == deckName)[1]
235 | nextDeckIndex <- deckIndex + 1
236 | if(nextDeckIndex > length(gameTypeDecks)) nextDeckIndex <- length(gameTypeDecks)
237 | options$`Next Deck` <- gameTypeDecks[[nextDeckIndex]]
238 | options$`Deck Size` <- gameDeckSizes[[deckIndex]]
239 | private$gameFlow[[deckName]] <- options
240 | })
241 |
242 | lapply(specialDecks, function(deckName) {
243 | options <- private$dataManager$getDeckOptions(deckName)
244 |
245 | options$`Next Deck` <- deckName
246 | options$`Deck Size` <- nrow(private$dataManager$getCards()[[deckName]])
247 |
248 | private$gameFlow[[deckName]] <- options
249 | })
250 |
251 | if(!skipTutorial) {
252 | private$currentDeck <- "Tutorial"
253 | private$gameFlow[["Tutorial"]]$`Next Deck` <- gameTypeDecks[1]
254 | } else {
255 | private$currentDeck <- gameTypeDecks[1]
256 | }
257 | },
258 |
259 | popCard = function() {
260 | if(private$gameFlow[[private$currentDeck]]$`Deck Size` == 0) {
261 | if(private$currentDeck == "Death") return("GAMEOVER")
262 |
263 | private$currentDeck <- private$gameFlow[[private$currentDeck]]$`Next Deck`
264 | }
265 | newSize <- as.numeric(private$gameFlow[[private$currentDeck]]$`Deck Size`) - 1
266 | private$gameFlow[[private$currentDeck]]$`Deck Size` <- newSize
267 |
268 | return(private$generateTemplateCard())
269 | },
270 |
271 | initialize = function(dataManager, stateManager) {
272 | self$resetState(
273 | dataManager = dataManager,
274 | stateManager = stateManager
275 | )
276 | }
277 | )
278 | )
279 |
--------------------------------------------------------------------------------
/src/app/logic/gameManager.R:
--------------------------------------------------------------------------------
1 | import("R6")
2 | import("utils")
3 | import("jsonlite")
4 | import("glue")
5 | import("shiny")
6 | import("shiny.blank")
7 | import("shiny.grid")
8 |
9 | export("gameManager")
10 |
11 | stateManager <- use("logic/stateManager.R")$stateManager
12 | deckManager <- use("logic/deckManager.R")$deckManager
13 | mapManager <- use("logic/mapManager.R")$mapManager
14 | metricsManager <- use("logic/metricsManager.R")$metricsManager
15 |
16 | dataManager <- use("logic/dataManager.R")$DataManager
17 |
18 | ui_icon <- function(icon, link) {
19 | tags$a(
20 | href = link,
21 | target = "_blank",
22 | onclick = glue::glue("sendAnalyticsEvent({{category: 'social', action: '{icon}', label: '{icon}'}})"),
23 | tags$i(class = glue::glue("nes-icon is-large {icon}"))
24 | )
25 | }
26 |
27 | game_buttons <- function() {
28 | div(
29 | class = "navigation",
30 | lapply(
31 | list(
32 | list(id = "startGameEasy", text = "Easy Mode"),
33 | list(id = "startGameMedium", text = "Medium Mode"),
34 | list(id = "startGameHard", text = "Hard Mode")
35 | ),
36 | function(options) {
37 | button(
38 | options$id,
39 | options$text,
40 | actions = list(
41 | click = glue::glue("
42 | modal_gameOverScreen.classList.remove('open')
43 | modal_entryScreen.classList.remove('open');
44 | modal_attributionScreen.classList.remove('open');
45 | modal_projectDetailsScreen.classList.remove('open');
46 | ")
47 | )
48 | )
49 | }
50 | )
51 | )
52 | }
53 |
54 | # data related to game state
55 | ui <- function() {
56 | tagList(
57 | div(
58 | id = "pause-game",
59 | style = "background-image: url(assets/ui/pause.png)"
60 | ),
61 | tags$script(glue::glue(
62 | '$( document ).ready(function() {{
63 | $("#pause-game").on("click", function(e){{
64 | modal_entryScreen.classList.toggle("open");
65 | modal_attributionScreen.classList.toggle("open");
66 | modal_projectDetailsScreen.classList.toggle("open");
67 | }});
68 | }});'
69 | )),
70 | modal(
71 | "attributionScreen",
72 | content = gridPanel(
73 | class = "entry-screen nes-container is-dark",
74 |
75 | gridPanel(
76 | id = "author-details",
77 | areas = c(
78 | "title title title",
79 | "avatar name name ",
80 | "avatar links links"
81 | ),
82 | rows = "25px 25px 65px",
83 | columns = "115px 110px 110px",
84 |
85 | div(class = "title", "About the author"),
86 | div(class = "name", "Pedro Silva"),
87 | div(class = "avatar", style = "background-image: url(assets/ui/author.png)"),
88 | div(
89 | class = "links",
90 | ui_icon("twitter", "https://twitter.com/sparktuga"),
91 | ui_icon("linkedin", "https://www.linkedin.com/in/pedrocoutinhosilva/"),
92 | ui_icon("github", "https://github.com/pedrocoutinhosilva"),
93 | )
94 | )
95 | ),
96 | open = TRUE,
97 | softClose = FALSE,
98 | closeButton = FALSE
99 | ),
100 | modal(
101 | "projectDetailsScreen",
102 | content = gridPanel(
103 | class = "entry-screen nes-container is-dark",
104 |
105 | gridPanel(
106 | id = "project-details",
107 | areas = c(
108 | "title",
109 | "... ",
110 | "links"
111 | ),
112 | rows = "25px 25px 65px",
113 | columns = "165px",
114 |
115 | div(class = "title", "Repository"),
116 | div(
117 | class = "links",
118 | ui_icon("github", "https://github.com/pedrocoutinhosilva/shiny.decisions"),
119 | )
120 | )
121 | ),
122 | open = TRUE,
123 | softClose = FALSE,
124 | closeButton = FALSE
125 | ),
126 | modal(
127 | "entryScreen",
128 | content = gridPanel(
129 | class = "entry-screen nes-container is-dark",
130 | areas = c("intro", "options", "navigation"),
131 | rows = "1fr 100px 100px",
132 |
133 | div(
134 | class = "options",
135 | checkbox("showTutorial", "Show tutorial at start", value = TRUE, class = "is-dark")
136 | ),
137 | div(
138 | class = "intro",
139 | p("Welcome to shiny decisions! A game about making the best of bad situations"),
140 | p("Try your best to lead your world in good (and hard) times and see how long you can keep it up!")
141 | ),
142 | game_buttons()
143 | ),
144 | open = TRUE,
145 | softClose = FALSE,
146 | closeButton = FALSE
147 | ),
148 |
149 | modal(
150 | "gameOverScreen",
151 | content = gridPanel(
152 | rows = "1fr 100px",
153 | areas = c("intro", "navigation"),
154 | class = "entry-screen",
155 |
156 | div(
157 | class = "intro",
158 | p(class = "title", "Game over"),
159 | p("You survived for:"),
160 | p(id = "game_over_message", "Week"),
161 | p("Would you like to go again?")
162 | ),
163 | div(
164 | class = "navigation",
165 | button(
166 | "restartGame",
167 | "Back to start",
168 | actions = list(
169 | click = glue::glue("
170 | modal_gameOverScreen.classList.remove('open');
171 | modal_entryScreen.classList.add('open');
172 | modal_attributionScreen.classList.add('open');
173 | modal_projectDetailsScreen.classList.add('open');
174 | ")
175 | )
176 | )
177 | )
178 | ),
179 | open = FALSE,
180 | softClose = FALSE,
181 | closeButton = FALSE
182 | )
183 | )
184 | }
185 |
186 | gameManager <- R6Class("gameManager",
187 |
188 | private = list(
189 | stateManager = NULL,
190 | deckManager = NULL,
191 | mapManager = NULL,
192 | metricsManager = NULL,
193 | dataManager = NULL,
194 |
195 | session = NULL,
196 | gameType = "Medium",
197 |
198 | resetState = function() {
199 | if (is.null(private$dataManager)) {
200 | private$dataManager <- dataManager$new(
201 | "1LwIPKAxbKvuGyMKktcTVuYZbTda0WMQxmNMhxqaQhGg"
202 | )
203 | }
204 | private$stateManager <- stateManager$new()
205 | private$metricsManager <- metricsManager$new()
206 | private$mapManager <- mapManager$new(private$stateManager, private$dataManager)
207 | private$deckManager <- deckManager$new(private$dataManager, private$stateManager)
208 |
209 | self$ui = list(
210 | gameStages = ui,
211 | metrics = private$metricsManager$metrics_ui,
212 | karma = private$metricsManager$karma_ui,
213 | map = private$mapManager$ui,
214 | cardStack = private$deckManager$ui
215 | )
216 | },
217 |
218 | triggerDeathPhase = function() {
219 | private$deckManager$triggerDeathPhase()
220 | }
221 | ),
222 |
223 | public = list(
224 | ui = NULL,
225 | init_server = function(session) {
226 | private$session <- session
227 |
228 | private$session$sendCustomMessage("init_card_stack", TRUE)
229 | private$metricsManager$init_server("metrics", private$stateManager$state)
230 | private$mapManager$init_server("map")
231 | },
232 |
233 | resetGame = function(gameType = private$gameType) {
234 | self$startGame(gameType, TRUE)
235 | },
236 |
237 | startGame = function(gameType, skipTutorial = FALSE) {
238 | private$session$sendCustomMessage( "clear_card_stack", TRUE)
239 |
240 | private$resetState()
241 | private$stateManager$resetState()
242 | private$deckManager$resetState(
243 | gameType,
244 | skipTutorial,
245 | private$dataManager,
246 | private$stateManager
247 | )
248 | private$mapManager$updateState(private$session)
249 |
250 | private$session$sendCustomMessage(
251 | "trackEvent",
252 | list(
253 | category = "Game state",
254 | action = "Game started",
255 | label = glue::glue("Game started, dificulty {gameType}")
256 | )
257 | )
258 |
259 | private$session$sendCustomMessage( "add_card", self$popCard())
260 | },
261 |
262 | popCard = function() {
263 | private$deckManager$popCard()
264 | },
265 |
266 | updateState = function(newState) {
267 | private$stateManager$updateState(newState)
268 |
269 | if(private$stateManager$isDeathState()) {
270 | private$triggerDeathPhase()
271 | }
272 |
273 | private$mapManager$updateState(private$session)
274 | card <- self$popCard()
275 |
276 | if (!is.null(card) && card == "GAMEOVER") {
277 | private$session$sendCustomMessage(
278 | "game_over",
279 | private$stateManager$state$week
280 | )
281 | private$session$sendCustomMessage(
282 | "trackEvent",
283 | list(
284 | category = "Game state",
285 | action = "Game end",
286 | label = glue::glue("Game ended, score was {private$stateManager$state$week}")
287 | )
288 | )
289 | } else {
290 | private$session$sendCustomMessage("add_card", card)
291 | }
292 | },
293 |
294 | initialize = function() {
295 | private$resetState()
296 | }
297 | )
298 | )
299 |
--------------------------------------------------------------------------------
/src/app/logic/mapManager.R:
--------------------------------------------------------------------------------
1 | import("R6")
2 | import("utils")
3 | import("jsonlite")
4 | import("glue")
5 | import("shiny.blank")
6 | import("leaflet")
7 | import("shiny")
8 | import("dplyr")
9 |
10 | export("mapManager")
11 |
12 | ui <- function(id) {
13 | ns <- NS(id)
14 |
15 | tagList(
16 | tags$script(src = "scripts/update_map_style.js"),
17 | tags$style(id = "updateMapStyles"),
18 | leafletOutput(ns("mainMap"), height = "100%")
19 | )
20 | }
21 |
22 | updateMarkers <- function(markers, required, name, map, dataManager) {
23 | # Current markers on the map
24 | if(is.null(markers)) markers = list()
25 | current <- ifelse(
26 | is.data.frame(markers),
27 | nrow(markers),
28 | 0
29 | )
30 |
31 | # Update marker list with new required side
32 | if(length(markers) == 0) {
33 | markers <- sample_n(dataManager$getCities(), required)[c("lat", "lng")]
34 | }
35 | if(required < current) {
36 | markers <- sample_n(markers, required)[c("lat", "lng")]
37 | }
38 | if(required > current) {
39 | markers <- rbind(
40 | markers,
41 | sample_n(dataManager$getCities(), required - current)[c("lat", "lng")]
42 | )
43 | }
44 |
45 | # Add new markers to the map
46 | if (length(markers) > 0 ) {
47 | map <- map %>%
48 | addMarkers(data = markers, lng = ~lng, lat = ~lat,
49 | icon = list(
50 | iconUrl = paste0("assets/map/", name, ".png"),
51 | iconSize = c(30, 30),
52 | className = paste0("marker-", name)
53 | ))
54 | }
55 |
56 | return(markers)
57 | }
58 |
59 | server <- function(input, output, session, stateManager, dataManager) {
60 | ns <- session$ns
61 |
62 | output$mainMap <- renderLeaflet({
63 | leaflet(
64 | options = leafletOptions(
65 | preferCanvas = TRUE,
66 | zoomControl = FALSE,
67 | dragging = FALSE,
68 | doubleClickZoom= FALSE,
69 | minZoom = 2,
70 | maxZoom = 2)
71 | ) %>%
72 | addProviderTiles("Stamen.Watercolor",
73 | options = providerTileOptions(noWrap = TRUE)
74 | ) %>%
75 | setView(0, 0, 2)
76 | })
77 |
78 | observe({
79 | map <- leafletProxy("map-mainMap") %>%
80 | clearMarkers()
81 |
82 | current <- reactiveValuesToList(stateManager$state)
83 | markers <- stateManager$markers
84 |
85 | # Base values for calculating necessary number of markers
86 | base <- list(
87 | environment = floor(current$environment/10),
88 | wealth = floor(current$wealth/10),
89 | opinion = floor(current$opinion/10)
90 | )
91 |
92 | # Marker categories for stats indicators
93 | categories <- list()
94 | # Environment indicators
95 | # Trees start at zero and grow with the current environment
96 | categories$tree <- base$environment * 5
97 | categories$tree_large <- base$environment
98 | categories$tree_small <- base$environment * 2
99 | # Fires appear at 40 environment an increase numbers as it gets lower
100 | categories$fire <- ifelse(current$environment <= 40, (5 - base$environment), 0)
101 | # Cold appear at 40 environment an increase numbers as it gets lower
102 | categories$cold <- ifelse(current$environment <= 40, (5 - base$environment), 0)
103 | # Sick appear at 40 environment an increase numbers as it gets lower
104 | categories$sick <- ifelse(current$environment <= 40, (5 - base$environment), 0)
105 | # Tornados appear at 25 environment an increase numbers as it gets lower
106 | categories$tornado <- ifelse(current$environment <= 25, (3 - base$environment), 0)
107 | # Thunder appear at 25 environment an increase numbers as it gets lower
108 | categories$thunder <- ifelse(current$environment <= 25, (3 - base$environment), 0)
109 |
110 | # Wealth Indicators
111 | # Broken houses start apearing at 50 wealth and increase numbers as it gets lower
112 | categories$house_broken <- ifelse(current$wealth <= 50, (6 - base$wealth), 0)
113 | # Mormal houses grow up to 50 wealth and start decreasing after that
114 | if (current$wealth >= 50) categories$house <- (11 - base$wealth)
115 | else categories$house <- base$wealth
116 | # Office buildings apearing at 50 wealth and increase numbers as it gets higher
117 | categories$office <- ifelse( current$wealth >= 50, (base$wealth - 4), 0)
118 |
119 | # Opinion Indicators
120 | # Mad people start apearing at 50 opinion and increase numbers as it gets lower
121 | categories$mad <- ifelse(current$opinion <= 50, (6 - base$opinion), 0)
122 | # Smily people grow up to 50 opinion and start decreasing after that
123 | if (current$opinion >= 50) categories$smile <- (11 - base$opinion)
124 | else categories$smile <- base$wealth
125 | # Super happy people apearing at 50 opinion and increase numbers as it gets higher
126 | categories$stareyes <- ifelse(current$opinion >= 50, (base$opinion - 4), 0)
127 |
128 | # Updates markers for all categories
129 | for(category in names(categories)) {
130 | stateManager$markers[[category]] <- updateMarkers(
131 | markers = markers[[category]],
132 | required = categories[[category]],
133 | name = category,
134 | map = map,
135 | dataManager = dataManager
136 | )
137 | }
138 | })
139 | }
140 |
141 | mapManager <- R6Class("mapManager",
142 | private = list(
143 | server = server,
144 | stateManager = NULL,
145 | dataManager = NULL
146 | ),
147 |
148 | public = list(
149 | ui = ui,
150 | init_server = function(id) {
151 | callModule(private$server, id, private$stateManager, private$dataManager)
152 | },
153 |
154 | updateState = function(session) {
155 | state <- private$stateManager$state
156 |
157 | session$sendCustomMessage(
158 | "updateMapStyle",
159 | reactiveValuesToList(state)
160 | )
161 | },
162 |
163 | initialize = function(stateManager, dataManager) {
164 | private$stateManager <- stateManager
165 | private$dataManager <- dataManager
166 | }
167 | )
168 | )
169 |
--------------------------------------------------------------------------------
/src/app/logic/metricsManager.R:
--------------------------------------------------------------------------------
1 | import("R6")
2 | import("shiny")
3 | import("glue")
4 | import("shiny.grid")
5 | import("shiny.blank")
6 |
7 | export("metricsManager")
8 |
9 | metricCard <- function(id, label, class, icon) {
10 | div(
11 | class = glue::glue("{class} metric-wrapper ui-element-style"),
12 |
13 | div(
14 | class = "metric-icon",
15 | style = glue::glue("background-image: url('{icon}')")
16 | ),
17 | tags$label(label),
18 | uiOutput(id, class = id)
19 | )
20 | }
21 |
22 | karma_ui <- function(id) {
23 | ns <- NS(id)
24 |
25 | gridPanel(
26 | class = "metric-karma",
27 | rows = "1fr 50vh 1fr",
28 | columns = "80px",
29 | areas = c(
30 | "...",
31 | "karma-container",
32 | "..."
33 | ),
34 | gridPanel(
35 | class = "karma-container",
36 | rows = "50px 1fr 50px",
37 | columns = "80px",
38 | areas = c(
39 | "karma-good",
40 | "karma-value",
41 | "karma-bad"
42 | ),
43 |
44 | div(
45 | class = "karma-good",
46 | style = "background-image: url('assets/ui/icons/halo.png')"
47 | ),
48 | div(
49 | class = "karma-bad",
50 | style = "background-image: url('assets/ui/icons/evil.png')"
51 | ),
52 | uiOutput(ns("stateKarma"), class = "karma-value")
53 | )
54 | )
55 | }
56 |
57 | metrics_ui <- function(id) {
58 | ns <- NS(id)
59 |
60 | gridPanel(
61 | rows = "80px",
62 | columns = "1fr 3fr 1fr 3fr 1fr 3fr 1fr",
63 | areas = c(
64 | "... metric-wealth ... metric-opinion ... metric-environment ..."
65 | ),
66 | class = "metrics",
67 |
68 | metricCard(
69 | ns("stateWealth"),
70 | "Wealth",
71 | "metric-wealth",
72 | "assets/ui/icons/gold.png"
73 | ),
74 | metricCard(
75 | ns("stateOpinion"),
76 | "Opinion",
77 | "metric-opinion",
78 | "assets/map/smile.png"
79 | ),
80 | metricCard(
81 | ns("stateEnvironment"),
82 | "Environment",
83 | "metric-environment",
84 | "assets/map/tree.png"
85 | )
86 | )
87 | }
88 |
89 | server <- function(input, output, session, state) {
90 | ns <- session$ns
91 |
92 | output$stateKarma <- renderUI(
93 | div(
94 | class = "karma-wrapper",
95 | progress(
96 | ns("stateKarmaNegative"),
97 | value = ifelse(state$karma < 50, (50 - state$karma) * 2, 0),
98 | type = "is-error negative"
99 | ),
100 | progress(
101 | ns("stateKarmaPositive"),
102 | value = ifelse(state$karma > 49, (state$karma - 50) * 2, 0),
103 | type = "is-primary positive"
104 | )
105 | )
106 | )
107 | output$stateWealth <- renderUI(
108 | progress(ns("stateWealth"), value = state$wealth, type = "is-wealth")
109 | )
110 | output$stateOpinion <- renderUI(
111 | progress(ns("stateOpinion"), value = state$opinion, type = "is-opinion")
112 | )
113 | output$stateEnvironment <- renderUI(
114 | progress(ns("stateEnvironment"), value = state$environment, type = "is-environment")
115 | )
116 | }
117 |
118 | # Manages the UI displaying the state metrics.
119 | metricsManager <- R6Class("metricsManager",
120 | private = list(
121 | server = server
122 | ),
123 |
124 | public = list(
125 | karma_ui = karma_ui,
126 | metrics_ui = metrics_ui,
127 | init_server = function(id, state) {
128 | callModule(private$server, id, state)
129 | }
130 | )
131 | )
132 |
--------------------------------------------------------------------------------
/src/app/logic/stateManager.R:
--------------------------------------------------------------------------------
1 | import("R6")
2 | import("shiny")
3 |
4 | export("stateManager")
5 |
6 | # Manages information about the current state of the game
7 | stateManager <- R6Class("stateManager",
8 | private = list(
9 | default_state = list(
10 | karma = 60,
11 | wealth = 50,
12 | opinion = 50,
13 | environment = 50,
14 | week = 1
15 | )
16 | ),
17 | public = list(
18 | # Metrics for game state
19 | state = reactiveValues(
20 | karma = 50,
21 | wealth = 0,
22 | opinion = 0,
23 | environment = 0,
24 | week = 0
25 | ),
26 | # Markers currently in the map
27 | markers = list(),
28 |
29 | # Allows reseting the state of the manager.
30 | resetState = function(state = private$default_state) {
31 | isolate(self$updateState(state, TRUE))
32 | self$markers = list()
33 | },
34 |
35 | # Checks for death states
36 | isDeathState = function() {
37 | if(self$state$wealth < 1 ||
38 | self$state$opinion < 1 ||
39 | self$state$environment < 1
40 | ) {
41 | return(TRUE)
42 | }
43 |
44 | return(FALSE)
45 | },
46 |
47 | # If force is false, newState contains the delta values to update
48 | # If force is true, newState contains the new values for the state attribute
49 | updateState = function(newState, force = FALSE) {
50 | lapply(names(newState), function(attribute) {
51 | self$state[[attribute]] <- ifelse (
52 | force,
53 | newState[[attribute]],
54 | self$state[[attribute]] + as.numeric(newState[[attribute]])
55 | )
56 |
57 | # Ignore week limits
58 | if(attribute != "week") {
59 | if(self$state[[attribute]] < 0)
60 | self$state[[attribute]] <- 0
61 | if(self$state[[attribute]] > 100)
62 | self$state[[attribute]] <- 100
63 | }
64 | })
65 | }
66 | )
67 | )
68 |
--------------------------------------------------------------------------------
/src/app/server.R:
--------------------------------------------------------------------------------
1 | function(input, output, session) {
2 |
3 | session$userData$gameManager <- use("logic/gameManager.R")$gameManager$new()
4 | session$userData$gameManager$init_server(session)
5 |
6 | observeEvent(input$update_state, {
7 | session$userData$gameManager$updateState(input$update_state)
8 | })
9 |
10 | observeEvent(input$startGameEasy, {
11 | session$userData$gameManager$startGame("Easy", !input$showTutorial)
12 | })
13 | observeEvent(input$startGameMedium, {
14 | session$userData$gameManager$startGame("Medium", !input$showTutorial)
15 | })
16 | observeEvent(input$startGameHard, {
17 | session$userData$gameManager$startGame("Hard", !input$showTutorial)
18 | })
19 | }
20 |
--------------------------------------------------------------------------------
/src/app/styles/main.scss:
--------------------------------------------------------------------------------
1 | //Modules and variables
2 | @import "modules/config";
3 | @import "modules/animations";
4 | @import "modules/static";
5 |
6 | //Modules and variables
7 | @import "partials/layout";
8 | @import "partials/modals";
9 | @import "partials/metrics";
10 | @import "partials/cards";
11 | @import "partials/map";
12 |
--------------------------------------------------------------------------------
/src/app/styles/modules/_animations.scss:
--------------------------------------------------------------------------------
1 | @-webkit-keyframes color-change {
2 | 0% { color: white; }
3 | 50% { color: black; }
4 | 100% { color: white; }
5 | }
6 | @-moz-keyframes color-change {
7 | 0% { color: white; }
8 | 50% { color: black; }
9 | 100% { color: white; }
10 | }
11 | @-ms-keyframes color-change {
12 | 0% { color: white; }
13 | 50% { color: black; }
14 | 100% { color: white; }
15 | }
16 | @-o-keyframes color-change {
17 | 0% { color: white; }
18 | 50% { color: black; }
19 | 100% { color: white; }
20 | }
21 | @keyframes color-change {
22 | 0% { color: white; }
23 | 50% { color: black; }
24 | 100% { color: white; }
25 | }
26 |
--------------------------------------------------------------------------------
/src/app/styles/modules/_config.scss:
--------------------------------------------------------------------------------
1 | $main-background-color: #212529;
2 |
3 | $progress-background-color: #fff;
4 | $progress-opinion-fill: #6853A3;
5 | $progress-wealth-fill: #e48e22;
6 | $progress-environment-fill: #6cab22;
7 |
--------------------------------------------------------------------------------
/src/app/styles/modules/_static.scss:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | width: 100%;
4 | overflow: hidden;
5 | }
6 |
7 | .modal-content,
8 | .ui-element-style {
9 | filter: drop-shadow(5px 10px 15px black);
10 | }
11 |
--------------------------------------------------------------------------------
/src/app/styles/partials/_cards.scss:
--------------------------------------------------------------------------------
1 | .app-cards {
2 | overflow: visible;
3 | z-index: 1;
4 | }
5 |
6 | #card_stack_wrapper {
7 | width: 100%;
8 | height: 100%;
9 | position: relative;
10 | overflow: visible;
11 | }
12 |
13 | #card_stack {
14 | width: 100%;
15 | height: 100%;
16 | position: absolute;
17 | bottom: 0;
18 | overflow: hidden;
19 | overflow: visible;
20 |
21 | .card {
22 | border: 3px solid #212529;
23 | position: absolute;
24 | top: 50%;
25 | left: 50%;
26 | border-radius: 1%;
27 | filter: drop-shadow(25px 25px 25px black);
28 | background-color: white;
29 | transform: translateX(-50%) translateY(-50%) scale(0.95);
30 | background-position: center center;
31 | background-repeat: no-repeat;
32 | width: 30vh;
33 | height: 30vh;
34 | max-width: 70vw;
35 | max-height: 70vw;
36 | font-size: 1rem;
37 |
38 | .card-background {
39 | position: absolute;
40 | top: 0;
41 | bottom: 0;
42 | left: 0;
43 | right: 0;
44 | }
45 |
46 | .card-image {
47 | z-index: 2;
48 | background-size: 90% 90% !important;
49 | background-repeat: no-repeat !important;
50 | background-position: 50% 220% !important;
51 | filter: drop-shadow(7px 1px 0px #3b3c3e);
52 | }
53 | .card-color {
54 | z-index: 1;
55 | filter: blur(10px);
56 | }
57 | }
58 |
59 | .message-left, .message-right {
60 | display: none;
61 | padding: 5px;
62 | position: absolute;
63 | z-index: 4;
64 | left: 8px;
65 | right: 8px;
66 | top: 8px;
67 | color: black;
68 | }
69 |
70 | .message-left {
71 | text-align: right;
72 | right: 8px;
73 | }
74 |
75 | .dragging-left .message-left,
76 | .dragging-right .message-right {
77 | display: block;
78 | }
79 | }
80 |
81 | #card_stack_message{
82 | width: 100%;
83 | height: 150px;
84 | display: flex;
85 | align-items: center;
86 | justify-content: center;
87 | text-align: center;
88 | background-color: $main-background-color;
89 | color: white;
90 | padding: 30px;
91 | position: relative;
92 |
93 | &:before, &:after {
94 | content: "";
95 | position: absolute;
96 | top: 0;
97 | z-index: -1;
98 | border-top: 150px solid transparent;
99 | }
100 |
101 | &:before {
102 | left: -40px;
103 | border-right: 40px solid $main-background-color;
104 | }
105 |
106 | &:after {
107 | right: -40px;
108 | border-left: 40px solid $main-background-color;
109 | }
110 | }
111 |
112 | .week-content {
113 | text-align: center;
114 | font-size: 28px;
115 | filter: drop-shadow(5px 10px 15px black);
116 | -webkit-text-stroke-width: 2px;
117 | -webkit-text-stroke-color: #ffffff33;
118 | }
119 |
120 | @media (orientation: portrait) {
121 | .card {
122 | font-size: 140% !important;
123 | }
124 |
125 | #card_stack_message {
126 | font-size: 140% !important;
127 | height: 90% !important;
128 | background-color: transparent;
129 | }
130 | #card_stack_message:after,
131 | #card_stack_message:before {
132 | display: none !important;
133 | }
134 |
135 | .week-content {
136 | color: white;
137 | line-height: 80px;
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/app/styles/partials/_layout.scss:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: $main-background-color !important;
3 | }
4 |
5 | @media (orientation: portrait) {
6 | #page-wrapper {
7 | grid-template-areas:
8 | 'app-metrics app-metrics app-metrics'
9 | '... app-week ...'
10 | 'app-karma app-task ...'
11 | 'app-karma app-task ...'
12 | 'app-karma app-cards ...'
13 | 'app-karma ... ...' !important;
14 | grid-template-rows: 80px 80px 20% 50px 1fr 20% !important;
15 | grid-template-columns: 80px 1fr 80px !important;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/app/styles/partials/_map.scss:
--------------------------------------------------------------------------------
1 | .app-map {
2 | position: absolute;
3 | height: 100%;
4 | width: 100%;
5 | z-index: -1;
6 | }
7 |
8 | .leaflet-marker-icon {
9 | filter: drop-shadow(2px 2px 0 black) drop-shadow(-2px -2px 0 black);
10 | }
11 |
12 | .marker-tree,
13 | .marker-tree_large,
14 | .marker-tree_small {
15 | z-index: 1 !important;
16 | }
17 |
18 | #map-mainMap {
19 | background: url("//stamen-tiles-a.a.ssl.fastly.net/watercolor/2/4/0.png");
20 | background-size: contain;
21 | }
22 |
23 | @media (orientation: portrait) {
24 | .app-map {
25 | height: 40vh !important;
26 | bottom: 10%;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/app/styles/partials/_metrics.scss:
--------------------------------------------------------------------------------
1 | .app-metrics {
2 | color: #fff;
3 | z-index: 3;
4 | }
5 |
6 | .metric-wrapper {
7 | padding-left: 55px;
8 | position: relative;
9 | background-color: $main-background-color;
10 |
11 | &:before, &:after {
12 | content: "";
13 | position: absolute;
14 | z-index: -1;
15 | top: 0;
16 | border-bottom: 80px solid transparent;
17 | }
18 | &:before {
19 | left: -20px;
20 | border-right: 20px solid $main-background-color;
21 | }
22 | &:after {
23 | right: -20px;
24 | border-left: 20px solid $main-background-color;
25 | }
26 |
27 | &.will-change,
28 | &.will-change-large {
29 | -webkit-animation: color-change 1s infinite;
30 | -moz-animation: color-change 1s infinite;
31 | -o-animation: color-change 1s infinite;
32 | -ms-animation: color-change 1s infinite;
33 | animation: color-change 1s infinite;
34 | }
35 |
36 | label {
37 | margin-top: 12px;
38 | margin-bottom: 0;
39 | }
40 |
41 | progress {
42 | width: calc(100% - 20px);
43 | }
44 |
45 | .metric-icon {
46 | position: absolute;
47 | left: 7px;
48 | top: 0;
49 | bottom: 0;
50 | margin: auto;
51 | width: 40px;
52 | height: 40px;
53 | background-position: center center;
54 | background-size: 80%;
55 | background-repeat: no-repeat;
56 | }
57 | }
58 |
59 | .metric-karma {
60 | z-index: 100;
61 |
62 | .karma-container {
63 | background-color: $main-background-color;
64 |
65 | .karma-bad,
66 | .karma-good {
67 | background-position: center center;
68 | background-repeat: no-repeat;
69 | position: relative;
70 | }
71 |
72 | .karma-bad {
73 | background-size: 34px;
74 | background-position: 20px;
75 | }
76 |
77 | .karma-good:before {
78 | content: "";
79 | position: absolute;
80 | top: -20px;
81 | z-index: -1;
82 | border-left: 80px solid #212529;
83 | border-top: 20px solid transparent;
84 | }
85 | .karma-bad:after {
86 | content: "";
87 | position: absolute;
88 | bottom: -20px;
89 | z-index: -1;
90 | border-left: 80px solid #212529;
91 | border-bottom: 20px solid transparent;
92 | }
93 | }
94 |
95 | .karma-value {
96 | width: calc(50vh - 100px);
97 | transform: translate(29px, 0) rotate(-90deg);
98 |
99 | .karma-wrapper {
100 | display: flex;
101 |
102 | .positive{
103 | width: 50%;
104 | float: right;
105 | padding-left: 4px;
106 | }
107 |
108 | .negative{
109 | transform: rotate(180deg);
110 | width: 50%;
111 | float: left;
112 | }
113 | }
114 | }
115 | }
116 |
117 | .nes-progress {
118 | height: 20px !important;
119 | margin: 0 !important;
120 |
121 | &.is-opinion {
122 | &::-webkit-progress-bar {
123 | background-color: $progress-background-color;
124 | }
125 | &::-webkit-progress-value {
126 | background-color: $progress-opinion-fill;
127 | }
128 | &::-moz-progress-bar {
129 | background-color: $progress-opinion-fill;
130 | }
131 | &::-ms-fill {
132 | background-color: $progress-opinion-fill;
133 | border: none
134 | }
135 | }
136 |
137 | &.is-wealth {
138 | &::-webkit-progress-bar {
139 | background-color: $progress-background-color;
140 | }
141 | &::-webkit-progress-value {
142 | background-color: $progress-wealth-fill;
143 | }
144 | &::-moz-progress-bar {
145 | background-color: $progress-wealth-fill;
146 | }
147 | &::-ms-fill {
148 | background-color: $progress-wealth-fill;
149 | border: none
150 | }
151 | }
152 |
153 | &.is-environment {
154 | &::-webkit-progress-bar {
155 | background-color: $progress-background-color;
156 | }
157 | &::-webkit-progress-value {
158 | background-color: $progress-environment-fill;
159 | }
160 | &::-moz-progress-bar {
161 | background-color: $progress-environment-fill;
162 | }
163 | &::-ms-fill {
164 | background-color: $progress-environment-fill;
165 | border: none
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/src/app/styles/partials/_modals.scss:
--------------------------------------------------------------------------------
1 | .modal {
2 | background-color: rgba(0, 0, 0, 0.8) !important;
3 | }
4 |
5 |
6 | #gameOverScreen {
7 | z-index: 100100 !important;
8 |
9 | .title, #game_over_message {
10 | font-size: 300%;
11 | }
12 | }
13 |
14 | .entry-screen {
15 | text-align: center;
16 | justify-content: center;
17 | align-items: center;
18 |
19 | button {
20 | margin: 15px;
21 | }
22 | }
23 |
24 | @media (orientation: portrait) {
25 | .entry-screen {
26 | grid-template-rows: 1fr 150px !important;
27 | font-size: 140% !important;
28 | }
29 | }
30 |
31 | #entryScreen {
32 | .modal-content {
33 | margin-top: 10vh !important;
34 | margin-bottom: calc(15vh + 200px) !important;
35 | }
36 | }
37 |
38 | #attributionScreen {
39 | pointer-events: none;
40 |
41 | background: transparent !important;
42 | z-index: 10001 !important;
43 | .modal-content {
44 | .title {
45 | text-decoration: underline;
46 | }
47 |
48 | .links {
49 | pointer-events: all;
50 | }
51 |
52 | background: transparent !important;
53 |
54 | width: 427px !important;
55 | height: 200px !important;
56 | padding: 0 !important;
57 |
58 | margin-left: 10vw !important;
59 | margin-bottom: 10vh !important;
60 |
61 | @media (orientation: portrait) {
62 | font-size: 75%;
63 | }
64 | }
65 |
66 | #author-details {
67 | text-align: left;
68 | grid-gap: 10px;
69 | margin: 0 !important;
70 |
71 | .avatar {
72 | background: url("/assets/ui/author.png");
73 | background-size: contain;
74 | background-repeat: no-repeat;
75 | }
76 | }
77 | }
78 |
79 | #projectDetailsScreen {
80 | pointer-events: none;
81 |
82 | background: transparent !important;
83 | z-index: 10001 !important;
84 | .modal-content {
85 |
86 | .title {
87 | text-decoration: underline;
88 | }
89 |
90 | .links {
91 | pointer-events: all;
92 | }
93 |
94 | background: transparent !important;
95 |
96 | width: 237px !important;
97 | height: 200px !important;
98 | padding: 0 !important;
99 |
100 | margin-right: 10vw !important;
101 | margin-bottom: 10vh !important;
102 |
103 | @media (orientation: portrait) {
104 | font-size: 75%;
105 | }
106 | }
107 |
108 | #project-details {
109 | text-align: left;
110 | grid-gap: 10px;
111 | margin: 0 !important;
112 |
113 | .avatar {
114 | background-size: contain;
115 | background-repeat: no-repeat;
116 | }
117 | }
118 | }
119 |
120 | #pause-game {
121 | position: absolute;
122 | bottom: 10px;
123 | left: 10px;
124 | height: 1.5cm;
125 | width: 1.5cm;
126 | z-index: 10010;
127 | background-size: contain;
128 | cursor: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAzElEQVRYR+2X0Q6AIAhF5f8/2jYXZkwEjNSVvVUjDpcrGgT7FUkI2D9xRfQETwNIiWO85wfINfQUEyxBG2ArsLwC0jioGt5zFcwF4OYDPi/mBYKm4t0U8ATgRm3ThFoAqkhNgWkA0jJLvaOVSs7j3qMnSgXWBMiWPXe94QqMBMBc1VZIvaTu5u5pQewq0EqNZvIEMCmxAawK0DNkay9QmfFNAJUXfgGgUkLaE7j/h8fnASkxHTz0DGIBMCnBeeM7AArpUd3mz2x3C7wADglA8BcWMZhZAAAAAElFTkSuQmCC) 14 0, pointer;
129 | background-color: #d1d1d1;
130 | border-radius: 50%;
131 | image-rendering: pixelated;
132 | filter: hue-rotate(-160deg) drop-shadow(2px 4px 6px black);
133 | }
134 |
--------------------------------------------------------------------------------
/src/app/ui.R:
--------------------------------------------------------------------------------
1 | blankPage(
2 | title = "Shiny Decisions",
3 | theme = "nes",
4 |
5 | tags$head(
6 | tags$head(includeHTML(("google-analytics.html"))),
7 | tags$script(src = "scripts/analytics-events.js"),
8 | tags$link(rel="shortcut icon", href="assets/map/tree.png"),
9 | tags$meta(name="apple-mobile-web-app-capable", content="yes"),
10 | tags$link(rel = "stylesheet", type = "text/css", href = "styles/sass.min.css")
11 | ),
12 |
13 | gameManager$ui$gameStages(),
14 |
15 | div(
16 | class = "app-map",
17 | gameManager$ui$map("map")
18 | ),
19 | gridPanel(
20 | id = "page-wrapper",
21 | rows = "100px 1fr 50px 150px",
22 | columns = "80px 1fr 1fr 1fr 1fr 1fr 1fr 80px",
23 | areas = c(
24 | "app-metrics app-metrics app-metrics app-metrics app-metrics app-metrics app-metrics app-metrics",
25 | "app-karma ... ... ... app-cards app-cards app-cards app-cards",
26 | "app-karma ... ... app-week app-week ... ... ...",
27 | "... ... app-task app-task app-task app-task ... ..."
28 | ),
29 |
30 | gridPanel(
31 | class = "app-metrics",
32 | gameManager$ui$metrics("metrics")
33 | ),
34 |
35 | gridPanel(
36 | class = "app-karma ui-element-style",
37 | gameManager$ui$karma("metrics")
38 | ),
39 |
40 | gridPanel(
41 | class = "app-cards",
42 | gameManager$ui$cardStack()
43 | ),
44 |
45 | div(
46 | id = "app_week",
47 | class = "app-week",
48 | p(class = "week-content")
49 | ),
50 |
51 | div(
52 | id = "card_stack_message",
53 | class = "app-task ui-element-style",
54 | p(class = "message-content")
55 | )
56 | )
57 | )
58 |
--------------------------------------------------------------------------------
/src/app/www/assets/cards/beekeeper-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/beekeeper-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/blacksmith-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/blacksmith-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/blank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/blank.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/boy-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/boy-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/boy-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/boy-2.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/boy-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/boy-3.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/boy-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/boy-4.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/boy-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/boy-5.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/boy-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/boy-6.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/boy-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/boy-7.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/chef-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/chef-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/doctor-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/doctor-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/farmer-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/farmer-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/girl-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/girl-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/girl-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/girl-2.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/girl-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/girl-3.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/girl-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/girl-4.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/hunter-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/hunter-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-10.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-11.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-12.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-13.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-14.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-15.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-16.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-17.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-18.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-19.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-2.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-20.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-21.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-22.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-23.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-24.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-25.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-26.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-27.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-27.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-28.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-28.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-29.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-3.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-30.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-30.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-31.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-31.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-32.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-33.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-33.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-34.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-34.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-35.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-35.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-36.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-37.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-37.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-4.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-5.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-6.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-7.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-8.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/man-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/man-9.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/nun-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/nun-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/pirate-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/pirate-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/pirate-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/pirate-2.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/sailor-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/sailor-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/santa-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/santa-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/scientist-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/scientist-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/shady-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/shady-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/shady-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/shady-2.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/shady-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/shady-3.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-1.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-10.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-11.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-12.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-13.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-14.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-16.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-17.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-18.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-19.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-2.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-20.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-21.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-22.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-23.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-24.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-25.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-25.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-26.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-26.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-6.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-7.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-8.png
--------------------------------------------------------------------------------
/src/app/www/assets/cards/woman-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/cards/woman-9.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/cold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/cold.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/fire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/fire.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/house.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/house.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/house_broken.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/house_broken.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/mad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/mad.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/mask.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/mask.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/office.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/office.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/sick.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/sick.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/smile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/smile.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/stareyes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/stareyes.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/thunder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/thunder.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/tornado.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/tornado.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/tree.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/tree_large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/tree_large.png
--------------------------------------------------------------------------------
/src/app/www/assets/map/tree_small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/map/tree_small.png
--------------------------------------------------------------------------------
/src/app/www/assets/ui/author.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/ui/author.png
--------------------------------------------------------------------------------
/src/app/www/assets/ui/icons/evil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/ui/icons/evil.png
--------------------------------------------------------------------------------
/src/app/www/assets/ui/icons/friend.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/ui/icons/friend.png
--------------------------------------------------------------------------------
/src/app/www/assets/ui/icons/gold.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/ui/icons/gold.png
--------------------------------------------------------------------------------
/src/app/www/assets/ui/icons/halo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/ui/icons/halo.png
--------------------------------------------------------------------------------
/src/app/www/assets/ui/icons/salad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/ui/icons/salad.png
--------------------------------------------------------------------------------
/src/app/www/assets/ui/pause.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pedrocoutinhosilva/shiny.decisions/4db92763bdc885b18d34cdb0bd53b301c4978964/src/app/www/assets/ui/pause.png
--------------------------------------------------------------------------------
/src/app/www/scripts/analytics-events.js:
--------------------------------------------------------------------------------
1 | let sendAnalyticsEvent = function(options) {
2 | gtag('event', options.action, {'event_category' : options.category,
3 | 'event_label' : options.label});
4 | }
5 | Shiny.addCustomMessageHandler('trackEvent', sendAnalyticsEvent)
6 |
--------------------------------------------------------------------------------
/src/app/www/scripts/card_stack.js:
--------------------------------------------------------------------------------
1 | class Carousel {
2 | constructor(element) {
3 | this.board = element
4 | this.handle()
5 | }
6 |
7 | handle() {
8 | this.cards = this.board.querySelectorAll('.card')
9 | this.topCard = this.cards[this.cards.length-1]
10 | this.nextCard = this.cards[this.cards.length-2]
11 | if (this.cards.length > 0) {
12 |
13 | this.topCard.style.transform =
14 | 'translateX(-50%) translateY(-50%) rotate(0deg) rotateY(0deg) scale(1)'
15 |
16 | if (this.hammer) this.hammer.destroy()
17 |
18 | this.hammer = new Hammer(this.topCard)
19 | this.hammer.add(new Hammer.Tap())
20 | this.hammer.add(new Hammer.Pan({
21 | position: Hammer.position_ALL, threshold: 0
22 | }))
23 |
24 | this.hammer.on('tap', (e) => { this.onTap(e) })
25 | this.hammer.on('pan', (e) => { this.onPan(e) })
26 |
27 | document.querySelector('#card_stack_message p').textContent = this.topCard.getAttribute('message-task')
28 | document.querySelector('#app_week p').textContent = this.topCard.getAttribute('week-text')
29 |
30 | }
31 |
32 | }
33 |
34 | onTap(e) {
35 |
36 | let propX = (e.center.x - e.target.getBoundingClientRect().left) / e.target.clientWidth
37 |
38 | let rotateY = 15 * (propX < 0.05 ? -1 : 1)
39 |
40 | this.topCard.style.transition = 'transform 100ms ease-out'
41 |
42 | this.topCard.style.transform =
43 | 'translateX(-50%) translateY(-50%) rotate(0deg) rotateY(' + rotateY + 'deg) scale(1)'
44 |
45 | setTimeout(() => {
46 | this.topCard.style.transform =
47 | 'translateX(-50%) translateY(-50%) rotate(0deg) rotateY(0deg) scale(1)'
48 | }, 100)
49 |
50 | }
51 |
52 | onPan(e) {
53 |
54 | if (!this.isPanning) {
55 |
56 | this.isPanning = true
57 |
58 | this.topCard.style.transition = null
59 | if (this.nextCard) this.nextCard.style.transition = null
60 |
61 | let style = window.getComputedStyle(this.topCard)
62 | let mx = style.transform.match(/^matrix\\((.+)\\)$/)
63 | this.startPosX = mx ? parseFloat(mx[1].split(', ')[4]) : 0
64 | this.startPosY = mx ? parseFloat(mx[1].split(', ')[5]) : 0
65 |
66 | let bounds = this.topCard.getBoundingClientRect()
67 |
68 | this.isDraggingFrom =
69 | (e.center.y - bounds.top) > this.topCard.clientHeight / 2 ? -1 : 1
70 |
71 | }
72 |
73 | let posX = e.deltaX + this.startPosX
74 | let posY = e.deltaY + this.startPosY
75 |
76 | let propX = e.deltaX / this.board.clientWidth
77 | let propY = e.deltaY / this.board.clientHeight
78 |
79 | let dirX = e.deltaX < 0 ? -1 : 1
80 |
81 | let delta_threshold = 10
82 | let delta_direction = ''
83 |
84 | if(dirX > 0) {
85 | this.topCard.classList.add('dragging-right')
86 | this.topCard.classList.remove('dragging-left')
87 | delta_direction = 'right'
88 | } else {
89 | this.topCard.classList.add('dragging-left')
90 | this.topCard.classList.remove('dragging-right')
91 | delta_direction = 'left'
92 | }
93 |
94 | Object.values(document.querySelectorAll(`.metric-wrapper`)).map(x => {
95 | x.classList.remove('will-change', 'will-change-large')
96 | })
97 |
98 | Object.entries({
99 | karma: Number(carousel.topCard.getAttribute(`delta-${delta_direction}-karma`)),
100 | wealth: Number(carousel.topCard.getAttribute(`delta-${delta_direction}-wealth`)),
101 | opinion: Number(carousel.topCard.getAttribute(`delta-${delta_direction}-opinion`)),
102 | environment: Number(carousel.topCard.getAttribute(`delta-${delta_direction}-environment`))
103 | }).map(attribute => {
104 | if(attribute[1] !== 0) {
105 | document.querySelector(`.metric-${attribute[0]}`)
106 | .classList.add(
107 | (attribute[1] > delta_threshold)
108 | ? 'will-change-large'
109 | : 'will-change'
110 | )
111 | }
112 | })
113 |
114 | let deg = this.isDraggingFrom * dirX * Math.abs(propX) * 45
115 |
116 | let scale = (95 + (5 * Math.abs(propX))) / 100
117 |
118 | this.topCard.style.transform =
119 | 'translateX(calc(' + posX + 'px - 50%)) translateY(calc(' + posY + 'px - 50%)) rotate(' + deg + 'deg) rotateY(0deg) scale(1)'
120 |
121 |
122 | if (this.nextCard) this.nextCard.style.transform =
123 | 'translateX(-50%) translateY(-50%) rotate(0deg) rotateY(0deg) scale(' + scale + ')'
124 |
125 | if (e.isFinal) {
126 | this.isPanning = false
127 | let successful = false
128 |
129 | let direction = ''
130 |
131 | this.topCard.classList.remove('dragging-left')
132 | this.topCard.classList.remove('dragging-right')
133 |
134 | Object.values(document.querySelectorAll(`.metric-wrapper`)).map(x => {
135 | x.classList.remove('will-change', 'will-change-large')
136 | })
137 |
138 | this.topCard.style.transition = 'transform 200ms ease-out'
139 | if (this.nextCard) this.nextCard.style.transition = 'transform 100ms linear'
140 |
141 | if (propX > 0.15 && e.direction == Hammer.DIRECTION_RIGHT) {
142 |
143 | direction = 'RIGHT'
144 | successful = true
145 | posX = this.board.clientWidth
146 |
147 | } else if (propX < -0.15 && e.direction == Hammer.DIRECTION_LEFT) {
148 |
149 | direction = 'LEFT'
150 | successful = true
151 | posX = - (this.board.clientWidth + this.topCard.clientWidth)
152 |
153 | }
154 |
155 | if (successful) {
156 |
157 | this.topCard.style.transform =
158 | 'translateX(calc(' + posX + 'px - 50%)) translateY(calc(' + posY + 'px - 50%)) rotate(' + deg + 'deg)'
159 |
160 | let delta = {}
161 |
162 | if(direction == 'LEFT') {
163 | delta = {
164 | karma: this.topCard.getAttribute('delta-left-karma'),
165 | wealth: this.topCard.getAttribute('delta-left-wealth'),
166 | opinion: this.topCard.getAttribute('delta-left-opinion'),
167 | environment: this.topCard.getAttribute('delta-left-environment')
168 | }
169 | }
170 |
171 | if(direction == 'RIGHT') {
172 | delta = {
173 | karma: this.topCard.getAttribute('delta-right-karma'),
174 | wealth: this.topCard.getAttribute('delta-right-wealth'),
175 | opinion: this.topCard.getAttribute('delta-right-opinion'),
176 | environment: this.topCard.getAttribute('delta-right-environment')
177 | }
178 | }
179 |
180 | setTimeout(() => {
181 | Shiny.setInputValue('update_state', {
182 | karma: delta.karma,
183 | wealth: delta.wealth,
184 | opinion: delta.opinion,
185 | environment: delta.environment,
186 | week: this.topCard.getAttribute('week-increment')
187 | }, {priority : 'event'})
188 |
189 | this.board.removeChild(this.topCard)
190 | this.handle()
191 |
192 | }, 200)
193 |
194 | } else {
195 |
196 | this.topCard.style.transform =
197 | 'translateX(-50%) translateY(-50%) rotate(0deg) rotateY(0deg) scale(1)'
198 | if (this.nextCard) this.nextCard.style.transform =
199 | 'translateX(-50%) translateY(-50%) rotate(0deg) rotateY(0deg) scale(0.95)'
200 |
201 | }
202 |
203 | }
204 |
205 | }
206 |
207 | push({ background, message, delta }) {
208 | let card = document.createElement('div')
209 |
210 | let card_color = document.createElement('div')
211 | let card_image = document.createElement('div')
212 |
213 | let message_left = document.createElement('p')
214 | let message_right = document.createElement('p')
215 |
216 | message_left.classList.add('message-left')
217 | message_left.textContent = message.left
218 |
219 | message_right.classList.add('message-right')
220 | message_right.textContent = message.right
221 |
222 | card.append(message_left)
223 | card.append(message_right)
224 |
225 | card.append(card_image)
226 | card.append(card_color)
227 |
228 | card.classList.add('card')
229 |
230 | Object.entries({
231 | 'message-task': message.task,
232 | 'message-left': message.left,
233 | 'message-right': message.right,
234 |
235 | 'week-text': message.week.text,
236 | 'week-increment': message.week.increment,
237 |
238 | 'delta-left-karma': delta.left.karma,
239 | 'delta-left-wealth': delta.left.wealth,
240 | 'delta-left-opinion': delta.left.opinion,
241 | 'delta-left-environment': delta.left.environment,
242 |
243 | 'delta-right-karma': delta.right.karma,
244 | 'delta-right-wealth': delta.right.wealth,
245 | 'delta-right-opinion': delta.right.opinion,
246 | 'delta-right-environment': delta.right.environment
247 | }).map(attribute => {
248 | card.setAttribute(attribute[0], attribute[1])
249 | })
250 |
251 | card_image.classList.add('card-background', 'card-image')
252 | card_color.classList.add('card-background', 'card-color')
253 |
254 | card_color.style.background = `linear-gradient(
255 | 135deg,
256 | ${background.color_left} 0%,
257 | ${background.color_left} 35%,
258 | ${background.color_right} 65%,
259 | ${background.color_right} 100%)`
260 |
261 | card_image.style.background =
262 | `url(${background.image})`
263 |
264 | if (this.board.firstChild) {
265 | this.board.insertBefore(card, this.board.firstChild)
266 | } else {
267 | this.board.append(card)
268 | }
269 |
270 | }
271 | }
272 |
273 | let carousel
274 |
275 | let init_card_stack = function(force) {
276 | carousel = new Carousel(document.querySelector('#card_stack'))
277 | }
278 | Shiny.addCustomMessageHandler('init_card_stack', init_card_stack);
279 |
280 | let addCard = function(options) {
281 | carousel.push(options)
282 | carousel.handle()
283 | }
284 | Shiny.addCustomMessageHandler('add_card', addCard)
285 |
286 | let gameOver = function(message) {
287 | modal_gameOverScreen.classList.add('open')
288 | document.getElementById('game_over_message').innerHTML = message
289 | }
290 | Shiny.addCustomMessageHandler('game_over', gameOver)
291 |
292 | let clearCardStack = function(message) {
293 | $("#card_stack .card").remove()
294 | }
295 | Shiny.addCustomMessageHandler('clear_card_stack', clearCardStack)
296 |
--------------------------------------------------------------------------------
/src/app/www/scripts/filter-toggler.js:
--------------------------------------------------------------------------------
1 | $( document ).ready(function() {
2 | $(document).on('click','#toggle-network-filters',function(){
3 | $("#network-filters-cell").toggleClass("open");
4 |
5 | let button_text = $("#network-filters-cell").hasClass("open")
6 | ? "Close Filters"
7 | : "Open Filters"
8 |
9 | $("#toggle-network-filters").html(button_text);
10 | });
11 | });
12 |
--------------------------------------------------------------------------------
/src/app/www/scripts/hammer.min.js:
--------------------------------------------------------------------------------
1 | /*! Hammer.JS - v2.0.7 - 2016-04-22
2 | * http://hammerjs.github.io/
3 | *
4 | * Copyright (c) 2016 Jorik Tangelder;
5 | * Licensed under the MIT license */
6 | !function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(j(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",f=a.console&&(a.console.warn||a.console.log);return f&&f.call(a.console,e,d),b.apply(this,arguments)}}function i(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&la(d,c)}function j(a,b){return function(){return a.apply(b,arguments)}}function k(a,b){return typeof a==oa?a.apply(b?b[0]||d:d,b):a}function l(a,b){return a===d?b:a}function m(a,b,c){g(q(b),function(b){a.addEventListener(b,c,!1)})}function n(a,b,c){g(q(b),function(b){a.removeEventListener(b,c,!1)})}function o(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function p(a,b){return a.indexOf(b)>-1}function q(a){return a.trim().split(/\s+/g)}function r(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;dc[b]}):d.sort()),d}function u(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g1&&!c.firstMultiple?c.firstMultiple=D(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=E(d);b.timeStamp=ra(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=I(h,i),b.distance=H(h,i),B(c,b),b.offsetDirection=G(b.deltaX,b.deltaY);var j=F(b.deltaTime,b.deltaX,b.deltaY);b.overallVelocityX=j.x,b.overallVelocityY=j.y,b.overallVelocity=qa(j.x)>qa(j.y)?j.x:j.y,b.scale=g?K(g.pointers,d):1,b.rotation=g?J(g.pointers,d):0,b.maxPointers=c.prevInput?b.pointers.length>c.prevInput.maxPointers?b.pointers.length:c.prevInput.maxPointers:b.pointers.length,C(c,b);var k=a.element;o(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function B(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};b.eventType!==Ea&&f.eventType!==Ga||(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function C(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ha&&(i>Da||h.velocity===d)){var j=b.deltaX-h.deltaX,k=b.deltaY-h.deltaY,l=F(i,j,k);e=l.x,f=l.y,c=qa(l.x)>qa(l.y)?l.x:l.y,g=G(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function D(a){for(var b=[],c=0;ce;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:pa(c/b),y:pa(d/b)}}function F(a,b,c){return{x:b/a||0,y:c/a||0}}function G(a,b){return a===b?Ia:qa(a)>=qa(b)?0>a?Ja:Ka:0>b?La:Ma}function H(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function I(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function J(a,b){return I(b[1],b[0],Ra)+I(a[1],a[0],Ra)}function K(a,b){return H(b[0],b[1],Ra)/H(a[0],a[1],Ra)}function L(){this.evEl=Ta,this.evWin=Ua,this.pressed=!1,x.apply(this,arguments)}function M(){this.evEl=Xa,this.evWin=Ya,x.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function N(){this.evTarget=$a,this.evWin=_a,this.started=!1,x.apply(this,arguments)}function O(a,b){var c=s(a.touches),d=s(a.changedTouches);return b&(Ga|Ha)&&(c=t(c.concat(d),"identifier",!0)),[c,d]}function P(){this.evTarget=bb,this.targetIds={},x.apply(this,arguments)}function Q(a,b){var c=s(a.touches),d=this.targetIds;if(b&(Ea|Fa)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=s(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return o(a.target,i)}),b===Ea)for(e=0;e-1&&d.splice(a,1)};setTimeout(e,cb)}}function U(a){for(var b=a.srcEvent.clientX,c=a.srcEvent.clientY,d=0;d=f&&db>=g)return!0}return!1}function V(a,b){this.manager=a,this.set(b)}function W(a){if(p(a,jb))return jb;var b=p(a,kb),c=p(a,lb);return b&&c?jb:b||c?b?kb:lb:p(a,ib)?ib:hb}function X(){if(!fb)return!1;var b={},c=a.CSS&&a.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(d){b[d]=c?a.CSS.supports("touch-action",d):!0}),b}function Y(a){this.options=la({},this.defaults,a||{}),this.id=v(),this.manager=null,this.options.enable=l(this.options.enable,!0),this.state=nb,this.simultaneous={},this.requireFail=[]}function Z(a){return a&sb?"cancel":a&qb?"end":a&pb?"move":a&ob?"start":""}function $(a){return a==Ma?"down":a==La?"up":a==Ja?"left":a==Ka?"right":""}function _(a,b){var c=b.manager;return c?c.get(a):a}function aa(){Y.apply(this,arguments)}function ba(){aa.apply(this,arguments),this.pX=null,this.pY=null}function ca(){aa.apply(this,arguments)}function da(){Y.apply(this,arguments),this._timer=null,this._input=null}function ea(){aa.apply(this,arguments)}function fa(){aa.apply(this,arguments)}function ga(){Y.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ha(a,b){return b=b||{},b.recognizers=l(b.recognizers,ha.defaults.preset),new ia(a,b)}function ia(a,b){this.options=la({},ha.defaults,b||{}),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=a,this.input=y(this),this.touchAction=new V(this,this.options.touchAction),ja(this,!0),g(this.options.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ja(a,b){var c=a.element;if(c.style){var d;g(a.options.cssProps,function(e,f){d=u(c.style,f),b?(a.oldCssProps[d]=c.style[d],c.style[d]=e):c.style[d]=a.oldCssProps[d]||""}),b||(a.oldCssProps={})}}function ka(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var la,ma=["","webkit","Moz","MS","ms","o"],na=b.createElement("div"),oa="function",pa=Math.round,qa=Math.abs,ra=Date.now;la="function"!=typeof Object.assign?function(a){if(a===d||null===a)throw new TypeError("Cannot convert undefined or null to object");for(var b=Object(a),c=1;ch&&(b.push(a),h=b.length-1):e&(Ga|Ha)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Za={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},$a="touchstart",_a="touchstart touchmove touchend touchcancel";i(N,x,{handler:function(a){var b=Za[a.type];if(b===Ea&&(this.started=!0),this.started){var c=O.call(this,a,b);b&(Ga|Ha)&&c[0].length-c[1].length===0&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}}});var ab={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},bb="touchstart touchmove touchend touchcancel";i(P,x,{handler:function(a){var b=ab[a.type],c=Q.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}});var cb=2500,db=25;i(R,x,{handler:function(a,b,c){var d=c.pointerType==za,e=c.pointerType==Ba;if(!(e&&c.sourceCapabilities&&c.sourceCapabilities.firesTouchEvents)){if(d)S.call(this,b,c);else if(e&&U.call(this,c))return;this.callback(a,b,c)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var eb=u(na.style,"touchAction"),fb=eb!==d,gb="compute",hb="auto",ib="manipulation",jb="none",kb="pan-x",lb="pan-y",mb=X();V.prototype={set:function(a){a==gb&&(a=this.compute()),fb&&this.manager.element.style&&mb[a]&&(this.manager.element.style[eb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){k(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),W(a.join(" "))},preventDefaults:function(a){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=p(d,jb)&&!mb[jb],f=p(d,lb)&&!mb[lb],g=p(d,kb)&&!mb[kb];if(e){var h=1===a.pointers.length,i=a.distance<2,j=a.deltaTime<250;if(h&&i&&j)return}return g&&f?void 0:e||f&&c&Na||g&&c&Oa?this.preventSrc(b):void 0},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var nb=1,ob=2,pb=4,qb=8,rb=qb,sb=16,tb=32;Y.prototype={defaults:{},set:function(a){return la(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=_(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=_(a,this),-1===r(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=_(a,this);var b=r(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(b,a)}var c=this,d=this.state;qb>d&&b(c.options.event+Z(d)),b(c.options.event),a.additionalEvent&&b(a.additionalEvent),d>=qb&&b(c.options.event+Z(d))},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=tb)},canEmit:function(){for(var a=0;af?Ja:Ka,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ia:0>g?La:Ma,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return aa.prototype.attrTest.call(this,a)&&(this.state&ob||!(this.state&ob)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$(a.direction);b&&(a.additionalEvent=this.options.event+b),this._super.emit.call(this,a)}}),i(ca,aa,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&ob)},emit:function(a){if(1!==a.scale){var b=a.scale<1?"in":"out";a.additionalEvent=this.options.event+b}this._super.emit.call(this,a)}}),i(da,Y,{defaults:{event:"press",pointers:1,time:251,threshold:9},getTouchAction:function(){return[hb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distanceb.time;if(this._input=a,!d||!c||a.eventType&(Ga|Ha)&&!f)this.reset();else if(a.eventType&Ea)this.reset(),this._timer=e(function(){this.state=rb,this.tryEmit()},b.time,this);else if(a.eventType&Ga)return rb;return tb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===rb&&(a&&a.eventType&Ga?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=ra(),this.manager.emit(this.options.event,this._input)))}}),i(ea,aa,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&ob)}}),i(fa,aa,{defaults:{event:"swipe",threshold:10,velocity:.3,direction:Na|Oa,pointers:1},getTouchAction:function(){return ba.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Na|Oa)?b=a.overallVelocity:c&Na?b=a.overallVelocityX:c&Oa&&(b=a.overallVelocityY),this._super.attrTest.call(this,a)&&c&a.offsetDirection&&a.distance>this.options.threshold&&a.maxPointers==this.options.pointers&&qa(b)>this.options.velocity&&a.eventType&Ga},emit:function(a){var b=$(a.offsetDirection);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),i(ga,Y,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[ib]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance