Bug Tale #1
Today I merged many significant patches added by various contributors. It was time to get back into the swing of things and try out the new code. I was especially excited to try pennomi’s new “monster pack” code, where monsters in combat would notify nearby monsters to enter combat. Finally, large groups of monsters couldn’t always be picked off one by one.
I’m merrily testing with a new character. I get through the alpha quest line, enjoy a romp in the caves, and make my way to the Lost Mines. I pull a large group and have to use a health potion to stay up. But the potion doesn’t go away. I clear out the enemies and try drinking again. I’m getting the full effect of the potion, but the potion is still in my inventory. I check my inventory and try using the potion from there — and finally it’s gone.
A bug!
But no code relating to potion use has changed, not in a long while. So what’s happening?
I restart the game. I test, and potions work fine. But I’m full health; let’s see what happens if I take damage. I find the nearest friendly Skeletal Warrior That Shoots Icicle Spells and take damage. Viola, my potion is stuck again!
I set debuggers to look at power use, for when I use my potion. I play again and the breakpoint is hitting every frame. Oh right, once the skeleton sees me he’s dropping his warning beacon; his beacon uses the same Power system as my potions. I tweak my breakpoints and test more.
Maybe it only happens when my health isn’t full? No, that’s not true. I take damage from the skeleton, drink my health back to full, and the potions are still there. Maybe it’s being in combat? I kill the skeleton, and my potions still persist. I test so much that I find this out: if I stand near the map entrance my potions work fine; if I go further in towards the skeleton they stop working. I can move back and forth a few tiles and watch my potions break and fix! Surely this can’t be related to map position. I trace all sorts of variables but nothing turns up.
Time for a break.
…
A minute into my break and the answer is obvious. The potions aren’t working when the skeleton sees me.
When the skeleton can see me, he’s creating a warning beacon every frame. When I move towards the exit he can’t see me anymore, and he’s not doing his warnings anymore.
When I drink a potion, there’s a “used_item” field that is set in the PowerManager. Another part of the code, later in the frame, looks for used items and removes them from the player’s inventory. Well, the enemy beacon spell doesn’t require an item, so it was resetting used_items to “no item used”. In a single frame the hero’s actions are processed first, then enemy actions, then afterwards is the cleanup code that checks for used items.
Previously, it was very rare for a hero and an enemy to use a power on the exact same frame. Even when it did happen, the consequences almost never mattered. With this new code, though, enemies are dropping beacons constantly. So this bug’s been in my code for months and only manifested now: enemy powers were resetting the hero’s powers “used_item” field. Thus making my potions endless if I was in sight of an enemy.
These are the weird bugs that can haunt a project for months. And apparently, keep programmers up until 3am. Feels good to solve ’em though.