Decoded: Rogue (1980) by Toy, Arnold, Wichman DOS version (1983) by Mel Sibony and Jon Lane Source file: STICKS.C Beginner friendly, line-by-line code walkthrough by MaiZure STICKS.C provides everything about wands and staves Original code: https://britzl.github.io/roguearchive/ Original code with line numbers http://www.maizure.org/projects/decoded-rogue/STICKS_linenum.txt 1 COMMENT 2 COMMENT 3 COMMENT 4 COMMENT 5 COMMENT 6 COMMENT 7 BLANK 8 Include the game header 9 Inclue the console management header 10 BLANK 11 COMMENT 12 COMMENT 13 COMMENT 14 COMMENT INITIALIZE A NEW WAND/STAFF 15 Defines fix_stick with one argument 16 Argument 1 is a pointer to a wand/staff 17 BLOCK START - fix_stick, initializes wand/staff 18 If the item is a staff... 19 Set the damage to 2d3 20 Otherwise it's a wand... 21 Set the damage to 1d1 22 In both cases, hurl damage is 1d1 23 BLANK 24 Add a random number of charges between 3 and 7 25 Switch on the type of magic 26 BLOCK START - Initialize wand/staff magic 27 CASE stick of striking 28 Add a huge hit chance bonus 29 Add some hit damage bonus 30 Change base damage to 1d8 31 CASE stick of light 32 Reroll charges between 10 and 19 33 BLOCK END - Initialize wand/staff magic 34 BLOCK END - fix_stick 35 BLANK 36 COMMENT 37 COMMENT 38 COMMENT 39 COMMENT ZAP A WAND 40 Defines do_zap with no arguments 41 BLOCK START - do_zap, magic attack with wand 42 Declare a pointer to an object (the wand to zap) 43 Declare a pointer to the target (usually a monster) 44 Declare position interfers 45 Declare a pointer to a name string 46 Declare an interger for wand magic type 47 BLANK 48 Ask the player to choose a wand, but if they don't choose one... 49 Return failed 50 Get the wand's magic type 51 If the wand's type isn't a wand for some reason... 52 BLOCK START - Not a wand but item may be vorpal 53 But it has a hated enemy with charges... 54 Then it may be a vorpal weapon, set that case 55 Otherwise... 56 BLOCK START - Not zappable 57 Message the player about invalid zapping item 58 Don't pass time 59 Return fail 60 BLOCK END - Not zappable 61 BLOCK END - Not a wand but item may be vorpal 62 If the wand has no charges left... 63 BLOCK START - No charges 64 Send a fail message 65 Return failure 66 BLOCK END - No charges 67 Switch one wand's magic type... 68 BLOCK START - SWITCH on wand magic type 69 CASE magic light 70 COMMENT 71 COMMENT 72 COMMENT 73 If the player is blind 74 Print a message about warmth 75 Otherwise the player can see... 76 BLOCK START - Zap light magic 77 The player knows about light magic wands 78 If the player is in a passagway 79 Print a passageway light up message 80 Otherwise the player is in a room 81 Print a room light up message 82 BLOCK END - Zap light magic 83 If the player is in a room... 84 BLOCK START - Light up dark room 85 Toggle the room darkness flag 86 COMMENT 87 COMMENT 88 COMMENT 89 Execute the full room entrance code 90 BLOCK END - Light up dark room 91 CASE drain magic 92 COMMENT 93 COMMENT 94 COMMENT 95 COMMENT 96 COMMENT 97 If the player only has 1 hitpoint left... 98 BLOCK START - Can't drain 99 Print failure message 100 Return fail 101 BLOCK END - Can't drain 102 Otherwise... 103 Perform drain magic 104 CASE polymorph magic (fallthrough) 105 CASE teleport away magic (fallthrough) 106 CASE controlled teleport magic (fallthrough) 107 CASE interrupt magic (fallthrough) 108 CASE special 109 BLOCK START - vorpal and teleport zap 110 Declare two bytes to characters 111 Declare a room number 112 Declare new coordiantes for teleporting 113 BLANK 114 Get the player's y position 115 Get the palyer's x position 116 While the path is clear... 117 BLOCK START seeking first blocked coordinate 118 Move y down 119 Move x right 120 BLOCK END - seeking first blocked coordinate 121 If there is a monster at the blocked coordinate... 122 BLOCK START - teleport monster 123 Declare another monster character 124 BLANK 125 Match all the monster characters to the current type 126 If the monster is a venus fly trap 127 Remove the held effect from the player 128 If the wand magic is vorpal or teleport 129 BLOCK START - special zap 130 If the monster is the hated enemy of the zapping item... 131 BLOCK START - teleport monster 132 Send teleport message 133 Change monster type 134 Kill the target monster 135 BLOCK END - teleport monster 136 Otherwise, no effect 137 Failed message 138 BLOCK END - special zap 139 If the magic type is polymorph 140 BLOCK START - monster polymorph 141 Declare pointer to a monster's inventory 142 BLANK 143 Get the old monster's inventory 144 Remove the monster 145 If the player can see the polymorphing monster... 146 Add the old floor character to the postion 147 Get the monster's buffered character 148 Set the delta y coordinate 149 Set the delta x coordinate 150 Create a new monster of a random type at the new coordinates 151 If the player can see the monster... 152 Add the character to the position 153 Match the old monster's character 154 Math the old monsters inventory 155 The player now knows about polymorph magic 156 BLOCK END - monster polymorph 157 But if the wand is an interrupt attack 158 BLOCK START - monster interrupt 159 Set the monster's cancel flag 160 Remove the monster's inivisibilty and confusion capability 161 Remove monster's disguise 162 BLOCK END - monster interrupt 163 Otherwise if this is a teleport type zip 164 BLOCK START - player teleport zap 165 If player can see the monster 166 Draw the floor where the monster should be 167 If the staff is a teleport away staff 168 BLOCK START - teleport monster 169 Set the monster's old char to a default value 170 Loop while we select a new room 171 BLOCK START - random room select 172 Get a random room 173 Initialize new coordinates to the monsters current coordinates 174 Get a random position within the room 175 BLOCK END - random room select 176 Set the monster to the new position 177 If the player can see the monster 178 Add its character to the room at the new position 179 Otherwise, if player has the see monster effect active 180 BLOCK START - See monster effect 181 Enable output character emphasis 182 Add the monster at the new position 183 End extended formatting effects 184 BLOCK END - See monster effect 185 BLOCK END - teleport monster 186 Finally, the last possible spell to zap is player teleport to 187 BLOCK START - monster teleport to player 188 Teleport monster y to calculate offset from earlier 189 Teleport monster x to calculate offset from earlier 190 BLOCK END - monster teleport to player 191 If the teleport monster is a flytrap.. 192 Remove the player's held flag 193 If the the position changed... 194 Cache the old value 195 BLOCK END - player teleport zap 196 The monster should target the hero 197 And start chasing 198 BLOCK END - teleport monster 199 BLOCK END - vorpal and teleport zap 200 CASE magic missile 201 BLOCK START - zapping magic missile 202 Declare a missile 203 BLANK 204 Player now knows about magive missle 205 Set the bolt character to asterisk 206 Set hurl damage 207 Set hit chance bonus 208 Set damage bonus 209 Set flags for missile 210 If the player has a weapon... 211 Set the current weapon as the launcher 212 Move the missile 213 If the missile hits a monster and the monster doesn't save... 214 Execute the hit 215 Otherwise it's a miss 216 Print the miss message 217 BLOCK END - zapping magic missile 218 CASE striking 219 Offset y to the monster 220 Offset x to the monster 221 If there is a monster at this location... 222 BLOCK START - Roll for striking bonus 223 There's a 5% chance that... 224 BLOCK START - large bonus 225 Add a larger base damage 226 And a larger bonus to damage 227 BLOCK END - large bonus 228 Otherwise we get the default bonus 229 BLOCK START - small bonus 230 Add a smaller base damage 231 Add a smaller damage bonus 232 BLOCK END - small bonus 233 Attack! 234 BLOCK START - Roll for striking bonus 235 CASE haste magic (fallthrough) 236 CASE slow magic 237 Get the player's y position 238 Get the player's x position 239 While the path is clear... 240 BLOCK START - Find a blocked coordinate 241 Advance y coordinate 242 Advance x coordinate 243 BLOCK END - Find a blocked coordinate 244 If we find a monster... 245 BLOCK START - Haste or slow monster 246 If the magic is haste 247 BLOCK START - Haste monster 248 If the monste is slow... 249 Bring it back to normal speed 250 Otherwise 251 Haste it 252 BLOCK END - Haste monster 253 Otherwise this is slow 254 BLOCK START - Slow monster 255 If the monster is hasted... 256 Remove haste 257 Otherwise, it's normal.. 258 Slow it down 259 Monster will take it's next turn 260 BLOCK END - Slow monster 261 Update the y position difference 262 Update the x position difference 263 Activate the monster that was just hasted/slowed 264 BLOCK END - Haste or slow monster 265 CASE lightening bolt (fallthrough) 266 CASE fire bolt (fallthrough) 267 CASE frost bolt 268 If this is a lightening zap... 269 Projectile name is 'bolt' 270 If this is a fire zap... 271 Projectile name is 'flame' 272 The only other option is... 273 Projectile name is 'ice' 274 In all cases, execute the bolt procedure with the name and player 275 Player knows about this wand magic 276 Check for debug mode 277 If we didn't recognize this zap... 278 Print a debug message 279 End check for debug mode 280 BLOCK END - SWITCH on wand magic type 281 Check if the number of charges went negative... 282 If so, then set it to zero 283 BLOCK START - do_zap 284 BLANK 285 COMMENT 286 COMMENT 287 COMMENT 288 COMMENT DEAL HEALTH DAMAGE 289 Define drain with no arguments 290 BLOCK START - drain, deals health damage all around, including player 291 Declare a pointer to a monster 292 Declare a counter 293 Declare a pointer to a room 294 Declare a pointer to a target to drain 295 Declare a flag to denote player in passage status 296 Declare an array of pointers for monsters to drain 297 BLANK 298 COMMENT 299 COMMENT 300 COMMENT 301 Initialize counter to zero 302 IF the hero is standing in a doorway 303 Get the passage that the hero is in 304 Otherwise 305 We don't need the direct passage pointer 306 Check if player is in a passage 307 Point to drain target to the drain buffer (currently empty) 308 Loop through all the monsters 309 If the monster is in the room with the player... 310 Or in the passage / passage doorway with the player 311 Or player is in a doorway with a monster nearby... 312 Add this monster to the drain array and increment 313 If there are no monsters to drain... 314 BLOCK START - Failed drain 315 Send failure message 316 Return - nothing happens 317 BLOCK END - Failed drain 318 Clear the drain pointer 319 Half the player's hitpointers 320 Allocate player's remaining health among the number of monsters 321 COMMENT 322 COMMENT 323 COMMENT 324 Loop through all drain targets 325 BLOCK START - drain loop 326 Point to the target 327 Remove allocated damage and if monster's health is gone... 328 Kill the monster 329 Otherwise, they survived... 330 So set them off to chase the player 331 BLOCK END - drain loop 332 BLOCK START - drain 333 BLANK 334 COMMENT 335 COMMENT 336 COMMENT 337 COMMENT FIRE BOLT ATTACK 338 Define fire_bolt with three arguments 339 Arguments 1 and 2 are coordinates for start position and motion vector 340 Argument three is the name of the bolt 341 BLOCK START - fire_bolt, ranged fire attack 342 Declare a character for bolt appearance and floor space 343 Declare a pointer to a target 344 Declare flags for bolt state 345 Declare iterators 346 Declare a position 347 Declare a struct to buffer a stream of bolt positions 348 One struct element is a position 349 Another element is the floor character 350 This struct is called spotpos and has two elements per floor space used 351 Declare a pointer to a bolt 352 Declare a flag for ice attack 353 BLANK 354 Set flag if this is a frost bolt using the name 355 Bolts are weapons 356 Bolts are flames 357 Bolt damage, including thrown damage, is 6d6 358 Hit bonus is 30 points 359 No damage bonus 360 Set the name of the zap 361 Switch on the sum of the direction offsets 362 CASE 0, bolt is going UR or DL, set character accordingly 363 CASE -1 or 1, it must be horizonal or vertical 364 CASE 2 or -2, it must be UL or DR 365 End check for bolt direction and setting graphic 366 Position is at the start 367 The bolt can't hit the player on its starting move...but later... 368 Set flag for saving check to false 369 Set update flag to false 370 Loop through the total length of the bolt (calculate each position) 371 The y position advances in its y direction 372 The x position advances in its x direction 373 Get the character under the position 374 Set the position of this bolt fragment 375 Store the floor character unless it is equal to another bolt... 376 Then store nothing (some other part of the bolt is storing it) 377 BLOCK START - Switch on floor type under bolt 378 CASE door (fallthrough) 379 CASE horizontal wall (fallthrough) 380 CASE vertical wall (fallthrough) 381 CASE corner wall (fallthrough) 382 CASE corner wall (fallthrough) 383 CASE corner wall (fallthrough) 384 CASE corner wall (fallthrough) 385 CASE empty space: 386 If the bolt hasn't moved...ricochet! 387 Then toggle ability to hit the player 388 The bolt hasn't changed position 389 Reverse y direction 390 Reverse x direction 391 Redo this calculation 392 Print message that the bolt bounced off a wall 393 End this update 394 CASE any other hit case 395 If the bolt can't hit the hero but there's a monster here... 396 The bolt is free to hit the player 397 Toggle the changed value 398 If the bolt character cache isn't using the default value... 399 Save the floor character under the bolt 400 If a saving check failed or the bolt is made of frost... 401 Cache the bolt's current position 402 Something attempted to save against this bolt 403 If the bolt hit a dragon and the bolt is fire 404 Print a message that the flame is useless against dragons 405 Otherwise this is a normal monster hit 406 Calculate the hit and damage 407 If the character under the bolt isn't another bolt (floor, etc)... 408 Save the floor character at this position 409 End check for monster hit 410 Otherwise, the bolt missed the monster so if the player sees that... 411 If the bolt came from the player... 412 Set off the monster to chase the player 413 Print a message about the miss... 414 Including the monster's name 415 End check for player witnessing a missed shot 416 The final hit case is if the bolt hits the player... 417 Set the player hit check to false 418 Toggle the change flag 419 If the save fails... 420 And the bolt is frost... 421 Print a message that the player is now frozen 422 If the player hasn't already lost more than 20 turns... 423 Player now loses up the 6 turns 424 For all other bolt types that hit the player...if the player dies... 425 If the bolt came from the player himself... 426 Set the death condition as the bolt 427 Otherwise the bolt came from a monster 428 Set the death conditions as the monster 429 Player is still alive and the bolt has been used 430 If this isn't a frost bolt... 431 Print that the player has been hit (frost bolts already had a msg) 432 End check for player hit, this bolt must have missed 433 Print a bolt missing message 434 End check for hitting/missing the player 435 If this is a frost bolt 436 Change print color to blue 437 Otherwise... 438 All other bolts are red 439 Pause time passing 440 Add the bolt character to its position 441 End extended format printing 442 BLOCK END - Switch on floor type under bolt 443 Retry loop through all bolt positions 444 Loop through all the bolt positions 445 Pause time 446 If the bolt has a floor space under it... 447 Reapply the old floor space 448 Redo loop through all bolt positions 449 BLOCK START - fire_bolt 450 BLANK 451 COMMENT 452 COMMENT 453 COMMENT 454 COMMENT GET WAND CHARGE COUNT 455 charge_str returns a string 456 Defines charge_str with one argument 457 Agument 1 is a pointer to a wand 458 BLOCK START - charge_str, returns the text of magic charges remaining 459 Declare a text buffer 460 BLANK 461 If the player doesn't know the item... 462 Then the player knows nothing about it....blank buffer 463 Otherwise... 464 Print the number of wand charges to the buffer 465 Return buffer 466 BLOCK END - charge_str 467 EOF˙