Have the engine handle all code that's redundant among damage calculations for each character. The characters will be forced to do the rest.
I don't know much about what kind of game you're making. But for some games, when the engine is told that A is attacking B, the code might look something like:
//somewhere in your engine:
damage = A.get_damage(B);
trace (damage); // {damage:60, hit_chance = 0.8}
B.send_damage(damage);
I believe it to be necessary in most cases to have B.send_damage()
rather than the engine directly controlling the health attribute of B. AI's tend to be state-driven. There will likely be some variables that are exclusive to A or B that affect damage (such as invincibility), which (IMO) it's best that the engine have no idea of their existence (or you'll end up with huge switch blocks ;D)
You see how I had to send B as an argument in A.get_damage()
? Unfortunately, that's often necessary in an an approach like this. A's damage/hit_chance could be influenced by how far away B is from A.