Well, the nicest thing (for us) in the code was how we made a separate class for each Actor. That made it real easy for us to add stuff like the volcano eruptions, cannonballs, divide the turrets into different parts etc. Sadly we used it in a kind of ugly way, because Python is really slow at calling functions, so most of the functionality was put in the framelistener instead of in the actors themselves.
That's one of the reasons why we have a lot of "if actor.name == xxx" and "if actor.state = yyy" everywhere, the other is probably just due to our lack of game architecture knowledge and skills.
In our new framework (can't really call it a game even though there are some gamespecific stuff in it right now, all of which is easily removable) we have a much nicer structure. Still have the Actor as a base class, and it will probably work in about the same way, although the hierarchy will be flatter this time I think (that is, just keep Actor as the base class and have all other Actors inherit directly from it).
But I have an idea for the AI (anything from moving in the direction the actor is facing to doing more advanced thinking stuff) that will still put the code not in the Actors themselves, but in other "systems". I've only started coding this so I'm not sure how it will work out, but I think it makes sense.
Basically, an actor can at any time have a number of [0-*] states, such as "Moving", "Firing", "Planning_Zombie_To_Wall_Attack". These are just a list of strings (iirc). Then, there are a number of "subsystems", basically framelisteners, that are allowed to go through each actor and check their states against anything that the subsystem can do with that.
So you can have a MoveSystem that looks like this:
...
def updateAllActors( self, aliveActors ):
for actor in aliveActors:
if "Moving" in actor.states:
actor.position += actor.direction * actor.speed
...
The benefits of this architecture is that the actor classes become quite small, and that they work independently of the AI. Just like they don't know how to draw themselves (OGRE does that), they don't know how to apply their AI. So one person could be responsible for building a collection of Actors while another is independently working on creating a bunch of AI scripts.
The states themselves are changed using a fuzzy state machine right now (a special system handles that), but that isn't really important.
Also we have a kind of a stack for handling changing of game states, so you can simply push a "Pause game state" on top of the normal game state, and the game will only continue when it is popped from the stack again. A game state is simply an ordered collection of subsystems right now.
Makes any sense? Sounds ok?