mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-29 10:31:34 +00:00
## About The Pull Request
Refactors the way we listen for reagent changes. The changes made can be
listed as points
**1. Removes `COMSIG_REAGENTS_PRE_ADD_REAGENT`**
Used to stop new reagents from being added to the holder, its only
application is with the BRPED to stop inserting reagents into
beakers/cells stored inside it.
Rather than using this signal a cleaner solution is to simply remove the
component part's reagent holders' flags which allow us to insert
reagents into it(i.e. `REFILABLE`, `INJECTIBLE`, `DRAINABLE`) and
restore them back when that part is removed thus achieving the same
results.
Thus `add_reagent()` is now slightly faster because it no longer uses
this signal
**2. Removes every other signal used by the reagent holder**
Removes pretty much every other signal used by `holder.dm` which are
`COMSIG_REAGENTS_[NEW_REAGENT, ADD_REAGENT,
DEL_REAGENT, REM_REAGENT, CLEAR_REAGENTS]`
While yes, it is true that all these signals are unique & serve a
specific purpose the problem is no object in code respects their
uniqueness & instead clumps them up all together & hooks them onto one
proc to listen for "reagent changes". You see this code pattern repeated
in so many places
9277364ef6/code/modules/power/power_store.dm (L105)
Not only does this look ugly but it also has a memory overhead (4 to 5
signal slots all performing the same action which is a lot compared to
the solution i implemented below). Bonus is that "none" of the
parameters passed to this proc are used so they go to waste as well.
So after removing a ton of code we need something that can still make
the code function which brings us to point 3
**3. Adds a new signal `COMSIG_REAGENTS_HOLDER_UPDATED` to rule them
all**
So if all objects in game are listening for "reagent
changes"[adding/removing, reagents] then we need to look at the proc
that is always called during these changes & that is none other than
`update_total()` so we let that send out a signal and cause all objects
to hook onto this 1 signal instead of 4 to 5 signals as explained in
point 2
## Why It's Good For The Game
This section isn't necessary but i want us to better appreciate both the
code & performance benifits of this PR.
1. First of all its waaaay less code and signals to worry about. Just
look at the number of lines of code removed compared to added. Nothing
more to say
2. Overhead of `RegisterSignal` compared to `RegisterSignals` is less
for obvious reasons
3. `remove_all` is significantly faster as it no longer calls
`remove_reagent()`[which in turn calls `update_total()` &
`handle_reactions()` per call & uses a for loop so its a nested for loop
of doom] for every reagent it removes, instead it does the work by
itself & calls the above 2 procs just once
4. Usually when a reagent is deleted it calls
`COMSIG_REAGENTS_REM_REAGENT` & `COMSIG_REAGENTS_DEL_REAGENT`. So if you
have a holder with like 3 reagents upon transferring/deleting them you
get a total of 6 signal calls!!. Now it's just 3(when using `trans_to`)
and just 1 when using `remove_all/clear_reagents`. Need i say more no
## Changelog
🆑
fix: hydrophonics circuit component actually sets output level when
reagents are changed in the tray
refactor: refactors how code listens for reagent changes. Report bugs on
github
/🆑
342 lines
12 KiB
Plaintext
342 lines
12 KiB
Plaintext
/* Kitchen tools
|
|
* Contains:
|
|
* Fork
|
|
* Kitchen knives
|
|
* Rolling Pins
|
|
* Plastic Utensils
|
|
*/
|
|
|
|
#define PLASTIC_BREAK_PROBABILITY 25
|
|
|
|
/obj/item/kitchen
|
|
icon = 'icons/obj/service/kitchen.dmi'
|
|
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
|
|
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
|
|
worn_icon_state = "kitchen_tool"
|
|
|
|
/obj/item/kitchen/Initialize(mapload)
|
|
. = ..()
|
|
ADD_TRAIT(src, TRAIT_APC_SHOCKING, INNATE_TRAIT)
|
|
|
|
/obj/item/kitchen/fork
|
|
name = "fork"
|
|
desc = "Pointy."
|
|
icon_state = "fork"
|
|
icon_angle = -90
|
|
force = 4
|
|
w_class = WEIGHT_CLASS_TINY
|
|
throwforce = 0
|
|
throw_speed = 3
|
|
throw_range = 5
|
|
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 0.8)
|
|
obj_flags = CONDUCTS_ELECTRICITY
|
|
attack_verb_continuous = list("attacks", "stabs", "pokes")
|
|
attack_verb_simple = list("attack", "stab", "poke")
|
|
hitsound = 'sound/items/weapons/bladeslice.ogg'
|
|
armor_type = /datum/armor/kitchen_fork
|
|
sharpness = SHARP_POINTY
|
|
var/datum/reagent/forkload //used to eat omelette
|
|
custom_price = PAYCHECK_LOWER
|
|
|
|
/datum/armor/kitchen_fork
|
|
fire = 50
|
|
acid = 30
|
|
|
|
/obj/item/kitchen/fork/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/eyestab)
|
|
|
|
/obj/item/kitchen/fork/suicide_act(mob/living/carbon/user)
|
|
user.visible_message(span_suicide("[user] stabs \the [src] into [user.p_their()] chest! It looks like [user.p_theyre()] trying to take a bite out of [user.p_them()]self!"))
|
|
playsound(src, 'sound/items/eatfood.ogg', 50, TRUE)
|
|
return BRUTELOSS
|
|
|
|
/obj/item/kitchen/fork/attack(mob/living/carbon/M, mob/living/carbon/user)
|
|
if(!istype(M))
|
|
return ..()
|
|
|
|
if(forkload)
|
|
if(M == user)
|
|
M.visible_message(span_notice("[user] eats a delicious forkful of omelette!"))
|
|
M.reagents.add_reagent(forkload.type, 1)
|
|
else
|
|
M.visible_message(span_notice("[user] feeds [M] a delicious forkful of omelette!"))
|
|
M.reagents.add_reagent(forkload.type, 1)
|
|
icon_state = "fork"
|
|
forkload = null
|
|
else
|
|
return ..()
|
|
|
|
/obj/item/kitchen/fork/plastic
|
|
name = "plastic fork"
|
|
desc = "Really takes you back to highschool lunch."
|
|
icon_state = "plastic_fork"
|
|
force = 0
|
|
w_class = WEIGHT_CLASS_TINY
|
|
throwforce = 0
|
|
custom_materials = list(/datum/material/plastic = SMALL_MATERIAL_AMOUNT * 0.8)
|
|
custom_price = PAYCHECK_LOWER * 1
|
|
|
|
/obj/item/kitchen/fork/plastic/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/easily_fragmented, PLASTIC_BREAK_PROBABILITY)
|
|
|
|
/obj/item/knife/kitchen
|
|
name = "kitchen knife"
|
|
desc = "A general purpose Chef's Knife made by SpaceCook Incorporated. Guaranteed to stay sharp for years to come."
|
|
|
|
/obj/item/knife/plastic
|
|
name = "plastic knife"
|
|
icon_state = "plastic_knife"
|
|
inhand_icon_state = "knife"
|
|
desc = "A very safe, barely sharp knife made of plastic. Good for cutting food and not much else."
|
|
force = 0
|
|
w_class = WEIGHT_CLASS_TINY
|
|
throwforce = 0
|
|
throw_range = 5
|
|
custom_materials = list(/datum/material/plastic = SMALL_MATERIAL_AMOUNT)
|
|
attack_verb_continuous = list("prods", "whiffs", "scratches", "pokes")
|
|
attack_verb_simple = list("prod", "whiff", "scratch", "poke")
|
|
sharpness = SHARP_EDGED
|
|
custom_price = PAYCHECK_LOWER * 2
|
|
|
|
/obj/item/knife/plastic/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/easily_fragmented, PLASTIC_BREAK_PROBABILITY)
|
|
|
|
/obj/item/knife/kitchen/silicon
|
|
name = "Kitchen Toolset"
|
|
icon = 'icons/obj/items_cyborg.dmi'
|
|
icon_state = "sili_knife"
|
|
icon_angle = 0
|
|
desc = "A breakthrough in synthetic engineering, this tool is a knife programmed to dull when not used for cooking purposes, and can exchange the blade for a rolling pin"
|
|
force = 0
|
|
throwforce = 0
|
|
sharpness = SHARP_EDGED
|
|
hitsound = 'sound/items/weapons/bladeslice.ogg'
|
|
attack_verb_continuous = list("prods", "whiffs", "scratches", "pokes")
|
|
attack_verb_simple = list("prod", "whiff", "scratch", "poke")
|
|
tool_behaviour = TOOL_KNIFE
|
|
|
|
/obj/item/knife/kitchen/silicon/get_all_tool_behaviours()
|
|
return list(TOOL_ROLLINGPIN, TOOL_KNIFE)
|
|
|
|
/obj/item/knife/kitchen/silicon/examine()
|
|
. = ..()
|
|
. += " It's fitted with a [tool_behaviour] head."
|
|
|
|
/obj/item/knife/kitchen/silicon/attack_self(mob/user)
|
|
playsound(get_turf(user), 'sound/items/tools/change_drill.ogg', 50, TRUE)
|
|
if(tool_behaviour != TOOL_ROLLINGPIN)
|
|
tool_behaviour = TOOL_ROLLINGPIN
|
|
to_chat(user, span_notice("You attach the rolling pin bit to the [src]."))
|
|
icon_state = "sili_rolling_pin"
|
|
force = 8
|
|
sharpness = NONE
|
|
hitsound = SFX_SWING_HIT
|
|
attack_verb_continuous = list("bashes", "batters", "bludgeons", "thrashes", "whacks")
|
|
attack_verb_simple = list("bash", "batter", "bludgeon", "thrash", "whack")
|
|
|
|
else
|
|
tool_behaviour = TOOL_KNIFE
|
|
to_chat(user, span_notice("You attach the knife bit to the [src]."))
|
|
icon_state = "sili_knife"
|
|
force = 0
|
|
sharpness = SHARP_EDGED
|
|
hitsound = 'sound/items/weapons/bladeslice.ogg'
|
|
attack_verb_continuous = list("prods", "whiffs", "scratches", "pokes")
|
|
attack_verb_simple = list("prod", "whiff", "scratch", "poke")
|
|
|
|
/obj/item/kitchen/rollingpin
|
|
name = "rolling pin"
|
|
desc = "Used to knock out the Bartender."
|
|
icon = 'icons/obj/service/kitchen.dmi'
|
|
icon_state = "rolling_pin"
|
|
worn_icon_state = "rolling_pin"
|
|
inhand_icon_state = "rolling_pin"
|
|
icon_angle = -45
|
|
force = 8
|
|
throwforce = 5
|
|
throw_speed = 3
|
|
throw_range = 7
|
|
custom_materials = list(/datum/material/wood = SHEET_MATERIAL_AMOUNT * 1.5)
|
|
resistance_flags = FLAMMABLE
|
|
w_class = WEIGHT_CLASS_NORMAL
|
|
attack_verb_continuous = list("bashes", "batters", "bludgeons", "thrashes", "whacks")
|
|
attack_verb_simple = list("bash", "batter", "bludgeon", "thrash", "whack")
|
|
custom_price = PAYCHECK_CREW * 1.5
|
|
tool_behaviour = TOOL_ROLLINGPIN
|
|
|
|
/obj/item/kitchen/rollingpin/illegal
|
|
name = "metal rolling pin"
|
|
desc = "A heavy metallic rolling pin used to bash in those annoying ingredients."
|
|
icon_state = "metal_rolling_pin"
|
|
inhand_icon_state = "metal_rolling_pin"
|
|
force = 12
|
|
obj_flags = CONDUCTS_ELECTRICITY
|
|
custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 1.5, /datum/material/plastic = SHEET_MATERIAL_AMOUNT * 1.5)
|
|
custom_price = PAYCHECK_CREW * 2
|
|
bare_wound_bonus = 14
|
|
|
|
/obj/item/kitchen/rollingpin/suicide_act(mob/living/carbon/user)
|
|
user.visible_message(span_suicide("[user] begins flattening [user.p_their()] head with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
|
|
return BRUTELOSS
|
|
/* Trays moved to /obj/item/storage/bag */
|
|
|
|
/obj/item/kitchen/spoon
|
|
name = "spoon"
|
|
desc = "Just be careful your food doesn't melt the spoon first."
|
|
icon_state = "spoon"
|
|
base_icon_state = "spoon"
|
|
icon_angle = -90
|
|
w_class = WEIGHT_CLASS_TINY
|
|
obj_flags = CONDUCTS_ELECTRICITY
|
|
force = 2
|
|
throw_speed = 3
|
|
throw_range = 5
|
|
attack_verb_simple = list("whack", "spoon", "tap")
|
|
attack_verb_continuous = list("whacks", "spoons", "taps")
|
|
armor_type = /datum/armor/kitchen_spoon
|
|
custom_materials = list(/datum/material/iron = SMALL_MATERIAL_AMOUNT * 1.2)
|
|
custom_price = PAYCHECK_LOWER * 2
|
|
tool_behaviour = TOOL_MINING
|
|
toolspeed = 25 // Literally 25 times worse than the base pickaxe
|
|
|
|
var/spoon_sip_size = 5
|
|
|
|
/obj/item/kitchen/spoon/Initialize(mapload)
|
|
. = ..()
|
|
create_reagents(5, INJECTABLE|OPENCONTAINER|DUNKABLE)
|
|
register_item_context()
|
|
|
|
/obj/item/kitchen/spoon/create_reagents(max_vol, flags)
|
|
. = ..()
|
|
RegisterSignal(reagents, COMSIG_REAGENTS_HOLDER_UPDATED, PROC_REF(on_reagent_change))
|
|
|
|
/obj/item/kitchen/spoon/proc/on_reagent_change(datum/reagents/reagents)
|
|
SIGNAL_HANDLER
|
|
|
|
update_appearance(UPDATE_OVERLAYS)
|
|
|
|
/obj/item/kitchen/spoon/add_item_context(obj/item/source, list/context, atom/target, mob/living/user)
|
|
if(target.is_open_container())
|
|
context[SCREENTIP_CONTEXT_LMB] = "Empty spoonful"
|
|
context[SCREENTIP_CONTEXT_RMB] = "Grab spoonful"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
if(isliving(target))
|
|
context[SCREENTIP_CONTEXT_LMB] = target == user ? "[spoon_sip_size >= reagents.maximum_volume ? "Swallow" : "Taste"] spoonful" : "Give spoonful"
|
|
return CONTEXTUAL_SCREENTIP_SET
|
|
return NONE
|
|
|
|
/obj/item/kitchen/spoon/update_overlays()
|
|
. = ..()
|
|
if(reagents.total_volume <= 0)
|
|
return
|
|
var/mutable_appearance/filled_overlay = mutable_appearance(icon, "[base_icon_state]_filled")
|
|
filled_overlay.color = mix_color_from_reagents(reagents.reagent_list)
|
|
. += filled_overlay
|
|
|
|
/obj/item/kitchen/spoon/attack(mob/living/target_mob, mob/living/user, params)
|
|
if(!target_mob.reagents || reagents.total_volume <= 0)
|
|
return ..()
|
|
|
|
if(target_mob.is_mouth_covered(ITEM_SLOT_HEAD) || target_mob.is_mouth_covered(ITEM_SLOT_MASK))
|
|
if(target_mob == user)
|
|
target_mob.balloon_alert(user, "can't eat with mouth covered!")
|
|
else
|
|
target_mob.balloon_alert(user, "[target_mob.p_their()] mouth is covered!")
|
|
return TRUE
|
|
|
|
if(target_mob == user)
|
|
user.visible_message(
|
|
span_notice("[user] scoops a spoonful into [user.p_their()] mouth."),
|
|
span_notice("You scoop a spoonful into your mouth.")
|
|
)
|
|
|
|
else
|
|
to_chat(target_mob, span_userdanger("[target_mob.is_blind() ? "Someone" : "[user]"] forces a spoon into your face!"))
|
|
target_mob.balloon_alert(user, "feeding spoonful...")
|
|
if(!do_after(user, 3 SECONDS, target_mob))
|
|
target_mob.balloon_alert(user, "interrupted!")
|
|
return TRUE
|
|
|
|
to_chat(target_mob, span_userdanger("[target_mob.is_blind() ? "You are forced to" : "[user] forces you to"] swallow a spoonful of something!"))
|
|
user.visible_message(
|
|
span_danger("[user] scoops a spoonful into [target_mob]'s mouth."),
|
|
span_notice("You scoop a spoonful into [target_mob]'s mouth.")
|
|
)
|
|
|
|
playsound(target_mob, 'sound/items/drink.ogg', rand(10,50), vary = TRUE)
|
|
reagents.trans_to(target_mob, spoon_sip_size, methods = INGEST)
|
|
return TRUE
|
|
|
|
/obj/item/kitchen/spoon/pre_attack(atom/attacked_atom, mob/living/user, params)
|
|
. = ..()
|
|
if(.)
|
|
return
|
|
if(isliving(attacked_atom))
|
|
return
|
|
if(!attacked_atom.is_open_container())
|
|
return
|
|
if(reagents.total_volume <= 0)
|
|
return
|
|
|
|
var/amount_given = reagents.trans_to(attacked_atom, reagents.maximum_volume)
|
|
if(amount_given >= reagents.total_volume)
|
|
attacked_atom.balloon_alert(user, "spoon emptied")
|
|
else if(amount_given > 0)
|
|
attacked_atom.balloon_alert(user, "spoon partially emptied")
|
|
else
|
|
attacked_atom.balloon_alert(user, "it's full!")
|
|
return TRUE
|
|
|
|
/obj/item/kitchen/spoon/pre_attack_secondary(atom/attacked_atom, mob/living/user, params)
|
|
. = ..()
|
|
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
|
|
return
|
|
if(isliving(attacked_atom))
|
|
return SECONDARY_ATTACK_CALL_NORMAL
|
|
if(!attacked_atom.is_open_container())
|
|
return SECONDARY_ATTACK_CALL_NORMAL
|
|
|
|
if(reagents.total_volume >= reagents.maximum_volume || attacked_atom.reagents.total_volume <= 0)
|
|
return SECONDARY_ATTACK_CALL_NORMAL
|
|
|
|
if(attacked_atom.reagents.trans_to(src, reagents.maximum_volume))
|
|
attacked_atom.balloon_alert(user, "grabbed spoonful")
|
|
else
|
|
attacked_atom.balloon_alert(user, "spoon is full!")
|
|
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
|
|
|
|
/obj/item/kitchen/spoon/plastic
|
|
name = "plastic spoon"
|
|
icon_state = "plastic_spoon"
|
|
force = 0
|
|
custom_materials = list(/datum/material/plastic = SMALL_MATERIAL_AMOUNT * 1.2)
|
|
toolspeed = 75 // The plastic spoon takes 5 minutes to dig through a single mineral turf... It's one, continuous, breakable, do_after...
|
|
custom_price = PAYCHECK_LOWER * 1
|
|
|
|
/datum/armor/kitchen_spoon
|
|
fire = 50
|
|
acid = 30
|
|
|
|
/obj/item/kitchen/spoon/plastic/Initialize(mapload)
|
|
. = ..()
|
|
AddElement(/datum/element/easily_fragmented, PLASTIC_BREAK_PROBABILITY)
|
|
|
|
/obj/item/kitchen/spoon/soup_ladle
|
|
name = "ladle"
|
|
desc = "What is a ladle but a comically large spoon?"
|
|
icon_state = "ladle"
|
|
base_icon_state = "ladle"
|
|
inhand_icon_state = "spoon"
|
|
icon_angle = 90
|
|
custom_price = PAYCHECK_LOWER * 4
|
|
spoon_sip_size = 3 // just a taste
|
|
|
|
/obj/item/kitchen/spoon/soup_ladle/Initialize(mapload)
|
|
. = ..()
|
|
create_reagents(SOUP_SERVING_SIZE + 5, INJECTABLE|OPENCONTAINER)
|
|
|
|
#undef PLASTIC_BREAK_PROBABILITY
|