I also plan to have NPCs attack autonomously, but I've two development goals right now: pathing as well as attacking.
Pathing:
For pathing, I'm going to create nested spaces, which you could think of as zones, and certain NPCs (rats, for example) can scamper within any room and to any room within that zone (collection of spaces). This is based on a timer that calls functions to update all objects of the type needing their locations updating.
Attacking:
Similar to pathing, attacking is tied, in part, to the overall timer. Different NPC properties work at different numbers of clicks of the timer. For example, rats have just a few clicks, which means in their object definitions, once their cooldown occurs, they can attack again. They don't do much damage, but they attack more frequently than a wild bear. Using a timer with combat gives me a nice way also to attenuate the cool down, giving me the ability, for example, for the player to cast a spell that increases the tick count property on a given instance of an NCP (slows their attacks) or resets the tick count to 0 (interrupts their attacks).
Side note about other timers:
I currently have a similar timing system for fire, and it works beautifully. You can strike a match, and without typing anything at all, hands completely off the keyboard, watch the match burn out after so long because there's a timer running in the background all the time, calling functions, and when an object's IsBurningYN boolean attribute is currently true and the object's property BurnTicksCount < MaxBurnTicks, it continues to burn, but when BurnTicksCount = MaxBurnTicks, the match (candle, whatever), also burns out. If you snuff a candle, for example, and there are burnticks left, you can re-light it again and then watch it burn out once it reaches its maximum number of burn ticks.
Important: I do not have a separate "match" object or "candle" or "torch" object. All manipulable objects are assigned my MCobject property list, which accounts for such things as fragility (can it and will it either break or shatter when dropped or thrown), burn-ability as mentioned, and other properties. Two challenges that I have not addressed yet include pouring liquids to spread part of one object around into smaller-volume copies of itself, etc. Their are script properties within the MCObject property list such as OnIgnite, OnDrop, OnThrow, etc., that initialize, increment, or reset other properties in the list (IsBrokenYN, IsBurningYN, etc.) and are called from verbs.
So NPCs, which is my next development piece to work on, it's timer + function calls + object type + object type properties. Lots of work in the background, but man it is cool to watch stuff happen when you're not even touching the keyboard. It feels more real-life.
I've no idea when I'll release the game, it's not high on my list of TO-DO's, but wanted to share my overall approach.