Items in your hands can catch fire (#83867)

## About The Pull Request

Recently we allowed items held in your hands to catch fire if you catch
fire.
This makes sense but the code had a few oversights, then we reverted it.

This PR reintroduces the feature, but with a few refinements.
The basic feature is simple: If you are on fire then items you are
holding will also catch fire, in the same vein as items you are wearing
on your head or hands.

There are also a few caveats we forgot about the first time we added
this:

- If your gloves cannot catch fire, your held items will not catch fire
(because your hands aren't on fire).
- If you are extinguished, your held items will also be extinguished.
- Stopping, Dropping, and Rolling on top of any items will also
extinguish those items.

As part of this change, after an argument about whether or not this is
an oversight in coding-general, I've made the proc `get_equipped_items`
take a bitflag instead of a series of booleans as an argument and added
a new one for "include held items", so that we need no longer argue
about whether holding something counts as "equipping" it (in all other
parts of the game than this proc, it does). This is what gives the PR
most of its code footprint, don't be scared.

## Why It's Good For The Game

Items you are holding in your hands _should_ catch fire if everything
else on your person is on fire, and taking an item off of your body to
put it in your hands shouldn't protect it from fire, because those
things don't make intuitive sense.
If we want an item to be able to catch fire when worn, then it should do
so.

This might expose some issues where we were improperly setting the
flammability flags on items, but any weapon which will burn in your
hands now would also have burned if you were wearing it on your belt or
back, so making those issues more visible should be a bonus (we'll also
stop them from burning on your back or belt).

If you see someone holding a piece of paper that you really don't want
them to read you can now set them on fire to stop them from reading it,
whereas previously they would deftly hold the very flammable object out
of reach of their flaming body.

## Changelog

🆑
balance: Items held in your hands can catch fire.
balance: Items you are holding won't catch fire if your hands cannot
catch fire.
balance: When you stop being on fire so will items you are holding.
balance: If you roll around on your burning items they will stop being
on fire.
/🆑
This commit is contained in:
Jacquerel
2024-06-19 12:15:27 +12:00
committed by GitHub
parent 4eb6960951
commit e8157f4dfc
21 changed files with 43 additions and 31 deletions
+5
View File
@@ -106,3 +106,8 @@
/// Flags for sharpness in obj/item
#define SHARP_EDGED (1<<0)
#define SHARP_POINTY (1<<1)
/// Flags for specifically what kind of items to get in get_equipped_items
#define INCLUDE_POCKETS (1<<0)
#define INCLUDE_ACCESSORIES (1<<1)
#define INCLUDE_HELD (1<<2)
+1 -1
View File
@@ -62,7 +62,7 @@
if(HAS_TRAIT_FROM(affected_mob, TRAIT_NO_TRANSFORM, REF(src)))
return
ADD_TRAIT(affected_mob, TRAIT_NO_TRANSFORM, REF(src))
for(var/obj/item/W in affected_mob.get_equipped_items(include_pockets = TRUE))
for(var/obj/item/W in affected_mob.get_equipped_items(INCLUDE_POCKETS))
affected_mob.dropItemToGround(W)
for(var/obj/item/I in affected_mob.held_items)
affected_mob.dropItemToGround(I)
+1 -1
View File
@@ -29,7 +29,7 @@
///We check if the item can be equipped, otherwise we drop it.
/datum/element/skill_reward/proc/drop_if_unworthy(datum/source, mob/living/user)
SIGNAL_HANDLER
if(check_equippable(user) || !(source in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)))
if(check_equippable(user) || !(source in user.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES)))
return NONE
to_chat(user, span_warning("You feel completely and utterly unworthy to even touch \the [source]."))
user.dropItemToGround(source, TRUE)
@@ -24,6 +24,9 @@
// Start with one weaker roll
owner.spin(spintime = actual_interval, speed = actual_interval / 4)
owner.adjust_fire_stacks(-0.25)
for (var/obj/item/dropped in owner.loc)
dropped.extinguish() // Effectively extinguish your items by rolling on them
return TRUE
/datum/status_effect/stop_drop_roll/on_remove()
@@ -247,7 +247,7 @@
owner.clear_mood_event("on_fire")
SEND_SIGNAL(owner, COMSIG_LIVING_EXTINGUISHED, owner)
cache_stacks()
for(var/obj/item/equipped in owner.get_equipped_items())
for(var/obj/item/equipped in (owner.get_equipped_items(INCLUDE_HELD)))
equipped.extinguish()
/datum/status_effect/fire_handler/fire_stacks/on_remove()
+1 -1
View File
@@ -445,7 +445,7 @@
balloon_alert(user, "can't reach!")
return
if((src in user.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE)) && !user.canUnEquip(src))
if((src in user.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES)) && !user.canUnEquip(src))
balloon_alert(user, "it's stuck!")
return
+1 -1
View File
@@ -25,7 +25,7 @@
/datum/admins/proc/equipAntagOnDummy(mob/living/carbon/human/dummy/mannequin, datum/antagonist/antag)
for(var/I in mannequin.get_equipped_items(include_pockets = TRUE))
for(var/I in mannequin.get_equipped_items(INCLUDE_POCKETS))
qdel(I)
if (ispath(antag, /datum/antagonist/ert))
var/datum/antagonist/ert/ert = antag
+2 -1
View File
@@ -209,7 +209,8 @@ ADMIN_VERB_ONLY_CONTEXT_MENU(select_equipment, R_FUN, "Select Equipment", mob/ta
delete_pocket = TRUE
BLACKBOX_LOG_ADMIN_VERB("Select Equipment")
for(var/obj/item/item in human_target.get_equipped_items(include_pockets = delete_pocket))
var/includes_flags = delete_pocket ? INCLUDE_POCKETS : NONE
for(var/obj/item/item in human_target.get_equipped_items(includes_flags))
qdel(item)
var/obj/item/organ/internal/brain/human_brain = human_target.get_organ_slot(BRAIN)
@@ -66,7 +66,7 @@
shoes = /obj/item/clothing/shoes/sneakers/black
/datum/outfit/obsessed/post_equip(mob/living/carbon/human/H)
for(var/obj/item/carried_item in H.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))
for(var/obj/item/carried_item in H.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES))
carried_item.add_mob_blood(H)//Oh yes, there will be blood...
H.regenerate_icons()
+1 -1
View File
@@ -66,7 +66,7 @@
/// Removes all blacklisted items from a mob and returns them to base state
/obj/machinery/quantum_server/proc/reset_equipment(mob/living/carbon/human/person)
for(var/obj/item in person.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))
for(var/obj/item in person.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES))
qdel(item)
var/datum/antagonist/bitrunning_glitch/antag_datum = locate() in person.mind?.antag_datums
+2 -2
View File
@@ -32,11 +32,11 @@
to_chat(c, span_warning("Pick an outfit first."))
return
for (var/item in dollie.get_equipped_items(include_pockets = TRUE))
for (var/item in dollie.get_equipped_items(INCLUDE_POCKETS))
qdel(item)
if(dressuptime != "Naked")
dollie.equipOutfit(dressuptime)
if(LAZYACCESS(modifiers, RIGHT_CLICK))
for (var/item in dollie.get_equipped_items(include_pockets = TRUE))
for (var/item in dollie.get_equipped_items(INCLUDE_POCKETS))
qdel(item)
+1 -1
View File
@@ -185,7 +185,7 @@
l_hand = /obj/item/fireaxe
/datum/outfit/psycho/post_equip(mob/living/carbon/human/H)
for(var/obj/item/carried_item in H.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))
for(var/obj/item/carried_item in H.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES))
carried_item.add_mob_blood(H)//Oh yes, there will be blood...
for(var/obj/item/I in H.held_items)
I.add_mob_blood(H)
+1 -1
View File
@@ -155,7 +155,7 @@
suit = /obj/item/clothing/suit/apron
/datum/outfit/mafia/obsessed/post_equip(mob/living/carbon/human/H)
for(var/obj/item/carried_item in H.get_equipped_items(include_pockets = TRUE, include_accessories = TRUE))
for(var/obj/item/carried_item in H.get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES))
carried_item.add_mob_blood(H)//Oh yes, there will be blood...
H.regenerate_icons()
+11 -12
View File
@@ -388,38 +388,37 @@
* Used to return a list of equipped items on a mob; does not include held items (use get_all_gear)
*
* Argument(s):
* * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list
* * Optional - include_accessories (TRUE/FALSE), whether or not to include the accessories in the returned list
* * Optional - include_flags, (see obj.flags.dm) describes which optional things to include or not (pockets, accessories, held items)
*/
/mob/living/proc/get_equipped_items(include_pockets = FALSE, include_accessories = FALSE)
/mob/living/proc/get_equipped_items(include_flags = NONE)
var/list/items = list()
for(var/obj/item/item_contents in contents)
if(item_contents.item_flags & IN_INVENTORY)
items += item_contents
items -= held_items
if (!(include_flags & INCLUDE_HELD))
items -= held_items
return items
/**
* Used to return a list of equipped items on a human mob; does not include held items (use get_all_gear)
* Used to return a list of equipped items on a human mob; does not by default include held items, see include_flags
*
* Argument(s):
* * Optional - include_pockets (TRUE/FALSE), whether or not to include the pockets and suit storage in the returned list
* * Optional - include_accessories (TRUE/FALSE), whether or not to include the accessories in the returned list
* * Optional - include_flags, (see obj.flags.dm) describes which optional things to include or not (pockets, accessories, held items)
*/
/mob/living/carbon/human/get_equipped_items(include_pockets = FALSE, include_accessories = FALSE)
/mob/living/carbon/human/get_equipped_items(include_flags = NONE)
var/list/items = ..()
if(!include_pockets)
if(!(include_flags & INCLUDE_POCKETS))
items -= list(l_store, r_store, s_store)
if(include_accessories && w_uniform)
if((include_flags & INCLUDE_ACCESSORIES) && w_uniform)
var/obj/item/clothing/under/worn_under = w_uniform
items += worn_under.attached_accessories
return items
/mob/living/proc/unequip_everything()
var/list/items = list()
items |= get_equipped_items(include_pockets = TRUE)
items |= get_equipped_items(INCLUDE_POCKETS)
for(var/I in items)
dropItemToGround(I)
drop_all_held_items()
@@ -558,7 +557,7 @@
//GetAllContents that is reasonable and not stupid
/mob/living/proc/get_all_gear()
var/list/processing_list = get_equipped_items(include_pockets = TRUE, include_accessories = TRUE) + held_items
var/list/processing_list = get_equipped_items(INCLUDE_POCKETS | INCLUDE_ACCESSORIES | INCLUDE_HELD)
list_clear_nulls(processing_list) // handles empty hands
var/i = 0
while(i < length(processing_list))
@@ -403,7 +403,7 @@ GLOBAL_LIST_EMPTY(features_by_species)
replacement.Insert(organ_holder, special=TRUE, movement_flags = DELETE_IF_REPLACED)
/datum/species/proc/worn_items_fit_body_check(mob/living/carbon/wearer)
for(var/obj/item/equipped_item in wearer.get_equipped_items(include_pockets = TRUE))
for(var/obj/item/equipped_item in wearer.get_equipped_items(INCLUDE_POCKETS))
var/equipped_item_slot = wearer.get_slot_by_item(equipped_item)
if(!equipped_item.mob_can_equip(wearer, equipped_item_slot, bypass_equip_delay_self = TRUE, ignore_equipped = TRUE))
wearer.dropItemToGround(equipped_item, force = TRUE)
@@ -41,7 +41,7 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy)
//Instead of just deleting our equipment, we save what we can and reinsert it into SSwardrobe's store
//Hopefully this makes preference reloading not the worst thing ever
/mob/living/carbon/human/dummy/delete_equipment()
var/list/items_to_check = get_equipped_items(include_pockets = TRUE) + held_items
var/list/items_to_check = get_equipped_items(INCLUDE_POCKETS | INCLUDE_HELD)
var/list/to_nuke = list() //List of items queued for deletion, can't qdel them before iterating their contents in case they hold something
///Travel to the bottom of the contents chain, expanding it out
for(var/i = 1; i <= length(items_to_check); i++) //Needs to be a c style loop since it can expand
@@ -93,7 +93,7 @@
return TRUE
var/block_chance_modifier = round(damage / -3)
for(var/obj/item/worn_thing in get_equipped_items(include_pockets = FALSE) + held_items)
for(var/obj/item/worn_thing in get_equipped_items(INCLUDE_HELD))
// Things that are supposed to be worn, being held = cannot block
if(isclothing(worn_thing))
if(worn_thing in held_items)
@@ -796,6 +796,10 @@
if(leg_clothes)
burning_items |= leg_clothes
if (!gloves || (!(gloves.resistance_flags & FIRE_PROOF) && (gloves.resistance_flags & FLAMMABLE)))
for(var/obj/item/burnable_item in held_items)
burning_items |= burnable_item
for(var/obj/item/burning in burning_items)
burning.fire_act((stacks * 25 * seconds_per_tick)) //damage taken is reduced to 2% of this value by fire_act()
@@ -347,7 +347,7 @@
//delete all equipment without dropping anything
/mob/living/carbon/human/proc/delete_equipment()
for(var/slot in get_equipped_items(include_pockets = TRUE))//order matters, dependant slots go first
for(var/slot in get_equipped_items(INCLUDE_POCKETS))//order matters, dependant slots go first
qdel(slot)
for(var/obj/item/held_item in held_items)
qdel(held_item)
+1 -1
View File
@@ -31,7 +31,7 @@
to_chat(src, span_warning("You can't vent crawl while buckled!"))
return
if(iscarbon(src) && required_nudity)
if(length(get_equipped_items(include_pockets = TRUE)) || get_num_held_items())
if(length(get_equipped_items(INCLUDE_POCKETS)) || get_num_held_items())
if(provide_feedback)
to_chat(src, span_warning("You can't crawl around in the ventilation ducts with items!"))
return
+1 -1
View File
@@ -312,7 +312,7 @@
SSblackbox.record_feedback("amount", "gorillas_created", 1)
var/Itemlist = get_equipped_items(include_pockets = TRUE)
var/Itemlist = get_equipped_items(INCLUDE_POCKETS)
Itemlist += held_items
for(var/obj/item/W in Itemlist)
dropItemToGround(W, TRUE)
+1 -1
View File
@@ -49,7 +49,7 @@
for (var/outfit_type in outfits_to_check)
// Only make one human and keep undressing it because it's much faster
for (var/obj/item/I in H.get_equipped_items(include_pockets = TRUE))
for (var/obj/item/I in H.get_equipped_items(INCLUDE_POCKETS))
qdel(I)
var/datum/outfit/outfit = new outfit_type