So I've expanded it to compare two materials and their relative hardness and adjust the amount of damage to that material appropriately.
Code:
int damage_item(struct char_data *ch, int attack_type, int item_type_damaged, struct char_data *damager)
{
int wearslot = 0; // Used in DAMAGE_ALL; runs a do...while loop while whichitem <= MAX_WEAR_SLOTS
int dicesize = 0, message = 0; // Message: 0 - severe, 1 - heavy, 2 - moderate, 3 - light, 4 - barely.
int attempts = 0; // Essentially, we'll give the function 3 chances to find a piece of armor to damage.
int material = 0; // Fill this value with what will be the material of item getting damaged.
int oppmaterial = 0, hardnessdiff, hardtarget, harddamager, damage;
bool add_damage = FALSE; // Does your armor seep in that heat or cold?
bool sub_damage = FALSE; // Does your armor block some of that heat or cold?
struct obj_data *whichitem = NULL;
struct obj_data *targ = NULL;
struct obj_data *wielded = NULL;
struct obj_data *dwielded = NULL;
/* There's 2 different actions here: damaging 1 item or damaging all. So, let's deal with all items
being damaged by, say, breath weapons and traps. We're going to make a check using a switch, and handle
DAM_ALL first. */
switch (item_type_damaged) {
case DAMAGE_ALL:
/* Here we go. the long haul!
So in here we need to run through every slot, check to see if it has any durability to damage. If it does,
then we need to check it's material, check the type of damage, and then compare material vs. damage type and
deal appropriate damage to durability. The easiest way to do this is using a do...while loop. So let's get
started. */
do {
whichitem = GET_EQ(ch, wearslot);
if (GET_OBJ_MAX_DURAB(whichitem) != 0 && (whichitem != NULL)) { // Does the item have durability tracked? And is an item there in the first place?
if (GET_OBJ_TYPE(whichitem) == ITEM_ARMOR) material = GET_OBJ_VAL(whichitem, 1); // If it's armor, material will be located here.
else
if (GET_OBJ_TYPE(whichitem) == ITEM_WEAPON) material = GET_OBJ_VAL(whichitem, 0); // If it's weapon, material will be located here.
else material = MAT_CLOTH; // If it's not a weapon or armor, likely it is a type of clothing. Keeps things from... crashing.
/* Durability checked, then we got the material. Should have attack type. Now to compare the two, deal appropriate damage. */
switch (attack_type) {
case ATT_ACID: // Acid will deal high damage to cloth, leather, hide but to metals, not so much. Almost none to mithril and adamantium.
switch (material) {
case MAT_CLOTH:
case MAT_LEATHER:
case MAT_HIDE:
case MAT_WOOD:
dicesize = 20;
message = MESSAGE_SEVERE;
break;
case MAT_COPPER:
case MAT_BRONZE:
dicesize = 12;
message = MESSAGE_HEAVY;
break;
case MAT_IRON:
case MAT_STEEL:
case MAT_ENDURIUM:
dicesize = 8;
message = MESSAGE_MODERATE;
break;
case MAT_MITHRIL:
dicesize = 2;
message = MESSAGE_BARELY;
sub_damage = TRUE;
break;
case MAT_ADAMANT:
dicesize = 4;
message = MESSAGE_LIGHT;
break;
default:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
}
break;
case ATT_COLD: // Cold barely damages metals, none to mithril and adamantium, but it WILL deal additional damage to the wearer. Light damage to cloth, etc.
switch (material) {
case MAT_CLOTH:
dicesize = 4;
message = MESSAGE_LIGHT;
break;
case MAT_LEATHER:
case MAT_HIDE:
dicesize = 4;
message = MESSAGE_LIGHT;
sub_damage = TRUE;
break;
case MAT_WOOD:
dicesize = 4;
message = MESSAGE_LIGHT;
break;
case MAT_COPPER:
case MAT_BRONZE:
case MAT_IRON:
case MAT_STEEL:
case MAT_ENDURIUM:
dicesize = 2;
message = MESSAGE_BARELY;
add_damage = TRUE;
break;
case MAT_MITHRIL:
dicesize = 1;
message = MESSAGE_BARELY;
sub_damage = TRUE;
break;
case MAT_ADAMANT:
dicesize = 1;
message = MESSAGE_BARELY;
break;
default:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
}
break;
case ATT_ELECTRIC: // Electric, like cold, barely damages items. But metal conducts, save mithril and adamantium. Wood blocks some of the damage.
switch (material) {
case MAT_CLOTH:
case MAT_LEATHER:
case MAT_HIDE:
dicesize = 4;
message = MESSAGE_LIGHT;
break;
case MAT_WOOD:
dicesize = 4;
message = MESSAGE_LIGHT;
sub_damage = TRUE;
break;
case MAT_COPPER:
case MAT_BRONZE:
case MAT_IRON:
case MAT_STEEL:
case MAT_ENDURIUM:
dicesize = 4;
message = MESSAGE_LIGHT;
add_damage = TRUE;
break;
case MAT_MITHRIL:
dicesize = 1;
message = MESSAGE_BARELY;
sub_damage = TRUE;
break;
case MAT_ADAMANT:
dicesize = 1;
message = MESSAGE_BARELY;
add_damage = TRUE;
break;
default:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
}
break;
case ATT_FIRE: // Fire damage deals lots of damage to wood, cloth, leather, etc. but not much to metals. Adds more damage if metal is worn.
switch (material) {
case MAT_CLOTH:
case MAT_LEATHER:
case MAT_HIDE:
dicesize = 12;
message = MESSAGE_HEAVY;
break;
case MAT_WOOD:
dicesize = 20;
message = MESSAGE_SEVERE;
break;
case MAT_COPPER:
case MAT_BRONZE:
case MAT_IRON:
case MAT_STEEL:
case MAT_ENDURIUM:
dicesize = 6;
message = MESSAGE_MODERATE;
add_damage = TRUE;
break;
case MAT_MITHRIL:
dicesize = 2;
message = MESSAGE_BARELY;
sub_damage = TRUE;
break;
case MAT_ADAMANT:
dicesize = 2;
message = MESSAGE_BARELY;
add_damage = TRUE;
break;
default:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
}
break;
case ATT_PHYSICAL: // Huh... not sure WHAT would use this, but let's assume it does moderate damage to all but mithril and adamant.
switch (material) {
case MAT_CLOTH:
case MAT_LEATHER:
case MAT_HIDE:
case MAT_WOOD:
case MAT_COPPER:
case MAT_BRONZE:
case MAT_IRON:
case MAT_STEEL:
case MAT_ENDURIUM:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
case MAT_MITHRIL:
case MAT_ADAMANT:
dicesize = 2;
message = MESSAGE_BARELY;
break;
default:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
}
break;
case ATT_STEAM: // Steam deals moderate damage to cloth and such, barely any to metals but will heat them up and deal more damage.
switch (material) {
case MAT_CLOTH:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
case MAT_LEATHER:
case MAT_HIDE:
case MAT_WOOD:
dicesize = 6;
message = MESSAGE_MODERATE;
sub_damage = TRUE;
break;
case MAT_COPPER:
case MAT_BRONZE:
case MAT_IRON:
case MAT_STEEL:
case MAT_ENDURIUM:
dicesize = 4;
message = MESSAGE_LIGHT;
add_damage = TRUE;
break;
case MAT_MITHRIL:
dicesize = 2;
message = MESSAGE_BARELY;
sub_damage = TRUE;
break;
case MAT_ADAMANT:
dicesize = 2;
message = MESSAGE_BARELY;
add_damage = TRUE;
break;
default:
dicesize = 6;
message = MESSAGE_MODERATE;
break;
}
break;
default: // Shouldn't get here but just default damage.
dicesize = 6;
message = MESSAGE_MODERATE;
break;
}
/* Whew! We've gotten the damage dice dealt to the item. Also if the item blocks or adds damage to the player. Now we get to it! */
// Message, then damage to the item itself. If it breaks, kick it off into inventory.
switch (message) {
case MESSAGE_SEVERE:
act("\tRThat attack does SEVERE damage to $p!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tR$n's $p took SEVERE damage from that attack!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
break;
case MESSAGE_HEAVY:
act("That attack does \tRHEAVY\tn damage to $p!", FALSE, ch, whichitem, 0, TO_CHAR);
act("$n's $p took \tRHEAVY\tn damage from that attack!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
break;
case MESSAGE_MODERATE:
act("That attack \tydamaged\tn $p!", FALSE, ch, whichitem, 0, TO_CHAR);
act("$n's $p took \tydamage\tn from that attack!", FALSE, ch, whichitem, 0, TO_ROOM);
break;
case MESSAGE_LIGHT:
act("That attack does some \tgminor\tn damage to $p!", FALSE, ch, whichitem, 0, TO_CHAR);
act("$n's $p took \tgminor\tn damage from that attack!", FALSE, ch, whichitem, 0, TO_ROOM);
break;
case MESSAGE_BARELY:
act("That attack hardly did any damage to $p...", FALSE, ch, whichitem, 0, TO_CHAR);
act("$n's $p hardly took any damage from that attack.", FALSE, ch, whichitem, 0, TO_ROOM);
break;
default:
break;
}
GET_OBJ_DURABILITY(whichitem) -= rand_number(1, dicesize);
if (GET_OBJ_DURABILITY(whichitem) < 0) GET_OBJ_DURABILITY(whichitem) = 0;
if (GET_OBJ_DURABILITY(whichitem) == 0) {
act("\tRYikes, $p\tR FELL APART!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tR$n's $p\tR FELL APART!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
obj_to_char(unequip_char(ch, wearslot), ch);
}
/* Players will love or hate this part... did the item block or deal more damage? */
if (add_damage == TRUE) {
switch (attack_type) {
case ATT_COLD:
act("\tcThe cold seeps through $p, freezing you!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tcThe cold seeps through $n's $p, the icey chill dealing more damage!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) -= rand_number(1, 3);
break;
case ATT_ELECTRIC:
act("\tYThe electricity shoots through $p, shocking you!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tYThe electricity shoots through $n's $p, shocking $m more!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) -= rand_number(1, 3);
break;
case ATT_FIRE:
act("\tOThe heat from the flames make $p hot, burning you more!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tOThe heat from the flames makes $p hot, burning $n more!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) -= rand_number(1, 2);
break;
case ATT_STEAM:
act("\tWThe steam heats up $p a lot, burning you more!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tWThe steam heats up $p a lot, burning $n more!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) -= rand_number(1, 4);
break;
}
}
if (sub_damage == TRUE) {
switch (attack_type) {
case ATT_COLD:
act("\tBThe cold is somewhat blocked by $p, insulating you!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tBThe cold is somewhat blocked by $p, keeping $n insultated!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) += rand_number(1, 2);
break;
case ATT_ELECTRIC:
act("\tBYou are somewhat insulated from the electrical attack by $p!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tB$n is somewhat insulated from the electrical attack by $p!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) += rand_number(1, 2);
break;
case ATT_FIRE:
act("\tBYou are somewhat protected from the flames by $p!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tB$n is somewhat protected from the flames by $p!tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) += rand_number(1, 2);
break;
case ATT_STEAM:
act("\tBThe steam is blocked a little by $p, and doesn't heat it!\tn", FALSE, ch, whichitem, 0, TO_CHAR);
act("\tB$n is somewhat protected from the steam attack by $p!\tn", FALSE, ch, whichitem, 0, TO_ROOM);
GET_HIT(ch) += rand_number(1, 2);
break;
}
}
}
wearslot++;
sub_damage = FALSE;
add_damage = FALSE;
} while (wearslot <= NUM_WEARS);
return (0);
break; // End of case DAMAGE_ALL code.
/* So what do we need to know? The following:
Is it a weapon or piece of armor? If a weapon, dual wielded or not?
What's the location being damage, if armor?
Once we know WHAT is getting damaged, then find the material. We also need to find the material of the opposing item (armor for weapon, weapon for armor) dealing damage.
Then, knowing what kind of attack is dealing the damage, how effective is it against said material?
Damage to item is dealt at the same time.
Once all is said and done, then check to see if durability is 0 or less. Set it to 0 if so, and then
kick it off of the player into inventory. */
case DAMAGE_WEAPON: // First, get material of weapon. Then, determine if armor was hit and that damaged it. Otherwise, normal rate of wear and tear.
wielded = GET_EQ(ch, WEAR_WIELD);
if (wielded != NULL) {
material = GET_OBJ_VAL(GET_EQ(ch, WEAR_WIELD), 0);
act("\tRYour $p\tR has been damaged!\tn", FALSE, ch, wielded, 0, TO_CHAR);
act("\tR$n's $p\tR has been damaged!\tn", FALSE, ch, wielded, 0, TO_ROOM);
}
for (attempts = 1; attempts <= 3; attempts ++) {
if ((targ = GET_EQ(ch, rand_number(0, NUM_WEARS))) != NULL) {
attempts = 3; // Got a hit on an item, so loop is no longer needed.
oppmaterial = GET_OBJ_VAL(targ, 1); // Grab the opposing material type
} else oppmaterial = MAT_OTHER;
}
break;
case DAMAGE_DWEAPON:
wielded = GET_EQ(ch, WEAR_DWIELD);
if (wielded != NULL) {
material = GET_OBJ_VAL(GET_EQ(ch, WEAR_DWIELD), 0);
act("\tRYour $p\tR has been damaged!\tn", FALSE, ch, wielded, 0, TO_CHAR);
act("\tR$n's $p\tR has been damaged!\tn", FALSE, ch, wielded, 0, TO_ROOM);
}
for (attempts = 1; attempts <= 3; attempts ++) {
if ((targ = GET_EQ(ch, rand_number(0, NUM_WEARS))) != NULL) {
attempts = 3; // Got a hit on an item, so loop is no longer needed.
oppmaterial = GET_OBJ_VAL(targ, 1); // Grab the opposing material type
} else oppmaterial = MAT_OTHER;
}
break;
case DAMAGE_ARMOR:
for (attempts = 1; attempts <= 3; attempts ++) {
if ((targ = GET_EQ(ch, rand_number(0, NUM_WEARS))) != NULL) {
attempts = 3; // Got a hit on an item, so loop is no longer needed.
material = GET_OBJ_VAL(targ, 1);
act("\tRYour $p\tR has been damaged!\tn", FALSE, ch, targ, 0, TO_CHAR);
act("\tR$n's $p\tR has been damaged!\tn", FALSE, ch, targ, 0, TO_ROOM);
}
}
/* Time to pull up any weapons damager has on hand. If Dwielding, pick at random which weapon is the damager. */
wielded = GET_EQ(damager, WEAR_WIELD);
dwielded = GET_EQ(damager, WEAR_DWIELD);
if ((dwielded != NULL) && (wielded != NULL)) {
if (rand_number(1, 2) == 1)
oppmaterial = GET_OBJ_VAL(wielded, 0);
else
oppmaterial = GET_OBJ_VAL(dwielded, 0);
} else if (wielded != NULL) oppmaterial = GET_OBJ_VAL(wielded, 0);
if (wielded == NULL) oppmaterial = MAT_OTHER;
break;
default:
send_to_char(ch, "Shouldn't see this, notify Admin immediately if possible.\r\n");
break;
}
/* Now we determine the hardness difference of the materials involved.
hardnessdiff = material - oppmaterial;
This is the general idea. */
switch (material) {
case MAT_CLOTH:
hardtarget = 1;
break;
case MAT_LEATHER:
case MAT_HIDE:
hardtarget = 2;
break;
case MAT_WOOD:
hardtarget = 3;
break;
case MAT_COPPER:
hardtarget = 4;
break;
case MAT_BRONZE:
hardtarget = 5;
break;
case MAT_IRON:
hardtarget = 6;
break;
case MAT_STEEL:
hardtarget = 7;
break;
case MAT_ENDURIUM:
hardtarget = 8;
break;
case MAT_MITHRIL:
hardtarget = 9;
break;
case MAT_ADAMANT:
hardtarget = 10;
break;
case MAT_OTHER:
hardtarget = 1;
break;
default:
hardtarget = 1;
break;
}
switch (oppmaterial) {
case MAT_CLOTH:
harddamager = 1;
break;
case MAT_LEATHER:
case MAT_HIDE:
harddamager = 2;
break;
case MAT_WOOD:
harddamager = 3;
break;
case MAT_COPPER:
harddamager = 4;
break;
case MAT_BRONZE:
harddamager = 5;
break;
case MAT_IRON:
harddamager = 6;
break;
case MAT_STEEL:
harddamager = 7;
break;
case MAT_ENDURIUM:
harddamager = 8;
break;
case MAT_MITHRIL:
harddamager = 9;
break;
case MAT_ADAMANT:
harddamager = 10;
break;
case MAT_OTHER:
harddamager = 1;
break;
default:
harddamager = 1;
break;
}
hardnessdiff = hardtarget - harddamager;
/* We have the hardness ratings of each... high is better. The one being damaged wants his hardness to be higher than the attacker's.
Example... Steel vs. Copper, 7 vs 4. Hardnessdiff = -3, so damage dealt to his steel item would be a third less. damage = damage * (-1 * hardnessdiff) if hardnessdiff < 0 */
switch (attack_type) {
case ATT_PHYSICAL: // Normal 1d6 damage to bronze, iron, steel, endurium. 1d8 vs copper, leather, and hide. 1d10 vs cloth and wood.
switch (material) {
case MAT_CLOTH:
case MAT_WOOD:
dicesize = 12;
break;
case MAT_LEATHER:
dicesize = 10;
break;
case MAT_HIDE:
case MAT_COPPER:
dicesize = 8;
break;
case MAT_BRONZE:
case MAT_IRON:
case MAT_STEEL:
case MAT_ENDURIUM:
dicesize = 6;
break;
case MAT_MITHRIL:
dicesize = 4;
break;
case MAT_ADAMANT:
dicesize = 2;
break;
default:
dicesize = 6;
break;
}
break;
default:
dicesize = 6;
break;
}
damage = rand_number(1, dicesize);
if (hardnessdiff > 0)
damage *= hardnessdiff;
else if (hardnessdiff < 0) {
damage = damage / (-1 * hardnessdiff);
if (damage == 0) damage = 1;
}
switch (item_type_damaged) {
case DAMAGE_WEAPON:
if (wielded != NULL) {
GET_OBJ_DURABILITY(wielded) -= damage;
if (GET_OBJ_DURABILITY(wielded) < 0) GET_OBJ_DURABILITY(wielded) = 0;
if (GET_OBJ_DURABILITY(wielded) == 0) {
act("\tRYikes, $p\tR FELL APART!\tn", FALSE, ch, wielded, 0, TO_CHAR);
act("\tR$n's $p\tR FELL APART!\tn", FALSE, ch, wielded, 0, TO_ROOM);
obj_to_char(unequip_char(ch, WEAR_WIELD), ch);
}
}
break;
case DAMAGE_DWEAPON:
if (wielded != NULL) {
GET_OBJ_DURABILITY(wielded) -= damage;
if (GET_OBJ_DURABILITY(wielded) < 0) GET_OBJ_DURABILITY(wielded) = 0;
if (GET_OBJ_DURABILITY(wielded) == 0) {
act("\tRYikes, $p\tR FELL APART!\tn", FALSE, ch, wielded, 0, TO_CHAR);
act("\tR$n's $p\tR FELL APART!\tn", FALSE, ch, wielded, 0, TO_ROOM);
obj_to_char(unequip_char(ch, WEAR_DWIELD), ch);
}
}
break;
case DAMAGE_ARMOR:
if (targ != NULL) {
GET_OBJ_DURABILITY(targ) -= damage;
if (GET_OBJ_DURABILITY(targ) < 0) GET_OBJ_DURABILITY(wielded) = 0;
if (GET_OBJ_DURABILITY(targ) == 0) {
act("\tRYikes, $p\tR FELL APART!\tn", FALSE, ch, targ, 0, TO_CHAR);
act("\tR$n's $p\tR FELL APART!\tn", FALSE, ch, targ, 0, TO_ROOM);
obj_to_char(unequip_char(ch, targ->worn_on), ch);
}
}
break;
default:
send_to_char(ch, "Shouldn't see, please contact Admin immediately.\r\n");
break;
}
return (0);
}
Obviously had to make some minor changes to the declaration of the function (we needed access to the opposing character's char_data), but it all compiles and should work fine. I was going to go even further and make further adjustments based on the attack type versus the type of armor, but found this is as far as I wanted to go in this regard.