Object collisions
Objects can be divided into "allied" objects (Special Objects (Link/companions), Items) and "enemy" objects (Enemies, Parts). Collisions are checked for between these two sets of objects.
If a Part needs to do something when colliding with an Enemy, it will needs its own code to handle that (this page does not apply). Similarly, interactions are not part of the standard collision system at all (though NPCs have their own functionality for this).
Deciding whether to act on a collision
There is a "collisionType" variable which all objects have. It behaves differently for items and enemies. For items, this is a value from 0-31 (ignoring bit 7); see constants/collisionTypes.s.
When an ally collides with an enemy, the game checks whether it should respond to that collisionType. It does this by reading from a bitset in data/enemyCollisionTypes.s. Each row corresponds to a value for the enemy's collisionType, and each of the 32 bits is set if the corresponding item's collisionType should be considered for collisions. If the bit is 0, the collision is ignored.
The enemy's collisionType is almost always identical to its ID value, although some enemies change it under certain circumstances. To enable collisions on an enemy, bit 7 of their "collisionType" variable must be set. That bit is ignored for all other purposes.
Collision effects
If the collision should be acted on as determined above, the effect of the collision must be determined.
The enemy's "collisionType" variable will henceforth be ignored in favor of their "collisionReactionSet" variable. The combination of the enemy's "collisionReactionSet" and the item's "collisionType" determines what will happen next; see data/objectCollisionReactionSets.s.
The byte that is read from that file is the "collision effect". Depending on the value of the byte, knockback may occur, Link may be damaged, or the Enemy may be damaged. See constants/collisionEffects.s.
Usually (depending on the collision effect), the item's "collisionType" variable will be copied to the enemy's "var2a" variable (needs a better name...) so that the enemy code can see what it collided with, and bit 7 of "var2a" will be set to indicate that a new collision occurred.
For the "generic" collision effects that cause damage, both Allies and Enemies have a "damage" variable which usually determines how much damage they deal.
There are also more exotic effects, such as electric shocks, switching places with switch hook, etc.
Attributes
For items, the values for "collisionType" and "damage" are determined in data/itemAttributes.s. These can be overwritten at any time by the item's code, but they usually aren't.
For enemies, the value of their "collisionReactionSet" variable is determined in data/enemyData.s. Bit 7 of that byte will be transferred to bit 7 of their "collisionType" to enable collisions if so desired.
The enemy's "collisionType" variable (bits 0-6) is set to be equal to the enemy ID on initialization. This is rarely overwritten by the enemy's code.