simple staves

      now that we took away some items, it's time to add a few of our own.
      this post will deal with adding new staves.

      basic extensions
      staves work by launching a specific type of magic bolt, and they have
      a limited number of charges (but can recharge, unlike wands). there are
      a few types of magic bolts that can't be launched with a staff; we'll
      be making a staff for two of these bolts: carnivorous vines (launched by
      mangrove dryads) and dragonfire (exhaled by dragons).

      what's so cool about these two magic bolts, exactly? well, dragonfire is
      a lot like normal fire, but it fuses the ground into obsidian and is extra
      powerful. carnivorous vines, besides being carnivorous vines, can be launched
      over bodies of water and set on fire to create an incredible amount of steam.

      anyway, let's get to the coding part. *hacker noises*

      near line 812 of Rogue.h, you'll find the enum that defines the different
      kinds of staves. at the start of this enum, add STAFF_DRAGONFIRE and
      STAFF_VINES. next, go to the switch statement near line 2325 of Items.c
      (you can search for STAFF_LIGHTNING as a shortcut to see where staff
      behavior is implemented). this block of code is where staff descriptions
      are defined, so copy another case branch and edit it as needed.

      next, go to Globals.c and find the staffTable (near line 2460). add the
      following staff definitions to the start of the table:
{"dragonfire", itemWoods[13], "", 15, 1300, BOLT_DRAGONFIRE, {2,4,1}, false, false, "This staff unleashes a powerful bolt of dragonfire that will burn any creature it \ hits. Creatures immune to fire will be unaffected."}, {"vines", itemWoods[14], "", 15, 1300, BOLT_ANCIENT_SPIRIT_VINES, {2,4,1}, false, false, "This staff releases carnivorous vines at its target."},
of course, you can edit the descriptions if you have a better idea. the random numbers and booleans in the table entries control things like spawning behavior and charges, so you can leave them alone unless you want to do some really detailed customization. this code should be enough to work, but in order to test things out you'll need to make sure you spawn with these two staves in debug mode. near line 452 of src/brogue/RogueMain.h, there's a DEBUG block that equips the player with items in debug mode only. add this code into that block:
theItem = generateItem(STAFF, STAFF_DRAGONFIRE); theItem->enchant1 = 10; theItem->charges = 300; theItem->flags &= ~ITEM_CURSED; identify(theItem); theItem = addItemToPack(theItem); theItem = generateItem(STAFF, STAFF_VINES); theItem->enchant1 = theItem->charges = 10; theItem->flags &= ~ITEM_CURSED; identify(theItem); theItem = addItemToPack(theItem);
congratulations -- you can now compile the code and wreak havoc! a more complicated staff next, we'll add a staff with an entirely new bolt type: swapping. a bolt of swapping will swap the player with the creature that it's fired at. so first, let's add in the new bolt, and handle the staff after that. near line 831 of Rogue.h, you'll find the definition for enum boltType. insert BOLT_SWAP into that enum after BOLT_LIGHTNING. then, near line 1700 there's another enum definition for boltEffects. add BE_SWAP in after BE_NONE. before we get the classic Rogue.h bookeeping out of the way, there's one more thing to define: the function that implements the "swapping" action. around line 2887 there's a header declaration of the teleport function, so putting our swap declaraction next to here would be appropriate. the swap function's header looks like this:
void swap(creature* monst1, creature* monst2);
and now for the implementation of swap. I'm going to be defining it in src/brogue/Monsters.c, next to the definition of teleport (~line 1068) for convenience. the code is pretty simple -- it's basically just two calls to teleport:
void swap(creature* monst1, creature* monst2) { // save the location of monst1 before we move it short x = monst1->xLoc; short y = monst1->yLoc; teleport(monst1, monst2->xLoc, monst2->yLoc, true); teleport(monst2, x, y, true); }
next, we'll add in the call to this function. the function updateBolt, located near line 4105 of Items.c, handles the behavior of bolts as the travel through space -- including what happens when the bolt hits a monster. near the start of the function there's a switch block that handles collisions with monsters based on which boltEffect a bolt has. add this case to it:
case BE_SWAP: swap(caster, monst); break;
with that out of the way, it's now time to add a staff for swapping. it's the same process as the start of this post, so I'll omit it in order to be less redundant.