target items of specified class in mon's inventory for possible destruction return total amount of damage inflicted, though this is unused if mon is the player */
| 5962 | return total amount of damage inflicted, though this is unused if mon is |
| 5963 | the player */ |
| 5964 | int |
| 5965 | destroy_items( |
| 5966 | struct monst *mon, /* monster whose invent is being subjected to |
| 5967 | * destruction */ |
| 5968 | int dmgtyp, /* AD_**** - currently only cold, fire, elec */ |
| 5969 | int dmg_in) /* the amount of HP damage the attack dealt */ |
| 5970 | { |
| 5971 | struct obj *obj; |
| 5972 | int i, defer; |
| 5973 | int limit; /* max amount of item stacks destroyed, based on damage */ |
| 5974 | struct { |
| 5975 | unsigned oid; |
| 5976 | struct obj *otmp; |
| 5977 | boolean deferred; |
| 5978 | } items_to_destroy[MAX_ITEMS_DESTROYED]; |
| 5979 | int elig_stacks = 0; /* number of destroyable objects found so far */ |
| 5980 | boolean u_carry = (mon == &gy.youmonst); |
| 5981 | /* this is a struct obj** because we might destroy the first item in it */ |
| 5982 | struct obj **objchn = u_carry ? &gi.invent : &mon->minvent; |
| 5983 | int dmg_out = 0; /* damage caused by items getting destroyed */ |
| 5984 | xint8 where = NOBJ_STATES; |
| 5985 | |
| 5986 | /* initialize items_to_destroy */ |
| 5987 | for (i = 0; i < MAX_ITEMS_DESTROYED; ++i) { |
| 5988 | /* 0 should not be a valid o_id for anything */ |
| 5989 | items_to_destroy[i].oid = 0; |
| 5990 | items_to_destroy[i].otmp = (struct obj *) 0; |
| 5991 | items_to_destroy[i].deferred = FALSE; |
| 5992 | } |
| 5993 | |
| 5994 | /* don't straight up destroy all items with an equal chance; limit it |
| 5995 | based on the amount of damage being dealt by the source of the item |
| 5996 | destruction */ |
| 5997 | limit = dmg_in / DMG_DESTROY_SCALE; |
| 5998 | if (dmg_in % DMG_DESTROY_SCALE > rn2(DMG_DESTROY_SCALE)) { |
| 5999 | limit++; /* dmg = 9: 20% chance of limit=1, 80% of limit=2, etc */ |
| 6000 | } |
| 6001 | if (limit > MAX_ITEMS_DESTROYED) { |
| 6002 | /* in case of incredibly high damage, prevent from overflowing |
| 6003 | * items_to_destroy */ |
| 6004 | limit = MAX_ITEMS_DESTROYED; |
| 6005 | } |
| 6006 | if (limit < 1) { |
| 6007 | return 0; /* nothing destroyed */ |
| 6008 | } |
| 6009 | |
| 6010 | /* Sometimes destroying an item can change inventory aside from |
| 6011 | * the item itself (cited case was a potion of unholy water; when |
| 6012 | * boiled, potionbreathe() caused hero to transform into were-beast |
| 6013 | * form and that resulted in dropping or destroying some worn armor). |
| 6014 | * |
| 6015 | * Unlike other uses of the object bypass mechanism, destroy_items() |
| 6016 | * can be called multiple times for the same event. So we have to |
| 6017 | * explicitly clear it before each use and hope no other section of |
| 6018 | * code expects it to retain previous value. |
| 6019 | * |
| 6020 | * Destruction of a ring of levitation or form change which pushes |
| 6021 | * off levitation boots could drop hero onto a fire trap that |
no test coverage detected