Decoded: Rogue (1980) by Toy, Arnold, Wichman DOS version (1983) by Mel Sibony and Jon Lane Source file: THINGS.C Beginner friendly, line-by-line code walkthrough by MaiZure THINGS.C provides general item management definitions and procedures Original code: https://britzl.github.io/roguearchive/ Original code with line numbers http://www.maizure.org/projects/decoded-rogue/THINGS_linenum.txt 1 COMMENT 2 COMMENT 3 COMMENT 4 COMMENT 5 COMMENT 6 COMMENT 7 BLANK 8 Include the game header 9 Include the console management header 10 BLANK 11 COMMENT 12 COMMENT 13 COMMENT 14 COMMENT 15 COMMENT THING INVENTORY NAME 16 inv_name returns a string 17 Defines inv_name with two arguments 18 Argument 1 is a pointer to an object 19 Argument 2 is a flag if the item is dropped in position 20 BLOCK START - inv_name, returns the inventory display name of an item 21 Declare index for name guesses 22 Declare a pointer to a string buffer (pointer to the print buffer) 23 BLANK 24 Point buffer to the global print buffer 25 SWITCH on item type 26 BLOCK START - SWITCH on item type 27 CASE scrolls 28 If there is only 1 scroll 29 Copy singular scroll to the print buffer 30 update buffer position 31 Otherwise, there are many scrolls 32 Copy plural string with count 33 Update buffer position 34 End check for item count 35 If the player knows about the scroll... 36 Print the real name of the scroll 37 But if the player has a guess about the scroll... 38 Print the guessed name 39 Otherwise... 40 Print the (possibly truncated) random name of the scroll 41 CASE potions 42 If there is only one potion... 43 BLOCK START - singular potion name 44 Copy singular name to the buffer 45 Update buffer position 46 BLOCK END - singular potion name 47 Otheriwse it's plural 48 BLOCK START - plural potion name 49 Copy the name with a count 50 Update buffer position 51 BLOCK END - plural potion name 52 If the player knows the real name of the potion 53 Copy the real name of the potion... 54 ...from the proper array 55 End check for known potion name 56 But if the player has guessed a name for the potion 57 Copy the guess to the print buffer 58 including the color information 59 End check for guessed potion name 60 Otherwise, if there is only one potion... 61 Copy the random name of a single potion to the buffer 62 including the color 63 Finally, there must be multiple randomly named potions 64 Copy the random name to the buffer 65 Including the color 66 CASE food 67 If it is a basic food type... 68 And there is only one 69 Copy the singular name of the food to the buffer 70 Otherwise, there are several.. 71 Copy the plural name of the food to the buffer 72 Otherwise these are rations 73 If there is one ration... 74 Copy basic ration name to the buffer 75 Otherwise there are multiple rations 76 Copy the name to the buffer 77 CASE weapons 78 If there is more than one weapon 79 Copy the count number to the buffer 80 Otherwise there is just one weapon.. 81 Copy the weapon's name to the buffer 82 Update buffer position 83 If the player knows about the weapon 84 Copy the weapon's bonuses... 85 ..and the real name to the buffer 86 Otherwise... 87 Just copy the regular name to the buffer 88 If there is more than one... 89 Add an 's' 90 If the weapon is vorpal... 91 BLOCK START - vorpal named weapon 92 Add 'of' 93 Add the name of the target monster 94 Add 'slaying' to the buffer 95 BLOCK END - vorpal named weapon 96 CASE armor 97 If the player knows about the armor 98 Output a possibly truncated name... 99 Including the armor bonuses 100 And the real name 101 Otherwise the player doesn't know so... 102 Copy the regular type name to the buffer 103 CASE amulet 104 There is only one amulet - copy its name to the print buffer 105 CASE wands/staves 106 Copy the name type (wand or staff) 107 from the proper buffer... 108 Update buffer position 109 If the player knows about the item... 110 Copy the (possibly truncatd) name 111 from the real name array 112 Including the magical charge count and material 113 But if the player has a guess about the type... 114 Copy the guessed name to the buffer 115 Including the material 116 Otherwise, player knows nothing 117 Update the buffer position and copy the random name... 118 including the material 119 CASE rings 120 If the player knows about the thing 121 Copy the ring's real name 122 Including its material 123 But if the player has a guess 124 Copy the guessed name to the output buffer 125 from the guess array but use the real material (precious stone) 126 Otherwise the player knows nothing of the ring 127 Copy the basic name... 128 But include the stones 129 Check for debug mode 130 CASE gold 131 Print the gold's location 132 CASE all other items 133 Print debug message about an unknown item 134 Also output the message to the buffer 135 End check for debug mode 136 BLOCK END - SWITCH on object type 137 If the object is the current armor 138 Add the worn tag 139 If the object is the current weapon 140 Add the wielded tag 141 If the object is the current left ring 142 Add the worn tag 143 If the object is the current right ring 144 Add the worn tag 145 If the object is dropped and is upper case 146 Convert the first letter to lower case 147 Otherwise if it's not dropped and is lower case 148 Convert the first letter to upper case 149 Return the buffer to caller 150 BLOCK END - inv_name 151 BLANK SHORTEN MESSAGE 152 Defines chopmsg with six arguments 153 Argument 1 is the string buffer, 2 is the short version, 3 is the longer 154 Arguments 4-6 are the formatting attributes (input variables to resolve) 155 BLOCK START - chopmsg, shortens an input message based on terse mode 156 In all cases, copy the long name to the buffer 157 But if we're in terse mode... 158 Replace it with the short version 159 BLOCK END - chopmsg 160 BLANK 161 COMMENT 162 COMMENT 163 COMMENT 164 COMMENT DROP ITEM 165 Define drop with no arguments 166 BLOCK START - drop, player drops an item 167 Declare a pointer to a character 168 Declare two pointers to object 169 BLANK 170 Get the floor character at the player's position 171 If the floor isn't a clear walkway... 172 BLOCK START - blocked drop 173 Print a message that the drop is blocked 174 Return failure to drop 175 BLOCK END - blocked drop 176 If the player has no items to drop... 177 Return failure 178 If the chosen item cannot be dropped 179 Return failure 180 COMMENT 181 COMMENT 182 COMMENT 183 If there is more than one of the item and it's not a weapon 184 BLOCK START - drop one weapon from a stack 185 If the new object cannot be created.. 186 BLOCK START - failed weapon drop 187 Print message that the drop failed 188 Return failure 189 BLOCK END - failed weapon drop 190 Reduce the weapon stack count 191 Copy the weapon's data to the newly allocated object 192 Set the object's count to 1 193 Repoint to the new object 194 If the object isn't in the pack 195 Add it to the pack 196 BLOCK END - drop one weapon from a stack 197 Otherwise, there is only one object, no need to split 198 Remove it from the pack 199 Reduce the inventory count 200 COMMENT 201 COMMENT 202 COMMENT 203 Add the object to th level 204 Set the floor tile under the player to the dropped object 205 Copy the player's location to the object 206 If the object is the amulet 207 Update the global saying the player no longer has it 208 Print drop message 209 BLOCK END - drop 210 BLANK 211 COMMENT 212 COMMENT 213 COMMENT 214 COMMENT ITEM DROPABILITY CHECK 215 Define can_drop with one argument 216 Argument 1 is a pointer to an object 217 BLOCK START - can_drop, return true if an item can be dropped 218 If there is no input object 219 Return true...can drop nothing 220 If the object isn't currently worn as armor, or weapon... 221 ...or either ring... 222 Return true. Can drop inventory items 223 If the object is worn but is cursed 224 Print failure message 225 Item is cursed 226 End check for cursed item 227 If the object is the current weapon 228 Take off the weapon 229 If the object is the current armor... 230 Pass time 231 Take off the armor 232 For all other objects... 233 Declare an integer for the hand number 234 BLANK 235 If the object isn't the left ring 236 and it's not the right ring... 237 Check for debug mode 238 Print debug message about unknown object type 239 End check for debug mode 240 Return true (not worn) 241 End check for non-worn rings 242 Remove the ring 243 BLOCK START - Switch on magic ring type 244 CASE strength ring 245 Take away strength bonus 246 End check for ring effects 247 CASE see inivisible ring 248 Undo see inivisible 249 Remove see invisible daemon 250 End check for ring effects 251 BLOCK END - Switch on magic ring type 252 End check for all other objects 253 Return true - unable to find a reason to disallow drop 254 BLOCK END - can_drop 255 BLANK 256 COMMENT 257 COMMENT 258 COMMENT 259 COMMENT CREATE NEW OBJECT 260 new_thing returns a pointer to an object 261 Define new_thing with no arguments 262 BLOCK START - new_thing, allocates and initializes a new item 263 Declare a pointer to an object 264 Declare two iterators 265 BLANK 266 Try to create a new item and if it fails... 267 Return failure 268 Clear all hit and damage bonuses 269 Clear all attack damages 270 Set AC to lowest 271 Only 1 new object 272 Not in a group 273 No flags 274 No target enemy 275 COMMENT 276 COMMENT 277 COMMENT 278 COMMENT 279 Switch on a randomly chosen new item type, favoring food 280 BLOCK START - Switch on new item type 281 CASE potion 282 Set new item type to potion 283 Pick a random potion type 284 CASE scroll 285 Set new item type to scroll 286 Pick a random scroll type 287 CASE food 288 Set no food counter to 0 289 Set new item type to food 290 Roll for a 90% chance for... 291 The food type to be a regular food consumable 292 Otherwise a 10% chance that... 293 It's a yummy food ration 294 CASE weapon 295 Set new item type to weapon 296 Choose a random weapon type 297 Initialize the weapon's stats 298 Roll for a 10% chance that... 299 BLOCK START - Cursed weapon 300 The weapon is cursed! 301 The weapon has a hit chance penalty 302 BLOCK END - Cursed weapon 303 Otherwise, check for a 5% chance that... 304 The weapon has a hit bonus 305 CASE armor 306 Set new item type to armor 307 Roll for the weapon type against the cumulative probability table 308 If the chance is under he armor table chance.. 309 We've found the desired armor 310 Check for debug mode 311 If the armor selection loop never terminated... 312 BLOCK START - armor choice debug 313 Print a debug message 314 Reset armor choice to lowest 315 BLOCK END - armor choice debug 316 End check for debug mode 317 Set the armor subtype 318 Get the type's base armor class 319 Roll for a 20% chance that... 320 BLOCK START - Cursed armor 321 Armor is cursed 322 Armor has an AC penalty 323 BLOCK END - Cursed armor 324 Otherwise, roll an 8% chance that... 325 The armor has an AC bonus 326 CASE ring 327 Set new item type to ring 328 Pick a magic ring type 329 SWITCH on magic ring type 330 BLOCK START - Switch on ring type 331 CASE strength ring (fallthrough) 332 CASE protection ring (fallthrough) 333 CASE hit bonus (fallthrough) 334 CASE damage bonus 335 Roll for an effect bonus, but if it's zero... 336 BLOCK START - Cursed ring 337 Ring has a negative effect 338 Ring is cursed 339 BLOCK END - Cursed ring 340 CASE aggro ring (fallthrough) 341 CASE teleport ring 342 Ring is cursed 343 BLOCK END - Switch on ring type 344 CASE wand/staff 345 Set new item type to wand or staff 346 Randomly pick between wand or staff type 347 Initialize the wand/staff 348 Check for debug mode 349 CASE unknown 350 Print a debug message 351 Wait for a space input 352 End check for debug mode 353 BLOCK END - Switch on new item type 354 Return the new object 355 BLOCK END - new_thing 356 BLANK 357 COMMENT 358 COMMENT 359 COMMENT 360 COMMENT CHOOSE RANDOM MAGIC ITEM 361 Define pick_one with two arguments 362 Argument 1 is the magic item list 363 Argument 2 is total number of possible items 364 BLOCK START - pick_one, chooses a magic item in a list, returns index 365 Declare a pointer to the end of the list 366 Declare an integer to be used as a random value 367 Declare a pointer to the beginning of the list 368 BLANK 369 Set the start of the list 370 Loop through the list to a randomly chosen probability threshold 371 If the random number is below the item's probabilitiy 372 Break on this index 373 If this is the end of the list... 374 BLOCK START - End of magic selection list 375 Check for debug mode 376 If wizard mode is active 377 BLOCK START - Wizard mode debug 378 Send message about failed pick probability 379 Loop through all items 380 Display message for each item 381 BLOCK END - Wizard mode debug 382 End check for debug mode 383 Reset to start of list 384 BLOCK END - End of magic selection list 385 Return the magic item list offset 386 BLOCK END - pick_one 387 BLANK 388 COMMENT 389 COMMENT 390 COMMENT 391 COMMENT 392 Initialize a counter for discoveries 393 BLANK 394 Initialize flag for new page of discoveries to false 395 BLANK 396 Declare pointers to the last formats and arguments in a list 397 BLANK PLAYER'S KNOWN ITEMS 398 Declare discovered with no arguments 399 BLOCK START - discovered, shows a list of things the player knows 400 Print the known potions list 401 Add a blank line 402 Print the known scrolls list 403 Add a blank line 404 Print the known rings list 405 Add a blank line 406 Print the known wands/staff list 407 Ad a blank line 408 BLOCK END - discovered 409 BLANK 410 COMMENT 411 COMMENT 412 COMMENT 413 COMMENT 414 BLANK 415 Declare a macro for a 4-way ternary maximum function 416 BLANK PRINT DISCOVERED ITEMS 417 Define print_disc with one argument 418 Argument 1 is the type of discovery list to print 419 BLOCK START - print_disc, shows discovers of a specific type 420 Declare a flag for known items 421 Declare a pointer to a name guess array 422 Declare counters and an index 423 Declare a static object 424 Declare an array to sort entries 425 BLANK 426 Switch on item type 427 BLOCK START - Switch on item type 428 CASE scroll discoveries 429 Get the maximum number of scrolls 430 Point to the known item array 431 Point to the guess array 432 Break after pointer setup for this type 433 CASE potion discoveries 434 Get the maximum number of potions 435 Point to the known item array 436 Point to the guess array 437 Break after pointer setup for this type 438 CASE ring discoveries 439 Get the maximum number of rings 440 Point to the known item array 441 Point to the guess array 442 Break after pointer setup for this type 443 CASE wand/staff discoveries 444 Get the maximum number of wands/staves 445 Point to the known item array 446 Break after pointer setup for this type 447 Break after pointer setup for this type 448 BLOCK END - Switch on item type 449 Order the array 450 Set the object count to 1 451 Clear flags 452 None found 453 Loop through all the items to fill in data 454 If the player knows about the item or has a guess 455 BLOCK START - Get discovery data 456 Set the object type 457 Get the order position 458 Add the item to the list 459 Increment the discovery counter 460 BLOCK END - Get discovery data 461 If no discoveries were found 462 Add a null line to the output list 463 BLOCK END - print_disc 464 BLANK 465 COMMENT 466 COMMENT 467 COMMENT 468 COMMENT SORT LIST 469 Define set_order with two arguments 470 Argument 1 is an array pointer 471 Argument 2 is an index 472 BLOCK START - set_order, randomize an input list 473 Declare iterators and indices 474 BLANK 475 Loop through the array 476 Initialize each array element to its index 477 BLANK 478 Loop backwards through the number of elements 479 BLOCK START - randomize array 480 Choose a random element 481 Save it in to a temporary space 482 Swap it with the next element 483 Replace target with the temporary (Swap) 484 BLOCK END - randomize array 485 BLOCK END - set_order 486 BLANK 487 COMMENT 488 COMMENT 489 COMMENT 490 COMMENT 491 COMMENT ADD TO DISCOVERED LIST 492 Define add_line with three arguments 493 Arguments are the use pointer, format string, and attributes 494 BLOCK START - add_line, adds to discovery list 495 Declare cursor position variables 496 Initialize return character to blank/space 497 If there are no lines in use... 498 BLOCK START - clear lines 499 Flush the save buffer 500 Clear the screen 501 BLOCK END - clear lines 502 If the number of lines is larger than the screen 503 BLOCK START - long pages 504 Move to the bottom line 505 If the player needs to use an item 506 Allow the player to select an item 507 Otherwise 508 Ask player to press space to continue 509 Loop for input 510 Get the input character 511 Repeat while input isn't escape or space 512 Clear the screen 513 Start a new space 514 Reset line count 515 BLOCK END - long pages 516 If there is formatting and it's not null 517 BLOCK START - Handle formatted line 518 Move to the line position 519 Print the formatted line 520 Get the cursor position 521 COMMENT 522 COMMENT 523 COMMENT 524 COMMENT 525 If the cursor isn't at the furthest left (something was printer) 526 Add to the line to the line count 527 Save the last format 528 Save the last argument 529 BLOCK END - Handle formatted lne 530 Return the last input character 531 BLOCK END - add_line 532 BLANK 533 COMMENT 534 COMMENT 535 COMMENT 536 COMMENT END ITEM LIST 537 Define end_line with one argument 538 Argument 1 is an item for use 539 BLOCK START - end_line, ends a list with a null item 540 Declare a return character 541 BLANK 542 Add the used item to the list and save the return value 543 Restore the old screen 544 Reset the line count 545 Not a new page 546 Return the last input value 547 BLOCK END - end_line 548 BLANK 549 COMMENT 550 COMMENT 551 COMMENT 552 COMMENT NO DISCOVERY MESSAGE 553 nothing returns a pointer to string 554 Define nothing with one argument 555 Argument 1 is an item type 556 BLOCK START - nothing, set up buffer for no discoveries 557 Declare a string pointer and a string 558 BLANK 559 Copy notice to print buffer that the player hasn't found anything 560 If this is terse mode... 561 Just copy nothing 562 Update the buffer position 563 SWITCH on the type of item 564 BLOCK START - Switch on item type 565 CASE potion - set the type string 566 CASE scroll - set the type string 567 CASE ring - set the type string 568 CASE stick - set the type string 569 BLOCK END - Switch on item type 570 Copy failure to buffer 571 Return the print buffer contents 572 BLOCK END - nothing 573 EOF˙