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