In 1.4.7 (only version I've tested and debugged this), normal zombie spawns can attack a village, as usual, but the real "siege" fails to start.

Tested by adding suitable console messages to VillageSiege class, tracking the midnight-test and when it starts spawning the extra zombies. Without a fix, it never happens.

Reason

While trying to start a siege, the process first looks if it can find a suitable spot to spawn the zombies (slightly cheating here; normal spawn rules seem to not apply). However, the method that looks for an exact spot to spawn at is missing a 'return'. Thus, a found valid spot is never returned and the siege start process just keeps on with a futile attempt at looking for spots...

Here is the bugged method, as seen by MCP:

VillageSiege.func_75527_a(int, int, int) private Vec3 func_75527_a( int par1, int par2, int par3) { for ( int var4 = 0; var4 < 10; ++var4) { int var5 = par1 + this .worldObj.rand.nextInt(16) - 8; int var6 = par2 + this .worldObj.rand.nextInt(6) - 3; int var7 = par3 + this .worldObj.rand.nextInt(16) - 8; if ( this .theVillage.isInRange(var5, var6, var7) && SpawnerAnimals.canCreatureTypeSpawnAtLocation(EnumCreatureType.monster, this .worldObj, var5, var6, var7)) { this .worldObj.getWorldVec3Pool().getVecFromPool(( double )var5, ( double )var6, ( double )var7); } } return null ; }

Fix

... if ( this .theVillage.isInRange(var5, var6, var7) && SpawnerAnimals.canCreatureTypeSpawnAtLocation(EnumCreatureType.monster, this .worldObj, var5, var6, var7)) { return this .worldObj.getWorldVec3Pool().getVecFromPool(( double )var5, ( double )var6, ( double )var7); } ...

Adding that missing return allows the rest of the process to finally find a suitable spot, start the siege, and spawn each zombie (even inside fully lit buildings, though, but this is known thing, worth of another issue).

EDIT: Important addition

I didn't figure this out at first (since I was fixing it "on the fly"), but once the above fix is done, another problem surfaces. The initial state in the siege engine is -1, but there is no proper handling of that state. In a new world this would not be a problem since the world starts into a day, which resets the state to 0. However, if an existing world that is currently in a night is loaded into a fixed game, the incorrect state slips through...

More fixing

Harder to explain the exact location of this fix, but in the same class, method tick(), right after all the code that checks that state-variable, add: