├── LICENSE.txt ├── README.md ├── favicon.png ├── index.html ├── scenes ├── PROMO.md ├── act1.md ├── act1_end.md └── intro.md ├── scripts ├── act1 │ ├── Act1_Beebee.js │ ├── Act1_Hong.js │ ├── Act1_Outro_BG.js │ └── Act1_SceneSetup.js ├── game │ ├── About.js │ ├── BG_Anxiety.js │ ├── Character.js │ ├── Game.js │ ├── HP.js │ ├── Loader.js │ ├── Options.js │ ├── Sounds.js │ └── Sprite.js ├── intro │ ├── Intro_BG.js │ └── Intro_SceneSetup.js ├── lib │ ├── helpers.js │ ├── howler.min.js │ ├── minpubsub.min.js │ └── rsvp.min.js └── main.js ├── sharing └── thumb.png ├── sounds ├── music │ ├── battle.mp3 │ ├── campus.mp3 │ ├── hum.mp3 │ └── pokemon.mp3 ├── sfx │ ├── act1_scream.mp3 │ ├── bag_kick.mp3 │ ├── bag_search.mp3 │ ├── bag_short.mp3 │ ├── bounce1.mp3 │ ├── bounce2.mp3 │ ├── bounce3.mp3 │ ├── dirty_explosion.mp3 │ ├── dramatic.mp3 │ ├── fart.mp3 │ ├── faucet.mp3 │ ├── grass_step1.mp3 │ ├── grass_step2.mp3 │ ├── hit.mp3 │ ├── hit_big.mp3 │ ├── intro_scream.mp3 │ ├── pop.mp3 │ ├── rustle.mp3 │ ├── rustle2.mp3 │ ├── sandwich.mp3 │ ├── whoosh.mp3 │ └── yelp.mp3 ├── ui │ ├── button1.mp3 │ ├── button2.mp3 │ ├── click.mp3 │ ├── hover.mp3 │ └── show_choice.mp3 └── voices │ ├── beebee-old.mp3 │ ├── beebee.mp3 │ ├── hong.mp3 │ ├── narrator.mp3 │ ├── narrator_emphasis.mp3 │ └── typewriter.mp3 ├── sprites ├── act1 │ ├── act1_beebee.png │ ├── act1_end.png │ └── act1_hong.png ├── end_demo │ ├── patreon.png │ ├── replay.png │ ├── share.png │ └── tbc.png ├── intro │ ├── intro_anim.png │ ├── intro_bg.png │ └── intro_logo.png └── ui │ ├── fear_alone.png │ ├── fear_bad.png │ ├── fear_captions.png │ ├── fear_harm.png │ ├── hp.png │ ├── icons.png │ └── preloader.png └── styles └── game.css /LICENSE.txt: -------------------------------------------------------------------------------- 1 | CC0 1.0 Universal 2 | 3 | Statement of Purpose 4 | 5 | The laws of most jurisdictions throughout the world automatically confer 6 | exclusive Copyright and Related Rights (defined below) upon the creator and 7 | subsequent owner(s) (each and all, an "owner") of an original work of 8 | authorship and/or a database (each, a "Work"). 9 | 10 | Certain owners wish to permanently relinquish those rights to a Work for the 11 | purpose of contributing to a commons of creative, cultural and scientific 12 | works ("Commons") that the public can reliably and without fear of later 13 | claims of infringement build upon, modify, incorporate in other works, reuse 14 | and redistribute as freely as possible in any form whatsoever and for any 15 | purposes, including without limitation commercial purposes. These owners may 16 | contribute to the Commons to promote the ideal of a free culture and the 17 | further production of creative, cultural and scientific works, or to gain 18 | reputation or greater distribution for their Work in part through the use and 19 | efforts of others. 20 | 21 | For these and/or other purposes and motivations, and without any expectation 22 | of additional consideration or compensation, the person associating CC0 with a 23 | Work (the "Affirmer"), to the extent that he or she is an owner of Copyright 24 | and Related Rights in the Work, voluntarily elects to apply CC0 to the Work 25 | and publicly distribute the Work under its terms, with knowledge of his or her 26 | Copyright and Related Rights in the Work and the meaning and intended legal 27 | effect of CC0 on those rights. 28 | 29 | 1. Copyright and Related Rights. A Work made available under CC0 may be 30 | protected by copyright and related or neighboring rights ("Copyright and 31 | Related Rights"). Copyright and Related Rights include, but are not limited 32 | to, the following: 33 | 34 | i. the right to reproduce, adapt, distribute, perform, display, communicate, 35 | and translate a Work; 36 | 37 | ii. moral rights retained by the original author(s) and/or performer(s); 38 | 39 | iii. publicity and privacy rights pertaining to a person's image or likeness 40 | depicted in a Work; 41 | 42 | iv. rights protecting against unfair competition in regards to a Work, 43 | subject to the limitations in paragraph 4(a), below; 44 | 45 | v. rights protecting the extraction, dissemination, use and reuse of data in 46 | a Work; 47 | 48 | vi. database rights (such as those arising under Directive 96/9/EC of the 49 | European Parliament and of the Council of 11 March 1996 on the legal 50 | protection of databases, and under any national implementation thereof, 51 | including any amended or successor version of such directive); and 52 | 53 | vii. other similar, equivalent or corresponding rights throughout the world 54 | based on applicable law or treaty, and any national implementations thereof. 55 | 56 | 2. Waiver. To the greatest extent permitted by, but not in contravention of, 57 | applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and 58 | unconditionally waives, abandons, and surrenders all of Affirmer's Copyright 59 | and Related Rights and associated claims and causes of action, whether now 60 | known or unknown (including existing as well as future claims and causes of 61 | action), in the Work (i) in all territories worldwide, (ii) for the maximum 62 | duration provided by applicable law or treaty (including future time 63 | extensions), (iii) in any current or future medium and for any number of 64 | copies, and (iv) for any purpose whatsoever, including without limitation 65 | commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes 66 | the Waiver for the benefit of each member of the public at large and to the 67 | detriment of Affirmer's heirs and successors, fully intending that such Waiver 68 | shall not be subject to revocation, rescission, cancellation, termination, or 69 | any other legal or equitable action to disrupt the quiet enjoyment of the Work 70 | by the public as contemplated by Affirmer's express Statement of Purpose. 71 | 72 | 3. Public License Fallback. Should any part of the Waiver for any reason be 73 | judged legally invalid or ineffective under applicable law, then the Waiver 74 | shall be preserved to the maximum extent permitted taking into account 75 | Affirmer's express Statement of Purpose. In addition, to the extent the Waiver 76 | is so judged Affirmer hereby grants to each affected person a royalty-free, 77 | non transferable, non sublicensable, non exclusive, irrevocable and 78 | unconditional license to exercise Affirmer's Copyright and Related Rights in 79 | the Work (i) in all territories worldwide, (ii) for the maximum duration 80 | provided by applicable law or treaty (including future time extensions), (iii) 81 | in any current or future medium and for any number of copies, and (iv) for any 82 | purpose whatsoever, including without limitation commercial, advertising or 83 | promotional purposes (the "License"). The License shall be deemed effective as 84 | of the date CC0 was applied by Affirmer to the Work. Should any part of the 85 | License for any reason be judged legally invalid or ineffective under 86 | applicable law, such partial invalidity or ineffectiveness shall not 87 | invalidate the remainder of the License, and in such case Affirmer hereby 88 | affirms that he or she will not (i) exercise any of his or her remaining 89 | Copyright and Related Rights in the Work or (ii) assert any associated claims 90 | and causes of action with respect to the Work, in either case contrary to 91 | Affirmer's express Statement of Purpose. 92 | 93 | 4. Limitations and Disclaimers. 94 | 95 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 96 | surrendered, licensed or otherwise affected by this document. 97 | 98 | b. Affirmer offers the Work as-is and makes no representations or warranties 99 | of any kind concerning the Work, express, implied, statutory or otherwise, 100 | including without limitation warranties of title, merchantability, fitness 101 | for a particular purpose, non infringement, or the absence of latent or 102 | other defects, accuracy, or the present or absence of errors, whether or not 103 | discoverable, all to the greatest extent permissible under applicable law. 104 | 105 | c. Affirmer disclaims responsibility for clearing rights of other persons 106 | that may apply to the Work or any use thereof, including without limitation 107 | any person's Copyright and Related Rights in the Work. Further, Affirmer 108 | disclaims responsibility for obtaining any necessary consents, permissions 109 | or other rights required for any use of the Work. 110 | 111 | d. Affirmer understands and acknowledges that Creative Commons is not a 112 | party to this document and has no duty or obligation with respect to this 113 | CC0 or use of the Work. 114 | 115 | For more information, please see 116 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![](https://ncase.me/anxiety-demo/sharing/thumb.png) 2 | 3 | # [Play the demo here!](https://ncase.me/anxiety-demo/) 4 | 5 | Everything I've made here is dedicated to the public domain, under [Creative Commons Zero](https://creativecommons.org/choose/zero/)! 6 | 7 | Created by [Nicky Case](https://ncase.me/) 8 | 9 | Music is ["Battle of Pogs" by Komiku](http://freemusicarchive.org/music/Komiku/Captain_Glouglous_Incredible_Week_Soundtrack/pog) (Creative Commons Zero) 10 | 11 | **Sound Effects from FreeSound.org (Creative Commons)** 12 | 13 | * [Intro Scream](https://freesound.org/people/analogchill/sounds/35716/) by MaderaDelEste Films 14 | * [Dramatic Hit](https://freesound.org/people/qubodup/sounds/222517/) by qubodup 15 | * [Nature Ambience](https://freesound.org/people/michorvath/sounds/427601/) by michorvath 16 | * [Grass Footstep 1](https://freesound.org/people/morganpurkis/sounds/384651/) by morganpurkis 17 | * [Grass Footstep 2](https://freesound.org/people/morganpurkis/sounds/384643/) by morganpurkis 18 | * [Eating a Sandwich](https://freesound.org/people/dleverett/sounds/441906/) by dleverett 19 | * [Search a Bag](https://freesound.org/people/Tristan_Lohengrin/sounds/233441/) by Tristan\_Lohengrin 20 | * [Whoosh](https://freesound.org/people/crackles04/sounds/369698/) by sounds 21 | * [Empty Room Ambience](https://freesound.org/people/kyles/sounds/451616/) by kyles 22 | * [Ball Bounce](https://freesound.org/people/13GPanska_Lakota_Jan/sounds/378355/) by 13GPanska\_Lakota\_Jan 23 | * [Faucet](https://freesound.org/people/calivintage/sounds/95709/) by calivintage 24 | * [Pop](https://freesound.org/people/onikage22/sounds/240566/) by onikage22 25 | * [Angry Scream](https://freesound.org/people/cdrk/sounds/21324/) by cdrk 26 | * [Dirty Explosion](https://freesound.org/people/Link-Boy/sounds/156615/) by Link-Boy 27 | * [Clothes Rustle](https://freesound.org/people/leonelmail/sounds/427866/) by leonelmail 28 | * [Typewriter](https://freesound.org/people/tams_kp/sounds/43559/) by tams\_kp 29 | * [Yelp](https://freesound.org/people/J%C3%BAliaLN/sounds/382990/) by JúliaLN 30 | * [Tension Building](https://freesound.org/people/benjaminharveydesign/sounds/316649/) by benjaminharveydesign 31 | * [Short Fart](https://freesound.org/people/DSISStudios/sounds/241000/) by DSISStudios 32 | 33 | **Sound Effects from Kenney.nl (Creative Commons Zero)** 34 | 35 | * [Beebee's & Hong's voices](https://kenney.nl/assets/digital-audio) 36 | * [Narrator's voice](https://kenney.nl/assets/rpg-audio) 37 | 38 | **Open Source Libraries** 39 | 40 | * [Howler.js](https://howlerjs.com/) by James Simpsson for sounds 41 | * [MinPubSub](https://github.com/daniellmb/MinPubSub) by Daniel Lamb for pub/sub 42 | * [RSVP.js](https://github.com/tildeio/rsvp.js/) by Tilde for promises 43 | * [Simple Sharing Buttons](https://simplesharingbuttons.com/) by Stefan Bohacek 44 | * [Ceaser](https://matthewlein.com/tools/ceaser) by Matthew Lein for CSS animation 45 | 46 | The Pokémon theme song is © of The Pokémon Company. It's a ~22s instrumental for a parody, probably fair use. I hope. 47 | 48 | Thank you to my playtesters! 49 | B Cavello, EmilyKate McDonough, Glen Chiacchieri, Mikayla Hutchinson, Monica Srivastava, Rowan, Srini Kadamati 50 | 51 | And of course, thank you to the generous support of [my fans on Patreon.](https://www.patreon.com/ncase) Luv y'all <3 -------------------------------------------------------------------------------- /favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ncase/anxiety-demo/f8460e9659422df706830fa1e941e49af3633e1f/favicon.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Adventures With Anxiety! (Demo) 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 50 | 51 | 52 | 53 | 54 |
55 | 56 | 57 | 58 |
59 |
60 |
61 | 62 | 63 |
64 | 65 |
66 | click anywhere 67 |
68 | 69 |
70 |
71 |
72 | 73 | 74 | 79 | 84 | 85 | 86 |
87 |
88 | paused 89 |
click anywhere to keep freaking out
90 |
91 |
92 | 93 | 94 |
95 |
96 |
97 |
98 |
99 |
100 | 101 | 102 |
103 |
104 |
105 | 106 | Augh games take so long to make! 107 | This one will be done August 2019, and released for free. 108 | 109 | 110 | This is a demo for my upcoming story-game, 111 | which will be released for free in August 2019. 112 | 113 | Get notified via my (once-a-month) newsletter! 114 |
115 |
116 | 117 | 118 |
119 | 120 | 123 | 124 |
125 | 126 | 127 | 128 | 129 | 130 | 131 |
132 |
133 | 134 |
135 | 136 |
137 |
138 | 139 |
140 | Help me keep making free games? 141 |
142 | 143 |
144 |
145 | 146 |
147 | A share on an anxiety-app helps too! 148 |
149 | 162 | 163 |
164 | 165 | Above all, thank you for playing! <3 166 |
167 | 168 | my other games 169 | 170 | · 171 | 172 | my twitter 173 | 174 | 175 |
176 | 177 |
178 |
close
179 | 180 |
181 |
182 | 183 | 184 |
185 |
186 |
187 | 188 |
189 |
190 | And advance 191 |
on click
192 |
193 |
194 | 195 |
Volume:
196 | 197 |
198 |
199 | ok
200 |
201 |
202 | 203 |
204 | 205 | 206 |
207 | 208 | Created by 209 | 210 | Nicky Case 211 | 212 |
213 | 214 | Music 215 | 216 | by Komiku 217 | 218 |
219 | 220 | See 221 | 222 | source code & full credits 223 | 224 |
225 |
226 | 227 | Thank you playtesters! 228 | 229 |

230 | 231 | B Cavello 232 |
233 | EmilyKate McDonough 234 |
235 | Glen Chiacchieri 236 |
237 | Mikayla Hutchinson 238 |
239 | Monica Srivastava 240 |
241 | Rowan 242 |
243 | Srini Kadamati 244 | 245 | 246 |
247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | -------------------------------------------------------------------------------- /scenes/PROMO.md: -------------------------------------------------------------------------------- 1 | # intro 2 | 3 | `SceneSetup.intro();` 4 | 5 | # intro-play-button 6 | 7 | [
PLAY!
](#intro-start) `publish("intro-to-game-1"); Game.OVERRIDE_CHOICE_LINE=true;` 8 | 9 | # intro-start 10 | 11 | (...500) 12 | 13 | `clearText()` 14 | 15 | n3: derp 16 | 17 | `publish("show_options_bottom")` 18 | 19 | # intro-start-2 20 | 21 | `clearText()` 22 | 23 | (...1000) 24 | 25 | `publish("intro-to-game-2")` 26 | 27 | n2: THIS IS A HUMAN 28 | 29 | (...600) 30 | 31 | `clearText()` 32 | 33 | (...300) 34 | 35 | `publish("intro-to-game-3")` 36 | 37 | # act1 38 | 39 | `SceneSetup.act1();` 40 | 41 | (...300) 42 | 43 | n: AND THIS IS THE HUMAN'S ANXIETY 44 | 45 | n: _YOU_ ARE THE ANXIETY 46 | 47 | [You're eating alone for lunch! Again!](#act1a_alone) 48 | 49 | [You're not productive while eating!](#act1a_productive) 50 | 51 | [That white bread's bad for you!](#act1a_bread) 52 | 53 | # act1a_alone 54 | 55 | `bb({mouth:"small", eyes:"narrow"})` 56 | 57 | b: Don't you know loneliness is associated with premature death as much as smoking 15 cigarettes a day?- 58 | 59 | `Game.OVERRIDE_TEXT_SPEED = 2;` 60 | 61 | `bb({mouth:"normal", eyes:"normal_right"})` 62 | 63 | b: (Holt-Lunstad et al, 2010, PLoS Medicine) 64 | 65 | `hong({mouth:"0_neutral", eyes:"0_annoyed"})` 66 | 67 | h: Um, thanks for citing your sources but-- 68 | 69 | `Game.OVERRIDE_TEXT_SPEED = 2;` 70 | 71 | `bb({body:"fear", mouth:"normal", eyes:"fear"})` 72 | 73 | b: Which means if you don't hang out with someone *right now* you're gonna- 74 | 75 | `bb({body:"panic"})` 76 | 77 | b: DIEEEEEEEEEEEEEEEEEEE 78 | 79 | ``` 80 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 81 | hong({mouth:"0_shock", eyes:"0_shock"}); 82 | attack("20p", "alone"); 83 | publish("hp_show"); 84 | ``` 85 | 86 | (...2500) 87 | -------------------------------------------------------------------------------- /scenes/act1.md: -------------------------------------------------------------------------------- 1 | # act1 2 | 3 | `SceneSetup.act1();` 4 | 5 | (...300) 6 | 7 | n: AND THIS IS THE HUMAN'S ANXIETY 8 | 9 | n: _YOU_ ARE THE ANXIETY 10 | 11 | `hong({mouth:"0_neutral", eyes:"0_annoyed"})` 12 | 13 | h: Oh good, I was hoping to *not* eat in peace today. 14 | 15 | `hong({eyes:"0_neutral"})` 16 | 17 | n: YOUR JOB IS TO PROTECT YOUR HUMAN FROM *DANGER* 18 | 19 | `bb({eyes:"look", mouth:"small_lock"})` 20 | 21 | n: IN FACT, THAT SANDWICH IS PUTTING THEM IN *DANGER* RIGHT NOW 22 | 23 | n: QUICK, WARN THEM! 24 | 25 | `bb({eyes:"normal", mouth:"normal"})` 26 | 27 | `Game.OVERRIDE_TEXT_SPEED = 1.25;` 28 | 29 | n4: (LET _YOUR_ ANXIETY COME OUT TO PLAY! PICK WHAT _YOUR_ FEAR WOULD MOST LIKELY SAY TO YOU) 30 | 31 | [You're eating alone for lunch! Again!](#act1a_alone) 32 | 33 | [You're not productive while eating!](#act1a_productive) 34 | 35 | [That white bread's bad for you!](#act1a_bread) 36 | 37 | # act1a_alone 38 | 39 | `bb({mouth:"small", eyes:"narrow"})` 40 | 41 | b: Don't you know loneliness is associated with premature death as much as smoking 15 cigarettes a day?- 42 | 43 | `Game.OVERRIDE_TEXT_SPEED = 2;` 44 | 45 | `bb({mouth:"normal", eyes:"normal_right"})` 46 | 47 | b: (Holt-Lunstad et al, 2010, PLoS Medicine) 48 | 49 | `hong({eyes:"0_annoyed"})` 50 | 51 | h: Um, thanks for citing your sources but-- 52 | 53 | `Game.OVERRIDE_TEXT_SPEED = 2;` 54 | 55 | `bb({body:"fear", mouth:"normal", eyes:"fear"})` 56 | 57 | b: Which means if you don't hang out with someone *right now* you're gonna- 58 | 59 | `bb({body:"panic"})` 60 | 61 | b: DIEEEEEEEEEEEEEEEEEEE 62 | 63 | ``` 64 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 65 | hong({mouth:"0_shock", eyes:"0_shock"}); 66 | attack("20p", "alone"); 67 | publish("hp_show"); 68 | ``` 69 | 70 | (...2500) 71 | 72 | `_.fifteencigs = true` 73 | 74 | n: YOU USED *FEAR OF BEING UNLOVED* 75 | 76 | (#act1b) 77 | 78 | # act1a_productive 79 | 80 | b: Whip out your laptop and do some work right now! 81 | 82 | `hong({eyes:"0_annoyed"})` 83 | 84 | h: Um, I'd rather not get crumbs in my keyboa-- 85 | 86 | ``` 87 | bb({mouth:"normal", eyes:"fear"}); 88 | Game.OVERRIDE_TEXT_SPEED = 1.5; 89 | ``` 90 | 91 | b: If you're not productive you'll become a penniless parasite and your parents will say 92 | 93 | `bb({mouth:"small", eyes:"narrow"})` 94 | 95 | b: “you have brought dishonor to our family, now we have to all commit seppuku” 96 | 97 | ``` 98 | bb({body:"fear", mouth:"normal", eyes:"fear"}); 99 | Game.OVERRIDE_TEXT_SPEED = 1.5; 100 | ``` 101 | 102 | b: and then you'll- 103 | 104 | `bb({body:"panic"})` 105 | 106 | b: DIEEEEEEEEEEEEEEEEEEE 107 | 108 | ``` 109 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 110 | hong({mouth:"0_shock", eyes:"0_shock"}); 111 | attack("20p", "bad"); 112 | publish("hp_show"); 113 | ``` 114 | 115 | (...2500) 116 | 117 | `_.seppuku = true` 118 | 119 | n: YOU USED *FEAR OF BEING A BAD PERSON* 120 | 121 | (#act1b) 122 | 123 | # act1a_bread 124 | 125 | `hong({eyes:"0_annoyed"})` 126 | 127 | h: Have those studies been replicat-- 128 | 129 | ``` 130 | bb({body:"fear", mouth:"normal", eyes:"fear"}); 131 | Game.OVERRIDE_TEXT_SPEED = 1.5; 132 | ``` 133 | 134 | b: Processed wheat will spike your blood sugar so they'll have to amputate all your limbs and then you'll- 135 | 136 | `bb({body:"panic"})` 137 | 138 | b: DIEEEEEEEEEEEEEEEEEEE 139 | 140 | ``` 141 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 142 | hong({mouth:"0_shock", eyes:"0_shock"}); 143 | attack("20p", "harm"); 144 | publish("hp_show"); 145 | ``` 146 | 147 | (...2500) 148 | 149 | `_.whitebread = true` 150 | 151 | n: YOU USED *FEAR OF BEING HARMED* 152 | 153 | (#act1b) 154 | 155 | # act1b 156 | 157 | n: IT'S SUPER EFFECTIVE 158 | 159 | `bb({mouth:"smile", eyes:"smile"});` 160 | 161 | b: I am best protector! 162 | 163 | n: BUT YOU'RE NOT DONE SAVING YOUR HUMAN YET 164 | 165 | n: GET YOUR HUMAN'S ENERGY BAR EMPTY 166 | 167 | n: TO PROTECT YOUR HUMAN'S PHYSICAL + SOCIAL + MORAL NEEDS, YOU CAN USE: 168 | 169 | n: FEAR OF *BEING HARMED* #harm# 170 | 171 | n: FEAR OF *BEING UNLOVED* #alone# 172 | 173 | n: AND FEAR OF *BEING A BAD PERSON* #bad# 174 | 175 | `Game.OVERRIDE_TEXT_SPEED = 1.25;` 176 | 177 | n4: (PRO-TIP: PLAY THE CHOICES THAT PERSONALLY HIT YOUR DEEPEST, DARKEST FEARS~) 178 | 179 | h: ... 180 | 181 | ``` 182 | hong({body:"putaway"}); 183 | sfx("rustle"); 184 | ``` 185 | 186 | (...1000) 187 | 188 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 189 | 190 | h: you know what maybe it's time to check my phone. 191 | 192 | ``` 193 | sfx("rustle2"); 194 | hong({body:"phone1", mouth:"neutral", eyes:"neutral"}) 195 | ``` 196 | 197 | n: PROTECT YOUR HUMAN 198 | 199 | n: FROM THE WORLD. FROM OTHER PEOPLE. FROM THEMSELF. 200 | 201 | n: GOOD LUCK 202 | 203 | (...500) 204 | 205 | `Game.clearText()` 206 | 207 | (...500) 208 | 209 | (#act1c) 210 | 211 | # act1c 212 | 213 | `music('battle', {volume:0.5})` 214 | 215 | n: ROUND ONE: *FIGHT!* 216 | 217 | `bb({body:"normal", mouth:"normal", eyes:"normal"});` 218 | 219 | h: Huh. Facebook feed says there's a party happening this weekend. 220 | 221 | `bb({eyes:"uncertain"});` 222 | 223 | b: Doesn't that weirdo throw a party *every* weekend? 224 | 225 | `bb({eyes:"uncertain_right"});` 226 | 227 | b: Must be some underlying neurosis there. 228 | 229 | `hong({eyes:"surprise"});` 230 | 231 | h: Also, I got an invite? 232 | 233 | `bb({eyes:"narrow", mouth:"normal"});` 234 | 235 | b: Well then! 236 | 237 | [Say yes, or you'll die from loneliness](#act1c_loner) 238 | 239 | [Say no, it's probably full of lethal drugs](#act1c_drugs) 240 | 241 | [Ignore it, you just make parties sad](#act1c_sad) 242 | 243 | # act1c_loner 244 | 245 | {{if _.fifteencigs}} 246 | b: Fifteen cigarettes a day, human. Fifteen. 247 | {{/if}} 248 | 249 | {{if !_.fifteencigs}} 250 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 251 | {{/if}} 252 | 253 | {{if !_.fifteencigs}} 254 | b: Then no one will show up at your funeral, they'll dump your ashes into the ocean, and you become WHALE POOP. 255 | {{/if}} 256 | 257 | {{if !_.fifteencigs}} `_.whalepoop = true` {{/if}} 258 | 259 | (...500) 260 | 261 | ``` 262 | hong({mouth:"shock", eyes:"shock"}); 263 | attack("10p", "alone"); 264 | ``` 265 | 266 | (...2500) 267 | 268 | `bb({eyes:"normal"});` 269 | 270 | {{if !_.fifteencigs}} 271 | b: So yeah you should go to that party. 272 | {{/if}} 273 | 274 | {{if _.seppuku}} 275 | b: Just bring your laptop so you can do some work. 276 | {{/if}} 277 | 278 | {{if _.whitebread}} 279 | b: Just as long as they don't serve WHITE BREAD 280 | {{/if}} 281 | 282 | `hong({mouth:"anger", eyes:"anger"});` 283 | 284 | h: GOD. If it'll make you shut up, fine. 285 | 286 | h: I'll say yes. 287 | 288 | {{if _.whalepoop}} 289 | b: Whale poop, human. Whale poop. 290 | {{/if}} 291 | 292 | `_.partyinvite="yes"` 293 | 294 | (#act1d) 295 | 296 | # act1c_drugs 297 | 298 | `bb({mouth:"small", eyes:"fear"});` 299 | 300 | {{if _.whitebread}} 301 | b: or even worse... WHITE BREAD 302 | {{/if}} 303 | 304 | {{if _.whitebread}} 305 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 306 | {{/if}} 307 | 308 | {{if _.whitebread}} 309 | b: You'll overdose on so much meth and white bread they won't be able to fit your fat corpse into the cremation furnace! 310 | {{/if}} 311 | 312 | {{if !_.whitebread}} 313 | b: You'll overdose on so many drugs the undertaker will wonder how your body was *already* pre-embalmed! 314 | {{/if}} 315 | 316 | ``` 317 | hong({mouth:"shock", eyes:"shock"}); 318 | attack("10p", "harm"); 319 | ``` 320 | 321 | (...2500) 322 | 323 | {{if _.seppuku}} 324 | b: Besides, can't party, you need to do work so your parents don't commit seppuku. 325 | {{/if}} 326 | 327 | `hong({mouth:"anger", eyes:"anger"});` 328 | 329 | h: GOD. If it'll make you shut up, fine. 330 | 331 | h: I'll say no. 332 | 333 | `_.partyinvite="no"` 334 | 335 | (#act1d) 336 | 337 | # act1c_sad 338 | 339 | `bb({eyes:"uncertain_right", mouth:"normal"});` 340 | 341 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 342 | 343 | {{if _.fifteencigs}} 344 | b: All you ever do is cry in a corner about how loneliness is as deadly as 15 cigarettes a day. 345 | {{/if}} 346 | 347 | {{if _.seppuku}} 348 | b: All you ever do at parties is worry about how you should be doing work instead. 349 | {{/if}} 350 | 351 | {{if _.whitebread}} 352 | b: All you ever do is worry about how the unhealthy food options are going to kill you. 353 | {{/if}} 354 | 355 | ``` 356 | bb({mouth:"normal", eyes:"normal"}); 357 | hong({mouth:"neutral", eyes:"lookaway"}); 358 | ``` 359 | 360 | h: gee i wonder why 361 | 362 | `hong({eyes:"neutral"});` 363 | 364 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 365 | 366 | b: So if you go you'll make them feel bad, but if you reject their invite you'll also make them feel bad! 367 | 368 | `bb({body:"fear", eyes:"fear"});` 369 | 370 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 371 | 372 | b: ALL YOU DO IS MAKE PEOPLE FEEL BAD, SO YOU SHOULD FEEL BAD 373 | 374 | ``` 375 | hong({mouth:"shock", eyes:"shock"}); 376 | attack("10p", "bad"); 377 | ``` 378 | 379 | (...2500) 380 | 381 | `hong({mouth:"anger", eyes:"anger"});` 382 | 383 | h: Ugh. If it'll make you shut up, fine. 384 | 385 | h: I'll ignore the invite. 386 | 387 | `_.partyinvite="ignore"` 388 | 389 | (#act1d) 390 | 391 | # act1d 392 | 393 | ``` 394 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 395 | hong({mouth:"neutral", eyes:"annoyed"}); 396 | ``` 397 | 398 | h: Anyway. Facebook's too much. I need something calmer, less anxiety-producing. 399 | 400 | `hong({eyes:"neutral"});` 401 | 402 | h: What's new on Twitter? 403 | 404 | `bb({eyes:"look"});` 405 | 406 | [Oh no, look at that horrible news story!](#act1d_news) 407 | 408 | [Oh no, is that tweet secretly about *you?*](#act1d_subtweet) 409 | 410 | [hey, a GIF of a cat drinking milk](#act1d_milk) 411 | 412 | 413 | # act1d_news 414 | 415 | ``` 416 | bb({eyes:"pained1"}); 417 | music(null, {fade:2}); 418 | ``` 419 | 420 | b: God, it feels like the world's burning, isn't it? 421 | 422 | ``` 423 | bb({eyes:"pained2"}); 424 | hong({mouth:"sad", eyes:"sad"}); 425 | ``` 426 | 427 | b: It feels like it's all ending, like everything's dying and we're doomed and there's nothing we can do about it. 428 | 429 | ``` 430 | Game.OVERRIDE_TEXT_SPEED = 0.5; 431 | bb({mouth:"shut"}); 432 | ``` 433 | 434 | b: ... 435 | 436 | `bb({mouth:"smile", eyes:"smile"});` 437 | 438 | b: Let's retweet that story! 439 | 440 | ``` 441 | hong({mouth:"shock", eyes:"shock"}); 442 | attack("10p", "harm"); 443 | ``` 444 | 445 | (...2500) 446 | 447 | `_.badnews=true` 448 | 449 | ``` 450 | music('battle', {volume:0.5}); 451 | hong({mouth:"anger", eyes:"anger"}); 452 | bb({body:"normal", mouth:"normal", eyes:"uncertain"}); 453 | Game.OVERRIDE_TEXT_SPEED = 1.5; 454 | ``` 455 | 456 | h: Okay I'll retweet it just please be quiet! 457 | 458 | `hong({mouth:"neutral", eyes:"annoyed"});` 459 | 460 | h: Screw it, let's look at Snapchat. 461 | 462 | (#act1e) 463 | 464 | 465 | # act1d_subtweet 466 | 467 | `bb({eyes:"fear"});` 468 | 469 | b: It's a subtweet! A sneaky, sneaky subtweet! 470 | 471 | `hong({eyes:"annoyed"});` 472 | 473 | h: It's probably not? 474 | 475 | `bb({eyes:"narrow", mouth:"small"});` 476 | 477 | b: but what if they're all talking behind your back 478 | 479 | h: They're n-- 480 | 481 | `bb({body:"fear", eyes:"fear", mouth:"normal"});` 482 | 483 | b: IN FRONT OF YOUR BACK 484 | 485 | `hong({eyes:"sad", mouth:"sad"});` 486 | 487 | h: I d-- 488 | 489 | `bb({eyes:"narrow", mouth:"small"});` 490 | 491 | b: but *what if* 492 | 493 | h: S-- 494 | 495 | `bb({eyes:"narrow_eyebrow"});` 496 | 497 | b: *what if* 498 | 499 | ``` 500 | Game.OVERRIDE_TEXT_SPEED = 0.5; 501 | hong({mouth:"shut"}); 502 | ``` 503 | 504 | h: ... 505 | 506 | (...1000) 507 | 508 | ``` 509 | hong({mouth:"shock", eyes:"shock"}); 510 | attack("10p", "alone"); 511 | ``` 512 | 513 | (...2500) 514 | 515 | `_.subtweet=true` 516 | 517 | ``` 518 | hong({mouth:"anger", eyes:"annoyed"}); 519 | bb({body:"normal", mouth:"normal", eyes:"uncertain"}); 520 | ``` 521 | 522 | h: o-KAY, gonna try Snapchat. 523 | 524 | (#act1e) 525 | 526 | # act1d_milk 527 | 528 | `hong({mouth:"smile", eyes:"neutral"});` 529 | 530 | h: Heh ya that's cute, just retweeted it, I thi-- 531 | 532 | ``` 533 | hong({mouth:"shock", eyes:"shock"}); 534 | bb({body:"scream_anger"}); 535 | Game.OVERRIDE_TEXT_SPEED = 1.8; 536 | ``` 537 | 538 | b: CATS CAN'T DIGEST MILK AND YOU'RE A TERRIBLE PERSON FOR ENJOYING ANIMAL ABUSE 539 | 540 | ``` 541 | bb({body:"normal", mouth:"normal", eyes:"narrow"}); 542 | attack("10p", "bad"); 543 | ``` 544 | 545 | (...2500) 546 | 547 | 548 | `_.catmilk=true` 549 | 550 | ``` 551 | hong({mouth:"anger", eyes:"annoyed"}); 552 | bb({body:"normal", mouth:"normal", eyes:"uncertain"}); 553 | ``` 554 | 555 | h: o-KAY, gonna try Snapchat. 556 | 557 | (#act1e) 558 | 559 | # act1e 560 | 561 | `hong({mouth:"neutral", eyes:"neutral"});` 562 | 563 | h: Huh, photos from yesterday night. So *that's* what those weekly parties are like. 564 | 565 | {{if _.partyinvite=="yes"}} (#act1e_said_yes) {{/if}} 566 | 567 | {{if _.partyinvite=="no"}} (#act1e_said_no) {{/if}} 568 | 569 | {{if _.partyinvite=="ignore"}} (#act1e_said_ignore) {{/if}} 570 | 571 | # act1e_said_yes 572 | 573 | `hong({mouth:"sad", eyes:"annoyed"});` 574 | 575 | h: Oof, looks way too crowded for my anxiety. 576 | 577 | h: Maybe I shouldn't have said yes to the invite? 578 | 579 | ``` 580 | hong({mouth:"neutral", eyes:"neutral"}); 581 | bb({mouth:"normal", eyes:"normal"}); 582 | ``` 583 | 584 | [Change your answer? You unreliable jerk!](#act1e_yes_dontchange) 585 | 586 | [Change your answer! It's too crowded!](#act1e_yes_changetono) 587 | 588 | {{if _.subtweet}} 589 | [yeah they were totally subtweeting you](#act1e_ignore_subtweet) 590 | {{/if}} 591 | 592 | {{if _.badnews}} 593 | [wait you retweeted that story without fact-checking](#act1e_ignore_factcheck) 594 | {{/if}} 595 | 596 | {{if (!_.subtweet && !_.badnews)}} 597 | [You know, you've got really bad posture?](#act1e_ignore_posture) 598 | {{/if}} 599 | 600 | # act1e_yes_dontchange 601 | 602 | ``` 603 | bb({eyes:"anger"}); 604 | Game.OVERRIDE_TEXT_SPEED = 1.5; 605 | ``` 606 | 607 | b: They were counting on you to come and now you're betraying their trust? Do you wanna die alone?! 608 | 609 | {{if _.fifteencigs}} 610 | b: FIFTEEN. CIGARETTES. 611 | {{/if}} 612 | 613 | {{if _.whalepoop}} 614 | b: WHALE. POOP. 615 | {{/if}} 616 | 617 | ``` 618 | hong({mouth:"shock", eyes:"shock"}); 619 | attack("10p", "alone"); 620 | ``` 621 | 622 | (...2500) 623 | 624 | ``` 625 | hong({mouth:"anger", eyes:"anger"}); 626 | Game.OVERRIDE_TEXT_SPEED = 1.5; 627 | ``` 628 | 629 | h: Shut up shut up I'll keep it as yes! 630 | 631 | (#act1f) 632 | 633 | # act1e_yes_changetono 634 | 635 | ``` 636 | bb({eyes:"fear"}); 637 | Game.OVERRIDE_TEXT_SPEED = 1.5; 638 | ``` 639 | 640 | b: Don't you know about human stampedes? 641 | 642 | ``` 643 | bb({body:"fear", mouth:"small", eyes:"narrow"}); 644 | hong({eyes:"sad", mouth:"sad"}); 645 | Game.OVERRIDE_TEXT_SPEED = 1.5; 646 | ``` 647 | 648 | b: In 2003 a Rhode Island nightclub had a fire and the panic made people jam the exits so 100 people burned to death- 649 | 650 | ``` 651 | bb({body:"normal", mouth:"normal", eyes:"fear"}); 652 | hong({mouth:"shock"}); 653 | Game.OVERRIDE_TEXT_SPEED = 1.5; 654 | ``` 655 | 656 | b: DO YOU WANT THAT TO HAPPEN TO YOU- 657 | 658 | ``` 659 | bb({body:"scream"}); 660 | Game.OVERRIDE_TEXT_SPEED = 2.5; 661 | ``` 662 | 663 | b: SAY NO SAY NO SAY NO SAY NO SAY NO SAY NO SAY NO SAY NO SAY N- 664 | 665 | 666 | ``` 667 | bb({body:"normal", eyes:"fear", mouth:"normal"}); 668 | hong({mouth:"shock", eyes:"shock"}); 669 | attack("10p", "harm"); 670 | ``` 671 | 672 | (...2500) 673 | 674 | ``` 675 | hong({eyes:"anger", mouth:"anger"}); 676 | Game.OVERRIDE_TEXT_SPEED = 1.5; 677 | ``` 678 | 679 | h: Shut up shut up I'll change my answer to no! God! 680 | 681 | (#act1f) 682 | 683 | # act1e_said_no 684 | 685 | `hong({mouth:"sad", eyes:"sad"});` 686 | 687 | h: Hm... that looks really fun. 688 | 689 | h: Maybe I shouldn't have said no to the invite? 690 | 691 | `bb({mouth:"normal", eyes:"normal"});` 692 | 693 | [Change your answer? You unreliable jerk!](#act1e_no_dontchange) 694 | 695 | [Change your answer! Don't die alone!](#act1e_no_changetoyes) 696 | 697 | {{if _.subtweet}} 698 | [yeah they were totally subtweeting you](#act1e_ignore_subtweet) 699 | {{/if}} 700 | 701 | {{if _.badnews}} 702 | [wait you retweeted that story without fact-checking](#act1e_ignore_factcheck) 703 | {{/if}} 704 | 705 | {{if (!_.subtweet && !_.badnews)}} 706 | [You know, you've got really bad posture?](#act1e_ignore_posture) 707 | {{/if}} 708 | 709 | # act1e_no_dontchange 710 | 711 | `bb({eyes:"anger"})` 712 | 713 | b: Everybody was counting on you! ...to leave them alone and let them have a nice party without you, you horrible disgusting {{if _.whitebread}}white-bread-munching{{/if}} cree-- 714 | 715 | 716 | ``` 717 | hong({mouth:"shock", eyes:"shock"}); 718 | attack("10p", "bad"); 719 | ``` 720 | 721 | (...2500) 722 | 723 | ``` 724 | bb({body:"normal", eyes:"uncertain", mouth:"normal"}); 725 | hong({mouth:"anger", eyes:"anger"}); 726 | Game.OVERRIDE_TEXT_SPEED = 1.5; 727 | ``` 728 | 729 | h: Shut up shut up I'll keep it as no! 730 | 731 | (#act1f) 732 | 733 | # act1e_no_changetoyes 734 | 735 | ``` 736 | bb({body:"fear", eyes:"fear", mouth:"normal"}); 737 | Game.OVERRIDE_TEXT_SPEED = 1.5; 738 | ``` 739 | 740 | b: Chronic loneliness increases your cortisol as well as risk for cardiovascular disease and stroke! 741 | 742 | ``` 743 | hong({mouth:"shock", eyes:"shock"}); 744 | attack("10p", "harm"); 745 | ``` 746 | 747 | (...2500) 748 | 749 | {{if _.fifteencigs}} 750 | b: FIFTEEN. CIGARETTES. 751 | {{/if}} 752 | 753 | ``` 754 | bb({body:"normal", eyes:"normal", mouth:"normal"}); 755 | hong({mouth:"anger", eyes:"anger"}); 756 | Game.OVERRIDE_TEXT_SPEED = 1.5; 757 | ``` 758 | 759 | h: Shut up shut up I'll change my answer to yes! God! 760 | 761 | (#act1f) 762 | 763 | # act1e_ignore_subtweet 764 | 765 | ``` 766 | bb({eyes:"fear", mouth:"small"}); 767 | Game.OVERRIDE_TEXT_SPEED = 1.5; 768 | ``` 769 | 770 | b: All your problematic tweets have come back to roost! 771 | 772 | ``` 773 | bb({body:"fear", eyes:"fear", mouth:"normal"}); 774 | Game.OVERRIDE_TEXT_SPEED = 1.7; 775 | ``` 776 | 777 | b: Say *one* thing wrong and all your so-called friends will drag you through the street for internet points! 778 | 779 | ``` 780 | hong({mouth:"shock", eyes:"shock"}); 781 | attack("10p", "alone"); 782 | ``` 783 | 784 | (...2500) 785 | 786 | ``` 787 | bb({body:"normal", eyes:"normal", mouth:"normal"}); 788 | hong({mouth:"anger", eyes:"anger"}); 789 | Game.OVERRIDE_TEXT_SPEED = 1.5; 790 | ``` 791 | 792 | h: Why are you like this?! 793 | 794 | (#act1f) 795 | 796 | # act1e_ignore_factcheck 797 | 798 | ``` 799 | bb({eyes:"anger"}); 800 | Game.OVERRIDE_TEXT_SPEED = 1.5; 801 | ``` 802 | 803 | b: You're spreading disinformation! 804 | 805 | ``` 806 | bb({body:"scream_anger"}); 807 | Game.OVERRIDE_TEXT_SPEED = 1.5; 808 | ``` 809 | 810 | b: People like you are the reason fascism will arise from the rubble of democracy! 811 | 812 | ``` 813 | bb({body:"normal", eyes:"anger"}); 814 | hong({mouth:"shock", eyes:"shock"}); 815 | attack("10p", "bad"); 816 | ``` 817 | 818 | (...2500) 819 | 820 | ``` 821 | hong({mouth:"anger", eyes:"anger"}); 822 | Game.OVERRIDE_TEXT_SPEED = 1.5; 823 | ``` 824 | 825 | h: Why are you like this?! 826 | 827 | (#act1f) 828 | 829 | # act1e_ignore_posture 830 | 831 | ``` 832 | bb({eyes:"anger"}); 833 | Game.OVERRIDE_TEXT_SPEED = 1.5; 834 | ``` 835 | 836 | b: Do you want to have a pretzel for a spine?! Stop hunching over your screen! 837 | 838 | ``` 839 | bb({body:"meta"}); 840 | ``` 841 | 842 | b: That means you too. 843 | 844 | ``` 845 | bb({body:"normal", mouth:"normal"}); 846 | hong({mouth:"shock", eyes:"shock"}); 847 | attack("10p", "harm"); 848 | ``` 849 | 850 | (...2500) 851 | 852 | ``` 853 | bb({body:"normal", eyes:"normal", mouth:"normal"}); 854 | hong({mouth:"anger", eyes:"anger"}); 855 | Game.OVERRIDE_TEXT_SPEED = 1.5; 856 | ``` 857 | 858 | h: Why are you like this?! 859 | 860 | (#act1f) 861 | 862 | # act1e_said_ignore 863 | 864 | `hong({mouth:"sad", eyes:"sad"});` 865 | 866 | h: Hm... that looks really fun. 867 | 868 | h: Maybe I shouldn't have ignored the invite? 869 | 870 | `bb({mouth:"normal", eyes:"normal"});` 871 | 872 | [Keep ignoring, you're still a party pooper](#act1e_ignore_continue) 873 | 874 | [Actually, say yes.](#act1e_ignore_changetoyes) 875 | 876 | [Actually, say no.](#act1e_ignore_changetono) 877 | 878 | # act1e_ignore_continue 879 | 880 | `hong({eyes:"annoyed"});` 881 | 882 | h: It's kinda rude to keep ignoring them though, no? 883 | 884 | `bb({eyes:"normal_right"});` 885 | 886 | b: Well other people always ignore *you* so 887 | 888 | ``` 889 | hong({mouth:"shock", eyes:"shock"}); 890 | attack("10p", "alone"); 891 | ``` 892 | 893 | (...2500) 894 | 895 | `bb({eyes:"normal"});` 896 | 897 | b: so let's just call it even. 898 | 899 | (#act1f) 900 | 901 | # act1e_ignore_changetoyes 902 | 903 | `hong({eyes:"surprise", mouth:"smile"});` 904 | 905 | h: You're... letting me have fun? 906 | 907 | b: Well, I mean, loneliness *can* kill you. 908 | 909 | `hong({eyes:"neutral", mouth:"neutral"});` 910 | 911 | (#act1e_no_changetoyes) 912 | 913 | # act1e_ignore_changetono 914 | 915 | `bb({eyes:"narrow"});` 916 | 917 | b: It's too crowded. Crowds are dangerous. 918 | 919 | (#act1e_yes_changetono) 920 | 921 | 922 | # act1f 923 | 924 | ``` 925 | hong({mouth:"neutral", eyes:"neutral"}); 926 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 927 | ``` 928 | 929 | h: Whatever. New Tinder notification. 930 | 931 | `bb({eyes:"uncertain"})` 932 | 933 | b: What, that hookup app? 934 | 935 | `hong({eyes:"annoyed"})` 936 | 937 | h: It's not a hookup app, it's just a way to meet new peopl-- 938 | 939 | `bb({eyes:"narrow"})` 940 | 941 | b: It's a hookup app. 942 | 943 | `hong({eyes:"surprise", mouth:"smile"})` 944 | 945 | h: Oh, I got a match! They look cute! 946 | 947 | ``` 948 | bb({eyes:"narrow_eyebrow"}); 949 | hong({eyes:"sad", mouth:"anger"}) 950 | ``` 951 | 952 | h: Please don't ruin this for m-- 953 | 954 | ``` 955 | bb({body:"panic"}); 956 | Game.OVERRIDE_TEXT_SPEED = 2.0; 957 | ``` 958 | 959 | b: DANGER DANGER DANGER DANGER DANGER DANGER 960 | 961 | `bb({body:"fear", eyes:"fear", mouth:"normal"})` 962 | 963 | [You're being *used* by other people.](#act1f_used_by_others) 964 | 965 | [You're just *using* other people.](#act1f_using_others) 966 | 967 | [YOUR MATCH IS A SERIAL KILLER](#act1f_killer) 968 | 969 | # act1f_used_by_others 970 | 971 | `bb({body:"point_crotch", eyes:"normal", mouth:"normal"})` 972 | 973 | b: Random hookups may be able to fill the hole down there 974 | 975 | b: but they can never fill the hole 976 | 977 | `bb({body:"point_heart", eyes:"pretty", mouth:"small"})` 978 | 979 | b: in *here*. 980 | 981 | (...3000) 982 | 983 | ``` 984 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 985 | Game.OVERRIDE_TEXT_SPEED = 1.5; 986 | ``` 987 | 988 | b: Point is you're gonna die alone 989 | 990 | ``` 991 | hong({mouth:"shock", eyes:"shock"}); 992 | attack("30p", "alone"); 993 | ``` 994 | 995 | (...2500) 996 | 997 | `_.hookuphole=true` 998 | 999 | (#act1g) 1000 | 1001 | # act1f_using_others 1002 | 1003 | `bb({eyes:"narrow", mouth:"small"})` 1004 | 1005 | b: You think other people's genitals are Pokémon for you to collect? 1006 | 1007 | ``` 1008 | bb({body:"sing", eyes:"pretty", mouth:"shut"}); 1009 | music("pokemon"); 1010 | Game.clearText(); 1011 | Game.FORCE_CANT_SKIP = true; 1012 | ``` 1013 | 1014 | ``` 1015 | Game.FORCE_TEXT_DURATION = 1000; 1016 | Game.FORCE_NO_VOICE = true; 1017 | ``` 1018 | 1019 | b: ♫ (pokemon theme song)- 1020 | 1021 | (...5600) 1022 | 1023 | ``` 1024 | bb({mouth:"normal"}); 1025 | Game.FORCE_TEXT_DURATION = 2400; 1026 | ``` 1027 | 1028 | b: ♫ I wanna be, the slutti-est- 1029 | 1030 | (...500) 1031 | 1032 | ``` 1033 | bb({eyes:"narrow", mouth:"small"}); 1034 | Game.FORCE_TEXT_DURATION = 2100; 1035 | ``` 1036 | 1037 | b: ♫ Like no one ever was- 1038 | 1039 | (...1500) 1040 | 1041 | ``` 1042 | bb({eyes:"pretty"}); 1043 | Game.FORCE_TEXT_DURATION = 2300; 1044 | ``` 1045 | 1046 | b: ♫ Thighs n' ass, voluptuous breast- 1047 | 1048 | (...500) 1049 | 1050 | ``` 1051 | bb({eyes:"fear", mouth:"normal"}); 1052 | Game.FORCE_TEXT_DURATION = 2000; 1053 | ``` 1054 | 1055 | b: ♫ with sweaty dick and balls!- 1056 | 1057 | (...1000) 1058 | 1059 | ``` 1060 | bb({eyes:"smile", mouth:"smile"}); 1061 | Game.FORCE_TEXT_DURATION = 1000; 1062 | ``` 1063 | 1064 | b: ♫ PERVY-MON! GOTTA CA- 1065 | 1066 | ``` 1067 | Game.FORCE_CANT_SKIP = false; 1068 | Game.clearText(); 1069 | music(false); 1070 | bb({body:"normal", mouth:"normal", eyes:"normal"}); 1071 | Game.OVERRIDE_TEXT_SPEED = 1.5; 1072 | ``` 1073 | 1074 | b: Point is you're a manipulative creep 1075 | 1076 | ``` 1077 | hong({mouth:"shock", eyes:"shock"}); 1078 | attack("30p", "bad"); 1079 | ``` 1080 | 1081 | (...2500) 1082 | 1083 | `_.pokemon=true` 1084 | 1085 | (#act1g) 1086 | 1087 | # act1f_killer 1088 | 1089 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 1090 | 1091 | {{if _.whitebread}} 1092 | b: They'll trap you in a well and force-feed you white bread to fatten you up so they can wear your skin like a suit! 1093 | {{/if}} 1094 | 1095 | {{if _.seppuku}} 1096 | b: They'll bludgeon you with a pomodoro timer and slice your belly open and say "this is what slackers get, SEPUKKU'D" 1097 | {{/if}} 1098 | 1099 | {{if !_.whitebread && !_.seppuku}} 1100 | b: They'll tear your flesh to gory confetti, turn your entrails into streamers, and mix your blood into a punch bowl! 1101 | {{/if}} 1102 | 1103 | {{if !_.whitebread && !_.seppuku}} 1104 | b: How's THAT for a party invite?! 1105 | {{/if}} 1106 | 1107 | ``` 1108 | hong({mouth:"shock", eyes:"shock"}); 1109 | attack("30p", "harm"); 1110 | ``` 1111 | 1112 | (...2500) 1113 | 1114 | `_.serialkiller=true` 1115 | 1116 | (#act1g) 1117 | 1118 | # act1g 1119 | 1120 | ``` 1121 | bb({body:"normal", mouth:"normal", eyes:"look"}); 1122 | hong({body:"2_tired"}); 1123 | Game.OVERRIDE_TEXT_SPEED = 0.5; 1124 | music(false); 1125 | ``` 1126 | 1127 | h: ... 1128 | 1129 | (...500) 1130 | 1131 | h: i'm so sick of this game. 1132 | 1133 | (...700) 1134 | 1135 | `Game.OVERRIDE_TEXT_SPEED = 1.5;` 1136 | 1137 | h: 1138 | {{if _.fifteencigs}}"loneliness will kill you"... {{/if}} 1139 | {{if _.seppuku}}"be productive or you'll be dishonored"... {{/if}} 1140 | {{if _.whitebread}}"don't eat that, it'll kill you"... {{/if}} 1141 | {{if _.subtweet}}"they're talking behind your back"... {{/if}} 1142 | {{if _.badnews}}"the world is burning"... {{/if}} 1143 | {{if _.hookuphole}}"you'll die alone"... {{/if}} 1144 | {{if _.serialkiller}}"they're a serial killer"... {{/if}} 1145 | {{if _.catmilk}}"cats can't digest milk"... {{/if}} 1146 | {{if _.pokemon}}a crappy parody song... {{/if}} 1147 | 1148 | h: i just want to live my life. 1149 | 1150 | h: i just want to be free from all this... pain. 1151 | 1152 | `bb({eyes:"look_sad"});` 1153 | 1154 | b: Hey... human... 1155 | 1156 | `Game.OVERRIDE_TEXT_SPEED = 0.5;` 1157 | 1158 | b: It'll be okay. 1159 | 1160 | (...600) 1161 | 1162 | `bb({body:"point_heart", eyes:"look_sad_smile", mouth:"smile"});` 1163 | 1164 | b: As your loyal protector, I'll always keep an eye out for danger, and do my best to keep you safe. 1165 | 1166 | `bb({body:"normal", eyes:"look_sad", mouth:"smile"});` 1167 | 1168 | b: I promise. 1169 | 1170 | (...600) 1171 | 1172 | ``` 1173 | bb({body:"normal", eyes:"normal", mouth:"normal"}); 1174 | hong({body:"phone1", eyes:"neutral", mouth:"neutral"}); 1175 | ``` 1176 | 1177 | h: Last app. Instagram. What you got? 1178 | 1179 | `hong({eyes:"sad"});` 1180 | 1181 | h: It's... more party pictures. 1182 | 1183 | `hong({mouth:"sad"});` 1184 | 1185 | h: Everyone looks so happy. Free from worry. Free from anxiety. 1186 | 1187 | `hong({mouth:"anger"});` 1188 | 1189 | h: God, why can't I be like them? Why can't I just be *normal?* 1190 | 1191 | `bb({eyes:"normal_right"});` 1192 | 1193 | b: Speaking of parties, about this weekend's invite. Here's my FINAL decision: 1194 | 1195 | `bb({eyes:"normal"});` 1196 | 1197 | [You should go.](#act1g_go) `Game.OVERRIDE_CHOICE_LINE=true` 1198 | 1199 | [You should not go.](#act1g_dont) `Game.OVERRIDE_CHOICE_LINE=true` 1200 | 1201 | # act1g_go 1202 | 1203 | `_.act1g = "go"` 1204 | 1205 | (#act1h) 1206 | 1207 | # act1g_dont 1208 | 1209 | `_.act1g = "dont"` 1210 | 1211 | (#act1h) 1212 | 1213 | # act1h 1214 | 1215 | b: You sh-- 1216 | 1217 | ``` 1218 | bb({eyes:"wat", mouth:"small"}); 1219 | hong({body:"2_fuck"}); 1220 | ``` 1221 | 1222 | h: *FUCK.* 1223 | 1224 | `hong({body:"2_you"});` 1225 | 1226 | h: YOU. 1227 | 1228 | (...500) 1229 | 1230 | b: w 1231 | 1232 | (...1500) 1233 | 1234 | `bb({eyes:"wat_2"});` 1235 | 1236 | b: wha? 1237 | 1238 | `hong({body:"phone1", eyes:"anger", mouth:"anger"});` 1239 | 1240 | h: I'm going to say YES to that party 1241 | 1242 | {{if _.act1g=="go"}} 1243 | h: NOT because you want me to, but because *I* want to. 1244 | {{/if}} 1245 | 1246 | {{if _.act1g=="dont"}} 1247 | h: Precisely BECAUSE you don't want me to. 1248 | {{/if}} 1249 | 1250 | ``` 1251 | hong({body:"putaway"}); 1252 | sfx("rustle"); 1253 | ``` 1254 | 1255 | h: You're NOT in control of me. 1256 | 1257 | ``` 1258 | sfx("rustle2"); 1259 | hong({body:"0_sammich", eyes:"0_annoyed", mouth:"0_neutral"}); 1260 | ``` 1261 | 1262 | h: Now excuse me while I eat this delicious sandwich in goddamn peace. 1263 | 1264 | `hong({body:"2_sammich_eat"});` 1265 | 1266 | (...601) 1267 | 1268 | ``` 1269 | sfx("sandwich"); 1270 | hong({body:"2_sammich_eaten", eyes:"0_lookaway", mouth:"0_chew1"}) 1271 | ``` 1272 | 1273 | (...601) 1274 | 1275 | ``` 1276 | bb({body:"normal", eyes:"uncertain", mouth:"shut"}); 1277 | Game.OVERRIDE_TEXT_SPEED = 0.5; 1278 | ``` 1279 | 1280 | b: ... 1281 | 1282 | ``` 1283 | bb({eyes:"normal_right"}); 1284 | Game.OVERRIDE_TEXT_SPEED = 1; 1285 | ``` 1286 | 1287 | b: ... 1288 | 1289 | ``` 1290 | bb({eyes:"fear"}); 1291 | Game.OVERRIDE_TEXT_SPEED = 4; 1292 | ``` 1293 | 1294 | b: .................. 1295 | 1296 | (...500) 1297 | 1298 | `bb({mouth:"normal"});` 1299 | 1300 | [AHHHHH WE'RE GONNA DIE](#act1h_death) `Game.OVERRIDE_CHOICE_LINE = true;` 1301 | 1302 | [AHHHHH EVERYONE HATES US](#act1h_loneliness) `Game.OVERRIDE_CHOICE_LINE = true;` 1303 | 1304 | [AHHHHH WE'RE HORRIBLE PEOPLE](#act1h_worthless) `Game.OVERRIDE_CHOICE_LINE = true;` 1305 | 1306 | # act1h_death 1307 | 1308 | ``` 1309 | bb({body:"fear"}); 1310 | Game.OVERRIDE_TEXT_SPEED = 3; 1311 | ``` 1312 | 1313 | b: AHHHHH WE'RE GONNA DIE AAAAAAHHHHHHH 1314 | 1315 | ``` 1316 | hong({body:"3_defeated1"}); 1317 | attack("100p", "harm"); 1318 | ``` 1319 | 1320 | (...2500) 1321 | 1322 | (#act1i) 1323 | 1324 | # act1h_loneliness 1325 | 1326 | ``` 1327 | bb({body:"fear"}); 1328 | Game.OVERRIDE_TEXT_SPEED = 3; 1329 | ``` 1330 | 1331 | b: AHHHHH EVERYONE HATES US AAAAAAHHHHHHH 1332 | 1333 | ``` 1334 | hong({body:"3_defeated1"}); 1335 | attack("100p", "alone"); 1336 | ``` 1337 | 1338 | (...2500) 1339 | 1340 | (#act1i) 1341 | 1342 | # act1h_worthless 1343 | 1344 | ``` 1345 | bb({body:"fear"}); 1346 | Game.OVERRIDE_TEXT_SPEED = 3; 1347 | ``` 1348 | 1349 | b: AHHHHH WE'RE HORRIBLE PEOPLE AAAAAAHHHHHHH 1350 | 1351 | ``` 1352 | hong({body:"3_defeated1"}); 1353 | attack("100p", "bad"); 1354 | ``` 1355 | 1356 | (...2500) 1357 | 1358 | (#act1i) 1359 | 1360 | # act1i 1361 | 1362 | ``` 1363 | bb({mouth:"smile_lock", eyes:"smile", body:"normal"}); 1364 | music('battle', {volume:0.5}); 1365 | ``` 1366 | 1367 | n: CONGRATULATIONS 1368 | 1369 | (...500) 1370 | 1371 | n: YOU'VE SUCCESSFULLY PROTECTED YOUR HUMAN'S NEEDS FOR SAFETY, LOVE, AND GOODNESS 1372 | 1373 | n: WHY, LOOK HOW GRATEFUL THEY ARE! 1374 | 1375 | (...500) 1376 | 1377 | n: NOW THAT THEIR ENERGY IS ZERO, YOU CAN DIRECTLY CONTROL THEIR ACTIONS 1378 | 1379 | `bb({mouth:"smile", eyes:"normal"});` 1380 | 1381 | n: PICK YOUR ENDING MOVE 1382 | 1383 | `bb({mouth:"normal", eyes:"narrow"});` 1384 | 1385 | n: *FINISH THEM* 1386 | 1387 | [{FIGHT: Punish your stressful phone!}](#act1i_phone) `Game.OVERRIDE_CHOICE_LINE=true` 1388 | 1389 | [{FLIGHT: Curl up in a ball and cry!}](#act1i_cry) `Game.OVERRIDE_CHOICE_LINE=true` 1390 | 1391 | # act1i_phone 1392 | 1393 | `bb({eyes:"anger", mouth:"normal"})` 1394 | 1395 | b: Your phone was giving you a panic attack! 1396 | 1397 | ``` 1398 | bb({body:"fear", eyes:"fear"}); 1399 | hong({body:"3_defeated2"}); 1400 | Game.OVERRIDE_TEXT_SPEED = 1.5; 1401 | ``` 1402 | 1403 | b: Punish it! Destroy your phone! Kill it! 1404 | 1405 | ``` 1406 | Game.OVERRIDE_TEXT_SPEED = 2.5; 1407 | bb({body:"flail"}); 1408 | hong({body:"3_defeated3"}); 1409 | _.act1_ending = "fight"; 1410 | ``` 1411 | 1412 | b: KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL IT KILL I-- 1413 | 1414 | (#act1j) 1415 | 1416 | # act1i_cry 1417 | 1418 | `bb({eyes:"fear"})` 1419 | 1420 | b: The whole world is filled with danger! 1421 | 1422 | ``` 1423 | bb({body:"fear"}); 1424 | hong({body:"3_defeated2"}); 1425 | Game.OVERRIDE_TEXT_SPEED = 1.5; 1426 | ``` 1427 | 1428 | b: Do like the armadillo! Curl up into a ball for self-defense! 1429 | 1430 | ``` 1431 | Game.OVERRIDE_TEXT_SPEED = 2.5; 1432 | bb({body:"flail"}); 1433 | hong({body:"3_defeated3"}); 1434 | _.act1_ending = "flight"; 1435 | ``` 1436 | 1437 | b: CURL UP AND CRY CURL UP AND CRY CURL UP AND CRY CURL UP AND CRY CURL UP AND CRY CURL UP AND CR-- 1438 | 1439 | (#act1j) 1440 | 1441 | # act1j 1442 | 1443 | `SceneSetup.act1_outro()` -------------------------------------------------------------------------------- /scenes/act1_end.md: -------------------------------------------------------------------------------- 1 | # act1_end 2 | 3 | `SceneSetup.act1_end()` 4 | 5 | (...1000) 6 | 7 | `sfx("dramatic");` 8 | 9 | (...1000) 10 | 11 | n: FEARS YOU USED: 12 | 13 | n: #harm# *BEING HARMED:* {{_.attack_harm}} 14 | 15 | n: #alone# *BEING UNLOVED:* {{_.attack_alone}} 16 | 17 | n: #bad# *BEING A BAD PERSON:* {{_.attack_bad}} 18 | 19 | (...3000) 20 | 21 | `Game.clearText()` 22 | 23 | (...2000) 24 | 25 | ``` 26 | publish("TO_BE_CONTINUED"); 27 | sfx("fart"); 28 | ``` 29 | 30 | (...2500) 31 | 32 | `publish("END_OF_DEMO")` -------------------------------------------------------------------------------- /scenes/intro.md: -------------------------------------------------------------------------------- 1 | # intro 2 | 3 | `SceneSetup.intro();` 4 | 5 | # intro-play-button 6 | 7 | `Game.HACK_MAKE_THE_LINE_BIG=true;` 8 | 9 | [
PLAY!
](#intro-start) `publish("intro-to-game-1"); Game.OVERRIDE_CHOICE_LINE=true;` 10 | 11 | # intro-start 12 | 13 | (...500) 14 | 15 | `clearText()` 16 | 17 | n3: Welcome! This is less of a "game", more of an interactive story. Hope you like reading, sucka 18 | 19 | n3: So before we start, how would *you* like to read? 20 | 21 | `publish("show_options_bottom")` 22 | 23 | # intro-start-2 24 | 25 | n3: Great! Note: you can always change text/audio options with the ⚙ icon below. 26 | 27 | n3: Now, let's begin our story... 28 | 29 | `clearText()` 30 | 31 | (...1000) 32 | 33 | `publish("intro-to-game-2")` 34 | 35 | n2: THIS IS A HUMAN 36 | 37 | (...600) 38 | 39 | `clearText()` 40 | 41 | (...300) 42 | 43 | `publish("intro-to-game-3")` -------------------------------------------------------------------------------- /scripts/act1/Act1_Beebee.js: -------------------------------------------------------------------------------- 1 | Loader.addImages([ 2 | { id:"act1_beebee", src:"sprites/act1/act1_beebee.png" } 3 | ]); 4 | 5 | function Act1_Beebee(){ 6 | 7 | var self = this; 8 | 9 | // SPRITE CONFIG! 10 | var spriteConfig = { 11 | image: Library.images.act1_beebee, 12 | grid:{ 13 | width: 4, 14 | height: 8 15 | }, 16 | frame:{ 17 | width: 720, 18 | height: 500 19 | }, 20 | anchor:{ 21 | x: 546/2, 22 | y: 400/2 23 | }, 24 | frameNames:[ 25 | 26 | "body_normal", 27 | "body_fear", 28 | "body_point_crotch", 29 | "body_point_heart", 30 | "body_sing", 31 | 32 | "mouth_normal", 33 | "mouth_normal_talk", 34 | "mouth_small", 35 | "mouth_small_talk", 36 | "mouth_small_lock", 37 | 38 | "eyes_normal", 39 | "eyes_normal_right", 40 | "eyes_uncertain", 41 | "eyes_uncertain_right", 42 | "eyes_narrow", 43 | "eyes_narrow_eyebrow", 44 | "eyes_fear", 45 | "eyes_pretty", 46 | "eyes_wat", 47 | "eyes_wat_2", 48 | 49 | "body_panic*", 50 | "body_panic_2*", 51 | "body_scream_anger*", 52 | "body_scream_anger_2*", 53 | "body_scream*", 54 | "body_scream_2*", 55 | 56 | "body_flail*", 57 | "body_flail2*", 58 | "body_flail3*", 59 | "body_flail4*", 60 | 61 | "mouth_smile", 62 | "mouth_smile_talk", 63 | "mouth_smile_lock", 64 | "eyes_smile", 65 | "eyes_look", 66 | "eyes_look_sad", 67 | "eyes_look_sad_smile", 68 | "eyes_pained1", 69 | "eyes_pained2", 70 | "mouth_shut", 71 | "eyes_anger", 72 | 73 | "body_meta*" 74 | 75 | ], 76 | x: 270-7.5, 77 | y: 390+4.5 78 | }; 79 | 80 | // ANIM LOOPS 81 | var animLoops = [ 82 | { target:"body", ifOnFrame:"panic*", wait:0.07, thenGoToFrame:"panic_2*" }, 83 | { target:"body", ifOnFrame:"panic_2*", wait:0.07, thenGoToFrame:"panic*" }, 84 | 85 | { target:"body", ifOnFrame:"scream_anger*", wait:0.1, thenGoToFrame:"scream_anger_2*" }, 86 | { target:"body", ifOnFrame:"scream_anger_2*", wait:0.1, thenGoToFrame:"scream_anger*" }, 87 | { target:"body", ifOnFrame:"scream*", wait:0.1, thenGoToFrame:"scream_2*" }, 88 | { target:"body", ifOnFrame:"scream_2*", wait:0.1, thenGoToFrame:"scream*" }, 89 | 90 | { target:"body", ifOnFrame:"flail*", wait:0.05, thenGoToFrame:"flail2*" }, 91 | { target:"body", ifOnFrame:"flail2*", wait:0.05, thenGoToFrame:"flail3*" }, 92 | { target:"body", ifOnFrame:"flail3*", wait:0.05, thenGoToFrame:"flail4*" }, 93 | { target:"body", ifOnFrame:"flail4*", wait:0.05, thenGoToFrame:"flail*" } 94 | ]; 95 | 96 | // Inherit from Character! 97 | Character.apply(self, [spriteConfig, animLoops]); 98 | 99 | // Go To Frames! 100 | self.gotoFrames({ 101 | body: "normal", 102 | mouth: "normal", 103 | eyes: "normal", 104 | }); 105 | var _subscriptions = []; 106 | _subscriptions.push( subscribe("bb", self.gotoFrames) ); 107 | 108 | // Draw! Same as earlier except a lot of vibration 109 | var ticker = 0; 110 | var _oldDraw = self.draw; 111 | self.characterSpeakerID = "b"; 112 | self.bounceHookes = 0.25; // loose 113 | self.bounceDamp = 0.9; // loose 114 | self.draw = function(ctx){ 115 | 116 | // Vibration! 117 | ticker += 1/60; 118 | self.characterSquash = 1 + Math.sin(ticker*Math.TAU*7)*0.01; // seven vibes per second 119 | 120 | // Old Draw 121 | _oldDraw.apply(self, arguments); 122 | 123 | }; 124 | ////////////////////////////////////////////////////////////////////////////// 125 | ////////////////////////////////////////////////////////////////////////////// 126 | ////////////////////////////////////////////////////////////////////////////// 127 | 128 | // Kill! 129 | self.kill = function(){ 130 | _subscriptions.forEach(unsubscribe); 131 | }; 132 | 133 | } -------------------------------------------------------------------------------- /scripts/act1/Act1_Hong.js: -------------------------------------------------------------------------------- 1 | Loader.addImages([ 2 | { id:"act1_hong", src:"sprites/act1/act1_hong.png" } 3 | ]); 4 | 5 | function Act1_Hong(){ 6 | 7 | var self = this; 8 | 9 | // SPRITE CONFIG! 10 | var spriteConfig = { 11 | image: Library.images.act1_hong, 12 | grid:{ 13 | width: 4, 14 | height: 10 15 | }, 16 | frame:{ 17 | width: 720, 18 | height: 500 19 | }, 20 | anchor:{ 21 | x: 122/2, 22 | y: 404/2 23 | }, 24 | frameNames:[ 25 | 26 | "body_0_sammich_no_outline", 27 | "body_0_sammich", 28 | "eyes_0_neutral", 29 | "eyes_0_lookaway", 30 | "eyes_0_annoyed", 31 | "eyes_0_shock", 32 | "mouth_0_neutral", 33 | "mouth_0_chew1", 34 | "mouth_0_chew2", 35 | "mouth_0_neutral_talk", 36 | "mouth_0_shock", 37 | 38 | "body_putaway*", 39 | "body_phone1", 40 | "body_phone2", 41 | "eyes_neutral", 42 | "eyes_annoyed", 43 | "eyes_sad", 44 | "eyes_shock", 45 | "eyes_lookaway", 46 | "eyes_anger", 47 | "eyes_surprise", 48 | "mouth_shut", 49 | "mouth_neutral", 50 | "mouth_neutral_talk", 51 | "mouth_smile", 52 | "mouth_smile_talk", 53 | "mouth_sad", 54 | "mouth_sad_talk", 55 | "mouth_shock", 56 | "mouth_anger", 57 | "mouth_anger_talk", 58 | 59 | "body_2_tired*", 60 | "body_2_fuck*", 61 | "body_2_you*", 62 | "body_2_sammich_eat*", 63 | "body_2_sammich_eaten", 64 | 65 | "body_3_defeated1*", 66 | "body_3_defeated2*", 67 | "body_3_defeated3*", 68 | "body_3_defeated3_no_outline*" 69 | 70 | ], 71 | x: 65, 72 | y: 385+14 73 | }; 74 | 75 | // ANIM LOOPS 76 | var animLoops = [ 77 | { target:"body", ifOnFrame:"phone1", wait:1, thenGoToFrame:"phone2" }, 78 | { target:"body", ifOnFrame:"phone2", wait:1, thenGoToFrame:"phone1" }, 79 | { target:"mouth", ifOnFrame:"0_chew1", wait:0.7, thenGoToFrame:"0_chew2" }, 80 | { target:"mouth", ifOnFrame:"0_chew2", wait:0.7, thenGoToFrame:"0_chew1" } 81 | ]; 82 | 83 | // Inherit from Character! 84 | Character.apply(self, [spriteConfig, animLoops]); 85 | 86 | // Go To Frames! 87 | self.gotoFrames({ 88 | body: "0_sammich", 89 | mouth: "0_chew1", 90 | eyes: "0_neutral", 91 | }); 92 | var _subscriptions = []; 93 | _subscriptions.push( subscribe("hong", self.gotoFrames) ); 94 | _subscriptions.push( subscribe("attack_hong", self.showAttackedIcon) ); 95 | 96 | // Draw 97 | self.characterSpeakerID = "h"; 98 | 99 | ////////////////////////////////////////////////////////////////////////////// 100 | ////////////////////////////////////////////////////////////////////////////// 101 | ////////////////////////////////////////////////////////////////////////////// 102 | 103 | // Kill! 104 | self.kill = function(){ 105 | _subscriptions.forEach(unsubscribe); 106 | }; 107 | 108 | } -------------------------------------------------------------------------------- /scripts/act1/Act1_Outro_BG.js: -------------------------------------------------------------------------------- 1 | Loader.addImages([ 2 | { id:"act1_end", src:"sprites/act1/act1_end.png" } 3 | ]); 4 | 5 | Loader.addSounds([ 6 | 7 | { id:"pop", src:"sounds/sfx/pop.mp3" }, 8 | { id:"bounce1", src:"sounds/sfx/bounce1.mp3" }, 9 | { id:"bounce2", src:"sounds/sfx/bounce2.mp3" }, 10 | { id:"bounce3", src:"sounds/sfx/bounce3.mp3" }, 11 | { id:"faucet", src:"sounds/sfx/faucet.mp3" }, 12 | 13 | { id:"dirty_explosion", src:"sounds/sfx/dirty_explosion.mp3" }, 14 | { id:"rustle", src:"sounds/sfx/rustle.mp3" }, 15 | { id:"rustle2", src:"sounds/sfx/rustle2.mp3" }, 16 | { id:"act1_scream", src:"sounds/sfx/act1_scream.mp3" } 17 | 18 | ]); 19 | 20 | function BG_Act1_Outro(){ 21 | 22 | var self = this; 23 | 24 | // Sprites! 25 | self.logoSprite = new Sprite({ 26 | image: Library.images.intro_logo, 27 | grid:{ width:1, height:1 }, 28 | frame:{ width:720, height:900 }, 29 | }); 30 | var spriteConfig = { 31 | image: Library.images.intro_bg, 32 | grid:{ 33 | width: 2, 34 | height: 3 35 | }, 36 | frame:{ 37 | width: 1200, 38 | height: 900 39 | }, 40 | anchor:{ 41 | x: 0, 42 | y: 0 43 | }, 44 | frameNames:[ 45 | "sky", 46 | "clouds", 47 | "buildings", 48 | "grass", 49 | "stump", 50 | "blackout" 51 | ], 52 | x: 0, 53 | y: 0 54 | }; 55 | self.layers = []; 56 | ["sky","clouds","buildings","grass","stump","blackout"].forEach(function(layerName){ 57 | var sprite = new Sprite(spriteConfig); 58 | sprite.gotoFrameByName(layerName); 59 | self.layers.push(sprite); 60 | }); 61 | 62 | // HONG 63 | var hongSpriteConfig = { 64 | image: Library.images.act1_end, 65 | grid:{ 66 | width: 4, 67 | height: 12 68 | }, 69 | frame:{ 70 | width: 1100, 71 | height: 480 72 | }, 73 | anchor:{ 74 | x: 560/2, 75 | y: 370/2 76 | }, 77 | x: 560/2, 78 | y: 370/2 79 | }; 80 | var craterSprite = new Sprite(hongSpriteConfig); 81 | self.layers.push(craterSprite); 82 | var hongSprite = new Sprite(hongSpriteConfig); 83 | self.layers.push(hongSprite); 84 | 85 | // DRAW 86 | var BG_WIDTH = 360; 87 | var BG_HEIGHT = 450; 88 | var PARALLAXES = [ 89 | 0, // sky 90 | 0.1, // clouds 91 | 0.25, // buildings 92 | 0.48, // grass 93 | 1.0, // stump 94 | 0, // blackout 95 | 1.0, // crater 96 | 1.0, // HONG 97 | ]; 98 | var OFFSETS = [ 99 | 0, 100 | 0, // clouds 101 | 0, 102 | 0, 103 | 20, 104 | 0, 105 | 20, 106 | 20 107 | ]; 108 | 109 | //////////////////////////////// 110 | // WHICH ANIM CYCLE TO USE? //// 111 | //////////////////////////////// 112 | 113 | var ANIM_TO_USE = _.act1_ending || "fight"; 114 | 115 | 116 | var ticker = 0; 117 | var frameTicker = ticker; 118 | var parallaxTicker = 1; 119 | var thePreviousFrame = -1; 120 | 121 | self.draw = function(ctx){ 122 | 123 | // TICKER 124 | ticker += 1/60; 125 | 126 | // CLOUD OFFSET 127 | OFFSETS[1] = -80 + ticker*3; 128 | 129 | // PARALLAX 130 | var parallax = 0; 131 | if(GAME_TRANSITION==0){ 132 | 133 | parallaxTicker -= 2/60; // 1 to 0 in 1/2 second 134 | 135 | if(parallaxTicker<0) parallaxTicker = 0; 136 | self.layers[5].alpha = parallaxTicker; // blackout alpha 137 | 138 | // 0 to -180 in one second, smoothed 139 | var t = Math.cos(parallaxTicker*Math.TAU/2); // 1 to -1 140 | t = (1-t)/2; // 0 to 1 141 | parallax = -t*215; 142 | 143 | } 144 | 145 | // Smoking crater & Hong frame 146 | frameTicker += 1/60; 147 | var results; 148 | if(ANIM_TO_USE == "fight"){ 149 | 150 | results = findOnTicker(SMOKING_CRATER, frameTicker); 151 | craterSprite.gotoFrame(results.frame); 152 | 153 | // Hong's frame 154 | results = findOnTicker(HONG_FRAMES_FIGHT, frameTicker); 155 | 156 | }else{ 157 | craterSprite.visible = false; 158 | 159 | // Hong's frame 160 | results = findOnTicker(HONG_FRAMES_FLIGHT, frameTicker); 161 | } 162 | 163 | // Is Hong on a new frame? 164 | thePreviousFrame = hongSprite.currentFrame; 165 | var isNewFrame = (thePreviousFrame!=results.frame); 166 | hongSprite.gotoFrame(results.frame); 167 | 168 | // SFX if new frame 169 | if(isNewFrame && results.sfx){ 170 | sfx(results.sfx, {volume: results.sfxVolume} ); 171 | } 172 | 173 | // If pre frameTicker=90/30, Hong is shaking like Beebee! 174 | if(frameTicker<90/30){ 175 | hongSprite.squash = 1 + Math.sin(ticker*Math.TAU*7)*0.01; // seven vibes per second 176 | }else{ 177 | hongSprite.squash = 1; 178 | } 179 | 180 | // Draw all! 181 | for(var i=0; i=6){ // the HONG & SMOKING layer 185 | layer.x += 560/2 + 20; // Hack, don't know why. 186 | layer.y = 210 + 370/2; 187 | } 188 | layer.draw(ctx); 189 | } 190 | 191 | // NEXT SCENE? 192 | if(frameTicker>=320/30){ 193 | Game.goto("act1_end"); 194 | } 195 | 196 | }; 197 | 198 | var GAME_TRANSITION = 0; 199 | 200 | ////////////////////////////////////////////////////////////////////////////// 201 | ////////////////////////////////////////////////////////////////////////////// 202 | ////////////////////////////////////////////////////////////////////////////// 203 | 204 | // Find it! 205 | /*var findFrameOnTicker = function(frameArray, ticker){ 206 | var lastFrame; 207 | for(var i=0; i0.5 ? -1 : 1) * (Math.random()*0.8+0.2); 31 | box.velY = 0; 32 | }else{ 33 | box.velX = 0; 34 | box.velY = (Math.random()>0.5 ? -1 : 1) * (Math.random()*0.8+0.2); 35 | } 36 | 37 | // If NOT start in view, use Velocity to determine where to put box 38 | if(!startInView){ 39 | 40 | // Horizontal 41 | if(box.velY==0){ 42 | box.y = Math.random()*(BG_HEIGHT+box.h*2) - box.h; 43 | if(box.velX>0){ // ltr 44 | box.x = -box.w; 45 | }else{ // rtl 46 | box.x = BG_WIDTH; 47 | } 48 | } 49 | 50 | // Vertical 51 | if(box.velX==0){ 52 | box.x = Math.random()*(BG_WIDTH+box.w*2) - box.w; 53 | if(box.velY>0){ // utd 54 | box.y = -box.h; 55 | }else{ // dtu 56 | box.y = BG_HEIGHT; 57 | } 58 | } 59 | 60 | } 61 | 62 | }; 63 | self.isBoxOutOfSight = function(box){ 64 | if(box.x<-box.w) return true; 65 | if(box.y<-box.h) return true; 66 | if(box.x>BG_WIDTH) return true; 67 | if(box.y>BG_HEIGHT) return true; 68 | return false; 69 | }; 70 | self.updateBox = function(box){ 71 | 72 | // Move it 73 | box.x += box.velX; 74 | box.y += box.velY; 75 | 76 | // If it's out of sight, reset it 77 | if(self.isBoxOutOfSight(box)){ 78 | self.resetBox(box); 79 | } 80 | 81 | }; 82 | self.drawBox = function(box, ctx){ 83 | ctx.fillStyle = "rgba(255,255,255,0.03)"; 84 | ctx.fillRect(box.x, box.y, box.w, box.h); 85 | }; 86 | for(var i=0; i<40; i++){ 87 | var box = {}; 88 | self.resetBox(box, true); 89 | self.boxes.push(box); 90 | } 91 | 92 | var allBoxAlpha = 0; 93 | self.draw = function(ctx){ 94 | 95 | // A big ol' black box 96 | ctx.fillStyle = "#111111"; 97 | ctx.fillRect(0,0, BG_WIDTH, BG_HEIGHT); 98 | 99 | // All-box alpha 100 | allBoxAlpha += 1/30; 101 | if(allBoxAlpha>1) allBoxAlpha=1; 102 | 103 | // Moving white boxes 104 | ctx.globalAlpha = allBoxAlpha; 105 | self.boxes.forEach(function(box){ 106 | self.updateBox(box); 107 | }); 108 | self.boxes.forEach(function(box){ 109 | self.drawBox(box, ctx); 110 | }); 111 | ctx.globalAlpha = 1; 112 | 113 | }; 114 | 115 | } -------------------------------------------------------------------------------- /scripts/game/Character.js: -------------------------------------------------------------------------------- 1 | /******************************** 2 | 3 | Character Architecture: 4 | 5 | * Layers: Body + Mouth + Eyes 6 | * Can animate each layer independently 7 | * Alternate mouth when talking 8 | * Short animation loops 9 | * [star] in body means show no eyes/mouth 10 | 11 | *********************************/ 12 | 13 | Loader.addImages([ 14 | 15 | { id:"fear_harm", src:"sprites/ui/fear_harm.png" }, 16 | { id:"fear_alone", src:"sprites/ui/fear_alone.png" }, 17 | { id:"fear_bad", src:"sprites/ui/fear_bad.png" }, 18 | { id:"fear_captions", src:"sprites/ui/fear_captions.png" } 19 | 20 | ]); 21 | 22 | function Character(spriteConfig, animLoops){ 23 | 24 | var self = this; 25 | self.spriteConfig = spriteConfig; 26 | self.animLoops = animLoops || []; 27 | 28 | // Sprite! 29 | self.layers = {}; 30 | ["body","mouth","eyes"].forEach(function(layerName){ 31 | self.layers[layerName] = new Sprite(spriteConfig); 32 | }); 33 | 34 | // Attack sprites (Hong only, really) 35 | self.fears = {}; 36 | ["harm","alone","bad"].forEach( function(fearName){ 37 | self.fears[fearName] = new Sprite({ 38 | image: Library.images["fear_"+fearName], 39 | grid:{ width:1, height:1 }, 40 | frame:{ width:200, height:200 }, 41 | anchor:{ x:100/2, y:100/2 }, 42 | scale:0.75 43 | }); 44 | } ); 45 | 46 | // Fear caption sprites 47 | self.fearCaptionSprite = new Sprite({ 48 | image: Library.images.fear_captions, 49 | grid: { width:1, height:3 }, 50 | frame: { width:200, height:200 }, 51 | anchor: { x:100/2, y:100/2 }, 52 | scale: 0.75, 53 | frameNames:["harm","alone","bad"] 54 | }); 55 | 56 | // Go To Frames 57 | self.bounce = 1; 58 | self.bounceVel = 0; 59 | self.bounceHookes = 0.2; 60 | self.bounceDamp = 0.8; 61 | self.characterFrames = {}; 62 | self.gotoFrames = function(args, bounce){ 63 | 64 | // Bounce? 65 | if(bounce===undefined) bounce=0.03; // a LITTLE bit, by default 66 | if(bounce!==undefined){ 67 | self.bounce += bounce; 68 | } 69 | 70 | // Gimme those args 71 | if(args.body){ 72 | if(!self.layers.body.doesFrameNameExist("body_"+args.body)) args.body+="*"; // add * if missing 73 | self.characterFrames.body = args.body; 74 | } 75 | if(args.mouth) self.characterFrames.mouth = args.mouth; 76 | if(args.eyes) self.characterFrames.eyes = args.eyes; 77 | 78 | if(args.body){ 79 | var bodyName = "body_"+args.body; 80 | self.layers.body.gotoFrameByName(bodyName); 81 | self.characterFrames.body = args.body; 82 | } 83 | 84 | if(args.mouth){ 85 | var mouthName = "mouth_"+args.mouth; 86 | self.layers.mouth.gotoFrameByName(mouthName); 87 | } 88 | 89 | if(args.eyes){ 90 | var eyesName = "eyes_"+args.eyes; 91 | self.layers.eyes.gotoFrameByName(eyesName); 92 | } 93 | 94 | // Go go go 95 | var l = self.layers; 96 | var c = self.characterFrames; 97 | l.body.gotoFrameByName( "body_"+c.body ); 98 | l.mouth.gotoFrameByName( "mouth_"+c.mouth ); 99 | l.eyes.gotoFrameByName( "eyes_"+c.eyes ); 100 | 101 | }; 102 | 103 | // Draw 104 | self.characterSpeakerID = "derp"; 105 | self.characterSquash = 1; 106 | self.draw = function(ctx){ 107 | 108 | var fname; 109 | var l = self.layers; 110 | var c = self.characterFrames; 111 | 112 | // Attacked? SHAKE WHOLE CONTEXT 113 | ctx.save(); 114 | if(IVE_BEEN_ATTACKED){ 115 | var shakeDuration = 0.6; 116 | if(attackedTimer=0); 149 | if(isMyMouthTalking){ 150 | l.mouth.gotoFrameByName( "mouth_"+c.mouth ); 151 | } 152 | } 153 | l.mouth.draw(ctx); 154 | 155 | // Eyes 156 | l.eyes.draw(ctx); 157 | 158 | } 159 | 160 | // Draw attacked icon 161 | if(IVE_BEEN_ATTACKED){ 162 | 163 | var icon = self.fears[attackedIconShown]; 164 | icon.draw(ctx); 165 | 166 | var caption = self.fearCaptionSprite; 167 | caption.gotoFrameByName(attackedIconShown); 168 | caption.x = icon.x; 169 | caption.y = icon.y-37; 170 | caption.alpha = icon.alpha; 171 | caption.draw(ctx); 172 | 173 | attackedTimer += 1/60; 174 | if(attackedTimer>1.75){ 175 | icon.y -= 1; 176 | icon.alpha -= 1/15; 177 | if(icon.alpha<0){ 178 | attackedIconShown = null; 179 | IVE_BEEN_ATTACKED = false; 180 | } 181 | } 182 | 183 | } 184 | ctx.restore(); 185 | 186 | }; 187 | 188 | // Anim Loop logic! 189 | self.animLoops.forEach(function(rule){ 190 | rule.active = false; 191 | rule.countdown = -1; 192 | }); 193 | self.runAnimLoopRules = function(){ 194 | for(var i=0; i0){ 237 | promiseNext.then(function(){ 238 | Game.executeNextLine(); 239 | }); 240 | } 241 | 242 | }; 243 | Game.clearQueue = function(){ 244 | Game.queue = []; 245 | }; 246 | Game.addToQueue = function(line){ 247 | Game.queue.push(line); 248 | } 249 | 250 | 251 | //////////////////////////////////////////////////////////////////////////////////////////////// 252 | // TEXT AND STUFF ////////////////////////////////////////////////////////////////////////////// 253 | //////////////////////////////////////////////////////////////////////////////////////////////// 254 | 255 | // Immediate Promise 256 | Game.immediatePromise = function(){ 257 | return new RSVP.Promise(function(resolve){ 258 | resolve(); 259 | }); 260 | }; 261 | 262 | // Move the text DOM to latest 263 | Game.FORCE_TEXT_Y = -1; 264 | Game.updateText = function(instant){ 265 | if(Game.FORCE_TEXT_Y<0){ 266 | var wordsHeight = 80 + Game.wordsDOM.getBoundingClientRect().height; 267 | var currentY = parseFloat(Game.wordsDOM.style.top) || 80; 268 | var gotoY = (wordsHeight<250) ? 0 : wordsHeight-250; 269 | gotoY = 80 - gotoY; 270 | var nextY = instant ? gotoY : currentY*0.9 + gotoY*0.1; 271 | Game.wordsDOM.style.top = nextY+"px"; 272 | }else{ 273 | Game.wordsDOM.style.top = Game.FORCE_TEXT_Y+"px"; 274 | } 275 | }; 276 | 277 | // CLEAR TEXT 278 | Game.clearText = function(){ 279 | Game.wordsDOM.innerHTML = ""; 280 | Game.updateText(true); 281 | }; 282 | window.clearText = Game.clearText; 283 | 284 | // Execute text! Just add it to text DOM. 285 | Game.TEXT_SPEED = 50; 286 | Game.CLICK_TO_ADVANCE = true; 287 | Game.FORCE_CANT_SKIP = false; 288 | Game.OVERRIDE_TEXT_SPEED = 1; 289 | Game.FORCE_TEXT_DURATION = -1; 290 | Game.WHO_IS_SPEAKING = null; // "h", "b", "n" etc... 291 | Game.CURRENT_SPEAKING_SPEED = 1; 292 | Game.FORCE_NO_VOICE = false; 293 | Game.executeText = function(line){ 294 | 295 | return new RSVP.Promise(function(resolve){ 296 | 297 | // Who's speaking? 298 | // b: Beebee, h: Hong, n: Narrator, n2: Narrator 2, n3: Narrator 3 299 | var regex = /^([^\:]+)\:(.*)/ 300 | var speaker = line.match(regex)[1].trim(); 301 | var dialogue = line.match(regex)[2].trim(); 302 | 303 | // Add the bubble, with animation 304 | var div = document.createElement("div"); 305 | Game.wordsDOM.appendChild(div); 306 | Game.WHO_IS_SPEAKING = speaker; // WHO'S SPEAKING?! 307 | Game.CURRENT_SPEAKING_SPEED = Game.OVERRIDE_TEXT_SPEED; 308 | switch(speaker){ 309 | case "b": 310 | div.className = "beebee-bubble"; 311 | break; 312 | case "h": 313 | div.className = "hong-bubble"; 314 | break; 315 | case "n": 316 | div.className = "narrator-bubble"; 317 | break; 318 | case "n2": // narrator 2 319 | div.className = "narrator-bubble-2"; 320 | break; 321 | case "n3": // narrator 3 322 | div.className = "narrator-bubble-3"; 323 | break; 324 | case "n4": // narrator 3 325 | div.className = "narrator-bubble-4"; 326 | break; 327 | } 328 | requestAnimationFrame(function(){ 329 | requestAnimationFrame(function(){ 330 | div.style.opacity = 1; 331 | div.style.left = 0; 332 | }); 333 | }); 334 | 335 | // Clear both 336 | var clearBoth = document.createElement("div"); 337 | clearBoth.className = "clear-both"; 338 | Game.wordsDOM.appendChild(clearBoth); 339 | 340 | // Add the text 341 | var interval = 0; 342 | var SPEED = Math.round(Game.TEXT_SPEED / Game.OVERRIDE_TEXT_SPEED); 343 | if(Game.FORCE_TEXT_DURATION>0){ 344 | SPEED = Math.round(Game.FORCE_TEXT_DURATION/dialogue.length); 345 | } 346 | 347 | // IF IT'S BEEBEE, HONG, or NARRATOR 3 348 | if(speaker=="b" || speaker=="h" || speaker=="n3"){ 349 | 350 | // Put in the text, each character a DIFFERENT SPAN... 351 | var span, chr; 352 | var isItalicized = false; 353 | for(var i=0; i"+chr+"" : chr; 365 | } 366 | span.style.opacity = 0; 367 | div.appendChild(span); 368 | 369 | } 370 | 371 | // Then REVEAL letters one-by-one 372 | for(var i=0; i *Emphasize* *multiple* *words* 433 | var regex = /\*([^\*]*)\*/g; 434 | var emphasized = dialogue.match(regex) || []; 435 | for(var i=emphasized.length-1; i>=0; i--){ // backwards coz replacing 436 | 437 | // Convert 438 | var originalEm = emphasized[i] 439 | var em = originalEm; 440 | em = em.substr(1,em.length-2); // remove * 441 | var ems = em.split(" "); 442 | ems = ems.map(function(word){ 443 | return "*"+word+"*"; 444 | }); 445 | em = ems.join(" "); 446 | 447 | // Replace in main string 448 | var startIndex = dialogue.indexOf(originalEm); 449 | dialogue = dialogue.slice(0, startIndex) + em + dialogue.slice(startIndex+originalEm.length); 450 | 451 | } 452 | 453 | // Put in the text, each word a DIFFERENT SPAN 454 | var span; 455 | var dialogueWords = dialogue.split(" "); 456 | for(var i=0; i"; 463 | } 464 | 465 | // Actual emphasis 466 | reggie = /\_(.*)\_/; 467 | if(reggie.test(word)){ 468 | word = "" + word.match(reggie)[1].trim() + ""; 469 | } 470 | 471 | // Add the span 472 | span = document.createElement("span"); 473 | span.innerHTML = word+" "; 474 | span.style.opacity = 0; 475 | div.appendChild(span); 476 | 477 | } 478 | 479 | // Then REVEAL words one-by-one 480 | for(var i=0; i" + results[1] + "" + choiceText.slice(endOfMatch); 598 | } 599 | 600 | var div = document.createElement("div"); 601 | div.innerHTML = choiceText; 602 | div.onclick = function(event){ 603 | 604 | // Any pre-choice code? 605 | if(preChoiceCodeIfAny) Game.executeCode(preChoiceCodeIfAny); 606 | 607 | // Override line... ONCE 608 | if(!Game.OVERRIDE_CHOICE_LINE){ 609 | Game.addToQueue("b: "+originalChoiceText); 610 | } 611 | Game.OVERRIDE_CHOICE_LINE = false; 612 | 613 | // Play sound 614 | sfx("ui_click"); 615 | 616 | // Goto that choice, now! 617 | Game.goto(choiceID); 618 | 619 | // STOP THE PROP 620 | event.stopPropagation(); 621 | 622 | }; 623 | div.onmouseover = function(){ 624 | sfx("ui_hover"); 625 | }; 626 | 627 | // Add choice, animated! 628 | div.style.top = "150px"; 629 | Game.choicesDOM.appendChild(div); 630 | setTimeout(function(){ 631 | div.style.top = "0px"; 632 | sfx("ui_show_choice", {volume:0.4}); 633 | },10); 634 | 635 | // Or... FORCE 636 | if(Game.HACK_MAKE_THE_LINE_BIG){ 637 | div.style.fontSize = "30px"; 638 | }else{ 639 | 640 | // If it's too big, shrink font size 641 | setTimeout(function(){ 642 | var choiceHeight = div.getBoundingClientRect().height; 643 | if(choiceHeight>40) div.style.fontSize = "18px"; 644 | // And if still too much??? 645 | setTimeout(function(){ 646 | var choiceHeight = div.getBoundingClientRect().height; 647 | if(choiceHeight>40) div.style.fontSize = "16px"; 648 | // And if still too much??? 649 | setTimeout(function(){ 650 | var choiceHeight = div.getBoundingClientRect().height; 651 | if(choiceHeight>40) div.style.fontSize = "14px"; 652 | },1); 653 | },1); 654 | },1); 655 | 656 | } 657 | Game.HACK_MAKE_THE_LINE_BIG = false; 658 | 659 | // Wait a bit before adding new line 660 | return new RSVP.Promise(function(resolve){ 661 | Game.setTimeout(resolve, 100); 662 | }); 663 | 664 | } 665 | 666 | // Execute code! 667 | Game.executeCode = function(line){ 668 | 669 | var code = line.match(/\`+([^\`]*)\`+/)[1].trim(); 670 | try{ 671 | eval(code); 672 | }catch(e){ 673 | console.log(e); 674 | } 675 | 676 | // Return immediate promise 677 | return Game.immediatePromise(); 678 | 679 | } 680 | 681 | // Execute wait! Just wait. 682 | Game.executeWait = function(line){ 683 | 684 | // Get integer from (...NN) 685 | var waitTime = parseInt(line.match(/^\(\.\.\.(\d+)\)/)[1].trim()); 686 | 687 | // Unless it's click to advance, then IGNORE ALL WAITS 688 | if(!Game.FORCE_CANT_SKIP){ 689 | 690 | // Specific wait-time, don't skip? 691 | var waitTimeString = waitTime+""; 692 | var lastDigit = waitTimeString[waitTimeString.length-1]; 693 | var cantSkip = (lastDigit=="1"); // CAN'T SKIP. 694 | 695 | if(!cantSkip && Game.CLICK_TO_ADVANCE && waitTime<999){ // hack: unless the wait is long. 696 | waitTime = 0; 697 | } 698 | 699 | } 700 | 701 | // Delayed promise 702 | return new RSVP.Promise(function(resolve){ 703 | Game.setTimeout(resolve, waitTime); 704 | }); 705 | 706 | }; 707 | 708 | // Execute goto! Just goto. 709 | Game.executeGoto = function(line){ 710 | var gotoID = line.match(/^\(\#(.*)\)/)[1].trim().toLocaleLowerCase(); 711 | Game.goto(gotoID); 712 | } 713 | 714 | // Determine line type... text, choice, or code? 715 | Game.getLineType = function(line){ 716 | 717 | // Is it a choice? 718 | var isChoice = /\[.*\]\(\#.*\)/.test(line); 719 | if(isChoice) return "choice"; 720 | 721 | // Is it a goto? 722 | var isGoto = /^\(\#(.*)\)/.test(line); 723 | if(isGoto) return "goto"; 724 | 725 | // Is it code? 726 | var isCode = /^\`/.test(line); 727 | if(isCode) return "code"; 728 | 729 | // Is it a wait? 730 | var isWait = /^\(\.\.\.\d+\)/.test(line); 731 | if(isWait) return "wait"; 732 | 733 | // Otherwise, it's text. 734 | return "text"; 735 | 736 | }; 737 | 738 | // Parse all the handlebars... 739 | Game.parseLine = function(line){ 740 | 741 | // Get rid of newlines 742 | line = line.replace(/\n/gi,""); 743 | 744 | // Get the IFs, if any 745 | var lookForIfs = true; 746 | while(lookForIfs){ 747 | 748 | lookForIfs = false; 749 | 750 | // Look for an IF! 751 | var regex = /\{\{if[^\/]*\/if\}\}/ig; // the reason it's inside here is to reset .exec 752 | var regexResult = regex.exec(line); 753 | if(regexResult){ 754 | 755 | // The result... 756 | var fullConditional = regexResult[0]; 757 | var startsAtIndex = regexResult.index; 758 | var endsAtIndex = startsAtIndex + fullConditional.length; 759 | 760 | // Extract the condition 761 | var condition = fullConditional.match(/\{\{if\s+([^\{\}]*)\}\}/)[1]; 762 | 763 | // Extract the inside text 764 | var insideText = fullConditional.match(/\}\}([^\{\}]*)\{\{/)[1].trim()+" "; 765 | 766 | // Eval condition! 767 | var conditionIsTrue = false; 768 | try{ 769 | conditionIsTrue = eval(condition); 770 | }catch(e){ 771 | console.log(e); 772 | } 773 | 774 | // Edit the line 775 | var insert = conditionIsTrue ? insideText : ""; 776 | line = line.slice(0,startsAtIndex) + insert + line.slice(endsAtIndex); 777 | 778 | // Keep searching... 779 | lookForIfs = true; 780 | 781 | } 782 | 783 | } 784 | 785 | // Evaluate {{expressions}}, if any 786 | var lookForExpressions = true; 787 | while(lookForExpressions){ 788 | 789 | lookForExpressions = false; 790 | 791 | // Look for an IF! 792 | var regex = /\{\{[^\}]*\}\}/ig; // the reason it's inside here is to reset .exec 793 | var regexResult = regex.exec(line); 794 | if(regexResult){ 795 | 796 | // The result... 797 | var fullExpression = regexResult[0]; 798 | var startsAtIndex = regexResult.index; 799 | var endsAtIndex = startsAtIndex + fullExpression.length; 800 | 801 | // Extract the expression 802 | var expression = fullExpression.match(/\{\{([^\}]*)\}\}/)[1]; 803 | 804 | // Eval condition! 805 | var evaluated = ""; 806 | try{ 807 | evaluated = eval(expression); 808 | }catch(e){ 809 | console.log(e); 810 | } 811 | 812 | // Edit the line 813 | line = line.slice(0,startsAtIndex) + evaluated + line.slice(endsAtIndex); 814 | 815 | // Keep searching... 816 | lookForExpressions = true; 817 | 818 | } 819 | 820 | } 821 | 822 | // Return line! 823 | return line; 824 | 825 | }; 826 | 827 | //////////////////////////////////////////////////////////////////////////////////////////////// 828 | // WHERE STUFF WILL BE DRAWN /////////////////////////////////////////////////////////////////// 829 | //////////////////////////////////////////////////////////////////////////////////////////////// 830 | 831 | Game.canvas.width = 360 * 2; 832 | Game.canvas.height = 450 * 2; 833 | Game.canvas.style.width = Game.canvas.width/2 + "px"; 834 | Game.canvas.style.height = Game.canvas.height/2 + "px"; 835 | Game.context = Game.canvas.getContext("2d"); 836 | 837 | // A blank scene 838 | Game.scene = null; 839 | Game.resetScene = function(){ 840 | 841 | // Kill all of previous scene 842 | if(Game.scene){ 843 | Game.scene.children.forEach(function(child){ 844 | if(child.kill) child.kill(); 845 | }); 846 | if(Game.scene.kill) Game.scene.kill(); 847 | } 848 | 849 | // New scene! 850 | Game.scene = {}; 851 | Game.scene.children = []; 852 | 853 | }; 854 | Game.resetScene(); 855 | 856 | // Update & draw all the kids! 857 | Game.updateCanvas = function(){ 858 | 859 | // For retina 860 | var ctx = Game.context; 861 | ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); 862 | ctx.save(); 863 | ctx.scale(2,2); 864 | 865 | // Update/Draw all kids 866 | Game.scene.children.forEach(function(child){ 867 | child.draw(ctx); 868 | }); 869 | 870 | // Restore 871 | ctx.restore(); 872 | 873 | // Draw HP 874 | HP.draw(); 875 | 876 | }; 877 | 878 | 879 | 880 | -------------------------------------------------------------------------------- /scripts/game/HP.js: -------------------------------------------------------------------------------- 1 | Loader.addImages([ 2 | { id:"hp", src:"sprites/ui/hp.png" } 3 | ]); 4 | 5 | Loader.addSounds([ 6 | { id:"hit", src:"sounds/sfx/hit.mp3" }, 7 | { id:"hit_big", src:"sounds/sfx/hit_big.mp3" } 8 | ]); 9 | 10 | 11 | // The Class! 12 | function HitPoints(){ 13 | 14 | var self = this; 15 | 16 | // My DOM & canvas 17 | self.dom = $("#game_hp"); 18 | self.canvas = document.createElement("canvas"); 19 | self.canvas.width = 360 * 2; 20 | self.canvas.height = 100 * 2; 21 | self.canvas.style.width = self.canvas.width/2 + "px"; 22 | self.canvas.style.height = self.canvas.height/2 + "px"; 23 | self.context = self.canvas.getContext("2d"); 24 | self.dom.appendChild(self.canvas); 25 | 26 | // My sprite 27 | self.image = Library.images.hp; 28 | 29 | // My stats 30 | self.reset = function(){ 31 | self.hong = 100; 32 | self.beebee = 100; 33 | self.leftWhite = 1; 34 | self.rightWhite = 1; 35 | }; 36 | self.reset(); 37 | 38 | // Show/hide 39 | self.show = function(){ 40 | self.dom.style.top = "0px"; 41 | }; 42 | self.hide = function(){ 43 | self.dom.style.top = "-100px"; 44 | }; 45 | subscribe("hp_show", self.show); 46 | subscribe("hp_hide", self.hide); 47 | 48 | // Attack! 49 | self.doDamage = function(str, target){ 50 | 51 | // Absolute or Relative Damage? 52 | var num = parseFloat(str); 53 | var isAbsolute = (str.slice(-1)=="p"); // p = absolute, % = relative 54 | if(isAbsolute){ 55 | self[target] -= num; 56 | }else{ 57 | var relativeDamage = Math.floor( self[target] * (num/100) ); 58 | self[target] -= relativeDamage; 59 | } 60 | 61 | // Floor bound 62 | if(self[target]<0){ 63 | self[target] = 0; 64 | } 65 | 66 | }; 67 | 68 | // Who's been attacked? 69 | subscribe("attack", function(target, damage, type){ 70 | 71 | Game.clearText(); // BYE 72 | 73 | if(target=="hong"){ 74 | self.doDamage(damage, "hong"); 75 | self.leftShake = 30; 76 | publish("attack_hong",[type]); 77 | }else{ 78 | self.doDamage(damage, "beebee"); 79 | self.rightShake = 30; 80 | } 81 | 82 | // Sound 83 | if(damage=="100p"){ // FULL! 84 | sfx("hit_big"); 85 | }else{ 86 | sfx("hit"); 87 | } 88 | 89 | }); 90 | 91 | // Draw 92 | self.leftShake = 0; 93 | self.leftRed = self.leftWhite = 1; 94 | self.rightShake = 0; 95 | self.rightRed = self.rightWhite = 1; 96 | self.drawHalf = function(ctx, isRight){ 97 | 98 | ctx.save(); 99 | 100 | // Which side? 101 | var side = isRight ? "right" : "left"; 102 | var hp = isRight ? self.beebee : self.hong; 103 | 104 | // Shaking 105 | var stoppedShaking = (self[side+"Shake"]==0); 106 | if(stoppedShaking){ 107 | self[side+"Shake"]=0; 108 | }else{ 109 | var amp = self[side+"Shake"]/7; 110 | var shakeY = Math.sin(self[side+"Shake"]*1.3)*amp; 111 | ctx.translate(0,shakeY); 112 | self[side+"Shake"]--; 113 | } 114 | 115 | // Damage 116 | if(!isRight){ // Hong 117 | var d = self.hong/100; 118 | self.leftRed = self.leftRed*0.8 + d*0.2; 119 | if(stoppedShaking){ 120 | if(self.leftWhite > self.leftRed){ 121 | self.leftWhite -= 0.001; 122 | } 123 | } 124 | }else{ 125 | var d = self.beebee/100; 126 | self.rightRed = self.rightRed*0.8 + d*0.2; 127 | if(stoppedShaking){ 128 | if(self.rightWhite > self.rightRed){ 129 | self.rightWhite -= 0.001; 130 | } 131 | } 132 | } 133 | 134 | // BG: Black 135 | var sx=isRight ? 360 : 0, sy=200*0, sw=360, sh=200; 136 | ctx.drawImage(self.image, sx,sy,sw,sh, sx/2,0,sw/2,sh/2); 137 | 138 | // Draw White INSIDE (source-atop) 139 | if(self[side+"Shake"]==0){ // if not shaking, slowly reduce 140 | if( self[side+"WhiteWidth"] > self[side+"Width"] ){ 141 | self[side+"WhiteWidth"] -= 0.1; 142 | } 143 | } 144 | var sx=isRight ? 360 : 0, sy=200*1, sw=360, sh=200; 145 | var offset = (1-self[side+"White"])*295;//self[side+"WhiteWidth"]; 146 | offset *= isRight ? -1 : 1; 147 | ctx.globalCompositeOperation = "source-atop"; 148 | ctx.drawImage(self.image, sx,sy,sw,sh, (sx+offset)/2,0,sw/2,sh/2); 149 | 150 | // Red 151 | var sx=isRight ? 360 : 0, sy=200*2, sw=360, sh=200; 152 | var offset = (1-self[side+"Red"])*295;//self[side+"WhiteWidth"]; 153 | offset *= isRight ? -1 : 1; 154 | ctx.globalCompositeOperation = "source-atop"; 155 | ctx.drawImage(self.image, sx,sy,sw,sh, (sx+offset)/2,0,sw/2,sh/2); 156 | 157 | // Restore 158 | ctx.restore(); 159 | 160 | }; 161 | self.draw = function(){ 162 | 163 | var ctx = self.context; 164 | ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height); 165 | ctx.save(); 166 | ctx.scale(2,2); 167 | 168 | // Draw Left & Right Sides 169 | self.drawHalf(ctx, false); 170 | self.drawHalf(ctx, true); 171 | 172 | // Draw BG BELOW 173 | ctx.globalCompositeOperation = "destination-over"; 174 | var sx=0, sy=200*4, sw=720, sh=200; 175 | ctx.drawImage(self.image, sx,sy,sw,sh, 0,0,sw/2,sh/2); 176 | 177 | // Draw "VS" 178 | ctx.globalCompositeOperation = "source-over"; 179 | var sx=0, sy=200*3, sw=720, sh=200; 180 | ctx.drawImage(self.image, sx,sy,sw,sh, 0,0,sw/2,sh/2); 181 | 182 | ctx.restore(); 183 | 184 | }; 185 | 186 | } -------------------------------------------------------------------------------- /scripts/game/Loader.js: -------------------------------------------------------------------------------- 1 | window.Loader = {}; 2 | window.Library = { 3 | images: {}, 4 | sounds: {} 5 | }; 6 | Loader.load = function(progressCallback){ 7 | 8 | var totalAssets = Loader.sceneSources.length + Loader.imageConfigs.length + Loader.soundConfigs.length; 9 | var assetsLoaded = 0; 10 | subscribe("assetLoaded", function(){ 11 | assetsLoaded++; 12 | progressCallback(assetsLoaded/totalAssets); 13 | }); 14 | 15 | // Gotta LOAD 'EM ALL 16 | return new RSVP.Promise(function(resolve){ 17 | 18 | var loadPromises = []; 19 | 20 | // All scenes 21 | Loader.sceneSources.forEach(function(src){ 22 | loadPromises.push( Loader.loadScene(src) ); 23 | }); 24 | 25 | // All images 26 | Loader.imageConfigs.forEach(function(config){ 27 | loadPromises.push( Loader.loadImage(config) ); 28 | }); 29 | 30 | // All sounds 31 | Loader.soundConfigs.forEach(function(config){ 32 | loadPromises.push( Loader.loadSound(config) ); 33 | }); 34 | 35 | // Go go go! 36 | RSVP.all(loadPromises).then(resolve); 37 | 38 | }); 39 | }; 40 | 41 | ///////////////////////////// 42 | // IMAGES /////////////////// 43 | ///////////////////////////// 44 | 45 | Loader.imageConfigs = []; 46 | Loader.addImages = function(imageConfigs){ 47 | Loader.imageConfigs = Loader.imageConfigs.concat(imageConfigs); 48 | }; 49 | Loader.loadImage = function(imageConfig){ 50 | return new RSVP.Promise(function(resolve){ 51 | var img = new Image(); 52 | var id = imageConfig.id; 53 | Library.images[id] = img; // ADD TO LIBRARY 54 | img.onload = function(){ 55 | publish("assetLoaded"); 56 | resolve(); 57 | } 58 | img.src = imageConfig.src; 59 | }); 60 | }; 61 | 62 | ///////////////////////////// 63 | // SCENES /////////////////// 64 | ///////////////////////////// 65 | 66 | Loader.sceneSources = []; 67 | Loader.addScenes = function(sceneSources){ 68 | Loader.sceneSources = Loader.sceneSources.concat(sceneSources); 69 | }; 70 | Loader.loadScene = function(src){ 71 | var loadDataPromise = new RSVP.Promise(function(resolve){ 72 | var xhr = new XMLHttpRequest(); 73 | xhr.open("GET", src); 74 | xhr.onload = function() { 75 | if(xhr.status===200){ 76 | Game.parseSceneMarkdown(xhr.responseText); // PARSE INTO GAME 77 | publish("assetLoaded"); 78 | resolve(); 79 | } 80 | }; 81 | xhr.send(); 82 | }); 83 | }; 84 | 85 | ///////////////////////////// 86 | // SOUNDS /////////////////// 87 | ///////////////////////////// 88 | 89 | Loader.soundConfigs = []; 90 | Loader.addSounds = function(soundConfigs){ 91 | Loader.soundConfigs = Loader.soundConfigs.concat(soundConfigs); 92 | }; 93 | Loader.loadSound = function(soundConfig){ 94 | return new RSVP.Promise(function(resolve){ 95 | var sound = new Howl({ 96 | src: [soundConfig.src] 97 | }); 98 | var id = soundConfig.id; 99 | Library.sounds[id] = sound; // ADD TO LIBRARY 100 | sound.once("load",function(){ 101 | publish("assetLoaded"); 102 | resolve(); 103 | }); 104 | }); 105 | }; 106 | -------------------------------------------------------------------------------- /scripts/game/Options.js: -------------------------------------------------------------------------------- 1 | window.Options = {}; 2 | 3 | Loader.addSounds([ 4 | { id:"ui_button1", src:"sounds/ui/button1.mp3" }, 5 | { id:"ui_button2", src:"sounds/ui/button2.mp3" } 6 | ]); 7 | 8 | (function(){ 9 | 10 | var optionsDOM = $("#options"); 11 | var text_speed_slider = $("#text_speed_slider"); 12 | var text_speed_preview = $("#text_speed_preview"); 13 | var volume_slider = $("#volume_slider"); 14 | 15 | text_speed_slider.oninput = function(){ 16 | updateText(); 17 | }; 18 | 19 | volume_slider.oninput = function(){ 20 | Howler.volume(parseFloat(volume_slider.value)); 21 | }; 22 | 23 | var text_automatic_toggle = $("#text_automatic_toggle"); 24 | text_automatic_toggle.onclick = function(){ 25 | if(!Game.CLICK_TO_ADVANCE){ 26 | HOW_MANY_PROMPTS = 1; 27 | } 28 | Game.CLICK_TO_ADVANCE = !Game.CLICK_TO_ADVANCE; 29 | text_automatic_toggle.innerHTML = Game.CLICK_TO_ADVANCE ? "on click" : "automatically"; 30 | 31 | // Sound 32 | sfx( Game.CLICK_TO_ADVANCE ? "ui_button2" : "ui_button1"); 33 | 34 | }; 35 | 36 | // Add sounds to slider 37 | var addSoundsToSlider = function(slider){ 38 | var _play1 = function(){ sfx("ui_button1"); }; 39 | var _play2 = function(){ sfx("ui_button2"); }; 40 | slider.addEventListener("mousedown", _play1); 41 | slider.addEventListener("touchstart", _play1); 42 | slider.addEventListener("change", _play2); 43 | //slider.addEventListener("touchend", _play2); 44 | }; 45 | addSoundsToSlider(text_speed_slider); 46 | addSoundsToSlider(volume_slider); 47 | 48 | 49 | 50 | /////////////////////////////////// 51 | // CLICK TO ADVANCE // 52 | /////////////////////////////////// 53 | 54 | var HOW_MANY_PROMPTS = 2; 55 | 56 | var ctaAlpha = 1; 57 | var click_to_advance = $("#click_to_advance"); 58 | var cta_text1 = $("#cta_text1"); 59 | var cta_text2 = $("#cta_text2"); 60 | click_to_advance.style.display = "none"; 61 | subscribe("show_click_to_advance", function(){ 62 | 63 | cta_text1.style.display = (HOW_MANY_PROMPTS>0) ? "inline" : "none"; 64 | cta_text2.style.display = (HOW_MANY_PROMPTS>0) ? "none" : "inline"; 65 | HOW_MANY_PROMPTS--; 66 | 67 | click_to_advance.style.display = "block"; 68 | blinkCTA(); 69 | 70 | }); 71 | subscribe("hide_click_to_advance", function(){ 72 | 73 | click_to_advance.style.display = "none"; 74 | 75 | if(currentBlinkingInterval) clearInterval(currentBlinkingInterval); 76 | currentBlinkingInterval = null; 77 | 78 | }); 79 | var currentBlinkingInterval; 80 | var blinkCTA = function(){ 81 | currentBlinkingInterval = setInterval(function(){ 82 | ctaAlpha = (ctaAlpha==1) ? 0 : 1; 83 | click_to_advance.style.opacity = ctaAlpha; 84 | }, 700); 85 | }; 86 | 87 | /////////////////////////////////// 88 | // For previewing the text speed // 89 | /////////////////////////////////// 90 | 91 | Options.update = function(){ 92 | 93 | // Timeout callbacks... 94 | for(var i=0; i<_timeoutCallbacks.length; i++){ 95 | var tc = _timeoutCallbacks[i]; 96 | tc.timeLeft -= 1000/60; 97 | if(tc.timeLeft<=0){ 98 | tc.callback(); 99 | _timeoutCallbacks.splice(i,1); // delete that one 100 | i -= 1; // set index back one 101 | } 102 | } 103 | 104 | // Also, move click_to_advance DOM 105 | var wordsTop = parseInt($("#game_words").style.top); 106 | var wordsHeight = $("#game_words").getBoundingClientRect().height; 107 | click_to_advance.style.top = Math.round(wordsTop+wordsHeight+5) + "px"; 108 | 109 | }; 110 | 111 | var _timeoutCallbacks = []; 112 | var _setTimeout = function(callback, interval){ 113 | _timeoutCallbacks.push({ 114 | callback: callback, 115 | timeLeft: interval 116 | }); 117 | }; 118 | var _clearAllTimeouts = function(){ 119 | _timeoutCallbacks = []; 120 | }; 121 | 122 | var updateText = function(){ 123 | 124 | var div = text_speed_preview; 125 | 126 | // Calculate text speed... 127 | var t = parseFloat(text_speed_slider.value); 128 | t = (1-t); // whoops, flip around 129 | // Log slider, from 5 to 120, with 50 "in the middle" 130 | // f(0)=5, f(0.5)=50, f(1)=120 131 | // a*e^(0.0*b) + c = 5 132 | // a*e^(0.5*b) + c = 50 133 | // a*e^(1.0*b) + c = 120 134 | // constants gotten by Wolfram Alpha, thanks Wolfy. 135 | var speed = Math.round( 81*Math.exp(t*0.885) - 76 ); 136 | Game.TEXT_SPEED = speed; 137 | 138 | // Clear previous crap 139 | _clearAllTimeouts(); 140 | div.innerHTML = ""; 141 | 142 | // What's the dialogue? 143 | var dialogue = Game.TEXT_SPEED<80 ? "Speak this fast" : "Speak this slow"; 144 | 145 | // Put in the text 146 | var span, chr; 147 | for(var i=0; i=0; 62 | }; 63 | self.gotoFrame(0); 64 | 65 | // Other transformations 66 | self.x = config.x || 0; 67 | self.y = config.y || 0; 68 | self.rotation = config.rotation || 0; 69 | self.scale = config.scale || 1; 70 | self.squash = config.squash || 1; 71 | self.alpha = config.alpha || 1; 72 | 73 | // Visible at all? 74 | self.visible = true; 75 | 76 | // Draw frame! 77 | self.draw = function(ctx){ 78 | 79 | if(!self.visible) return; // nah 80 | 81 | ctx.save(); 82 | 83 | // Which part of image to draw? 84 | var sx = self.currentFrame % self.grid.width; 85 | var sy = Math.floor((self.currentFrame - sx)/self.grid.width); 86 | var fw = self.frame.width; 87 | var fh = self.frame.height; 88 | 89 | // Translate... 90 | var dx = self.x; 91 | var dy = self.y; 92 | ctx.translate(dx, dy); 93 | 94 | // Scale 95 | var scaleX = self.scale * self.squash; 96 | var scaleY = self.scale / self.squash; 97 | ctx.scale(scaleX, scaleY); 98 | 99 | // Alpha 100 | ctx.globalAlpha = self.alpha; 101 | 102 | // Draw it! 103 | ctx.drawImage( 104 | self.image, 105 | sx*fw, sy*fh, fw, fh, 106 | -self.anchor.x, -self.anchor.y, fw/2, fh/2 107 | ); 108 | 109 | ctx.restore(); 110 | 111 | }; 112 | 113 | } -------------------------------------------------------------------------------- /scripts/intro/Intro_BG.js: -------------------------------------------------------------------------------- 1 | Loader.addImages([ 2 | { id:"intro_logo", src:"sprites/intro/intro_logo.png" }, 3 | { id:"intro_bg", src:"sprites/intro/intro_bg.png" }, 4 | { id:"intro_anim", src:"sprites/intro/intro_anim.png" } 5 | ]); 6 | 7 | Loader.addSounds([ 8 | 9 | { id:"whoosh", src:"sounds/sfx/whoosh.mp3" }, 10 | { id:"intro_scream", src:"sounds/sfx/intro_scream.mp3" }, 11 | 12 | { id:"grass_step1", src:"sounds/sfx/grass_step1.mp3" }, 13 | { id:"grass_step2", src:"sounds/sfx/grass_step2.mp3" }, 14 | { id:"bag_short", src:"sounds/sfx/bag_short.mp3" }, 15 | { id:"bag_search", src:"sounds/sfx/bag_search.mp3" }, 16 | { id:"bag_kick", src:"sounds/sfx/bag_kick.mp3" }, 17 | { id:"sandwich", src:"sounds/sfx/sandwich.mp3" }, 18 | 19 | ]); 20 | 21 | function BG_Intro(){ 22 | 23 | var ticker = 0;//18;//0; 24 | 25 | 26 | var self = this; 27 | 28 | // Sprites! 29 | self.logoSprite = new Sprite({ 30 | image: Library.images.intro_logo, 31 | grid:{ width:1, height:1 }, 32 | frame:{ width:720, height:900 }, 33 | }); 34 | var spriteConfig = { 35 | image: Library.images.intro_bg, 36 | grid:{ 37 | width: 2, 38 | height: 3 39 | }, 40 | frame:{ 41 | width: 1200, 42 | height: 900 43 | }, 44 | anchor:{ 45 | x: 0, 46 | y: 0 47 | }, 48 | frameNames:[ 49 | "sky", 50 | "clouds", 51 | "buildings", 52 | "grass", 53 | "stump", 54 | "blackout" 55 | ], 56 | x: 0, 57 | y: 0 58 | }; 59 | self.layers = []; 60 | ["sky","clouds","buildings","grass","stump","blackout"].forEach(function(layerName){ 61 | var sprite = new Sprite(spriteConfig); 62 | sprite.gotoFrameByName(layerName); 63 | self.layers.push(sprite); 64 | }); 65 | self.layers[5].alpha = 0; // blackout alpha is ZERO at start. 66 | 67 | // HONG 68 | var hongSpriteConfig = { 69 | image: Library.images.intro_anim, 70 | grid:{ 71 | width: 4, 72 | height: 7 73 | }, 74 | frame:{ 75 | width: 1200, 76 | height: 900 77 | }, 78 | anchor:{ 79 | x: 0, 80 | y: 0 81 | }, 82 | x: 0, 83 | y: 0 84 | }; 85 | var hongSprite = new Sprite(hongSpriteConfig); 86 | self.layers.push(hongSprite); 87 | 88 | // DRAW 89 | var BG_WIDTH = 360; 90 | var BG_HEIGHT = 450; 91 | var PARALLAXES = [ 92 | 0, // sky 93 | 0.1, // clouds 94 | 0.25, // buildings 95 | 0.48, // grass 96 | 1.0, // stump 97 | 0, // blackout 98 | 1.0, // HONG 99 | ]; 100 | var OFFSETS = [ 101 | 0, 102 | 0, // clouds 103 | 0, 104 | 0, 105 | 20, 106 | 0, 107 | 20 108 | ] 109 | 110 | var frameTicker = ticker; 111 | var parallaxTicker = 0; 112 | var SHOWN_PLAY_BUTTON = false; 113 | var SHOWN_LOGO = false; 114 | var thePreviousFrame; 115 | self.draw = function(ctx){ 116 | 117 | // TICKER 118 | ticker += 1/60; 119 | 120 | // CLOUD OFFSET 121 | OFFSETS[1] = -80 + ticker*3; 122 | 123 | // Animate Hong: Which frame? 124 | var parallax = 0; 125 | frameTicker += 1/60; 126 | if(GAME_TRANSITION==0 || GAME_TRANSITION==1 || GAME_TRANSITION==2){ 127 | if(frameTicker>590/30){ 128 | if(GAME_TRANSITION==0){ 129 | frameTicker = 381/30; // LOOP to NOM. 130 | } 131 | if(GAME_TRANSITION==1 || GAME_TRANSITION==2){ // actually ew nah stop it 132 | frameTicker = 590/30; // STOP. 133 | } 134 | } 135 | } 136 | if(GAME_TRANSITION==3){ // START PARALLAXING 137 | 138 | parallaxTicker += 1/60; // 0 to 1 in one second 139 | if(parallaxTicker>1) parallaxTicker = 1; 140 | self.layers[5].alpha = parallaxTicker; // blackout alpha 141 | 142 | // 0 to -180 in one second, smoothed 143 | var t = Math.cos(parallaxTicker*Math.TAU/2); // 1 to -1 144 | t = (1-t)/2; // 0 to 1 145 | parallax = -t*215; 146 | 147 | } 148 | 149 | // Find... on ticker! 150 | var results = findOnTicker(frameTicker); 151 | 152 | // Frame, new frame? 153 | var frame = results.frame; 154 | thePreviousFrame = hongSprite.currentFrame; 155 | var isNewFrame = (thePreviousFrame!=frame); 156 | hongSprite.gotoFrame(frame); 157 | 158 | // SFX if new frame 159 | if(isNewFrame && results.sfx){ 160 | sfx(results.sfx, {volume: results.sfxVolume} ); 161 | } 162 | 163 | // Draw all! 164 | for(var i=0; i=530/30){ 170 | SHOWN_LOGO = true; 171 | sfx("intro_scream", {volume:0.9}); 172 | } 173 | if(GAME_TRANSITION==0 && SHOWN_LOGO){ 174 | self.logoSprite.draw(ctx); 175 | } 176 | 177 | // Show Play Button 178 | if(!SHOWN_PLAY_BUTTON && ticker>=645/30){ 179 | SHOWN_PLAY_BUTTON = true; 180 | Game.goto("intro-play-button"); 181 | } 182 | 183 | // NEXT SCENE? 184 | if(frame==26){ 185 | Game.goto("act1"); 186 | } 187 | 188 | }; 189 | 190 | var GAME_TRANSITION = 0; 191 | var _subscriptions = []; 192 | _subscriptions.push( 193 | subscribe("intro-to-game-1", function(){ 194 | GAME_TRANSITION = 1; // BYE LOGO 195 | }) 196 | ); 197 | _subscriptions.push( 198 | subscribe("intro-to-game-2", function(){ 199 | GAME_TRANSITION = 2; // STOP LOOPING 200 | }) 201 | ); 202 | _subscriptions.push( 203 | subscribe("intro-to-game-3", function(){ 204 | frameTicker = 600/30; 205 | GAME_TRANSITION = 3; // START PARALLAXING 206 | 207 | // WHOOSH 208 | sfx("whoosh"); 209 | 210 | // Music 211 | music("hum", {fade:2, volume:0.6}); 212 | 213 | }) 214 | ); 215 | 216 | ////////////////////////////////////////////////////////////////////////////// 217 | ////////////////////////////////////////////////////////////////////////////// 218 | ////////////////////////////////////////////////////////////////////////////// 219 | 220 | // ANIMATE HONG, THE FRAMES! 221 | 222 | var HONG_FRAMES = [ 223 | "0-0", 224 | "1-59-grass_step1-0.1", 225 | "2-79-grass_step2-0.2", 226 | "3-99-grass_step1-0.25", 227 | "4-119-grass_step2-0.3", 228 | "5-139-grass_step1-0.35", 229 | "6-199-bag_short", 230 | "7-234-bag_search", 231 | "8-244", 232 | "9-254", 233 | "8-264", 234 | "9-274", 235 | "10-299-bag_short", 236 | "11-336-bag_kick", 237 | "12-346", 238 | "13-381-sandwich", 239 | "14-400", 240 | "15-410", 241 | "14-420", 242 | "15-430", 243 | "14-440", 244 | "15-450", 245 | "16-470", 246 | 247 | "17-600", 248 | "18-603", 249 | "19-606", 250 | "20-609", 251 | "21-612", 252 | "22-615", 253 | "23-618", 254 | "24-621", 255 | "25-624", 256 | "26-627" 257 | ]; 258 | HONG_FRAMES = HONG_FRAMES.map(function(frame){ 259 | var f = frame.split("-"); 260 | var frame = parseInt(f[0]); 261 | var ticker = parseInt(f[1])/30; 262 | var sfx = f[2] ? f[2] : null; 263 | var sfxVolume = f[3] ? f[3] : 1; 264 | return [frame, ticker, sfx, sfxVolume]; 265 | }); 266 | var findOnTicker = function(ticker){ 267 | var lastConfig; 268 | for(var i=0; i=0&&e<=1){if(o._volume=e,o._muted)return o;o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var t=0;t=0;o--)e._howls[o].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"suspended":"suspended",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var o=new Audio;void 0===o.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var o=new Audio;o.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,o=null;try{o="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!o||"function"!=typeof o.canPlayType)return e;var t=o.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator&&e._navigator.userAgent.match(/OPR\/([0-6].)/g),a=r&&parseInt(r[0].split("/")[1],10)<33;return e._codecs={mp3:!(a||!t&&!o.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!t,opus:!!o.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!o.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),aac:!!o.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!o.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(o.canPlayType("audio/x-m4a;")||o.canPlayType("audio/m4a;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(o.canPlayType("audio/x-mp4;")||o.canPlayType("audio/mp4;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),webm:!!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),dolby:!!o.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(o.canPlayType("audio/x-flac;")||o.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_unlockAudio:function(){var e=this||n;if(!e._audioUnlocked&&e.ctx){e._audioUnlocked=!1,e.autoUnlock=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var o=function(n){for(var t=0;t0?i._seek:t._sprite[e][0]/1e3),s=Math.max(0,(t._sprite[e][0]+t._sprite[e][1])/1e3-_),l=1e3*s/Math.abs(i._rate),c=t._sprite[e][0]/1e3,f=(t._sprite[e][0]+t._sprite[e][1])/1e3,p=!(!i._loop&&!t._sprite[e][2]);i._sprite=e,i._ended=!1;var m=function(){i._paused=!1,i._seek=_,i._start=c,i._stop=f,i._loop=p};if(_>=f)return void t._ended(i);var v=i._node;if(t._webAudio){var h=function(){t._playLock=!1,m(),t._refreshBuffer(i);var e=i._muted||t._muted?0:i._volume;v.gain.setValueAtTime(e,n.ctx.currentTime),i._playStart=n.ctx.currentTime,void 0===v.bufferSource.start?i._loop?v.bufferSource.noteGrainOn(0,_,86400):v.bufferSource.noteGrainOn(0,_,s):i._loop?v.bufferSource.start(0,_,86400):v.bufferSource.start(0,_,s),l!==1/0&&(t._endTimers[i._id]=setTimeout(t._ended.bind(t,i),l)),o||setTimeout(function(){t._emit("play",i._id),t._loadQueue()},0)};"running"===n.state?h():(t._playLock=!0,t.once("resume",h),t._clearTimer(i._id))}else{var y=function(){v.currentTime=_,v.muted=i._muted||t._muted||n._muted||v.muted,v.volume=i._volume*n.volume(),v.playbackRate=i._rate;try{var r=v.play();if(r&&"undefined"!=typeof Promise&&(r instanceof Promise||"function"==typeof r.then)?(t._playLock=!0,m(),r.then(function(){t._playLock=!1,v._unlocked=!0,o||(t._emit("play",i._id),t._loadQueue())}).catch(function(){t._playLock=!1,t._emit("playerror",i._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."),i._ended=!0,i._paused=!0})):o||(t._playLock=!1,m(),t._emit("play",i._id),t._loadQueue()),v.playbackRate=i._rate,v.paused)return void t._emit("playerror",i._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");"__default"!==e||i._loop?t._endTimers[i._id]=setTimeout(t._ended.bind(t,i),l):(t._endTimers[i._id]=function(){t._ended(i),v.removeEventListener("ended",t._endTimers[i._id],!1)},v.addEventListener("ended",t._endTimers[i._id],!1))}catch(e){t._emit("playerror",i._id,e)}};"data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"===v.src&&(v.src=t._src,v.load());var g=window&&window.ejecta||!v.readyState&&n._navigator.isCocoonJS;if(v.readyState>=3||g)y();else{t._playLock=!0;var A=function(){y(),v.removeEventListener(n._canPlayEvent,A,!1)};v.addEventListener(n._canPlayEvent,A,!1),t._clearTimer(i._id)}}return i._id},pause:function(e){var n=this;if("loaded"!==n._state||n._playLock)return n._queue.push({event:"pause",action:function(){n.pause(e)}}),n;for(var o=n._getSoundIds(e),t=0;t=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else r.length>=2&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var a;if(!(void 0!==e&&e>=0&&e<=1))return a=o?t._soundById(o):t._sounds[0],a?a._volume:0;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"volume",action:function(){t.volume.apply(t,r)}}),t;void 0===o&&(t._volume=e),o=t._getSoundIds(o);for(var u=0;u0?t/_:t),l=Date.now();e._fadeTo=o,e._interval=setInterval(function(){var r=(Date.now()-l)/t;l=Date.now(),i+=d*r,i=Math.max(0,i),i=Math.min(1,i),i=Math.round(100*i)/100,u._webAudio?e._volume=i:u.volume(i,e._id,!0),a&&(u._volume=i),(on&&i>=o)&&(clearInterval(e._interval),e._interval=null,e._fadeTo=null,u.volume(o,e._id),u._emit("fade",e._id))},s)},_stopFade:function(e){var o=this,t=o._soundById(e);return t&&t._interval&&(o._webAudio&&t._node.gain.cancelScheduledValues(n.ctx.currentTime),clearInterval(t._interval),t._interval=null,o.volume(t._fadeTo,e),t._fadeTo=null,o._emit("fade",e)),o},loop:function(){var e,n,o,t=this,r=arguments;if(0===r.length)return t._loop;if(1===r.length){if("boolean"!=typeof r[0])return!!(o=t._soundById(parseInt(r[0],10)))&&o._loop;e=r[0],t._loop=e}else 2===r.length&&(e=r[0],n=parseInt(r[1],10));for(var a=t._getSoundIds(n),u=0;u=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var i;if("number"!=typeof e)return i=t._soundById(o),i?i._rate:t._rate;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"rate",action:function(){t.rate.apply(t,r)}}),t;void 0===o&&(t._rate=e),o=t._getSoundIds(o);for(var d=0;d=0?o=parseInt(r[0],10):t._sounds.length&&(o=t._sounds[0]._id,e=parseFloat(r[0]))}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));if(void 0===o)return t;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"seek",action:function(){t.seek.apply(t,r)}}),t;var i=t._soundById(o);if(i){if(!("number"==typeof e&&e>=0)){if(t._webAudio){var d=t.playing(o)?n.ctx.currentTime-i._playStart:0,_=i._rateSeek?i._rateSeek-i._seek:0;return i._seek+(_+d*Math.abs(i._rate))}return i._node.currentTime}var s=t.playing(o);s&&t.pause(o,!0),i._seek=e,i._ended=!1,t._clearTimer(o),t._webAudio||!i._node||isNaN(i._node.duration)||(i._node.currentTime=e);var l=function(){t._emit("seek",o),s&&t.play(o,!0)};if(s&&!t._webAudio){var c=function(){t._playLock?setTimeout(c,0):l()};setTimeout(c,0)}else l()}return t},playing:function(e){var n=this;if("number"==typeof e){var o=n._soundById(e);return!!o&&!o._paused}for(var t=0;t=0&&n._howls.splice(a,1);var u=!0;for(t=0;t=0){u=!1;break}return r&&u&&delete r[e._src],n.noAudio=!1,e._state="unloaded",e._sounds=[],e=null,null},on:function(e,n,o,t){var r=this,a=r["_on"+e];return"function"==typeof n&&a.push(t?{id:o,fn:n,once:t}:{id:o,fn:n}),r},off:function(e,n,o){var t=this,r=t["_on"+e],a=0;if("number"==typeof n&&(o=n,n=null),n||o)for(a=0;a=0;a--)r[a].id&&r[a].id!==n&&"load"!==e||(setTimeout(function(e){e.call(this,n,o)}.bind(t,r[a].fn),0),r[a].once&&t.off(e,r[a].fn,r[a].id));return t._loadQueue(e),t},_loadQueue:function(e){var n=this;if(n._queue.length>0){var o=n._queue[0];o.event===e&&(n._queue.shift(),n._loadQueue()),e||o.action()}return n},_ended:function(e){var o=this,t=e._sprite;if(!o._webAudio&&e._node&&!e._node.paused&&!e._node.ended&&e._node.currentTime=0;t--){if(o<=n)return;e._sounds[t]._ended&&(e._webAudio&&e._sounds[t]._node&&e._sounds[t]._node.disconnect(0),e._sounds.splice(t,1),o--)}}},_getSoundIds:function(e){var n=this;if(void 0===e){for(var o=[],t=0;t=0;if(n._scratchBuffer&&e.bufferSource&&(e.bufferSource.onended=null,e.bufferSource.disconnect(0),t))try{e.bufferSource.buffer=n._scratchBuffer}catch(e){}return e.bufferSource=null,o},_clearSound:function(e){/MSIE |Trident\//.test(n._navigator&&n._navigator.userAgent)||(e.src="data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA")}};var t=function(e){this._parent=e,this.init()};t.prototype={init:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,o._sounds.push(e),e.create(),e},create:function(){var e=this,o=e._parent,t=n._muted||e._muted||e._parent._muted?0:e._volume;return o._webAudio?(e._node=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),e._node.gain.setValueAtTime(t,n.ctx.currentTime),e._node.paused=!0,e._node.connect(n.masterGain)):(e._node=n._obtainHtml5Audio(),e._errorFn=e._errorListener.bind(e),e._node.addEventListener("error",e._errorFn,!1),e._loadFn=e._loadListener.bind(e),e._node.addEventListener(n._canPlayEvent,e._loadFn,!1),e._node.src=o._src,e._node.preload="auto",e._node.volume=t*n.volume(),e._node.load()),e},reset:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._rateSeek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,e},_errorListener:function(){var e=this;e._parent._emit("loaderror",e._id,e._node.error?e._node.error.code:0),e._node.removeEventListener("error",e._errorFn,!1)},_loadListener:function(){var e=this,o=e._parent;o._duration=Math.ceil(10*e._node.duration)/10,0===Object.keys(o._sprite).length&&(o._sprite={__default:[0,1e3*o._duration]}),"loaded"!==o._state&&(o._state="loaded",o._emit("load"),o._loadQueue()),e._node.removeEventListener(n._canPlayEvent,e._loadFn,!1)}};var r={},a=function(e){var n=e._src;if(r[n])return e._duration=r[n].duration,void d(e);if(/^data:[^;]+;base64,/.test(n)){for(var o=atob(n.split(",")[1]),t=new Uint8Array(o.length),a=0;a0?(r[o._src]=e,d(o,e)):t()};"undefined"!=typeof Promise&&1===n.ctx.decodeAudioData.length?n.ctx.decodeAudioData(e).then(a).catch(t):n.ctx.decodeAudioData(e,a,t)},d=function(e,n){n&&!e._duration&&(e._duration=n.duration),0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue())},_=function(){if(n.usingWebAudio){try{"undefined"!=typeof AudioContext?n.ctx=new AudioContext:"undefined"!=typeof webkitAudioContext?n.ctx=new webkitAudioContext:n.usingWebAudio=!1}catch(e){n.usingWebAudio=!1}n.ctx||(n.usingWebAudio=!1);var e=/iP(hone|od|ad)/.test(n._navigator&&n._navigator.platform),o=n._navigator&&n._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),t=o?parseInt(o[1],10):null;if(e&&t&&t<9){var r=/safari/.test(n._navigator&&n._navigator.userAgent.toLowerCase());(n._navigator&&n._navigator.standalone&&!r||n._navigator&&!n._navigator.standalone&&!r)&&(n.usingWebAudio=!1)}n.usingWebAudio&&(n.masterGain=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),n.masterGain.gain.setValueAtTime(n._muted?0:1,n.ctx.currentTime),n.masterGain.connect(n.ctx.destination)),n._setup()}};"function"==typeof define&&define.amd&&define([],function(){return{Howler:n,Howl:o}}),"undefined"!=typeof exports&&(exports.Howler=n,exports.Howl=o),"undefined"!=typeof window?(window.HowlerGlobal=e,window.Howler=n,window.Howl=o,window.Sound=t):"undefined"!=typeof global&&(global.HowlerGlobal=e,global.Howler=n,global.Howl=o,global.Sound=t)}(); 3 | /*! Spatial Plugin */ 4 | !function(){"use strict";HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(e){var n=this;if(!n.ctx||!n.ctx.listener)return n;for(var t=n._howls.length-1;t>=0;t--)n._howls[t].stereo(e);return n},HowlerGlobal.prototype.pos=function(e,n,t){var r=this;return r.ctx&&r.ctx.listener?(n="number"!=typeof n?r._pos[1]:n,t="number"!=typeof t?r._pos[2]:t,"number"!=typeof e?r._pos:(r._pos=[e,n,t],void 0!==r.ctx.listener.positionX?(r.ctx.listener.positionX.setTargetAtTime(r._pos[0],Howler.ctx.currentTime,.1),r.ctx.listener.positionY.setTargetAtTime(r._pos[1],Howler.ctx.currentTime,.1),r.ctx.listener.positionZ.setTargetAtTime(r._pos[2],Howler.ctx.currentTime,.1)):r.ctx.listener.setPosition(r._pos[0],r._pos[1],r._pos[2]),r)):r},HowlerGlobal.prototype.orientation=function(e,n,t,r,o,i){var a=this;if(!a.ctx||!a.ctx.listener)return a;var s=a._orientation;return n="number"!=typeof n?s[1]:n,t="number"!=typeof t?s[2]:t,r="number"!=typeof r?s[3]:r,o="number"!=typeof o?s[4]:o,i="number"!=typeof i?s[5]:i,"number"!=typeof e?s:(a._orientation=[e,n,t,r,o,i],void 0!==a.ctx.listener.forwardX?(a.ctx.listener.forwardX.setTargetAtTime(e,Howler.ctx.currentTime,.1),a.ctx.listener.forwardY.setTargetAtTime(n,Howler.ctx.currentTime,.1),a.ctx.listener.forwardZ.setTargetAtTime(t,Howler.ctx.currentTime,.1),a.ctx.listener.upX.setTargetAtTime(e,Howler.ctx.currentTime,.1),a.ctx.listener.upY.setTargetAtTime(n,Howler.ctx.currentTime,.1),a.ctx.listener.upZ.setTargetAtTime(t,Howler.ctx.currentTime,.1)):a.ctx.listener.setOrientation(e,n,t,r,o,i),a)},Howl.prototype.init=function(e){return function(n){var t=this;return t._orientation=n.orientation||[1,0,0],t._stereo=n.stereo||null,t._pos=n.pos||null,t._pannerAttr={coneInnerAngle:void 0!==n.coneInnerAngle?n.coneInnerAngle:360,coneOuterAngle:void 0!==n.coneOuterAngle?n.coneOuterAngle:360,coneOuterGain:void 0!==n.coneOuterGain?n.coneOuterGain:0,distanceModel:void 0!==n.distanceModel?n.distanceModel:"inverse",maxDistance:void 0!==n.maxDistance?n.maxDistance:1e4,panningModel:void 0!==n.panningModel?n.panningModel:"HRTF",refDistance:void 0!==n.refDistance?n.refDistance:1,rolloffFactor:void 0!==n.rolloffFactor?n.rolloffFactor:1},t._onstereo=n.onstereo?[{fn:n.onstereo}]:[],t._onpos=n.onpos?[{fn:n.onpos}]:[],t._onorientation=n.onorientation?[{fn:n.onorientation}]:[],e.call(this,n)}}(Howl.prototype.init),Howl.prototype.stereo=function(n,t){var r=this;if(!r._webAudio)return r;if("loaded"!==r._state)return r._queue.push({event:"stereo",action:function(){r.stereo(n,t)}}),r;var o=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof n)return r._stereo;r._stereo=n,r._pos=[n,0,0]}for(var i=r._getSoundIds(t),a=0;a2&&void 0!==arguments[2])||arguments[2],o=arguments[3];return G(this,t.call(this,e,r,n,o))}L(e,t);e.prototype._init=function(t,e){this._result={};this._enumerate(e);0===this._remaining&&v(this.promise,this._result)};e.prototype._enumerate=function(t){var e=this.promise,r=[];for(var n in t)St.call(t,n)&&r.push({position:n,entry:t[n]});var o=r.length;this._remaining=o;for(var i=void 0,s=0;e._state===mt&&s .icon, #about > .icon{ 72 | position: absolute; 73 | width: 0; 74 | height: 0; 75 | top: 10px; 76 | } 77 | 78 | #gear{ 79 | left: 0; 80 | border-top-right-radius: 50px; 81 | } 82 | #gear > .icon{ 83 | left: 4px; 84 | } 85 | #about{ 86 | right: 0; 87 | border-top-left-radius: 50px; 88 | } 89 | #about > .icon{ 90 | color: rgba(255,255,255,0.4); 91 | font-weight: bold; 92 | right: 19px; 93 | } 94 | 95 | 96 | 97 | 98 | /****************************************************************************************************** 99 | 100 | PAUSED & LOADING 101 | 102 | ******************************************************************************************************/ 103 | 104 | #paused, #loading{ 105 | display: none; 106 | 107 | width: 100%; 108 | height: 100%; 109 | position: absolute; 110 | top: 0; 111 | left: 0; 112 | background: rgba(40,40,40,0.9); 113 | color: #fff; 114 | font-weight: bold; 115 | text-align: center; 116 | } 117 | #paused > div{ 118 | position: absolute; 119 | margin: auto; 120 | top: 0; 121 | left: 0; 122 | right: 0; 123 | bottom: 0; 124 | width: 260px; 125 | height: 70px; 126 | font-size: 69px; 127 | } 128 | #paused > div > div{ 129 | font-size: 20px; 130 | font-weight: lighter; 131 | line-height: 1em; 132 | width: 220px; 133 | margin: 15px auto; 134 | } 135 | #paused[modal=yes]{ 136 | background: rgba(70,70,70,0.9); 137 | } 138 | #paused[modal=yes] > div{ 139 | display: none; 140 | } 141 | 142 | #loading_bar{ 143 | width: 150px; 144 | height: 100px; 145 | overflow: hidden; 146 | 147 | position: absolute; 148 | margin: auto; 149 | top: 0; 150 | left: 0; 151 | right: 0; 152 | bottom: 0; 153 | } 154 | #loading_bar_bg{ 155 | width: 140px; 156 | height: 0px; 157 | background: #ff4040; 158 | position: absolute; 159 | left:5px; 160 | bottom: 44px; 161 | } 162 | #loading_pic{ 163 | width: 100%; 164 | height: 100%; 165 | background: url(../sprites/ui/preloader.png); 166 | position: absolute; 167 | top: 0; 168 | left: 0; 169 | background-size: 100%; 170 | } 171 | #loading{ 172 | display:block; 173 | background:#282828; 174 | } 175 | #loading[loaded=yes]{ 176 | cursor: pointer; 177 | background:#282828; 178 | } 179 | #loading[loaded=yes]:hover{ 180 | background:#444; 181 | } 182 | #loading[loaded=yes] #loading_bar_bg{ 183 | display: none; 184 | } 185 | #loading[loaded=yes] #loading_pic{ 186 | background-position: 0px -100%; 187 | } 188 | #loading[loaded=yes]:hover #loading_pic{ 189 | background-position: 0px -200%; 190 | } 191 | #loading[loaded=yes]:active #loading_pic{ 192 | background-position: 0px -300%; 193 | } 194 | 195 | 196 | 197 | /****************************************************************************************************** 198 | 199 | ABOUT / END DEMO 200 | 201 | ******************************************************************************************************/ 202 | 203 | #end_demo{ 204 | 205 | position: absolute; 206 | top:600px; 207 | left:0; 208 | 209 | background: #2E2E2E; 210 | width: 100%; 211 | height: 100%; 212 | color:#fff; 213 | text-align: center; 214 | 215 | /* Spring OUT only */ 216 | -webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */ 217 | -webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 218 | -moz-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 219 | -o-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 220 | transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */ 221 | 222 | -webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */ 223 | -webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 224 | -moz-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 225 | -o-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 226 | transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */ 227 | 228 | 229 | } 230 | #end_demo_tbc{ 231 | 232 | position: absolute; 233 | top: 220px; 234 | display: none; 235 | 236 | background: url(../sprites/end_demo/tbc.png); 237 | background-size: 100%; 238 | width: 100%; 239 | height: 100px; 240 | } 241 | #end_demo_words{ 242 | width: 310px; 243 | margin: 0 auto; 244 | font-size: 18px; 245 | line-height: 1.3em; 246 | } 247 | #end_demo_words a{ 248 | color: #ff4040; 249 | font-weight: normal; 250 | } 251 | #end_demo_words a:hover{ 252 | color: #ff8080; 253 | } 254 | #end_demo a.no_deco{ 255 | text-decoration: none; 256 | } 257 | 258 | #the_newsletter #email{ 259 | width: 300px; 260 | font-size: 20px; 261 | border: none; 262 | padding: 5px; 263 | font-weight: 300; 264 | margin-top: 10px; 265 | border-radius: 5px; 266 | } 267 | #the_newsletter #email_info{ 268 | position: relative; 269 | width: 310px; 270 | height: 60px; 271 | } 272 | #the_newsletter #gdpr{ 273 | position: absolute; 274 | transform: scale(2); 275 | top: 11px; 276 | left: 3px; 277 | } 278 | #the_newsletter #consent{ 279 | font-size: 13px; 280 | position: absolute; 281 | left: 31px; 282 | top: 8px; 283 | width: 110px; 284 | line-height: 1em; 285 | text-align: left; 286 | } 287 | #the_newsletter #submit{ 288 | background: #ff4040; 289 | position: absolute; 290 | top: 6px; 291 | left: 150px; 292 | width: 160px; 293 | height: 30px; 294 | font-size: 20px; 295 | font-weight: 300; 296 | border-radius: 30px; 297 | border: none; 298 | color: #ffffff; 299 | cursor: pointer; 300 | } 301 | #the_newsletter #submit:hover{ 302 | background: #ff7070; 303 | } 304 | #the_newsletter #submit[disabled]{ 305 | background: #555; 306 | color: #222; 307 | cursor: default; 308 | } 309 | 310 | #patreon{ 311 | width: 160px; 312 | height: 56px; 313 | background: url(../sprites/end_demo/patreon.png); 314 | background-size: 100%; 315 | margin: 5px auto 10px auto; 316 | cursor: pointer; 317 | position: relative; 318 | } 319 | #patreon:hover{ 320 | top:-2px; 321 | } 322 | 323 | #share{ 324 | overflow: hidden; 325 | text-align: center; 326 | padding: 2px 0; 327 | margin-bottom: 3px; 328 | } 329 | #share div{ 330 | display: inline-block; 331 | overflow: hidden; 332 | width:40px; height:40px; 333 | background: url(../sprites/end_demo/share.png); 334 | background-size: 300%; 335 | position: relative; 336 | cursor: pointer; 337 | } 338 | #share div:hover{ 339 | top:-2px; 340 | } 341 | #share #share_fb{ 342 | background-position: 0px; 343 | } 344 | #share #share_tw{ 345 | background-position: -40px; 346 | } 347 | #share #share_em{ 348 | background-position: -80px; 349 | } 350 | 351 | #replay{ 352 | width:100px; 353 | height: 80px; 354 | background: url(../sprites/end_demo/replay.png); 355 | background-size: 300%; 356 | position: absolute; 357 | bottom: 0; 358 | left: 130px; 359 | cursor: pointer; 360 | } 361 | #replay:hover{ 362 | background-position: -100px; 363 | } 364 | #replay:active{ 365 | background-position: -200px; 366 | } 367 | 368 | #end_demo #end_words1{ display: inline; } 369 | #end_demo #end_words2{ display: none; } 370 | #end_demo #replay{ display: block; } 371 | #end_demo #close_about{ display: none; } 372 | #end_demo .about_padding{ 373 | padding-top: 10px; 374 | } 375 | #end_demo #end_demo_words{ 376 | padding-top: 50px; 377 | } 378 | 379 | #end_demo[about=yes]{ 380 | padding-top: 25px; 381 | height: 490px; 382 | } 383 | #end_demo[about=yes] #end_words1{ display: none; } 384 | #end_demo[about=yes] #end_words2{ display: inline; } 385 | #end_demo[about=yes] #replay{ display: none; } 386 | #end_demo[about=yes] #close_about{ 387 | display: block; 388 | float: none; 389 | width: 50px; 390 | margin: 10px auto; 391 | } 392 | #end_demo[about=yes] .about_padding{ 393 | padding-top: 0px; 394 | } 395 | #end_demo[about=yes] #end_demo_words{ 396 | padding-top: 0px; 397 | } 398 | 399 | 400 | /****************************************************************************************************** 401 | 402 | OPTIONS 403 | 404 | ******************************************************************************************************/ 405 | 406 | #options{ 407 | position: absolute; 408 | top: 600px; 409 | 410 | width: 300px; 411 | padding: 15px; 412 | margin: 15px; 413 | 414 | background: #2e2e2e; 415 | color:#fff; 416 | 417 | /* Spring OUT only */ 418 | -webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */ 419 | -webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 420 | -moz-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 421 | -o-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 422 | transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */ 423 | 424 | -webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */ 425 | -webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 426 | -moz-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 427 | -o-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 428 | transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */ 429 | 430 | } 431 | #options #volume_options{ 432 | display: none; 433 | } 434 | #options[past_intro=yes] #volume_options{ 435 | display: block; 436 | } 437 | #text_speed_preview{ 438 | height: 1.3em; 439 | } 440 | #close_about, #options_ok{ 441 | display: inline-block; 442 | background: #000; 443 | padding: 5px 10px; 444 | border-radius: 10px; 445 | color: #fff; 446 | font-weight: bold; 447 | margin: 0 auto; 448 | float: right; 449 | 450 | position: relative; 451 | top:0; 452 | 453 | cursor: pointer; 454 | } 455 | #close_about:hover, #options_ok:hover{ 456 | background: #666; 457 | top:-2px; 458 | } 459 | #text_automatic_toggle{ 460 | border: 1px solid #fff; 461 | border-radius: 5px; 462 | padding: 1px 5px; 463 | cursor: pointer; 464 | } 465 | #text_automatic_toggle:hover{ 466 | background:rgba(255,255,255,0.3); 467 | } 468 | #click_to_advance{ 469 | display: block; 470 | position: absolute; 471 | text-align: center; 472 | width: 100%; 473 | top: 254px; 474 | color:#fff; 475 | } 476 | 477 | /* 478 | Slider CSS by Noah Blon 479 | https://codepen.io/noahblon/pen/OyajvN 480 | */ 481 | input[type="range"]{ 482 | margin: auto; 483 | -webkit-appearance: none; 484 | position: relative; 485 | overflow: hidden; 486 | /*height: 40px; 487 | width: 200px;*/ 488 | cursor: pointer; 489 | border-radius: 0; /* iOS */ 490 | 491 | width: 300px; 492 | height: 30px; 493 | } 494 | #text_speed_slider{ 495 | width: 150px; 496 | } 497 | ::-webkit-slider-runnable-track{ 498 | background: #ddd; 499 | } 500 | ::-webkit-slider-thumb { 501 | -webkit-appearance: none; 502 | width: 30px; /* 1 */ 503 | height: 30px; 504 | background: #fff; 505 | box-shadow: -100vw 0 0 100vw #ff4040; 506 | border: 2px solid #999; /* 1 */ 507 | } 508 | ::-moz-range-track { 509 | height: 30px; 510 | background: #ddd; 511 | } 512 | ::-moz-range-thumb { 513 | background: #fff; 514 | height: 30px; 515 | width: 30px; 516 | border: 3px solid #999; 517 | border-radius: 0 !important; 518 | box-shadow: -100vw 0 0 100vw #ff4040; 519 | box-sizing: border-box; 520 | } 521 | ::-ms-fill-lower { 522 | background: #ff4040; 523 | } 524 | ::-ms-thumb { 525 | background: #fff; 526 | border: 2px solid #999; 527 | height: 30px; 528 | width: 30px; 529 | box-sizing: border-box; 530 | } 531 | ::-ms-ticks-after { 532 | display: none; 533 | } 534 | ::-ms-ticks-before { 535 | display: none; 536 | } 537 | ::-ms-track { 538 | background: #ddd; 539 | color: transparent; 540 | height: 30px; 541 | border: none; 542 | } 543 | ::-ms-tooltip { 544 | display: none; 545 | } 546 | 547 | 548 | 549 | /****************************************************************************************************** 550 | 551 | DIALOGUEZ 552 | 553 | ******************************************************************************************************/ 554 | 555 | 556 | .clear-both{ 557 | clear:both; 558 | } 559 | 560 | .mini-icon{ 561 | display: inline-block; 562 | background: url(../sprites/ui/icons.png); 563 | background-size: 700%; 564 | width: 20px; height:20px; 565 | position: relative; 566 | } 567 | .mini-icon[pic="gear"]{ 568 | background-position: -0px 0px; 569 | } 570 | .mini-icon[pic="about"]{ 571 | background-position: -100% 0px; 572 | } 573 | .mini-icon[pic="next"]{ 574 | background-position: -200% 0px; 575 | } 576 | .mini-icon[pic="play1"]{ 577 | background-position: -300% 0px; 578 | } 579 | .mini-icon[pic="play2"]{ 580 | background-position: -400% 0px; 581 | } 582 | .mini-icon[pic="click"]{ 583 | background-position: -500% 0px; 584 | } 585 | .mini-icon[pic="ok"]{ 586 | background-position: -600% 0px; 587 | } 588 | 589 | .narrator-bubble, .narrator-bubble-2, .narrator-bubble-4{ 590 | position: relative; 591 | color: #FFFFFF; 592 | text-align: center; 593 | padding: 0 10px; 594 | font-size: 1.3em; 595 | margin: 25px 15px; 596 | font-weight: bold; 597 | } 598 | .narrator-bubble:before, .narrator-bubble-4:before{ 599 | 600 | content: ''; 601 | 602 | position: absolute; 603 | top: -9px; 604 | left: 0; 605 | 606 | border: 6px solid #fff; 607 | border-right: 0; 608 | 609 | width: 10px; 610 | height: calc(100% + 4px); 611 | 612 | } 613 | .narrator-bubble:after, .narrator-bubble-4:after{ 614 | 615 | content: ''; 616 | 617 | position: absolute; 618 | top: -9px; 619 | right: 0; 620 | 621 | border: 6px solid #fff; 622 | border-left: 0; 623 | 624 | width: 10px; 625 | height: calc(100% + 4px); 626 | 627 | } 628 | .narrator-bubble i, .narrator-bubble-2 i, .narrator-bubble-4 i{ 629 | font-style: normal; 630 | color: #ff4040; 631 | } 632 | .narrator-bubble i.italics, .narrator-bubble-4 i.italics{ 633 | font-style: italic; 634 | color: #fff; 635 | } 636 | .narrator-bubble-2{ 637 | color: #fff; 638 | background: #000; 639 | margin: 10px 15px; 640 | padding: 15px 0; 641 | } 642 | .narrator-bubble-4{ 643 | font-size: 20px; 644 | } 645 | .narrator-bubble-3 { 646 | 647 | position: relative; 648 | background: #000000; 649 | color: #ffffff; 650 | padding: 15px; 651 | margin: 5px 30px; 652 | 653 | text-align: center; 654 | 655 | /*opacity: 0; 656 | transition: all 0.3s ease-in-out;*/ 657 | 658 | } 659 | 660 | .hong-bubble { 661 | position: relative; 662 | background: #ffffff; 663 | color: #000000; 664 | border-radius: .4em; 665 | padding: 15px; 666 | margin: 5px 30px; 667 | 668 | opacity: 0; 669 | left: -15px; 670 | transition: all 0.3s ease-in-out; 671 | 672 | display: inline-block; 673 | float: left; 674 | 675 | } 676 | .hong-bubble:after { 677 | content: ''; 678 | position: absolute; 679 | left: 1px; 680 | top: 50%; 681 | width: 0; 682 | height: 0; 683 | border: 15px solid transparent; 684 | border-right-color: #ffffff; 685 | border-left: 0; 686 | margin-top: -15px; 687 | margin-left: -15px; 688 | } 689 | 690 | .beebee-bubble { 691 | position: relative; 692 | background: #000000; 693 | color: #ffffff; 694 | border-radius: .4em; 695 | padding: 15px; 696 | margin: 5px 30px; 697 | 698 | opacity: 0; 699 | left: 15px; 700 | transition: all 0.3s ease-in-out; 701 | 702 | display: inline-block; 703 | float: right; 704 | 705 | } 706 | .beebee-bubble:after { 707 | content: ''; 708 | position: absolute; 709 | right: 1px; 710 | top: 50%; 711 | width: 0; 712 | height: 0; 713 | border: 15px solid transparent; 714 | border-left-color: #000000; 715 | border-right: 0; 716 | margin-top: -15px; 717 | margin-right: -15px; 718 | } 719 | 720 | #game_choices{ 721 | 722 | width: 100%; 723 | height: 110px; 724 | padding: 20px 0; 725 | 726 | position: absolute; 727 | bottom:0; 728 | 729 | background: #2E2E2E; 730 | text-align: center; 731 | color: #fff; 732 | font-weight: lighter; 733 | 734 | } 735 | #game_choices > div{ 736 | padding: 0.25em 0; 737 | cursor: pointer; 738 | position: relative; 739 | 740 | /* Spring OUT only */ 741 | -webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */ 742 | -webkit-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 743 | -moz-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 744 | -o-transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); 745 | transition: top 500ms cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */ 746 | 747 | -webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1); /* older webkit */ 748 | -webkit-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 749 | -moz-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 750 | -o-transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); 751 | transition-timing-function: cubic-bezier(0.350, 0.005, 0.370, 1.390); /* custom */ 752 | } 753 | #game_choices > div:hover{ 754 | background: rgba(255,255,255,0.25); 755 | } 756 | 757 | /***********************************/ 758 | /***********************************/ 759 | /***********************************/ 760 | 761 | canvas{ 762 | border: none; 763 | } 764 | #game_canvas{ 765 | position: absolute; 766 | top:0; left:0; 767 | } 768 | 769 | #game_hp{ 770 | position: absolute; 771 | width: 360px; 772 | height: 100px; 773 | top:-100px; 774 | left:0; 775 | transition: top 0.5s ease-in-out; 776 | } 777 | 778 | /****************************************************************************************************** 779 | 780 | CORNER TEXT 781 | 782 | ******************************************************************************************************/ 783 | 784 | #topleft, #bottomright{ 785 | width: 200px; 786 | color: #555; 787 | font-family: Helvetica, Arial, sans-serif; 788 | font-weight: 500; 789 | font-size: 14px; 790 | line-height: 1.3em; 791 | position: absolute; 792 | } 793 | #topleft a, #bottomright a{ 794 | color: #666; 795 | } 796 | #topleft a:hover, #bottomright a:hover{ 797 | color: #888; 798 | } 799 | #topleft{ 800 | top:10px; 801 | left:10px; 802 | text-align: left; 803 | } 804 | #bottomright{ 805 | bottom:10px; 806 | right:10px; 807 | text-align: right; 808 | } 809 | @media screen and (max-width: 800px) { 810 | #topleft, #bottomright { 811 | display: none; 812 | } 813 | } --------------------------------------------------------------------------------