1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <meta name="viewport" content="width=device-width"> 6 <title>The Room Adventure: Additional Features</title> 7 8 <link href="/index.css" rel="stylesheet" type="text/css"/> 9 <link href="/roomadventure/rooms.css" rel="stylesheet" type="text/css"/> 10 <link rel="shortcut icon" href="http://stephenjwolf.com/coding/favicon.ico" type="image/x-icon"/> 11 </head> 12 <body> 13 <div id="body"><!-- Required div for navigation bar --> 14 <div class="imgfloater max150px"><img src="/images/SergeiStudious.png"></div> 15 <h1>The Room Adventure: Additional Features</h1> 16 17 <h2>Locking Rooms and Needing Keys</h2> 18 <h4>Difficulty: ★★★☆☆</h4> 19 <h4><em>Requirement: Added Interactive Features</em></h4> 20 <h4><strong>Note: This version of the feature will not necessarily work with the randomizeRoomLayout() function from 21 the book.</strong> It is recommended you also create the <a href="addkeycheck.html">checkKeys()</a> function to 22 correct this and to check your lock and key placement.</h4> 23 24 25 <!-- 26 🔐 closed lock and key symbol 27 🔑 key symbol 28 🔒 lock symbol 29 🔓 open lock symbol 30 --> 31 32 <div class="flex-container"> 33 <div> 34 35 <!--Explanation--> 36 <p>Sometimes a good challenge is making the player find a key they need to get to another location. This lets you 37 control the flow of your game better.</p> 38 <p>There are many ways we can handle this situation. Is there only one type of key? Can a key be used more than 39 once? Do unlocked doors get locked again?</p> 40 <p>For the purposes here, we will make this closer to real life and less like some video games.</p> 41 <ul> 42 <li>Keys won't break or be consumed when they are used.</li> 43 <li>Keys can be used over and over.</li> 44 <li>Different locks will usually need different keys.</li> 45 <li>Some locks can share the same key.</li> 46 </ul> 47 <h3>Note: this feature isn't particularly difficult to add, but it has a lot of parts that need to be updated for 48 it to work.</h3> 49 50 <div class="sidenote"><img class="sidenoteimage" src="/images/DrLupinoTakeNote.png"> <strong>Sidenote:</strong> 51 The <span class="function">randomizeRoomLayout</span> function is an optional feature from the book that 52 shuffles the locations of the rooms. This may lead to a key being hidden behind a locked door where the player 53 can't get to it. If you're using this basic version of the locked door feature, you should disable the <span 54 class="function">randomizeRoomLayout</span> function by commenting it out inside <span class="function">startGame</span>. 55 Do so by putting two slashes <code>//</code> in front of the line, like this. 56 57 <div class="code override"> 58 <ul> 59 <li><span class="comment">//rooms = <span class="function">randomizeRoomLayout</span>(rooms)</span>;</li> 60 </ul> 61 </div> 62 </div> 63 64 65 <p>O-Key-Do-Key... let's get to it.</p> 66 67 <h2>What we need to do</h2> 68 69 <ul> 70 <li>Let's add a property to our player that holds the keys.</li> 71 <li>Add a property to specific rooms that are locked, with the key needed to open it.</li> 72 <li>Add keys to other rooms to be found.</li> 73 <li>Prevent player from going into locked rooms.</li> 74 <li>Handle finding and using keys.</li> 75 </ul> 76 </div> 77 <div class="imgwrapper"> 78 <br> 79 <!--Screenshot--> 80 <!--<img src="/roomadventure/screenimages/getplayername.png">--> 81 </div> 82 </div> 83 84 <p>We want to add some challenge by locking some rooms and making the player find the right key for it. Once again, we 85 have many ways to achieve this. I'm making certain design decisions here; some for simplicity, and some for future 86 plans.</p> 87 88 <h2>Step 1: Prep the player object</h2> 89 <p>By far the easiest part of this feature is to add a new <span class="property">keys</span> property to the player. 90 We're going to use an array so the player can hold more than one key at a time. I've played games where you could 91 only hold one. It wasn't very realistic and although it added a definite strategic challenge, it was more of a 92 frustration, and we don't want that experience for our player.</p> 93 <p>You have an idea how to do this on your own, right?</p> 94 95 <p>Go into your <span class="function">getPlayer</span> function. Inside the <span class="object">player</span> 96 object, add the <span class="property">keys</span> property as an empty array.</p> 97 98 <div class="code"> 99 <ul> 100 <li><span class="keyword">var</span> <span class="object">player</span> =</li> 101 <li>{ 102 <ul> 103 <li><span class="property">name</span>: <span class="string">"Lica"</span>,</li> 104 <li><span class="property">score</span>: 0,</li> 105 <li><span class="property">currentRoom</span>: <span class="object">rooms</span>[<span class="string">"living 106 room"</span>], 107 </li> 108 <li><span class="property">inventory</span>: [],</li> 109 <li><strong><span class="property">keys</span>: [], <span class="comment">// add this</span></strong></li> 110 <li><span class="property">itemsLeftToFix</span>: 13,</li> 111 <li><span class="property">maxScore</span>: 0,</li> 112 <li><span class="property">pathTaken</span>: []</li> 113 </ul> 114 </li> 115 <li>};</li> 116 </ul> 117 </div> 118 <p>I added mine right after the <span class="property">inventory</span> property because they're related, but you can 119 put it anywhere in the list.</p> 120 121 <h2>Step 2: Locking a room and placing its key</h2> 122 <p>Think about the layout of your house and where you want to have a locked room. Then we're going to put its key 123 somewhere else. Hey, it's like how we originally set up the game with our broken things! Yep, but it's an added 124 layer on top.</p> 125 126 <h3>A few locking rules:</h3> 127 <h4>Don't lock the room your player starts in.</h4> 128 <p>The way we're going to handle locked rooms here, your player will be able to walk out of the room, but won't be 129 able to get back in without a key.</p> 130 131 <p>You can do that if you want; people do get locked out of things all the time. But it's an awkward experience for 132 the player. "Hey, wait, I was just in there, why can't I go back in?"</p> 133 134 <h4>Don't lock the next room over unless you have a second exit.</h4> 135 <p>For example, I start in the living room. I have a dining room to the north and a hallway to the east. If I lock my 136 dining room, that's ok, because my player can still go east and eventually find a key that way. </p> 137 138 <p>On the other hand, if my player started in the pantry, and I locked the kitchen, there would be no place for the 139 player to go to. They'd be trapped.</p> 140 141 <h4>When placing the key, make sure the player can reach it.</h4> 142 <p>This seems obvious, but it's easy to overlook, especially if you lock more than one room and use more than one kind 143 of key. Let's say you need a red key to open the dining room. In there, I hid the blue key. I hid the red key inside 144 the office and I need the blue key to open the office. Uh oh. There's a problem. I can't get to either key.</p> 145 146 <p>It pays to have a map drawn out with the doors you're locking and the keys you need.</p> 147 148 <p>Incidentally, this is why we can't use our <span class="function">randomizeRoomLayout</span> function without some 149 serious computer decision-making code to place locks and keys.</p> 150 151 <h2>Step 3: Setting the lock and key</h2> 152 <p>Go on and pick a room that you want to lock. We are going to another property to that room to tell us which it 153 needs. The fact that it needs a key will tell us that it's locked at all.</p> 154 155 <p>For flexibility, we're going to use an array here instead of a string. What if we later decide to have a master key 156 that works for all bedrooms? Then two possible keys could open that room up. Using an array now will allow us to 157 make use of that later if we want to.</p> 158 159 <h3>Go into <span class="function">getRooms</span>.</h3> 160 <p>We have two things to do here. Lock a room and place the key elsewhere.</p> 161 162 <h4>Lock a room.</h4> 163 <p>Find the room you want to lock and add the <code><span class="property">locked</span>: [<span class="string">"brass 164 key"</span>]</code> property. (You don't have to use a brass key. Use whatever you like.)</p> 165 166 <div class="code"> 167 <ul> 168 <li><span class="keyword">var</span> diningRoom =</li> 169 <li>{ 170 <ul> 171 <li><span class="property">name</span>: <span class="string">"dining room"</span>,</li> 172 <li><span class="property">locked</span>: [<span class="string">"brass key"</span>],</li> 173 <li><span class="comment">//rest of properties</span></li> 174 </ul> 175 </li> 176 </ul> 177 </div> 178 179 <h4>Place the key.</h4> 180 <p>Now go to another room and place the key into it. For consistency, we'll also use an array. Let's add the 181 <code><span class="property">keys</span>: [<span class="string">"brass key"</span>]</code> property. If you changed 182 the name of the key, make sure you use that same name.</p> 183 184 <div class="code"> 185 <ul> 186 <li><span class="keyword">var</span> office =</li> 187 <li>{ 188 <ul> 189 <li><span class="property">name</span>: <span class="string">"office"</span>,</li> 190 <li><span class="property">keys</span>: [<span class="string">"brass key"</span>],</li> 191 <li><span class="comment">//rest of properties</span></li> 192 </ul> 193 </li> 194 </ul> 195 </div> 196 197 <h2>Step 4: Update navigation buttons</h2> 198 <p>We need to let the player know if the room they want to go to is locked. We'll show this on the navigation button 199 itself. All we need is a simple conditional statement to show it.</p> 200 201 <p>Go to <span class="function">createNavigationButtons</span>. Depending on what features you have added, your 202 section may look a little different, but the important line you're looking for is the one that closes the <code></button></code> 203 tag. Your new <span class="keyword">if</span> statement goes just above that.</p> 204 205 <div class="code"> 206 <ul> 207 <li><span class="keyword">if</span> (room.<span class="property">locked</span>)</li> 208 <li>{ 209 <ul> 210 <li>button += <span class="string">"<br>&#128274; <em>locked</em>"</span>; <span 211 class="comment">//this is new</span></li> 212 </ul> 213 </li> 214 <li>}</li> 215 <li>button += <span class="string">"</button>"</span>; <span class="comment">//this was already there</span> 216 </li> 217 </ul> 218 </div> 219 220 <p>Ok, now the button will show us if a room is locked, but it won't keep us out! Let's tackle that next. The HTML 221 entity number <code>&#128274;</code> shows <code>🔒</code>.</p> 222 223 <!-- 224 <p><strong>Note:</strong> If you did not add the <em>Tracking the Player</em> feature from the book, then the 225 <code><span class="object">room</span>.<span class="property">locked</span></code> will produce an error in the 226 first line here. Just add these lines right before that line to fix it.</p> 227 --> 228 229 <div class="code"> 230 <ul> 231 <li><span class="keyword">var</span> exits = <span class="object">player</span>.<span 232 class="property">currentRoom</span>.<span class="property">exits</span>[exit]; 233 </li> 234 <li><span class="keyword">var</span> roomName = <span class="object">exits</span>[exit];</li> 235 <li><span class="keyword">var</span> room = <span class="object">rooms</span>[roomName];</li> 236 </ul> 237 </div> 238 239 240 <h2>Step 5: Preventing the player from entering a locked room</h2> 241 <p>Well if it's locked, it's locked. They can't go in without the key. So let's keep 'em out!</p> 242 243 <p>Again, here's a design decision. If the player has the key in their possession, do they need to specifically unlock 244 the door first or will it open automatically on its own? I'm going to keep the player interactive by making them 245 unlock the door first. This way, if they use the wrong key, they can't get in. 246 247 <p>Our <span class="function">movePlayer</span> function is called when the player presses a navigation button, so 248 let's go there to handle the locked room situation.</p> 249 250 <p>Here's the entire function as it is. Do you know where we have to change it?</p> 251 252 <div class="code"> 253 <ul> 254 <li><span class="keyword">function</span> <span class="function">movePlayer</span>(direction)</li> 255 <li>{ 256 <ul> 257 <li><span class="keyword">var</span> exits = <span class="object">player</span>.<span class="property">currentRoom</span>.<span 258 class="property">exits</span>; 259 </li> 260 <li><span class="keyword">var</span> roomName = <span class="object">exits</span>[direction];</li> 261 <li><span class="keyword">var</span> roomToGoTo = <span class="object">rooms</span>[roomName];</li> 262 <li><span class="object">player</span>.<span class="property">currentRoom</span> = <span class="object">roomToGoTo</span>; 263 </li> 264 <li><span class="function">moveToRoom</span>();</li> 265 </ul> 266 </li> 267 <li>}</li> 268 </ul> 269 </div> 270 271 <p>We used a lot of helper variables when we made this one. Which variable represents the room that might be locked? 272 Yep. It's <code>roomToGoTo</code>.</p> 273 274 <p>We're going to insert a conditional statement to see if the room is locked. If so, we're going to let the player 275 know. If not, we're going to finish the function as normal. That means we have to wrap those last two lines of code 276 in an <span class="keyword">else</span> block of our upcoming <span class="keyword">if</span> statement.</p> 277 <p>This goes right after <code>roomToGoTo</code> is created.</p> 278 279 <div class="code"> 280 <ul> 281 <li><span class="keyword">var</span> roomToGoTo = <span class="object">rooms</span>[roomName];</li> 282 <li><span class="keyword">if</span> (<span class="object">roomToGoTo</span>.<span class="property">locked</span>) 283 </li> 284 <li>{ 285 <ul> 286 <li><span class="keyword">var</span> text = <span class="string">"<h3>You cannot go to the "</span> + 287 direction + <span class="string">".</h3>"</span>; 288 </li> 289 <li>text += <span class="string">"<h3>That way is locked.</h3>"</span>;</li> 290 <li><span class="object">display</span>.<span class="function">broken</span>(text);</li> 291 292 <li> </li> 293 <li><span class="keyword">var</span> penalty = 2;</li> 294 <li>text = <span class="string">"You lose "</span> + penalty + <span class="string">" points. <p>Did you 295 try using a key?</p>"</span>; 296 </li> 297 </li> 298 <li><span class="object">display</span>.<span class="function">found</span>(<span class="string">text</span>); 299 <li><span class="object">player</span>.<span class="property">score</span> -= penalty;</li> 300 <li><span class="object">display</span>.<span class="function">score</span>();</li> 301 <li><span class="function">updateColors</span>(<span class="string">"red"</span>); <span class="comment">//<a 302 href="addhtmlcolorschemes.html">optional add-on feature</a></span></li> 303 <li> </li> 304 <li><span class="keyword">var</span> button = <span class="string">"<button class='text' onclick='<span 305 class="function">moveToRoom</span>()'>OK</button>"</span>; 306 </li> 307 <li><span class="object">display</span>.<span class="function">navigation</span>(button);</li> 308 </ul> 309 </li> 310 <li>}</li> 311 <li><span class="keyword">else</span></li> 312 <li>{ 313 <ul> 314 <li><span class="comment">//these next two lines are already there</span></li> 315 <li><span class="object">player</span>.<span class="property">currentRoom</span> = <span class="object">roomToGoTo</span>; 316 </li> 317 <li><span class="function">moveToRoom</span>();</li> 318 </ul> 319 </li> 320 <li>} <span class="comment">//this brace is new</span></li> 321 </ul> 322 </div> 323 324 <p>Instead of just showing the information, we're interrupting the player with an OK button so they know what 325 happened.</p> 326 327 <p>I also added a small penalty for jiggling the lock just to show you how to do it. You can leave that part out. If 328 you do decide to leave out the penalty, I suggest using <code><span class="object">display</span>.<span 329 class="function">found</span>(<span class="string">""</span>);</code> to clear out that part of the UI until 330 they hit the OK button.</p> 331 332 <h2>Step 6: Looking around</h2> 333 <p>We already have a way for a player to pick up something in a room. Now we need them to be able to pick up a 334 key.</p> 335 336 <p>I want to make a change to how we handle finding things. I want the player to purposely look around the room to see 337 if something is there. Right now, if there is an item to pick, we automatically tell them there is something useful 338 there. We're going to change that.</p> 339 340 <p>We're going to make changes to <span class="function">showItemInRoom</span>, <span 341 class="function">isThereAnItem</span>, and we're going to create <span class="function">isThereAKey</span>.</p> 342 343 <h4>Updating showItemInRoom</h4> 344 <p>We're really changing this. We're removing the <span class="keyword">if</span> check, changing the text of the 345 button, and adding a second button. Here's the new version.</p> 346 347 <div class="code"> 348 <ul> 349 <li><span class="keyword">function</span> <span class="function">showItemInRoom</span>()</li> 350 <li>{ 351 <ul> 352 <li><span class="keyword">var</span> buttons = <span class="string">"<div id='foundItem' class='text' 353 style='float:left; width:45%;'>"</span>; 354 </li> 355 <li>buttons += <span class="string">"<button class='item' onclick='<span 356 class="function">isThereAnItem</span>()'>Look for an item.</button></div>"</span>; 357 </li> 358 <li> </li> 359 <li>buttons += <span class="string">"<div id='foundKey' class='text' style='float:right; 360 width:45%;'>"</span>; 361 </li> 362 <li>buttons += <span class="string">"<button class='item' onclick='<span 363 class="function">isThereAKey</span>()'>Look for a key.</button>"</span>; 364 </li> 365 <li><span class="object">display</span>.<span class="function">found</span>(buttons);</li> 366 </ul> 367 </li> 368 <li>}</li> 369 </ul> 370 </div> 371 372 <p>We're really doing something different here. We're adding two HTML <code><div></code> tags inside of the 373 <code><span class="object">display</span>.<span class="function">found</span></code> box. Again, this isn't normally 374 how'd we'd create all of these elements through JavaScript but it's convenient for us and it works as long as we're 375 careful with our syntax.</p> 376 377 <p>I gave them each an <code>id</code> so we can just update that part when they're clicked. Although we should 378 probably update our <span class="object">display</span> object to be official, we're just going to take the shortcut 379 here.</p> 380 381 <p>I'm using the <code>text</code> class so its basic format is the same as the res of the text boxes. I'm adding a 382 style element, which is usually done through CSS. The <code>float</code> attribute has the <code><div></code> 383 float inside of its container (the <code>found</code> box) either on the left or other side. This will spread the 384 apart a bit on a larger screen. Let's not worry too much about that now.</p> 385 386 <h2>Step 6: Updating isThereAnItem</h2> 387 <p>With the new floating buttons, let's only change out the <code>Look for an item</code> button with information 388 regarding the search for an item. We'll make use of the <code>foundItem</code> id for this. But as always, I like to 389 be cautious so we don't have errors.</p> 390 391 <p>Go into <span class="function">isThereAnItem</span>. We're going to start with an empty <code>text</code> string 392 now. Where we have both cases of <code><span class="object">display</span>.<span 393 class="function">found</span></code>, we're going to set the text string equal to what we were displaying 394 before. Then at the bottom, we will check to make sure the floating <div> exists. If so, we'll display the 395 text there and if not, we'll display it to the regular <code>found</code> box.</p> 396 397 <p>Here's the whole function with the new or updated parts noted with comments. It's only a few changes, really.</p> 398 399 <div class="code"> 400 <ul> 401 <li><span class="keyword">function</span> <span class="function">isThereAnItem</span>()</li> 402 <li>{ 403 <ul> 404 <li><strong><span class="keyword">var</span> text = <span class="string">""</span>; <span class="comment">// 405 ← this line is new</span></strong> 406 </li> 407 <li><span class="keyword">var</span> item = <span class="object">player</span>.<span class="property">currentRoom</span>.<span 408 class="property">itemFound</span>; 409 </li> 410 <li><span class="keyword">if</span> (item)</li> 411 <li>{ 412 <ul> 413 <li><strong>text += <span class="string">"You found the "</span> + item + <span class="string">"!"</span>; 414 <span 415 class="comment">// ← updated</span></strong></li> 416 <li><span class="object">player</span>.<span class="property">inventory</span>.<span 417 class="function">push</span>(item); 418 </li> 419 <li><span class="object">player</span>.<span class="property">currentRoom</span>.<span class="property">itemFound</span> 420 = <span class="keyword">null</span>; 421 </li> 422 </ul> 423 </li> 424 <li>}</li> 425 <li><span class="keyword">else</span> 426 <li>{ 427 <ul> 428 <li><strong>text += <span class="string">"There's nothing to take.<br>You lose 5 points."</span>; 429 <span 430 class="comment">// ← updated</span></strong></li> 431 <li><span class="object">player</span>.<span class="property">score</span> -= 5;</li> 432 <li><span class="function">updateColors</span>(<span class="string">"red"</span>); <span class="comment">//<a 433 href="addhtmlcolorschemes.html">optional add-on feature</a></span></li> 434 </ul> 435 </li> 436 <li>}</li> 437 <li> </li> 438 <li><strong><span class="comment">// ↓ these next few lines are new ↓ </span></strong></li> 439 <li><strong><span class="keyword">var</span> foundItem = <span class="object">document</span>.<span 440 class="function">getElementById</span>(<span 441 class="string">"foundItem"</span>);</strong> 442 </li> 443 <li><strong><span class="keyword">if</span> (foundItem)</strong></li> 444 <li><strong>{</strong> 445 <ul> 446 <li><strong><span class="object">foundItem</span>.<span class="property">innerHTML</span> = text;</strong> 447 </li> 448 </ul> 449 </li> 450 <li><strong>}</strong></li> 451 <li><strong><span class="keyword">else</span></strong></li> 452 <li><strong>{</strong> 453 <ul> 454 <li><strong><span class="object">display</span>.<span class="function">found</span>(text);</strong></li> 455 </ul> 456 </li> 457 <li><strong>}</strong></li> 458 <li> </li> 459 460 <li><span class="object">display</span>.<span class="function">score</span>();</li> 461 <li><span class="function">showInventory</span>();</li> 462 </ul> 463 </li> 464 <li>}</li> 465 </ul> 466 </div> 467 468 <h2>Step 7: Creating isThereAKey</h2> 469 <p>We need a function that handles checking for a key in the room. You can probably imagine that this will be very 470 similar to <span class="function">isThereAnItem</span> and you'd be right. The main difference is that we're using 471 an array for the <span class="object">room</span>'s <span class="property">keys</span> property, so it will take a 472 little extra work.</p> 473 474 <p>Copying and pasting code is not a recommended practice. It's very easy to forget to change the names of things, and 475 that can lead to a lot of bugs in your code that can be hard to track down. You know the function works in one place 476 so why not in the other?</p> 477 478 <p>Well, let's practice it anyway. Go ahead and highlight your updated <span class="function">isThereAnItem</span> 479 function, copy it, and then paste it into a new spot as if you were creating a new function from scratch. Watch 480 carefully for changes. As you try this, you may start to see why it's not recommended to do in most cases.</p> 481 482 <p>If you don't want to do it that way, that's fine. You can just build this function from scratch too!</p> 483 484 <p>The main changes are renaming <code>item</code> and <code>inventory</code>to <code>keys</code> and pulling a key 485 from the room's array of keys.</p> 486 487 <h4>Here's the <em>isThereAKey</em> function</h4> 488 489 <div class="code"> 490 <ul> 491 <li><span class="keyword">function</span> <span class="function">isThereAKey</span>()</li> 492 <li>{ 493 <ul> 494 <li><span class="keyword">var</span> text = <span class="string">""</span>;</li> 495 <li><span class="keyword">var</span> keys = <span class="object">player</span>.<span class="property">currentRoom</span>.<span 496 class="property">keys</span>; 497 </li> 498 <li> </li> 499 <li><span class="keyword">if</span> (keys && keys.<span class="property">length</span> > 0)</li> 500 <li>{ 501 <ul> 502 <li><span class="keyword">var</span> index = <span class="object">Math</span>.<span 503 class="function">floor</span>(<span class="object">Math</span>.<span class="function">random</span>() 504 * keys.<span class="property">length</span>); 505 </li> 506 <li><span class="keyword">var</span> key = keys[index];</li> 507 508 <li> </li> 509 510 <li>text += <span class="string">"You found the "</span> + key + <span class="string">"!"</span>;</li> 511 <li><span class="object">player</span>.<span class="property">keys</span>.<span 512 class="function">push</span>(key); 513 </li> 514 <li><span class="object">player</span>.<span class="property">currentRoom</span>.<span 515 class="property">keys</span>.<span class="function">splice</span>(index, 1); 516 </li> 517 </ul> 518 </li> 519 <li>}</li> 520 <li><span class="keyword">else</span> 521 <li>{ 522 <ul> 523 <li><span class="comment">//I don't want the player to lose points for looking for a key, so I'm changing 524 the text and commenting out the part that takes off points.</span></li> 525 526 <li>text += <span class="string">"There is no key here."</span>;</li> 527 <li> </li> 528 <li><span class="comment">/*</span> 529 <ul> 530 <li><span class="comment">text += "There's nothing to take. <p>You lose 5 points.";</span></li> 531 <li><span class="comment">player.score -= 5;</span></li> 532 <li><span class="comment">updateColors("red"); //optional add-on feature</span></li> 533 </ul> 534 </li> 535 <li><span class="comment">*/</span></li> 536 </ul> 537 </li> 538 <li>}</li> 539 <li> </li> 540 <li><span class="keyword">var</span> foundKey = <span class="object">document</span>.<span 541 class="function">getElementById</span>(<span 542 class="string">"foundKey"</span>); 543 </li> 544 <li><span class="keyword">if</span> (foundKey)</li> 545 <li>{ 546 <ul> 547 <li><span class="object">foundKey</span>.<span class="property">innerHTML</span> = text; 548 </li> 549 </ul> 550 </li> 551 <li>}</li> 552 <li><span class="keyword">else</span></li> 553 <li>{ 554 <ul> 555 <li><span class="object">display</span>.<span class="function">found</span>(text);</li> 556 </ul> 557 </li> 558 <li>}</li> 559 <li> </li> 560 <li><span class="object">display</span>.<span class="function">score</span>();</li> 561 <li><span class="function">showInventory</span>();</li> 562 </ul> 563 </li> 564 <li>}</li> 565 </ul> 566 </div> 567 <p>I don't want to penalize the player for searching for a key. You'll where I used block a block comment <code>/* ... 568 */</code> to comment out the code that was there which takes away the points. I could have just deleted it, but this 569 gives me the option of putting it back in later.</p> 570 571 <p>Another option, which I used in another feature (<a href="addhtmlpasscodehint.html">getting a passcode hint</a>), 572 would be to use a <code>penalty</code> variable. Setting it to zero would say there's no key, and having a value 573 would use the dialogue I commented out. That would be a more flexible way to handle all the places we take points 574 away from a player, but let's not worry about it for now.</p> 575 576 <h2>Step 8: Displaying the keys</h2> 577 <p>Now the player can pick up keys. It's time to let show them. Keys are related to inventory, right? Why don't we 578 display them there?</p> 579 580 <p>Inside our <span class="function">showInventory</span> function, we'll cycle through any keys the player has and 581 display those. Clicking them will call a new function that tries to use them. Since they will behave differently 582 than other items we use to fix things, we don't want to use our <span class="function">fixBrokenThing</span> 583 function for that.</p> 584 585 <h4>Updating <em>showInventory</em></h4> 586 <p>Right now the <span class="function">showInventory</span> function turns every inventory item into a clickable 587 button by looping through the player's <code>inventory</code> array. Let's add a second loop to do the same for the 588 player's new <code>keys</code> array. But if the player has no keys, let's not show anything for them, not even a 589 placeholder.</p> 590 591 <p>Go to the bottom of the function and insert this new loop <em>before</em> the text string gets displayed. This loop 592 is going to be very similar to the one that's already there for the inventory buttons, but wrapped inside an <span 593 class="keyword">if</span> statement, so if you want to try that copy/paste technique a second time, go ahead. 594 Even the best programmers out there make mistakes when using copy/paste, so it may be better to avoid it, but 595 everyone codes differently. Use what works for you.</p> 596 597 <div class="code"> 598 <ul> 599 <li> 600 <ul> 601 602 <li><span class="keyword">if</span> (<span class="object">player</span>.<span class="property">keys</span> && 603 <span class="object">player</span>.<span class="property">keys</span>.<span class="property">length</span> > 604 0) 605 </li> 606 <li>{ 607 <ul> 608 <li>text += <span class="string">"<br><strong>Keys: </strong>"</span>;</li> 609 <li><span class="keyword">for</span> (<span class="keyword">var</span> i = 0; i < <span class="object">player</span>.<span 610 class="property">keys</span>.<span class="property">length</span>; i++) 611 </li> 612 <li>{ 613 <ul> 614 <li>text += "<button class='keyButton' ";</li> 615 <li> </li> 616 <li><span class="keyword">if</span> (!disable)</li> 617 <li>{ 618 <ul> 619 <li><span class="comment">// ***watch the single and double quotes on these next two 620 lines***</span></li> 621 <li>text += <span class="string">"onclick='useKey(\""</span>;</li> 622 <li>text += <span class="object">player</span>.<span class="property">keys</span>[i] + <span 623 class="string">"\")'"</span>; 624 </li> 625 </ul> 626 </li> 627 <li>}</li> 628 <li>text += <span class="string">">"</span>;</li> 629 <li>text += <span class="string">"&#128273; "</span>; <span class="comment">// add a key symbol (🔑)</span> 630 </li> 631 <li>text += <span class="object">player</span>.<span class="property">keys</span>[i];</li> 632 <li>text += <span class="string">"</button>"</span>;</li> 633 </ul> 634 </li> 635 <li>}</li> 636 </ul> 637 </li> 638 <li>}</li> 639 </ul> 640 </li> 641 <li><span class="object">display</span>.<span class="function">inventory</span>(text);</li> 642 <li>}</li> 643 </ul> 644 </div> 645 646 <h2>Step 9: Unlocking a room</h2> 647 <p>We've come all this way. It's time to use the key to unlock a room. In our update to the inventory box, we have the 648 key buttons call a new function we have to create, <span class="function">useKey</span>. Can you guess what function 649 it's going to look the most like?</p> 650 651 <p>When we try to use the key, we need to see if there is a locked room attached to our current room. If there is, 652 then we need to see if the key we have will work to open the lock. If so, then open it and remove the lock from that 653 room so we don't have to unlock it again.</p> 654 655 <p>It sounds a lot like our <span class="function">fixBrokenThing</span> function, doesn't it?</p> 656 657 <h4>Building the <em>useKey</em> function</h4> 658 <p>When the key button is pressed, the name of the key is sent in so we can use it to try to unlock the door.</p> 659 660 <p>One thing that's different from fixing broken things is that we're using arrays for locked doors and keys. In 661 addition to that, you could be in a room that has more than one locked door around you. So even though the basic 662 idea is the same as <span class="function">fixBrokenThing</span>, we're going to handle it a little differently.</p> 663 <p>I'm going to break this down into a few parts so we can talk about it.</p> 664 665 <h4>Starting the <em>useKey</em> function</h4> 666 <p>Here we declare the function as well as a few variables we're going to use to track what's happening with the locks 667 and keys.</p> 668 669 <div class="code"> 670 <ul> 671 <li><span class="keyword">function</span> <span class="function">useKey</span>(keyName)</li> 672 <li>{ 673 <ul> 674 <li><span class="keyword">var</span> text = <span class="string">""</span>;</li> 675 <li><span class="keyword">var</span> locks = [];</li> 676 <li><span class="keyword">var</span> unlocked = [];</li> 677 <li><span class="keyword">var</span> notUnlocked = [];</li> 678 </ul> 679 </li> 680 </ul> 681 </div> 682 683 <p>The <code>text</code> variable you're used to by now. It makes it easier to display information to the player. The 684 others are less obvious.</p> 685 <ul> 686 <li><code>locks</code> keeps track of every exit from the current room that is locked.</li> 687 <li><code>unlocked</code> keeps track of locked rooms if the key sent in unlocks them.</li> 688 <li><code>notUnlocked</code> keeps track of locked rooms if the key sent in does not unlock them.</li> 689 </ul> 690 691 <p>Let's fill those arrays.</p> 692 693 <h4>Finding locked doors, and trying to unlock them.</h4> 694 <p>We're going to look at the exits of the room the player is currently in to see if any of them are locked. If so, 695 they go on the <code>locked</code> list so we can count them. If this list is empty later, then it means the player 696 tried to unlock a door but none of them were locked.</p> 697 698 <p>For any door that <em>is</em> locked, we see if the key being used (<code>keyName</code>) is one of the keys that 699 can unlock that door. If it is, then we add that exit to the <code>unlocked</code> list and remove the lock from 700 that room by setting the <span class="property">locked</span> property to <span class="keyword">null</span>.</p> 701 702 <p>Finally, if door was locked but key sent in does not unlock it, we add that exit to the <code>notUnlocked</code> 703 list.</p> 704 705 <p>To do all this, we need to loop through all of the current room's exits.</p> 706 707 <div class="code"> 708 <ul> 709 <li> 710 <ul> 711 <li><span class="comment">//get the set of rooms with locks, the number of doors unlocked, and the doors not 712 unlocked</span></li> 713 <li><span class="keyword">for</span> (<span class="keyword">var</span> exit <span class="keyword">in</span> 714 <span class="object">player</span>.<span class="property">currentRoom</span>.<span 715 class="property">exits</span>) 716 </li> 717 <li>{ 718 <ul> 719 <li><span class="keyword">var</span> exitName = <span class="object">player</span>.<span 720 class="property">currentRoom</span>.<span class="property">exits</span>[exit]; 721 </li> 722 <li><span class="keyword">var</span> <span class="object">room</span> = <span class="object">rooms</span>[exitName]; 723 </li> 724 <li><span class="keyword">if</span> (<span class="object">room</span>.<span class="property">locked</span> 725 && <span class="object">room</span>.<span class="property">locked</span>.<span 726 class="keyword">length</span> > 0) 727 </li> 728 <li>{ 729 <ul> 730 <li>locks.<span class="function">push</span>(exit);</li> 731 <li><span class="keyword">var</span> index = <span class="object">room</span>.<span class="property">locked</span>.<span 732 class="function">indexOf</span>(keyName); 733 </li> 734 <li><span class="keyword">if</span> (index === -1) <span class="comment">//the key will not 735 work</span></li> 736 <li>{ 737 <ul> 738 <li>notUnlocked.<span class="function">push</span>(exit);</li> 739 </ul> 740 </li> 741 <li>}</li> 742 <li><span class="keyword">else</span> <span class="comment">//otherwise the key <em>will</em> 743 work</span></li> 744 <li>{ 745 <ul> 746 <li>unlocked.<span class="function">push</span>(exit);</li> 747 <li><span class="object">room</span>.<span class="property">locked</span> = <span class="keyword">null</span>; 748 </li> 749 </ul> 750 </li> 751 <li>}</li> 752 </ul> 753 </li> 754 <li>}</li> 755 </ul> 756 </li> 757 <li>}</li> 758 </ul> 759 </li> 760 </ul> 761 </div> 762 763 <h4>If nothing was locked...</h4> 764 <p>If the <code>locks</code> array is empty, then none of the exits were locked. The player tried to use a key on 765 unlocked doors. I'm going to give a penalty for this, like I give one for using the wrong item to try to fix 766 something. As always, you don't have to have a penalty.</p> 767 768 <div class="code"> 769 <ul> 770 <li> 771 <ul> 772 <li><span class="keyword">if</span> (locks.<span class="property">length</span> === 0)</li> 773 <li>{ 774 <ul> 775 <li>text += <span class="string">"<h3>No doors were locked here.</h3^gt;"</span>;</li> 776 <li>text += <span class="string">"You lose 5 points."</span>;</li> 777 <li><span class="object">player</span>.<span class="property">score</span> -= 5;</li> 778 <li><span class="function">updateColors</span>(<span class="string">"red"</span>); <span class="comment">//<a 779 href="addhtmlcolorschemes.html">optional add-on feature</a></span></li> 780 </ul> 781 </li> 782 <li>}</li> 783 </ul> 784 </li> 785 </ul> 786 </div> 787 788 <p>Even though we're going to test other conditions after this, we're not going to use <span 789 class="keyword">else</span> or <span class="keyword">else if</span>. We <em>could</em> wrap the next two checks in 790 an <span class="keyword">else</span> block, but the other two arrays don't every get touched if the 791 <code>locks</code> array is empty. In this case, our code doesn't require it. Again, I'm just showing you options. 792 If you want to wrap the next part in an <span class="keyword">else</span> block, go right ahead.</p> 793 794 <h4>If something <em>was</em> locked...</h4> 795 <p>If there was at least one locked exit, then we will have information in <code>unlocked</code>, 796 <code>notUnlocked</code>, or both. We want to report all that to the player. Here is another design decision. How 797 detailed do you want the text to be? We can do a very simple list along the lines of <code>Exits unlocked: east, 798 west</code> or we could be very detailed in our sentence structure and grammar: <code>The silver key opened the 799 east, west, and south exits.</code></p> 800 801 <p>I'm going to show you both ways. We will start with the first, simpler case. It's very short because it doesn't 802 worry about singles and plurals and all that. The second version is pretty hefty and you may not want to deal with 803 it at this moment in time. But if you're up for it, it'll be here for you.</p> 804 805 <p>In either case, we'll be using the array <span class="function">join</span> method, which takes the elements of the 806 array and combines them into a string, separated by whatever we put in the parentheses.</p> 807 808 <h4>Player report: Simple grammar version</h4> 809 810 <div class="code"> 811 <ul> 812 <li> 813 <ul> 814 <li><span class="comment">//this sets up the report for any doors that were unlocked</span></li> 815 <li><span class="keyword">if</span> (unlocked.<span class="property">length</span> > 0)</li> 816 <li>{ 817 <ul> 818 <li>text += <span class="string">"<strong>Exit(s) unlocked with the "</span> + keyName + <span 819 class="string">": </strong>"</span>; 820 </li> 821 <li>text += unlocked.<span class="function">join</span>(<span class="string">", "</span>);</li> 822 </ul> 823 </li> 824 <li>}</li> 825 <li> </li> 826 <li><span class="comment">//this sets up the report for any doors that could not be unlocked by the key that 827 was used</span></li> 828 <li><span class="keyword">if</span> (notUnlocked.<span class="property">length</span> > 0)</li> 829 <li>{ 830 <ul> 831 <li>text += <span class="string">"<strong>Exit(s) not unlocked with the "</span> + keyName + <span 832 class="string">": </strong>"</span>; 833 </li> 834 <li>text += notUnlocked.<span class="function">join</span>(<span class="function">", "</span>);</li> 835 </ul> 836 </li> 837 <li>}</li> 838 </ul> 839 </li> 840 </ul> 841 </div> 842 843 <p>All that's left is to display that information. If you're happy with this version of reporting the information, 844 then <a href="#skip">skip down to the next part</a> to finish off this function.</p> 845 846 <h4>Player report: Complex grammar version</h4> 847 <p>This version adds a bit of complexity to the dialogue that gets shown to the player. It's because we have different 848 rules for lists. Let's use colored hats as an example.</p> 849 <ul> 850 <li>I have a red hat.</li> 851 <li>I have red and blue hats.</li> 852 <li>I have a red, a blue, and green hats.</li> 853 </ul> 854 <p>We have the difference between "hat" and "hats" for one thing. Also, comma usage differs depending on the number of 855 items in the list and that changes things for our text string. I also use the Oxford comma. That's comma after the 856 banana in the third example. Not everyone puts a comma before the last item ini a list, but I think it's clearer 857 when you do. So, I'm even going to control for that.</p> 858 <p>Ready for this?</p> 859 860 <div class="code"> 861 <ul> 862 <li> 863 <ul> 864 <li><span class="comment">//this sets up the report for any doors that were unlocked</span></li> 865 <li><span class="keyword">if</span> (unlocked.<span class="property">length</span> === 1)</li> 866 <li>{ 867 <ul> 868 <li>text += <span class="string">"<h3>The "</span> + keyName + <span class="string">" unlocked the 869 "</span> + unlocked[0] + <span class="string">" exit.</h3>"</span>; 870 </li> 871 </ul> 872 </li> 873 <li>} 874 <ul> 875 <li><span class="keyword">else if</span> (unlocked.<span class="property">length</span> > 1)</li> 876 <li>{ 877 <ul> 878 <li>text += <span class="string">"<h3>The "</span> + keyName + <span class="string">" unlocked 879 the "</span>; 880 </li> 881 <li> </li> 882 <li><span class="keyword">var</span> exitSlice = unlocked.<span class="function">slice</span>(0, 883 unlocked.<span class="property">length</span> - 1); 884 </li> 885 <li>text += exitSlice.<span class="function">join</span>(<span class="string">", "</span>);</li> 886 <li><span class="keyword">if</span> (unlocked.<span class="property">length</span> > 2) <span 887 class="comment">//add the Oxford comma</span></li> 888 <li>{ 889 <ul> 890 <li>text += <span class="string">","</span>;</li> 891 </ul> 892 </li> 893 <li>}</li> 894 <li>text += <span class="string">" and "</span>;</li> 895 <li>text += unlocked[unlocked.<span class="property">length</span> - 1];</li> 896 <li>text += <span class="string">" exits.</h3>"</span>;</li> 897 </ul> 898 </li> 899 <li>}</li> 900 </ul> 901 </li> 902 </ul> 903 </li> 904 </ul> 905 </div> 906 907 <p>Whoa, right? That's just to show what the <code>unlocked</code> array holds. We need to repeat all of this again 908 for the <code>notUnlocked</code> array. Well, we've done the copy/paste twice here, so let's do one more. Copy that 909 whole code block and paste it back in right below it. Then change all of the <code>unlocked</code> to <code>notUnlocked</code>. 910 And in the two text strings where it says <span class="string">" unlocked the "</span>, change it to say, <span 911 class="string">" could not unlock the "</span>.</p> 912 913 <p>I'll put the code here, but see if you can do it on your own based on the instructions I just gave you.</p> 914 915 <div class="code"> 916 <ul> 917 <li> 918 <ul> 919 <li><span class="comment">//this sets up the report for any doors that could not be unlocked by the key that 920 was used</span></li> 921 <li><span class="keyword">if</span> (notUnlocked.<span class="property">length</span> === 1)</li> 922 <li>{ 923 <ul> 924 <li>text += <span class="string">"<h3>The "</span> + keyName + <span class="string">" could not 925 unlock the "</span> + notUnlocked[0] + <span class="string">" exit.</h3>"</span>; 926 </li> 927 </ul> 928 </li> 929 <li>} 930 <ul> 931 <li><span class="keyword">else if</span> (notUnlocked.<span class="property">length</span> > 1)</li> 932 <li>{ 933 <ul> 934 <li>text += <span class="string">"<h3>The "</span> + keyName + <span class="string">" could not 935 unlock the "</span>; 936 </li> 937 <li> </li> 938 <li><span class="keyword">var</span> exitSlice = notUnlocked.<span class="function">slice</span>(0, 939 notUnlocked.<span class="property">length</span> - 1); 940 </li> 941 <li>text += exitSlice.<span class="function">join</span>(<span class="string">", "</span>);</li> 942 <li><span class="keyword">if</span> (notUnlocked.<span class="property">length</span> > 2) <span 943 class="comment">//add the Oxford comma</span></li> 944 <li>{ 945 <ul> 946 <li>text += <span class="string">","</span>;</li> 947 </ul> 948 </li> 949 <li>}</li> 950 <li>text += <span class="string">" and "</span>;</li> 951 <li>text += notUnlocked[notUnlocked.<span class="property">length</span> - 1];</li> 952 <li>text += <span class="string">" exits.</h3>"</span>;</li> 953 </ul> 954 </li> 955 <li>}</li> 956 </ul> 957 </li> 958 </ul> 959 </li> 960 </ul> 961 </div> 962 963 <p>Got all that? You deserve a break. But let's polish off this function first. You're almost there.</p> 964 965 <h4 id="skip">Finishing the function</h4> 966 <p>Whether you created the simple or the complete reports, these lines go next, and they should look pretty 967 familiar.</p> 968 969 <div class="code"> 970 <ul> 971 <li> 972 <ul> 973 <li><span class="object">display</span>.<span class="function">broken</span>(text);</li> 974 <li><span class="object">display</span>.<span class="function">found</span>(<span class="string">""</span>); 975 </li> 976 <li><span class="keyword">var</span> button = <span class="string">"<button class='text' onclick='<span 977 class="function">moveToRoom</span>()'>OK</button>"</span>; 978 </li> 979 <li><span class="object">display</span>.<span class="function">navigation</span>(button);</li> 980 </ul> 981 </li> 982 <li>}</li> 983 </ul> 984 </div> 985 986 <p>That was a long journey, but it's finally finished. There are two more optional things you could consider doing, 987 which I'll mention below.</p> 988 989 <p>Once you've got it running and tested, put different keys around and see how it all goes. I'm going to put a silver 990 key in my dining room and that key will unlock the upstairs. But the dining room itself will be locked and you'll 991 need the brass key to open it up! That key is going to be hiding in the office.</p> 992 993 <h4><strong>It is recommended you also create the <a href="addkeycheck.html">checkKeys()</a> function to 994 check your lock and key placement.</strong></h4> 995 996 997 <h2>Optional: Step 11: Styling the key buttons</h2> 998 <p>We added a <code>keyButton</code> class to the key buttons, did you notice? That means we can style them! If we 999 don't they will have the default <code><button></code> style, which is totally fine.</p> 1000 1001 <h4>Some styling for the keys</h4> 1002 <p>Remember, this has to go in your CSS file!</p> 1003 1004 <div class="code"> 1005 <ul> 1006 <li><span class="object">.keyButton</span> { 1007 <ul> 1008 <li><span class="property">background-color</span>: darkgreen;</li> 1009 <li><span class="property">padding</span>: 10px;</li> 1010 <li><span class="property">font-size</span>: 0.8em;</li> 1011 </ul> 1012 </li> 1013 <li>}</li> 1014 </ul> 1015 </div> 1016 1017 <h2>Optional: Step 12: Passcode pieces as keys</h2> 1018 <p>In my opinion, passcode pieces are part of a larger key and now that we have a place to hold keys, I want to move 1019 the pieces there. Alternately, we could make a <code>passcodePiece</code> array and display them separately but 1020 let's outside of the keys we're talking about here.</p> 1021 1022 <p>We can move the passcode pieces from the <span class="property">inventory</span> array into the <span 1023 class="property">keys</span> array with a single word change! Go into the <span 1024 class="function">fixBrokenThing</span> function where the player finds a passcode piece and we add it to the 1025 inventory. Look for this line.</p> 1026 1027 <div class="code"> 1028 <ul> 1029 <li> 1030 <span class="object">player</span>.<span class="property"><strong>inventory</strong></span>.<span 1031 class="function">push</span>(<span class="object">player</span>.<span 1032 class="property">currentRoom</span>.<span class="property">passcodeHint</span>); 1033 </li> 1034 </ul> 1035 </div> 1036 1037 <p>See the work <code>inventory</code>? Change it to <code>keys</code>.</p> 1038 1039 <div class="code"> 1040 <ul> 1041 <li> 1042 <span class="object">player</span>.<span class="property"><strong>keys</strong></span>.<span class="function">push</span>(<span 1043 class="object">player</span>.<span class="property">currentRoom</span>.<span 1044 class="property">passcodeHint</span>); 1045 </li> 1046 </ul> 1047 </div> 1048 <h3>Update complete.</h3> 1049 1050 <h4>Added caution — mostly for my code</h4> 1051 <div class="sidenote"><img class="sidenoteimage" src="/images/DrLupinoTakeNote.png"> <strong>Sidenote:</strong> You 1052 may wonder why I'm bothering. The only way someone would change it to <code>keys</code> is if they made this update 1053 anyway, right? True. But if they're looking at my code and copy a function from it to use in their code because 1054 their function isn't working, and if they didn't get to this page, then I don't want to break their game. It's one 1055 of the reasons why I have so many extra conditionals throughout the code where it looks like we may not need them. 1056 Now you know. 1057 </div> 1058 1059 <p>I need to keep my code extra (overly?) flexible because different people may be at different parts of the game, so 1060 I'm actually going to make the following change instead, but you don't have to. I'm replacing that inventory line 1061 above with this.</p> 1062 1063 <div class="code"> 1064 <ul> 1065 <li><span class="keyword">if</span> (<span class="object">player</span>.<span class="property">keys</span>)</li> 1066 <li>{ 1067 <ul> 1068 <li> 1069 <span class="object">player</span>.<span class="property"><strong>keys</strong></span>.<span 1070 class="function">push</span>(<span 1071 class="object">player</span>.<span class="property">currentRoom</span>.<span 1072 class="property">passcodeHint</span>); 1073 </li> 1074 </ul> 1075 </li> 1076 <li>} 1077 <li><span class="keyword">else</span></li> 1078 <li>{ 1079 <ul> 1080 <li> 1081 <span class="object">player</span>.<span class="property">inventory</span>.<span 1082 class="function">push</span>(<span class="object">player</span>.<span 1083 class="property">currentRoom</span>.<span class="property">passcodeHint</span>); 1084 </li> 1085 </ul> 1086 </li> 1087 <li>}</li> 1088 </ul> 1089 </div> 1090 1091 1092 <h2>You've unlocked more of your potential today!</h2> 1093 <h2>—Dr. Wolf</h2> 1094 1095 <div id="prevnext"></div> 1096 <!-- required section for navigation sidebar --> 1097 </div> 1098 <script src="/navigator.js"></script> 1099 <script>begin("roomadventure");</script> 1100 <!-- end of required section for navigation sidebar --> 1101 </body> 1102 </html> 1103