Decoded: Rogue (1980) by Toy, Arnold, Wichman DOS version (1983) by Mel Sibony and Jon Lane Source file: COMMAND.C Beginner friendly, line-by-line code walkthrough by MaiZure COMMAND.C provides functions to read and handle user input Original code: https://britzl.github.io/roguearchive/ Original code with line numbers http://www.maizure.org/projects/decoded-rogue/COMMAND_linenum.txt 1 COMMENT 2 COMMENT 3 COMMENT 4 COMMENT 5 COMMENT 6 BLANK 7 Includes the game header 8 Includes the console management header 9 BLANK 10 Declares a compilation unit level static integer for counting 11 Declares three static bytes for input character buffer and obj pointers 12 BLANK USER INPUT HANDLER 13 Declares command with no arguments 14 BLOCK START - command, handles input. Called every cycle of game loop 15 Declares an interger counting the number of commands to handle 16 BLANK 17 If the player has the Haste condition 18 Then the player can act 2 or 3 times per command loop 19 Otherwise... 20 The player gets one turn per loop 21 While there are still turns for the loop.. 22 Update the status bar 23 Checks keyboard for utility keys (caps, numlock, etc) via DOS interrupts 24 Checks if we're in wizard mode (we're not) 25 If wizard mode is active... 26 Then there is no score 27 End check for wizard mode 28 If the player cannot move now (sleeping, too much food, etc) 29 Decrement the no_command counter and check if it's 0 30 Print a message that the player can move 31 Set no_command to zero 32 End check for no_command at ero 33 Otherwise, the player is free to move 34 Execute the most recent command 35 Update single-shot timers 36 Update background tasks 37 Clever loop to cover both ring slots and apply effects if needed. Note this loop is an inner loop for the outer while but reuses the main iterator. In any case, we loop from 0 to 1 to cover L and R slots 38 Check if the slot has a ring 39 SWITCH on the type of ring 40 CASE ring of searching 41 Execute a search 42 CASE ring of teleport 43 Roll a random number and if it matches 17 (2% chance) 44 Teleport the player randomly 45 End Switch 46 End command loop 47 BLOCK END - command 48 BLANK 49 Defines com_char with no arguments CHECK FIRST CHARACTER (ESCAPE CHARACTER CHECK) 50 BLOCK START - com_char, returns an escaped character and sets state 51 Declare a local integer for a previous state flag and the return char 52 BLANK 53 Grab the current state of the text parsing (for running, etc) 54 Read in the input character from the keyboard. Note that this could change the faststate setting, which is why we grabbed it earlier 55 If the state matches 56 Then set the fastmode to match 57 Otherwise... 58 Make them different 59 SWITCH on the character to return 60 CASE backspace: set it to h (move left) 61 CASE plus: map it to 't' for throw 62 CASE minus: map it to 'z' for zapping wands 63 End switch 64 If the cursor is in the room of play and the player isn't running 65 Clear the status line 66 Return the character to the player 67 BLOCK END - com_char 68 BLANK 69 COMMENT 70 COMMENT 71 COMMENT 72 COMMENT 73 BLANK 74 Define get_prefix with no arguments GET COMMAND PREFIX (FIRST LETTER) 75 BLOCK START - get_prefix, returns the first character of input 76 Declare integers for return, storage, and temporary values 77 BLANK 78 Command is executed after the background update daemons 79 Match the running/detection mode 80 Update the screen to the current location 81 If the player isn't running... 82 Then don't stop the player that encounters a door 83 Pick up items that the player runs in to 84 Assume the command isn't repeated 85 If the command is to be issued at least once... 86 Update the item taking from the global buffer variable 87 Update the last returned character from global buffer 88 Disable fast mode 89 Otherwise there was only one command to issue (or none?) 90 Make sure count is zero (could be -1 at this point?) 91 If the player is currently running 92 Update the return character to the current running direction 93 Update the take state 94 Otherwise, the character is not running so... 95 Loop while there is no return character (process multichar input) 96 SWITCH on the first input character (after escaping via com_char) 97 If the first character is 0-4... 98 ...or 5-9... 99 Setting up repeated commands: multiply the first digit by 10 100 Check and add more input. If it's less than 10000 total.. 101 Use the input number for future repeated processing loops 102 Display the number of times the next command will repeat 103 CASE input is 'f' (searching) 104 Toggle fast mode for item searching 105 CASE input is 'g' (item get) 106 Clear the last item take state 107 CASE input is 'a' (repeat last input) 108 Set return character to the last returned character 109 Set the repeat counter to the last used repeat counter 110 Set the take state to the previous state 111 Mark flag for repeat 112 CASE space (ignore) 113 CASE escape (cancel input) 114 Don't allow door interruptions 115 No repeats 116 Show the updated counter 117 For everything else... 118 Set the return value and we'll process later 119 End Switch on input character 120 End loop while reading input 121 End check for player not running input case 122 End case for only one input repeat loop remaining 123 If we are repeating a command.. 124 Set the fastmode to false so we can be interrupted by interesting things 125 SWITCH on input character now that we've looped through all repeats 126 If input is a single step cardinal direction.. 127 or if input is a single step ordinal direction.. 128 Check if we're in fastmode and not running (we must simulate running). 129 If the player isn't blind... 130 Stop on doors 131 This is the first movement 132 End check for blindness 133 Return the upper case of the movement directionm 134 End check for fast mode but not running 135 If input is a running cardinal... 136 ...or a running ordinal... 137 ...or an item usage command... 138 ...or throw or wait... 139 Preprocessor check for wiz mode 140 ...or the wizard command to create items... 141 End check for wiz mode 142 All these above cases require no extra processing, retch is already set 143 For all other cases... 144 Set count to 0, nothing to repeat 145 End Switch 146 If there is something to repeat or we're in the middle of repeating 147 Show the count display 148 Set the global buffer history to reflect this character 149 Set the global counter to the now updated count 150 Set the global take state to reflect current take state 151 Return the character determined character 152 BLOCK END - get_prefix 153 BLANK 154 Define show_count with no arguments SHOW REPEATED COMMAND COUNTS 155 BLOCK START - show_count, displays the current count of repeated actions 156 Move the cursor to (almost) the bottom right 157 If there is a repeating count in progress... 158 Print the value to the status line 159 Otherwise... 160 Print nothing 161 BLOCK END - show_count 162 BLANK 163 Define execcom with no arguments EXECUTE COMMANDS 164 BLOCK START - execcom, dispatches command input to the proper handler 165 Declare a local coordinate struct 166 Declare a local variable to hold input char values 167 BLANK 168 Start the main input loop 169 SWITCH on the input character 170 CASE walking cardinal direction (fallthrough) 171 CASE walking ordinal direction 172 Set the motion offset in to the temp coordinate 173 Apply the change to the character 174 CASE running cardinal direction (fallthrough) 175 CASE walking ordinal direction 176 Run to the indicated direction based on the input 177 CASE throw 178 If the player chooses a valid direction 179 Launch the item in the correct direction 180 Otherwise... 181 No valid options were chosen, redo turn 182 CASE quit: quit the game 183 CASE inventory: check the player inventory 184 CASE drop: drop items 185 CASE quaff: drink a potion 186 CASE read: read a scroll 187 CASE eat: eat something 188 CASE wield: equip a weapon 189 CASE wear: put on armor 190 CASE take off: rake off armor 191 CASE wear ring: put on a ring 192 CASE take off ring: do iiiit! 193 CASE rename item: change an item name, no turn passes 194 CASE go down: Take stairs down to the next level, no turn passes 195 CASE go up: Take stairs up to the previous level, no turn passes 196 CASE object help: Shows the game legend 197 CASE command help: Shows the commands 198 CASE boss key: Jump to fake DOS while playing on the job. DOS at work? Maybe if you're in a Government job. 199 CASE search: Search function 200 CASE zap: 201 If player inputs a valid direction 202 Zap the wand that way 203 Otherwise... 204 Redo the turn 205 CASE discoveries: Show the list of discoveries 206 CASE terse mode: 207 No turn passes 208 Out a message condition on the toggle value of the expert mode 209 Message if mode is now on 210 Message if mode is now off 211 CASE macro: create a new macro, no turn passes 212 CASE function: Set the executing macro 213 CASE repeat last message: repeat it! 214 CASE show version: 215 Pass no time 216 If the player is some hidden fun super user guy 217 Return the current checksum 218 Output the game version, including the Easter egg coder/hacker tag 219 CASE save game: Save! 220 CASE pass time: check healing routine and pass time 221 CASE identify trap: 222 No turn passes 223 If the player provides a valid direction... 224 Declare temp coordinate 225 BLANK 226 Set the x coordinate based on player position plus offset 227 Set the y coordinate based on player position plus offset 228 If there is no trap at the chosen location 229 Say so 230 Otherwise 231 Say that there is a trap.. 232 and include the name using the flag lookup index 233 Otherwise the player didn't choose a valid direction 234 CASE 'o' input: No time passes and a useless message is output 235 CASE ctrl-l: 236 No time passes 237 Another coder/hacker easter egg message 238 Check if wizard mode is enabled 239 Handle create object 240 End check for wizard mode 241 CASE no command matches 242 No time passes 243 Disable message buffer 244 Output bad command message 245 Reset count to 0 (don't repeat nonsense commands) 246 Enable message buffer 247 End switch 248 If take mode and an object are identified 249 Pick up the object 250 Deassert the take flag 251 If the player is walking... 252 Don't get stopped by hitting a door 253 Redo the main input loop while there isn't a valid command to process 254 BLOCK END - execcom 255 EOF˙