I cannot believe I just spent 4 harrowing hours on this piece of code, I was pulling my hair out and gnashing my teeth so I thought I would share it here. It just was not resulting in what I expected.
My code causing all sorts of strange behaviour.
for ability_ref in DataStore.available_abilities:
if DataStore.used_abilities.has(ability_ref):
DataStore.available_abilities[ability_ref] -= 1
DataStore.used_abilities.erase(ability_ref)
if DataStore.available_abilities[ability_ref] <= 0:
DataStore.available_abilities.erase(ability_ref)
DataStore.activated_abilities.erase(ability_ref)
The variable available_abilities is a dictionary. The other two, activated_abilities and used_abilities, are arrays.
These are used extensively in my players abilities code and I know they are all fine. The code above just simply (or so I thought) checks if the available ability was used during the previous level, and if so depletes its available quantity by 1. Then, if it has been used, checks to see if it is completely depleted, in which case it is removed from the players available abilities. Easy-peasy you may think. And so did I until all mayhem broke lose.
After at least 4 hours testing this again and again in gameplay, tracing and tracking the problems down it came to that piece of code above. It turns out the correct code is this:
Can you spot the error? Here is the corrected code:
for ability_ref in DataStore.available_abilities.keys():
if ability_ref in DataStore.used_abilities:
DataStore.available_abilities[ability_ref] -= 1
DataStore.used_abilities.erase(ability_ref)
if DataStore.available_abilities[ability_ref] <= 0:
DataStore.available_abilities.erase(ability_ref)
DataStore.activated_abilities.erase(ability_ref)
Can you see the difference? The all important difference that after today I shall never forget! A painful lesson I thought I would share. It all comes down to this note at the bottom of the dictionaries page:
The lesson I learned the hard way today:
Note: Erasing elements while iterating over dictionaries is not supported and will result in unpredictable behavior.
Dictionary — Godot Engine (stable) documentation in English
They were not kidding when they wrote that note! You can only iterate through dictionary keys if you are modifying the dictionary in the loop. Otherwise you truly get some very peculiar, inconsistent and downright unfathomable behaviour.
Hmph. At least I got an answer in the end. What a day.
(I really must pay more attention to those humble notes in the docs)