Well, since someone recently asked about this, and I've been rather curious about it for a while, here's a bit about how weapon damage is calculated.
The function of interest can be found at address 004A3690. I've referred to it in my comments as Unit:Weapon.DoDamage().
The majority of the start of this function is conerned with the blast radius. It setups up a range on the x and y coordinates that fall within the damage zone. Note that this zone is square. It checks the destinations x and y coordinates (in pixels) and converts them to tiles. Then it converts the weaponBlastRadius (in pixels) to tiles (rounding up to the next full tile). The area of interest when calculating damage is then TileX/Y-TileRadius to TileX/Y+TileRadius. It then clips the Y values. The X values are not clipped as they may wrap around the world in an around the world type map. That behavior is handled later.
It then plays the explosion sound at the destination location.
It then loops through the tiles in that regions and checks the 11 unitIndex bits of each tile to see if there is a unit there that needs to be damaged. If no unit is present (these bits are all 0), then it will check for walls to damage.
If a unit is found, then it does some basic checking to ensure the unit is still alive/valid. It then checks to see if the unit is a building or not.
If the unit is not a building, then it calculates the absolute value of the distance between the unit (at it's center) and the weapons fire destination (all done in pixels).
If the unit was a building, then some different code executes first (relating to distance), and then the program flow rejoins units at this point.
There is some clipping like code done at this point for the x direction based on the map width (in pixels).
If mapPixelWidth/2 >= absPixelXDiff then pixelXDiff = mapPixelWidth/2 - absPixelXDiff else pixelXDiff = mapPixelWidth - absPixelXDiff
The y difference is simply taken as the absolute value of the difference in y coordinates. A special distance measure is calculated. It is:
dist = Min(pixelXDiff, pixelYDiff)/2 + Max(pixelXDiff, pixelYDiff)
If this dist >= weaponBlastRadius, then no damage is done. The code continues checking for the next unit in the damage zone.
It then loads the unit's armor, and the weapons penetration and concussion damage. It calculates a base damage value as follows:
damage = armor * concussionDamage / 256 + pentrationDamage
It then checks a flag, which is probably set for weapons fire from a GuardPost connected to a CC that increases the damage to 150% (damage = damage + damage/2). Right after this is checks a hidden flag, probably used for some kind of debug mode, that increases damage by 4x (global to the whole game). I'd come across a way to set this flag previously, but it didn't seem to have much use, so I won't discuss it here.
If the unit is a building, then the final damage will be calculated from the above damage based on the average DIRT damage prevention. If the unit is not a building than the final damage is calculated based on the above distance measure:
FinalDamage = damage * (weaponBlastRadius - dist) / weaponBlastRadius
If the FinalDamage <= 0 then the code continues checking for the next unit in the damage zone. Otherwise it applies the damage and checks if the player needs to hear an alert about being attacked.
So in short, if the target unit is a vehicle, than damage is:
FinalDamage = (armor * concussionDamage / 256 + penetrationDamage) * (weaponBlastRadius - dist) / weaponBlastRadius