Yes you will want to break it up into two parts, an initialization period and a periodic check. Given that not all improvements are owned by a player, and ownership can shift during the course of a turn, you might want to use OnBeginGameTurn instead.
Now, the system I use in my Monster lairs and Ruins mod is to store this sort of information in the ScriptData of the plot (because each plot can only have one improvement--roads are features). What the ScriptData "services" let you do is store an arbitrary stream of bytes associated with an object within the game engine (meaning it is persisted, even across game saves). This is cool. Now, you can just set the script data to the turn your improvement was built, if you like. Personally, I'm not a Python programmer historically, and I haven't spent much effort in really learning the capabilities of the language or the libraries which have been built for it to date. I have, however, spent some time reading over the works of modders more knowledgable about Python then I

. There is an object serializer for Python called Pickle (because you pickle the objects). A serializer is basically an object which takes a Python object (any object) and converts it into a stream of bytes which can be saved and later restored to reinstantiate that object (like a snapshot). Sort of like one of those kids books with the 3d castles inside. It flattens up the object so it can be stored. Python provides some built-in collections, one of which is the Dictionary, which lets you associate arbitrary keys with arbitrary python objects. So here's the cool part. A Dictionary is an object. So you use Pickle to serialize it and store in the ScriptData of the plot, and now you can persist as much information as you like in it.
Not sure I explained that well, so let me find some code to cut and paste.
This is written for my fuel mod, but the same code works for plots as for units--
Code:
def initUnitDictionary(pUnit):
unitDict = {}
pUnit.setScriptData(cPickle.dumps(unitDict))
def getUnitDictionary(pUnit):
unitDict = cPickle.loads(pUnit.getScriptData())
return unitDict
def setUnitDictionary(pUnit, unitDict):
pUnit.setScriptData(cPickle.dumps(unitDict))
def getFuel(pUnit):
unitDict = getUnitDictionary(pUnit)
return unitDict["fuel"]
def refuel(pUnit):
unitDict = getUnitDictionary(pUnit)
unitDict["fuel"] = getMaxFuel(pUnit)
setUnitDictionary(pUnit, unitDict)
So, in onImprovementBuilt, you initialize the plot with the Den to have a plotDictionary. Then onBeginGameTurn you walk all the plots on the map, check each for an improvement, check the improvement to make sure it's a Den, then retrieve it's turn created, and evaluate your equation for determining if you want to spawn a new animal. Although, I think you want to introduce some randomness, IMO.
Also, if you set a den to be a goody, the map generators will spread them around for you. You can set the goody to be bad if you want the AI to not want to explore them.
Anyhow, this should be more then enough information to get you going.