-
-
- E - Edit, tries to determine the variable type by itself.
- C - Change, asks you for the var type first.
- M - Mass modify: changes this variable for all objects of this type.
-
-
-
-
-
-
- Search:
-
-
-
-
-
-
-
-
-
- [variable_html.Join()]
-
-
-
-
-"}
- src << browse(html, "window=variables[refid];size=475x650")
-
-
-/client/proc/vv_update_display(datum/D, span, content)
- src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")
-
-
-#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
-/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE)
- var/header
- if(DA)
- if (islist(DA))
- var/index = name
- if (value)
- name = DA[name] //name is really the index until this line
- else
- value = DA[name]
- header = "
+
+
+ E - Edit, tries to determine the variable type by itself.
+ C - Change, asks you for the var type first.
+ M - Mass modify: changes this variable for all objects of this type.
+
+
+
+
+
+
+ Search:
+
+
+
+
+
+
+
+
+
+ [variable_html.Join()]
+
+
+
+
+"}
+ src << browse(html, "window=variables[refid];size=475x650")
+
+
+/client/proc/vv_update_display(datum/D, span, content)
+ src << output("[span]:[content]", "variables[REF(D)].browser:replace_span")
+
+
+#define VV_HTML_ENCODE(thing) ( sanitize ? html_encode(thing) : thing )
+/proc/debug_variable(name, value, level, datum/DA = null, sanitize = TRUE)
+ var/header
+ if(DA)
+ if (islist(DA))
+ var/index = name
+ if (value)
+ name = DA[name] //name is really the index until this line
+ else
+ value = DA[name]
+ header = "
+
+
+ "}
+ return output
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/get_reagents_form()
+ var/r_list = get_reagents_list()
+ var/inputs
+ if(r_list)
+ inputs += ""
+ inputs += ""
+ inputs += ""
+ var/output = {"
+ [r_list? "Only the first [synth_speed] selected reagent\s will be added to production" : null]
+ "}
+ return output
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/get_reagents_list()
+ var/output
+ for(var/i=1 to known_reagents.len)
+ var/reagent_id = known_reagents[i]
+ output += {" [known_reagents[reagent_id]] "}
+ return output
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/get_current_reagents()
+ var/output
+ for(var/datum/reagent/R in reagents.reagent_list)
+ if(R.volume > 0)
+ output += "[R]: [round(R.volume,0.001)] - Purge Reagent "
+ if(output)
+ output += "Total: [round(reagents.total_volume,0.001)]/[reagents.maximum_volume] - Purge All"
+ return output || "None"
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/load_syringe(obj/item/reagent_containers/syringe/S)
+ if(syringes.len= 2)
+ occupant_message("The syringe is too far away.")
+ return 0
+ for(var/obj/structure/D in S.loc)//Basic level check for structures in the way (Like grilles and windows)
+ if(!(D.CanPass(S,src.loc)))
+ occupant_message("Unable to load syringe.")
+ return 0
+ for(var/obj/machinery/door/D in S.loc)//Checks for doors
+ if(!(D.CanPass(S,src.loc)))
+ occupant_message("Unable to load syringe.")
+ return 0
+ S.reagents.trans_to(src, S.reagents.total_volume)
+ S.forceMove(src)
+ syringes += S
+ occupant_message("Syringe loaded.")
+ update_equip_info()
+ return 1
+ occupant_message("[src]'s syringe chamber is full.")
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/analyze_reagents(atom/A)
+ if(get_dist(src,A) >= 4)
+ occupant_message("The object is too far away.")
+ return 0
+ if(!A.reagents || ismob(A))
+ occupant_message("No reagent info gained from [A].")
+ return 0
+ occupant_message("Analyzing reagents...")
+ for(var/datum/reagent/R in A.reagents.reagent_list)
+ if(R.can_synth && add_known_reagent(R.type,R.name))
+ occupant_message("Reagent analyzed, identified as [R.name] and added to database.")
+ send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form())
+ occupant_message("Analyzis complete.")
+ return 1
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/proc/add_known_reagent(r_id,r_name)
+ if(!(r_id in known_reagents))
+ known_reagents += r_id
+ known_reagents[r_id] = r_name
+ return 1
+ return 0
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/update_equip_info()
+ if(..())
+ send_byjax(chassis.occupant,"msyringegun.browser","reagents",get_current_reagents())
+ send_byjax(chassis.occupant,"msyringegun.browser","reagents_form",get_reagents_form())
+ return 1
+ return
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/on_reagent_change(changetype)
+ ..()
+ update_equip_info()
+ return
+
+
+/obj/item/mecha_parts/mecha_equipment/medical/syringe_gun/process()
+ if(..())
+ return
+ if(!processed_reagents.len || reagents.total_volume >= reagents.maximum_volume || !chassis.has_charge(energy_drain))
+ occupant_message("Reagent processing stopped.")
+ log_message("Reagent processing stopped.")
+ STOP_PROCESSING(SSobj, src)
+ return
+ var/amount = synth_speed / processed_reagents.len
+ for(var/reagent in processed_reagents)
+ reagents.add_reagent(reagent,amount)
+ chassis.use_power(energy_drain)
+
+///////////////////////////////// Medical Beam ///////////////////////////////////////////////////////////////
+
+/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam
+ name = "exosuit medical beamgun"
+ desc = "Equipment for medical exosuits. Generates a focused beam of medical nanites."
+ icon_state = "mecha_medigun"
+ energy_drain = 10
+ range = MECHA_MELEE|MECHA_RANGED
+ equip_cooldown = 0
+ var/obj/item/gun/medbeam/mech/medigun
+ materials = list(MAT_METAL = 15000, MAT_GLASS = 8000, MAT_PLASMA = 3000, MAT_GOLD = 8000, MAT_DIAMOND = 2000)
+
+/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/Initialize()
+ . = ..()
+ medigun = new(src)
+
+
+/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/Destroy()
+ qdel(medigun)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/process()
+ if(..())
+ return
+ medigun.process()
+
+/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/action(atom/target)
+ medigun.process_fire(target, loc)
+
+
+/obj/item/mecha_parts/mecha_equipment/medical/mechmedbeam/detach()
+ STOP_PROCESSING(SSobj, src)
+ medigun.LoseTarget()
+ return ..()
diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm
index a2222fa2..c89fe14e 100644
--- a/code/game/mecha/equipment/tools/work_tools.dm
+++ b/code/game/mecha/equipment/tools/work_tools.dm
@@ -169,7 +169,7 @@
/obj/item/mecha_parts/mecha_equipment/extinguisher/Initialize()
. = ..()
create_reagents(1000)
- reagents.add_reagent("water", 1000)
+ reagents.add_reagent(/datum/reagent/water, 1000)
/obj/item/mecha_parts/mecha_equipment/extinguisher/action(atom/target) //copypasted from extinguisher. TODO: Rewrite from scratch.
if(!action_checks(target) || get_dist(chassis, target)>3)
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index e07d46dd..a5ed0df2 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -289,10 +289,10 @@
/obj/mecha/proc/mech_toxin_damage(mob/living/target)
playsound(src, 'sound/effects/spray2.ogg', 50, 1)
if(target.reagents)
- if(target.reagents.get_reagent_amount("cryptobiolin") + force < force*2)
- target.reagents.add_reagent("cryptobiolin", force/2)
- if(target.reagents.get_reagent_amount("toxin") + force < force*2)
- target.reagents.add_reagent("toxin", force/2.5)
+ if(target.reagents.get_reagent_amount(/datum/reagent/cryptobiolin) + force < force*2)
+ target.reagents.add_reagent(/datum/reagent/cryptobiolin, force/2)
+ if(target.reagents.get_reagent_amount(/datum/reagent/toxin) + force < force*2)
+ target.reagents.add_reagent(/datum/reagent/toxin, force/2.5)
/obj/mecha/mech_melee_attack(obj/mecha/M)
diff --git a/code/game/objects/effects/decals/cleanable/aliens.dm b/code/game/objects/effects/decals/cleanable/aliens.dm
index 022cc0ba..676581a2 100644
--- a/code/game/objects/effects/decals/cleanable/aliens.dm
+++ b/code/game/objects/effects/decals/cleanable/aliens.dm
@@ -1,71 +1,71 @@
-// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
-
-/obj/effect/decal/cleanable/blood/xeno
- name = "xeno blood"
- desc = "It's green and acidic. It looks like... blood?"
- color = BLOOD_COLOR_XENO
-
-/obj/effect/decal/cleanable/blood/splatter/xeno
- color = BLOOD_COLOR_XENO
-
-/obj/effect/decal/cleanable/blood/gibs/xeno
- color = BLOOD_COLOR_XENO
- gibs_reagent_id = "liquidxenogibs"
- gibs_bloodtype = "X*"
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/Initialize(mapload, list/datum/disease/diseases)
- . = ..()
- update_icon()
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon()
- add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
- cut_overlays()
- var/mutable_appearance/flesh = mutable_appearance(icon, "[icon_state]x_flesh")
- flesh.appearance_flags = RESET_COLOR
- flesh.color = body_colors
- add_overlay(flesh)
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/streak(list/directions)
- set waitfor = FALSE
- var/list/diseases = list()
- SEND_SIGNAL(src, COMSIG_GIBS_STREAK, directions, diseases)
- var/direction = pick(directions)
- for(var/i in 0 to pick(0, 200; 1, 150; 2, 50))
- sleep(2)
- if(i > 0)
- var/obj/effect/decal/cleanable/blood/splatter/xeno/splat = new /obj/effect/decal/cleanable/blood/splatter/xeno(loc, diseases)
- splat.transfer_blood_dna(blood_DNA, diseases)
- if(!step_to(src, get_step(src, direction), 0))
- break
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/up
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/down
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/body
- random_icon_states = list("gibhead", "gibtorso")
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/torso
- random_icon_states = list("gibtorso")
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/limb
- random_icon_states = list("gibleg", "gibarm")
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/core
- random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/larva
- random_icon_states = list("xgiblarva1", "xgiblarva2")
-
-/obj/effect/decal/cleanable/blood/gibs/xeno/larva/body
- random_icon_states = list("xgiblarvahead", "xgiblarvatorso")
-
-/obj/effect/decal/cleanable/blood/xtracks
- icon_state = "tracks"
- random_icon_states = null
-
-/obj/effect/decal/cleanable/blood/xtracks/Initialize()
- add_blood_DNA(list("UNKNOWN DNA" = "X*"))
- . = ..()
+// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
+
+/obj/effect/decal/cleanable/blood/xeno
+ name = "xeno blood"
+ desc = "It's green and acidic. It looks like... blood?"
+ color = BLOOD_COLOR_XENO
+
+/obj/effect/decal/cleanable/blood/splatter/xeno
+ color = BLOOD_COLOR_XENO
+
+/obj/effect/decal/cleanable/blood/gibs/xeno
+ color = BLOOD_COLOR_XENO
+ gibs_reagent_id = /datum/reagent/liquidgibs/xeno
+ gibs_bloodtype = "X*"
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ update_icon()
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/update_icon()
+ add_atom_colour(blood_DNA_to_color(), FIXED_COLOUR_PRIORITY)
+ cut_overlays()
+ var/mutable_appearance/flesh = mutable_appearance(icon, "[icon_state]x_flesh")
+ flesh.appearance_flags = RESET_COLOR
+ flesh.color = body_colors
+ add_overlay(flesh)
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/streak(list/directions)
+ set waitfor = FALSE
+ var/list/diseases = list()
+ SEND_SIGNAL(src, COMSIG_GIBS_STREAK, directions, diseases)
+ var/direction = pick(directions)
+ for(var/i in 0 to pick(0, 200; 1, 150; 2, 50))
+ sleep(2)
+ if(i > 0)
+ var/obj/effect/decal/cleanable/blood/splatter/xeno/splat = new /obj/effect/decal/cleanable/blood/splatter/xeno(loc, diseases)
+ splat.transfer_blood_dna(blood_DNA, diseases)
+ if(!step_to(src, get_step(src, direction), 0))
+ break
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibup1","gibup1","gibup1")
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6","gibdown1","gibdown1","gibdown1")
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/body
+ random_icon_states = list("gibhead", "gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/torso
+ random_icon_states = list("gibtorso")
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/limb
+ random_icon_states = list("gibleg", "gibarm")
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/core
+ random_icon_states = list("gibmid1", "gibmid2", "gibmid3")
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/larva
+ random_icon_states = list("xgiblarva1", "xgiblarva2")
+
+/obj/effect/decal/cleanable/blood/gibs/xeno/larva/body
+ random_icon_states = list("xgiblarvahead", "xgiblarvatorso")
+
+/obj/effect/decal/cleanable/blood/xtracks
+ icon_state = "tracks"
+ random_icon_states = null
+
+/obj/effect/decal/cleanable/blood/xtracks/Initialize()
+ add_blood_DNA(list("UNKNOWN DNA" = "X*"))
+ . = ..()
diff --git a/code/game/objects/effects/decals/cleanable/gibs.dm b/code/game/objects/effects/decals/cleanable/gibs.dm
index 287bbd88..1a235e4d 100644
--- a/code/game/objects/effects/decals/cleanable/gibs.dm
+++ b/code/game/objects/effects/decals/cleanable/gibs.dm
@@ -7,7 +7,7 @@
mergeable_decal = FALSE
bloodiness = 0
var/body_colors = "#e3ba84" //a default color just in case.
- var/gibs_reagent_id = "liquidgibs"
+ var/gibs_reagent_id = /datum/reagent/liquidgibs
var/gibs_bloodtype = "A+"
/obj/effect/decal/cleanable/blood/gibs/Initialize(mapload, list/datum/disease/diseases)
@@ -121,7 +121,6 @@
//Lizards
/obj/effect/decal/cleanable/blood/gibs/human/lizard
body_colors = "117720"
- gibs_reagent_id = "liquidgibs"
gibs_bloodtype = "L"
/obj/effect/decal/cleanable/blood/gibs/human/lizard/Initialize(mapload, list/datum/disease/diseases)
@@ -149,7 +148,7 @@
// Slime Gibs
/obj/effect/decal/cleanable/blood/gibs/slime
desc = "They look gooey and gruesome."
- gibs_reagent_id = "liquidslimegibs"
+ gibs_reagent_id = /datum/reagent/liquidgibs/slime
gibs_bloodtype = "GEL"
/obj/effect/decal/cleanable/blood/gibs/slime/Initialize(mapload, list/datum/disease/diseases)
@@ -188,7 +187,7 @@
/obj/effect/decal/cleanable/blood/gibs/synth
desc = "They look sludgy and disgusting."
- gibs_reagent_id = "liquidsyntheticgibs"
+ gibs_reagent_id = /datum/reagent/liquidgibs/synth
gibs_bloodtype = "SY"
/obj/effect/decal/cleanable/blood/gibs/synth/Initialize(mapload, list/datum/disease/diseases)
@@ -199,7 +198,7 @@
/obj/effect/decal/cleanable/blood/gibs/ipc
desc = "They look sharp yet oozing."
body_colors = "00ff00"
- gibs_reagent_id = "liquidoilgibs"
+ gibs_reagent_id = /datum/reagent/liquidgibs/oil
gibs_bloodtype = "HF"
/obj/effect/decal/cleanable/blood/gibs/ipc/Initialize(mapload, list/datum/disease/diseases)
diff --git a/code/game/objects/effects/decals/cleanable/misc.dm b/code/game/objects/effects/decals/cleanable/misc.dm
index cae889f3..6a257860 100644
--- a/code/game/objects/effects/decals/cleanable/misc.dm
+++ b/code/game/objects/effects/decals/cleanable/misc.dm
@@ -1,257 +1,255 @@
-/obj/effect/decal/cleanable/generic
- name = "clutter"
- desc = "Someone should clean that up."
- icon = 'icons/obj/objects.dmi'
- icon_state = "shards"
-
-/obj/effect/decal/cleanable/ash
- name = "ashes"
- desc = "Ashes to ashes, dust to dust, and into space."
- icon = 'icons/obj/objects.dmi'
- icon_state = "ash"
- mergeable_decal = FALSE
-
-/obj/effect/decal/cleanable/ash/Initialize()
- . = ..()
- reagents.add_reagent("ash", 30)
- pixel_x = rand(-5, 5)
- pixel_y = rand(-5, 5)
-
-/obj/effect/decal/cleanable/ash/crematorium
-//crematoriums need their own ash cause default ash deletes itself if created in an obj
- turf_loc_check = FALSE
-
-/obj/effect/decal/cleanable/ash/large
- name = "large pile of ashes"
- icon_state = "big_ash"
-
-/obj/effect/decal/cleanable/ash/large/Initialize()
- . = ..()
- reagents.add_reagent("ash", 30) //double the amount of ash.
-
-/obj/effect/decal/cleanable/glass
- name = "tiny shards"
- desc = "Back to sand."
- icon = 'icons/obj/shards.dmi'
- icon_state = "tiny"
-
-/obj/effect/decal/cleanable/glass/Initialize()
- . = ..()
- setDir(pick(GLOB.cardinals))
-
-/obj/effect/decal/cleanable/glass/ex_act()
- qdel(src)
-
-/obj/effect/decal/cleanable/dirt
- name = "dirt"
- desc = "Someone should clean that up."
- icon_state = "dirt"
- canSmoothWith = list(/obj/effect/decal/cleanable/dirt, /turf/closed/wall, /obj/structure/falsewall)
- smooth = SMOOTH_FALSE
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
-
-/obj/effect/decal/cleanable/dirt/Initialize()
- . = ..()
- var/turf/T = get_turf(src)
- if(T.tiled_dirt)
- smooth = SMOOTH_MORE
- icon = 'icons/effects/dirt.dmi'
- icon_state = ""
- queue_smooth(src)
- queue_smooth_neighbors(src)
-
-/obj/effect/decal/cleanable/dirt/Destroy()
- queue_smooth_neighbors(src)
- return ..()
-
-/obj/effect/decal/cleanable/flour
- name = "flour"
- desc = "It's still good. Four second rule!"
- icon_state = "flour"
-
-/obj/effect/decal/cleanable/greenglow/ecto
- name = "ectoplasmic puddle"
- desc = "You know who to call."
- light_power = 2
-
-/obj/effect/decal/cleanable/greenglow
- name = "glowing goo"
- desc = "Jeez. I hope that's not for lunch."
- light_color = LIGHT_COLOR_GREEN
- icon_state = "greenglow"
-
-/obj/effect/decal/cleanable/greenglow/Initialize(mapload)
- . = ..()
- set_light(2, 0.8, "#22FFAA")
-
-/obj/effect/decal/cleanable/greenglow/radioactive
- name = "radioactive hazard"
- desc = "You should really clean this up..."
- var/rad_pulse_strength = 5
- var/last_event = 0
- var/active = null
-
-/obj/effect/decal/cleanable/greenglow/radioactive/Crossed(atom/movable/O)
- . = ..()
- if(ismob(O))
- radiate()
-
-/obj/effect/decal/cleanable/greenglow/radioactive/proc/radiate()
- if(!active)
- if(world.time > last_event+15)
- active = 1
- radiation_pulse(src, rad_pulse_strength)
- for(var/obj/effect/decal/cleanable/greenglow/radioactive/T in orange(1,src))
- T.radiate()
- last_event = world.time
- active = 0
- return
-
-/obj/effect/decal/cleanable/greenglow/ex_act()
- return
-
-/obj/effect/decal/cleanable/cobweb
- name = "cobweb"
- desc = "Somebody should remove that."
- gender = NEUTER
- layer = WALL_OBJ_LAYER
- icon_state = "cobweb1"
- resistance_flags = FLAMMABLE
-
-/obj/effect/decal/cleanable/cobweb/cobweb2
- icon_state = "cobweb2"
-
-/obj/effect/decal/cleanable/molten_object
- name = "gooey grey mass"
- desc = "It looks like a melted... something."
- gender = NEUTER
- icon = 'icons/effects/effects.dmi'
- icon_state = "molten"
- mergeable_decal = FALSE
-
-/obj/effect/decal/cleanable/molten_object/large
- name = "big gooey grey mass"
- icon_state = "big_molten"
-
-//Vomit (sorry)
-/obj/effect/decal/cleanable/vomit
- name = "vomit"
- desc = "Gosh, how unpleasant."
- icon = 'icons/effects/blood.dmi'
- icon_state = "vomit_1"
- random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
-
-/obj/effect/decal/cleanable/vomit/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- if(isflyperson(H))
- playsound(get_turf(src), 'sound/items/drink.ogg', 50, 1) //slurp
- H.visible_message("[H] extends a small proboscis into the vomit pool, sucking it with a slurping sound.")
- if(reagents)
- for(var/datum/reagent/R in reagents.reagent_list)
- if (istype(R, /datum/reagent/consumable))
- var/datum/reagent/consumable/nutri_check = R
- if(nutri_check.nutriment_factor >0)
- H.nutrition += nutri_check.nutriment_factor * nutri_check.volume
- reagents.remove_reagent(nutri_check.id,nutri_check.volume)
- reagents.trans_to(H, reagents.total_volume)
- qdel(src)
-
-/obj/effect/decal/cleanable/vomit/old
- name = "crusty dried vomit"
- desc = "You try not to look at the chunks, and fail."
-
-/obj/effect/decal/cleanable/vomit/old/Initialize(mapload, list/datum/disease/diseases)
- . = ..()
- icon_state += "-old"
-
-/obj/effect/decal/cleanable/tomato_smudge
- name = "tomato smudge"
- desc = "It's red."
- gender = NEUTER
- icon = 'icons/effects/tomatodecal.dmi'
- random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
-
-/obj/effect/decal/cleanable/plant_smudge
- name = "plant smudge"
- gender = NEUTER
- icon = 'icons/effects/tomatodecal.dmi'
- random_icon_states = list("smashed_plant")
-
-/obj/effect/decal/cleanable/egg_smudge
- name = "smashed egg"
- desc = "Seems like this one won't hatch."
- gender = NEUTER
- icon = 'icons/effects/tomatodecal.dmi'
- random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3")
-
-/obj/effect/decal/cleanable/pie_smudge //honk
- name = "smashed pie"
- desc = "It's pie cream from a cream pie."
- gender = NEUTER
- icon = 'icons/effects/tomatodecal.dmi'
- random_icon_states = list("smashed_pie")
-
-/obj/effect/decal/cleanable/chem_pile
- name = "chemical pile"
- desc = "A pile of chemicals. You can't quite tell what's inside it."
- gender = NEUTER
- icon = 'icons/obj/objects.dmi'
- icon_state = "ash"
-
-/obj/effect/decal/cleanable/shreds
- name = "shreds"
- desc = "The shredded remains of what appears to be clothing."
- icon_state = "shreds"
- gender = PLURAL
- mergeable_decal = FALSE
-
-/obj/effect/decal/cleanable/shreds/ex_act(severity, target)
- if(severity == 1) //so shreds created during an explosion aren't deleted by the explosion.
- qdel(src)
-
-/obj/effect/decal/cleanable/shreds/Initialize()
- pixel_x = rand(-10, 10)
- pixel_y = rand(-10, 10)
- . = ..()
-
-/obj/effect/decal/cleanable/salt
- name = "salt pile"
- desc = "A sizable pile of table salt. Someone must be upset."
- icon = 'icons/effects/tomatodecal.dmi'
- icon_state = "salt_pile"
- gender = NEUTER
-
-/obj/effect/decal/cleanable/glitter
- name = "generic glitter pile"
- desc = "The herpes of arts and crafts."
- icon = 'icons/effects/atmospherics.dmi'
- gender = NEUTER
-
-/obj/effect/decal/cleanable/glitter/pink
- name = "pink glitter"
- icon_state = "plasma_old"
-
-/obj/effect/decal/cleanable/glitter/white
- name = "white glitter"
- icon_state = "nitrous_oxide_old"
-
-/obj/effect/decal/cleanable/glitter/blue
- name = "blue glitter"
- icon_state = "freon_old"
-
-/obj/effect/decal/cleanable/plasma
- name = "stabilized plasma"
- desc = "A puddle of stabilized plasma."
- icon_state = "flour"
- color = "#9e0089"
-
-/obj/effect/decal/cleanable/insectguts
- name = "insect guts"
- desc = "One bug squashed. Four more will rise in its place."
- icon = 'icons/effects/blood.dmi'
- icon_state = "xfloor1"
- random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
+/obj/effect/decal/cleanable/generic
+ name = "clutter"
+ desc = "Someone should clean that up."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "shards"
+
+/obj/effect/decal/cleanable/ash
+ name = "ashes"
+ desc = "Ashes to ashes, dust to dust, and into space."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "ash"
+ mergeable_decal = FALSE
+
+/obj/effect/decal/cleanable/ash/Initialize()
+ . = ..()
+ reagents.add_reagent(/datum/reagent/ash, 30)
+ pixel_x = rand(-5, 5)
+ pixel_y = rand(-5, 5)
+
+/obj/effect/decal/cleanable/ash/crematorium
+//crematoriums need their own ash cause default ash deletes itself if created in an obj
+ turf_loc_check = FALSE
+
+/obj/effect/decal/cleanable/ash/large
+ name = "large pile of ashes"
+ icon_state = "big_ash"
+
+/obj/effect/decal/cleanable/ash/large/Initialize()
+ . = ..()
+ reagents.add_reagent(/datum/reagent/ash, 30) //double the amount of ash.
+
+/obj/effect/decal/cleanable/glass
+ name = "tiny shards"
+ desc = "Back to sand."
+ icon = 'icons/obj/shards.dmi'
+ icon_state = "tiny"
+
+/obj/effect/decal/cleanable/glass/Initialize()
+ . = ..()
+ setDir(pick(GLOB.cardinals))
+
+/obj/effect/decal/cleanable/glass/ex_act()
+ qdel(src)
+
+/obj/effect/decal/cleanable/dirt
+ name = "dirt"
+ desc = "Someone should clean that up."
+ icon_state = "dirt"
+ canSmoothWith = list(/obj/effect/decal/cleanable/dirt, /turf/closed/wall, /obj/structure/falsewall)
+ smooth = SMOOTH_FALSE
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+
+/obj/effect/decal/cleanable/dirt/Initialize()
+ . = ..()
+ var/turf/T = get_turf(src)
+ if(T.tiled_dirt)
+ smooth = SMOOTH_MORE
+ icon = 'icons/effects/dirt.dmi'
+ icon_state = ""
+ queue_smooth(src)
+ queue_smooth_neighbors(src)
+
+/obj/effect/decal/cleanable/dirt/Destroy()
+ queue_smooth_neighbors(src)
+ return ..()
+
+/obj/effect/decal/cleanable/flour
+ name = "flour"
+ desc = "It's still good. Four second rule!"
+ icon_state = "flour"
+
+/obj/effect/decal/cleanable/greenglow/ecto
+ name = "ectoplasmic puddle"
+ desc = "You know who to call."
+ light_power = 2
+
+/obj/effect/decal/cleanable/greenglow
+ name = "glowing goo"
+ desc = "Jeez. I hope that's not for lunch."
+ light_color = LIGHT_COLOR_GREEN
+ icon_state = "greenglow"
+
+/obj/effect/decal/cleanable/greenglow/Initialize(mapload)
+ . = ..()
+ set_light(2, 0.8, "#22FFAA")
+
+/obj/effect/decal/cleanable/greenglow/radioactive
+ name = "radioactive hazard"
+ desc = "You should really clean this up..."
+ var/rad_pulse_strength = 5
+ var/last_event = 0
+ var/active = null
+
+/obj/effect/decal/cleanable/greenglow/radioactive/Crossed(atom/movable/O)
+ . = ..()
+ if(ismob(O))
+ radiate()
+
+/obj/effect/decal/cleanable/greenglow/radioactive/proc/radiate()
+ if(!active)
+ if(world.time > last_event+15)
+ active = 1
+ radiation_pulse(src, rad_pulse_strength)
+ for(var/obj/effect/decal/cleanable/greenglow/radioactive/T in orange(1,src))
+ T.radiate()
+ last_event = world.time
+ active = 0
+ return
+
+/obj/effect/decal/cleanable/greenglow/ex_act()
+ return
+
+/obj/effect/decal/cleanable/cobweb
+ name = "cobweb"
+ desc = "Somebody should remove that."
+ gender = NEUTER
+ layer = WALL_OBJ_LAYER
+ icon_state = "cobweb1"
+ resistance_flags = FLAMMABLE
+
+/obj/effect/decal/cleanable/cobweb/cobweb2
+ icon_state = "cobweb2"
+
+/obj/effect/decal/cleanable/molten_object
+ name = "gooey grey mass"
+ desc = "It looks like a melted... something."
+ gender = NEUTER
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "molten"
+ mergeable_decal = FALSE
+
+/obj/effect/decal/cleanable/molten_object/large
+ name = "big gooey grey mass"
+ icon_state = "big_molten"
+
+//Vomit (sorry)
+/obj/effect/decal/cleanable/vomit
+ name = "vomit"
+ desc = "Gosh, how unpleasant."
+ icon = 'icons/effects/blood.dmi'
+ icon_state = "vomit_1"
+ random_icon_states = list("vomit_1", "vomit_2", "vomit_3", "vomit_4")
+
+/obj/effect/decal/cleanable/vomit/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(isflyperson(H))
+ playsound(get_turf(src), 'sound/items/drink.ogg', 50, 1) //slurp
+ H.visible_message("[H] extends a small proboscis into the vomit pool, sucking it with a slurping sound.")
+ if(reagents)
+ for(var/datum/reagent/consumable/R in reagents.reagent_list)
+ if(R.nutriment_factor > 0)
+ H.nutrition += R.nutriment_factor * R.volume
+ reagents.del_reagent(R.type)
+ reagents.trans_to(H, reagents.total_volume)
+ qdel(src)
+
+/obj/effect/decal/cleanable/vomit/old
+ name = "crusty dried vomit"
+ desc = "You try not to look at the chunks, and fail."
+
+/obj/effect/decal/cleanable/vomit/old/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ icon_state += "-old"
+
+/obj/effect/decal/cleanable/tomato_smudge
+ name = "tomato smudge"
+ desc = "It's red."
+ gender = NEUTER
+ icon = 'icons/effects/tomatodecal.dmi'
+ random_icon_states = list("tomato_floor1", "tomato_floor2", "tomato_floor3")
+
+/obj/effect/decal/cleanable/plant_smudge
+ name = "plant smudge"
+ gender = NEUTER
+ icon = 'icons/effects/tomatodecal.dmi'
+ random_icon_states = list("smashed_plant")
+
+/obj/effect/decal/cleanable/egg_smudge
+ name = "smashed egg"
+ desc = "Seems like this one won't hatch."
+ gender = NEUTER
+ icon = 'icons/effects/tomatodecal.dmi'
+ random_icon_states = list("smashed_egg1", "smashed_egg2", "smashed_egg3")
+
+/obj/effect/decal/cleanable/pie_smudge //honk
+ name = "smashed pie"
+ desc = "It's pie cream from a cream pie."
+ gender = NEUTER
+ icon = 'icons/effects/tomatodecal.dmi'
+ random_icon_states = list("smashed_pie")
+
+/obj/effect/decal/cleanable/chem_pile
+ name = "chemical pile"
+ desc = "A pile of chemicals. You can't quite tell what's inside it."
+ gender = NEUTER
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "ash"
+
+/obj/effect/decal/cleanable/shreds
+ name = "shreds"
+ desc = "The shredded remains of what appears to be clothing."
+ icon_state = "shreds"
+ gender = PLURAL
+ mergeable_decal = FALSE
+
+/obj/effect/decal/cleanable/shreds/ex_act(severity, target)
+ if(severity == 1) //so shreds created during an explosion aren't deleted by the explosion.
+ qdel(src)
+
+/obj/effect/decal/cleanable/shreds/Initialize()
+ pixel_x = rand(-10, 10)
+ pixel_y = rand(-10, 10)
+ . = ..()
+
+/obj/effect/decal/cleanable/salt
+ name = "salt pile"
+ desc = "A sizable pile of table salt. Someone must be upset."
+ icon = 'icons/effects/tomatodecal.dmi'
+ icon_state = "salt_pile"
+ gender = NEUTER
+
+/obj/effect/decal/cleanable/glitter
+ name = "generic glitter pile"
+ desc = "The herpes of arts and crafts."
+ icon = 'icons/effects/atmospherics.dmi'
+ gender = NEUTER
+
+/obj/effect/decal/cleanable/glitter/pink
+ name = "pink glitter"
+ icon_state = "plasma_old"
+
+/obj/effect/decal/cleanable/glitter/white
+ name = "white glitter"
+ icon_state = "nitrous_oxide_old"
+
+/obj/effect/decal/cleanable/glitter/blue
+ name = "blue glitter"
+ icon_state = "freon_old"
+
+/obj/effect/decal/cleanable/plasma
+ name = "stabilized plasma"
+ desc = "A puddle of stabilized plasma."
+ icon_state = "flour"
+ color = "#9e0089"
+
+/obj/effect/decal/cleanable/insectguts
+ name = "insect guts"
+ desc = "One bug squashed. Four more will rise in its place."
+ icon = 'icons/effects/blood.dmi'
+ icon_state = "xfloor1"
+ random_icon_states = list("xfloor1", "xfloor2", "xfloor3", "xfloor4", "xfloor5", "xfloor6", "xfloor7")
diff --git a/code/game/objects/effects/decals/cleanable/robots.dm b/code/game/objects/effects/decals/cleanable/robots.dm
index cd208d33..3e94abbf 100644
--- a/code/game/objects/effects/decals/cleanable/robots.dm
+++ b/code/game/objects/effects/decals/cleanable/robots.dm
@@ -1,65 +1,65 @@
-// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
-
-/obj/effect/decal/cleanable/robot_debris
- name = "robot debris"
- desc = "It's a useless heap of junk... or is it?"
- icon = 'icons/mob/robots.dmi'
- icon_state = "gib1"
- layer = LOW_OBJ_LAYER
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
- blood_state = BLOOD_STATE_OIL
- bloodiness = BLOOD_AMOUNT_PER_DECAL
- mergeable_decal = FALSE
-
-/obj/effect/decal/cleanable/robot_debris/Initialize(mapload, list/datum/disease/diseases)
- . = ..()
- reagents.add_reagent("liquidoilgibs", 5)
-
-/obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions)
- set waitfor = 0
- var/direction = pick(directions)
- for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
- sleep(2)
- if (i > 0)
- if (prob(40))
- new /obj/effect/decal/cleanable/oil/streak(src.loc)
- else if (prob(10))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- if (!step_to(src, get_step(src, direction), 0))
- break
-
-/obj/effect/decal/cleanable/robot_debris/ex_act()
- return
-
-/obj/effect/decal/cleanable/robot_debris/limb
- random_icon_states = list("gibarm", "gibleg")
-
-/obj/effect/decal/cleanable/robot_debris/up
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibup1","gibup1")
-
-/obj/effect/decal/cleanable/robot_debris/down
- random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1")
-
-/obj/effect/decal/cleanable/oil
- name = "motor oil"
- desc = "It's black and greasy. Looks like Beepsky made another mess."
- icon = 'icons/mob/robots.dmi'
- icon_state = "floor1"
- random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
- blood_state = BLOOD_STATE_OIL
- bloodiness = BLOOD_AMOUNT_PER_DECAL
-
-/obj/effect/decal/cleanable/oil/Initialize()
- . = ..()
- reagents.add_reagent("oil", 30)
- reagents.add_reagent("liquidoilgibs", 5)
-
-/obj/effect/decal/cleanable/oil/streak
- random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
-
-/obj/effect/decal/cleanable/oil/slippery
-
-/obj/effect/decal/cleanable/oil/slippery/Initialize()
- AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))
+// Note: BYOND is object oriented. There is no reason for this to be copy/pasted blood code.
+
+/obj/effect/decal/cleanable/robot_debris
+ name = "robot debris"
+ desc = "It's a useless heap of junk... or is it?"
+ icon = 'icons/mob/robots.dmi'
+ icon_state = "gib1"
+ layer = LOW_OBJ_LAYER
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7")
+ blood_state = BLOOD_STATE_OIL
+ bloodiness = BLOOD_AMOUNT_PER_DECAL
+ mergeable_decal = FALSE
+
+/obj/effect/decal/cleanable/robot_debris/Initialize(mapload, list/datum/disease/diseases)
+ . = ..()
+ reagents.add_reagent(/datum/reagent/liquidgibs, 5)
+
+/obj/effect/decal/cleanable/robot_debris/proc/streak(list/directions)
+ set waitfor = 0
+ var/direction = pick(directions)
+ for (var/i = 0, i < pick(1, 200; 2, 150; 3, 50), i++)
+ sleep(2)
+ if (i > 0)
+ if (prob(40))
+ new /obj/effect/decal/cleanable/oil/streak(src.loc)
+ else if (prob(10))
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ if (!step_to(src, get_step(src, direction), 0))
+ break
+
+/obj/effect/decal/cleanable/robot_debris/ex_act()
+ return
+
+/obj/effect/decal/cleanable/robot_debris/limb
+ random_icon_states = list("gibarm", "gibleg")
+
+/obj/effect/decal/cleanable/robot_debris/up
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibup1","gibup1")
+
+/obj/effect/decal/cleanable/robot_debris/down
+ random_icon_states = list("gib1", "gib2", "gib3", "gib4", "gib5", "gib6", "gib7","gibdown1","gibdown1")
+
+/obj/effect/decal/cleanable/oil
+ name = "motor oil"
+ desc = "It's black and greasy. Looks like Beepsky made another mess."
+ icon = 'icons/mob/robots.dmi'
+ icon_state = "floor1"
+ random_icon_states = list("floor1", "floor2", "floor3", "floor4", "floor5", "floor6", "floor7")
+ blood_state = BLOOD_STATE_OIL
+ bloodiness = BLOOD_AMOUNT_PER_DECAL
+
+/obj/effect/decal/cleanable/oil/Initialize()
+ . = ..()
+ reagents.add_reagent(/datum/reagent/oil, 30)
+ reagents.add_reagent(/datum/reagent/liquidgibs/oil, 5)
+
+/obj/effect/decal/cleanable/oil/streak
+ random_icon_states = list("streak1", "streak2", "streak3", "streak4", "streak5")
+
+/obj/effect/decal/cleanable/oil/slippery
+
+/obj/effect/decal/cleanable/oil/slippery/Initialize()
+ AddComponent(/datum/component/slippery, 80, (NO_SLIP_WHEN_WALKING | SLIDE))
diff --git a/code/game/objects/effects/effect_system/effects_foam.dm b/code/game/objects/effects/effect_system/effects_foam.dm
index 06fa3612..5c809a35 100644
--- a/code/game/objects/effects/effect_system/effects_foam.dm
+++ b/code/game/objects/effects/effect_system/effects_foam.dm
@@ -1,347 +1,347 @@
-// Foam
-// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin.
-#define ALUMINUM_FOAM 1
-#define IRON_FOAM 2
-#define RESIN_FOAM 3
-
-
-/obj/effect/particle_effect/foam
- name = "foam"
- icon_state = "foam"
- opacity = 0
- anchored = TRUE
- density = FALSE
- layer = EDGED_TURF_LAYER
- mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- var/amount = 3
- animate_movement = 0
- var/metal = 0
- var/lifetime = 40
- var/reagent_divisor = 7
- var/static/list/blacklisted_turfs = typecacheof(list(
- /turf/open/space/transit,
- /turf/open/chasm,
- /turf/open/lava))
-
-/obj/effect/particle_effect/foam/firefighting
- name = "firefighting foam"
- lifetime = 20 //doesn't last as long as normal foam
- amount = 0 //no spread
- var/absorbed_plasma = 0
-
-/obj/effect/particle_effect/foam/firefighting/MakeSlippery()
- return
-
-/obj/effect/particle_effect/foam/firefighting/process()
- ..()
-
- var/turf/open/T = get_turf(src)
- var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T)
- if(hotspot && istype(T) && T.air)
- qdel(hotspot)
- var/datum/gas_mixture/G = T.air
- var/plas_amt = min(30,G.gases[/datum/gas/plasma]) //Absorb some plasma
- G.gases[/datum/gas/plasma] -= plas_amt
- absorbed_plasma += plas_amt
- if(G.temperature > T20C)
- G.temperature = max(G.temperature/2,T20C)
- GAS_GARBAGE_COLLECT(G.gases)
- T.air_update_turf()
-
-/obj/effect/particle_effect/foam/firefighting/kill_foam()
- STOP_PROCESSING(SSfastprocess, src)
-
- if(absorbed_plasma)
- var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src))
- if(!P)
- P = new(loc)
- P.reagents.add_reagent("stable_plasma", absorbed_plasma)
-
- flick("[icon_state]-disolve", src)
- QDEL_IN(src, 5)
-
-/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L)
- if(!istype(L))
- return
- L.adjust_fire_stacks(-2)
- L.ExtinguishMob()
-
-/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- return
-
-/obj/effect/particle_effect/foam/metal
- name = "aluminium foam"
- metal = ALUMINUM_FOAM
- icon_state = "mfoam"
-
-/obj/effect/particle_effect/foam/metal/MakeSlippery()
- return
-
-/obj/effect/particle_effect/foam/metal/smart
- name = "smart foam"
-
-/obj/effect/particle_effect/foam/metal/iron
- name = "iron foam"
- metal = IRON_FOAM
-
-/obj/effect/particle_effect/foam/metal/resin
- name = "resin foam"
- metal = RESIN_FOAM
-
-/obj/effect/particle_effect/foam/long_life
- lifetime = 150
-
-/obj/effect/particle_effect/foam/Initialize()
- . = ..()
- MakeSlippery()
- create_reagents(1000) //limited by the size of the reagent holder anyway.
- START_PROCESSING(SSfastprocess, src)
- playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
-
-/obj/effect/particle_effect/foam/proc/MakeSlippery()
- AddComponent(/datum/component/slippery, 100)
-
-/obj/effect/particle_effect/foam/Destroy()
- STOP_PROCESSING(SSfastprocess, src)
- return ..()
-
-
-/obj/effect/particle_effect/foam/proc/kill_foam()
- STOP_PROCESSING(SSfastprocess, src)
- switch(metal)
- if(ALUMINUM_FOAM)
- new /obj/structure/foamedmetal(get_turf(src))
- if(IRON_FOAM)
- new /obj/structure/foamedmetal/iron(get_turf(src))
- if(RESIN_FOAM)
- new /obj/structure/foamedmetal/resin(get_turf(src))
- flick("[icon_state]-disolve", src)
- QDEL_IN(src, 5)
-
-/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls
- STOP_PROCESSING(SSfastprocess, src)
- if(metal)
- var/turf/T = get_turf(src)
- if(isspaceturf(T)) //Block up any exposed space
- T.PlaceOnTop(/turf/open/floor/plating/foam)
- for(var/direction in GLOB.cardinals)
- var/turf/cardinal_turf = get_step(T, direction)
- if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf!
- new/obj/structure/foamedmetal(T)
- break
- flick("[icon_state]-disolve", src)
- QDEL_IN(src, 5)
-
-/obj/effect/particle_effect/foam/process()
- lifetime--
- if(lifetime < 1)
- kill_foam()
- return
-
- var/fraction = 1/initial(reagent_divisor)
- for(var/obj/O in range(0,src))
- if(O.type == src.type)
- continue
- if(isturf(O.loc))
- var/turf/T = O.loc
- if(T.intact && O.level == 1) //hidden under the floor
- continue
- if(lifetime % reagent_divisor)
- reagents.reaction(O, VAPOR, fraction)
- var/hit = 0
- for(var/mob/living/L in range(0,src))
- hit += foam_mob(L)
- if(hit)
- lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate.
- var/T = get_turf(src)
- if(lifetime % reagent_divisor)
- reagents.reaction(T, VAPOR, fraction)
-
- if(--amount < 0)
- return
- spread_foam()
-
-/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L)
- if(lifetime<1)
- return 0
- if(!istype(L))
- return 0
- var/fraction = 1/initial(reagent_divisor)
- if(lifetime % reagent_divisor)
- reagents.reaction(L, VAPOR, fraction)
- lifetime--
- return 1
-
-/obj/effect/particle_effect/foam/proc/spread_foam()
- var/turf/t_loc = get_turf(src)
- for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
- var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam!
- if(foundfoam)
- continue
-
- if(is_type_in_typecache(T, blacklisted_turfs))
- continue
-
- for(var/mob/living/L in T)
- foam_mob(L)
- var/obj/effect/particle_effect/foam/F = new src.type(T)
- F.amount = amount
- reagents.copy_to(F, (reagents.total_volume))
- F.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
- F.metal = metal
-
-
-/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated
- kill_foam()
-
-
-/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
- return
-
-
-///////////////////////////////////////////////
-//FOAM EFFECT DATUM
-/datum/effect_system/foam_spread
- var/amount = 10 // the size of the foam spread.
- var/obj/chemholder
- effect_type = /obj/effect/particle_effect/foam
- var/metal = 0
-
-
-/datum/effect_system/foam_spread/metal
- effect_type = /obj/effect/particle_effect/foam/metal
-
-
-/datum/effect_system/foam_spread/metal/smart
- effect_type = /obj/effect/particle_effect/foam/smart
-
-
-/datum/effect_system/foam_spread/long
- effect_type = /obj/effect/particle_effect/foam/long_life
-
-/datum/effect_system/foam_spread/New()
- ..()
- chemholder = new /obj()
- var/datum/reagents/R = new/datum/reagents(1000)
- chemholder.reagents = R
- R.my_atom = chemholder
-
-/datum/effect_system/foam_spread/Destroy()
- qdel(chemholder)
- chemholder = null
- return ..()
-
-/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null)
- if(isturf(loca))
- location = loca
- else
- location = get_turf(loca)
-
- amount = round(sqrt(amt / 2), 1)
- carry.copy_to(chemholder, carry.total_volume)
-
-/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype)
- ..()
- metal = metaltype
-
-/datum/effect_system/foam_spread/start()
- var/obj/effect/particle_effect/foam/F = new effect_type(location)
- var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
- chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount)
- F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY)
- F.amount = amount
- F.metal = metal
-
-
-//////////////////////////////////////////////////////////
-// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break
-/obj/structure/foamedmetal
- icon = 'icons/effects/effects.dmi'
- icon_state = "metalfoam"
- density = TRUE
- opacity = 1 // changed in New()
- anchored = TRUE
- layer = EDGED_TURF_LAYER
- resistance_flags = FIRE_PROOF | ACID_PROOF
- name = "foamed metal"
- desc = "A lightweight foamed metal wall."
- gender = PLURAL
- max_integrity = 20
- CanAtmosPass = ATMOS_PASS_DENSITY
-
-/obj/structure/foamedmetal/Initialize()
- . = ..()
- air_update_turf(1)
-
-/obj/structure/foamedmetal/Move()
- var/turf/T = loc
- . = ..()
- move_update_air(T)
-
-/obj/structure/foamedmetal/attack_paw(mob/user)
- return attack_hand(user)
-
-/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
- playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
-
-/obj/structure/foamedmetal/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- user.changeNext_move(CLICK_CD_MELEE)
- user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
- to_chat(user, "You hit [src] but bounce off it!")
- playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
-
-/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target)
- return !density
-
-/obj/structure/foamedmetal/iron
- max_integrity = 50
- icon_state = "ironfoam"
-
-//Atmos Backpack Resin, transparent, prevents atmos and filters the air
-/obj/structure/foamedmetal/resin
- name = "\improper ATMOS Resin"
- desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature."
- opacity = FALSE
- icon_state = "atmos_resin"
- alpha = 120
- max_integrity = 10
-
-/obj/structure/foamedmetal/resin/Initialize()
- . = ..()
- if(isopenturf(loc))
- var/turf/open/O = loc
- O.ClearWet()
- if(O.air)
- var/datum/gas_mixture/G = O.air
- G.temperature = 293.15
- for(var/obj/effect/hotspot/H in O)
- qdel(H)
- var/list/G_gases = G.gases
- for(var/I in G_gases)
- if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen)
- continue
- G_gases[I] = 0
- GAS_GARBAGE_COLLECT(G.gases)
- O.air_update_turf()
- for(var/obj/machinery/atmospherics/components/unary/U in O)
- if(!U.welded)
- U.welded = TRUE
- U.update_icon()
- U.visible_message("[U] sealed shut!")
- for(var/mob/living/L in O)
- L.ExtinguishMob()
- for(var/obj/item/Item in O)
- Item.extinguish()
-
-/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target)
- if(istype(mover) && (mover.pass_flags & PASSGLASS))
- return TRUE
- . = ..()
-
-#undef ALUMINUM_FOAM
-#undef IRON_FOAM
-#undef RESIN_FOAM
+// Foam
+// Similar to smoke, but slower and mobs absorb its reagent through their exposed skin.
+#define ALUMINUM_FOAM 1
+#define IRON_FOAM 2
+#define RESIN_FOAM 3
+
+
+/obj/effect/particle_effect/foam
+ name = "foam"
+ icon_state = "foam"
+ opacity = 0
+ anchored = TRUE
+ density = FALSE
+ layer = EDGED_TURF_LAYER
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+ var/amount = 3
+ animate_movement = 0
+ var/metal = 0
+ var/lifetime = 40
+ var/reagent_divisor = 7
+ var/static/list/blacklisted_turfs = typecacheof(list(
+ /turf/open/space/transit,
+ /turf/open/chasm,
+ /turf/open/lava))
+
+/obj/effect/particle_effect/foam/firefighting
+ name = "firefighting foam"
+ lifetime = 20 //doesn't last as long as normal foam
+ amount = 0 //no spread
+ var/absorbed_plasma = 0
+
+/obj/effect/particle_effect/foam/firefighting/MakeSlippery()
+ return
+
+/obj/effect/particle_effect/foam/firefighting/process()
+ ..()
+
+ var/turf/open/T = get_turf(src)
+ var/obj/effect/hotspot/hotspot = (locate(/obj/effect/hotspot) in T)
+ if(hotspot && istype(T) && T.air)
+ qdel(hotspot)
+ var/datum/gas_mixture/G = T.air
+ var/plas_amt = min(30,G.gases[/datum/gas/plasma]) //Absorb some plasma
+ G.gases[/datum/gas/plasma] -= plas_amt
+ absorbed_plasma += plas_amt
+ if(G.temperature > T20C)
+ G.temperature = max(G.temperature/2,T20C)
+ GAS_GARBAGE_COLLECT(G.gases)
+ T.air_update_turf()
+
+/obj/effect/particle_effect/foam/firefighting/kill_foam()
+ STOP_PROCESSING(SSfastprocess, src)
+
+ if(absorbed_plasma)
+ var/obj/effect/decal/cleanable/plasma/P = (locate(/obj/effect/decal/cleanable/plasma) in get_turf(src))
+ if(!P)
+ P = new(loc)
+ P.reagents.add_reagent(/datum/reagent/stable_plasma, absorbed_plasma)
+
+ flick("[icon_state]-disolve", src)
+ QDEL_IN(src, 5)
+
+/obj/effect/particle_effect/foam/firefighting/foam_mob(mob/living/L)
+ if(!istype(L))
+ return
+ L.adjust_fire_stacks(-2)
+ L.ExtinguishMob()
+
+/obj/effect/particle_effect/foam/firefighting/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ return
+
+/obj/effect/particle_effect/foam/metal
+ name = "aluminium foam"
+ metal = ALUMINUM_FOAM
+ icon_state = "mfoam"
+
+/obj/effect/particle_effect/foam/metal/MakeSlippery()
+ return
+
+/obj/effect/particle_effect/foam/metal/smart
+ name = "smart foam"
+
+/obj/effect/particle_effect/foam/metal/iron
+ name = "iron foam"
+ metal = IRON_FOAM
+
+/obj/effect/particle_effect/foam/metal/resin
+ name = "resin foam"
+ metal = RESIN_FOAM
+
+/obj/effect/particle_effect/foam/long_life
+ lifetime = 150
+
+/obj/effect/particle_effect/foam/Initialize()
+ . = ..()
+ MakeSlippery()
+ create_reagents(1000) //limited by the size of the reagent holder anyway.
+ START_PROCESSING(SSfastprocess, src)
+ playsound(src, 'sound/effects/bubbles2.ogg', 80, 1, -3)
+
+/obj/effect/particle_effect/foam/proc/MakeSlippery()
+ AddComponent(/datum/component/slippery, 100)
+
+/obj/effect/particle_effect/foam/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+
+/obj/effect/particle_effect/foam/proc/kill_foam()
+ STOP_PROCESSING(SSfastprocess, src)
+ switch(metal)
+ if(ALUMINUM_FOAM)
+ new /obj/structure/foamedmetal(get_turf(src))
+ if(IRON_FOAM)
+ new /obj/structure/foamedmetal/iron(get_turf(src))
+ if(RESIN_FOAM)
+ new /obj/structure/foamedmetal/resin(get_turf(src))
+ flick("[icon_state]-disolve", src)
+ QDEL_IN(src, 5)
+
+/obj/effect/particle_effect/foam/smart/kill_foam() //Smart foam adheres to area borders for walls
+ STOP_PROCESSING(SSfastprocess, src)
+ if(metal)
+ var/turf/T = get_turf(src)
+ if(isspaceturf(T)) //Block up any exposed space
+ T.PlaceOnTop(/turf/open/floor/plating/foam)
+ for(var/direction in GLOB.cardinals)
+ var/turf/cardinal_turf = get_step(T, direction)
+ if(get_area(cardinal_turf) != get_area(T)) //We're at an area boundary, so let's block off this turf!
+ new/obj/structure/foamedmetal(T)
+ break
+ flick("[icon_state]-disolve", src)
+ QDEL_IN(src, 5)
+
+/obj/effect/particle_effect/foam/process()
+ lifetime--
+ if(lifetime < 1)
+ kill_foam()
+ return
+
+ var/fraction = 1/initial(reagent_divisor)
+ for(var/obj/O in range(0,src))
+ if(O.type == src.type)
+ continue
+ if(isturf(O.loc))
+ var/turf/T = O.loc
+ if(T.intact && O.level == 1) //hidden under the floor
+ continue
+ if(lifetime % reagent_divisor)
+ reagents.reaction(O, VAPOR, fraction)
+ var/hit = 0
+ for(var/mob/living/L in range(0,src))
+ hit += foam_mob(L)
+ if(hit)
+ lifetime++ //this is so the decrease from mobs hit and the natural decrease don't cumulate.
+ var/T = get_turf(src)
+ if(lifetime % reagent_divisor)
+ reagents.reaction(T, VAPOR, fraction)
+
+ if(--amount < 0)
+ return
+ spread_foam()
+
+/obj/effect/particle_effect/foam/proc/foam_mob(mob/living/L)
+ if(lifetime<1)
+ return 0
+ if(!istype(L))
+ return 0
+ var/fraction = 1/initial(reagent_divisor)
+ if(lifetime % reagent_divisor)
+ reagents.reaction(L, VAPOR, fraction)
+ lifetime--
+ return 1
+
+/obj/effect/particle_effect/foam/proc/spread_foam()
+ var/turf/t_loc = get_turf(src)
+ for(var/turf/T in t_loc.GetAtmosAdjacentTurfs())
+ var/obj/effect/particle_effect/foam/foundfoam = locate() in T //Don't spread foam where there's already foam!
+ if(foundfoam)
+ continue
+
+ if(is_type_in_typecache(T, blacklisted_turfs))
+ continue
+
+ for(var/mob/living/L in T)
+ foam_mob(L)
+ var/obj/effect/particle_effect/foam/F = new src.type(T)
+ F.amount = amount
+ reagents.copy_to(F, (reagents.total_volume))
+ F.add_atom_colour(color, FIXED_COLOUR_PRIORITY)
+ F.metal = metal
+
+
+/obj/effect/particle_effect/foam/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ if(prob(max(0, exposed_temperature - 475))) //foam dissolves when heated
+ kill_foam()
+
+
+/obj/effect/particle_effect/foam/metal/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
+ return
+
+
+///////////////////////////////////////////////
+//FOAM EFFECT DATUM
+/datum/effect_system/foam_spread
+ var/amount = 10 // the size of the foam spread.
+ var/obj/chemholder
+ effect_type = /obj/effect/particle_effect/foam
+ var/metal = 0
+
+
+/datum/effect_system/foam_spread/metal
+ effect_type = /obj/effect/particle_effect/foam/metal
+
+
+/datum/effect_system/foam_spread/metal/smart
+ effect_type = /obj/effect/particle_effect/foam/smart
+
+
+/datum/effect_system/foam_spread/long
+ effect_type = /obj/effect/particle_effect/foam/long_life
+
+/datum/effect_system/foam_spread/New()
+ ..()
+ chemholder = new /obj()
+ var/datum/reagents/R = new/datum/reagents(1000)
+ chemholder.reagents = R
+ R.my_atom = chemholder
+
+/datum/effect_system/foam_spread/Destroy()
+ qdel(chemholder)
+ chemholder = null
+ return ..()
+
+/datum/effect_system/foam_spread/set_up(amt=5, loca, datum/reagents/carry = null)
+ if(isturf(loca))
+ location = loca
+ else
+ location = get_turf(loca)
+
+ amount = round(sqrt(amt / 2), 1)
+ carry.copy_to(chemholder, carry.total_volume)
+
+/datum/effect_system/foam_spread/metal/set_up(amt=5, loca, datum/reagents/carry = null, metaltype)
+ ..()
+ metal = metaltype
+
+/datum/effect_system/foam_spread/start()
+ var/obj/effect/particle_effect/foam/F = new effect_type(location)
+ var/foamcolor = mix_color_from_reagents(chemholder.reagents.reagent_list)
+ chemholder.reagents.copy_to(F, chemholder.reagents.total_volume/amount)
+ F.add_atom_colour(foamcolor, FIXED_COLOUR_PRIORITY)
+ F.amount = amount
+ F.metal = metal
+
+
+//////////////////////////////////////////////////////////
+// FOAM STRUCTURE. Formed by metal foams. Dense and opaque, but easy to break
+/obj/structure/foamedmetal
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "metalfoam"
+ density = TRUE
+ opacity = 1 // changed in New()
+ anchored = TRUE
+ layer = EDGED_TURF_LAYER
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ name = "foamed metal"
+ desc = "A lightweight foamed metal wall."
+ gender = PLURAL
+ max_integrity = 20
+ CanAtmosPass = ATMOS_PASS_DENSITY
+
+/obj/structure/foamedmetal/Initialize()
+ . = ..()
+ air_update_turf(1)
+
+/obj/structure/foamedmetal/Move()
+ var/turf/T = loc
+ . = ..()
+ move_update_air(T)
+
+/obj/structure/foamedmetal/attack_paw(mob/user)
+ return attack_hand(user)
+
+/obj/structure/foamedmetal/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
+ playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
+
+/obj/structure/foamedmetal/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ user.changeNext_move(CLICK_CD_MELEE)
+ user.do_attack_animation(src, ATTACK_EFFECT_PUNCH)
+ to_chat(user, "You hit [src] but bounce off it!")
+ playsound(src.loc, 'sound/weapons/tap.ogg', 100, 1)
+
+/obj/structure/foamedmetal/CanPass(atom/movable/mover, turf/target)
+ return !density
+
+/obj/structure/foamedmetal/iron
+ max_integrity = 50
+ icon_state = "ironfoam"
+
+//Atmos Backpack Resin, transparent, prevents atmos and filters the air
+/obj/structure/foamedmetal/resin
+ name = "\improper ATMOS Resin"
+ desc = "A lightweight, transparent resin used to suffocate fires, scrub the air of toxins, and restore the air to a safe temperature."
+ opacity = FALSE
+ icon_state = "atmos_resin"
+ alpha = 120
+ max_integrity = 10
+
+/obj/structure/foamedmetal/resin/Initialize()
+ . = ..()
+ if(isopenturf(loc))
+ var/turf/open/O = loc
+ O.ClearWet()
+ if(O.air)
+ var/datum/gas_mixture/G = O.air
+ G.temperature = 293.15
+ for(var/obj/effect/hotspot/H in O)
+ qdel(H)
+ var/list/G_gases = G.gases
+ for(var/I in G_gases)
+ if(I == /datum/gas/oxygen || I == /datum/gas/nitrogen)
+ continue
+ G_gases[I] = 0
+ GAS_GARBAGE_COLLECT(G.gases)
+ O.air_update_turf()
+ for(var/obj/machinery/atmospherics/components/unary/U in O)
+ if(!U.welded)
+ U.welded = TRUE
+ U.update_icon()
+ U.visible_message("[U] sealed shut!")
+ for(var/mob/living/L in O)
+ L.ExtinguishMob()
+ for(var/obj/item/Item in O)
+ Item.extinguish()
+
+/obj/structure/foamedmetal/resin/CanPass(atom/movable/mover, turf/target)
+ if(istype(mover) && (mover.pass_flags & PASSGLASS))
+ return TRUE
+ . = ..()
+
+#undef ALUMINUM_FOAM
+#undef IRON_FOAM
+#undef RESIN_FOAM
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index 2e1e7e00..8ae6ba9c 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -1,176 +1,176 @@
-/obj/effect/mine
- name = "dummy mine"
- desc = "Better stay away from that thing."
- density = FALSE
- anchored = TRUE
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "uglymine"
- var/triggered = 0
-
-/obj/effect/mine/proc/mineEffect(mob/victim)
- to_chat(victim, "*click*")
-
-/obj/effect/mine/Crossed(AM as mob|obj)
- if(isturf(loc))
- if(ismob(AM))
- var/mob/MM = AM
- if(!(MM.movement_type & FLYING))
- triggermine(AM)
- else
- triggermine(AM)
-
-/obj/effect/mine/proc/triggermine(mob/victim)
- if(triggered)
- return
- visible_message("[victim] sets off [icon2html(src, viewers(src))] [src]!")
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- mineEffect(victim)
- triggered = 1
- qdel(src)
-
-
-/obj/effect/mine/explosive
- name = "explosive mine"
- var/range_devastation = 0
- var/range_heavy = 1
- var/range_light = 2
- var/range_flash = 3
-
-/obj/effect/mine/explosive/mineEffect(mob/victim)
- explosion(loc, range_devastation, range_heavy, range_light, range_flash)
-
-
-/obj/effect/mine/stun
- name = "stun mine"
- var/stun_time = 80
-
-/obj/effect/mine/stun/mineEffect(mob/living/victim)
- if(isliving(victim))
- victim.Knockdown(stun_time)
-
-/obj/effect/mine/kickmine
- name = "kick mine"
-
-/obj/effect/mine/kickmine/mineEffect(mob/victim)
- if(isliving(victim) && victim.client)
- to_chat(victim, "You have been kicked FOR NO REISIN!")
- qdel(victim.client)
-
-
-/obj/effect/mine/gas
- name = "oxygen mine"
- var/gas_amount = 360
- var/gas_type = "o2"
-
-/obj/effect/mine/gas/mineEffect(mob/victim)
- atmos_spawn_air("[gas_type]=[gas_amount]")
-
-
-/obj/effect/mine/gas/plasma
- name = "plasma mine"
- gas_type = "plasma"
-
-
-/obj/effect/mine/gas/n2o
- name = "\improper N2O mine"
- gas_type = "n2o"
-
-
-/obj/effect/mine/sound
- name = "honkblaster 1000"
- var/sound = 'sound/items/bikehorn.ogg'
-
-/obj/effect/mine/sound/mineEffect(mob/victim)
- playsound(loc, sound, 100, 1)
-
-
-/obj/effect/mine/sound/bwoink
- name = "bwoink mine"
- sound = 'sound/effects/adminhelp.ogg'
-
-/obj/effect/mine/pickup
- name = "pickup"
- desc = "pick me up"
- icon = 'icons/effects/effects.dmi'
- icon_state = "electricity2"
- density = FALSE
- var/duration = 0
-
-/obj/effect/mine/pickup/Initialize()
- . = ..()
- animate(src, pixel_y = 4, time = 20, loop = -1)
-
-/obj/effect/mine/pickup/triggermine(mob/victim)
- if(triggered)
- return
- triggered = 1
- invisibility = INVISIBILITY_ABSTRACT
- mineEffect(victim)
- qdel(src)
-
-
-/obj/effect/mine/pickup/bloodbath
- name = "Red Orb"
- desc = "You feel angry just looking at it."
- duration = 1200 //2min
- color = "#FF0000"
-
-/obj/effect/mine/pickup/bloodbath/mineEffect(mob/living/carbon/victim)
- if(!victim.client || !istype(victim))
- return
- to_chat(victim, "RIP AND TEAR")
- var/old_color = victim.client.color
- var/static/list/red_splash = list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0)
- var/static/list/pure_red = list(0,0,0,0,0,0,0,0,0,1,0,0)
-
- spawn(0)
- new /datum/hallucination/delusion(victim, TRUE, "demon",duration,0)
-
- var/obj/item/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc)
- victim.log_message("entered a blood frenzy", LOG_ATTACK)
-
- ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT)
- victim.drop_all_held_items()
- victim.put_in_hands(chainsaw, forced = TRUE)
- chainsaw.attack_self(victim)
- chainsaw.wield(victim)
- victim.reagents.add_reagent("adminordrazine",25)
- to_chat(victim, "KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!")
-
- victim.client.color = pure_red
- animate(victim.client,color = red_splash, time = 10, easing = SINE_EASING|EASE_OUT)
- sleep(10)
- animate(victim.client,color = old_color, time = duration)//, easing = SINE_EASING|EASE_OUT)
- sleep(duration)
- to_chat(victim, "Your bloodlust seeps back into the bog of your subconscious and you regain self control.")
- qdel(chainsaw)
- victim.log_message("exited a blood frenzy", LOG_ATTACK)
- qdel(src)
-
-/obj/effect/mine/pickup/healing
- name = "Blue Orb"
- desc = "You feel better just looking at it."
- color = "#0000FF"
-
-/obj/effect/mine/pickup/healing/mineEffect(mob/living/carbon/victim)
- if(!victim.client || !istype(victim))
- return
- to_chat(victim, "You feel great!")
- victim.revive(full_heal = 1, admin_revive = 1)
-
-/obj/effect/mine/pickup/speed
- name = "Yellow Orb"
- desc = "You feel faster just looking at it."
- color = "#FFFF00"
- duration = 300
-
-/obj/effect/mine/pickup/speed/mineEffect(mob/living/carbon/victim)
- if(!victim.client || !istype(victim))
- return
- to_chat(victim, "You feel fast!")
- ADD_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
- sleep(duration)
- REMOVE_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
- to_chat(victim, "You slow down.")
+/obj/effect/mine
+ name = "dummy mine"
+ desc = "Better stay away from that thing."
+ density = FALSE
+ anchored = TRUE
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "uglymine"
+ var/triggered = 0
+
+/obj/effect/mine/proc/mineEffect(mob/victim)
+ to_chat(victim, "*click*")
+
+/obj/effect/mine/Crossed(AM as mob|obj)
+ if(isturf(loc))
+ if(ismob(AM))
+ var/mob/MM = AM
+ if(!(MM.movement_type & FLYING))
+ triggermine(AM)
+ else
+ triggermine(AM)
+
+/obj/effect/mine/proc/triggermine(mob/victim)
+ if(triggered)
+ return
+ visible_message("[victim] sets off [icon2html(src, viewers(src))] [src]!")
+ var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
+ s.set_up(3, 1, src)
+ s.start()
+ mineEffect(victim)
+ triggered = 1
+ qdel(src)
+
+
+/obj/effect/mine/explosive
+ name = "explosive mine"
+ var/range_devastation = 0
+ var/range_heavy = 1
+ var/range_light = 2
+ var/range_flash = 3
+
+/obj/effect/mine/explosive/mineEffect(mob/victim)
+ explosion(loc, range_devastation, range_heavy, range_light, range_flash)
+
+
+/obj/effect/mine/stun
+ name = "stun mine"
+ var/stun_time = 80
+
+/obj/effect/mine/stun/mineEffect(mob/living/victim)
+ if(isliving(victim))
+ victim.Knockdown(stun_time)
+
+/obj/effect/mine/kickmine
+ name = "kick mine"
+
+/obj/effect/mine/kickmine/mineEffect(mob/victim)
+ if(isliving(victim) && victim.client)
+ to_chat(victim, "You have been kicked FOR NO REISIN!")
+ qdel(victim.client)
+
+
+/obj/effect/mine/gas
+ name = "oxygen mine"
+ var/gas_amount = 360
+ var/gas_type = "o2"
+
+/obj/effect/mine/gas/mineEffect(mob/victim)
+ atmos_spawn_air("[gas_type]=[gas_amount]")
+
+
+/obj/effect/mine/gas/plasma
+ name = "plasma mine"
+ gas_type = "plasma"
+
+
+/obj/effect/mine/gas/n2o
+ name = "\improper N2O mine"
+ gas_type = "n2o"
+
+
+/obj/effect/mine/sound
+ name = "honkblaster 1000"
+ var/sound = 'sound/items/bikehorn.ogg'
+
+/obj/effect/mine/sound/mineEffect(mob/victim)
+ playsound(loc, sound, 100, 1)
+
+
+/obj/effect/mine/sound/bwoink
+ name = "bwoink mine"
+ sound = 'sound/effects/adminhelp.ogg'
+
+/obj/effect/mine/pickup
+ name = "pickup"
+ desc = "pick me up"
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "electricity2"
+ density = FALSE
+ var/duration = 0
+
+/obj/effect/mine/pickup/Initialize()
+ . = ..()
+ animate(src, pixel_y = 4, time = 20, loop = -1)
+
+/obj/effect/mine/pickup/triggermine(mob/victim)
+ if(triggered)
+ return
+ triggered = 1
+ invisibility = INVISIBILITY_ABSTRACT
+ mineEffect(victim)
+ qdel(src)
+
+
+/obj/effect/mine/pickup/bloodbath
+ name = "Red Orb"
+ desc = "You feel angry just looking at it."
+ duration = 1200 //2min
+ color = "#FF0000"
+
+/obj/effect/mine/pickup/bloodbath/mineEffect(mob/living/carbon/victim)
+ if(!victim.client || !istype(victim))
+ return
+ to_chat(victim, "RIP AND TEAR")
+ var/old_color = victim.client.color
+ var/static/list/red_splash = list(1,0,0,0.8,0.2,0, 0.8,0,0.2,0.1,0,0)
+ var/static/list/pure_red = list(0,0,0,0,0,0,0,0,0,1,0,0)
+
+ spawn(0)
+ new /datum/hallucination/delusion(victim, TRUE, "demon",duration,0)
+
+ var/obj/item/twohanded/required/chainsaw/doomslayer/chainsaw = new(victim.loc)
+ victim.log_message("entered a blood frenzy", LOG_ATTACK)
+
+ ADD_TRAIT(chainsaw, TRAIT_NODROP, CHAINSAW_FRENZY_TRAIT)
+ victim.drop_all_held_items()
+ victim.put_in_hands(chainsaw, forced = TRUE)
+ chainsaw.attack_self(victim)
+ chainsaw.wield(victim)
+ victim.reagents.add_reagent(/datum/reagent/medicine/adminordrazine,25)
+ to_chat(victim, "KILL, KILL, KILL! YOU HAVE NO ALLIES ANYMORE, KILL THEM ALL!")
+
+ victim.client.color = pure_red
+ animate(victim.client,color = red_splash, time = 10, easing = SINE_EASING|EASE_OUT)
+ sleep(10)
+ animate(victim.client,color = old_color, time = duration)//, easing = SINE_EASING|EASE_OUT)
+ sleep(duration)
+ to_chat(victim, "Your bloodlust seeps back into the bog of your subconscious and you regain self control.")
+ qdel(chainsaw)
+ victim.log_message("exited a blood frenzy", LOG_ATTACK)
+ qdel(src)
+
+/obj/effect/mine/pickup/healing
+ name = "Blue Orb"
+ desc = "You feel better just looking at it."
+ color = "#0000FF"
+
+/obj/effect/mine/pickup/healing/mineEffect(mob/living/carbon/victim)
+ if(!victim.client || !istype(victim))
+ return
+ to_chat(victim, "You feel great!")
+ victim.revive(full_heal = 1, admin_revive = 1)
+
+/obj/effect/mine/pickup/speed
+ name = "Yellow Orb"
+ desc = "You feel faster just looking at it."
+ color = "#FFFF00"
+ duration = 300
+
+/obj/effect/mine/pickup/speed/mineEffect(mob/living/carbon/victim)
+ if(!victim.client || !istype(victim))
+ return
+ to_chat(victim, "You feel fast!")
+ ADD_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
+ sleep(duration)
+ REMOVE_TRAIT(victim, TRAIT_GOTTAGOREALLYFAST, "yellow_orb")
+ to_chat(victim, "You slow down.")
diff --git a/code/game/objects/items/RSF.dm b/code/game/objects/items/RSF.dm
index b6196b0c..62d6aae7 100644
--- a/code/game/objects/items/RSF.dm
+++ b/code/game/objects/items/RSF.dm
@@ -180,7 +180,7 @@ RSF
to_chat(user, "Fabricating Cookie..")
var/obj/item/reagent_containers/food/snacks/cookie/S = new /obj/item/reagent_containers/food/snacks/cookie(T)
if(toxin)
- S.reagents.add_reagent("chloralhydratedelayed", 10)
+ S.reagents.add_reagent(/datum/reagent/toxin/chloralhydrate, 10)
if (iscyborg(user))
var/mob/living/silicon/robot/R = user
R.cell.charge -= 100
diff --git a/code/game/objects/items/airlock_painter.dm b/code/game/objects/items/airlock_painter.dm
index 1dac4df9..2a91584e 100644
--- a/code/game/objects/items/airlock_painter.dm
+++ b/code/game/objects/items/airlock_painter.dm
@@ -1,126 +1,126 @@
-/obj/item/airlock_painter
- name = "airlock painter"
- desc = "An advanced autopainter preprogrammed with several paintjobs for airlocks. Use it on an airlock during or after construction to change the paintjob."
- icon = 'icons/obj/objects.dmi'
- icon_state = "paint sprayer"
- item_state = "paint sprayer"
-
- w_class = WEIGHT_CLASS_SMALL
-
- materials = list(MAT_METAL=50, MAT_GLASS=50)
-
- flags_1 = CONDUCT_1
- item_flags = NOBLUDGEON
- slot_flags = ITEM_SLOT_BELT
- usesound = 'sound/effects/spray2.ogg'
-
- var/obj/item/toner/ink = null
-
-/obj/item/airlock_painter/Initialize()
- . = ..()
- ink = new /obj/item/toner(src)
-
-//This proc doesn't just check if the painter can be used, but also uses it.
-//Only call this if you are certain that the painter will be used right after this check!
-/obj/item/airlock_painter/proc/use_paint(mob/user)
- if(can_use(user))
- ink.charges--
- playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1)
- return 1
- else
- return 0
-
-//This proc only checks if the painter can be used.
-//Call this if you don't want the painter to be used right after this check, for example
-//because you're expecting user input.
-/obj/item/airlock_painter/proc/can_use(mob/user)
- if(!ink)
- to_chat(user, "There is no toner cartridge installed in [src]!")
- return 0
- else if(ink.charges < 1)
- to_chat(user, "[src] is out of ink!")
- return 0
- else
- return 1
-
-/obj/item/airlock_painter/suicide_act(mob/user)
- var/obj/item/organ/lungs/L = user.getorganslot(ORGAN_SLOT_LUNGS)
-
- if(can_use(user) && L)
- user.visible_message("[user] is inhaling toner from [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- use(user)
-
- // Once you've inhaled the toner, you throw up your lungs
- // and then die.
-
- // Find out if there is an open turf in front of us,
- // and if not, pick the turf we are standing on.
- var/turf/T = get_step(get_turf(src), user.dir)
- if(!isopenturf(T))
- T = get_turf(src)
-
- // they managed to lose their lungs between then and
- // now. Good job.
- if(!L)
- return OXYLOSS
-
- L.Remove(user)
-
- // make some colorful reagent, and apply it to the lungs
- L.create_reagents(10)
- L.reagents.add_reagent("colorful_reagent", 10)
- L.reagents.reaction(L, TOUCH, 1)
-
- // TODO maybe add some colorful vomit?
-
- user.visible_message("[user] vomits out [user.p_their()] [L]!")
- playsound(user.loc, 'sound/effects/splat.ogg', 50, 1)
-
- L.forceMove(T)
-
- return (TOXLOSS|OXYLOSS)
- else if(can_use(user) && !L)
- user.visible_message("[user] is spraying toner on [user.p_them()]self from [src]! It looks like [user.p_theyre()] trying to commit suicide.")
- user.reagents.add_reagent("colorful_reagent", 1)
- user.reagents.reaction(user, TOUCH, 1)
- return TOXLOSS
-
- else
- user.visible_message("[user] is trying to inhale toner from [src]! It might be a suicide attempt if [src] had any toner.")
- return SHAME
-
-
-/obj/item/airlock_painter/examine(mob/user)
- . = ..()
- if(!ink)
- . += "It doesn't have a toner cartridge installed."
- return
- var/ink_level = "high"
- if(ink.charges < 1)
- ink_level = "empty"
- else if((ink.charges/ink.max_charges) <= 0.25) //25%
- ink_level = "low"
- else if((ink.charges/ink.max_charges) > 1) //Over 100% (admin var edit)
- ink_level = "dangerously high"
- . += "Its ink levels look [ink_level]."
-
-/obj/item/airlock_painter/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/toner))
- if(ink)
- to_chat(user, "[src] already contains \a [ink].")
- return
- if(!user.transferItemToLoc(W, src))
- return
- to_chat(user, "You install [W] into [src].")
- ink = W
- playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
- else
- return ..()
-
-/obj/item/airlock_painter/attack_self(mob/user)
- if(ink)
- playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
- ink.forceMove(user.drop_location())
- user.put_in_hands(ink)
- to_chat(user, "You remove [ink] from [src].")
- ink = null
+/obj/item/airlock_painter
+ name = "airlock painter"
+ desc = "An advanced autopainter preprogrammed with several paintjobs for airlocks. Use it on an airlock during or after construction to change the paintjob."
+ icon = 'icons/obj/objects.dmi'
+ icon_state = "paint sprayer"
+ item_state = "paint sprayer"
+
+ w_class = WEIGHT_CLASS_SMALL
+
+ materials = list(MAT_METAL=50, MAT_GLASS=50)
+
+ flags_1 = CONDUCT_1
+ item_flags = NOBLUDGEON
+ slot_flags = ITEM_SLOT_BELT
+ usesound = 'sound/effects/spray2.ogg'
+
+ var/obj/item/toner/ink = null
+
+/obj/item/airlock_painter/Initialize()
+ . = ..()
+ ink = new /obj/item/toner(src)
+
+//This proc doesn't just check if the painter can be used, but also uses it.
+//Only call this if you are certain that the painter will be used right after this check!
+/obj/item/airlock_painter/proc/use_paint(mob/user)
+ if(can_use(user))
+ ink.charges--
+ playsound(src.loc, 'sound/effects/spray2.ogg', 50, 1)
+ return 1
+ else
+ return 0
+
+//This proc only checks if the painter can be used.
+//Call this if you don't want the painter to be used right after this check, for example
+//because you're expecting user input.
+/obj/item/airlock_painter/proc/can_use(mob/user)
+ if(!ink)
+ to_chat(user, "There is no toner cartridge installed in [src]!")
+ return 0
+ else if(ink.charges < 1)
+ to_chat(user, "[src] is out of ink!")
+ return 0
+ else
+ return 1
+
+/obj/item/airlock_painter/suicide_act(mob/user)
+ var/obj/item/organ/lungs/L = user.getorganslot(ORGAN_SLOT_LUNGS)
+
+ if(can_use(user) && L)
+ user.visible_message("[user] is inhaling toner from [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ use(user)
+
+ // Once you've inhaled the toner, you throw up your lungs
+ // and then die.
+
+ // Find out if there is an open turf in front of us,
+ // and if not, pick the turf we are standing on.
+ var/turf/T = get_step(get_turf(src), user.dir)
+ if(!isopenturf(T))
+ T = get_turf(src)
+
+ // they managed to lose their lungs between then and
+ // now. Good job.
+ if(!L)
+ return OXYLOSS
+
+ L.Remove(user)
+
+ // make some colorful reagent, and apply it to the lungs
+ L.create_reagents(10)
+ L.reagents.add_reagent(/datum/reagent/colorful_reagent, 10)
+ L.reagents.reaction(L, TOUCH, 1)
+
+ // TODO maybe add some colorful vomit?
+
+ user.visible_message("[user] vomits out [user.p_their()] [L]!")
+ playsound(user.loc, 'sound/effects/splat.ogg', 50, 1)
+
+ L.forceMove(T)
+
+ return (TOXLOSS|OXYLOSS)
+ else if(can_use(user) && !L)
+ user.visible_message("[user] is spraying toner on [user.p_them()]self from [src]! It looks like [user.p_theyre()] trying to commit suicide.")
+ user.reagents.add_reagent(/datum/reagent/colorful_reagent, 1)
+ user.reagents.reaction(user, TOUCH, 1)
+ return TOXLOSS
+
+ else
+ user.visible_message("[user] is trying to inhale toner from [src]! It might be a suicide attempt if [src] had any toner.")
+ return SHAME
+
+
+/obj/item/airlock_painter/examine(mob/user)
+ . = ..()
+ if(!ink)
+ . += "It doesn't have a toner cartridge installed."
+ return
+ var/ink_level = "high"
+ if(ink.charges < 1)
+ ink_level = "empty"
+ else if((ink.charges/ink.max_charges) <= 0.25) //25%
+ ink_level = "low"
+ else if((ink.charges/ink.max_charges) > 1) //Over 100% (admin var edit)
+ ink_level = "dangerously high"
+ . += "Its ink levels look [ink_level]."
+
+/obj/item/airlock_painter/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/toner))
+ if(ink)
+ to_chat(user, "[src] already contains \a [ink].")
+ return
+ if(!user.transferItemToLoc(W, src))
+ return
+ to_chat(user, "You install [W] into [src].")
+ ink = W
+ playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
+ else
+ return ..()
+
+/obj/item/airlock_painter/attack_self(mob/user)
+ if(ink)
+ playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
+ ink.forceMove(user.drop_location())
+ user.put_in_hands(ink)
+ to_chat(user, "You remove [ink] from [src].")
+ ink = null
diff --git a/code/game/objects/items/apc_frame.dm b/code/game/objects/items/apc_frame.dm
index 25ae1822..c725148d 100644
--- a/code/game/objects/items/apc_frame.dm
+++ b/code/game/objects/items/apc_frame.dm
@@ -120,4 +120,4 @@
flags_1 = CONDUCT_1
w_class = WEIGHT_CLASS_SMALL
materials = list(MAT_METAL=50, MAT_GLASS=50)
- grind_results = list("iron" = 10, "silicon" = 10)
+ grind_results = list(/datum/reagent/iron = 10, /datum/reagent/silicon = 10)
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 6dae3a41..6982bba9 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -1,1068 +1,1068 @@
-//cleansed 9/15/2012 17:48
-
-/*
-CONTAINS:
-MATCHES
-CIGARETTES
-CIGARS
-SMOKING PIPES
-CHEAP LIGHTERS
-ZIPPO
-
-CIGARETTE PACKETS ARE IN FANCY.DM
-*/
-
-///////////
-//MATCHES//
-///////////
-/obj/item/match
- name = "match"
- desc = "A simple match stick, used for lighting fine smokables."
- icon = 'icons/obj/cigarettes.dmi'
- icon_state = "match_unlit"
- var/lit = FALSE
- var/burnt = FALSE
- var/smoketime = 5
- w_class = WEIGHT_CLASS_TINY
- heat = 1000
- grind_results = list("phosphorus" = 2)
-
-/obj/item/match/process()
- smoketime--
- if(smoketime < 1)
- matchburnout()
- else
- open_flame(heat)
-
-/obj/item/match/fire_act(exposed_temperature, exposed_volume)
- matchignite()
-
-/obj/item/match/proc/matchignite()
- if(!lit && !burnt)
- lit = TRUE
- icon_state = "match_lit"
- damtype = "fire"
- force = 3
- hitsound = 'sound/items/welder.ogg'
- item_state = "cigon"
- name = "lit match"
- desc = "A match. This one is lit."
- attack_verb = list("burnt","singed")
- START_PROCESSING(SSobj, src)
- update_icon()
-
-/obj/item/match/proc/matchburnout()
- if(lit)
- lit = FALSE
- burnt = TRUE
- damtype = "brute"
- force = initial(force)
- icon_state = "match_burnt"
- item_state = "cigoff"
- name = "burnt match"
- desc = "A match. This one has seen better days."
- attack_verb = list("flicked")
- STOP_PROCESSING(SSobj, src)
-
-/obj/item/match/dropped(mob/user)
- matchburnout()
- . = ..()
-
-/obj/item/match/attack(mob/living/carbon/M, mob/living/carbon/user)
- if(!isliving(M))
- return
- if(lit && M.IgniteMob())
- message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
- log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
- var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
- if(lit && cig && user.a_intent == INTENT_HELP)
- if(cig.lit)
- to_chat(user, "[cig] is already lit.")
- if(M == user)
- cig.attackby(src, user)
- else
- cig.light("[user] holds [src] out for [M], and lights [cig].")
- else
- ..()
-
-/obj/item/proc/help_light_cig(mob/living/M)
- var/mask_item = M.get_item_by_slot(SLOT_WEAR_MASK)
- if(istype(mask_item, /obj/item/clothing/mask/cigarette))
- return mask_item
-
-/obj/item/match/is_hot()
- return lit * heat
-
-//////////////////
-//FINE SMOKABLES//
-//////////////////
-/obj/item/clothing/mask/cigarette
- name = "cigarette"
- desc = "A roll of tobacco and nicotine."
- icon_state = "cigoff"
- throw_speed = 0.5
- item_state = "cigoff"
- w_class = WEIGHT_CLASS_TINY
- body_parts_covered = null
- grind_results = list()
- var/lit = FALSE
- var/starts_lit = FALSE
- var/icon_on = "cigon" //Note - these are in masks.dmi not in cigarette.dmi
- var/icon_off = "cigoff"
- var/type_butt = /obj/item/cigbutt
- var/lastHolder = null
- var/smoketime = 300
- var/chem_volume = 30
- var/list/list_reagents = list("nicotine" = 15)
- heat = 1000
-
-/obj/item/clothing/mask/cigarette/suicide_act(mob/user)
- user.visible_message("[user] is huffing [src] as quickly as [user.p_they()] can! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer.")
- return (TOXLOSS|OXYLOSS)
-
-/obj/item/clothing/mask/cigarette/Initialize()
- . = ..()
- create_reagents(chem_volume, INJECTABLE | NO_REACT) // so it doesn't react until you light it
- if(list_reagents)
- reagents.add_reagent_list(list_reagents)
- if(starts_lit)
- light()
- AddComponent(/datum/component/knockoff,90,list(BODY_ZONE_PRECISE_MOUTH),list(SLOT_WEAR_MASK))//90% to knock off when wearing a mask
-
-/obj/item/clothing/mask/cigarette/Destroy()
- STOP_PROCESSING(SSobj, src)
- . = ..()
-
-/obj/item/clothing/mask/cigarette/attackby(obj/item/W, mob/user, params)
- if(!lit && smoketime > 0)
- var/lighting_text = W.ignition_effect(src, user)
- if(lighting_text)
- light(lighting_text)
- else
- return ..()
-
-/obj/item/clothing/mask/cigarette/afterattack(obj/item/reagent_containers/glass/glass, mob/user, proximity)
- . = ..()
- if(!proximity || lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
- return
- if(istype(glass)) //you can dip cigarettes into beakers
- if(glass.reagents.trans_to(src, chem_volume)) //if reagents were transfered, show the message
- to_chat(user, "You dip \the [src] into \the [glass].")
- else //if not, either the beaker was empty, or the cigarette was full
- if(!glass.reagents.total_volume)
- to_chat(user, "[glass] is empty.")
- else
- to_chat(user, "[src] is full.")
-
-
-/obj/item/clothing/mask/cigarette/proc/light(flavor_text = null)
- if(lit)
- return
- if(!(flags_1 & INITIALIZED_1))
- icon_state = icon_on
- item_state = icon_on
- return
-
- lit = TRUE
- name = "lit [name]"
- attack_verb = list("burnt", "singed")
- hitsound = 'sound/items/welder.ogg'
- damtype = "fire"
- force = 4
- if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire
- var/datum/effect_system/reagents_explosion/e = new()
- e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0)
- e.start()
- qdel(src)
- return
- if(reagents.get_reagent_amount("welding_fuel")) // the fuel explodes, too, but much less violently
- var/datum/effect_system/reagents_explosion/e = new()
- e.set_up(round(reagents.get_reagent_amount("welding_fuel") / 5, 1), get_turf(src), 0, 0)
- e.start()
- qdel(src)
- return
- // allowing reagents to react after being lit
- DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
- reagents.handle_reactions()
- icon_state = icon_on
- item_state = icon_on
- if(flavor_text)
- var/turf/T = get_turf(src)
- T.visible_message(flavor_text)
- START_PROCESSING(SSobj, src)
-
- //can't think of any other way to update the overlays :<
- if(ismob(loc))
- var/mob/M = loc
- M.update_inv_wear_mask()
- M.update_inv_hands()
-
-
-/obj/item/clothing/mask/cigarette/proc/handle_reagents()
- if(reagents.total_volume)
- if(iscarbon(loc))
- var/mob/living/carbon/C = loc
- if (src == C.wear_mask) // if it's in the human/monkey mouth, transfer reagents to the mob
- var/fraction = min(REAGENTS_METABOLISM/reagents.total_volume, 1)
- reagents.reaction(C, INGEST, fraction)
- if(!reagents.trans_to(C, REAGENTS_METABOLISM))
- reagents.remove_any(REAGENTS_METABOLISM)
- return
- reagents.remove_any(REAGENTS_METABOLISM)
-
-
-/obj/item/clothing/mask/cigarette/process()
- var/turf/location = get_turf(src)
- var/mob/living/M = loc
- if(isliving(loc))
- M.IgniteMob()
- smoketime--
- if(smoketime < 1)
- new type_butt(location)
- if(ismob(loc))
- to_chat(M, "Your [name] goes out.")
- qdel(src)
- return
- open_flame()
- if(reagents && reagents.total_volume)
- handle_reagents()
-
-/obj/item/clothing/mask/cigarette/attack_self(mob/user)
- if(lit)
- user.visible_message("[user] calmly drops and treads on \the [src], putting it out instantly.")
- new type_butt(user.loc)
- new /obj/effect/decal/cleanable/ash(user.loc)
- qdel(src)
- . = ..()
-
-/obj/item/clothing/mask/cigarette/attack(mob/living/carbon/M, mob/living/carbon/user)
- if(!istype(M))
- return ..()
- if(M.on_fire && !lit)
- light("[user] lights [src] with [M]'s burning body. What a cold-blooded badass.")
- return
- var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
- if(lit && cig && user.a_intent == INTENT_HELP)
- if(cig.lit)
- to_chat(user, "The [cig.name] is already lit.")
- if(M == user)
- cig.attackby(src, user)
- else
- cig.light("[user] holds the [name] out for [M], and lights [M.p_their()] [cig.name].")
- else
- return ..()
-
-/obj/item/clothing/mask/cigarette/fire_act(exposed_temperature, exposed_volume)
- light()
-
-/obj/item/clothing/mask/cigarette/is_hot()
- return lit * heat
-
-// Cigarette brands.
-
-/obj/item/clothing/mask/cigarette/space_cigarette
- desc = "A Space Cigarette brand cigarette."
-
-/obj/item/clothing/mask/cigarette/dromedary
- desc = "A DromedaryCo brand cigarette."
- list_reagents = list("nicotine" = 7.5, "silicon" = 7.5)
-
-/obj/item/clothing/mask/cigarette/smokekins
- desc = "A Kinaris Corp brand cigarette"
- list_reagents = list("nicotine" = 7.5, "gold" = 1)
-
-/obj/item/clothing/mask/cigarette/uplift
- desc = "An Uplift Smooth brand cigarette."
- list_reagents = list("nicotine" = 7.5, "menthol" = 7.5)
-
-/obj/item/clothing/mask/cigarette/robust
- desc = "A Robust brand cigarette."
- list_reagents = list("nicotine" = 7.5, "grenadine" = 7.5)
-
-/obj/item/clothing/mask/cigarette/robustgold
- desc = "A Robust Gold brand cigarette."
- list_reagents = list("nicotine" = 15, "gold" = 1)
-
-/obj/item/clothing/mask/cigarette/carp
- desc = "A Carp Classic brand cigarette."
- list_reagents = list("nicotine" = 7.5, "sodiumchloride" = 7.5)
-
-/obj/item/clothing/mask/cigarette/syndicate
- desc = "An unknown brand cigarette."
- list_reagents = list("nicotine" = 15, "omnizine" = 15)
-
-/obj/item/clothing/mask/cigarette/shadyjims
- desc = "A Shady Jim's Super Slims cigarette."
- list_reagents = list("nicotine" = 15, "lipolicide" = 4, "ammonia" = 2, "plantbgone" = 1, "toxin" = 1.5)
-
-/obj/item/clothing/mask/cigarette/xeno
- desc = "A Xeno Filtered brand cigarette."
- list_reagents = list ("nicotine" = 20, "regen_jelly" = 15, "krokodil" = 4)
-
-// Rollies.
-
-/obj/item/clothing/mask/cigarette/rollie
- name = "rollie"
- desc = "A roll of dried plant matter wrapped in thin paper."
- icon_state = "spliffoff"
- icon_on = "spliffon"
- icon_off = "spliffoff"
- type_butt = /obj/item/cigbutt/roach
- throw_speed = 0.5
- item_state = "spliffoff"
- smoketime = 180
- chem_volume = 50
- list_reagents = null
-
-/obj/item/clothing/mask/cigarette/rollie/New()
- ..()
- src.pixel_x = rand(-5, 5)
- src.pixel_y = rand(-5, 5)
-
-/obj/item/clothing/mask/cigarette/rollie/nicotine
- list_reagents = list("nicotine" = 15)
-
-/obj/item/clothing/mask/cigarette/rollie/trippy
- list_reagents = list("nicotine" = 15, "mushroomhallucinogen" = 35)
- starts_lit = TRUE
-
-/obj/item/clothing/mask/cigarette/rollie/cannabis
- list_reagents = list("space_drugs" = 15, "lipolicide" = 35)
-
-/obj/item/clothing/mask/cigarette/rollie/mindbreaker
- list_reagents = list("mindbreaker" = 35, "lipolicide" = 15)
-
-/obj/item/cigbutt/roach
- name = "roach"
- desc = "A manky old roach, or for non-stoners, a used rollup."
- icon_state = "roach"
-
-/obj/item/cigbutt/roach/New()
- ..()
- src.pixel_x = rand(-5, 5)
- src.pixel_y = rand(-5, 5)
-
-
-////////////
-// CIGARS //
-////////////
-/obj/item/clothing/mask/cigarette/cigar
- name = "premium cigar"
- desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!"
- icon_state = "cigaroff"
- icon_on = "cigaron"
- icon_off = "cigaroff" //make sure to add positional sprites in icons/obj/cigarettes.dmi if you add more.
- type_butt = /obj/item/cigbutt/cigarbutt
- throw_speed = 0.5
- item_state = "cigaroff"
- smoketime = 1500
- chem_volume = 40
-
-/obj/item/clothing/mask/cigarette/cigar/cohiba
- name = "\improper Cohiba Robusto cigar"
- desc = "There's little more you could want from a cigar."
- icon_state = "cigar2off"
- icon_on = "cigar2on"
- icon_off = "cigar2off"
- smoketime = 2000
- chem_volume = 80
-
-
-/obj/item/clothing/mask/cigarette/cigar/havana
- name = "premium Havanian cigar"
- desc = "A cigar fit for only the best of the best."
- icon_state = "cigar2off"
- icon_on = "cigar2on"
- icon_off = "cigar2off"
- smoketime = 7200
- chem_volume = 50
-
-/obj/item/cigbutt
- name = "cigarette butt"
- desc = "A manky old cigarette butt."
- icon = 'icons/obj/clothing/masks.dmi'
- icon_state = "cigbutt"
- w_class = WEIGHT_CLASS_TINY
- throwforce = 0
- grind_results = list("carbon" = 2)
-
-/obj/item/cigbutt/cigarbutt
- name = "cigar butt"
- desc = "A manky old cigar butt."
- icon_state = "cigarbutt"
-
-/////////////////
-//SMOKING PIPES//
-/////////////////
-/obj/item/clothing/mask/cigarette/pipe
- name = "smoking pipe"
- desc = "A pipe, for smoking. Probably made of meerschaum or something."
- icon_state = "pipeoff"
- item_state = "pipeoff"
- icon_on = "pipeon" //Note - these are in masks.dmi
- icon_off = "pipeoff"
- smoketime = 0
- chem_volume = 100
- list_reagents = null
- var/packeditem = 0
-
-/obj/item/clothing/mask/cigarette/pipe/Initialize()
- . = ..()
- name = "empty [initial(name)]"
-
-/obj/item/clothing/mask/cigarette/pipe/Destroy()
- STOP_PROCESSING(SSobj, src)
- . = ..()
-
-/obj/item/clothing/mask/cigarette/pipe/process()
- var/turf/location = get_turf(src)
- smoketime--
- if(smoketime < 1)
- new /obj/effect/decal/cleanable/ash(location)
- if(ismob(loc))
- var/mob/living/M = loc
- to_chat(M, "Your [name] goes out.")
- lit = 0
- icon_state = icon_off
- item_state = icon_off
- M.update_inv_wear_mask()
- packeditem = 0
- name = "empty [initial(name)]"
- STOP_PROCESSING(SSobj, src)
- return
- open_flame()
- if(reagents && reagents.total_volume) // check if it has any reagents at all
- handle_reagents()
-
-
-/obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/O, mob/user, params)
- if(istype(O, /obj/item/reagent_containers/food/snacks/grown))
- var/obj/item/reagent_containers/food/snacks/grown/G = O
- if(!packeditem)
- if(G.dry == 1)
- to_chat(user, "You stuff [O] into [src].")
- smoketime = 400
- packeditem = 1
- name = "[O.name]-packed [initial(name)]"
- if(O.reagents)
- O.reagents.trans_to(src, O.reagents.total_volume)
- qdel(O)
- else
- to_chat(user, "It has to be dried first!")
- else
- to_chat(user, "It is already packed!")
- else
- var/lighting_text = O.ignition_effect(src,user)
- if(lighting_text)
- if(smoketime > 0)
- light(lighting_text)
- else
- to_chat(user, "There is nothing to smoke!")
- else
- return ..()
-
-/obj/item/clothing/mask/cigarette/pipe/attack_self(mob/user)
- var/turf/location = get_turf(user)
- if(lit)
- user.visible_message("[user] puts out [src].", "You put out [src].")
- lit = 0
- icon_state = icon_off
- item_state = icon_off
- STOP_PROCESSING(SSobj, src)
- return
- if(!lit && smoketime > 0)
- to_chat(user, "You empty [src] onto [location].")
- new /obj/effect/decal/cleanable/ash(location)
- packeditem = 0
- smoketime = 0
- reagents.clear_reagents()
- name = "empty [initial(name)]"
- return
-
-/obj/item/clothing/mask/cigarette/pipe/cobpipe
- name = "corn cob pipe"
- desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects."
- icon_state = "cobpipeoff"
- item_state = "cobpipeoff"
- icon_on = "cobpipeon" //Note - these are in masks.dmi
- icon_off = "cobpipeoff"
- smoketime = 0
-
-
-/////////
-//ZIPPO//
-/////////
-/obj/item/lighter
- name = "\improper Zippo lighter"
- desc = "The zippo."
- icon = 'icons/obj/cigarettes.dmi'
- icon_state = "zippo"
- item_state = "zippo"
- w_class = WEIGHT_CLASS_TINY
- flags_1 = CONDUCT_1
- slot_flags = ITEM_SLOT_BELT
- var/lit = 0
- var/fancy = TRUE
- var/overlay_state
- var/overlay_list = list(
- "plain",
- "dame",
- "thirteen",
- "snake"
- )
- heat = 1500
- resistance_flags = FIRE_PROOF
- light_color = LIGHT_COLOR_FIRE
- grind_results = list("iron" = 1, "welding_fuel" = 5, "oil" = 5)
-
-/obj/item/lighter/Initialize()
- . = ..()
- if(!overlay_state)
- overlay_state = pick(overlay_list)
- update_icon()
-
-/obj/item/lighter/suicide_act(mob/living/carbon/user)
- if (lit)
- user.visible_message("[user] begins holding \the [src]'s flame up to [user.p_their()] face! It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(src, 'sound/items/welder.ogg', 50, 1)
- return FIRELOSS
- else
- user.visible_message("[user] begins whacking [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return BRUTELOSS
-
-/obj/item/lighter/update_icon()
- cut_overlays()
- var/mutable_appearance/lighter_overlay = mutable_appearance(icon,"lighter_overlay_[overlay_state][lit ? "-on" : ""]")
- icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
- add_overlay(lighter_overlay)
-
-/obj/item/lighter/ignition_effect(atom/A, mob/user)
- if(is_hot())
- . = "With a single flick of [user.p_their()] wrist, [user] smoothly lights [A] with [src]. Damn [user.p_theyre()] cool."
-
-/obj/item/lighter/proc/set_lit(new_lit)
- lit = new_lit
- if(lit)
- force = 5
- damtype = "fire"
- hitsound = 'sound/items/welder.ogg'
- attack_verb = list("burnt", "singed")
- set_light(2, 0.6, LIGHT_COLOR_FIRE)
- START_PROCESSING(SSobj, src)
- else
- hitsound = "swing_hit"
- force = 0
- attack_verb = null //human_defense.dm takes care of it
- set_light(0)
- STOP_PROCESSING(SSobj, src)
- update_icon()
-
-/obj/item/lighter/attack_self(mob/living/user)
- if(user.is_holding(src))
- if(!lit)
- set_lit(TRUE)
- if(fancy)
- user.visible_message("Without even breaking stride, [user] flips open and lights [src] in one smooth movement.", "Without even breaking stride, you flip open and light [src] in one smooth movement.")
- else
- var/prot = FALSE
- var/mob/living/carbon/human/H = user
-
- if(istype(H) && H.gloves)
- var/obj/item/clothing/gloves/G = H.gloves
- if(G.max_heat_protection_temperature)
- prot = (G.max_heat_protection_temperature > 360)
- else
- prot = TRUE
-
- if(prot || prob(75))
- user.visible_message("After a few attempts, [user] manages to light [src].", "After a few attempts, you manage to light [src].")
- else
- var/hitzone = user.held_index_to_dir(user.active_hand_index) == "r" ? BODY_ZONE_PRECISE_R_HAND : BODY_ZONE_PRECISE_L_HAND
- user.apply_damage(5, BURN, hitzone)
- user.visible_message("After a few attempts, [user] manages to light [src] - however, [user.p_they()] burn [user.p_their()] finger in the process.", "You burn yourself while lighting the lighter!")
- SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "burnt_thumb", /datum/mood_event/burnt_thumb)
-
- else
- set_lit(FALSE)
- if(fancy)
- user.visible_message("You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.", "You quietly shut off [src] without even looking at what you're doing. Wow.")
- else
- user.visible_message("[user] quietly shuts off [src].", "You quietly shut off [src].")
- else
- . = ..()
-
-/obj/item/lighter/attack(mob/living/carbon/M, mob/living/carbon/user)
- if(lit && M.IgniteMob())
- message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
- log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
- var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
- if(lit && cig && user.a_intent == INTENT_HELP)
- if(cig.lit)
- to_chat(user, "The [cig.name] is already lit.")
- if(M == user)
- cig.attackby(src, user)
- else
- if(fancy)
- cig.light("[user] whips the [name] out and holds it for [M]. [user.p_their(TRUE)] arm is as steady as the unflickering flame [user.p_they()] light[user.p_s()] \the [cig] with.")
- else
- cig.light("[user] holds the [name] out for [M], and lights [M.p_their()] [cig.name].")
- else
- ..()
-
-/obj/item/lighter/process()
- open_flame()
-
-/obj/item/lighter/is_hot()
- return lit * heat
-
-
-/obj/item/lighter/greyscale
- name = "cheap lighter"
- desc = "A cheap-as-free lighter."
- icon_state = "lighter"
- fancy = FALSE
- overlay_list = list(
- "transp",
- "tall",
- "matte",
- "zoppo" //u cant stoppo th zoppo
- )
- var/lighter_color
- var/list/color_list = list( //Same 16 color selection as electronic assemblies
- COLOR_ASSEMBLY_BLACK,
- COLOR_FLOORTILE_GRAY,
- COLOR_ASSEMBLY_BGRAY,
- COLOR_ASSEMBLY_WHITE,
- COLOR_ASSEMBLY_RED,
- COLOR_ASSEMBLY_ORANGE,
- COLOR_ASSEMBLY_BEIGE,
- COLOR_ASSEMBLY_BROWN,
- COLOR_ASSEMBLY_GOLD,
- COLOR_ASSEMBLY_YELLOW,
- COLOR_ASSEMBLY_GURKHA,
- COLOR_ASSEMBLY_LGREEN,
- COLOR_ASSEMBLY_GREEN,
- COLOR_ASSEMBLY_LBLUE,
- COLOR_ASSEMBLY_BLUE,
- COLOR_ASSEMBLY_PURPLE
- )
-
-/obj/item/lighter/greyscale/Initialize()
- . = ..()
- if(!lighter_color)
- lighter_color = pick(color_list)
- update_icon()
-
-/obj/item/lighter/greyscale/update_icon()
- cut_overlays()
- var/mutable_appearance/lighter_overlay = mutable_appearance(icon,"lighter_overlay_[overlay_state][lit ? "-on" : ""]")
- icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
- lighter_overlay.color = lighter_color
- add_overlay(lighter_overlay)
-
-/obj/item/lighter/greyscale/ignition_effect(atom/A, mob/user)
- if(is_hot())
- . = "After some fiddling, [user] manages to light [A] with [src]."
-
-
-/obj/item/lighter/slime
- name = "slime zippo"
- desc = "A specialty zippo made from slimes and industry. Has a much hotter flame than normal."
- icon_state = "slighter"
- heat = 3000 //Blue flame!
- light_color = LIGHT_COLOR_CYAN
- overlay_state = "slime"
- grind_results = list("iron" = 1, "welding_fuel" = 5, "pyroxadone" = 5)
-
-
-///////////
-//ROLLING//
-///////////
-/obj/item/rollingpaper
- name = "rolling paper"
- desc = "A thin piece of paper used to make fine smokeables."
- icon = 'icons/obj/cigarettes.dmi'
- icon_state = "cig_paper"
- w_class = WEIGHT_CLASS_TINY
-
-/obj/item/rollingpaper/afterattack(atom/target, mob/user, proximity)
- . = ..()
- if(!proximity)
- return
- if(istype(target, /obj/item/reagent_containers/food/snacks/grown))
- var/obj/item/reagent_containers/food/snacks/grown/O = target
- if(O.dry)
- var/obj/item/clothing/mask/cigarette/rollie/R = new /obj/item/clothing/mask/cigarette/rollie(user.loc)
- R.chem_volume = target.reagents.total_volume
- target.reagents.trans_to(R, R.chem_volume)
- qdel(target)
- qdel(src)
- user.put_in_active_hand(R)
- to_chat(user, "You roll the [target.name] into a rolling paper.")
- R.desc = "Dried [target.name] rolled up in a thin piece of paper."
- else
- to_chat(user, "You need to dry this first!")
-
-///////////////
-//VAPE NATION//
-///////////////
-/obj/item/clothing/mask/vape
- name = "\improper E-Cigarette"
- desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\""//<<< i'd vape to that.
- icon = 'icons/obj/clothing/masks.dmi'
- icon_state = null
- item_state = null
- w_class = WEIGHT_CLASS_TINY
- var/chem_volume = 100
- var/vapetime = FALSE //this so it won't puff out clouds every tick
- var/screw = FALSE // kinky
- var/super = FALSE //for the fattest vapes dude.
-
-/obj/item/clothing/mask/vape/suicide_act(mob/user)
- user.visible_message("[user] is puffin hard on dat vape, [user.p_they()] trying to join the vape life on a whole notha plane!")//it doesn't give you cancer, it is cancer
- return (TOXLOSS|OXYLOSS)
-
-
-/obj/item/clothing/mask/vape/Initialize(mapload, param_color)
- . = ..()
- create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it
- reagents.add_reagent("nicotine", 50)
- if(!icon_state)
- if(!param_color)
- param_color = pick("red","blue","black","white","green","purple","yellow","orange")
- icon_state = "[param_color]_vape"
- item_state = "[param_color]_vape"
-
-/obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params)
- if(O.tool_behaviour == TOOL_SCREWDRIVER)
- if(!screw)
- screw = TRUE
- to_chat(user, "You open the cap on [src].")
- ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
- if(obj_flags & EMAGGED)
- add_overlay("vapeopen_high")
- else if(super)
- add_overlay("vapeopen_med")
- else
- add_overlay("vapeopen_low")
- else
- screw = FALSE
- to_chat(user, "You close the cap on [src].")
- DISABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
- cut_overlays()
-
- if(O.tool_behaviour == TOOL_MULTITOOL)
- if(screw && !(obj_flags & EMAGGED))//also kinky
- if(!super)
- cut_overlays()
- super = TRUE
- to_chat(user, "You increase the voltage of [src].")
- add_overlay("vapeopen_med")
- else
- cut_overlays()
- super = FALSE
- to_chat(user, "You decrease the voltage of [src].")
- add_overlay("vapeopen_low")
-
- if(screw && (obj_flags & EMAGGED))
- to_chat(user, "[src] can't be modified!")
-
- else
- ..()
-
-/obj/item/clothing/mask/vape/emag_act(mob/user)// I WON'T REGRET WRITTING THIS, SURLY.
- if(screw)
- if(!(obj_flags & EMAGGED))
- cut_overlays()
- obj_flags |= EMAGGED
- super = FALSE
- to_chat(user, "You maximize the voltage of [src].")
- add_overlay("vapeopen_high")
- var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect
- sp.set_up(5, 1, src)
- sp.start()
- else
- to_chat(user, "[src] is already emagged!")
- else
- to_chat(user, "You need to open the cap to do that.")
-
-/obj/item/clothing/mask/vape/attack_self(mob/user)
- if(reagents.total_volume > 0)
- to_chat(user, "You empty [src] of all reagents.")
- reagents.clear_reagents()
-
-/obj/item/clothing/mask/vape/equipped(mob/user, slot)
- if(slot == SLOT_WEAR_MASK)
- if(!screw)
- to_chat(user, "You start puffing on the vape.")
- DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
- START_PROCESSING(SSobj, src)
- else //it will not start if the vape is opened.
- to_chat(user, "You need to close the cap first!")
-
-/obj/item/clothing/mask/vape/dropped(mob/user)
- var/mob/living/carbon/C = user
- if(C.get_item_by_slot(SLOT_WEAR_MASK) == src)
- ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
- STOP_PROCESSING(SSobj, src)
-
-/obj/item/clothing/mask/vape/proc/hand_reagents()//had to rename to avoid duplicate error
- if(reagents.total_volume)
- if(iscarbon(loc))
- var/mob/living/carbon/C = loc
- if (src == C.wear_mask) // if it's in the human/monkey mouth, transfer reagents to the mob
- var/fraction = min(REAGENTS_METABOLISM/reagents.total_volume, 1) //this will react instantly, making them a little more dangerous than cigarettes
- reagents.reaction(C, INGEST, fraction)
- if(!reagents.trans_to(C, REAGENTS_METABOLISM))
- reagents.remove_any(REAGENTS_METABOLISM)
- if(reagents.get_reagent_amount("welding_fuel"))
- //HOT STUFF
- C.fire_stacks = 2
- C.IgniteMob()
-
- if(reagents.get_reagent_amount("plasma")) // the plasma explodes when exposed to fire
- var/datum/effect_system/reagents_explosion/e = new()
- e.set_up(round(reagents.get_reagent_amount("plasma") / 2.5, 1), get_turf(src), 0, 0)
- e.start()
- qdel(src)
- return
- reagents.remove_any(REAGENTS_METABOLISM)
-
-/obj/item/clothing/mask/vape/process()
- var/mob/living/M = loc
-
- if(isliving(loc))
- M.IgniteMob()
-
- vapetime++
-
- if(!reagents.total_volume)
- if(ismob(loc))
- to_chat(M, "[src] is empty!")
- STOP_PROCESSING(SSobj, src)
- //it's reusable so it won't unequip when empty
- return
- //open flame removed because vapes are a closed system, they wont light anything on fire
-
- if(super && vapetime > 3)//Time to start puffing those fat vapes, yo.
- var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
- s.set_up(reagents, 1, 24, loc)
- s.start()
- vapetime = 0
-
- if((obj_flags & EMAGGED) && vapetime > 3)
- var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
- s.set_up(reagents, 4, 24, loc)
- s.start()
- vapetime = 0
- if(prob(5))//small chance for the vape to break and deal damage if it's emagged
- playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, 0)
- M.apply_damage(20, BURN, BODY_ZONE_HEAD)
- M.Knockdown(300, 1, 0)
- var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread
- sp.set_up(5, 1, src)
- sp.start()
- to_chat(M, "[src] suddenly explodes in your mouth!")
- qdel(src)
- return
-
- if(reagents && reagents.total_volume)
- hand_reagents()
-
-///////////////
-/////BONGS/////
-///////////////
-
-/obj/item/bong
- name = "bong"
- desc = "A water bong used for smoking dried plants."
- icon = 'icons/obj/bongs.dmi'
- icon_state = null
- item_state = null
- w_class = WEIGHT_CLASS_NORMAL
- light_color = "#FFCC66"
- var/icon_off = "bong"
- var/icon_on = "bong_lit"
- var/chem_volume = 100
- var/last_used_time //for cooldown
- var/firecharges = 0 //used for counting how many hits can be taken before the flame goes out
- var/list/list_reagents = list() //For the base reagents bongs could get
-
-
-/obj/item/bong/Initialize()
- . = ..()
- create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it
- reagents.add_reagent_list(list_reagents)
- icon_state = icon_off
-
-/obj/item/bong/attackby(obj/item/O, mob/user, params)
- . = ..()
- //If we're using a dried plant..
- if(istype(O,/obj/item/reagent_containers/food/snacks))
- var/obj/item/reagent_containers/food/snacks/DP = O
- if (DP.dry)
- //Nothing if our bong is full
- if (reagents.holder_full())
- user.show_message("The bowl is full!", 1)
- return
-
- //Transfer reagents and remove the plant
- user.show_message("You stuff the [DP] into the [src]'s bowl.", 1)
- DP.reagents.trans_to(src, 100)
- qdel(DP)
- return
- else
- user.show_message("[DP] must be dried first!", 1)
- return
-
- if (O.heat > 500)
- if (reagents && reagents.total_volume) //if there's stuff in the bong
- var/lighting_text = O.ignition_effect(src, user)
- if(lighting_text)
- //Logic regarding igniting it on
- if (firecharges == 0)
- user.show_message("You light the [src] with the [O]!", 1)
- bongturnon()
- else
- user.show_message("You rekindle [src]'s flame with the [O]!", 1)
-
- firecharges = 1
- return
- else
- user.show_message("There's nothing to light up in the bowl.", 1)
- return
-
-/obj/item/bong/CtrlShiftClick(mob/user) //empty reagents on alt click
- if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
- return
-
- if (reagents && reagents.total_volume)
- user.show_message("You empty the [src].", 1)
- reagents.clear_reagents()
- if(firecharges)
- firecharges = 0
- bongturnoff()
- else
- user.show_message("The [src] is already empty.", 1)
-
-/obj/item/bong/AltClick(mob/user)
- if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
- return
-
- if(firecharges)
- firecharges = 0
- bongturnoff()
- user.show_message("You quench the flame.", 1)
-
-/obj/item/bong/examine(mob/user)
- . = ..()
- if(!reagents.total_volume)
- . += "The bowl is empty."
- else if (reagents.total_volume > 80)
- . += "The bowl is filled to the brim."
- else if (reagents.total_volume > 40)
- . += "The bowl has plenty weed in it."
- else
- . += "The bowl has some weed in it."
-
- . += "Ctrl+Shift-click to empty."
- . += "Alt-click to extinguish."
-
-/obj/item/bong/ignition_effect(atom/A, mob/user)
- if(firecharges)
- . = "[user] lights [A] off of the [src]."
- else
- . = ""
-
-/obj/item/bong/attack(mob/living/carbon/M, mob/living/carbon/user, obj/target)
- //if it's lit up, some stuff in the bowl and the user is a target, and we're not on cooldown
- if (!reagents)
- return
-
- if (M ==! user)
- return
-
- if(user.is_mouth_covered(head_only = 1))
- to_chat(user, "Remove your headgear first.")
- return
-
- if(user.is_mouth_covered(mask_only = 1))
- to_chat(user, "Remove your mask first.")
- return
-
- if (!reagents.total_volume)
- to_chat(user, "There's nothing in the bowl.")
- return
-
- if (!firecharges)
- to_chat(user, "You have to light it up first.")
- return
-
- if (last_used_time + 30 < world.time)
- var/hit_strength
- var/noise
- var/hittext = ""
- //if the intent is help then you take a small hit, else a big one
- if (user.a_intent == INTENT_HARM)
- hit_strength = 2
- noise = 100
- hittext = "big hit"
- else
- hit_strength = 1
- noise = 70
- hittext = "hit"
- //bubbling sound
- playsound(user.loc,'sound/effects/bonghit.ogg', noise, 1)
-
- last_used_time = world.time
-
- //message
- user.visible_message("[user] begins to take a "+ hittext +" from the [src]!", \
- "You begin to take a "+ hittext +" from [src].")
-
- //we take a hit here, after an uninterrupted delay
- if(do_after(user, 25, target = user))
- if (reagents && reagents.total_volume)
- var/fraction = 12 * hit_strength
-
- var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
- s.set_up(reagents, hit_strength, 18, user.loc)
- s.start()
-
- reagents.reaction(user, INGEST, fraction)
- if(!reagents.trans_to(user, fraction))
- reagents.remove_any(fraction)
-
- if (hit_strength == 2 && prob(15))
- user.emote("cough")
- user.adjustOxyLoss(15)
-
- //playsound(user.loc, 'sound/effects/smoke.ogg', 10, 1, -3)
-
- user.visible_message("[user] takes a "+ hittext +" from the [src]!", \
- "You take a "+ hittext +" from [src].")
-
- firecharges = firecharges - 1
- if (firecharges == 0)
- bongturnoff()
- if (!reagents.total_volume)
- firecharges = 0
- bongturnoff()
-
-
-
-/obj/item/bong/proc/bongturnon()
- icon_state = icon_on
- set_light(3, 0.8)
-
-/obj/item/bong/proc/bongturnoff()
- icon_state = icon_off
- set_light(0, 0.0)
-
-
-
-/obj/item/bong/coconut
- name = "coconut bong"
- icon_off = "coconut_bong"
- icon_on = "coconut_bong_lit"
- desc = "A water bong used for smoking dried plants. This one's made out of a coconut and some bamboo"
+//cleansed 9/15/2012 17:48
+
+/*
+CONTAINS:
+MATCHES
+CIGARETTES
+CIGARS
+SMOKING PIPES
+CHEAP LIGHTERS
+ZIPPO
+
+CIGARETTE PACKETS ARE IN FANCY.DM
+*/
+
+///////////
+//MATCHES//
+///////////
+/obj/item/match
+ name = "match"
+ desc = "A simple match stick, used for lighting fine smokables."
+ icon = 'icons/obj/cigarettes.dmi'
+ icon_state = "match_unlit"
+ var/lit = FALSE
+ var/burnt = FALSE
+ var/smoketime = 5
+ w_class = WEIGHT_CLASS_TINY
+ heat = 1000
+ grind_results = list(/datum/reagent/phosphorus = 2)
+
+/obj/item/match/process()
+ smoketime--
+ if(smoketime < 1)
+ matchburnout()
+ else
+ open_flame(heat)
+
+/obj/item/match/fire_act(exposed_temperature, exposed_volume)
+ matchignite()
+
+/obj/item/match/proc/matchignite()
+ if(!lit && !burnt)
+ lit = TRUE
+ icon_state = "match_lit"
+ damtype = "fire"
+ force = 3
+ hitsound = 'sound/items/welder.ogg'
+ item_state = "cigon"
+ name = "lit match"
+ desc = "A match. This one is lit."
+ attack_verb = list("burnt","singed")
+ START_PROCESSING(SSobj, src)
+ update_icon()
+
+/obj/item/match/proc/matchburnout()
+ if(lit)
+ lit = FALSE
+ burnt = TRUE
+ damtype = "brute"
+ force = initial(force)
+ icon_state = "match_burnt"
+ item_state = "cigoff"
+ name = "burnt match"
+ desc = "A match. This one has seen better days."
+ attack_verb = list("flicked")
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/match/dropped(mob/user)
+ matchburnout()
+ . = ..()
+
+/obj/item/match/attack(mob/living/carbon/M, mob/living/carbon/user)
+ if(!isliving(M))
+ return
+ if(lit && M.IgniteMob())
+ message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
+ log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
+ var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
+ if(lit && cig && user.a_intent == INTENT_HELP)
+ if(cig.lit)
+ to_chat(user, "[cig] is already lit.")
+ if(M == user)
+ cig.attackby(src, user)
+ else
+ cig.light("[user] holds [src] out for [M], and lights [cig].")
+ else
+ ..()
+
+/obj/item/proc/help_light_cig(mob/living/M)
+ var/mask_item = M.get_item_by_slot(SLOT_WEAR_MASK)
+ if(istype(mask_item, /obj/item/clothing/mask/cigarette))
+ return mask_item
+
+/obj/item/match/is_hot()
+ return lit * heat
+
+//////////////////
+//FINE SMOKABLES//
+//////////////////
+/obj/item/clothing/mask/cigarette
+ name = "cigarette"
+ desc = "A roll of tobacco and nicotine."
+ icon_state = "cigoff"
+ throw_speed = 0.5
+ item_state = "cigoff"
+ w_class = WEIGHT_CLASS_TINY
+ body_parts_covered = null
+ grind_results = list()
+ var/lit = FALSE
+ var/starts_lit = FALSE
+ var/icon_on = "cigon" //Note - these are in masks.dmi not in cigarette.dmi
+ var/icon_off = "cigoff"
+ var/type_butt = /obj/item/cigbutt
+ var/lastHolder = null
+ var/smoketime = 300
+ var/chem_volume = 30
+ var/list/list_reagents = list(/datum/reagent/drug/nicotine = 15)
+ heat = 1000
+
+/obj/item/clothing/mask/cigarette/suicide_act(mob/user)
+ user.visible_message("[user] is huffing [src] as quickly as [user.p_they()] can! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer.")
+ return (TOXLOSS|OXYLOSS)
+
+/obj/item/clothing/mask/cigarette/Initialize()
+ . = ..()
+ create_reagents(chem_volume, INJECTABLE | NO_REACT) // so it doesn't react until you light it
+ if(list_reagents)
+ reagents.add_reagent_list(list_reagents)
+ if(starts_lit)
+ light()
+ AddComponent(/datum/component/knockoff,90,list(BODY_ZONE_PRECISE_MOUTH),list(SLOT_WEAR_MASK))//90% to knock off when wearing a mask
+
+/obj/item/clothing/mask/cigarette/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ . = ..()
+
+/obj/item/clothing/mask/cigarette/attackby(obj/item/W, mob/user, params)
+ if(!lit && smoketime > 0)
+ var/lighting_text = W.ignition_effect(src, user)
+ if(lighting_text)
+ light(lighting_text)
+ else
+ return ..()
+
+/obj/item/clothing/mask/cigarette/afterattack(obj/item/reagent_containers/glass/glass, mob/user, proximity)
+ . = ..()
+ if(!proximity || lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
+ return
+ if(istype(glass)) //you can dip cigarettes into beakers
+ if(glass.reagents.trans_to(src, chem_volume)) //if reagents were transfered, show the message
+ to_chat(user, "You dip \the [src] into \the [glass].")
+ else //if not, either the beaker was empty, or the cigarette was full
+ if(!glass.reagents.total_volume)
+ to_chat(user, "[glass] is empty.")
+ else
+ to_chat(user, "[src] is full.")
+
+
+/obj/item/clothing/mask/cigarette/proc/light(flavor_text = null)
+ if(lit)
+ return
+ if(!(flags_1 & INITIALIZED_1))
+ icon_state = icon_on
+ item_state = icon_on
+ return
+
+ lit = TRUE
+ name = "lit [name]"
+ attack_verb = list("burnt", "singed")
+ hitsound = 'sound/items/welder.ogg'
+ damtype = "fire"
+ force = 4
+ if(reagents.get_reagent_amount(/datum/reagent/toxin/plasma)) // the plasma explodes when exposed to fire
+ var/datum/effect_system/reagents_explosion/e = new()
+ e.set_up(round(reagents.get_reagent_amount(/datum/reagent/toxin/plasma) / 2.5, 1), get_turf(src), 0, 0)
+ e.start()
+ qdel(src)
+ return
+ if(reagents.get_reagent_amount(/datum/reagent/fuel)) // the fuel explodes, too, but much less violently
+ var/datum/effect_system/reagents_explosion/e = new()
+ e.set_up(round(reagents.get_reagent_amount(/datum/reagent/fuel) / 5, 1), get_turf(src), 0, 0)
+ e.start()
+ qdel(src)
+ return
+ // allowing reagents to react after being lit
+ DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
+ reagents.handle_reactions()
+ icon_state = icon_on
+ item_state = icon_on
+ if(flavor_text)
+ var/turf/T = get_turf(src)
+ T.visible_message(flavor_text)
+ START_PROCESSING(SSobj, src)
+
+ //can't think of any other way to update the overlays :<
+ if(ismob(loc))
+ var/mob/M = loc
+ M.update_inv_wear_mask()
+ M.update_inv_hands()
+
+
+/obj/item/clothing/mask/cigarette/proc/handle_reagents()
+ if(reagents.total_volume)
+ if(iscarbon(loc))
+ var/mob/living/carbon/C = loc
+ if (src == C.wear_mask) // if it's in the human/monkey mouth, transfer reagents to the mob
+ var/fraction = min(REAGENTS_METABOLISM/reagents.total_volume, 1)
+ reagents.reaction(C, INGEST, fraction)
+ if(!reagents.trans_to(C, REAGENTS_METABOLISM))
+ reagents.remove_any(REAGENTS_METABOLISM)
+ return
+ reagents.remove_any(REAGENTS_METABOLISM)
+
+
+/obj/item/clothing/mask/cigarette/process()
+ var/turf/location = get_turf(src)
+ var/mob/living/M = loc
+ if(isliving(loc))
+ M.IgniteMob()
+ smoketime--
+ if(smoketime < 1)
+ new type_butt(location)
+ if(ismob(loc))
+ to_chat(M, "Your [name] goes out.")
+ qdel(src)
+ return
+ open_flame()
+ if(reagents && reagents.total_volume)
+ handle_reagents()
+
+/obj/item/clothing/mask/cigarette/attack_self(mob/user)
+ if(lit)
+ user.visible_message("[user] calmly drops and treads on \the [src], putting it out instantly.")
+ new type_butt(user.loc)
+ new /obj/effect/decal/cleanable/ash(user.loc)
+ qdel(src)
+ . = ..()
+
+/obj/item/clothing/mask/cigarette/attack(mob/living/carbon/M, mob/living/carbon/user)
+ if(!istype(M))
+ return ..()
+ if(M.on_fire && !lit)
+ light("[user] lights [src] with [M]'s burning body. What a cold-blooded badass.")
+ return
+ var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
+ if(lit && cig && user.a_intent == INTENT_HELP)
+ if(cig.lit)
+ to_chat(user, "The [cig.name] is already lit.")
+ if(M == user)
+ cig.attackby(src, user)
+ else
+ cig.light("[user] holds the [name] out for [M], and lights [M.p_their()] [cig.name].")
+ else
+ return ..()
+
+/obj/item/clothing/mask/cigarette/fire_act(exposed_temperature, exposed_volume)
+ light()
+
+/obj/item/clothing/mask/cigarette/is_hot()
+ return lit * heat
+
+// Cigarette brands.
+
+/obj/item/clothing/mask/cigarette/space_cigarette
+ desc = "A Space Cigarette brand cigarette."
+
+/obj/item/clothing/mask/cigarette/dromedary
+ desc = "A DromedaryCo brand cigarette."
+ list_reagents = list(/datum/reagent/drug/nicotine = 7.5, /datum/reagent/silicon = 7.5)
+
+/obj/item/clothing/mask/cigarette/smokekins
+ desc = "A Kinaris Corp brand cigarette"
+ list_reagents = list(/datum/reagent/drug/nicotine = 7.5, /datum/reagent/gold = 1)
+
+/obj/item/clothing/mask/cigarette/uplift
+ desc = "An Uplift Smooth brand cigarette."
+ list_reagents = list(/datum/reagent/drug/nicotine = 7.5, /datum/reagent/consumable/menthol = 7.5)
+
+/obj/item/clothing/mask/cigarette/robust
+ desc = "A Robust brand cigarette."
+ list_reagents = list(/datum/reagent/drug/nicotine = 7.5, /datum/reagent/consumable/grenadine = 7.5)
+
+/obj/item/clothing/mask/cigarette/robustgold
+ desc = "A Robust Gold brand cigarette."
+ list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/gold = 1)
+
+/obj/item/clothing/mask/cigarette/carp
+ desc = "A Carp Classic brand cigarette."
+ list_reagents = list(/datum/reagent/drug/nicotine = 7.5, /datum/reagent/consumable/sodiumchloride = 7.5)
+
+/obj/item/clothing/mask/cigarette/syndicate
+ desc = "An unknown brand cigarette."
+ list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/medicine/omnizine = 15)
+
+/obj/item/clothing/mask/cigarette/shadyjims
+ desc = "A Shady Jim's Super Slims cigarette."
+ list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/toxin/lipolicide = 4, /datum/reagent/ammonia = 2, /datum/reagent/toxin/plantbgone = 1, /datum/reagent/toxin = 1.5)
+
+/obj/item/clothing/mask/cigarette/xeno
+ desc = "A Xeno Filtered brand cigarette."
+ list_reagents = list (/datum/reagent/drug/nicotine = 20, /datum/reagent/medicine/regen_jelly = 15, /datum/reagent/drug/krokodil = 4)
+
+// Rollies.
+
+/obj/item/clothing/mask/cigarette/rollie
+ name = "rollie"
+ desc = "A roll of dried plant matter wrapped in thin paper."
+ icon_state = "spliffoff"
+ icon_on = "spliffon"
+ icon_off = "spliffoff"
+ type_butt = /obj/item/cigbutt/roach
+ throw_speed = 0.5
+ item_state = "spliffoff"
+ smoketime = 180
+ chem_volume = 50
+ list_reagents = null
+
+/obj/item/clothing/mask/cigarette/rollie/New()
+ ..()
+ src.pixel_x = rand(-5, 5)
+ src.pixel_y = rand(-5, 5)
+
+/obj/item/clothing/mask/cigarette/rollie/nicotine
+ list_reagents = list(/datum/reagent/drug/nicotine = 15)
+
+/obj/item/clothing/mask/cigarette/rollie/trippy
+ list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/drug/mushroomhallucinogen = 35)
+ starts_lit = TRUE
+
+/obj/item/clothing/mask/cigarette/rollie/cannabis
+ list_reagents = list(/datum/reagent/drug/space_drugs = 15, /datum/reagent/toxin/lipolicide = 35)
+
+/obj/item/clothing/mask/cigarette/rollie/mindbreaker
+ list_reagents = list(/datum/reagent/toxin/mindbreaker = 35, /datum/reagent/toxin/lipolicide = 15)
+
+/obj/item/cigbutt/roach
+ name = "roach"
+ desc = "A manky old roach, or for non-stoners, a used rollup."
+ icon_state = "roach"
+
+/obj/item/cigbutt/roach/New()
+ ..()
+ src.pixel_x = rand(-5, 5)
+ src.pixel_y = rand(-5, 5)
+
+
+////////////
+// CIGARS //
+////////////
+/obj/item/clothing/mask/cigarette/cigar
+ name = "premium cigar"
+ desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!"
+ icon_state = "cigaroff"
+ icon_on = "cigaron"
+ icon_off = "cigaroff" //make sure to add positional sprites in icons/obj/cigarettes.dmi if you add more.
+ type_butt = /obj/item/cigbutt/cigarbutt
+ throw_speed = 0.5
+ item_state = "cigaroff"
+ smoketime = 1500
+ chem_volume = 40
+
+/obj/item/clothing/mask/cigarette/cigar/cohiba
+ name = "\improper Cohiba Robusto cigar"
+ desc = "There's little more you could want from a cigar."
+ icon_state = "cigar2off"
+ icon_on = "cigar2on"
+ icon_off = "cigar2off"
+ smoketime = 2000
+ chem_volume = 80
+
+
+/obj/item/clothing/mask/cigarette/cigar/havana
+ name = "premium Havanian cigar"
+ desc = "A cigar fit for only the best of the best."
+ icon_state = "cigar2off"
+ icon_on = "cigar2on"
+ icon_off = "cigar2off"
+ smoketime = 7200
+ chem_volume = 50
+
+/obj/item/cigbutt
+ name = "cigarette butt"
+ desc = "A manky old cigarette butt."
+ icon = 'icons/obj/clothing/masks.dmi'
+ icon_state = "cigbutt"
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 0
+ grind_results = list(/datum/reagent/carbon = 2)
+
+/obj/item/cigbutt/cigarbutt
+ name = "cigar butt"
+ desc = "A manky old cigar butt."
+ icon_state = "cigarbutt"
+
+/////////////////
+//SMOKING PIPES//
+/////////////////
+/obj/item/clothing/mask/cigarette/pipe
+ name = "smoking pipe"
+ desc = "A pipe, for smoking. Probably made of meerschaum or something."
+ icon_state = "pipeoff"
+ item_state = "pipeoff"
+ icon_on = "pipeon" //Note - these are in masks.dmi
+ icon_off = "pipeoff"
+ smoketime = 0
+ chem_volume = 100
+ list_reagents = null
+ var/packeditem = 0
+
+/obj/item/clothing/mask/cigarette/pipe/Initialize()
+ . = ..()
+ name = "empty [initial(name)]"
+
+/obj/item/clothing/mask/cigarette/pipe/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ . = ..()
+
+/obj/item/clothing/mask/cigarette/pipe/process()
+ var/turf/location = get_turf(src)
+ smoketime--
+ if(smoketime < 1)
+ new /obj/effect/decal/cleanable/ash(location)
+ if(ismob(loc))
+ var/mob/living/M = loc
+ to_chat(M, "Your [name] goes out.")
+ lit = 0
+ icon_state = icon_off
+ item_state = icon_off
+ M.update_inv_wear_mask()
+ packeditem = 0
+ name = "empty [initial(name)]"
+ STOP_PROCESSING(SSobj, src)
+ return
+ open_flame()
+ if(reagents && reagents.total_volume) // check if it has any reagents at all
+ handle_reagents()
+
+
+/obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/O, mob/user, params)
+ if(istype(O, /obj/item/reagent_containers/food/snacks/grown))
+ var/obj/item/reagent_containers/food/snacks/grown/G = O
+ if(!packeditem)
+ if(G.dry == 1)
+ to_chat(user, "You stuff [O] into [src].")
+ smoketime = 400
+ packeditem = 1
+ name = "[O.name]-packed [initial(name)]"
+ if(O.reagents)
+ O.reagents.trans_to(src, O.reagents.total_volume)
+ qdel(O)
+ else
+ to_chat(user, "It has to be dried first!")
+ else
+ to_chat(user, "It is already packed!")
+ else
+ var/lighting_text = O.ignition_effect(src,user)
+ if(lighting_text)
+ if(smoketime > 0)
+ light(lighting_text)
+ else
+ to_chat(user, "There is nothing to smoke!")
+ else
+ return ..()
+
+/obj/item/clothing/mask/cigarette/pipe/attack_self(mob/user)
+ var/turf/location = get_turf(user)
+ if(lit)
+ user.visible_message("[user] puts out [src].", "You put out [src].")
+ lit = 0
+ icon_state = icon_off
+ item_state = icon_off
+ STOP_PROCESSING(SSobj, src)
+ return
+ if(!lit && smoketime > 0)
+ to_chat(user, "You empty [src] onto [location].")
+ new /obj/effect/decal/cleanable/ash(location)
+ packeditem = 0
+ smoketime = 0
+ reagents.clear_reagents()
+ name = "empty [initial(name)]"
+ return
+
+/obj/item/clothing/mask/cigarette/pipe/cobpipe
+ name = "corn cob pipe"
+ desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects."
+ icon_state = "cobpipeoff"
+ item_state = "cobpipeoff"
+ icon_on = "cobpipeon" //Note - these are in masks.dmi
+ icon_off = "cobpipeoff"
+ smoketime = 0
+
+
+/////////
+//ZIPPO//
+/////////
+/obj/item/lighter
+ name = "\improper Zippo lighter"
+ desc = "The zippo."
+ icon = 'icons/obj/cigarettes.dmi'
+ icon_state = "zippo"
+ item_state = "zippo"
+ w_class = WEIGHT_CLASS_TINY
+ flags_1 = CONDUCT_1
+ slot_flags = ITEM_SLOT_BELT
+ var/lit = 0
+ var/fancy = TRUE
+ var/overlay_state
+ var/overlay_list = list(
+ "plain",
+ "dame",
+ "thirteen",
+ "snake"
+ )
+ heat = 1500
+ resistance_flags = FIRE_PROOF
+ light_color = LIGHT_COLOR_FIRE
+ grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/oil = 5)
+
+/obj/item/lighter/Initialize()
+ . = ..()
+ if(!overlay_state)
+ overlay_state = pick(overlay_list)
+ update_icon()
+
+/obj/item/lighter/suicide_act(mob/living/carbon/user)
+ if (lit)
+ user.visible_message("[user] begins holding \the [src]'s flame up to [user.p_their()] face! It looks like [user.p_theyre()] trying to commit suicide!")
+ playsound(src, 'sound/items/welder.ogg', 50, 1)
+ return FIRELOSS
+ else
+ user.visible_message("[user] begins whacking [user.p_them()]self with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return BRUTELOSS
+
+/obj/item/lighter/update_icon()
+ cut_overlays()
+ var/mutable_appearance/lighter_overlay = mutable_appearance(icon,"lighter_overlay_[overlay_state][lit ? "-on" : ""]")
+ icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
+ add_overlay(lighter_overlay)
+
+/obj/item/lighter/ignition_effect(atom/A, mob/user)
+ if(is_hot())
+ . = "With a single flick of [user.p_their()] wrist, [user] smoothly lights [A] with [src]. Damn [user.p_theyre()] cool."
+
+/obj/item/lighter/proc/set_lit(new_lit)
+ lit = new_lit
+ if(lit)
+ force = 5
+ damtype = "fire"
+ hitsound = 'sound/items/welder.ogg'
+ attack_verb = list("burnt", "singed")
+ set_light(2, 0.6, LIGHT_COLOR_FIRE)
+ START_PROCESSING(SSobj, src)
+ else
+ hitsound = "swing_hit"
+ force = 0
+ attack_verb = null //human_defense.dm takes care of it
+ set_light(0)
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+
+/obj/item/lighter/attack_self(mob/living/user)
+ if(user.is_holding(src))
+ if(!lit)
+ set_lit(TRUE)
+ if(fancy)
+ user.visible_message("Without even breaking stride, [user] flips open and lights [src] in one smooth movement.", "Without even breaking stride, you flip open and light [src] in one smooth movement.")
+ else
+ var/prot = FALSE
+ var/mob/living/carbon/human/H = user
+
+ if(istype(H) && H.gloves)
+ var/obj/item/clothing/gloves/G = H.gloves
+ if(G.max_heat_protection_temperature)
+ prot = (G.max_heat_protection_temperature > 360)
+ else
+ prot = TRUE
+
+ if(prot || prob(75))
+ user.visible_message("After a few attempts, [user] manages to light [src].", "After a few attempts, you manage to light [src].")
+ else
+ var/hitzone = user.held_index_to_dir(user.active_hand_index) == "r" ? BODY_ZONE_PRECISE_R_HAND : BODY_ZONE_PRECISE_L_HAND
+ user.apply_damage(5, BURN, hitzone)
+ user.visible_message("After a few attempts, [user] manages to light [src] - however, [user.p_they()] burn [user.p_their()] finger in the process.", "You burn yourself while lighting the lighter!")
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "burnt_thumb", /datum/mood_event/burnt_thumb)
+
+ else
+ set_lit(FALSE)
+ if(fancy)
+ user.visible_message("You hear a quiet click, as [user] shuts off [src] without even looking at what [user.p_theyre()] doing. Wow.", "You quietly shut off [src] without even looking at what you're doing. Wow.")
+ else
+ user.visible_message("[user] quietly shuts off [src].", "You quietly shut off [src].")
+ else
+ . = ..()
+
+/obj/item/lighter/attack(mob/living/carbon/M, mob/living/carbon/user)
+ if(lit && M.IgniteMob())
+ message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
+ log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
+ var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
+ if(lit && cig && user.a_intent == INTENT_HELP)
+ if(cig.lit)
+ to_chat(user, "The [cig.name] is already lit.")
+ if(M == user)
+ cig.attackby(src, user)
+ else
+ if(fancy)
+ cig.light("[user] whips the [name] out and holds it for [M]. [user.p_their(TRUE)] arm is as steady as the unflickering flame [user.p_they()] light[user.p_s()] \the [cig] with.")
+ else
+ cig.light("[user] holds the [name] out for [M], and lights [M.p_their()] [cig.name].")
+ else
+ ..()
+
+/obj/item/lighter/process()
+ open_flame()
+
+/obj/item/lighter/is_hot()
+ return lit * heat
+
+
+/obj/item/lighter/greyscale
+ name = "cheap lighter"
+ desc = "A cheap-as-free lighter."
+ icon_state = "lighter"
+ fancy = FALSE
+ overlay_list = list(
+ "transp",
+ "tall",
+ "matte",
+ "zoppo" //u cant stoppo th zoppo
+ )
+ var/lighter_color
+ var/list/color_list = list( //Same 16 color selection as electronic assemblies
+ COLOR_ASSEMBLY_BLACK,
+ COLOR_FLOORTILE_GRAY,
+ COLOR_ASSEMBLY_BGRAY,
+ COLOR_ASSEMBLY_WHITE,
+ COLOR_ASSEMBLY_RED,
+ COLOR_ASSEMBLY_ORANGE,
+ COLOR_ASSEMBLY_BEIGE,
+ COLOR_ASSEMBLY_BROWN,
+ COLOR_ASSEMBLY_GOLD,
+ COLOR_ASSEMBLY_YELLOW,
+ COLOR_ASSEMBLY_GURKHA,
+ COLOR_ASSEMBLY_LGREEN,
+ COLOR_ASSEMBLY_GREEN,
+ COLOR_ASSEMBLY_LBLUE,
+ COLOR_ASSEMBLY_BLUE,
+ COLOR_ASSEMBLY_PURPLE
+ )
+
+/obj/item/lighter/greyscale/Initialize()
+ . = ..()
+ if(!lighter_color)
+ lighter_color = pick(color_list)
+ update_icon()
+
+/obj/item/lighter/greyscale/update_icon()
+ cut_overlays()
+ var/mutable_appearance/lighter_overlay = mutable_appearance(icon,"lighter_overlay_[overlay_state][lit ? "-on" : ""]")
+ icon_state = "[initial(icon_state)][lit ? "-on" : ""]"
+ lighter_overlay.color = lighter_color
+ add_overlay(lighter_overlay)
+
+/obj/item/lighter/greyscale/ignition_effect(atom/A, mob/user)
+ if(is_hot())
+ . = "After some fiddling, [user] manages to light [A] with [src]."
+
+
+/obj/item/lighter/slime
+ name = "slime zippo"
+ desc = "A specialty zippo made from slimes and industry. Has a much hotter flame than normal."
+ icon_state = "slighter"
+ heat = 3000 //Blue flame!
+ light_color = LIGHT_COLOR_CYAN
+ overlay_state = "slime"
+ grind_results = list(/datum/reagent/iron = 1, /datum/reagent/fuel = 5, /datum/reagent/medicine/pyroxadone = 5)
+
+
+///////////
+//ROLLING//
+///////////
+/obj/item/rollingpaper
+ name = "rolling paper"
+ desc = "A thin piece of paper used to make fine smokeables."
+ icon = 'icons/obj/cigarettes.dmi'
+ icon_state = "cig_paper"
+ w_class = WEIGHT_CLASS_TINY
+
+/obj/item/rollingpaper/afterattack(atom/target, mob/user, proximity)
+ . = ..()
+ if(!proximity)
+ return
+ if(istype(target, /obj/item/reagent_containers/food/snacks/grown))
+ var/obj/item/reagent_containers/food/snacks/grown/O = target
+ if(O.dry)
+ var/obj/item/clothing/mask/cigarette/rollie/R = new /obj/item/clothing/mask/cigarette/rollie(user.loc)
+ R.chem_volume = target.reagents.total_volume
+ target.reagents.trans_to(R, R.chem_volume)
+ qdel(target)
+ qdel(src)
+ user.put_in_active_hand(R)
+ to_chat(user, "You roll the [target.name] into a rolling paper.")
+ R.desc = "Dried [target.name] rolled up in a thin piece of paper."
+ else
+ to_chat(user, "You need to dry this first!")
+
+///////////////
+//VAPE NATION//
+///////////////
+/obj/item/clothing/mask/vape
+ name = "\improper E-Cigarette"
+ desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\""//<<< i'd vape to that.
+ icon = 'icons/obj/clothing/masks.dmi'
+ icon_state = null
+ item_state = null
+ w_class = WEIGHT_CLASS_TINY
+ var/chem_volume = 100
+ var/vapetime = FALSE //this so it won't puff out clouds every tick
+ var/screw = FALSE // kinky
+ var/super = FALSE //for the fattest vapes dude.
+
+/obj/item/clothing/mask/vape/suicide_act(mob/user)
+ user.visible_message("[user] is puffin hard on dat vape, [user.p_they()] trying to join the vape life on a whole notha plane!")//it doesn't give you cancer, it is cancer
+ return (TOXLOSS|OXYLOSS)
+
+
+/obj/item/clothing/mask/vape/Initialize(mapload, param_color)
+ . = ..()
+ create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it
+ reagents.add_reagent(/datum/reagent/drug/nicotine, 50)
+ if(!icon_state)
+ if(!param_color)
+ param_color = pick("red","blue","black","white","green","purple","yellow","orange")
+ icon_state = "[param_color]_vape"
+ item_state = "[param_color]_vape"
+
+/obj/item/clothing/mask/vape/attackby(obj/item/O, mob/user, params)
+ if(O.tool_behaviour == TOOL_SCREWDRIVER)
+ if(!screw)
+ screw = TRUE
+ to_chat(user, "You open the cap on [src].")
+ ENABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
+ if(obj_flags & EMAGGED)
+ add_overlay("vapeopen_high")
+ else if(super)
+ add_overlay("vapeopen_med")
+ else
+ add_overlay("vapeopen_low")
+ else
+ screw = FALSE
+ to_chat(user, "You close the cap on [src].")
+ DISABLE_BITFIELD(reagents.reagents_holder_flags, OPENCONTAINER)
+ cut_overlays()
+
+ if(O.tool_behaviour == TOOL_MULTITOOL)
+ if(screw && !(obj_flags & EMAGGED))//also kinky
+ if(!super)
+ cut_overlays()
+ super = TRUE
+ to_chat(user, "You increase the voltage of [src].")
+ add_overlay("vapeopen_med")
+ else
+ cut_overlays()
+ super = FALSE
+ to_chat(user, "You decrease the voltage of [src].")
+ add_overlay("vapeopen_low")
+
+ if(screw && (obj_flags & EMAGGED))
+ to_chat(user, "[src] can't be modified!")
+
+ else
+ ..()
+
+/obj/item/clothing/mask/vape/emag_act(mob/user)// I WON'T REGRET WRITTING THIS, SURLY.
+ if(screw)
+ if(!(obj_flags & EMAGGED))
+ cut_overlays()
+ obj_flags |= EMAGGED
+ super = FALSE
+ to_chat(user, "You maximize the voltage of [src].")
+ add_overlay("vapeopen_high")
+ var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread //for effect
+ sp.set_up(5, 1, src)
+ sp.start()
+ else
+ to_chat(user, "[src] is already emagged!")
+ else
+ to_chat(user, "You need to open the cap to do that.")
+
+/obj/item/clothing/mask/vape/attack_self(mob/user)
+ if(reagents.total_volume > 0)
+ to_chat(user, "You empty [src] of all reagents.")
+ reagents.clear_reagents()
+
+/obj/item/clothing/mask/vape/equipped(mob/user, slot)
+ if(slot == SLOT_WEAR_MASK)
+ if(!screw)
+ to_chat(user, "You start puffing on the vape.")
+ DISABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
+ START_PROCESSING(SSobj, src)
+ else //it will not start if the vape is opened.
+ to_chat(user, "You need to close the cap first!")
+
+/obj/item/clothing/mask/vape/dropped(mob/user)
+ var/mob/living/carbon/C = user
+ if(C.get_item_by_slot(SLOT_WEAR_MASK) == src)
+ ENABLE_BITFIELD(reagents.reagents_holder_flags, NO_REACT)
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/clothing/mask/vape/proc/hand_reagents()//had to rename to avoid duplicate error
+ if(reagents.total_volume)
+ if(iscarbon(loc))
+ var/mob/living/carbon/C = loc
+ if (src == C.wear_mask) // if it's in the human/monkey mouth, transfer reagents to the mob
+ var/fraction = min(REAGENTS_METABOLISM/reagents.total_volume, 1) //this will react instantly, making them a little more dangerous than cigarettes
+ reagents.reaction(C, INGEST, fraction)
+ if(!reagents.trans_to(C, REAGENTS_METABOLISM))
+ reagents.remove_any(REAGENTS_METABOLISM)
+ if(reagents.get_reagent_amount(/datum/reagent/fuel))
+ //HOT STUFF
+ C.fire_stacks = 2
+ C.IgniteMob()
+
+ if(reagents.get_reagent_amount(/datum/reagent/toxin/plasma)) // the plasma explodes when exposed to fire
+ var/datum/effect_system/reagents_explosion/e = new()
+ e.set_up(round(reagents.get_reagent_amount(/datum/reagent/toxin/plasma) / 2.5, 1), get_turf(src), 0, 0)
+ e.start()
+ qdel(src)
+ return
+ reagents.remove_any(REAGENTS_METABOLISM)
+
+/obj/item/clothing/mask/vape/process()
+ var/mob/living/M = loc
+
+ if(isliving(loc))
+ M.IgniteMob()
+
+ vapetime++
+
+ if(!reagents.total_volume)
+ if(ismob(loc))
+ to_chat(M, "[src] is empty!")
+ STOP_PROCESSING(SSobj, src)
+ //it's reusable so it won't unequip when empty
+ return
+ //open flame removed because vapes are a closed system, they wont light anything on fire
+
+ if(super && vapetime > 3)//Time to start puffing those fat vapes, yo.
+ var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
+ s.set_up(reagents, 1, 24, loc)
+ s.start()
+ vapetime = 0
+
+ if((obj_flags & EMAGGED) && vapetime > 3)
+ var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
+ s.set_up(reagents, 4, 24, loc)
+ s.start()
+ vapetime = 0
+ if(prob(5))//small chance for the vape to break and deal damage if it's emagged
+ playsound(get_turf(src), 'sound/effects/pop_expl.ogg', 50, 0)
+ M.apply_damage(20, BURN, BODY_ZONE_HEAD)
+ M.Knockdown(300, 1, 0)
+ var/datum/effect_system/spark_spread/sp = new /datum/effect_system/spark_spread
+ sp.set_up(5, 1, src)
+ sp.start()
+ to_chat(M, "[src] suddenly explodes in your mouth!")
+ qdel(src)
+ return
+
+ if(reagents && reagents.total_volume)
+ hand_reagents()
+
+///////////////
+/////BONGS/////
+///////////////
+
+/obj/item/bong
+ name = "bong"
+ desc = "A water bong used for smoking dried plants."
+ icon = 'icons/obj/bongs.dmi'
+ icon_state = null
+ item_state = null
+ w_class = WEIGHT_CLASS_NORMAL
+ light_color = "#FFCC66"
+ var/icon_off = "bong"
+ var/icon_on = "bong_lit"
+ var/chem_volume = 100
+ var/last_used_time //for cooldown
+ var/firecharges = 0 //used for counting how many hits can be taken before the flame goes out
+ var/list/list_reagents = list() //For the base reagents bongs could get
+
+
+/obj/item/bong/Initialize()
+ . = ..()
+ create_reagents(chem_volume, NO_REACT) // so it doesn't react until you light it
+ reagents.add_reagent_list(list_reagents)
+ icon_state = icon_off
+
+/obj/item/bong/attackby(obj/item/O, mob/user, params)
+ . = ..()
+ //If we're using a dried plant..
+ if(istype(O,/obj/item/reagent_containers/food/snacks))
+ var/obj/item/reagent_containers/food/snacks/DP = O
+ if (DP.dry)
+ //Nothing if our bong is full
+ if (reagents.holder_full())
+ user.show_message("The bowl is full!", 1)
+ return
+
+ //Transfer reagents and remove the plant
+ user.show_message("You stuff the [DP] into the [src]'s bowl.", 1)
+ DP.reagents.trans_to(src, 100)
+ qdel(DP)
+ return
+ else
+ user.show_message("[DP] must be dried first!", 1)
+ return
+
+ if (O.heat > 500)
+ if (reagents && reagents.total_volume) //if there's stuff in the bong
+ var/lighting_text = O.ignition_effect(src, user)
+ if(lighting_text)
+ //Logic regarding igniting it on
+ if (firecharges == 0)
+ user.show_message("You light the [src] with the [O]!", 1)
+ bongturnon()
+ else
+ user.show_message("You rekindle [src]'s flame with the [O]!", 1)
+
+ firecharges = 1
+ return
+ else
+ user.show_message("There's nothing to light up in the bowl.", 1)
+ return
+
+/obj/item/bong/CtrlShiftClick(mob/user) //empty reagents on alt click
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+
+ if (reagents && reagents.total_volume)
+ user.show_message("You empty the [src].", 1)
+ reagents.clear_reagents()
+ if(firecharges)
+ firecharges = 0
+ bongturnoff()
+ else
+ user.show_message("The [src] is already empty.", 1)
+
+/obj/item/bong/AltClick(mob/user)
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+
+ if(firecharges)
+ firecharges = 0
+ bongturnoff()
+ user.show_message("You quench the flame.", 1)
+
+/obj/item/bong/examine(mob/user)
+ . = ..()
+ if(!reagents.total_volume)
+ . += "The bowl is empty."
+ else if (reagents.total_volume > 80)
+ . += "The bowl is filled to the brim."
+ else if (reagents.total_volume > 40)
+ . += "The bowl has plenty weed in it."
+ else
+ . += "The bowl has some weed in it."
+
+ . += "Ctrl+Shift-click to empty."
+ . += "Alt-click to extinguish."
+
+/obj/item/bong/ignition_effect(atom/A, mob/user)
+ if(firecharges)
+ . = "[user] lights [A] off of the [src]."
+ else
+ . = ""
+
+/obj/item/bong/attack(mob/living/carbon/M, mob/living/carbon/user, obj/target)
+ //if it's lit up, some stuff in the bowl and the user is a target, and we're not on cooldown
+ if (!reagents)
+ return
+
+ if (M ==! user)
+ return
+
+ if(user.is_mouth_covered(head_only = 1))
+ to_chat(user, "Remove your headgear first.")
+ return
+
+ if(user.is_mouth_covered(mask_only = 1))
+ to_chat(user, "Remove your mask first.")
+ return
+
+ if (!reagents.total_volume)
+ to_chat(user, "There's nothing in the bowl.")
+ return
+
+ if (!firecharges)
+ to_chat(user, "You have to light it up first.")
+ return
+
+ if (last_used_time + 30 < world.time)
+ var/hit_strength
+ var/noise
+ var/hittext = ""
+ //if the intent is help then you take a small hit, else a big one
+ if (user.a_intent == INTENT_HARM)
+ hit_strength = 2
+ noise = 100
+ hittext = "big hit"
+ else
+ hit_strength = 1
+ noise = 70
+ hittext = "hit"
+ //bubbling sound
+ playsound(user.loc,'sound/effects/bonghit.ogg', noise, 1)
+
+ last_used_time = world.time
+
+ //message
+ user.visible_message("[user] begins to take a "+ hittext +" from the [src]!", \
+ "You begin to take a "+ hittext +" from [src].")
+
+ //we take a hit here, after an uninterrupted delay
+ if(do_after(user, 25, target = user))
+ if (reagents && reagents.total_volume)
+ var/fraction = 12 * hit_strength
+
+ var/datum/effect_system/smoke_spread/chem/smoke_machine/s = new
+ s.set_up(reagents, hit_strength, 18, user.loc)
+ s.start()
+
+ reagents.reaction(user, INGEST, fraction)
+ if(!reagents.trans_to(user, fraction))
+ reagents.remove_any(fraction)
+
+ if (hit_strength == 2 && prob(15))
+ user.emote("cough")
+ user.adjustOxyLoss(15)
+
+ //playsound(user.loc, 'sound/effects/smoke.ogg', 10, 1, -3)
+
+ user.visible_message("[user] takes a "+ hittext +" from the [src]!", \
+ "You take a "+ hittext +" from [src].")
+
+ firecharges = firecharges - 1
+ if (firecharges == 0)
+ bongturnoff()
+ if (!reagents.total_volume)
+ firecharges = 0
+ bongturnoff()
+
+
+
+/obj/item/bong/proc/bongturnon()
+ icon_state = icon_on
+ set_light(3, 0.8)
+
+/obj/item/bong/proc/bongturnoff()
+ icon_state = icon_off
+ set_light(0, 0.0)
+
+
+
+/obj/item/bong/coconut
+ name = "coconut bong"
+ icon_off = "coconut_bong"
+ icon_on = "coconut_bong_lit"
+ desc = "A water bong used for smoking dried plants. This one's made out of a coconut and some bamboo"
diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm
index 8106733a..5f87f9ff 100644
--- a/code/game/objects/items/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/circuitboards/circuitboard.dm
@@ -12,7 +12,7 @@
righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
materials = list(MAT_GLASS=1000)
w_class = WEIGHT_CLASS_SMALL
- grind_results = list("silicon" = 20)
+ grind_results = list(/datum/reagent/silicon = 20)
var/build_path = null
/obj/item/circuitboard/proc/apply_default_parts(obj/machinery/M)
diff --git a/code/game/objects/items/clown_items.dm b/code/game/objects/items/clown_items.dm
index 770d1805..5d3cdaa6 100644
--- a/code/game/objects/items/clown_items.dm
+++ b/code/game/objects/items/clown_items.dm
@@ -1,171 +1,171 @@
-/* Clown Items
- * Contains:
- * Soap
- * Bike Horns
- * Air Horns
- * Canned Laughter
- */
-
-/*
- * Soap
- */
-
-/obj/item/soap
- name = "soap"
- desc = "A cheap bar of soap. Doesn't smell."
- gender = PLURAL
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "soap"
- lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
- w_class = WEIGHT_CLASS_TINY
- item_flags = NOBLUDGEON
- throwforce = 0
- throw_speed = 3
- throw_range = 7
- grind_results = list("lye" = 10)
- var/cleanspeed = 50 //slower than mop
- force_string = "robust... against germs"
-
-/obj/item/soap/Initialize()
- . = ..()
- AddComponent(/datum/component/slippery, 80)
-
-/obj/item/soap/nanotrasen
- desc = "A Kinaris.Co brand bar of soap. Smells of plasma."
- icon_state = "soapnt"
-
-/obj/item/soap/homemade
- desc = "A homemade bar of soap. Smells of... well...."
- icon_state = "soapgibs"
- cleanspeed = 45 // a little faster to reward chemists for going to the effort
-
-/obj/item/soap/deluxe
- desc = "A deluxe Waffle Co. brand bar of soap. Smells of high-class luxury."
- icon_state = "soapdeluxe"
- cleanspeed = 40 //same speed as mop because deluxe -- captain gets one of these
-
-/obj/item/soap/syndie
- desc = "An untrustworthy bar of soap made of strong chemical agents that dissolve blood faster."
- icon_state = "soapsyndie"
- cleanspeed = 10 //much faster than mop so it is useful for traitors who want to clean crime scenes
-
-/obj/item/soap/suicide_act(mob/user)
- user.say(";FFFFFFFFFFFFFFFFUUUUUUUDGE!!", forced="soap suicide")
- user.visible_message("[user] lifts [src] to [user.p_their()] mouth and gnaws on it furiously, producing a thick froth! [user.p_they(TRUE)]'ll never get that BB gun now!")
- new /obj/effect/particle_effect/foam(loc)
- return (TOXLOSS)
-
-/obj/item/soap/afterattack(atom/target, mob/user, proximity)
- . = ..()
- if(!proximity || !check_allowed_items(target))
- return
- //I couldn't feasibly fix the overlay bugs caused by cleaning items we are wearing.
- //So this is a workaround. This also makes more sense from an IC standpoint. ~Carn
- if(user.client && ((target in user.client.screen) && !user.is_holding(target)))
- to_chat(user, "You need to take that [target.name] off before cleaning it!")
- else if(istype(target, /obj/effect/decal/cleanable))
- user.visible_message("[user] begins to scrub \the [target.name] out with [src].", "You begin to scrub \the [target.name] out with [src]...")
- if(do_after(user, src.cleanspeed, target = target))
- to_chat(user, "You scrub \the [target.name] out.")
- qdel(target)
- else if(ishuman(target) && user.zone_selected == BODY_ZONE_PRECISE_MOUTH)
- var/mob/living/carbon/human/H = user
- user.visible_message("\the [user] washes \the [target]'s mouth out with [src.name]!", "You wash \the [target]'s mouth out with [src.name]!") //washes mouth out with soap sounds better than 'the soap' here
- H.lip_style = null //removes lipstick
- H.update_body()
- return
- else if(istype(target, /obj/structure/window))
- user.visible_message("[user] begins to clean \the [target.name] with [src]...", "You begin to clean \the [target.name] with [src]...")
- if(do_after(user, src.cleanspeed, target = target))
- to_chat(user, "You clean \the [target.name].")
- target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- target.set_opacity(initial(target.opacity))
- else
- user.visible_message("[user] begins to clean \the [target.name] with [src]...", "You begin to clean \the [target.name] with [src]...")
- if(do_after(user, src.cleanspeed, target = target))
- to_chat(user, "You clean \the [target.name].")
- var/obj/effect/decal/cleanable/C = locate() in target
- qdel(C)
- target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
- SEND_SIGNAL(target, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
- target.wash_cream()
- return
-
-
-/*
- * Bike Horns
- */
-
-/obj/item/bikehorn
- name = "bike horn"
- desc = "A horn off of a bicycle."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "bike_horn"
- item_state = "bike_horn"
- lefthand_file = 'icons/mob/inhands/equipment/horns_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/horns_righthand.dmi'
- throwforce = 0
- hitsound = null //To prevent tap.ogg playing, as the item lacks of force
- w_class = WEIGHT_CLASS_TINY
- throw_speed = 3
- throw_range = 7
- attack_verb = list("HONKED")
-
-/obj/item/bikehorn/Initialize()
- . = ..()
- AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
-
-/obj/item/bikehorn/attack(mob/living/carbon/M, mob/living/carbon/user)
- SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "honk", /datum/mood_event/honk)
- return ..()
-
-/obj/item/bikehorn/suicide_act(mob/user)
- user.visible_message("[user] solemnly points the horn at [user.p_their()] temple! It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(src, 'sound/items/bikehorn.ogg', 50, 1)
- return (BRUTELOSS)
-
-//air horn
-/obj/item/bikehorn/airhorn
- name = "air horn"
- desc = "Damn son, where'd you find this?"
- icon_state = "air_horn"
-
-/obj/item/bikehorn/airhorn/Initialize()
- . = ..()
- AddComponent(/datum/component/squeak, list('sound/items/airhorn2.ogg'=1), 50)
-
-//golden bikehorn
-/obj/item/bikehorn/golden
- name = "golden bike horn"
- desc = "Golden? Clearly, it's made with bananium! Honk!"
- icon_state = "gold_horn"
- item_state = "gold_horn"
- var/flip_cooldown = 0
-
-/obj/item/bikehorn/golden/attack()
- if(flip_cooldown < world.time)
- flip_mobs()
- return ..()
-
-/obj/item/bikehorn/golden/attack_self(mob/user)
- if(flip_cooldown < world.time)
- flip_mobs()
- ..()
-
-/obj/item/bikehorn/golden/proc/flip_mobs(mob/living/carbon/M, mob/user)
- var/turf/T = get_turf(src)
- for(M in ohearers(7, T))
- if(ishuman(M) && M.can_hear())
- var/mob/living/carbon/human/H = M
- if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
- continue
- M.emote("flip")
- flip_cooldown = world.time + 7
-
-//canned laughter
-/obj/item/reagent_containers/food/drinks/soda_cans/canned_laughter
- name = "Canned Laughter"
- desc = "Just looking at this makes you want to giggle."
- icon_state = "laughter"
- list_reagents = list("laughter" = 50)
\ No newline at end of file
+/* Clown Items
+ * Contains:
+ * Soap
+ * Bike Horns
+ * Air Horns
+ * Canned Laughter
+ */
+
+/*
+ * Soap
+ */
+
+/obj/item/soap
+ name = "soap"
+ desc = "A cheap bar of soap. Doesn't smell."
+ gender = PLURAL
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "soap"
+ lefthand_file = 'icons/mob/inhands/equipment/custodial_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/custodial_righthand.dmi'
+ w_class = WEIGHT_CLASS_TINY
+ item_flags = NOBLUDGEON
+ throwforce = 0
+ throw_speed = 3
+ throw_range = 7
+ grind_results = list(/datum/reagent/lye = 10)
+ var/cleanspeed = 50 //slower than mop
+ force_string = "robust... against germs"
+
+/obj/item/soap/Initialize()
+ . = ..()
+ AddComponent(/datum/component/slippery, 80)
+
+/obj/item/soap/nanotrasen
+ desc = "A Kinaris.Co brand bar of soap. Smells of plasma."
+ icon_state = "soapnt"
+
+/obj/item/soap/homemade
+ desc = "A homemade bar of soap. Smells of... well...."
+ icon_state = "soapgibs"
+ cleanspeed = 45 // a little faster to reward chemists for going to the effort
+
+/obj/item/soap/deluxe
+ desc = "A deluxe Waffle Co. brand bar of soap. Smells of high-class luxury."
+ icon_state = "soapdeluxe"
+ cleanspeed = 40 //same speed as mop because deluxe -- captain gets one of these
+
+/obj/item/soap/syndie
+ desc = "An untrustworthy bar of soap made of strong chemical agents that dissolve blood faster."
+ icon_state = "soapsyndie"
+ cleanspeed = 10 //much faster than mop so it is useful for traitors who want to clean crime scenes
+
+/obj/item/soap/suicide_act(mob/user)
+ user.say(";FFFFFFFFFFFFFFFFUUUUUUUDGE!!", forced="soap suicide")
+ user.visible_message("[user] lifts [src] to [user.p_their()] mouth and gnaws on it furiously, producing a thick froth! [user.p_they(TRUE)]'ll never get that BB gun now!")
+ new /obj/effect/particle_effect/foam(loc)
+ return (TOXLOSS)
+
+/obj/item/soap/afterattack(atom/target, mob/user, proximity)
+ . = ..()
+ if(!proximity || !check_allowed_items(target))
+ return
+ //I couldn't feasibly fix the overlay bugs caused by cleaning items we are wearing.
+ //So this is a workaround. This also makes more sense from an IC standpoint. ~Carn
+ if(user.client && ((target in user.client.screen) && !user.is_holding(target)))
+ to_chat(user, "You need to take that [target.name] off before cleaning it!")
+ else if(istype(target, /obj/effect/decal/cleanable))
+ user.visible_message("[user] begins to scrub \the [target.name] out with [src].", "You begin to scrub \the [target.name] out with [src]...")
+ if(do_after(user, src.cleanspeed, target = target))
+ to_chat(user, "You scrub \the [target.name] out.")
+ qdel(target)
+ else if(ishuman(target) && user.zone_selected == BODY_ZONE_PRECISE_MOUTH)
+ var/mob/living/carbon/human/H = user
+ user.visible_message("\the [user] washes \the [target]'s mouth out with [src.name]!", "You wash \the [target]'s mouth out with [src.name]!") //washes mouth out with soap sounds better than 'the soap' here
+ H.lip_style = null //removes lipstick
+ H.update_body()
+ return
+ else if(istype(target, /obj/structure/window))
+ user.visible_message("[user] begins to clean \the [target.name] with [src]...", "You begin to clean \the [target.name] with [src]...")
+ if(do_after(user, src.cleanspeed, target = target))
+ to_chat(user, "You clean \the [target.name].")
+ target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ target.set_opacity(initial(target.opacity))
+ else
+ user.visible_message("[user] begins to clean \the [target.name] with [src]...", "You begin to clean \the [target.name] with [src]...")
+ if(do_after(user, src.cleanspeed, target = target))
+ to_chat(user, "You clean \the [target.name].")
+ var/obj/effect/decal/cleanable/C = locate() in target
+ qdel(C)
+ target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ SEND_SIGNAL(target, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
+ target.wash_cream()
+ return
+
+
+/*
+ * Bike Horns
+ */
+
+/obj/item/bikehorn
+ name = "bike horn"
+ desc = "A horn off of a bicycle."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "bike_horn"
+ item_state = "bike_horn"
+ lefthand_file = 'icons/mob/inhands/equipment/horns_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/horns_righthand.dmi'
+ throwforce = 0
+ hitsound = null //To prevent tap.ogg playing, as the item lacks of force
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ attack_verb = list("HONKED")
+
+/obj/item/bikehorn/Initialize()
+ . = ..()
+ AddComponent(/datum/component/squeak, list('sound/items/bikehorn.ogg'=1), 50)
+
+/obj/item/bikehorn/attack(mob/living/carbon/M, mob/living/carbon/user)
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "honk", /datum/mood_event/honk)
+ return ..()
+
+/obj/item/bikehorn/suicide_act(mob/user)
+ user.visible_message("[user] solemnly points the horn at [user.p_their()] temple! It looks like [user.p_theyre()] trying to commit suicide!")
+ playsound(src, 'sound/items/bikehorn.ogg', 50, 1)
+ return (BRUTELOSS)
+
+//air horn
+/obj/item/bikehorn/airhorn
+ name = "air horn"
+ desc = "Damn son, where'd you find this?"
+ icon_state = "air_horn"
+
+/obj/item/bikehorn/airhorn/Initialize()
+ . = ..()
+ AddComponent(/datum/component/squeak, list('sound/items/airhorn2.ogg'=1), 50)
+
+//golden bikehorn
+/obj/item/bikehorn/golden
+ name = "golden bike horn"
+ desc = "Golden? Clearly, it's made with bananium! Honk!"
+ icon_state = "gold_horn"
+ item_state = "gold_horn"
+ var/flip_cooldown = 0
+
+/obj/item/bikehorn/golden/attack()
+ if(flip_cooldown < world.time)
+ flip_mobs()
+ return ..()
+
+/obj/item/bikehorn/golden/attack_self(mob/user)
+ if(flip_cooldown < world.time)
+ flip_mobs()
+ ..()
+
+/obj/item/bikehorn/golden/proc/flip_mobs(mob/living/carbon/M, mob/user)
+ var/turf/T = get_turf(src)
+ for(M in ohearers(7, T))
+ if(ishuman(M) && M.can_hear())
+ var/mob/living/carbon/human/H = M
+ if(istype(H.ears, /obj/item/clothing/ears/earmuffs))
+ continue
+ M.emote("flip")
+ flip_cooldown = world.time + 7
+
+//canned laughter
+/obj/item/reagent_containers/food/drinks/soda_cans/canned_laughter
+ name = "Canned Laughter"
+ desc = "Just looking at this makes you want to giggle."
+ icon_state = "laughter"
+ list_reagents = list(/datum/reagent/consumable/laughter = 50)
\ No newline at end of file
diff --git a/code/game/objects/items/crayons.dm b/code/game/objects/items/crayons.dm
index 6e1bac03..0176ee61 100644
--- a/code/game/objects/items/crayons.dm
+++ b/code/game/objects/items/crayons.dm
@@ -59,7 +59,7 @@
var/edible = TRUE // That doesn't mean eating it is a good idea
- var/list/reagent_contents = list("nutriment" = 1)
+ var/list/reagent_contents = list(/datum/reagent/consumable/nutriment = 1)
// If the user can toggle the colour, a la vanilla spraycan
var/can_change_colour = FALSE
@@ -485,63 +485,63 @@
icon_state = "crayonred"
paint_color = "#DA0000"
item_color = "red"
- reagent_contents = list("nutriment" = 1, "redcrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/red = 1)
/obj/item/toy/crayon/orange
icon_state = "crayonorange"
paint_color = "#FF9300"
item_color = "orange"
- reagent_contents = list("nutriment" = 1, "orangecrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/orange = 1)
/obj/item/toy/crayon/yellow
icon_state = "crayonyellow"
paint_color = "#FFF200"
item_color = "yellow"
- reagent_contents = list("nutriment" = 1, "yellowcrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/yellow = 1)
/obj/item/toy/crayon/green
icon_state = "crayongreen"
paint_color = "#A8E61D"
item_color = "green"
- reagent_contents = list("nutriment" = 1, "greencrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/green = 1)
/obj/item/toy/crayon/blue
icon_state = "crayonblue"
paint_color = "#00B7EF"
item_color = "blue"
- reagent_contents = list("nutriment" = 1, "bluecrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/blue = 1)
/obj/item/toy/crayon/purple
icon_state = "crayonpurple"
paint_color = "#DA00FF"
item_color = "purple"
- reagent_contents = list("nutriment" = 1, "purplecrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/purple = 1)
/obj/item/toy/crayon/black
icon_state = "crayonblack"
paint_color = "#1C1C1C" //Not completely black because total black looks bad. So Mostly Black.
item_color = "black"
- reagent_contents = list("nutriment" = 1, "blackcrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/black = 1)
/obj/item/toy/crayon/white
icon_state = "crayonwhite"
paint_color = "#FFFFFF"
item_color = "white"
- reagent_contents = list("nutriment" = 1, "whitecrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/white = 1)
/obj/item/toy/crayon/mime
icon_state = "crayonmime"
desc = "A very sad-looking crayon."
paint_color = "#FFFFFF"
item_color = "mime"
- reagent_contents = list("nutriment" = 1, "invisiblecrayonpowder" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent/crayonpowder/invisible = 1)
charges = -1
/obj/item/toy/crayon/rainbow
icon_state = "crayonrainbow"
paint_color = "#FFF000"
item_color = "rainbow"
- reagent_contents = list("nutriment" = 1, "colorful_reagent" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/colorful_reagent = 1)
drawtype = RANDOM_ANY // just the default starter.
charges = -1
@@ -621,7 +621,7 @@
can_change_colour = TRUE
gang = TRUE //Gang check is true for all things upon the honored hierarchy of spraycans, except those that are FALSE.
- reagent_contents = list("welding_fuel" = 1, "ethanol" = 1)
+ reagent_contents = list(/datum/reagent/fuel = 1, /datum/reagent/consumable/ethanol = 1)
pre_noise = TRUE
post_noise = FALSE
@@ -778,7 +778,7 @@
volume_multiplier = 25
charges = 100
- reagent_contents = list("clf3" = 1)
+ reagent_contents = list(/datum/reagent/clf3 = 1)
actually_paints = FALSE
paint_color = "#000000"
@@ -791,7 +791,7 @@
use_overlays = FALSE
gang = FALSE
- reagent_contents = list("lube" = 1, "banana" = 1)
+ reagent_contents = list(/datum/reagent/lube = 1, /datum/reagent/consumable/banana = 1)
volume_multiplier = 5
/obj/item/toy/crayon/spraycan/lubecan/isValidSurface(surface)
@@ -811,7 +811,7 @@
pre_noise = FALSE
post_noise = FALSE
- reagent_contents = list("nothing" = 1, "mutetoxin" = 1)
+ reagent_contents = list(/datum/reagent/consumable/nothing = 1, /datum/reagent/toxin/mutetoxin = 1)
/obj/item/toy/crayon/spraycan/gang
charges = 20 // Charges back to 20, which is the default value for them.
diff --git a/code/game/objects/items/devices/dogborg_sleeper.dm b/code/game/objects/items/devices/dogborg_sleeper.dm
index ca1648bb..6db2e9af 100644
--- a/code/game/objects/items/devices/dogborg_sleeper.dm
+++ b/code/game/objects/items/devices/dogborg_sleeper.dm
@@ -13,7 +13,8 @@
var/cleaning = FALSE
var/cleaning_cycles = 10
var/patient_laststat = null
- var/list/injection_chems = list("antitoxin", "epinephrine", "salbutamol", "bicaridine", "kelotane")
+ var/list/injection_chems = list(/datum/reagent/medicine/antitoxin, /datum/reagent/medicine/epinephrine,
+ /datum/reagent/medicine/salbutamol, /datum/reagent/medicine/bicaridine, /datum/reagent/medicine/kelotane)
var/eject_port = "ingestion"
var/escape_in_progress = FALSE
var/message_cooldown
@@ -184,7 +185,7 @@
data["chem"] = list()
for(var/chem in injection_chems)
var/datum/reagent/R = GLOB.chemical_reagents_list[chem]
- data["chem"] += list(list("name" = R.name, "id" = R.id))
+ data["chem"] += list(list("name" = R.name, "id" = R.type))
data["occupant"] = list()
var/mob/living/mob_occupant = patient
@@ -227,8 +228,8 @@
go_out()
. = TRUE
if("inject")
- var/chem = params["chem"]
- if(!patient)
+ var/chem = text2path(params["chem"])
+ if(!patient || !chem)
return
inject_chem(chem)
. = TRUE
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index 5eea5703..278d5115 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -1,545 +1,546 @@
-/obj/item/flashlight
- name = "flashlight"
- desc = "A hand-held emergency light."
- icon = 'icons/obj/lighting.dmi'
- icon_state = "flashlight"
- item_state = "flashlight"
- lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
- w_class = WEIGHT_CLASS_SMALL
- flags_1 = CONDUCT_1
- slot_flags = ITEM_SLOT_BELT
- materials = list(MAT_METAL=50, MAT_GLASS=20)
- actions_types = list(/datum/action/item_action/toggle_light)
- var/on = FALSE
- var/brightness_on = 4 //range of light when on
- var/flashlight_power = 0.8 //strength of the light when on
- light_color = "#FFCC66"
-
-/obj/item/flashlight/Initialize()
- . = ..()
- if(icon_state == "[initial(icon_state)]-on")
- on = TRUE
- update_brightness()
-
-/obj/item/flashlight/proc/update_brightness(mob/user = null)
- if(on)
- icon_state = "[initial(icon_state)]-on"
- if(flashlight_power)
- set_light(l_range = brightness_on, l_power = flashlight_power)
- else
- set_light(brightness_on)
- else
- icon_state = initial(icon_state)
- set_light(0)
-
-/obj/item/flashlight/attack_self(mob/user)
- on = !on
- update_brightness(user)
- playsound(user, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, 1)
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
- return 1
-
-/obj/item/flashlight/suicide_act(mob/living/carbon/human/user)
- if (user.eye_blind)
- user.visible_message("[user] is putting [src] close to [user.p_their()] eyes and turning it on ... but [user.p_theyre()] blind!")
- return SHAME
- user.visible_message("[user] is putting [src] close to [user.p_their()] eyes and turning it on! It looks like [user.p_theyre()] trying to commit suicide!")
- return (FIRELOSS)
-
-/obj/item/flashlight/attack(mob/living/carbon/M, mob/living/carbon/human/user)
- add_fingerprint(user)
- if(istype(M) && on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))
-
- if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
- return ..() //just hit them in the head
-
- if(!user.IsAdvancedToolUser())
- to_chat(user, "You don't have the dexterity to do this!")
- return
-
- if(!M.get_bodypart(BODY_ZONE_HEAD))
- to_chat(user, "[M] doesn't have a head!")
- return
-
- if(flashlight_power < 0.3)
- to_chat(user, "\The [src] isn't bright enough to see anything! ")
- return
-
- switch(user.zone_selected)
- if(BODY_ZONE_PRECISE_EYES)
- if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES))
- to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first.")
- return
-
- var/obj/item/organ/eyes/E = M.getorganslot(ORGAN_SLOT_EYES)
- if(!E)
- to_chat(user, "[M] doesn't have any eyes!")
- return
-
- if(M == user) //they're using it on themselves
- if(M.flash_act(visual = 1))
- M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes! Trippy!")
- else
- M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes.")
- else
- user.visible_message("[user] directs [src] to [M]'s eyes.", \
- "You direct [src] to [M]'s eyes.")
- if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_BLIND)) || !M.flash_act(visual = 1)) //mob is dead or fully blind
- to_chat(user, "[M]'s pupils don't react to the light!")
- else if(M.dna && M.dna.check_mutation(XRAY)) //mob has X-ray vision
- to_chat(user, "[M]'s pupils give an eerie glow!")
- else //they're okay!
- to_chat(user, "[M]'s pupils narrow.")
-
- if(BODY_ZONE_PRECISE_MOUTH)
-
- if(M.is_mouth_covered())
- to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first.")
- return
-
- var/their = M.p_their()
-
- var/list/mouth_organs = new
- for(var/obj/item/organ/O in M.internal_organs)
- if(O.zone == BODY_ZONE_PRECISE_MOUTH)
- mouth_organs.Add(O)
- var/organ_list = ""
- var/organ_count = LAZYLEN(mouth_organs)
- if(organ_count)
- for(var/I in 1 to organ_count)
- if(I > 1)
- if(I == mouth_organs.len)
- organ_list += ", and "
- else
- organ_list += ", "
- var/obj/item/organ/O = mouth_organs[I]
- organ_list += (O.gender == "plural" ? O.name : "\an [O.name]")
-
- var/pill_count = 0
- for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions)
- pill_count++
-
- if(M == user)
- var/can_use_mirror = FALSE
- if(isturf(user.loc))
- var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc)
- if(mirror)
- switch(user.dir)
- if(NORTH)
- can_use_mirror = mirror.pixel_y > 0
- if(SOUTH)
- can_use_mirror = mirror.pixel_y < 0
- if(EAST)
- can_use_mirror = mirror.pixel_x > 0
- if(WEST)
- can_use_mirror = mirror.pixel_x < 0
-
- M.visible_message("[M] directs [src] to [their] mouth.", \
- "You point [src] into your mouth.")
- if(!can_use_mirror)
- to_chat(user, "You can't see anything without a mirror.")
- return
- if(organ_count)
- to_chat(user, "Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list].")
- else
- to_chat(user, "There's nothing inside your mouth.")
- if(pill_count)
- to_chat(user, "You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""].")
-
- else
- user.visible_message("[user] directs [src] to [M]'s mouth.",\
- "You direct [src] to [M]'s mouth.")
- if(organ_count)
- to_chat(user, "Inside [their] mouth [organ_count > 1 ? "are" : "is"] [organ_list].")
- else
- to_chat(user, "[M] doesn't have any organs in [their] mouth.")
- if(pill_count)
- to_chat(user, "[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [their] teeth.")
-
- else
- return ..()
-
-/obj/item/flashlight/pen
- name = "penlight"
- desc = "A pen-sized light, used by medical staff. It can also be used to create a hologram to alert people of incoming medical assistance."
- icon_state = "penlight"
- item_state = ""
- flags_1 = CONDUCT_1
- brightness_on = 2
- light_color = "#FFDDCC"
- flashlight_power = 0.3
- var/holo_cooldown = 0
-
-/obj/item/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag)
- . = ..()
- if(!proximity_flag)
- if(holo_cooldown > world.time)
- to_chat(user, "[src] is not ready yet!")
- return
- var/T = get_turf(target)
- if(locate(/mob/living) in T)
- new /obj/effect/temp_visual/medical_holosign(T,user) //produce a holographic glow
- holo_cooldown = world.time + 100
- return
-
-/obj/effect/temp_visual/medical_holosign
- name = "medical holosign"
- desc = "A small holographic glow that indicates a medic is coming to treat a patient."
- icon_state = "medi_holo"
- duration = 30
-
-/obj/effect/temp_visual/medical_holosign/Initialize(mapload, creator)
- . = ..()
- playsound(loc, 'sound/machines/ping.ogg', 50, 0) //make some noise!
- if(creator)
- visible_message("[creator] created a medical hologram!")
-
-
-/obj/item/flashlight/seclite
- name = "seclite"
- desc = "A robust flashlight used by security."
- icon_state = "seclite"
- item_state = "seclite"
- lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
- force = 9 // Not as good as a stun baton.
- brightness_on = 5 // A little better than the standard flashlight.
- light_color = "#CDDDFF"
- flashlight_power = 0.9
- hitsound = 'sound/weapons/genhit1.ogg'
-
-// the desk lamps are a bit special
-/obj/item/flashlight/lamp
- name = "desk lamp"
- desc = "A desk lamp with an adjustable mount."
- icon_state = "lamp"
- item_state = "lamp"
- lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/items_righthand.dmi'
- force = 10
- brightness_on = 5
- light_color = "#FFDDBB"
- w_class = WEIGHT_CLASS_BULKY
- flags_1 = CONDUCT_1
- materials = list()
- on = TRUE
-
-
-// green-shaded desk lamp
-/obj/item/flashlight/lamp/green
- desc = "A classic green-shaded desk lamp."
- icon_state = "lampgreen"
- item_state = "lampgreen"
-
-
-
-/obj/item/flashlight/lamp/verb/toggle_light()
- set name = "Toggle light"
- set category = "Object"
- set src in oview(1)
-
- if(!usr.stat)
- attack_self(usr)
-
-//Bananalamp
-/obj/item/flashlight/lamp/bananalamp
- name = "banana lamp"
- desc = "Only a clown would think to make a ghetto banana-shaped lamp. Even has a goofy pullstring."
- icon_state = "bananalamp"
- item_state = "bananalamp"
-
-// FLARES
-
-/obj/item/flashlight/flare
- name = "flare"
- desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'."
- w_class = WEIGHT_CLASS_SMALL
- brightness_on = 7 // Pretty bright.
- light_color = "#FA421A"
- icon_state = "flare"
- item_state = "flare"
- actions_types = list()
- var/fuel = 0
- var/on_damage = 7
- var/produce_heat = 1500
- heat = 1000
- light_color = LIGHT_COLOR_FLARE
- grind_results = list("sulfur" = 15)
-
-/obj/item/flashlight/flare/New()
- fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.
- ..()
-
-/obj/item/flashlight/flare/process()
- open_flame(heat)
- fuel = max(fuel - 1, 0)
- if(!fuel || !on)
- turn_off()
- if(!fuel)
- icon_state = "[initial(icon_state)]-empty"
- STOP_PROCESSING(SSobj, src)
-
-/obj/item/flashlight/flare/ignition_effect(atom/A, mob/user)
- if(fuel && on)
- . = "[user] lights [A] with [src] like a real \
- badass."
- else
- . = ""
-
-/obj/item/flashlight/flare/proc/turn_off()
- on = FALSE
- force = initial(src.force)
- damtype = initial(src.damtype)
- if(ismob(loc))
- var/mob/U = loc
- update_brightness(U)
- else
- update_brightness(null)
-
-/obj/item/flashlight/flare/update_brightness(mob/user = null)
- ..()
- if(on)
- item_state = "[initial(item_state)]-on"
- else
- item_state = "[initial(item_state)]"
-
-/obj/item/flashlight/flare/attack_self(mob/user)
-
- // Usual checks
- if(!fuel)
- to_chat(user, "[src] is out of fuel!")
- return
- if(on)
- to_chat(user, "[src] is already on.")
- return
-
- . = ..()
- // All good, turn it on.
- if(.)
- user.visible_message("[user] lights \the [src].", "You light \the [src]!")
- force = on_damage
- damtype = "fire"
- START_PROCESSING(SSobj, src)
-
-/obj/item/flashlight/flare/is_hot()
- return on * heat
-
-/obj/item/flashlight/flare/torch
- name = "torch"
- desc = "A torch fashioned from some leaves and a log."
- w_class = WEIGHT_CLASS_BULKY
- brightness_on = 4
- light_color = "#FAA44B"
- icon_state = "torch"
- item_state = "torch"
- lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/items_righthand.dmi'
- light_color = LIGHT_COLOR_ORANGE
- on_damage = 10
- slot_flags = null
-
-/obj/item/flashlight/lantern
- name = "lantern"
- icon_state = "lantern"
- item_state = "lantern"
- lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
- desc = "A mining lantern."
- brightness_on = 6 // luminosity when on
- light_color = "#FFAA44"
- flashlight_power = 0.75
-
-
-/obj/item/flashlight/slime
- gender = PLURAL
- name = "glowing slime extract"
- desc = "Extract from a yellow slime. It emits a strong light when squeezed."
- icon = 'icons/obj/lighting.dmi'
- icon_state = "slime"
- item_state = "slime"
- w_class = WEIGHT_CLASS_SMALL
- slot_flags = ITEM_SLOT_BELT
- materials = list()
- brightness_on = 6 //luminosity when on
- light_color = "#FFEEAA"
- flashlight_power = 0.6
-
-/obj/item/flashlight/emp
- var/emp_max_charges = 4
- var/emp_cur_charges = 4
- var/charge_tick = 0
-
-
-/obj/item/flashlight/emp/New()
- ..()
- START_PROCESSING(SSobj, src)
-
-/obj/item/flashlight/emp/Destroy()
- STOP_PROCESSING(SSobj, src)
- . = ..()
-
-/obj/item/flashlight/emp/process()
- charge_tick++
- if(charge_tick < 10)
- return FALSE
- charge_tick = 0
- emp_cur_charges = min(emp_cur_charges+1, emp_max_charges)
- return TRUE
-
-/obj/item/flashlight/emp/attack(mob/living/M, mob/living/user)
- if(on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH)) // call original attack when examining organs
- ..()
- return
-
-/obj/item/flashlight/emp/afterattack(atom/movable/A, mob/user, proximity)
- . = ..()
- if(!proximity)
- return
-
- if(emp_cur_charges > 0)
- emp_cur_charges -= 1
-
- if(ismob(A))
- var/mob/M = A
- log_combat(user, M, "attacked", "EMP-light")
- M.visible_message("[user] blinks \the [src] at \the [A].", \
- "[user] blinks \the [src] at you.")
- else
- A.visible_message("[user] blinks \the [src] at \the [A].")
- to_chat(user, "\The [src] now has [emp_cur_charges] charge\s.")
- A.emp_act(EMP_HEAVY)
- else
- to_chat(user, "\The [src] needs time to recharge!")
- return
-
-/obj/item/flashlight/emp/debug //for testing emp_act()
- name = "debug EMP flashlight"
- emp_max_charges = 100
- emp_cur_charges = 100
-
-// Glowsticks, in the uncomfortable range of similar to flares,
-// but not similar enough to make it worth a refactor
-/obj/item/flashlight/glowstick
- name = "glowstick"
- desc = "A military-grade glowstick."
- w_class = WEIGHT_CLASS_SMALL
- brightness_on = 4
- color = LIGHT_COLOR_GREEN
- icon_state = "glowstick"
- item_state = "glowstick"
- grind_results = list("phenol" = 15, "hydrogen" = 10, "oxygen" = 5) //Meth-in-a-stick
- var/fuel = 0
-
-/obj/item/flashlight/glowstick/Initialize()
- fuel = rand(1600, 2000)
- light_color = color
- . = ..()
-
-/obj/item/flashlight/glowstick/Destroy()
- STOP_PROCESSING(SSobj, src)
- . = ..()
-
-/obj/item/flashlight/glowstick/process()
- fuel = max(fuel - 1, 0)
- if(!fuel)
- turn_off()
- STOP_PROCESSING(SSobj, src)
- update_icon()
-
-/obj/item/flashlight/glowstick/proc/turn_off()
- on = FALSE
- update_icon()
-
-/obj/item/flashlight/glowstick/update_icon()
- item_state = "glowstick"
- cut_overlays()
- if(!fuel)
- icon_state = "glowstick-empty"
- cut_overlays()
- set_light(0)
- else if(on)
- var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
- glowstick_overlay.color = color
- add_overlay(glowstick_overlay)
- item_state = "glowstick-on"
- set_light(brightness_on)
- else
- icon_state = "glowstick"
- cut_overlays()
-
-/obj/item/flashlight/glowstick/attack_self(mob/user)
- if(!fuel)
- to_chat(user, "[src] is spent.")
- return
- if(on)
- to_chat(user, "[src] is already lit.")
- return
-
- . = ..()
- if(.)
- user.visible_message("[user] cracks and shakes [src].", "You crack and shake [src], turning it on!")
- activate()
-
-/obj/item/flashlight/glowstick/proc/activate()
- if(!on)
- on = TRUE
- START_PROCESSING(SSobj, src)
-
-/obj/item/flashlight/glowstick/red
- name = "red glowstick"
- color = LIGHT_COLOR_RED
-
-/obj/item/flashlight/glowstick/blue
- name = "blue glowstick"
- color = LIGHT_COLOR_BLUE
-
-/obj/item/flashlight/glowstick/cyan
- name = "cyan glowstick"
- color = LIGHT_COLOR_CYAN
-
-/obj/item/flashlight/glowstick/orange
- name = "orange glowstick"
- color = LIGHT_COLOR_ORANGE
-
-/obj/item/flashlight/glowstick/yellow
- name = "yellow glowstick"
- color = LIGHT_COLOR_YELLOW
-
-/obj/item/flashlight/glowstick/pink
- name = "pink glowstick"
- color = LIGHT_COLOR_PINK
-
-/obj/item/flashlight/spotlight //invisible lighting source
- name = "disco light"
- desc = "Groovy..."
- icon_state = null
- light_color = null
- brightness_on = 0
- flashlight_power = 1
- light_range = 0
- light_power = 10
- alpha = 0
- layer = 0
- on = TRUE
- anchored = TRUE
- var/range = null
- resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
-
-/obj/item/flashlight/flashdark
- name = "flashdark"
- desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure."
- icon_state = "flashdark"
- item_state = "flashdark"
- brightness_on = 2.5
- flashlight_power = -3
-
-/obj/item/flashlight/eyelight
- name = "eyelight"
- desc = "This shouldn't exist outside of someone's head, how are you seeing this?"
- brightness_on = 15
- flags_1 = CONDUCT_1
- item_flags = DROPDEL
- actions_types = list()
+/obj/item/flashlight
+ name = "flashlight"
+ desc = "A hand-held emergency light."
+ icon = 'icons/obj/lighting.dmi'
+ icon_state = "flashlight"
+ item_state = "flashlight"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+ flags_1 = CONDUCT_1
+ slot_flags = ITEM_SLOT_BELT
+ materials = list(MAT_METAL=50, MAT_GLASS=20)
+ actions_types = list(/datum/action/item_action/toggle_light)
+ var/on = FALSE
+ var/brightness_on = 4 //range of light when on
+ var/flashlight_power = 0.8 //strength of the light when on
+ light_color = "#FFCC66"
+
+/obj/item/flashlight/Initialize()
+ . = ..()
+ if(icon_state == "[initial(icon_state)]-on")
+ on = TRUE
+ update_brightness()
+
+/obj/item/flashlight/proc/update_brightness(mob/user = null)
+ if(on)
+ icon_state = "[initial(icon_state)]-on"
+ if(flashlight_power)
+ set_light(l_range = brightness_on, l_power = flashlight_power)
+ else
+ set_light(brightness_on)
+ else
+ icon_state = initial(icon_state)
+ set_light(0)
+
+/obj/item/flashlight/attack_self(mob/user)
+ on = !on
+ update_brightness(user)
+ playsound(user, on ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, 1)
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+ return 1
+
+/obj/item/flashlight/suicide_act(mob/living/carbon/human/user)
+ if (user.eye_blind)
+ user.visible_message("[user] is putting [src] close to [user.p_their()] eyes and turning it on ... but [user.p_theyre()] blind!")
+ return SHAME
+ user.visible_message("[user] is putting [src] close to [user.p_their()] eyes and turning it on! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (FIRELOSS)
+
+/obj/item/flashlight/attack(mob/living/carbon/M, mob/living/carbon/human/user)
+ add_fingerprint(user)
+ if(istype(M) && on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH))
+
+ if((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50)) //too dumb to use flashlight properly
+ return ..() //just hit them in the head
+
+ if(!user.IsAdvancedToolUser())
+ to_chat(user, "You don't have the dexterity to do this!")
+ return
+
+ if(!M.get_bodypart(BODY_ZONE_HEAD))
+ to_chat(user, "[M] doesn't have a head!")
+ return
+
+ if(flashlight_power < 0.3)
+ to_chat(user, "\The [src] isn't bright enough to see anything! ")
+ return
+
+ switch(user.zone_selected)
+ if(BODY_ZONE_PRECISE_EYES)
+ if((M.head && M.head.flags_cover & HEADCOVERSEYES) || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) || (M.glasses && M.glasses.flags_cover & GLASSESCOVERSEYES))
+ to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSEYES) ? "helmet" : (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSEYES) ? "mask": "glasses"] first.")
+ return
+
+ var/obj/item/organ/eyes/E = M.getorganslot(ORGAN_SLOT_EYES)
+ if(!E)
+ to_chat(user, "[M] doesn't have any eyes!")
+ return
+
+ if(M == user) //they're using it on themselves
+ if(M.flash_act(visual = 1))
+ M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes! Trippy!")
+ else
+ M.visible_message("[M] directs [src] to [M.p_their()] eyes.", "You wave the light in front of your eyes.")
+ else
+ user.visible_message("[user] directs [src] to [M]'s eyes.", \
+ "You direct [src] to [M]'s eyes.")
+ if(M.stat == DEAD || (HAS_TRAIT(M, TRAIT_BLIND)) || !M.flash_act(visual = 1)) //mob is dead or fully blind
+ to_chat(user, "[M]'s pupils don't react to the light!")
+ else if(M.dna && M.dna.check_mutation(XRAY)) //mob has X-ray vision
+ to_chat(user, "[M]'s pupils give an eerie glow!")
+ else //they're okay!
+ to_chat(user, "[M]'s pupils narrow.")
+
+ if(BODY_ZONE_PRECISE_MOUTH)
+
+ if(M.is_mouth_covered())
+ to_chat(user, "You're going to need to remove that [(M.head && M.head.flags_cover & HEADCOVERSMOUTH) ? "helmet" : "mask"] first.")
+ return
+
+ var/their = M.p_their()
+
+ var/list/mouth_organs = new
+ for(var/obj/item/organ/O in M.internal_organs)
+ if(O.zone == BODY_ZONE_PRECISE_MOUTH)
+ mouth_organs.Add(O)
+ var/organ_list = ""
+ var/organ_count = LAZYLEN(mouth_organs)
+ if(organ_count)
+ for(var/I in 1 to organ_count)
+ if(I > 1)
+ if(I == mouth_organs.len)
+ organ_list += ", and "
+ else
+ organ_list += ", "
+ var/obj/item/organ/O = mouth_organs[I]
+ organ_list += (O.gender == "plural" ? O.name : "\an [O.name]")
+
+ var/pill_count = 0
+ for(var/datum/action/item_action/hands_free/activate_pill/AP in M.actions)
+ pill_count++
+
+ if(M == user)
+ var/can_use_mirror = FALSE
+ if(isturf(user.loc))
+ var/obj/structure/mirror/mirror = locate(/obj/structure/mirror, user.loc)
+ if(mirror)
+ switch(user.dir)
+ if(NORTH)
+ can_use_mirror = mirror.pixel_y > 0
+ if(SOUTH)
+ can_use_mirror = mirror.pixel_y < 0
+ if(EAST)
+ can_use_mirror = mirror.pixel_x > 0
+ if(WEST)
+ can_use_mirror = mirror.pixel_x < 0
+
+ M.visible_message("[M] directs [src] to [their] mouth.", \
+ "You point [src] into your mouth.")
+ if(!can_use_mirror)
+ to_chat(user, "You can't see anything without a mirror.")
+ return
+ if(organ_count)
+ to_chat(user, "Inside your mouth [organ_count > 1 ? "are" : "is"] [organ_list].")
+ else
+ to_chat(user, "There's nothing inside your mouth.")
+ if(pill_count)
+ to_chat(user, "You have [pill_count] implanted pill[pill_count > 1 ? "s" : ""].")
+
+ else
+ user.visible_message("[user] directs [src] to [M]'s mouth.",\
+ "You direct [src] to [M]'s mouth.")
+ if(organ_count)
+ to_chat(user, "Inside [their] mouth [organ_count > 1 ? "are" : "is"] [organ_list].")
+ else
+ to_chat(user, "[M] doesn't have any organs in [their] mouth.")
+ if(pill_count)
+ to_chat(user, "[M] has [pill_count] pill[pill_count > 1 ? "s" : ""] implanted in [their] teeth.")
+
+ else
+ return ..()
+
+/obj/item/flashlight/pen
+ name = "penlight"
+ desc = "A pen-sized light, used by medical staff. It can also be used to create a hologram to alert people of incoming medical assistance."
+ icon_state = "penlight"
+ item_state = ""
+ flags_1 = CONDUCT_1
+ brightness_on = 2
+ light_color = "#FFDDCC"
+ flashlight_power = 0.3
+ var/holo_cooldown = 0
+
+/obj/item/flashlight/pen/afterattack(atom/target, mob/user, proximity_flag)
+ . = ..()
+ if(!proximity_flag)
+ if(holo_cooldown > world.time)
+ to_chat(user, "[src] is not ready yet!")
+ return
+ var/T = get_turf(target)
+ if(locate(/mob/living) in T)
+ new /obj/effect/temp_visual/medical_holosign(T,user) //produce a holographic glow
+ holo_cooldown = world.time + 100
+ return
+
+/obj/effect/temp_visual/medical_holosign
+ name = "medical holosign"
+ desc = "A small holographic glow that indicates a medic is coming to treat a patient."
+ icon_state = "medi_holo"
+ duration = 30
+
+/obj/effect/temp_visual/medical_holosign/Initialize(mapload, creator)
+ . = ..()
+ playsound(loc, 'sound/machines/ping.ogg', 50, 0) //make some noise!
+ if(creator)
+ visible_message("[creator] created a medical hologram!")
+
+
+/obj/item/flashlight/seclite
+ name = "seclite"
+ desc = "A robust flashlight used by security."
+ icon_state = "seclite"
+ item_state = "seclite"
+ lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi'
+ force = 9 // Not as good as a stun baton.
+ brightness_on = 5 // A little better than the standard flashlight.
+ light_color = "#CDDDFF"
+ flashlight_power = 0.9
+ hitsound = 'sound/weapons/genhit1.ogg'
+
+// the desk lamps are a bit special
+/obj/item/flashlight/lamp
+ name = "desk lamp"
+ desc = "A desk lamp with an adjustable mount."
+ icon_state = "lamp"
+ item_state = "lamp"
+ lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/items_righthand.dmi'
+ force = 10
+ brightness_on = 5
+ light_color = "#FFDDBB"
+ w_class = WEIGHT_CLASS_BULKY
+ flags_1 = CONDUCT_1
+ materials = list()
+ on = TRUE
+
+
+// green-shaded desk lamp
+/obj/item/flashlight/lamp/green
+ desc = "A classic green-shaded desk lamp."
+ icon_state = "lampgreen"
+ item_state = "lampgreen"
+
+
+
+/obj/item/flashlight/lamp/verb/toggle_light()
+ set name = "Toggle light"
+ set category = "Object"
+ set src in oview(1)
+
+ if(!usr.stat)
+ attack_self(usr)
+
+//Bananalamp
+/obj/item/flashlight/lamp/bananalamp
+ name = "banana lamp"
+ desc = "Only a clown would think to make a ghetto banana-shaped lamp. Even has a goofy pullstring."
+ icon_state = "bananalamp"
+ item_state = "bananalamp"
+
+// FLARES
+
+/obj/item/flashlight/flare
+ name = "flare"
+ desc = "A red Nanotrasen issued flare. There are instructions on the side, it reads 'pull cord, make light'."
+ w_class = WEIGHT_CLASS_SMALL
+ brightness_on = 7 // Pretty bright.
+ light_color = "#FA421A"
+ icon_state = "flare"
+ item_state = "flare"
+ actions_types = list()
+ var/fuel = 0
+ var/on_damage = 7
+ var/produce_heat = 1500
+ heat = 1000
+ light_color = LIGHT_COLOR_FLARE
+ grind_results = list(/datum/reagent/sulfur = 15)
+
+/obj/item/flashlight/flare/New()
+ fuel = rand(800, 1000) // Sorry for changing this so much but I keep under-estimating how long X number of ticks last in seconds.
+ ..()
+
+/obj/item/flashlight/flare/process()
+ open_flame(heat)
+ fuel = max(fuel - 1, 0)
+ if(!fuel || !on)
+ turn_off()
+ if(!fuel)
+ icon_state = "[initial(icon_state)]-empty"
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/flashlight/flare/ignition_effect(atom/A, mob/user)
+ if(fuel && on)
+ . = "[user] lights [A] with [src] like a real \
+ badass."
+ else
+ . = ""
+
+/obj/item/flashlight/flare/proc/turn_off()
+ on = FALSE
+ force = initial(src.force)
+ damtype = initial(src.damtype)
+ if(ismob(loc))
+ var/mob/U = loc
+ update_brightness(U)
+ else
+ update_brightness(null)
+
+/obj/item/flashlight/flare/update_brightness(mob/user = null)
+ ..()
+ if(on)
+ item_state = "[initial(item_state)]-on"
+ else
+ item_state = "[initial(item_state)]"
+
+/obj/item/flashlight/flare/attack_self(mob/user)
+
+ // Usual checks
+ if(!fuel)
+ to_chat(user, "[src] is out of fuel!")
+ return
+ if(on)
+ to_chat(user, "[src] is already on.")
+ return
+
+ . = ..()
+ // All good, turn it on.
+ if(.)
+ user.visible_message("[user] lights \the [src].", "You light \the [src]!")
+ force = on_damage
+ damtype = "fire"
+ START_PROCESSING(SSobj, src)
+
+/obj/item/flashlight/flare/is_hot()
+ return on * heat
+
+/obj/item/flashlight/flare/torch
+ name = "torch"
+ desc = "A torch fashioned from some leaves and a log."
+ w_class = WEIGHT_CLASS_BULKY
+ brightness_on = 4
+ light_color = "#FAA44B"
+ icon_state = "torch"
+ item_state = "torch"
+ lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/items_righthand.dmi'
+ light_color = LIGHT_COLOR_ORANGE
+ on_damage = 10
+ slot_flags = null
+
+/obj/item/flashlight/lantern
+ name = "lantern"
+ icon_state = "lantern"
+ item_state = "lantern"
+ lefthand_file = 'icons/mob/inhands/equipment/mining_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/mining_righthand.dmi'
+ desc = "A mining lantern."
+ brightness_on = 6 // luminosity when on
+ light_color = "#FFAA44"
+ flashlight_power = 0.75
+
+
+/obj/item/flashlight/slime
+ gender = PLURAL
+ name = "glowing slime extract"
+ desc = "Extract from a yellow slime. It emits a strong light when squeezed."
+ icon = 'icons/obj/lighting.dmi'
+ icon_state = "slime"
+ item_state = "slime"
+ w_class = WEIGHT_CLASS_SMALL
+ slot_flags = ITEM_SLOT_BELT
+ materials = list()
+ brightness_on = 6 //luminosity when on
+ light_color = "#FFEEAA"
+ flashlight_power = 0.6
+
+/obj/item/flashlight/emp
+ var/emp_max_charges = 4
+ var/emp_cur_charges = 4
+ var/charge_tick = 0
+
+
+/obj/item/flashlight/emp/New()
+ ..()
+ START_PROCESSING(SSobj, src)
+
+/obj/item/flashlight/emp/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ . = ..()
+
+/obj/item/flashlight/emp/process()
+ charge_tick++
+ if(charge_tick < 10)
+ return FALSE
+ charge_tick = 0
+ emp_cur_charges = min(emp_cur_charges+1, emp_max_charges)
+ return TRUE
+
+/obj/item/flashlight/emp/attack(mob/living/M, mob/living/user)
+ if(on && user.zone_selected in list(BODY_ZONE_PRECISE_EYES, BODY_ZONE_PRECISE_MOUTH)) // call original attack when examining organs
+ ..()
+ return
+
+/obj/item/flashlight/emp/afterattack(atom/movable/A, mob/user, proximity)
+ . = ..()
+ if(!proximity)
+ return
+
+ if(emp_cur_charges > 0)
+ emp_cur_charges -= 1
+
+ if(ismob(A))
+ var/mob/M = A
+ log_combat(user, M, "attacked", "EMP-light")
+ M.visible_message("[user] blinks \the [src] at \the [A].", \
+ "[user] blinks \the [src] at you.")
+ else
+ A.visible_message("[user] blinks \the [src] at \the [A].")
+ to_chat(user, "\The [src] now has [emp_cur_charges] charge\s.")
+ A.emp_act(EMP_HEAVY)
+ else
+ to_chat(user, "\The [src] needs time to recharge!")
+ return
+
+/obj/item/flashlight/emp/debug //for testing emp_act()
+ name = "debug EMP flashlight"
+ emp_max_charges = 100
+ emp_cur_charges = 100
+
+// Glowsticks, in the uncomfortable range of similar to flares,
+// but not similar enough to make it worth a refactor
+/obj/item/flashlight/glowstick
+ name = "glowstick"
+ desc = "A military-grade glowstick."
+ w_class = WEIGHT_CLASS_SMALL
+ brightness_on = 4
+ color = LIGHT_COLOR_GREEN
+ icon_state = "glowstick"
+ item_state = "glowstick"
+ grind_results = list(/datum/reagent/phenol = 15, /datum/reagent/hydrogen = 10, /datum/reagent/oxygen = 5) //Meth-in-a-stick
+ rad_flags = RAD_NO_CONTAMINATE
+ var/fuel = 0
+
+/obj/item/flashlight/glowstick/Initialize()
+ fuel = rand(1600, 2000)
+ light_color = color
+ . = ..()
+
+/obj/item/flashlight/glowstick/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ . = ..()
+
+/obj/item/flashlight/glowstick/process()
+ fuel = max(fuel - 1, 0)
+ if(!fuel)
+ turn_off()
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+
+/obj/item/flashlight/glowstick/proc/turn_off()
+ on = FALSE
+ update_icon()
+
+/obj/item/flashlight/glowstick/update_icon()
+ item_state = "glowstick"
+ cut_overlays()
+ if(!fuel)
+ icon_state = "glowstick-empty"
+ cut_overlays()
+ set_light(0)
+ else if(on)
+ var/mutable_appearance/glowstick_overlay = mutable_appearance(icon, "glowstick-glow")
+ glowstick_overlay.color = color
+ add_overlay(glowstick_overlay)
+ item_state = "glowstick-on"
+ set_light(brightness_on)
+ else
+ icon_state = "glowstick"
+ cut_overlays()
+
+/obj/item/flashlight/glowstick/attack_self(mob/user)
+ if(!fuel)
+ to_chat(user, "[src] is spent.")
+ return
+ if(on)
+ to_chat(user, "[src] is already lit.")
+ return
+
+ . = ..()
+ if(.)
+ user.visible_message("[user] cracks and shakes [src].", "You crack and shake [src], turning it on!")
+ activate()
+
+/obj/item/flashlight/glowstick/proc/activate()
+ if(!on)
+ on = TRUE
+ START_PROCESSING(SSobj, src)
+
+/obj/item/flashlight/glowstick/red
+ name = "red glowstick"
+ color = LIGHT_COLOR_RED
+
+/obj/item/flashlight/glowstick/blue
+ name = "blue glowstick"
+ color = LIGHT_COLOR_BLUE
+
+/obj/item/flashlight/glowstick/cyan
+ name = "cyan glowstick"
+ color = LIGHT_COLOR_CYAN
+
+/obj/item/flashlight/glowstick/orange
+ name = "orange glowstick"
+ color = LIGHT_COLOR_ORANGE
+
+/obj/item/flashlight/glowstick/yellow
+ name = "yellow glowstick"
+ color = LIGHT_COLOR_YELLOW
+
+/obj/item/flashlight/glowstick/pink
+ name = "pink glowstick"
+ color = LIGHT_COLOR_PINK
+
+/obj/item/flashlight/spotlight //invisible lighting source
+ name = "disco light"
+ desc = "Groovy..."
+ icon_state = null
+ light_color = null
+ brightness_on = 0
+ flashlight_power = 1
+ light_range = 0
+ light_power = 10
+ alpha = 0
+ layer = 0
+ on = TRUE
+ anchored = TRUE
+ var/range = null
+ resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
+
+/obj/item/flashlight/flashdark
+ name = "flashdark"
+ desc = "A strange device manufactured with mysterious elements that somehow emits darkness. Or maybe it just sucks in light? Nobody knows for sure."
+ icon_state = "flashdark"
+ item_state = "flashdark"
+ brightness_on = 2.5
+ flashlight_power = -3
+
+/obj/item/flashlight/eyelight
+ name = "eyelight"
+ desc = "This shouldn't exist outside of someone's head, how are you seeing this?"
+ brightness_on = 15
+ flags_1 = CONDUCT_1
+ item_flags = DROPDEL
+ actions_types = list()
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 906cf6da..c54f9aba 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -1,844 +1,843 @@
-
-/*
-
-CONTAINS:
-T-RAY
-HEALTH ANALYZER
-GAS ANALYZER
-SLIME SCANNER
-NANITE SCANNER
-GENE SCANNER
-
-*/
-/obj/item/t_scanner
- name = "\improper T-ray scanner"
- desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
- icon = 'icons/obj/device.dmi'
- icon_state = "t-ray0"
- var/on = FALSE
- slot_flags = ITEM_SLOT_BELT
- w_class = WEIGHT_CLASS_SMALL
- item_state = "electronic"
- lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
- materials = list(MAT_METAL=150)
-
-/obj/item/t_scanner/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins to emit terahertz-rays into [user.p_their()] brain with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return TOXLOSS
-
-/obj/item/t_scanner/attack_self(mob/user)
-
- on = !on
- icon_state = copytext(icon_state, 1, length(icon_state))+"[on]"
-
- if(on)
- START_PROCESSING(SSobj, src)
-
-/obj/item/t_scanner/process()
- if(!on)
- STOP_PROCESSING(SSobj, src)
- return null
- scan()
-
-/obj/item/t_scanner/proc/scan()
- t_ray_scan(loc)
-
-/proc/t_ray_scan(mob/viewer, flick_time = 8, distance = 3)
- if(!ismob(viewer) || !viewer.client)
- return
- var/list/t_ray_images = list()
- for(var/obj/O in orange(distance, viewer) )
- if(O.level != 1)
- continue
-
- if(O.invisibility == INVISIBILITY_MAXIMUM)
- var/image/I = new(loc = get_turf(O))
- var/mutable_appearance/MA = new(O)
- MA.alpha = 128
- MA.dir = O.dir
- I.appearance = MA
- t_ray_images += I
- if(t_ray_images.len)
- flick_overlay(t_ray_images, list(viewer.client), flick_time)
-
-/obj/item/healthanalyzer
- name = "health analyzer"
- icon = 'icons/obj/device.dmi'
- icon_state = "health"
- item_state = "healthanalyzer"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- desc = "A hand-held body scanner able to distinguish vital signs of the subject."
- flags_1 = CONDUCT_1
- item_flags = NOBLUDGEON
- slot_flags = ITEM_SLOT_BELT
- throwforce = 3
- w_class = WEIGHT_CLASS_TINY
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL=200)
- var/mode = 1
- var/scanmode = 0
- var/advanced = FALSE
-
-/obj/item/healthanalyzer/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!")
- return BRUTELOSS
-
-/obj/item/healthanalyzer/attack_self(mob/user)
- if(!scanmode)
- to_chat(user, "You switch the health analyzer to scan chemical contents.")
- scanmode = 1
- else
- to_chat(user, "You switch the health analyzer to check physical health.")
- scanmode = 0
-
-/obj/item/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
-
- // Clumsiness/brain damage check
- if ((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50))
- to_chat(user, "You stupidly try to analyze the floor's vitals!")
- user.visible_message("[user] has analyzed the floor's vitals!")
- var/msg = "*---------*\nAnalyzing results for The floor:\n\tOverall status: Healthy\n"
- msg += "Key: Suffocation/Toxin/Burn/Brute\n"
- msg += "\tDamage specifics: 0-0-0-0\n"
- msg += "Body temperature: ???\n"
- msg += "*---------*"
- to_chat(user, msg)
- return
-
- user.visible_message("[user] has analyzed [M]'s vitals.")
-
- if(scanmode == 0)
- healthscan(user, M, mode, advanced)
- else if(scanmode == 1)
- chemscan(user, M)
-
- add_fingerprint(user)
-
-
-// Used by the PDA medical scanner too
-/proc/healthscan(mob/user, mob/living/M, mode = 1, advanced = FALSE)
- if(isliving(user) && (user.incapacitated() || user.eye_blind))
- return
- //Damage specifics
- var/oxy_loss = M.getOxyLoss()
- var/tox_loss = M.getToxLoss()
- var/fire_loss = M.getFireLoss()
- var/brute_loss = M.getBruteLoss()
- var/mob_status = (M.stat == DEAD ? "Deceased" : "[round(M.health/M.maxHealth,0.01)*100] % healthy")
-
- if(HAS_TRAIT(M, TRAIT_FAKEDEATH) && !advanced)
- mob_status = "Deceased"
- oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss
-
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.undergoing_cardiac_arrest() && H.stat != DEAD)
- to_chat(user, "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!")
- if(H.undergoing_liver_failure() && H.stat != DEAD) //might be depreciated BUG_PROBABLE_CAUSE
- to_chat(user, "Subject is suffering from liver failure: Apply Corazone and begin a liver transplant immediately!")
-
- var/msg = "*---------*\nAnalyzing results for [M]:\n\tOverall status: [mob_status]\n"
-
- // Damage descriptions
- if(brute_loss > 10)
- msg += "\t[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.\n"
- if(fire_loss > 10)
- msg += "\t[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.\n"
- if(oxy_loss > 10)
- msg += "\t[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.\n"
- if(tox_loss > 10)
- msg += "\t[tox_loss > 50 ? "Severe" : "Minor"] amount of toxin damage detected.\n"
- if(M.getStaminaLoss())
- msg += "\tSubject appears to be suffering from fatigue.\n"
- if(advanced)
- msg += "\tFatigue Level: [M.getStaminaLoss()]%.\n"
- if (M.getCloneLoss())
- msg += "\tSubject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.\n"
- if(advanced)
- msg += "\tCellular Damage Level: [M.getCloneLoss()].\n"
- if (!M.getorgan(/obj/item/organ/brain))
- to_chat(user, "\tSubject lacks a brain.") //Unsure how this won't proc for 50% of the cit playerbase (This is a joke everyone on cit a cute.)
- if(ishuman(M) && advanced) // Should I make this not advanced?
- var/mob/living/carbon/human/H = M
- var/obj/item/organ/liver/L = H.getorganslot("liver")
- if(L)
- if(L.swelling > 20)
- msg += "\tSubject is suffering from an enlarged liver.\n" //i.e. shrink their liver or give them a transplant.
- else
- msg += "\tSubject's liver is missing.\n"
- var/obj/item/organ/tongue/T = H.getorganslot("tongue")
- if(T)
- if(T.damage > 40)
- msg += "\tSubject is suffering from severe burn tissue on their tongue.\n" //i.e. their tongue is shot
- if(T.name == "fluffy tongue")
- msg += "\tSubject is suffering from a fluffified tongue. Suggested cure: Yamerol or a tongue transplant.\n"
- else
- msg += "\tSubject's tongue is missing.\n"
- var/obj/item/organ/lungs/Lung = H.getorganslot("lungs")
- if(Lung)
- if(Lung.damage > 150)
- msg += "\tSubject is suffering from acute emphysema leading to trouble breathing.\n" //i.e. Their lungs are shot
- else
- msg += "\tSubject's lungs have collapsed from trauma!\n"
- var/obj/item/organ/genital/penis/P = H.getorganslot("penis")
- if(P)
- if(P.length>20)
- msg += "\tSubject has a sizeable gentleman's organ at [P.length] inches.\n"
- var/obj/item/organ/genital/breasts/Br = H.getorganslot("breasts")
- if(Br)
- if(Br.cached_size>5)
- msg += "\tSubject has a sizeable bosom with a [Br.size] cup.\n"
- if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 200 || !M.getorgan(/obj/item/organ/brain))
- msg += "\tSubject's brain function is non-existent.\n"
- else if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 120)
- msg += "\tSevere brain damage detected. Subject likely to have mental traumas.\n"
- else if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 45)
- msg += "\tBrain damage detected.\n"
-
- if(iscarbon(M))
-
- var/mob/living/carbon/C = M
- if(LAZYLEN(C.get_traumas()))
- var/list/trauma_text = list()
- for(var/datum/brain_trauma/B in C.get_traumas())
- var/trauma_desc = ""
- switch(B.resilience)
- if(TRAUMA_RESILIENCE_SURGERY)
- trauma_desc += "severe "
- if(TRAUMA_RESILIENCE_LOBOTOMY)
- trauma_desc += "deep-rooted "
- if(TRAUMA_RESILIENCE_MAGIC, TRAUMA_RESILIENCE_ABSOLUTE)
- trauma_desc += "permanent "
- trauma_desc += B.scan_desc
- trauma_text += trauma_desc
- msg += "\tCerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].\n"
- if(C.roundstart_quirks.len)
- msg += "\tSubject has the following physiological traits: [C.get_trait_string()].\n"
- if(advanced)
- msg += "\tBrain Activity Level: [(200 - M.getOrganLoss(ORGAN_SLOT_BRAIN))/2]%.\n"
- if(M.radiation)
- msg += "\tSubject is irradiated.\n"
- if(advanced)
- msg += "\tRadiation Level: [M.radiation]%.\n"
-
- if(advanced && M.hallucinating())
- msg += "\tSubject is hallucinating.\n"
-
- //MKUltra
- if(advanced && M.has_status_effect(/datum/status_effect/chem/enthrall))
- msg += "\tSubject has abnormal brain fuctions.\n"
-
- //Astrogen shenanigans
- if(advanced && M.reagents.has_reagent("astral"))
- if(M.mind)
- msg += "\tWarning: subject may be possesed.\n"
- else
- msg += "\tSubject appears to be astrally projecting.\n"
-
- //Eyes and ears
- if(advanced)
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS)
- msg += "\t==EAR STATUS==\n"
- if(istype(ears))
- var/healthy = TRUE
- if(HAS_TRAIT_FROM(C, TRAIT_DEAF, GENETIC_MUTATION))
- healthy = FALSE
- msg += "\tSubject is genetically deaf.\n"
- else if(HAS_TRAIT(C, TRAIT_DEAF))
- healthy = FALSE
- msg += "\tSubject is deaf.\n"
- else
- if(ears.damage)
- to_chat(user, "\tSubject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.")
- healthy = FALSE
- if(ears.deaf)
- to_chat(user, "\tSubject is [ears.damage > ears.maxHealth ? "permanently ": "temporarily "] deaf.")
- healthy = FALSE
- if(healthy)
- msg += "\tHealthy.\n"
- else
- msg += "\tSubject does not have ears.\n"
- var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES)
- msg += "\t==EYE STATUS==\n"
- if(istype(eyes))
- var/healthy = TRUE
- if(HAS_TRAIT(C, TRAIT_BLIND))
- msg += "\tSubject is blind.\n"
- healthy = FALSE
- if(HAS_TRAIT(C, TRAIT_NEARSIGHT))
- msg += "\tSubject is nearsighted.\n"
- healthy = FALSE
- if(eyes.damage > 30)
- msg += "\tSubject has severe eye damage.\n"
- healthy = FALSE
- else if(eyes.damage > 20)
- msg += "\tSubject has significant eye damage.\n"
- healthy = FALSE
- else if(eyes.damage)
- msg += "\tSubject has minor eye damage.\n"
- healthy = FALSE
- if(healthy)
- msg += "\tHealthy.\n"
- else
- msg += "\tSubject does not have eyes.\n"
-
-
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/ldamage = H.return_liver_damage()
- if(ldamage > 10)
- msg += "\t[ldamage > 45 ? "Severe" : "Minor"] liver damage detected.\n"
- if(advanced && H.has_dna())
- to_chat(user, "\tGenetic Stability: [H.dna.stability]%.")
- // Body part damage report
- if(iscarbon(M) && mode == 1)
- var/mob/living/carbon/C = M
- var/list/damaged = C.get_damaged_bodyparts(1,1)
- if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0)
- msg += "\tDamage: Brute-Burn-Toxin-Suffocation\n\t\tSpecifics: [brute_loss]-[fire_loss]-[tox_loss]-[oxy_loss]\n"
- for(var/obj/item/bodypart/org in damaged)
- msg += "\t\t[capitalize(org.name)]: [(org.brute_dam > 0) ? "[org.brute_dam]" : "0"]-[(org.burn_dam > 0) ? "[org.burn_dam]" : "0"]\n"
-
- //Bones broken report! Hyperstation 13
- if(iscarbon(M) && mode == 1)
- var/mob/living/carbon/C = M
- for(var/X in C.bodyparts)
- var/obj/item/bodypart/LB = X
- var/broken = LB.broken
- if(broken == 1)
- msg += "\tSubjects [LB.name] is fractured!\n"
-
-//Organ damages report
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/minor_damage
- var/major_damage
- var/max_damage
- var/report_organs = FALSE
-
- //Piece together the lists to be reported
- for(var/O in H.internal_organs)
- var/obj/item/organ/organ = O
- if(organ.organ_flags & ORGAN_FAILING)
- report_organs = TRUE //if we report one organ, we report all organs, even if the lists are empty, just for consistency
- if(max_damage)
- max_damage += ", " //prelude the organ if we've already reported an organ
- max_damage += organ.name //this just slaps the organ name into the string of text
- else
- max_damage = "\tNon-Functional Organs: " //our initial statement
- max_damage += organ.name
- else if(organ.damage > organ.high_threshold)
- report_organs = TRUE
- if(major_damage)
- major_damage += ", "
- major_damage += organ.name
- else
- major_damage = "\tSeverely Damaged Organs: "
- major_damage += organ.name
- else if(organ.damage > organ.low_threshold)
- report_organs = TRUE
- if(minor_damage)
- minor_damage += ", "
- minor_damage += organ.name
- else
- minor_damage = "\tMildly Damaged Organs: "
- minor_damage += organ.name
-
- if(report_organs) //we either finish the list, or set it to be empty if no organs were reported in that category
- if(!max_damage)
- max_damage = "\tNon-Functional Organs: "
- else
- max_damage += ""
- if(!major_damage)
- major_damage = "\tSeverely Damaged Organs: "
- else
- major_damage += ""
- if(!minor_damage)
- minor_damage = "\tMildly Damaged Organs: "
- else
- minor_damage += ""
- msg += "[minor_damage]"
- msg += "[major_damage]"
- msg += "[max_damage]"
-
- // Species and body temperature
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- var/datum/species/S = H.dna.species
- var/mutant = FALSE
- if (H.dna.check_mutation(HULK))
- mutant = TRUE
- else if (S.mutantlungs != initial(S.mutantlungs))
- mutant = TRUE
- else if (S.mutant_brain != initial(S.mutant_brain))
- mutant = TRUE
- else if (S.mutant_heart != initial(S.mutant_heart))
- mutant = TRUE
- else if (S.mutanteyes != initial(S.mutanteyes))
- mutant = TRUE
- else if (S.mutantears != initial(S.mutantears))
- mutant = TRUE
- else if (S.mutanthands != initial(S.mutanthands))
- mutant = TRUE
- else if (S.mutanttongue != initial(S.mutanttongue))
- mutant = TRUE
- else if (S.mutanttail != initial(S.mutanttail))
- mutant = TRUE
- else if (S.mutantliver != initial(S.mutantliver))
- mutant = TRUE
- else if (S.mutantstomach != initial(S.mutantstomach))
- mutant = TRUE
-
- msg += "Species: [H.dna.custom_species ? H.dna.custom_species : S.name] Base: [S.name]\n"
- if(mutant)
- msg += "Subject has mutations present."
- msg += "Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)\n"
-
- // Time of death
- if(M.tod && (M.stat == DEAD || ((HAS_TRAIT(M, TRAIT_FAKEDEATH)) && !advanced)))
- msg += "Time of Death: [M.tod]\n"
- var/tdelta = round(world.time - M.timeofdeath)
- if(tdelta < (DEFIB_TIME_LIMIT * 10))
- msg += "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!\n"
-
- for(var/thing in M.diseases)
- var/datum/disease/D = thing
- if(!(D.visibility_flags & HIDDEN_SCANNER))
- msg += "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]\n"
-
- // Blood Level
- if(M.has_dna())
- var/mob/living/carbon/C = M
- var/blood_id = C.get_blood_id()
- if(blood_id)
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if(H.bleed_rate)
- msg += "Subject is bleeding!\n"
- var/blood_percent = round((C.scan_blood_volume() / (BLOOD_VOLUME_NORMAL * C.blood_ratio))*100)
- var/blood_type = C.dna.blood_type
- if(blood_id != ("blood" || "jellyblood"))//special blood substance
- var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
- if(R)
- blood_type = R.name
- else
- blood_type = blood_id
- if(C.scan_blood_volume() <= (BLOOD_VOLUME_SAFE*C.blood_ratio) && C.scan_blood_volume() > (BLOOD_VOLUME_OKAY*C.blood_ratio))
- msg += "LOW blood level [blood_percent] %, [C.scan_blood_volume()] cl,type: [blood_type]\n"
- else if(C.scan_blood_volume() <= (BLOOD_VOLUME_OKAY*C.blood_ratio))
- msg += "CRITICAL blood level [blood_percent] %, [C.scan_blood_volume()] cl,type: [blood_type]\n"
- else
- msg += "Blood level [blood_percent] %, [C.scan_blood_volume()] cl, type: [blood_type]\n"
-
- var/cyberimp_detect
- for(var/obj/item/organ/cyberimp/CI in C.internal_organs)
- if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
- cyberimp_detect += "[C.name] is modified with a [CI.name]. "
- if(cyberimp_detect)
- msg += "Detected cybernetic modifications:\n"
- msg += "[cyberimp_detect]\n"
- msg += "*---------*"
- to_chat(user, msg)
- SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, FALSE)
-
-/proc/chemscan(mob/living/user, mob/living/M)
- if(istype(M))
- if(M.reagents)
- var/msg = "*---------*\n"
- if(M.reagents.reagent_list.len)
- var/list/datum/reagent/reagents = list()
- for(var/datum/reagent/R in M.reagents.reagent_list)
- if(R.chemical_flags & REAGENT_INVISIBLE)
- continue
- reagents += R
-
- if(length(reagents))
- msg += "Subject contains the following reagents:\n"
- for(var/datum/reagent/R in reagents)
- msg += "[R.volume] units of [R.name][R.overdosed == 1 ? " - OVERDOSING" : "."]\n"
- else
- msg += "Subject contains no reagents.\n"
-
- else
- msg += "Subject contains no reagents.\n"
- if(M.reagents.addiction_list.len)
- msg += "Subject is addicted to the following reagents:\n"
- for(var/datum/reagent/R in M.reagents.addiction_list)
- msg += "[R.name]\n"
- else
- msg += "Subject is not addicted to any reagents.\n"
- msg += "*---------*"
- to_chat(user, msg)
-
- if(M.reagents.has_reagent("fermiTox"))
- var/datum/reagent/fermiTox = M.reagents.has_reagent("fermiTox")
- switch(fermiTox.volume)
- if(5 to 10)
- msg += "Subject contains a low amount of toxic isomers.\n"
- if(10 to 25)
- msg += "Subject contains toxic isomers.\n"
- if(25 to 50)
- msg += "Subject contains a substantial amount of toxic isomers.\n"
- if(50 to 95)
- msg += "Subject contains a high amount of toxic isomers.\n"
- if(95 to INFINITY)
- msg += "Subject contains a extremely dangerous amount of toxic isomers.\n"
-
-/obj/item/healthanalyzer/verb/toggle_mode()
- set name = "Switch Verbosity"
- set category = "Object"
-
- if(usr.stat || !usr.canmove || usr.restrained())
- return
-
- mode = !mode
- switch (mode)
- if(1)
- to_chat(usr, "The scanner now shows specific limb damage.")
- if(0)
- to_chat(usr, "The scanner no longer shows limb damage.")
-
-/obj/item/healthanalyzer/advanced
- name = "advanced health analyzer"
- icon_state = "health_adv"
- desc = "A hand-held body scanner able to distinguish vital signs of the subject with high accuracy."
- advanced = TRUE
-
-/obj/item/analyzer
- desc = "A hand-held environmental scanner which reports current gas levels. Alt-Click to use the built in barometer function."
- name = "analyzer"
- icon = 'icons/obj/device.dmi'
- icon_state = "analyzer"
- item_state = "analyzer"
- lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
- w_class = WEIGHT_CLASS_SMALL
- flags_1 = CONDUCT_1
- item_flags = NOBLUDGEON
- slot_flags = ITEM_SLOT_BELT
- throwforce = 0
- throw_speed = 3
- throw_range = 7
- tool_behaviour = TOOL_ANALYZER
- materials = list(MAT_METAL=30, MAT_GLASS=20)
- grind_results = list("mercury" = 5, "iron" = 5, "silicon" = 5)
- var/cooldown = FALSE
- var/cooldown_time = 250
- var/accuracy // 0 is the best accuracy.
-
-/obj/item/analyzer/examine(mob/user)
- . = ..()
- . += "Alt-click [src] to activate the barometer function."
-
-/obj/item/analyzer/suicide_act(mob/living/carbon/user)
- user.visible_message("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!")
- return BRUTELOSS
-
-/obj/item/analyzer/attack_self(mob/user)
- add_fingerprint(user)
-
- if (user.stat || user.eye_blind)
- return
-
- var/turf/location = user.loc
- if(!istype(location))
- return
-
- var/datum/gas_mixture/environment = location.return_air()
-
- var/pressure = environment.return_pressure()
- var/total_moles = environment.total_moles()
-
- to_chat(user, "Results:")
- if(abs(pressure - ONE_ATMOSPHERE) < 10)
- to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
- else
- to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
- if(total_moles)
- var/list/env_gases = environment.gases
-
- var/o2_concentration = env_gases[/datum/gas/oxygen]/total_moles
- var/n2_concentration = env_gases[/datum/gas/nitrogen]/total_moles
- var/co2_concentration = env_gases[/datum/gas/carbon_dioxide]/total_moles
- var/plasma_concentration = env_gases[/datum/gas/plasma]/total_moles
-
- if(abs(n2_concentration - N2STANDARD) < 20)
- to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen], 0.01)] mol)")
- else
- to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen], 0.01)] mol)")
-
- if(abs(o2_concentration - O2STANDARD) < 2)
- to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen], 0.01)] mol)")
- else
- to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen], 0.01)] mol)")
-
- if(co2_concentration > 0.01)
- to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide], 0.01)] mol)")
- else
- to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide], 0.01)] mol)")
-
- if(plasma_concentration > 0.005)
- to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma], 0.01)] mol)")
- else
- to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma], 0.01)] mol)")
-
- GAS_GARBAGE_COLLECT(environment.gases)
-
- for(var/id in env_gases)
- if(id in GLOB.hardcoded_gases)
- continue
- var/gas_concentration = env_gases[id]/total_moles
- to_chat(user, "[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(env_gases[id], 0.01)] mol)")
- to_chat(user, "Temperature: [round(environment.temperature-T0C, 0.01)] °C ([round(environment.temperature, 0.01)] K)")
-
-/obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens
- ..()
-
- if(user.canUseTopic(src))
-
- if(cooldown)
- to_chat(user, "[src]'s barometer function is preparing itself.")
- return
-
- var/turf/T = get_turf(user)
- if(!T)
- return
-
- playsound(src, 'sound/effects/pop.ogg', 100)
- var/area/user_area = T.loc
- var/datum/weather/ongoing_weather = null
-
- if(!user_area.outdoors)
- to_chat(user, "[src]'s barometer function won't work indoors!")
- return
-
- for(var/V in SSweather.processing)
- var/datum/weather/W = V
- if(W.barometer_predictable && (T.z in W.impacted_z_levels) && W.area_type == user_area.type && !(W.stage == END_STAGE))
- ongoing_weather = W
- break
-
- if(ongoing_weather)
- if((ongoing_weather.stage == MAIN_STAGE) || (ongoing_weather.stage == WIND_DOWN_STAGE))
- to_chat(user, "[src]'s barometer function can't trace anything while the storm is [ongoing_weather.stage == MAIN_STAGE ? "already here!" : "winding down."]")
- return
-
- to_chat(user, "The next [ongoing_weather] will hit in [butchertime(ongoing_weather.next_hit_time - world.time)].")
- if(ongoing_weather.aesthetic)
- to_chat(user, "[src]'s barometer function says that the next storm will breeze on by.")
- else
- var/next_hit = SSweather.next_hit_by_zlevel["[T.z]"]
- var/fixed = next_hit ? next_hit - world.time : -1
- if(fixed < 0)
- to_chat(user, "[src]'s barometer function was unable to trace any weather patterns.")
- else
- to_chat(user, "[src]'s barometer function says a storm will land in approximately [butchertime(fixed)].")
- cooldown = TRUE
- addtimer(CALLBACK(src,/obj/item/analyzer/proc/ping), cooldown_time)
-
-/obj/item/analyzer/proc/ping()
- if(isliving(loc))
- var/mob/living/L = loc
- to_chat(L, "[src]'s barometer function is ready!")
- playsound(src, 'sound/machines/click.ogg', 100)
- cooldown = FALSE
-
-/obj/item/analyzer/proc/butchertime(amount)
- if(!amount)
- return
- if(accuracy)
- var/inaccurate = round(accuracy*(1/3))
- if(prob(50))
- amount -= inaccurate
- if(prob(50))
- amount += inaccurate
- return DisplayTimeText(max(1,amount))
-
-/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src)
- var/icon = target
- user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(src))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].")
- to_chat(user, "Results of analysis of [icon2html(icon, user)] [target].")
-
- var/list/airs = islist(mixture) ? mixture : list(mixture)
- for(var/g in airs)
- if(airs.len > 1) //not a unary gas mixture
- to_chat(user, "Node [airs.Find(g)]")
- var/datum/gas_mixture/air_contents = g
-
- var/total_moles = air_contents.total_moles()
- var/pressure = air_contents.return_pressure()
- var/volume = air_contents.return_volume() //could just do mixture.volume... but safety, I guess?
- var/temperature = air_contents.temperature
- var/cached_scan_results = air_contents.analyzer_results
-
- if(total_moles > 0)
- to_chat(user, "Moles: [round(total_moles, 0.01)] mol")
- to_chat(user, "Volume: [volume] L")
- to_chat(user, "Pressure: [round(pressure,0.01)] kPa")
-
- var/list/cached_gases = air_contents.gases
- for(var/id in cached_gases)
- var/gas_concentration = cached_gases[id]/total_moles
- to_chat(user, "[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(cached_gases[id], 0.01)] mol)")
- to_chat(user, "Temperature: [round(temperature - T0C,0.01)] °C ([round(temperature, 0.01)] K)")
-
- else
- if(airs.len > 1)
- to_chat(user, "This node is empty!")
- else
- to_chat(user, "[target] is empty!")
-
- if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
- var/instability = round(cached_scan_results["fusion"], 0.01)
- to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.")
- to_chat(user, "Instability of the last fusion reaction: [instability].")
- return
-
-//slime scanner
-
-/obj/item/slime_scanner
- name = "slime scanner"
- desc = "A device that analyzes a slime's internal composition and measures its stats."
- icon = 'icons/obj/device.dmi'
- icon_state = "adv_spectrometer"
- item_state = "analyzer"
- lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
- w_class = WEIGHT_CLASS_SMALL
- flags_1 = CONDUCT_1
- throwforce = 0
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL=30, MAT_GLASS=20)
-
-/obj/item/slime_scanner/attack(mob/living/M, mob/living/user)
- if(user.stat || user.eye_blind)
- return
- if (!isslime(M))
- to_chat(user, "This device can only scan slimes!")
- return
- var/mob/living/simple_animal/slime/T = M
- slime_scan(T, user)
-
-/proc/slime_scan(mob/living/simple_animal/slime/T, mob/living/user)
- to_chat(user, "========================")
- to_chat(user, "Slime scan results:")
- to_chat(user, "[T.colour] [T.is_adult ? "adult" : "baby"] slime")
- to_chat(user, "Nutrition: [T.nutrition]/[T.get_max_nutrition()]")
- if (T.nutrition < T.get_starve_nutrition())
- to_chat(user, "Warning: slime is starving!")
- else if (T.nutrition < T.get_hunger_nutrition())
- to_chat(user, "Warning: slime is hungry")
- to_chat(user, "Electric change strength: [T.powerlevel]")
- to_chat(user, "Health: [round(T.health/T.maxHealth,0.01)*100]%")
- if (T.slime_mutation[4] == T.colour)
- to_chat(user, "This slime does not evolve any further.")
- else
- if (T.slime_mutation[3] == T.slime_mutation[4])
- if (T.slime_mutation[2] == T.slime_mutation[1])
- to_chat(user, "Possible mutation: [T.slime_mutation[3]]")
- to_chat(user, "Genetic destability: [T.mutation_chance/2] % chance of mutation on splitting")
- else
- to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)")
- to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting")
- else
- to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]")
- to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting")
- if (T.cores > 1)
- to_chat(user, "Multiple cores detected")
- to_chat(user, "Growth progress: [T.amount_grown]/[SLIME_EVOLUTION_THRESHOLD]")
- if(T.effectmod)
- to_chat(user, "Core mutation in progress: [T.effectmod]")
- to_chat(user, "Progress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]")
- to_chat(user, "========================")
-
-
-/obj/item/nanite_scanner
- name = "nanite scanner"
- icon = 'icons/obj/device.dmi'
- icon_state = "nanite_scanner"
- item_state = "nanite_remote"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- desc = "A hand-held body scanner able to detect nanites and their programming."
- flags_1 = CONDUCT_1
- item_flags = NOBLUDGEON
- slot_flags = ITEM_SLOT_BELT
- throwforce = 3
- w_class = WEIGHT_CLASS_TINY
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL=200)
-
-/obj/item/nanite_scanner/attack(mob/living/M, mob/living/carbon/human/user)
- user.visible_message("[user] has analyzed [M]'s nanites.")
-
- add_fingerprint(user)
-
- var/response = SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, TRUE)
- if(!response)
- to_chat(user, "No nanites detected in the subject.")
-
-/obj/item/sequence_scanner
- name = "genetic sequence scanner"
- icon = 'icons/obj/device.dmi'
- icon_state = "gene"
- item_state = "healthanalyzer"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- desc = "A hand-held scanner able to swiftly scan someone for potential mutations. Hold near a DNA console to update from their database."
- flags_1 = CONDUCT_1
- item_flags = NOBLUDGEON
- slot_flags = ITEM_SLOT_BELT
- throwforce = 3
- w_class = WEIGHT_CLASS_TINY
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL=200)
- var/list/discovered = list() //hit a dna console to update the scanners database
-
-/obj/item/sequence_scanner/attack(mob/living/M, mob/living/carbon/human/user)
- user.visible_message("[user] has analyzed [M]'s genetic sequence.")
-
- add_fingerprint(user)
-
- gene_scan(M, user, src)
-
-/obj/item/sequence_scanner/afterattack(obj/O, mob/user, proximity)
- . = ..()
- if(!istype(O) || !proximity)
- return
-
- if(istype(O, /obj/machinery/computer/scan_consolenew))
- var/obj/machinery/computer/scan_consolenew/C = O
- if(C.stored_research)
- to_chat(user, "[name] database updated.")
- discovered = C.stored_research.discovered_mutations
- else
- to_chat(user,"No database to update from.")
-
-/proc/gene_scan(mob/living/carbon/C, mob/living/user, obj/item/sequence_scanner/G)
- if(!iscarbon(C) || !C.has_dna())
- return
- to_chat(user, "[C.name]'s potential mutations.")
- for(var/A in C.dna.mutation_index)
- var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(A)
- var/mut_name
- if(G && (A in G.discovered))
- mut_name = "[HM.name] ([HM.alias])"
- else
- mut_name = HM.alias
- var/temp = GET_GENE_STRING(HM.type, C.dna)
- var/display
- for(var/i in 0 to length(temp) / DNA_MUTATION_BLOCKS-1)
- if(i)
- display += "-"
- display += copytext(temp, 1 + i*DNA_MUTATION_BLOCKS, DNA_MUTATION_BLOCKS*(1+i) + 1)
-
-
- to_chat(user, "- [mut_name] > [display]")
+
+/*
+
+CONTAINS:
+T-RAY
+HEALTH ANALYZER
+GAS ANALYZER
+SLIME SCANNER
+NANITE SCANNER
+GENE SCANNER
+
+*/
+/obj/item/t_scanner
+ name = "\improper T-ray scanner"
+ desc = "A terahertz-ray emitter and scanner used to detect underfloor objects such as cables and pipes."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "t-ray0"
+ var/on = FALSE
+ slot_flags = ITEM_SLOT_BELT
+ w_class = WEIGHT_CLASS_SMALL
+ item_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ materials = list(MAT_METAL=150)
+
+/obj/item/t_scanner/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins to emit terahertz-rays into [user.p_their()] brain with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return TOXLOSS
+
+/obj/item/t_scanner/attack_self(mob/user)
+
+ on = !on
+ icon_state = copytext(icon_state, 1, length(icon_state))+"[on]"
+
+ if(on)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/t_scanner/process()
+ if(!on)
+ STOP_PROCESSING(SSobj, src)
+ return null
+ scan()
+
+/obj/item/t_scanner/proc/scan()
+ t_ray_scan(loc)
+
+/proc/t_ray_scan(mob/viewer, flick_time = 8, distance = 3)
+ if(!ismob(viewer) || !viewer.client)
+ return
+ var/list/t_ray_images = list()
+ for(var/obj/O in orange(distance, viewer) )
+ if(O.level != 1)
+ continue
+
+ if(O.invisibility == INVISIBILITY_MAXIMUM)
+ var/image/I = new(loc = get_turf(O))
+ var/mutable_appearance/MA = new(O)
+ MA.alpha = 128
+ MA.dir = O.dir
+ I.appearance = MA
+ t_ray_images += I
+ if(t_ray_images.len)
+ flick_overlay(t_ray_images, list(viewer.client), flick_time)
+
+/obj/item/healthanalyzer
+ name = "health analyzer"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "health"
+ item_state = "healthanalyzer"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ desc = "A hand-held body scanner able to distinguish vital signs of the subject."
+ flags_1 = CONDUCT_1
+ item_flags = NOBLUDGEON
+ slot_flags = ITEM_SLOT_BELT
+ throwforce = 3
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL=200)
+ var/mode = 1
+ var/scanmode = 0
+ var/advanced = FALSE
+
+/obj/item/healthanalyzer/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!")
+ return BRUTELOSS
+
+/obj/item/healthanalyzer/attack_self(mob/user)
+ if(!scanmode)
+ to_chat(user, "You switch the health analyzer to scan chemical contents.")
+ scanmode = 1
+ else
+ to_chat(user, "You switch the health analyzer to check physical health.")
+ scanmode = 0
+
+/obj/item/healthanalyzer/attack(mob/living/M, mob/living/carbon/human/user)
+
+ // Clumsiness/brain damage check
+ if ((HAS_TRAIT(user, TRAIT_CLUMSY) || HAS_TRAIT(user, TRAIT_DUMB)) && prob(50))
+ to_chat(user, "You stupidly try to analyze the floor's vitals!")
+ user.visible_message("[user] has analyzed the floor's vitals!")
+ var/msg = "*---------*\nAnalyzing results for The floor:\n\tOverall status: Healthy\n"
+ msg += "Key: Suffocation/Toxin/Burn/Brute\n"
+ msg += "\tDamage specifics: 0-0-0-0\n"
+ msg += "Body temperature: ???\n"
+ msg += "*---------*"
+ to_chat(user, msg)
+ return
+
+ user.visible_message("[user] has analyzed [M]'s vitals.")
+
+ if(scanmode == 0)
+ healthscan(user, M, mode, advanced)
+ else if(scanmode == 1)
+ chemscan(user, M)
+
+ add_fingerprint(user)
+
+
+// Used by the PDA medical scanner too
+/proc/healthscan(mob/user, mob/living/M, mode = 1, advanced = FALSE)
+ if(isliving(user) && (user.incapacitated() || user.eye_blind))
+ return
+ //Damage specifics
+ var/oxy_loss = M.getOxyLoss()
+ var/tox_loss = M.getToxLoss()
+ var/fire_loss = M.getFireLoss()
+ var/brute_loss = M.getBruteLoss()
+ var/mob_status = (M.stat == DEAD ? "Deceased" : "[round(M.health/M.maxHealth,0.01)*100] % healthy")
+
+ if(HAS_TRAIT(M, TRAIT_FAKEDEATH) && !advanced)
+ mob_status = "Deceased"
+ oxy_loss = max(rand(1, 40), oxy_loss, (300 - (tox_loss + fire_loss + brute_loss))) // Random oxygen loss
+
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.undergoing_cardiac_arrest() && H.stat != DEAD)
+ to_chat(user, "Subject suffering from heart attack: Apply defibrillation or other electric shock immediately!")
+ if(H.undergoing_liver_failure() && H.stat != DEAD) //might be depreciated BUG_PROBABLE_CAUSE
+ to_chat(user, "Subject is suffering from liver failure: Apply Corazone and begin a liver transplant immediately!")
+
+ var/msg = "*---------*\nAnalyzing results for [M]:\n\tOverall status: [mob_status]\n"
+
+ // Damage descriptions
+ if(brute_loss > 10)
+ msg += "\t[brute_loss > 50 ? "Severe" : "Minor"] tissue damage detected.\n"
+ if(fire_loss > 10)
+ msg += "\t[fire_loss > 50 ? "Severe" : "Minor"] burn damage detected.\n"
+ if(oxy_loss > 10)
+ msg += "\t[oxy_loss > 50 ? "Severe" : "Minor"] oxygen deprivation detected.\n"
+ if(tox_loss > 10)
+ msg += "\t[tox_loss > 50 ? "Severe" : "Minor"] amount of toxin damage detected.\n"
+ if(M.getStaminaLoss())
+ msg += "\tSubject appears to be suffering from fatigue.\n"
+ if(advanced)
+ msg += "\tFatigue Level: [M.getStaminaLoss()]%.\n"
+ if (M.getCloneLoss())
+ msg += "\tSubject appears to have [M.getCloneLoss() > 30 ? "Severe" : "Minor"] cellular damage.\n"
+ if(advanced)
+ msg += "\tCellular Damage Level: [M.getCloneLoss()].\n"
+ if (!M.getorgan(/obj/item/organ/brain))
+ to_chat(user, "\tSubject lacks a brain.") //Unsure how this won't proc for 50% of the cit playerbase (This is a joke everyone on cit a cute.)
+ if(ishuman(M) && advanced) // Should I make this not advanced?
+ var/mob/living/carbon/human/H = M
+ var/obj/item/organ/liver/L = H.getorganslot("liver")
+ if(L)
+ if(L.swelling > 20)
+ msg += "\tSubject is suffering from an enlarged liver.\n" //i.e. shrink their liver or give them a transplant.
+ else
+ msg += "\tSubject's liver is missing.\n"
+ var/obj/item/organ/tongue/T = H.getorganslot("tongue")
+ if(T)
+ if(T.damage > 40)
+ msg += "\tSubject is suffering from severe burn tissue on their tongue.\n" //i.e. their tongue is shot
+ if(T.name == "fluffy tongue")
+ msg += "\tSubject is suffering from a fluffified tongue. Suggested cure: Yamerol or a tongue transplant.\n"
+ else
+ msg += "\tSubject's tongue is missing.\n"
+ var/obj/item/organ/lungs/Lung = H.getorganslot("lungs")
+ if(Lung)
+ if(Lung.damage > 150)
+ msg += "\tSubject is suffering from acute emphysema leading to trouble breathing.\n" //i.e. Their lungs are shot
+ else
+ msg += "\tSubject's lungs have collapsed from trauma!\n"
+ var/obj/item/organ/genital/penis/P = H.getorganslot("penis")
+ if(P)
+ if(P.length>20)
+ msg += "\tSubject has a sizeable gentleman's organ at [P.length] inches.\n"
+ var/obj/item/organ/genital/breasts/Br = H.getorganslot("breasts")
+ if(Br)
+ if(Br.cached_size>5)
+ msg += "\tSubject has a sizeable bosom with a [Br.size] cup.\n"
+ if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 200 || !M.getorgan(/obj/item/organ/brain))
+ msg += "\tSubject's brain function is non-existent.\n"
+ else if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 120)
+ msg += "\tSevere brain damage detected. Subject likely to have mental traumas.\n"
+ else if (M.getOrganLoss(ORGAN_SLOT_BRAIN) >= 45)
+ msg += "\tBrain damage detected.\n"
+
+ if(iscarbon(M))
+
+ var/mob/living/carbon/C = M
+ if(LAZYLEN(C.get_traumas()))
+ var/list/trauma_text = list()
+ for(var/datum/brain_trauma/B in C.get_traumas())
+ var/trauma_desc = ""
+ switch(B.resilience)
+ if(TRAUMA_RESILIENCE_SURGERY)
+ trauma_desc += "severe "
+ if(TRAUMA_RESILIENCE_LOBOTOMY)
+ trauma_desc += "deep-rooted "
+ if(TRAUMA_RESILIENCE_MAGIC, TRAUMA_RESILIENCE_ABSOLUTE)
+ trauma_desc += "permanent "
+ trauma_desc += B.scan_desc
+ trauma_text += trauma_desc
+ msg += "\tCerebral traumas detected: subject appears to be suffering from [english_list(trauma_text)].\n"
+ if(C.roundstart_quirks.len)
+ msg += "\tSubject has the following physiological traits: [C.get_trait_string()].\n"
+ if(advanced)
+ msg += "\tBrain Activity Level: [(200 - M.getOrganLoss(ORGAN_SLOT_BRAIN))/2]%.\n"
+ if(M.radiation)
+ msg += "\tSubject is irradiated.\n"
+ if(advanced)
+ msg += "\tRadiation Level: [M.radiation]%.\n"
+
+ if(advanced && M.hallucinating())
+ msg += "\tSubject is hallucinating.\n"
+
+ //MKUltra
+ if(advanced && M.has_status_effect(/datum/status_effect/chem/enthrall))
+ msg += "\tSubject has abnormal brain fuctions.\n"
+
+ //Astrogen shenanigans
+ if(advanced && M.reagents.has_reagent("astral"))
+ if(M.mind)
+ msg += "\tWarning: subject may be possesed.\n"
+ else
+ msg += "\tSubject appears to be astrally projecting.\n"
+
+ //Eyes and ears
+ if(advanced)
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ var/obj/item/organ/ears/ears = C.getorganslot(ORGAN_SLOT_EARS)
+ msg += "\t==EAR STATUS==\n"
+ if(istype(ears))
+ var/healthy = TRUE
+ if(HAS_TRAIT_FROM(C, TRAIT_DEAF, GENETIC_MUTATION))
+ healthy = FALSE
+ msg += "\tSubject is genetically deaf.\n"
+ else if(HAS_TRAIT(C, TRAIT_DEAF))
+ healthy = FALSE
+ msg += "\tSubject is deaf.\n"
+ else
+ if(ears.damage)
+ to_chat(user, "\tSubject has [ears.damage > ears.maxHealth ? "permanent ": "temporary "]hearing damage.")
+ healthy = FALSE
+ if(ears.deaf)
+ to_chat(user, "\tSubject is [ears.damage > ears.maxHealth ? "permanently ": "temporarily "] deaf.")
+ healthy = FALSE
+ if(healthy)
+ msg += "\tHealthy.\n"
+ else
+ msg += "\tSubject does not have ears.\n"
+ var/obj/item/organ/eyes/eyes = C.getorganslot(ORGAN_SLOT_EYES)
+ msg += "\t==EYE STATUS==\n"
+ if(istype(eyes))
+ var/healthy = TRUE
+ if(HAS_TRAIT(C, TRAIT_BLIND))
+ msg += "\tSubject is blind.\n"
+ healthy = FALSE
+ if(HAS_TRAIT(C, TRAIT_NEARSIGHT))
+ msg += "\tSubject is nearsighted.\n"
+ healthy = FALSE
+ if(eyes.damage > 30)
+ msg += "\tSubject has severe eye damage.\n"
+ healthy = FALSE
+ else if(eyes.damage > 20)
+ msg += "\tSubject has significant eye damage.\n"
+ healthy = FALSE
+ else if(eyes.damage)
+ msg += "\tSubject has minor eye damage.\n"
+ healthy = FALSE
+ if(healthy)
+ msg += "\tHealthy.\n"
+ else
+ msg += "\tSubject does not have eyes.\n"
+
+
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/ldamage = H.return_liver_damage()
+ if(ldamage > 10)
+ msg += "\t[ldamage > 45 ? "Severe" : "Minor"] liver damage detected.\n"
+ if(advanced && H.has_dna())
+ to_chat(user, "\tGenetic Stability: [H.dna.stability]%.")
+ // Body part damage report
+ if(iscarbon(M) && mode == 1)
+ var/mob/living/carbon/C = M
+ var/list/damaged = C.get_damaged_bodyparts(1,1)
+ if(length(damaged)>0 || oxy_loss>0 || tox_loss>0 || fire_loss>0)
+ msg += "\tDamage: Brute-Burn-Toxin-Suffocation\n\t\tSpecifics: [brute_loss]-[fire_loss]-[tox_loss]-[oxy_loss]\n"
+ for(var/obj/item/bodypart/org in damaged)
+ msg += "\t\t[capitalize(org.name)]: [(org.brute_dam > 0) ? "[org.brute_dam]" : "0"]-[(org.burn_dam > 0) ? "[org.burn_dam]" : "0"]\n"
+
+ //Bones broken report! Hyperstation 13
+ if(iscarbon(M) && mode == 1)
+ var/mob/living/carbon/C = M
+ for(var/X in C.bodyparts)
+ var/obj/item/bodypart/LB = X
+ var/broken = LB.broken
+ if(broken == 1)
+ msg += "\tSubjects [LB.name] is fractured!\n"
+
+//Organ damages report
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/minor_damage
+ var/major_damage
+ var/max_damage
+ var/report_organs = FALSE
+
+ //Piece together the lists to be reported
+ for(var/O in H.internal_organs)
+ var/obj/item/organ/organ = O
+ if(organ.organ_flags & ORGAN_FAILING)
+ report_organs = TRUE //if we report one organ, we report all organs, even if the lists are empty, just for consistency
+ if(max_damage)
+ max_damage += ", " //prelude the organ if we've already reported an organ
+ max_damage += organ.name //this just slaps the organ name into the string of text
+ else
+ max_damage = "\tNon-Functional Organs: " //our initial statement
+ max_damage += organ.name
+ else if(organ.damage > organ.high_threshold)
+ report_organs = TRUE
+ if(major_damage)
+ major_damage += ", "
+ major_damage += organ.name
+ else
+ major_damage = "\tSeverely Damaged Organs: "
+ major_damage += organ.name
+ else if(organ.damage > organ.low_threshold)
+ report_organs = TRUE
+ if(minor_damage)
+ minor_damage += ", "
+ minor_damage += organ.name
+ else
+ minor_damage = "\tMildly Damaged Organs: "
+ minor_damage += organ.name
+
+ if(report_organs) //we either finish the list, or set it to be empty if no organs were reported in that category
+ if(!max_damage)
+ max_damage = "\tNon-Functional Organs: "
+ else
+ max_damage += ""
+ if(!major_damage)
+ major_damage = "\tSeverely Damaged Organs: "
+ else
+ major_damage += ""
+ if(!minor_damage)
+ minor_damage = "\tMildly Damaged Organs: "
+ else
+ minor_damage += ""
+ msg += "[minor_damage]"
+ msg += "[major_damage]"
+ msg += "[max_damage]"
+
+ // Species and body temperature
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ var/datum/species/S = H.dna.species
+ var/mutant = FALSE
+ if (H.dna.check_mutation(HULK))
+ mutant = TRUE
+ else if (S.mutantlungs != initial(S.mutantlungs))
+ mutant = TRUE
+ else if (S.mutant_brain != initial(S.mutant_brain))
+ mutant = TRUE
+ else if (S.mutant_heart != initial(S.mutant_heart))
+ mutant = TRUE
+ else if (S.mutanteyes != initial(S.mutanteyes))
+ mutant = TRUE
+ else if (S.mutantears != initial(S.mutantears))
+ mutant = TRUE
+ else if (S.mutanthands != initial(S.mutanthands))
+ mutant = TRUE
+ else if (S.mutanttongue != initial(S.mutanttongue))
+ mutant = TRUE
+ else if (S.mutanttail != initial(S.mutanttail))
+ mutant = TRUE
+ else if (S.mutantliver != initial(S.mutantliver))
+ mutant = TRUE
+ else if (S.mutantstomach != initial(S.mutantstomach))
+ mutant = TRUE
+
+ msg += "Species: [H.dna.custom_species ? H.dna.custom_species : S.name] Base: [S.name]\n"
+ if(mutant)
+ msg += "Subject has mutations present."
+ msg += "Body temperature: [round(M.bodytemperature-T0C,0.1)] °C ([round(M.bodytemperature*1.8-459.67,0.1)] °F)\n"
+
+ // Time of death
+ if(M.tod && (M.stat == DEAD || ((HAS_TRAIT(M, TRAIT_FAKEDEATH)) && !advanced)))
+ msg += "Time of Death: [M.tod]\n"
+ var/tdelta = round(world.time - M.timeofdeath)
+ if(tdelta < (DEFIB_TIME_LIMIT * 10))
+ msg += "Subject died [DisplayTimeText(tdelta)] ago, defibrillation may be possible!\n"
+
+ for(var/thing in M.diseases)
+ var/datum/disease/D = thing
+ if(!(D.visibility_flags & HIDDEN_SCANNER))
+ msg += "Warning: [D.form] detected\nName: [D.name].\nType: [D.spread_text].\nStage: [D.stage]/[D.max_stages].\nPossible Cure: [D.cure_text]\n"
+
+ // Blood Level
+ if(M.has_dna())
+ var/mob/living/carbon/C = M
+ var/blood_id = C.get_blood_id()
+ if(blood_id)
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if(H.bleed_rate)
+ msg += "Subject is bleeding!\n"
+ var/blood_percent = round((C.scan_blood_volume() / (BLOOD_VOLUME_NORMAL * C.blood_ratio))*100)
+ var/blood_type = C.dna.blood_type
+ if(blood_id != ("blood" || "jellyblood"))//special blood substance
+ var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
+ if(R)
+ blood_type = R.name
+ else
+ blood_type = blood_id
+ if(C.scan_blood_volume() <= (BLOOD_VOLUME_SAFE*C.blood_ratio) && C.scan_blood_volume() > (BLOOD_VOLUME_OKAY*C.blood_ratio))
+ msg += "LOW blood level [blood_percent] %, [C.scan_blood_volume()] cl,type: [blood_type]\n"
+ else if(C.scan_blood_volume() <= (BLOOD_VOLUME_OKAY*C.blood_ratio))
+ msg += "CRITICAL blood level [blood_percent] %, [C.scan_blood_volume()] cl,type: [blood_type]\n"
+ else
+ msg += "Blood level [blood_percent] %, [C.scan_blood_volume()] cl, type: [blood_type]\n"
+
+ var/cyberimp_detect
+ for(var/obj/item/organ/cyberimp/CI in C.internal_organs)
+ if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
+ cyberimp_detect += "[C.name] is modified with a [CI.name]. "
+ if(cyberimp_detect)
+ msg += "Detected cybernetic modifications:\n"
+ msg += "[cyberimp_detect]\n"
+ msg += "*---------*"
+ to_chat(user, msg)
+ SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, FALSE)
+
+/proc/chemscan(mob/living/user, mob/living/M)
+ if(istype(M))
+ if(M.reagents)
+ var/msg = "*---------*\n"
+ if(M.reagents.reagent_list.len)
+ var/list/datum/reagent/reagents = list()
+ for(var/datum/reagent/R in M.reagents.reagent_list)
+ if(R.chemical_flags & REAGENT_INVISIBLE)
+ continue
+ reagents += R
+
+ if(length(reagents))
+ msg += "Subject contains the following reagents:\n"
+ for(var/datum/reagent/R in reagents)
+ msg += "[R.volume] units of [R.name][R.overdosed == 1 ? " - OVERDOSING" : "."]\n"
+ else
+ msg += "Subject contains no reagents.\n"
+
+ else
+ msg += "Subject contains no reagents.\n"
+ if(M.reagents.addiction_list.len)
+ msg += "Subject is addicted to the following reagents:\n"
+ for(var/datum/reagent/R in M.reagents.addiction_list)
+ msg += "[R.name]\n"
+ else
+ msg += "Subject is not addicted to any reagents.\n"
+ msg += "*---------*"
+ to_chat(user, msg)
+
+ var/datum/reagent/impure/fermiTox/F = M.reagents.has_reagent(/datum/reagent/impure/fermiTox)
+ switch(F?.volume)
+ if(5 to 10)
+ msg += "Subject contains a low amount of toxic isomers.\n"
+ if(10 to 25)
+ msg += "Subject contains toxic isomers.\n"
+ if(25 to 50)
+ msg += "Subject contains a substantial amount of toxic isomers.\n"
+ if(50 to 95)
+ msg += "Subject contains a high amount of toxic isomers.\n"
+ if(95 to INFINITY)
+ msg += "Subject contains a extremely dangerous amount of toxic isomers.\n"
+
+/obj/item/healthanalyzer/verb/toggle_mode()
+ set name = "Switch Verbosity"
+ set category = "Object"
+
+ if(usr.stat || !usr.canmove || usr.restrained())
+ return
+
+ mode = !mode
+ switch (mode)
+ if(1)
+ to_chat(usr, "The scanner now shows specific limb damage.")
+ if(0)
+ to_chat(usr, "The scanner no longer shows limb damage.")
+
+/obj/item/healthanalyzer/advanced
+ name = "advanced health analyzer"
+ icon_state = "health_adv"
+ desc = "A hand-held body scanner able to distinguish vital signs of the subject with high accuracy."
+ advanced = TRUE
+
+/obj/item/analyzer
+ desc = "A hand-held environmental scanner which reports current gas levels. Alt-Click to use the built in barometer function."
+ name = "analyzer"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "analyzer"
+ item_state = "analyzer"
+ lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+ flags_1 = CONDUCT_1
+ item_flags = NOBLUDGEON
+ slot_flags = ITEM_SLOT_BELT
+ throwforce = 0
+ throw_speed = 3
+ throw_range = 7
+ tool_behaviour = TOOL_ANALYZER
+ materials = list(MAT_METAL=30, MAT_GLASS=20)
+ grind_results = list(/datum/reagent/mercury = 5, /datum/reagent/iron = 5, /datum/reagent/silicon = 5)
+ var/cooldown = FALSE
+ var/cooldown_time = 250
+ var/accuracy // 0 is the best accuracy.
+
+/obj/item/analyzer/examine(mob/user)
+ . = ..()
+ . += "Alt-click [src] to activate the barometer function."
+
+/obj/item/analyzer/suicide_act(mob/living/carbon/user)
+ user.visible_message("[user] begins to analyze [user.p_them()]self with [src]! The display shows that [user.p_theyre()] dead!")
+ return BRUTELOSS
+
+/obj/item/analyzer/attack_self(mob/user)
+ add_fingerprint(user)
+
+ if (user.stat || user.eye_blind)
+ return
+
+ var/turf/location = user.loc
+ if(!istype(location))
+ return
+
+ var/datum/gas_mixture/environment = location.return_air()
+
+ var/pressure = environment.return_pressure()
+ var/total_moles = environment.total_moles()
+
+ to_chat(user, "Results:")
+ if(abs(pressure - ONE_ATMOSPHERE) < 10)
+ to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
+ else
+ to_chat(user, "Pressure: [round(pressure, 0.01)] kPa")
+ if(total_moles)
+ var/list/env_gases = environment.gases
+
+ var/o2_concentration = env_gases[/datum/gas/oxygen]/total_moles
+ var/n2_concentration = env_gases[/datum/gas/nitrogen]/total_moles
+ var/co2_concentration = env_gases[/datum/gas/carbon_dioxide]/total_moles
+ var/plasma_concentration = env_gases[/datum/gas/plasma]/total_moles
+
+ if(abs(n2_concentration - N2STANDARD) < 20)
+ to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen], 0.01)] mol)")
+ else
+ to_chat(user, "Nitrogen: [round(n2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/nitrogen], 0.01)] mol)")
+
+ if(abs(o2_concentration - O2STANDARD) < 2)
+ to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen], 0.01)] mol)")
+ else
+ to_chat(user, "Oxygen: [round(o2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/oxygen], 0.01)] mol)")
+
+ if(co2_concentration > 0.01)
+ to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide], 0.01)] mol)")
+ else
+ to_chat(user, "CO2: [round(co2_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/carbon_dioxide], 0.01)] mol)")
+
+ if(plasma_concentration > 0.005)
+ to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma], 0.01)] mol)")
+ else
+ to_chat(user, "Plasma: [round(plasma_concentration*100, 0.01)] % ([round(env_gases[/datum/gas/plasma], 0.01)] mol)")
+
+ GAS_GARBAGE_COLLECT(environment.gases)
+
+ for(var/id in env_gases)
+ if(id in GLOB.hardcoded_gases)
+ continue
+ var/gas_concentration = env_gases[id]/total_moles
+ to_chat(user, "[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(env_gases[id], 0.01)] mol)")
+ to_chat(user, "Temperature: [round(environment.temperature-T0C, 0.01)] °C ([round(environment.temperature, 0.01)] K)")
+
+/obj/item/analyzer/AltClick(mob/user) //Barometer output for measuring when the next storm happens
+ ..()
+
+ if(user.canUseTopic(src))
+
+ if(cooldown)
+ to_chat(user, "[src]'s barometer function is preparing itself.")
+ return
+
+ var/turf/T = get_turf(user)
+ if(!T)
+ return
+
+ playsound(src, 'sound/effects/pop.ogg', 100)
+ var/area/user_area = T.loc
+ var/datum/weather/ongoing_weather = null
+
+ if(!user_area.outdoors)
+ to_chat(user, "[src]'s barometer function won't work indoors!")
+ return
+
+ for(var/V in SSweather.processing)
+ var/datum/weather/W = V
+ if(W.barometer_predictable && (T.z in W.impacted_z_levels) && W.area_type == user_area.type && !(W.stage == END_STAGE))
+ ongoing_weather = W
+ break
+
+ if(ongoing_weather)
+ if((ongoing_weather.stage == MAIN_STAGE) || (ongoing_weather.stage == WIND_DOWN_STAGE))
+ to_chat(user, "[src]'s barometer function can't trace anything while the storm is [ongoing_weather.stage == MAIN_STAGE ? "already here!" : "winding down."]")
+ return
+
+ to_chat(user, "The next [ongoing_weather] will hit in [butchertime(ongoing_weather.next_hit_time - world.time)].")
+ if(ongoing_weather.aesthetic)
+ to_chat(user, "[src]'s barometer function says that the next storm will breeze on by.")
+ else
+ var/next_hit = SSweather.next_hit_by_zlevel["[T.z]"]
+ var/fixed = next_hit ? next_hit - world.time : -1
+ if(fixed < 0)
+ to_chat(user, "[src]'s barometer function was unable to trace any weather patterns.")
+ else
+ to_chat(user, "[src]'s barometer function says a storm will land in approximately [butchertime(fixed)].")
+ cooldown = TRUE
+ addtimer(CALLBACK(src,/obj/item/analyzer/proc/ping), cooldown_time)
+
+/obj/item/analyzer/proc/ping()
+ if(isliving(loc))
+ var/mob/living/L = loc
+ to_chat(L, "[src]'s barometer function is ready!")
+ playsound(src, 'sound/machines/click.ogg', 100)
+ cooldown = FALSE
+
+/obj/item/analyzer/proc/butchertime(amount)
+ if(!amount)
+ return
+ if(accuracy)
+ var/inaccurate = round(accuracy*(1/3))
+ if(prob(50))
+ amount -= inaccurate
+ if(prob(50))
+ amount += inaccurate
+ return DisplayTimeText(max(1,amount))
+
+/proc/atmosanalyzer_scan(mixture, mob/living/user, atom/target = src)
+ var/icon = target
+ user.visible_message("[user] has used the analyzer on [icon2html(icon, viewers(src))] [target].", "You use the analyzer on [icon2html(icon, user)] [target].")
+ to_chat(user, "Results of analysis of [icon2html(icon, user)] [target].")
+
+ var/list/airs = islist(mixture) ? mixture : list(mixture)
+ for(var/g in airs)
+ if(airs.len > 1) //not a unary gas mixture
+ to_chat(user, "Node [airs.Find(g)]")
+ var/datum/gas_mixture/air_contents = g
+
+ var/total_moles = air_contents.total_moles()
+ var/pressure = air_contents.return_pressure()
+ var/volume = air_contents.return_volume() //could just do mixture.volume... but safety, I guess?
+ var/temperature = air_contents.temperature
+ var/cached_scan_results = air_contents.analyzer_results
+
+ if(total_moles > 0)
+ to_chat(user, "Moles: [round(total_moles, 0.01)] mol")
+ to_chat(user, "Volume: [volume] L")
+ to_chat(user, "Pressure: [round(pressure,0.01)] kPa")
+
+ var/list/cached_gases = air_contents.gases
+ for(var/id in cached_gases)
+ var/gas_concentration = cached_gases[id]/total_moles
+ to_chat(user, "[GLOB.meta_gas_names[id]]: [round(gas_concentration*100, 0.01)] % ([round(cached_gases[id], 0.01)] mol)")
+ to_chat(user, "Temperature: [round(temperature - T0C,0.01)] °C ([round(temperature, 0.01)] K)")
+
+ else
+ if(airs.len > 1)
+ to_chat(user, "This node is empty!")
+ else
+ to_chat(user, "[target] is empty!")
+
+ if(cached_scan_results && cached_scan_results["fusion"]) //notify the user if a fusion reaction was detected
+ var/instability = round(cached_scan_results["fusion"], 0.01)
+ to_chat(user, "Large amounts of free neutrons detected in the air indicate that a fusion reaction took place.")
+ to_chat(user, "Instability of the last fusion reaction: [instability].")
+ return
+
+//slime scanner
+
+/obj/item/slime_scanner
+ name = "slime scanner"
+ desc = "A device that analyzes a slime's internal composition and measures its stats."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "adv_spectrometer"
+ item_state = "analyzer"
+ lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
+ w_class = WEIGHT_CLASS_SMALL
+ flags_1 = CONDUCT_1
+ throwforce = 0
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL=30, MAT_GLASS=20)
+
+/obj/item/slime_scanner/attack(mob/living/M, mob/living/user)
+ if(user.stat || user.eye_blind)
+ return
+ if (!isslime(M))
+ to_chat(user, "This device can only scan slimes!")
+ return
+ var/mob/living/simple_animal/slime/T = M
+ slime_scan(T, user)
+
+/proc/slime_scan(mob/living/simple_animal/slime/T, mob/living/user)
+ to_chat(user, "========================")
+ to_chat(user, "Slime scan results:")
+ to_chat(user, "[T.colour] [T.is_adult ? "adult" : "baby"] slime")
+ to_chat(user, "Nutrition: [T.nutrition]/[T.get_max_nutrition()]")
+ if (T.nutrition < T.get_starve_nutrition())
+ to_chat(user, "Warning: slime is starving!")
+ else if (T.nutrition < T.get_hunger_nutrition())
+ to_chat(user, "Warning: slime is hungry")
+ to_chat(user, "Electric change strength: [T.powerlevel]")
+ to_chat(user, "Health: [round(T.health/T.maxHealth,0.01)*100]%")
+ if (T.slime_mutation[4] == T.colour)
+ to_chat(user, "This slime does not evolve any further.")
+ else
+ if (T.slime_mutation[3] == T.slime_mutation[4])
+ if (T.slime_mutation[2] == T.slime_mutation[1])
+ to_chat(user, "Possible mutation: [T.slime_mutation[3]]")
+ to_chat(user, "Genetic destability: [T.mutation_chance/2] % chance of mutation on splitting")
+ else
+ to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]] (x2)")
+ to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting")
+ else
+ to_chat(user, "Possible mutations: [T.slime_mutation[1]], [T.slime_mutation[2]], [T.slime_mutation[3]], [T.slime_mutation[4]]")
+ to_chat(user, "Genetic destability: [T.mutation_chance] % chance of mutation on splitting")
+ if (T.cores > 1)
+ to_chat(user, "Multiple cores detected")
+ to_chat(user, "Growth progress: [T.amount_grown]/[SLIME_EVOLUTION_THRESHOLD]")
+ if(T.effectmod)
+ to_chat(user, "Core mutation in progress: [T.effectmod]")
+ to_chat(user, "Progress in core mutation: [T.applied] / [SLIME_EXTRACT_CROSSING_REQUIRED]")
+ to_chat(user, "========================")
+
+
+/obj/item/nanite_scanner
+ name = "nanite scanner"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "nanite_scanner"
+ item_state = "nanite_remote"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ desc = "A hand-held body scanner able to detect nanites and their programming."
+ flags_1 = CONDUCT_1
+ item_flags = NOBLUDGEON
+ slot_flags = ITEM_SLOT_BELT
+ throwforce = 3
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL=200)
+
+/obj/item/nanite_scanner/attack(mob/living/M, mob/living/carbon/human/user)
+ user.visible_message("[user] has analyzed [M]'s nanites.")
+
+ add_fingerprint(user)
+
+ var/response = SEND_SIGNAL(M, COMSIG_NANITE_SCAN, user, TRUE)
+ if(!response)
+ to_chat(user, "No nanites detected in the subject.")
+
+/obj/item/sequence_scanner
+ name = "genetic sequence scanner"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "gene"
+ item_state = "healthanalyzer"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ desc = "A hand-held scanner able to swiftly scan someone for potential mutations. Hold near a DNA console to update from their database."
+ flags_1 = CONDUCT_1
+ item_flags = NOBLUDGEON
+ slot_flags = ITEM_SLOT_BELT
+ throwforce = 3
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL=200)
+ var/list/discovered = list() //hit a dna console to update the scanners database
+
+/obj/item/sequence_scanner/attack(mob/living/M, mob/living/carbon/human/user)
+ user.visible_message("[user] has analyzed [M]'s genetic sequence.")
+
+ add_fingerprint(user)
+
+ gene_scan(M, user, src)
+
+/obj/item/sequence_scanner/afterattack(obj/O, mob/user, proximity)
+ . = ..()
+ if(!istype(O) || !proximity)
+ return
+
+ if(istype(O, /obj/machinery/computer/scan_consolenew))
+ var/obj/machinery/computer/scan_consolenew/C = O
+ if(C.stored_research)
+ to_chat(user, "[name] database updated.")
+ discovered = C.stored_research.discovered_mutations
+ else
+ to_chat(user,"No database to update from.")
+
+/proc/gene_scan(mob/living/carbon/C, mob/living/user, obj/item/sequence_scanner/G)
+ if(!iscarbon(C) || !C.has_dna())
+ return
+ to_chat(user, "[C.name]'s potential mutations.")
+ for(var/A in C.dna.mutation_index)
+ var/datum/mutation/human/HM = GET_INITIALIZED_MUTATION(A)
+ var/mut_name
+ if(G && (A in G.discovered))
+ mut_name = "[HM.name] ([HM.alias])"
+ else
+ mut_name = HM.alias
+ var/temp = GET_GENE_STRING(HM.type, C.dna)
+ var/display
+ for(var/i in 0 to length(temp) / DNA_MUTATION_BLOCKS-1)
+ if(i)
+ display += "-"
+ display += copytext(temp, 1 + i*DNA_MUTATION_BLOCKS, DNA_MUTATION_BLOCKS*(1+i) + 1)
+
+
+ to_chat(user, "- [mut_name] > [display]")
diff --git a/code/game/objects/items/extinguisher.dm b/code/game/objects/items/extinguisher.dm
index d54cf4b1..81317b6e 100644
--- a/code/game/objects/items/extinguisher.dm
+++ b/code/game/objects/items/extinguisher.dm
@@ -1,257 +1,257 @@
-/obj/item/extinguisher
- name = "fire extinguisher"
- desc = "A traditional red fire extinguisher."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "fire_extinguisher0"
- item_state = "fire_extinguisher"
- hitsound = 'sound/weapons/smash.ogg'
- flags_1 = CONDUCT_1
- throwforce = 10
- w_class = WEIGHT_CLASS_NORMAL
- throw_speed = 2
- throw_range = 7
- force = 10
- materials = list(MAT_METAL = 90)
- attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed")
- dog_fashion = /datum/dog_fashion/back
- resistance_flags = FIRE_PROOF
- var/max_water = 50
- var/last_use = 1
- var/chem = "water"
- var/safety = TRUE
- var/refilling = FALSE
- var/tanktype = /obj/structure/reagent_dispensers/watertank
- var/sprite_name = "fire_extinguisher"
- var/power = 5 //Maximum distance launched water will travel
- var/precision = FALSE //By default, turfs picked from a spray are random, set to 1 to make it always have at least one water effect per row
- var/cooling_power = 2 //Sets the cooling_temperature of the water reagent datum inside of the extinguisher when it is refilled
-
-/obj/item/extinguisher/mini
- name = "pocket fire extinguisher"
- desc = "A light and compact fibreglass-framed model fire extinguisher."
- icon_state = "miniFE0"
- item_state = "miniFE"
- hitsound = null //it is much lighter, after all.
- flags_1 = null //doesn't CONDUCT_1
- throwforce = 2
- w_class = WEIGHT_CLASS_SMALL
- force = 3
- materials = list(MAT_METAL = 50, MAT_GLASS = 40)
- max_water = 30
- sprite_name = "miniFE"
- dog_fashion = null
-
-/obj/item/extinguisher/mini/family
- name = "pocket fire extinguisher"
- desc = "A old fashen pocket fire extinguisher that has been modified with a larger water tank, and a small high-power sprayer. It feels cool to the touch and has a small humming to it..."
- icon_state = "miniFE0"
- item_state = "miniFE"
- throwforce = 1
- w_class = WEIGHT_CLASS_SMALL
- force = 2
- max_water = 40
- power = 7
- cooling_power = 3
-
-/obj/item/extinguisher/Initialize()
- . = ..()
- create_reagents(max_water, AMOUNT_VISIBLE)
- reagents.add_reagent(chem, max_water)
-
-
-/obj/item/extinguisher/advanced
- name = "advanced fire extinguisher"
- desc = "Used to stop thermonuclear fires from spreading inside your engine."
- icon_state = "foam_extinguisher0"
- //item_state = "foam_extinguisher" needs sprite
- dog_fashion = null
- chem = "firefighting_foam"
- tanktype = /obj/structure/reagent_dispensers/foamtank
- sprite_name = "foam_extinguisher"
- precision = TRUE
-
-/obj/item/extinguisher/proc/refill()
- create_reagents(max_water, AMOUNT_VISIBLE)
- reagents.add_reagent(chem, max_water)
-
-/obj/item/extinguisher/suicide_act(mob/living/carbon/user)
- if (!safety && (reagents.total_volume >= 1))
- user.visible_message("[user] puts the nozzle to [user.p_their()] mouth. It looks like [user.p_theyre()] trying to extinguish the spark of life!")
- afterattack(user,user)
- return OXYLOSS
- else if (safety && (reagents.total_volume >= 1))
- user.visible_message("[user] puts the nozzle to [user.p_their()] mouth... The safety's still on!")
- return SHAME
- else
- user.visible_message("[user] puts the nozzle to [user.p_their()] mouth... [src] is empty!")
- return SHAME
-
-/obj/item/extinguisher/attack_self(mob/user)
- safety = !safety
- src.icon_state = "[sprite_name][!safety]"
- to_chat(user, "The safety is [safety ? "on" : "off"].")
- return
-
-/obj/item/extinguisher/attack(mob/M, mob/user)
- if(user.a_intent == INTENT_HELP && !safety) //If we're on help intent and going to spray people, don't bash them.
- return FALSE
- else
- return ..()
-
-/obj/item/extinguisher/attack_obj(obj/O, mob/living/user)
- if(AttemptRefill(O, user))
- refilling = TRUE
- return FALSE
- else
- return ..()
-
-/obj/item/extinguisher/examine(mob/user)
- . = ..()
- . += "The safety is [safety ? "on" : "off"]."
-
- if(reagents.total_volume)
- . += "You can loose its screws to empty it."
-
-/obj/item/extinguisher/proc/AttemptRefill(atom/target, mob/user)
- if(istype(target, tanktype) && target.Adjacent(user))
- var/safety_save = safety
- safety = TRUE
- if(reagents.total_volume == reagents.maximum_volume)
- to_chat(user, "\The [src] is already full!")
- safety = safety_save
- return 1
- var/obj/structure/reagent_dispensers/W = target //will it work?
- var/transferred = W.reagents.trans_to(src, max_water)
- if(transferred > 0)
- to_chat(user, "\The [src] has been refilled by [transferred] units.")
- playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6)
- for(var/datum/reagent/water/R in reagents.reagent_list)
- R.cooling_temperature = cooling_power
- else
- to_chat(user, "\The [W] is empty!")
- safety = safety_save
- return 1
- else
- return 0
-
-/obj/item/extinguisher/afterattack(atom/target, mob/user , flag)
- . = ..()
- // Make it so the extinguisher doesn't spray yourself when you click your inventory items
- if (target.loc == user)
- return
- //TODO; Add support for reagents in water.
- if(refilling)
- refilling = FALSE
- return
- if (!safety)
- if (src.reagents.total_volume < 1)
- to_chat(usr, "\The [src] is empty!")
- return
-
- if (world.time < src.last_use + 12)
- return
-
- src.last_use = world.time
-
- playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3)
-
- var/direction = get_dir(src,target)
-
- if(user.buckled && isobj(user.buckled) && !user.buckled.anchored)
- var/obj/B = user.buckled
- var/movementdirection = turn(direction,180)
- addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_chair, B, movementdirection), 1)
-
- else user.newtonian_move(turn(direction, 180))
-
- //Get all the turfs that can be shot at
- var/turf/T = get_turf(target)
- var/turf/T1 = get_step(T,turn(direction, 90))
- var/turf/T2 = get_step(T,turn(direction, -90))
- var/list/the_targets = list(T,T1,T2)
- if(precision)
- var/turf/T3 = get_step(T1, turn(direction, 90))
- var/turf/T4 = get_step(T2,turn(direction, -90))
- the_targets.Add(T3,T4)
-
- var/list/water_particles=list()
- for(var/a=0, a<5, a++)
- var/obj/effect/particle_effect/water/W = new /obj/effect/particle_effect/water(get_turf(src))
- var/my_target = pick(the_targets)
- water_particles[W] = my_target
- // If precise, remove turf from targets so it won't be picked more than once
- if(precision)
- the_targets -= my_target
- var/datum/reagents/R = new/datum/reagents(5)
- W.reagents = R
- R.my_atom = W
- reagents.trans_to(W,1)
-
- //Make em move dat ass, hun
- addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_particles, water_particles), 2)
-
-//Particle movement loop
-/obj/item/extinguisher/proc/move_particles(var/list/particles, var/repetition=0)
- //Check if there's anything in here first
- if(!particles || particles.len == 0)
- return
- // Second loop: Get all the water particles and make them move to their target
- for(var/obj/effect/particle_effect/water/W in particles)
- var/turf/my_target = particles[W]
- if(!W)
- continue
- step_towards(W,my_target)
- if(!W.reagents)
- continue
- W.reagents.reaction(get_turf(W))
- for(var/A in get_turf(W))
- W.reagents.reaction(A)
- if(W.loc == my_target)
- break
- if(repetition < power)
- repetition++
- addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_particles, particles, repetition), 2)
-
-//Chair movement loop
-/obj/item/extinguisher/proc/move_chair(var/obj/B, var/movementdirection, var/repetition=0)
- step(B, movementdirection)
-
- var/timer_seconds
- switch(repetition)
- if(0 to 2)
- timer_seconds = 1
- if(3 to 4)
- timer_seconds = 2
- if(5 to 8)
- timer_seconds = 3
- else
- return
-
- repetition++
- addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_chair, B, movementdirection, repetition), timer_seconds)
-
-/obj/item/extinguisher/screwdriver_act(mob/user, obj/item/tool)
- if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
- return
- EmptyExtinguisher(user)
-
-/obj/item/extinguisher/proc/EmptyExtinguisher(var/mob/user)
- if(loc == user && reagents.total_volume)
- reagents.clear_reagents()
-
- var/turf/T = get_turf(loc)
- if(isopenturf(T))
- var/turf/open/theturf = T
- theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
-
- user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by loosing the release valve's screws.")
-
-//firebot assembly
-/obj/item/extinguisher/attackby(obj/O, mob/user, params)
- if(istype(O, /obj/item/bodypart/l_arm/robot) || istype(O, /obj/item/bodypart/r_arm/robot))
- to_chat(user, "You add [O] to [src].")
- qdel(O)
- qdel(src)
- user.put_in_hands(new /obj/item/bot_assembly/firebot)
- else
- ..()
+/obj/item/extinguisher
+ name = "fire extinguisher"
+ desc = "A traditional red fire extinguisher."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "fire_extinguisher0"
+ item_state = "fire_extinguisher"
+ hitsound = 'sound/weapons/smash.ogg'
+ flags_1 = CONDUCT_1
+ throwforce = 10
+ w_class = WEIGHT_CLASS_NORMAL
+ throw_speed = 2
+ throw_range = 7
+ force = 10
+ materials = list(MAT_METAL = 90)
+ attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed")
+ dog_fashion = /datum/dog_fashion/back
+ resistance_flags = FIRE_PROOF
+ var/max_water = 50
+ var/last_use = 1
+ var/chem = /datum/reagent/water
+ var/safety = TRUE
+ var/refilling = FALSE
+ var/tanktype = /obj/structure/reagent_dispensers/watertank
+ var/sprite_name = "fire_extinguisher"
+ var/power = 5 //Maximum distance launched water will travel
+ var/precision = FALSE //By default, turfs picked from a spray are random, set to 1 to make it always have at least one water effect per row
+ var/cooling_power = 2 //Sets the cooling_temperature of the water reagent datum inside of the extinguisher when it is refilled
+
+/obj/item/extinguisher/mini
+ name = "pocket fire extinguisher"
+ desc = "A light and compact fibreglass-framed model fire extinguisher."
+ icon_state = "miniFE0"
+ item_state = "miniFE"
+ hitsound = null //it is much lighter, after all.
+ flags_1 = null //doesn't CONDUCT_1
+ throwforce = 2
+ w_class = WEIGHT_CLASS_SMALL
+ force = 3
+ materials = list(MAT_METAL = 50, MAT_GLASS = 40)
+ max_water = 30
+ sprite_name = "miniFE"
+ dog_fashion = null
+
+/obj/item/extinguisher/mini/family
+ name = "pocket fire extinguisher"
+ desc = "A old fashen pocket fire extinguisher that has been modified with a larger water tank, and a small high-power sprayer. It feels cool to the touch and has a small humming to it..."
+ icon_state = "miniFE0"
+ item_state = "miniFE"
+ throwforce = 1
+ w_class = WEIGHT_CLASS_SMALL
+ force = 2
+ max_water = 40
+ power = 7
+ cooling_power = 3
+
+/obj/item/extinguisher/Initialize()
+ . = ..()
+ create_reagents(max_water, AMOUNT_VISIBLE)
+ reagents.add_reagent(chem, max_water)
+
+
+/obj/item/extinguisher/advanced
+ name = "advanced fire extinguisher"
+ desc = "Used to stop thermonuclear fires from spreading inside your engine."
+ icon_state = "foam_extinguisher0"
+ //item_state = "foam_extinguisher" needs sprite
+ dog_fashion = null
+ chem = /datum/reagent/firefighting_foam
+ tanktype = /obj/structure/reagent_dispensers/foamtank
+ sprite_name = "foam_extinguisher"
+ precision = TRUE
+
+/obj/item/extinguisher/proc/refill()
+ create_reagents(max_water, AMOUNT_VISIBLE)
+ reagents.add_reagent(chem, max_water)
+
+/obj/item/extinguisher/suicide_act(mob/living/carbon/user)
+ if (!safety && (reagents.total_volume >= 1))
+ user.visible_message("[user] puts the nozzle to [user.p_their()] mouth. It looks like [user.p_theyre()] trying to extinguish the spark of life!")
+ afterattack(user,user)
+ return OXYLOSS
+ else if (safety && (reagents.total_volume >= 1))
+ user.visible_message("[user] puts the nozzle to [user.p_their()] mouth... The safety's still on!")
+ return SHAME
+ else
+ user.visible_message("[user] puts the nozzle to [user.p_their()] mouth... [src] is empty!")
+ return SHAME
+
+/obj/item/extinguisher/attack_self(mob/user)
+ safety = !safety
+ src.icon_state = "[sprite_name][!safety]"
+ to_chat(user, "The safety is [safety ? "on" : "off"].")
+ return
+
+/obj/item/extinguisher/attack(mob/M, mob/user)
+ if(user.a_intent == INTENT_HELP && !safety) //If we're on help intent and going to spray people, don't bash them.
+ return FALSE
+ else
+ return ..()
+
+/obj/item/extinguisher/attack_obj(obj/O, mob/living/user)
+ if(AttemptRefill(O, user))
+ refilling = TRUE
+ return FALSE
+ else
+ return ..()
+
+/obj/item/extinguisher/examine(mob/user)
+ . = ..()
+ . += "The safety is [safety ? "on" : "off"]."
+
+ if(reagents.total_volume)
+ . += "You can loose its screws to empty it."
+
+/obj/item/extinguisher/proc/AttemptRefill(atom/target, mob/user)
+ if(istype(target, tanktype) && target.Adjacent(user))
+ var/safety_save = safety
+ safety = TRUE
+ if(reagents.total_volume == reagents.maximum_volume)
+ to_chat(user, "\The [src] is already full!")
+ safety = safety_save
+ return 1
+ var/obj/structure/reagent_dispensers/W = target //will it work?
+ var/transferred = W.reagents.trans_to(src, max_water)
+ if(transferred > 0)
+ to_chat(user, "\The [src] has been refilled by [transferred] units.")
+ playsound(src.loc, 'sound/effects/refill.ogg', 50, 1, -6)
+ for(var/datum/reagent/water/R in reagents.reagent_list)
+ R.cooling_temperature = cooling_power
+ else
+ to_chat(user, "\The [W] is empty!")
+ safety = safety_save
+ return 1
+ else
+ return 0
+
+/obj/item/extinguisher/afterattack(atom/target, mob/user , flag)
+ . = ..()
+ // Make it so the extinguisher doesn't spray yourself when you click your inventory items
+ if (target.loc == user)
+ return
+ //TODO; Add support for reagents in water.
+ if(refilling)
+ refilling = FALSE
+ return
+ if (!safety)
+ if (src.reagents.total_volume < 1)
+ to_chat(usr, "\The [src] is empty!")
+ return
+
+ if (world.time < src.last_use + 12)
+ return
+
+ src.last_use = world.time
+
+ playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3)
+
+ var/direction = get_dir(src,target)
+
+ if(user.buckled && isobj(user.buckled) && !user.buckled.anchored)
+ var/obj/B = user.buckled
+ var/movementdirection = turn(direction,180)
+ addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_chair, B, movementdirection), 1)
+
+ else user.newtonian_move(turn(direction, 180))
+
+ //Get all the turfs that can be shot at
+ var/turf/T = get_turf(target)
+ var/turf/T1 = get_step(T,turn(direction, 90))
+ var/turf/T2 = get_step(T,turn(direction, -90))
+ var/list/the_targets = list(T,T1,T2)
+ if(precision)
+ var/turf/T3 = get_step(T1, turn(direction, 90))
+ var/turf/T4 = get_step(T2,turn(direction, -90))
+ the_targets.Add(T3,T4)
+
+ var/list/water_particles=list()
+ for(var/a=0, a<5, a++)
+ var/obj/effect/particle_effect/water/W = new /obj/effect/particle_effect/water(get_turf(src))
+ var/my_target = pick(the_targets)
+ water_particles[W] = my_target
+ // If precise, remove turf from targets so it won't be picked more than once
+ if(precision)
+ the_targets -= my_target
+ var/datum/reagents/R = new/datum/reagents(5)
+ W.reagents = R
+ R.my_atom = W
+ reagents.trans_to(W,1)
+
+ //Make em move dat ass, hun
+ addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_particles, water_particles), 2)
+
+//Particle movement loop
+/obj/item/extinguisher/proc/move_particles(var/list/particles, var/repetition=0)
+ //Check if there's anything in here first
+ if(!particles || particles.len == 0)
+ return
+ // Second loop: Get all the water particles and make them move to their target
+ for(var/obj/effect/particle_effect/water/W in particles)
+ var/turf/my_target = particles[W]
+ if(!W)
+ continue
+ step_towards(W,my_target)
+ if(!W.reagents)
+ continue
+ W.reagents.reaction(get_turf(W))
+ for(var/A in get_turf(W))
+ W.reagents.reaction(A)
+ if(W.loc == my_target)
+ break
+ if(repetition < power)
+ repetition++
+ addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_particles, particles, repetition), 2)
+
+//Chair movement loop
+/obj/item/extinguisher/proc/move_chair(var/obj/B, var/movementdirection, var/repetition=0)
+ step(B, movementdirection)
+
+ var/timer_seconds
+ switch(repetition)
+ if(0 to 2)
+ timer_seconds = 1
+ if(3 to 4)
+ timer_seconds = 2
+ if(5 to 8)
+ timer_seconds = 3
+ else
+ return
+
+ repetition++
+ addtimer(CALLBACK(src, /obj/item/extinguisher/proc/move_chair, B, movementdirection, repetition), timer_seconds)
+
+/obj/item/extinguisher/screwdriver_act(mob/user, obj/item/tool)
+ if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+ EmptyExtinguisher(user)
+
+/obj/item/extinguisher/proc/EmptyExtinguisher(var/mob/user)
+ if(loc == user && reagents.total_volume)
+ reagents.clear_reagents()
+
+ var/turf/T = get_turf(loc)
+ if(isopenturf(T))
+ var/turf/open/theturf = T
+ theturf.MakeSlippery(TURF_WET_WATER, min_wet_time = 10 SECONDS, wet_time_to_add = 5 SECONDS)
+
+ user.visible_message("[user] empties out \the [src] onto the floor using the release valve.", "You quietly empty out \the [src] by loosing the release valve's screws.")
+
+//firebot assembly
+/obj/item/extinguisher/attackby(obj/O, mob/user, params)
+ if(istype(O, /obj/item/bodypart/l_arm/robot) || istype(O, /obj/item/bodypart/r_arm/robot))
+ to_chat(user, "You add [O] to [src].")
+ qdel(O)
+ qdel(src)
+ user.put_in_hands(new /obj/item/bot_assembly/firebot)
+ else
+ ..()
diff --git a/code/game/objects/items/grenades/chem_grenade.dm b/code/game/objects/items/grenades/chem_grenade.dm
index a21d14ca..92bc25ea 100644
--- a/code/game/objects/items/grenades/chem_grenade.dm
+++ b/code/game/objects/items/grenades/chem_grenade.dm
@@ -1,602 +1,602 @@
-#define EMPTY 1
-#define WIRED 2
-#define READY 3
-
-/obj/item/grenade/chem_grenade
- name = "chemical grenade"
- desc = "A custom made grenade."
- icon_state = "chemg"
- item_state = "flashbang"
- w_class = WEIGHT_CLASS_SMALL
- force = 2
- var/stage = EMPTY
- var/list/beakers = list()
- var/list/allowed_containers = list(/obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle)
- var/affected_area = 3
- var/obj/item/assembly_holder/nadeassembly = null
- var/assemblyattacher
- var/ignition_temp = 10 // The amount of heat added to the reagents when this grenade goes off.
- var/threatscale = 1 // Used by advanced grenades to make them slightly more worthy.
- var/no_splash = FALSE //If the grenade deletes even if it has no reagents to splash with. Used for slime core reactions.
- var/casedesc = "This basic model accepts both beakers and bottles. It heats contents by 10°K upon ignition." // Appears when examining empty casings.
-
-/obj/item/grenade/chem_grenade/Initialize()
- . = ..()
- create_reagents(1000)
- stage_change() // If no argument is set, it will change the stage to the current stage, useful for stock grenades that start READY.
-
-/obj/item/grenade/chem_grenade/examine(mob/user)
- display_timer = (stage == READY && !nadeassembly) //show/hide the timer based on assembly state
- . = ..()
- if(user.can_see_reagents())
- var/count = 0
- if(beakers.len)
- . += "You scan the grenade and detect the following reagents:"
- for(var/obj/item/reagent_containers/glass/G in beakers)
- var/textcount = thtotext(++count)
- for(var/datum/reagent/R in G.reagents.reagent_list)
- . += "[R.volume] units of [R.name] in the [textcount] beaker."
- if(beakers.len == 1)
- . += "You detect no second beaker in the grenade."
- else
- . += "You scan the grenade, but detect nothing."
-
-
-/obj/item/grenade/chem_grenade/attack_self(mob/user)
- if(stage == READY && !active)
- if(nadeassembly)
- nadeassembly.attack_self(user)
- else
- ..()
-
-
-/obj/item/grenade/chem_grenade/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/screwdriver))
- if(stage == WIRED)
- if(beakers.len)
- stage_change(READY)
- to_chat(user, "You lock the [initial(name)] assembly.")
- I.play_tool_sound(src, 25)
- else
- to_chat(user, "You need to add at least one beaker before locking the [initial(name)] assembly!")
- else if(stage == READY && !nadeassembly)
- det_time = det_time == 50 ? 30 : 50 //toggle between 30 and 50
- to_chat(user, "You modify the time delay. It's set for [DisplayTimeText(det_time)].")
- else if(stage == EMPTY)
- to_chat(user, "You need to add an activation mechanism!")
-
- else if(stage == WIRED && is_type_in_list(I, allowed_containers))
- . = 1 //no afterattack
- if(beakers.len == 2)
- to_chat(user, "[src] can not hold more containers!")
- return
- else
- if(I.reagents.total_volume)
- if(!user.transferItemToLoc(I, src))
- return
- to_chat(user, "You add [I] to the [initial(name)] assembly.")
- beakers += I
- var/reagent_list = pretty_string_from_reagent_list(I.reagents)
- user.log_message("inserted [I] ([reagent_list]) into [src]",LOG_GAME)
- else
- to_chat(user, "[I] is empty!")
-
- else if(stage == EMPTY && istype(I, /obj/item/assembly_holder))
- . = 1 // no afterattack
- var/obj/item/assembly_holder/A = I
- if(isigniter(A.a_left) == isigniter(A.a_right)) //Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it
- return
- if(!user.transferItemToLoc(I, src))
- return
-
- nadeassembly = A
- A.master = src
- assemblyattacher = user.ckey
-
- stage_change(WIRED)
- to_chat(user, "You add [A] to the [initial(name)] assembly.")
-
- else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/C = I
- if (C.use(1))
- det_time = 50 // In case the cable_coil was removed and readded.
- stage_change(WIRED)
- to_chat(user, "You rig the [initial(name)] assembly.")
- else
- to_chat(user, "You need one length of coil to wire the assembly!")
- return
-
- else if(stage == READY && istype(I, /obj/item/wirecutters) && !active)
- stage_change(WIRED)
- to_chat(user, "You unlock the [initial(name)] assembly.")
-
- else if(stage == WIRED && istype(I, /obj/item/wrench))
- if(beakers.len)
- for(var/obj/O in beakers)
- O.forceMove(drop_location())
- if(!O.reagents)
- continue
- var/reagent_list = pretty_string_from_reagent_list(O.reagents)
- user.log_message("removed [O] ([reagent_list]) from [src]", LOG_GAME)
- beakers = list()
- to_chat(user, "You open the [initial(name)] assembly and remove the payload.")
- return // First use of the wrench remove beakers, then use the wrench to remove the activation mechanism.
- if(nadeassembly)
- nadeassembly.forceMove(drop_location())
- nadeassembly.master = null
- nadeassembly = null
- else // If "nadeassembly = null && stage == WIRED", then it most have been cable_coil that was used.
- new /obj/item/stack/cable_coil(get_turf(src),1)
- stage_change(EMPTY)
- to_chat(user, "You remove the activation mechanism from the [initial(name)] assembly.")
- else
- return ..()
-
-/obj/item/grenade/chem_grenade/proc/stage_change(N)
- if(N)
- stage = N
- if(stage == EMPTY)
- name = "[initial(name)] casing"
- desc = "A do it yourself [initial(name)]! [initial(casedesc)]"
- icon_state = initial(icon_state)
- else if(stage == WIRED)
- name = "unsecured [initial(name)]"
- desc = "An unsecured [initial(name)] assembly."
- icon_state = "[initial(icon_state)]_ass"
- else if(stage == READY)
- name = initial(name)
- desc = initial(desc)
- icon_state = "[initial(icon_state)]_locked"
-
-
-//assembly stuff
-/obj/item/grenade/chem_grenade/receive_signal()
- prime()
-
-
-/obj/item/grenade/chem_grenade/Crossed(atom/movable/AM)
- if(nadeassembly)
- nadeassembly.Crossed(AM)
-
-/obj/item/grenade/chem_grenade/on_found(mob/finder)
- if(nadeassembly)
- nadeassembly.on_found(finder)
-
-/obj/item/grenade/chem_grenade/log_grenade(mob/user, turf/T)
- ..()
- var/reagent_string = ""
- var/beaker_number = 1
- for(var/obj/exploded_beaker in beakers)
- if(!exploded_beaker.reagents)
- continue
- reagent_string += "[exploded_beaker] [beaker_number++] : " + pretty_string_from_reagent_list(exploded_beaker.reagents.reagent_list) + ";"
- var/message = "[src] primed by [user] at [ADMIN_VERBOSEJMP(T)] contained [reagent_string]."
- GLOB.bombers += message
- message_admins(message)
- user.log_message("primed [src] ([reagent_string])",LOG_GAME)
-
-/obj/item/grenade/chem_grenade/prime()
- if(stage != READY)
- return
-
- var/list/datum/reagents/reactants = list()
- for(var/obj/item/reagent_containers/glass/G in beakers)
- reactants += G.reagents
-
- var/turf/detonation_turf = get_turf(src)
-
- if(!chem_splash(detonation_turf, affected_area, reactants, ignition_temp, threatscale) && !no_splash)
- playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
- if(beakers.len)
- for(var/obj/O in beakers)
- O.forceMove(drop_location())
- beakers = list()
- stage_change(EMPTY)
- return
-
- if(nadeassembly)
- var/mob/M = get_mob_by_ckey(assemblyattacher)
- var/mob/last = get_mob_by_ckey(nadeassembly.fingerprintslast)
- message_admins("grenade primed by an assembly, attached by [ADMIN_LOOKUPFLW(M)] and last touched by [ADMIN_LOOKUPFLW(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [ADMIN_VERBOSEJMP(detonation_turf)].")
- log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [AREACOORD(detonation_turf)]")
-
- log_game("A grenade detonated at [AREACOORD(detonation_turf)]")
-
- update_mob()
-
- qdel(src)
-
-//Large chem grenades accept slime cores and use the appropriately.
-/obj/item/grenade/chem_grenade/large
- name = "large grenade"
- desc = "A custom made large grenade. Larger splash range and increased ignition temperature compared to basic grenades. Fits exotic containers."
- casedesc = "This casing affects a larger area than the basic model and can fit exotic containers, including slime cores. Heats contents by 25°K upon ignition."
- icon_state = "large_grenade"
- allowed_containers = list(/obj/item/reagent_containers/glass, /obj/item/reagent_containers/food/condiment, /obj/item/reagent_containers/food/drinks)
- affected_area = 5
- ignition_temp = 25 // Large grenades are slightly more effective at setting off heat-sensitive mixtures than smaller grenades.
- threatscale = 1.1 // 10% more effective.
-
-/obj/item/grenade/chem_grenade/large/prime()
- if(stage != READY)
- return
-
- for(var/obj/item/slime_extract/S in beakers)
- if(S.Uses)
- for(var/obj/item/reagent_containers/glass/G in beakers)
- G.reagents.trans_to(S, G.reagents.total_volume)
-
- //If there is still a core (sometimes it's used up)
- //and there are reagents left, behave normally,
- //otherwise drop it on the ground for timed reactions like gold.
-
- if(S)
- if(S.reagents && S.reagents.total_volume)
- for(var/obj/item/reagent_containers/glass/G in beakers)
- S.reagents.trans_to(G, S.reagents.total_volume)
- else
- S.forceMove(get_turf(src))
- no_splash = TRUE
- ..()
-
- //I tried to just put it in the allowed_containers list but
- //if you do that it must have reagents. If you're going to
- //make a special case you might as well do it explicitly. -Sayu
-/obj/item/grenade/chem_grenade/large/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/slime_extract) && stage == WIRED)
- if(!user.transferItemToLoc(I, src))
- return
- to_chat(user, "You add [I] to the [initial(name)] assembly.")
- beakers += I
- else
- return ..()
-
-/obj/item/grenade/chem_grenade/cryo // Intended for rare cryogenic mixes. Cools the area moderately upon detonation.
- name = "cryo grenade"
- desc = "A custom made cryogenic grenade. Rapidly cools contents upon ignition."
- casedesc = "Upon ignition, it rapidly cools contents by 100°K. Smaller splash range than regular casings."
- icon_state = "cryog"
- affected_area = 2
- ignition_temp = -100
-
-/obj/item/grenade/chem_grenade/pyro // Intended for pyrotechnical mixes. Produces a small fire upon detonation, igniting potentially flammable mixtures.
- name = "pyro grenade"
- desc = "A custom made pyrotechnical grenade. Heats up contents upon ignition."
- casedesc = "Upon ignition, it rapidly heats contents by 500°K."
- icon_state = "pyrog"
- ignition_temp = 500 // This is enough to expose a hotspot.
-
-/obj/item/grenade/chem_grenade/adv_release // Intended for weaker, but longer lasting effects. Could have some interesting uses.
- name = "advanced release grenade"
- desc = "A custom made advanced release grenade. It is able to be detonated more than once. Can be configured using a multitool."
- casedesc = "This casing is able to detonate more than once. Can be configured using a multitool."
- icon_state = "timeg"
- var/unit_spread = 10 // Amount of units per repeat. Can be altered with a multitool.
-
-/obj/item/grenade/chem_grenade/adv_release/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/multitool))
- switch(unit_spread)
- if(0 to 24)
- unit_spread += 5
- if(25 to 99)
- unit_spread += 25
- else
- unit_spread = 5
- to_chat(user, " You set the time release to [unit_spread] units per detonation.")
- return
- ..()
-
-/obj/item/grenade/chem_grenade/adv_release/prime()
- if(stage != READY)
- return
-
- var/total_volume = 0
- for(var/obj/item/reagent_containers/RC in beakers)
- total_volume += RC.reagents.total_volume
- if(!total_volume)
- qdel(src)
- qdel(nadeassembly)
- return
- var/fraction = unit_spread/total_volume
- var/datum/reagents/reactants = new(unit_spread)
- reactants.my_atom = src
- for(var/obj/item/reagent_containers/RC in beakers)
- RC.reagents.trans_to(reactants, RC.reagents.total_volume*fraction, threatscale, 1, 1)
- chem_splash(get_turf(src), affected_area, list(reactants), ignition_temp, threatscale)
-
- var/turf/DT = get_turf(src)
- if(nadeassembly)
- var/mob/M = get_mob_by_ckey(assemblyattacher)
- var/mob/last = get_mob_by_ckey(nadeassembly.fingerprintslast)
- message_admins("grenade primed by an assembly at [AREACOORD(DT)], attached by [ADMIN_LOOKUPFLW(M)] and last touched by [ADMIN_LOOKUPFLW(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]).")
- log_game("grenade primed by an assembly at [AREACOORD(DT)], attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name])")
- else
- addtimer(CALLBACK(src, .proc/prime), det_time)
- log_game("A grenade detonated at [AREACOORD(DT)]")
-
-
-
-
-
-//////////////////////////////
-////// PREMADE GRENADES //////
-//////////////////////////////
-
-/obj/item/grenade/chem_grenade/metalfoam
- name = "metal foam grenade"
- desc = "Used for emergency sealing of hull breaches."
- stage = READY
-
-/obj/item/grenade/chem_grenade/metalfoam/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
-
- B1.reagents.add_reagent("aluminium", 30)
- B2.reagents.add_reagent("foaming_agent", 10)
- B2.reagents.add_reagent("facid", 10)
-
- beakers += B1
- beakers += B2
-
-
-/obj/item/grenade/chem_grenade/smart_metal_foam
- name = "smart metal foam grenade"
- desc = "Used for emergency sealing of hull breaches, while keeping areas accessible."
- stage = READY
-
-/obj/item/grenade/chem_grenade/smart_metal_foam/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/large/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
-
- B1.reagents.add_reagent("aluminium", 75)
- B2.reagents.add_reagent("smart_foaming_agent", 25)
- B2.reagents.add_reagent("facid", 25)
-
- beakers += B1
- beakers += B2
-
-
-/obj/item/grenade/chem_grenade/incendiary
- name = "incendiary grenade"
- desc = "Used for clearing rooms of living things."
- stage = READY
-
-/obj/item/grenade/chem_grenade/incendiary/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
-
- B1.reagents.add_reagent("phosphorus", 25)
- B2.reagents.add_reagent("stable_plasma", 25)
- B2.reagents.add_reagent("sacid", 25)
-
- beakers += B1
- beakers += B2
-
-
-/obj/item/grenade/chem_grenade/antiweed
- name = "weedkiller grenade"
- desc = "Used for purging large areas of invasive plant species. Contents under pressure. Do not directly inhale contents."
- stage = READY
-
-/obj/item/grenade/chem_grenade/antiweed/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
-
- B1.reagents.add_reagent("plantbgone", 25)
- B1.reagents.add_reagent("potassium", 25)
- B2.reagents.add_reagent("phosphorus", 25)
- B2.reagents.add_reagent("sugar", 25)
-
- beakers += B1
- beakers += B2
-
-
-/obj/item/grenade/chem_grenade/cleaner
- name = "cleaner grenade"
- desc = "BLAM!-brand foaming space cleaner. In a special applicator for rapid cleaning of wide areas."
- stage = READY
-
-/obj/item/grenade/chem_grenade/cleaner/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/plastic/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/plastic/B2 = new(src)
-
- B1.reagents.add_reagent("fluorosurfactant", 40)
- B2.reagents.add_reagent("water", 40)
- B2.reagents.add_reagent("cleaner", 10)
-
- beakers += B1
- beakers += B2
-
-
-/obj/item/grenade/chem_grenade/ez_clean
- name = "cleaner grenade"
- desc = "Waffle Co.-brand foaming space cleaner. In a special applicator for rapid cleaning of wide areas."
- stage = READY
-
-/obj/item/grenade/chem_grenade/ez_clean/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/plastic/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/plastic/B2 = new(src)
-
- B1.reagents.add_reagent("fluorosurfactant", 40)
- B2.reagents.add_reagent("water", 40)
- B2.reagents.add_reagent("ez_clean", 60) //ensures a t h i c c distribution
-
- beakers += B1
- beakers += B2
-
-
-
-/obj/item/grenade/chem_grenade/teargas
- name = "teargas grenade"
- desc = "Used for nonlethal riot control. Contents under pressure. Do not directly inhale contents."
- stage = READY
-
-/obj/item/grenade/chem_grenade/teargas/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/large/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/large/B2 = new(src)
-
- B1.reagents.add_reagent("condensedcapsaicin", 60)
- B1.reagents.add_reagent("potassium", 40)
- B2.reagents.add_reagent("phosphorus", 40)
- B2.reagents.add_reagent("sugar", 40)
-
- beakers += B1
- beakers += B2
-
-
-/obj/item/grenade/chem_grenade/facid
- name = "acid grenade"
- desc = "Used for melting armoured opponents."
- stage = READY
-
-/obj/item/grenade/chem_grenade/facid/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
-
- B1.reagents.add_reagent("facid", 290)
- B1.reagents.add_reagent("potassium", 10)
- B2.reagents.add_reagent("phosphorus", 10)
- B2.reagents.add_reagent("sugar", 10)
- B2.reagents.add_reagent("facid", 280)
-
- beakers += B1
- beakers += B2
-
-
-/obj/item/grenade/chem_grenade/colorful
- name = "colorful grenade"
- desc = "Used for wide scale painting projects."
- stage = READY
-
-/obj/item/grenade/chem_grenade/colorful/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
-
- B1.reagents.add_reagent("colorful_reagent", 25)
- B1.reagents.add_reagent("potassium", 25)
- B2.reagents.add_reagent("phosphorus", 25)
- B2.reagents.add_reagent("sugar", 25)
-
- beakers += B1
- beakers += B2
-
-/obj/item/grenade/chem_grenade/glitter
- name = "generic glitter grenade"
- desc = "You shouldn't see this description."
- stage = READY
- var/glitter_type = "glitter"
-
-/obj/item/grenade/chem_grenade/glitter/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
-
- B1.reagents.add_reagent(glitter_type, 25)
- B1.reagents.add_reagent("potassium", 25)
- B2.reagents.add_reagent("phosphorus", 25)
- B2.reagents.add_reagent("sugar", 25)
-
- beakers += B1
- beakers += B2
-
-/obj/item/grenade/chem_grenade/glitter/pink
- name = "pink glitter bomb"
- desc = "For that HOT glittery look."
- glitter_type = "pink_glitter"
-
-/obj/item/grenade/chem_grenade/glitter/blue
- name = "blue glitter bomb"
- desc = "For that COOL glittery look."
- glitter_type = "blue_glitter"
-
-/obj/item/grenade/chem_grenade/glitter/white
- name = "white glitter bomb"
- desc = "For that somnolent glittery look."
- glitter_type = "white_glitter"
-
-/obj/item/grenade/chem_grenade/clf3
- name = "clf3 grenade"
- desc = "BURN!-brand foaming clf3. In a special applicator for rapid purging of wide areas."
- stage = READY
-
-/obj/item/grenade/chem_grenade/clf3/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
-
- B1.reagents.add_reagent("fluorosurfactant", 250)
- B1.reagents.add_reagent("clf3", 50)
- B2.reagents.add_reagent("water", 250)
- B2.reagents.add_reagent("clf3", 50)
-
- beakers += B1
- beakers += B2
-
-/obj/item/grenade/chem_grenade/bioterrorfoam
- name = "Bio terror foam grenade"
- desc = "Tiger Cooperative chemical foam grenade. Causes temporary irration, blindness, confusion, mutism, and mutations to carbon based life forms. Contains additional spore toxin."
- stage = READY
-
-/obj/item/grenade/chem_grenade/bioterrorfoam/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
-
- B1.reagents.add_reagent("cryptobiolin", 75)
- B1.reagents.add_reagent("water", 50)
- B1.reagents.add_reagent("mutetoxin", 50)
- B1.reagents.add_reagent("spore", 75)
- B1.reagents.add_reagent("itching_powder", 50)
- B2.reagents.add_reagent("fluorosurfactant", 150)
- B2.reagents.add_reagent("mutagen", 150)
- beakers += B1
- beakers += B2
-
-/obj/item/grenade/chem_grenade/tuberculosis
- name = "Fungal tuberculosis grenade"
- desc = "WARNING: GRENADE WILL RELEASE DEADLY SPORES CONTAINING ACTIVE AGENTS. SEAL SUIT AND AIRFLOW BEFORE USE."
- stage = READY
-
-/obj/item/grenade/chem_grenade/tuberculosis/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
-
- B1.reagents.add_reagent("potassium", 50)
- B1.reagents.add_reagent("phosphorus", 50)
- B1.reagents.add_reagent("fungalspores", 200)
- B2.reagents.add_reagent("blood", 250)
- B2.reagents.add_reagent("sugar", 50)
-
- beakers += B1
- beakers += B2
-
-/obj/item/grenade/chem_grenade/holy
- name = "holy hand grenade"
- desc = "A vessel of concentrated religious might."
- icon_state = "holy_grenade"
- stage = READY
-
-/obj/item/grenade/chem_grenade/holy/Initialize()
- . = ..()
- var/obj/item/reagent_containers/glass/beaker/large/B1 = new(src)
- var/obj/item/reagent_containers/glass/beaker/large/B2 = new(src)
-
- B1.reagents.add_reagent("potassium", 100)
- B2.reagents.add_reagent("holywater", 100)
-
- beakers += B1
- beakers += B2
-
-#undef READY
-#undef WIRED
-#undef EMPTY
+#define EMPTY 1
+#define WIRED 2
+#define READY 3
+
+/obj/item/grenade/chem_grenade
+ name = "chemical grenade"
+ desc = "A custom made grenade."
+ icon_state = "chemg"
+ item_state = "flashbang"
+ w_class = WEIGHT_CLASS_SMALL
+ force = 2
+ var/stage = EMPTY
+ var/list/beakers = list()
+ var/list/allowed_containers = list(/obj/item/reagent_containers/glass/beaker, /obj/item/reagent_containers/glass/bottle)
+ var/affected_area = 3
+ var/obj/item/assembly_holder/nadeassembly = null
+ var/assemblyattacher
+ var/ignition_temp = 10 // The amount of heat added to the reagents when this grenade goes off.
+ var/threatscale = 1 // Used by advanced grenades to make them slightly more worthy.
+ var/no_splash = FALSE //If the grenade deletes even if it has no reagents to splash with. Used for slime core reactions.
+ var/casedesc = "This basic model accepts both beakers and bottles. It heats contents by 10°K upon ignition." // Appears when examining empty casings.
+
+/obj/item/grenade/chem_grenade/Initialize()
+ . = ..()
+ create_reagents(1000)
+ stage_change() // If no argument is set, it will change the stage to the current stage, useful for stock grenades that start READY.
+
+/obj/item/grenade/chem_grenade/examine(mob/user)
+ display_timer = (stage == READY && !nadeassembly) //show/hide the timer based on assembly state
+ . = ..()
+ if(user.can_see_reagents())
+ var/count = 0
+ if(beakers.len)
+ . += "You scan the grenade and detect the following reagents:"
+ for(var/obj/item/reagent_containers/glass/G in beakers)
+ var/textcount = thtotext(++count)
+ for(var/datum/reagent/R in G.reagents.reagent_list)
+ . += "[R.volume] units of [R.name] in the [textcount] beaker."
+ if(beakers.len == 1)
+ . += "You detect no second beaker in the grenade."
+ else
+ . += "You scan the grenade, but detect nothing."
+
+
+/obj/item/grenade/chem_grenade/attack_self(mob/user)
+ if(stage == READY && !active)
+ if(nadeassembly)
+ nadeassembly.attack_self(user)
+ else
+ ..()
+
+
+/obj/item/grenade/chem_grenade/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/screwdriver))
+ if(stage == WIRED)
+ if(beakers.len)
+ stage_change(READY)
+ to_chat(user, "You lock the [initial(name)] assembly.")
+ I.play_tool_sound(src, 25)
+ else
+ to_chat(user, "You need to add at least one beaker before locking the [initial(name)] assembly!")
+ else if(stage == READY && !nadeassembly)
+ det_time = det_time == 50 ? 30 : 50 //toggle between 30 and 50
+ to_chat(user, "You modify the time delay. It's set for [DisplayTimeText(det_time)].")
+ else if(stage == EMPTY)
+ to_chat(user, "You need to add an activation mechanism!")
+
+ else if(stage == WIRED && is_type_in_list(I, allowed_containers))
+ . = 1 //no afterattack
+ if(beakers.len == 2)
+ to_chat(user, "[src] can not hold more containers!")
+ return
+ else
+ if(I.reagents.total_volume)
+ if(!user.transferItemToLoc(I, src))
+ return
+ to_chat(user, "You add [I] to the [initial(name)] assembly.")
+ beakers += I
+ var/reagent_list = pretty_string_from_reagent_list(I.reagents)
+ user.log_message("inserted [I] ([reagent_list]) into [src]",LOG_GAME)
+ else
+ to_chat(user, "[I] is empty!")
+
+ else if(stage == EMPTY && istype(I, /obj/item/assembly_holder))
+ . = 1 // no afterattack
+ var/obj/item/assembly_holder/A = I
+ if(isigniter(A.a_left) == isigniter(A.a_right)) //Check if either part of the assembly has an igniter, but if both parts are igniters, then fuck it
+ return
+ if(!user.transferItemToLoc(I, src))
+ return
+
+ nadeassembly = A
+ A.master = src
+ assemblyattacher = user.ckey
+
+ stage_change(WIRED)
+ to_chat(user, "You add [A] to the [initial(name)] assembly.")
+
+ else if(stage == EMPTY && istype(I, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/C = I
+ if (C.use(1))
+ det_time = 50 // In case the cable_coil was removed and readded.
+ stage_change(WIRED)
+ to_chat(user, "You rig the [initial(name)] assembly.")
+ else
+ to_chat(user, "You need one length of coil to wire the assembly!")
+ return
+
+ else if(stage == READY && istype(I, /obj/item/wirecutters) && !active)
+ stage_change(WIRED)
+ to_chat(user, "You unlock the [initial(name)] assembly.")
+
+ else if(stage == WIRED && istype(I, /obj/item/wrench))
+ if(beakers.len)
+ for(var/obj/O in beakers)
+ O.forceMove(drop_location())
+ if(!O.reagents)
+ continue
+ var/reagent_list = pretty_string_from_reagent_list(O.reagents)
+ user.log_message("removed [O] ([reagent_list]) from [src]", LOG_GAME)
+ beakers = list()
+ to_chat(user, "You open the [initial(name)] assembly and remove the payload.")
+ return // First use of the wrench remove beakers, then use the wrench to remove the activation mechanism.
+ if(nadeassembly)
+ nadeassembly.forceMove(drop_location())
+ nadeassembly.master = null
+ nadeassembly = null
+ else // If "nadeassembly = null && stage == WIRED", then it most have been cable_coil that was used.
+ new /obj/item/stack/cable_coil(get_turf(src),1)
+ stage_change(EMPTY)
+ to_chat(user, "You remove the activation mechanism from the [initial(name)] assembly.")
+ else
+ return ..()
+
+/obj/item/grenade/chem_grenade/proc/stage_change(N)
+ if(N)
+ stage = N
+ if(stage == EMPTY)
+ name = "[initial(name)] casing"
+ desc = "A do it yourself [initial(name)]! [initial(casedesc)]"
+ icon_state = initial(icon_state)
+ else if(stage == WIRED)
+ name = "unsecured [initial(name)]"
+ desc = "An unsecured [initial(name)] assembly."
+ icon_state = "[initial(icon_state)]_ass"
+ else if(stage == READY)
+ name = initial(name)
+ desc = initial(desc)
+ icon_state = "[initial(icon_state)]_locked"
+
+
+//assembly stuff
+/obj/item/grenade/chem_grenade/receive_signal()
+ prime()
+
+
+/obj/item/grenade/chem_grenade/Crossed(atom/movable/AM)
+ if(nadeassembly)
+ nadeassembly.Crossed(AM)
+
+/obj/item/grenade/chem_grenade/on_found(mob/finder)
+ if(nadeassembly)
+ nadeassembly.on_found(finder)
+
+/obj/item/grenade/chem_grenade/log_grenade(mob/user, turf/T)
+ ..()
+ var/reagent_string = ""
+ var/beaker_number = 1
+ for(var/obj/exploded_beaker in beakers)
+ if(!exploded_beaker.reagents)
+ continue
+ reagent_string += "[exploded_beaker] [beaker_number++] : " + pretty_string_from_reagent_list(exploded_beaker.reagents.reagent_list) + ";"
+ var/message = "[src] primed by [user] at [ADMIN_VERBOSEJMP(T)] contained [reagent_string]."
+ GLOB.bombers += message
+ message_admins(message)
+ user.log_message("primed [src] ([reagent_string])",LOG_GAME)
+
+/obj/item/grenade/chem_grenade/prime()
+ if(stage != READY)
+ return
+
+ var/list/datum/reagents/reactants = list()
+ for(var/obj/item/reagent_containers/glass/G in beakers)
+ reactants += G.reagents
+
+ var/turf/detonation_turf = get_turf(src)
+
+ if(!chem_splash(detonation_turf, affected_area, reactants, ignition_temp, threatscale) && !no_splash)
+ playsound(src, 'sound/items/screwdriver2.ogg', 50, 1)
+ if(beakers.len)
+ for(var/obj/O in beakers)
+ O.forceMove(drop_location())
+ beakers = list()
+ stage_change(EMPTY)
+ return
+
+ if(nadeassembly)
+ var/mob/M = get_mob_by_ckey(assemblyattacher)
+ var/mob/last = get_mob_by_ckey(nadeassembly.fingerprintslast)
+ message_admins("grenade primed by an assembly, attached by [ADMIN_LOOKUPFLW(M)] and last touched by [ADMIN_LOOKUPFLW(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [ADMIN_VERBOSEJMP(detonation_turf)].")
+ log_game("grenade primed by an assembly, attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]) at [AREACOORD(detonation_turf)]")
+
+ log_game("A grenade detonated at [AREACOORD(detonation_turf)]")
+
+ update_mob()
+
+ qdel(src)
+
+//Large chem grenades accept slime cores and use the appropriately.
+/obj/item/grenade/chem_grenade/large
+ name = "large grenade"
+ desc = "A custom made large grenade. Larger splash range and increased ignition temperature compared to basic grenades. Fits exotic containers."
+ casedesc = "This casing affects a larger area than the basic model and can fit exotic containers, including slime cores. Heats contents by 25°K upon ignition."
+ icon_state = "large_grenade"
+ allowed_containers = list(/obj/item/reagent_containers/glass, /obj/item/reagent_containers/food/condiment, /obj/item/reagent_containers/food/drinks)
+ affected_area = 5
+ ignition_temp = 25 // Large grenades are slightly more effective at setting off heat-sensitive mixtures than smaller grenades.
+ threatscale = 1.1 // 10% more effective.
+
+/obj/item/grenade/chem_grenade/large/prime()
+ if(stage != READY)
+ return
+
+ for(var/obj/item/slime_extract/S in beakers)
+ if(S.Uses)
+ for(var/obj/item/reagent_containers/glass/G in beakers)
+ G.reagents.trans_to(S, G.reagents.total_volume)
+
+ //If there is still a core (sometimes it's used up)
+ //and there are reagents left, behave normally,
+ //otherwise drop it on the ground for timed reactions like gold.
+
+ if(S)
+ if(S.reagents && S.reagents.total_volume)
+ for(var/obj/item/reagent_containers/glass/G in beakers)
+ S.reagents.trans_to(G, S.reagents.total_volume)
+ else
+ S.forceMove(get_turf(src))
+ no_splash = TRUE
+ ..()
+
+ //I tried to just put it in the allowed_containers list but
+ //if you do that it must have reagents. If you're going to
+ //make a special case you might as well do it explicitly. -Sayu
+/obj/item/grenade/chem_grenade/large/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/slime_extract) && stage == WIRED)
+ if(!user.transferItemToLoc(I, src))
+ return
+ to_chat(user, "You add [I] to the [initial(name)] assembly.")
+ beakers += I
+ else
+ return ..()
+
+/obj/item/grenade/chem_grenade/cryo // Intended for rare cryogenic mixes. Cools the area moderately upon detonation.
+ name = "cryo grenade"
+ desc = "A custom made cryogenic grenade. Rapidly cools contents upon ignition."
+ casedesc = "Upon ignition, it rapidly cools contents by 100°K. Smaller splash range than regular casings."
+ icon_state = "cryog"
+ affected_area = 2
+ ignition_temp = -100
+
+/obj/item/grenade/chem_grenade/pyro // Intended for pyrotechnical mixes. Produces a small fire upon detonation, igniting potentially flammable mixtures.
+ name = "pyro grenade"
+ desc = "A custom made pyrotechnical grenade. Heats up contents upon ignition."
+ casedesc = "Upon ignition, it rapidly heats contents by 500°K."
+ icon_state = "pyrog"
+ ignition_temp = 500 // This is enough to expose a hotspot.
+
+/obj/item/grenade/chem_grenade/adv_release // Intended for weaker, but longer lasting effects. Could have some interesting uses.
+ name = "advanced release grenade"
+ desc = "A custom made advanced release grenade. It is able to be detonated more than once. Can be configured using a multitool."
+ casedesc = "This casing is able to detonate more than once. Can be configured using a multitool."
+ icon_state = "timeg"
+ var/unit_spread = 10 // Amount of units per repeat. Can be altered with a multitool.
+
+/obj/item/grenade/chem_grenade/adv_release/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/multitool))
+ switch(unit_spread)
+ if(0 to 24)
+ unit_spread += 5
+ if(25 to 99)
+ unit_spread += 25
+ else
+ unit_spread = 5
+ to_chat(user, " You set the time release to [unit_spread] units per detonation.")
+ return
+ ..()
+
+/obj/item/grenade/chem_grenade/adv_release/prime()
+ if(stage != READY)
+ return
+
+ var/total_volume = 0
+ for(var/obj/item/reagent_containers/RC in beakers)
+ total_volume += RC.reagents.total_volume
+ if(!total_volume)
+ qdel(src)
+ qdel(nadeassembly)
+ return
+ var/fraction = unit_spread/total_volume
+ var/datum/reagents/reactants = new(unit_spread)
+ reactants.my_atom = src
+ for(var/obj/item/reagent_containers/RC in beakers)
+ RC.reagents.trans_to(reactants, RC.reagents.total_volume*fraction, threatscale, 1, 1)
+ chem_splash(get_turf(src), affected_area, list(reactants), ignition_temp, threatscale)
+
+ var/turf/DT = get_turf(src)
+ if(nadeassembly)
+ var/mob/M = get_mob_by_ckey(assemblyattacher)
+ var/mob/last = get_mob_by_ckey(nadeassembly.fingerprintslast)
+ message_admins("grenade primed by an assembly at [AREACOORD(DT)], attached by [ADMIN_LOOKUPFLW(M)] and last touched by [ADMIN_LOOKUPFLW(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name]).")
+ log_game("grenade primed by an assembly at [AREACOORD(DT)], attached by [key_name(M)] and last touched by [key_name(last)] ([nadeassembly.a_left.name] and [nadeassembly.a_right.name])")
+ else
+ addtimer(CALLBACK(src, .proc/prime), det_time)
+ log_game("A grenade detonated at [AREACOORD(DT)]")
+
+
+
+
+
+//////////////////////////////
+////// PREMADE GRENADES //////
+//////////////////////////////
+
+/obj/item/grenade/chem_grenade/metalfoam
+ name = "metal foam grenade"
+ desc = "Used for emergency sealing of hull breaches."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/metalfoam/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/aluminium, 30)
+ B2.reagents.add_reagent(/datum/reagent/foaming_agent, 10)
+ B2.reagents.add_reagent(/datum/reagent/toxin/acid/fluacid, 10)
+
+ beakers += B1
+ beakers += B2
+
+
+/obj/item/grenade/chem_grenade/smart_metal_foam
+ name = "smart metal foam grenade"
+ desc = "Used for emergency sealing of hull breaches, while keeping areas accessible."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/smart_metal_foam/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/large/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/aluminium, 75)
+ B2.reagents.add_reagent(/datum/reagent/smart_foaming_agent, 25)
+ B2.reagents.add_reagent(/datum/reagent/toxin/acid/fluacid, 25)
+
+ beakers += B1
+ beakers += B2
+
+
+/obj/item/grenade/chem_grenade/incendiary
+ name = "incendiary grenade"
+ desc = "Used for clearing rooms of living things."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/incendiary/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/phosphorus, 25)
+ B2.reagents.add_reagent(/datum/reagent/stable_plasma, 25)
+ B2.reagents.add_reagent(/datum/reagent/toxin/acid, 25)
+
+ beakers += B1
+ beakers += B2
+
+
+/obj/item/grenade/chem_grenade/antiweed
+ name = "weedkiller grenade"
+ desc = "Used for purging large areas of invasive plant species. Contents under pressure. Do not directly inhale contents."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/antiweed/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/toxin/plantbgone, 25)
+ B1.reagents.add_reagent(/datum/reagent/potassium, 25)
+ B2.reagents.add_reagent(/datum/reagent/phosphorus, 25)
+ B2.reagents.add_reagent(/datum/reagent/consumable/sugar, 25)
+
+ beakers += B1
+ beakers += B2
+
+
+/obj/item/grenade/chem_grenade/cleaner
+ name = "cleaner grenade"
+ desc = "BLAM!-brand foaming space cleaner. In a special applicator for rapid cleaning of wide areas."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/cleaner/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/plastic/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/plastic/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/fluorosurfactant, 40)
+ B2.reagents.add_reagent(/datum/reagent/water, 40)
+ B2.reagents.add_reagent(/datum/reagent/space_cleaner, 10)
+
+ beakers += B1
+ beakers += B2
+
+
+/obj/item/grenade/chem_grenade/ez_clean
+ name = "cleaner grenade"
+ desc = "Waffle Co.-brand foaming space cleaner. In a special applicator for rapid cleaning of wide areas."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/ez_clean/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/plastic/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/plastic/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/fluorosurfactant, 40)
+ B2.reagents.add_reagent(/datum/reagent/water, 40)
+ B2.reagents.add_reagent(/datum/reagent/space_cleaner/ez_clean, 60) //ensures a t h i c c distribution
+
+ beakers += B1
+ beakers += B2
+
+
+
+/obj/item/grenade/chem_grenade/teargas
+ name = "teargas grenade"
+ desc = "Used for nonlethal riot control. Contents under pressure. Do not directly inhale contents."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/teargas/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/large/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/large/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/consumable/condensedcapsaicin, 60)
+ B1.reagents.add_reagent(/datum/reagent/potassium, 40)
+ B2.reagents.add_reagent(/datum/reagent/phosphorus, 40)
+ B2.reagents.add_reagent(/datum/reagent/consumable/sugar, 40)
+
+ beakers += B1
+ beakers += B2
+
+
+/obj/item/grenade/chem_grenade/facid
+ name = "acid grenade"
+ desc = "Used for melting armoured opponents."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/facid/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/toxin/acid/fluacid, 290)
+ B1.reagents.add_reagent(/datum/reagent/potassium, 10)
+ B2.reagents.add_reagent(/datum/reagent/phosphorus, 10)
+ B2.reagents.add_reagent(/datum/reagent/consumable/sugar, 10)
+ B2.reagents.add_reagent(/datum/reagent/toxin/acid/fluacid, 280)
+
+ beakers += B1
+ beakers += B2
+
+
+/obj/item/grenade/chem_grenade/colorful
+ name = "colorful grenade"
+ desc = "Used for wide scale painting projects."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/colorful/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/colorful_reagent, 25)
+ B1.reagents.add_reagent(/datum/reagent/potassium, 25)
+ B2.reagents.add_reagent(/datum/reagent/phosphorus, 25)
+ B2.reagents.add_reagent(/datum/reagent/consumable/sugar, 25)
+
+ beakers += B1
+ beakers += B2
+
+/obj/item/grenade/chem_grenade/glitter
+ name = "generic glitter grenade"
+ desc = "You shouldn't see this description."
+ stage = READY
+ var/glitter_type = /datum/reagent/glitter
+
+/obj/item/grenade/chem_grenade/glitter/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/B2 = new(src)
+
+ B1.reagents.add_reagent(glitter_type, 25)
+ B1.reagents.add_reagent(/datum/reagent/potassium, 25)
+ B2.reagents.add_reagent(/datum/reagent/phosphorus, 25)
+ B2.reagents.add_reagent(/datum/reagent/consumable/sugar, 25)
+
+ beakers += B1
+ beakers += B2
+
+/obj/item/grenade/chem_grenade/glitter/pink
+ name = "pink glitter bomb"
+ desc = "For that HOT glittery look."
+ glitter_type = /datum/reagent/glitter/pink
+
+/obj/item/grenade/chem_grenade/glitter/blue
+ name = "blue glitter bomb"
+ desc = "For that COOL glittery look."
+ glitter_type = /datum/reagent/glitter/blue
+
+/obj/item/grenade/chem_grenade/glitter/white
+ name = "white glitter bomb"
+ desc = "For that somnolent glittery look."
+ glitter_type = /datum/reagent/glitter/white
+
+/obj/item/grenade/chem_grenade/clf3
+ name = "clf3 grenade"
+ desc = "BURN!-brand foaming clf3. In a special applicator for rapid purging of wide areas."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/clf3/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/fluorosurfactant, 250)
+ B1.reagents.add_reagent(/datum/reagent/clf3, 50)
+ B2.reagents.add_reagent(/datum/reagent/water, 250)
+ B2.reagents.add_reagent(/datum/reagent/clf3, 50)
+
+ beakers += B1
+ beakers += B2
+
+/obj/item/grenade/chem_grenade/bioterrorfoam
+ name = "Bio terror foam grenade"
+ desc = "Tiger Cooperative chemical foam grenade. Causes temporary irration, blindness, confusion, mutism, and mutations to carbon based life forms. Contains additional spore toxin."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/bioterrorfoam/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/cryptobiolin, 75)
+ B1.reagents.add_reagent(/datum/reagent/water, 50)
+ B1.reagents.add_reagent(/datum/reagent/toxin/mutetoxin, 50)
+ B1.reagents.add_reagent(/datum/reagent/toxin/spore, 75)
+ B1.reagents.add_reagent(/datum/reagent/toxin/itching_powder, 50)
+ B2.reagents.add_reagent(/datum/reagent/fluorosurfactant, 150)
+ B2.reagents.add_reagent(/datum/reagent/toxin/mutagen, 150)
+ beakers += B1
+ beakers += B2
+
+/obj/item/grenade/chem_grenade/tuberculosis
+ name = "Fungal tuberculosis grenade"
+ desc = "WARNING: GRENADE WILL RELEASE DEADLY SPORES CONTAINING ACTIVE AGENTS. SEAL SUIT AND AIRFLOW BEFORE USE."
+ stage = READY
+
+/obj/item/grenade/chem_grenade/tuberculosis/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/bluespace/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/potassium, 50)
+ B1.reagents.add_reagent(/datum/reagent/phosphorus, 50)
+ B1.reagents.add_reagent(/datum/reagent/fungalspores, 200)
+ B2.reagents.add_reagent(/datum/reagent/blood, 250)
+ B2.reagents.add_reagent(/datum/reagent/consumable/sugar, 50)
+
+ beakers += B1
+ beakers += B2
+
+/obj/item/grenade/chem_grenade/holy
+ name = "holy hand grenade"
+ desc = "A vessel of concentrated religious might."
+ icon_state = "holy_grenade"
+ stage = READY
+
+/obj/item/grenade/chem_grenade/holy/Initialize()
+ . = ..()
+ var/obj/item/reagent_containers/glass/beaker/large/B1 = new(src)
+ var/obj/item/reagent_containers/glass/beaker/large/B2 = new(src)
+
+ B1.reagents.add_reagent(/datum/reagent/potassium, 100)
+ B2.reagents.add_reagent(/datum/reagent/water/holywater, 100)
+
+ beakers += B1
+ beakers += B2
+
+#undef READY
+#undef WIRED
+#undef EMPTY
diff --git a/code/game/objects/items/grenades/clusterbuster.dm b/code/game/objects/items/grenades/clusterbuster.dm
index 923361de..c16b4a30 100644
--- a/code/game/objects/items/grenades/clusterbuster.dm
+++ b/code/game/objects/items/grenades/clusterbuster.dm
@@ -94,11 +94,11 @@
var/chem = pick(slime_chems)
var/amount = 5
if(chem == "lesser plasma") //In the rare case we get another rainbow.
- chem = "plasma"
+ chem = /datum/reagent/toxin/plasma
amount = 4
if(chem == "holy water and uranium")
- chem = "uranium"
- reagents.add_reagent("holywater")
+ chem = /datum/reagent/uranium
+ reagents.add_reagent(/datum/reagent/water/holywater)
reagents.add_reagent(chem,amount)
/obj/effect/payload_spawner/random_slime/spawn_payload(type, numspawned)
diff --git a/code/game/objects/items/hot_potato.dm b/code/game/objects/items/hot_potato.dm
index d74a611f..16ac2ad6 100644
--- a/code/game/objects/items/hot_potato.dm
+++ b/code/game/objects/items/hot_potato.dm
@@ -1,171 +1,171 @@
-//CREATOR'S NOTE: DO NOT FUCKING GIVE THIS TO BOTANY!
-/obj/item/hot_potato
- name = "hot potato"
- desc = "A label on the side of this potato reads \"Product of DonkCo Service Wing. Activate far away from populated areas. Device will only attach to sapient creatures.\" You can attack anyone with it to force it on them instead of yourself!"
- icon = 'icons/obj/hydroponics/harvest.dmi'
- icon_state = "potato"
- item_flags = NOBLUDGEON
- force = 0
- var/icon_off = "potato"
- var/icon_on = "potato_active"
- var/detonation_timerid
- var/activation_time = 0
- var/timer = 600 //deciseconds
- var/show_timer = FALSE
- var/reusable = FALSE //absolute madman
- var/sticky = TRUE
- var/forceful_attachment = TRUE
- var/stimulant = TRUE
- var/detonate_explosion = TRUE
- var/detonate_dev_range = 0
- var/detonate_heavy_range = 0
- var/detonate_light_range = 2
- var/detonate_flash_range = 5
- var/detonate_fire_range = 5
-
- var/active = FALSE
-
- var/color_val = FALSE
-
- var/datum/weakref/current
-
-/obj/item/hot_potato/Destroy()
- if(active)
- deactivate()
- return ..()
-
-/obj/item/hot_potato/proc/colorize(mob/target)
- //Clear color from old target
- if(current)
- var/mob/M = current.resolve()
- if(istype(M))
- M.remove_atom_colour(FIXED_COLOUR_PRIORITY)
- //Give to new target
- current = null
- //Swap colors
- color_val = !color_val
- if(istype(target))
- current = WEAKREF(target)
- target.add_atom_colour(color_val? "#ffff00" : "#00ffff", FIXED_COLOUR_PRIORITY)
-
-/obj/item/hot_potato/proc/detonate()
- var/atom/location = loc
- location.visible_message("[src] [detonate_explosion? "explodes" : "activates"]!", "[src] activates! You've ran out of time!")
- if(detonate_explosion)
- explosion(src, detonate_dev_range, detonate_heavy_range, detonate_light_range, detonate_flash_range, flame_range = detonate_fire_range)
- deactivate()
- if(!reusable)
- var/mob/M = loc
- if(istype(M))
- M.dropItemToGround(src, TRUE)
- qdel(src)
-
-/obj/item/hot_potato/attack_self(mob/user)
- if(activate(timer, user))
- user.visible_message("[user] squeezes [src], which promptly starts to flash red-hot colors!", "You squeeze [src], activating its countdown and attachment mechanism!",
- "You hear a mechanical click and a loud beeping!")
- return
- return ..()
-
-/obj/item/hot_potato/process()
- if(stimulant)
- if(isliving(loc))
- var/mob/living/L = loc
- L.SetStun(0)
- L.SetKnockdown(0)
- L.SetSleeping(0)
- L.SetUnconscious(0)
- L.reagents.add_reagent("muscle_stimulant", CLAMP(5 - L.reagents.get_reagent_amount("muscle_stimulant"), 0, 5)) //If you don't have legs or get bola'd, tough luck!
- colorize(L)
-
-/obj/item/hot_potato/examine(mob/user)
- . = ..()
- if(active)
- . += "[src] is flashing red-hot! You should probably get rid of it!"
- if(show_timer)
- . += "[src]'s timer looks to be at [DisplayTimeText(activation_time - world.time)]!"
-
-/obj/item/hot_potato/equipped(mob/user)
- . = ..()
- if(active)
- to_chat(user, "You have a really bad feeling about [src]!")
-
-/obj/item/hot_potato/afterattack(atom/target, mob/user, adjacent, params)
- . = ..()
- if(!adjacent || !ismob(target))
- return
- force_onto(target, user)
-
-/obj/item/hot_potato/proc/force_onto(mob/living/victim, mob/user)
- if(!istype(victim) || user != loc || victim == user)
- return FALSE
- if(!victim.client)
- to_chat(user, "[src] refuses to attach to a non-sapient creature!")
- if(victim.stat != CONSCIOUS || !victim.get_num_legs())
- to_chat(user, "[src] refuses to attach to someone incapable of using it!")
- user.temporarilyRemoveItemFromInventory(src, TRUE)
- . = FALSE
- if(!victim.put_in_hands(src))
- if(forceful_attachment)
- victim.dropItemToGround(victim.get_inactive_held_item())
- if(!victim.put_in_hands(src))
- victim.dropItemToGround(victim.get_active_held_item())
- if(victim.put_in_hands(src))
- . = TRUE
- else
- . = TRUE
- else
- . = TRUE
- if(.)
- log_combat(user, victim, "forced a hot potato with explosive variables ([detonate_explosion]-[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_flash_range]/[detonate_fire_range]) onto")
- user.visible_message("[user] forces [src] onto [victim]!", "You force [src] onto [victim]!", "You hear a mechanical click and a beep.")
- colorize(null)
- else
- log_combat(user, victim, "tried to force a hot potato with explosive variables ([detonate_explosion]-[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_flash_range]/[detonate_fire_range]) onto")
- user.visible_message("[user] tried to force [src] onto [victim], but it could not attach!", "You try to force [src] onto [victim], but it is unable to attach!", "You hear a mechanical click and two buzzes.")
- user.put_in_hands(src)
-
-/obj/item/hot_potato/dropped(mob/user)
- . = ..()
- colorize(null)
-
-/obj/item/hot_potato/proc/activate(delay, mob/user)
- if(active)
- return
- update_icon()
- if(sticky)
- ADD_TRAIT(src, TRAIT_NODROP, HOT_POTATO_TRAIT)
- name = "primed [name]"
- activation_time = timer + world.time
- detonation_timerid = addtimer(CALLBACK(src, .proc/detonate), delay, TIMER_STOPPABLE)
- START_PROCESSING(SSfastprocess, src)
- var/turf/T = get_turf(src)
- message_admins("[user? "[ADMIN_LOOKUPFLW(user)] has primed [src]" : "A [src] has been primed"] (Timer:[delay],Explosive:[detonate_explosion],Range:[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_fire_range]) for detonation at [ADMIN_VERBOSEJMP(T)]")
- log_game("[user ? "[key_name(user)] has primed [src]" : "A [src] has been primed"] ([detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_fire_range]) for detonation at [AREACOORD(T)]")
- active = TRUE
-
-/obj/item/hot_potato/proc/deactivate()
- update_icon()
- name = initial(name)
- REMOVE_TRAIT(src, TRAIT_NODROP, HOT_POTATO_TRAIT)
- deltimer(detonation_timerid)
- STOP_PROCESSING(SSfastprocess, src)
- detonation_timerid = null
- colorize(null)
- active = FALSE
-
-/obj/item/hot_potato/update_icon()
- icon_state = active? icon_on : icon_off
-
-/obj/item/hot_potato/syndicate
- detonate_light_range = 4
- detonate_fire_range = 5
-
-/obj/item/hot_potato/harmless
- detonate_explosion = FALSE
-
-/obj/item/hot_potato/harmless/toy
- desc = "A label on the side of this potato reads \"Product of DonkCo Toys and Recreation department.\" You can attack anyone with it to put it on them instead, if they have a free hand to take it!"
- sticky = FALSE
- reusable = TRUE
- forceful_attachment = FALSE
+//CREATOR'S NOTE: DO NOT FUCKING GIVE THIS TO BOTANY!
+/obj/item/hot_potato
+ name = "hot potato"
+ desc = "A label on the side of this potato reads \"Product of DonkCo Service Wing. Activate far away from populated areas. Device will only attach to sapient creatures.\" You can attack anyone with it to force it on them instead of yourself!"
+ icon = 'icons/obj/hydroponics/harvest.dmi'
+ icon_state = "potato"
+ item_flags = NOBLUDGEON
+ force = 0
+ var/icon_off = "potato"
+ var/icon_on = "potato_active"
+ var/detonation_timerid
+ var/activation_time = 0
+ var/timer = 600 //deciseconds
+ var/show_timer = FALSE
+ var/reusable = FALSE //absolute madman
+ var/sticky = TRUE
+ var/forceful_attachment = TRUE
+ var/stimulant = TRUE
+ var/detonate_explosion = TRUE
+ var/detonate_dev_range = 0
+ var/detonate_heavy_range = 0
+ var/detonate_light_range = 2
+ var/detonate_flash_range = 5
+ var/detonate_fire_range = 5
+
+ var/active = FALSE
+
+ var/color_val = FALSE
+
+ var/datum/weakref/current
+
+/obj/item/hot_potato/Destroy()
+ if(active)
+ deactivate()
+ return ..()
+
+/obj/item/hot_potato/proc/colorize(mob/target)
+ //Clear color from old target
+ if(current)
+ var/mob/M = current.resolve()
+ if(istype(M))
+ M.remove_atom_colour(FIXED_COLOUR_PRIORITY)
+ //Give to new target
+ current = null
+ //Swap colors
+ color_val = !color_val
+ if(istype(target))
+ current = WEAKREF(target)
+ target.add_atom_colour(color_val? "#ffff00" : "#00ffff", FIXED_COLOUR_PRIORITY)
+
+/obj/item/hot_potato/proc/detonate()
+ var/atom/location = loc
+ location.visible_message("[src] [detonate_explosion? "explodes" : "activates"]!", "[src] activates! You've ran out of time!")
+ if(detonate_explosion)
+ explosion(src, detonate_dev_range, detonate_heavy_range, detonate_light_range, detonate_flash_range, flame_range = detonate_fire_range)
+ deactivate()
+ if(!reusable)
+ var/mob/M = loc
+ if(istype(M))
+ M.dropItemToGround(src, TRUE)
+ qdel(src)
+
+/obj/item/hot_potato/attack_self(mob/user)
+ if(activate(timer, user))
+ user.visible_message("[user] squeezes [src], which promptly starts to flash red-hot colors!", "You squeeze [src], activating its countdown and attachment mechanism!",
+ "You hear a mechanical click and a loud beeping!")
+ return
+ return ..()
+
+/obj/item/hot_potato/process()
+ if(stimulant)
+ if(isliving(loc))
+ var/mob/living/L = loc
+ L.SetStun(0)
+ L.SetKnockdown(0)
+ L.SetSleeping(0)
+ L.SetUnconscious(0)
+ L.reagents.add_reagent(/datum/reagent/medicine/muscle_stimulant, CLAMP(5 - L.reagents.get_reagent_amount(/datum/reagent/medicine/muscle_stimulant), 0, 5)) //If you don't have legs or get bola'd, tough luck!
+ colorize(L)
+
+/obj/item/hot_potato/examine(mob/user)
+ . = ..()
+ if(active)
+ . += "[src] is flashing red-hot! You should probably get rid of it!"
+ if(show_timer)
+ . += "[src]'s timer looks to be at [DisplayTimeText(activation_time - world.time)]!"
+
+/obj/item/hot_potato/equipped(mob/user)
+ . = ..()
+ if(active)
+ to_chat(user, "You have a really bad feeling about [src]!")
+
+/obj/item/hot_potato/afterattack(atom/target, mob/user, adjacent, params)
+ . = ..()
+ if(!adjacent || !ismob(target))
+ return
+ force_onto(target, user)
+
+/obj/item/hot_potato/proc/force_onto(mob/living/victim, mob/user)
+ if(!istype(victim) || user != loc || victim == user)
+ return FALSE
+ if(!victim.client)
+ to_chat(user, "[src] refuses to attach to a non-sapient creature!")
+ if(victim.stat != CONSCIOUS || !victim.get_num_legs())
+ to_chat(user, "[src] refuses to attach to someone incapable of using it!")
+ user.temporarilyRemoveItemFromInventory(src, TRUE)
+ . = FALSE
+ if(!victim.put_in_hands(src))
+ if(forceful_attachment)
+ victim.dropItemToGround(victim.get_inactive_held_item())
+ if(!victim.put_in_hands(src))
+ victim.dropItemToGround(victim.get_active_held_item())
+ if(victim.put_in_hands(src))
+ . = TRUE
+ else
+ . = TRUE
+ else
+ . = TRUE
+ if(.)
+ log_combat(user, victim, "forced a hot potato with explosive variables ([detonate_explosion]-[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_flash_range]/[detonate_fire_range]) onto")
+ user.visible_message("[user] forces [src] onto [victim]!", "You force [src] onto [victim]!", "You hear a mechanical click and a beep.")
+ colorize(null)
+ else
+ log_combat(user, victim, "tried to force a hot potato with explosive variables ([detonate_explosion]-[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_flash_range]/[detonate_fire_range]) onto")
+ user.visible_message("[user] tried to force [src] onto [victim], but it could not attach!", "You try to force [src] onto [victim], but it is unable to attach!", "You hear a mechanical click and two buzzes.")
+ user.put_in_hands(src)
+
+/obj/item/hot_potato/dropped(mob/user)
+ . = ..()
+ colorize(null)
+
+/obj/item/hot_potato/proc/activate(delay, mob/user)
+ if(active)
+ return
+ update_icon()
+ if(sticky)
+ ADD_TRAIT(src, TRAIT_NODROP, HOT_POTATO_TRAIT)
+ name = "primed [name]"
+ activation_time = timer + world.time
+ detonation_timerid = addtimer(CALLBACK(src, .proc/detonate), delay, TIMER_STOPPABLE)
+ START_PROCESSING(SSfastprocess, src)
+ var/turf/T = get_turf(src)
+ message_admins("[user? "[ADMIN_LOOKUPFLW(user)] has primed [src]" : "A [src] has been primed"] (Timer:[delay],Explosive:[detonate_explosion],Range:[detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_fire_range]) for detonation at [ADMIN_VERBOSEJMP(T)]")
+ log_game("[user ? "[key_name(user)] has primed [src]" : "A [src] has been primed"] ([detonate_dev_range]/[detonate_heavy_range]/[detonate_light_range]/[detonate_fire_range]) for detonation at [AREACOORD(T)]")
+ active = TRUE
+
+/obj/item/hot_potato/proc/deactivate()
+ update_icon()
+ name = initial(name)
+ REMOVE_TRAIT(src, TRAIT_NODROP, HOT_POTATO_TRAIT)
+ deltimer(detonation_timerid)
+ STOP_PROCESSING(SSfastprocess, src)
+ detonation_timerid = null
+ colorize(null)
+ active = FALSE
+
+/obj/item/hot_potato/update_icon()
+ icon_state = active? icon_on : icon_off
+
+/obj/item/hot_potato/syndicate
+ detonate_light_range = 4
+ detonate_fire_range = 5
+
+/obj/item/hot_potato/harmless
+ detonate_explosion = FALSE
+
+/obj/item/hot_potato/harmless/toy
+ desc = "A label on the side of this potato reads \"Product of DonkCo Toys and Recreation department.\" You can attack anyone with it to put it on them instead, if they have a free hand to take it!"
+ sticky = FALSE
+ reusable = TRUE
+ forceful_attachment = FALSE
diff --git a/code/game/objects/items/implants/implant_misc.dm b/code/game/objects/items/implants/implant_misc.dm
index 75b0c677..6cdc5ee8 100644
--- a/code/game/objects/items/implants/implant_misc.dm
+++ b/code/game/objects/items/implants/implant_misc.dm
@@ -33,7 +33,7 @@
/obj/item/implant/adrenalin/activate()
. = ..()
uses--
- imp_in.do_adrenaline(150, TRUE, 0, 0, TRUE, list("inaprovaline" = 3, "synaptizine" = 10, "regen_jelly" = 10, "stimulants" = 10), "You feel a sudden surge of energy!")
+ imp_in.do_adrenaline(150, TRUE, 0, 0, TRUE, list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/stimulants = 10), "You feel a sudden surge of energy!")
to_chat(imp_in, "You feel a sudden surge of energy!")
if(!uses)
qdel(src)
diff --git a/code/game/objects/items/kitchen.dm b/code/game/objects/items/kitchen.dm
index a1ee1d1d..b1662c12 100644
--- a/code/game/objects/items/kitchen.dm
+++ b/code/game/objects/items/kitchen.dm
@@ -1,236 +1,236 @@
-/* Kitchen tools
- * Contains:
- * Fork
- * Kitchen knives
- * Ritual Knife
- * Butcher's cleaver
- * Combat Knife
- * Rolling Pins
- */
-
-/obj/item/kitchen
- icon = 'icons/obj/kitchen.dmi'
- lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
-
-/obj/item/kitchen/fork
- name = "fork"
- desc = "Pointy."
- icon_state = "fork"
- force = 5
- w_class = WEIGHT_CLASS_TINY
- grind_results = list(/datum/reagent/iron = 3, /datum/reagent/silver = 3)
- throwforce = 0
- throw_speed = 3
- throw_range = 5
- materials = list(MAT_METAL=80)
- flags_1 = CONDUCT_1
- attack_verb = list("attacked", "stabbed", "poked")
- hitsound = 'sound/weapons/bladeslice.ogg'
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
- var/datum/reagent/forkload //used to eat omelette
-
-/obj/item/kitchen/fork/suicide_act(mob/living/carbon/user)
- user.visible_message("[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, 1)
- 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("[user] eats a delicious forkful of omelette!")
- M.reagents.add_reagent(forkload.id, 1)
- else
- M.visible_message("[user] feeds [M] a delicious forkful of omelette!")
- M.reagents.add_reagent(forkload.id, 1)
- icon_state = "fork"
- forkload = null
-
- else if(user.zone_selected == BODY_ZONE_PRECISE_EYES)
- return eyestab(M,user)
- 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
- grind_results = list(/datum/material/plastic=80)
- var/break_chance = 25
-
-/obj/item/kitchen/fork/plastic/afterattack(mob/living/carbon/user)
- .=..()
- if(prob(break_chance))
- user.visible_message("[user]'s fork snaps into tiny pieces in their hand.")
- qdel(src)
-
-/obj/item/kitchen/knife
- name = "kitchen knife"
- icon_state = "knife"
- desc = "A general purpose Chef's Knife made by SpaceCook Incorporated. Guaranteed to stay sharp for years to come."
- grind_results = list(/datum/reagent/iron = 3, /datum/reagent/silver = 3)
- flags_1 = CONDUCT_1
- force = 10
- w_class = WEIGHT_CLASS_SMALL
- throwforce = 10
- hitsound = 'sound/weapons/bladeslice.ogg'
- throw_speed = 3
- throw_range = 6
- materials = list(MAT_METAL=12000)
- attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- sharpness = IS_SHARP_ACCURATE
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
- var/bayonet = FALSE //Can this be attached to a gun?
-
-/obj/item/kitchen/knife/Initialize()
- . = ..()
- AddComponent(/datum/component/butchering, 80 - force, 100, force - 10) //bonus chance increases depending on force
-
-/obj/item/kitchen/knife/attack(mob/living/carbon/M, mob/living/carbon/user)
- if(user.zone_selected == BODY_ZONE_PRECISE_EYES)
- return eyestab(M,user)
- else
- return ..()
-
-/obj/item/kitchen/knife/suicide_act(mob/user)
- user.visible_message(pick("[user] is slitting [user.p_their()] wrists with the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.", \
- "[user] is slitting [user.p_their()] throat with the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.", \
- "[user] is slitting [user.p_their()] stomach open with the [src.name]! It looks like [user.p_theyre()] trying to commit seppuku."))
- return (BRUTELOSS)
-
-/obj/item/kitchen/knife/plastic
- name = "plastic knife"
- icon_state = "plastic_knife"
- item_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
- grind_results = list(/datum/material/plastic = 100)
- attack_verb = list("prodded", "whiffed","scratched", "poked")
- sharpness = IS_SHARP
- var/break_chance = 25
-
-/obj/item/kitchen/knife/plastic/afterattack(mob/living/carbon/user)
- .=..()
- if(prob(break_chance))
- user.visible_message("[user]'s knife snaps into tiny pieces in their hand.")
- qdel(src)
-
-/obj/item/kitchen/knife/ritual
- name = "ritual knife"
- desc = "The unearthly energies that once powered this blade are now dormant."
- icon = 'icons/obj/wizard.dmi'
- icon_state = "render"
- item_state = "knife"
- lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
- w_class = WEIGHT_CLASS_NORMAL
-
-/obj/item/kitchen/knife/butcher
- name = "butcher's cleaver"
- icon_state = "butch"
- desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown by-products."
- flags_1 = CONDUCT_1
- force = 15
- throwforce = 10
- materials = list(MAT_METAL=18000)
- attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- w_class = WEIGHT_CLASS_NORMAL
-
-/obj/item/kitchen/knife/combat
- name = "combat knife"
- icon_state = "buckknife"
- item_state = "knife"
- desc = "A military combat utility survival knife."
- force = 20
- throwforce = 20
- attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cut")
- bayonet = TRUE
-
-/obj/item/kitchen/knife/combat/survival
- name = "survival knife"
- icon_state = "survivalknife"
- item_state = "knife"
- desc = "A hunting grade survival knife."
- force = 15
- throwforce = 15
- bayonet = TRUE
-
-/obj/item/kitchen/knife/combat/bone
- name = "bone dagger"
- item_state = "bone_dagger"
- icon_state = "bone_dagger"
- lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
- desc = "A sharpened bone. The bare minimum in survival."
- force = 15
- throwforce = 15
- materials = list()
-
-/obj/item/kitchen/knife/combat/cyborg
- name = "cyborg knife"
- icon = 'icons/obj/items_cyborg.dmi'
- icon_state = "knife"
- desc = "A cyborg-mounted plasteel knife. Extremely sharp and durable."
-
-/obj/item/kitchen/knife/carrotshiv
- name = "carrot shiv"
- icon_state = "carrotshiv"
- item_state = "carrotshiv"
- lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
- desc = "Unlike other carrots, you should probably keep this far away from your eyes."
- force = 8
- throwforce = 12//fuck git
- materials = list()
- attack_verb = list("shanked", "shivved")
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
-
-/obj/item/kitchen/rollingpin
- name = "rolling pin"
- desc = "Used to knock out the Bartender."
- icon_state = "rolling_pin"
- force = 8
- throwforce = 5
- throw_speed = 3
- throw_range = 7
- w_class = WEIGHT_CLASS_NORMAL
- attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked")
-
-/obj/item/kitchen/rollingpin/suicide_act(mob/living/carbon/user)
- user.visible_message("[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/plastic
- name = "plastic spoon"
- desc = "Just be careful your food doesn't melt the spoon first."
- icon_state = "plastic_spoon"
- force = 0
- w_class = WEIGHT_CLASS_TINY
- throwforce = 0
- grind_results = list(/datum/material/plastic=120)
- var/break_chance = 25
-
-/obj/item/kitchen/knife/plastic/afterattack(mob/living/carbon/user)
- .=..()
- if(prob(break_chance))
- user.visible_message("[user]'s spoon snaps into tiny pieces in their hand.")
- qdel(src)
-
-/obj/item/kitchen/knife/scimitar
- name = "Scimitar knife"
- desc = "A knife used to cleanly butcher. Its razor-sharp edge has been honed for butchering, but has been poorly maintained over the years."
- attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
-
-/obj/item/kitchen/knife/scimiar/Initialize()
- . = ..()
- AddComponent(/datum/component/butchering, 90 - force, 100, force - 60) //bonus chance increases depending on force
+/* Kitchen tools
+ * Contains:
+ * Fork
+ * Kitchen knives
+ * Ritual Knife
+ * Butcher's cleaver
+ * Combat Knife
+ * Rolling Pins
+ */
+
+/obj/item/kitchen
+ icon = 'icons/obj/kitchen.dmi'
+ lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
+
+/obj/item/kitchen/fork
+ name = "fork"
+ desc = "Pointy."
+ icon_state = "fork"
+ force = 5
+ w_class = WEIGHT_CLASS_TINY
+ grind_results = list(/datum/reagent/iron = 3, /datum/reagent/silver = 3)
+ throwforce = 0
+ throw_speed = 3
+ throw_range = 5
+ materials = list(MAT_METAL=80)
+ flags_1 = CONDUCT_1
+ attack_verb = list("attacked", "stabbed", "poked")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 30)
+ var/datum/reagent/forkload //used to eat omelette
+
+/obj/item/kitchen/fork/suicide_act(mob/living/carbon/user)
+ user.visible_message("[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, 1)
+ 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("[user] eats a delicious forkful of omelette!")
+ M.reagents.add_reagent(forkload.type, 1)
+ else
+ M.visible_message("[user] feeds [M] a delicious forkful of omelette!")
+ M.reagents.add_reagent(forkload.type, 1)
+ icon_state = "fork"
+ forkload = null
+
+ else if(user.zone_selected == BODY_ZONE_PRECISE_EYES)
+ return eyestab(M,user)
+ 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
+ grind_results = list(/datum/material/plastic=80)
+ var/break_chance = 25
+
+/obj/item/kitchen/fork/plastic/afterattack(mob/living/carbon/user)
+ .=..()
+ if(prob(break_chance))
+ user.visible_message("[user]'s fork snaps into tiny pieces in their hand.")
+ qdel(src)
+
+/obj/item/kitchen/knife
+ name = "kitchen knife"
+ icon_state = "knife"
+ desc = "A general purpose Chef's Knife made by SpaceCook Incorporated. Guaranteed to stay sharp for years to come."
+ grind_results = list(/datum/reagent/iron = 3, /datum/reagent/silver = 3)
+ flags_1 = CONDUCT_1
+ force = 10
+ w_class = WEIGHT_CLASS_SMALL
+ throwforce = 10
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ throw_speed = 3
+ throw_range = 6
+ materials = list(MAT_METAL=12000)
+ attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ sharpness = IS_SHARP_ACCURATE
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 50, "acid" = 50)
+ var/bayonet = FALSE //Can this be attached to a gun?
+
+/obj/item/kitchen/knife/Initialize()
+ . = ..()
+ AddComponent(/datum/component/butchering, 80 - force, 100, force - 10) //bonus chance increases depending on force
+
+/obj/item/kitchen/knife/attack(mob/living/carbon/M, mob/living/carbon/user)
+ if(user.zone_selected == BODY_ZONE_PRECISE_EYES)
+ return eyestab(M,user)
+ else
+ return ..()
+
+/obj/item/kitchen/knife/suicide_act(mob/user)
+ user.visible_message(pick("[user] is slitting [user.p_their()] wrists with the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.", \
+ "[user] is slitting [user.p_their()] throat with the [src.name]! It looks like [user.p_theyre()] trying to commit suicide.", \
+ "[user] is slitting [user.p_their()] stomach open with the [src.name]! It looks like [user.p_theyre()] trying to commit seppuku."))
+ return (BRUTELOSS)
+
+/obj/item/kitchen/knife/plastic
+ name = "plastic knife"
+ icon_state = "plastic_knife"
+ item_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
+ grind_results = list(/datum/material/plastic = 100)
+ attack_verb = list("prodded", "whiffed","scratched", "poked")
+ sharpness = IS_SHARP
+ var/break_chance = 25
+
+/obj/item/kitchen/knife/plastic/afterattack(mob/living/carbon/user)
+ .=..()
+ if(prob(break_chance))
+ user.visible_message("[user]'s knife snaps into tiny pieces in their hand.")
+ qdel(src)
+
+/obj/item/kitchen/knife/ritual
+ name = "ritual knife"
+ desc = "The unearthly energies that once powered this blade are now dormant."
+ icon = 'icons/obj/wizard.dmi'
+ icon_state = "render"
+ item_state = "knife"
+ lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/kitchen/knife/butcher
+ name = "butcher's cleaver"
+ icon_state = "butch"
+ desc = "A huge thing used for chopping and chopping up meat. This includes clowns and clown by-products."
+ flags_1 = CONDUCT_1
+ force = 15
+ throwforce = 10
+ materials = list(MAT_METAL=18000)
+ attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ w_class = WEIGHT_CLASS_NORMAL
+
+/obj/item/kitchen/knife/combat
+ name = "combat knife"
+ icon_state = "buckknife"
+ item_state = "knife"
+ desc = "A military combat utility survival knife."
+ force = 20
+ throwforce = 20
+ attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "cut")
+ bayonet = TRUE
+
+/obj/item/kitchen/knife/combat/survival
+ name = "survival knife"
+ icon_state = "survivalknife"
+ item_state = "knife"
+ desc = "A hunting grade survival knife."
+ force = 15
+ throwforce = 15
+ bayonet = TRUE
+
+/obj/item/kitchen/knife/combat/bone
+ name = "bone dagger"
+ item_state = "bone_dagger"
+ icon_state = "bone_dagger"
+ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
+ desc = "A sharpened bone. The bare minimum in survival."
+ force = 15
+ throwforce = 15
+ materials = list()
+
+/obj/item/kitchen/knife/combat/cyborg
+ name = "cyborg knife"
+ icon = 'icons/obj/items_cyborg.dmi'
+ icon_state = "knife"
+ desc = "A cyborg-mounted plasteel knife. Extremely sharp and durable."
+
+/obj/item/kitchen/knife/carrotshiv
+ name = "carrot shiv"
+ icon_state = "carrotshiv"
+ item_state = "carrotshiv"
+ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
+ desc = "Unlike other carrots, you should probably keep this far away from your eyes."
+ force = 8
+ throwforce = 12//fuck git
+ materials = list()
+ attack_verb = list("shanked", "shivved")
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 0, "acid" = 0)
+
+/obj/item/kitchen/rollingpin
+ name = "rolling pin"
+ desc = "Used to knock out the Bartender."
+ icon_state = "rolling_pin"
+ force = 8
+ throwforce = 5
+ throw_speed = 3
+ throw_range = 7
+ w_class = WEIGHT_CLASS_NORMAL
+ attack_verb = list("bashed", "battered", "bludgeoned", "thrashed", "whacked")
+
+/obj/item/kitchen/rollingpin/suicide_act(mob/living/carbon/user)
+ user.visible_message("[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/plastic
+ name = "plastic spoon"
+ desc = "Just be careful your food doesn't melt the spoon first."
+ icon_state = "plastic_spoon"
+ force = 0
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 0
+ grind_results = list(/datum/material/plastic=120)
+ var/break_chance = 25
+
+/obj/item/kitchen/knife/plastic/afterattack(mob/living/carbon/user)
+ .=..()
+ if(prob(break_chance))
+ user.visible_message("[user]'s spoon snaps into tiny pieces in their hand.")
+ qdel(src)
+
+/obj/item/kitchen/knife/scimitar
+ name = "Scimitar knife"
+ desc = "A knife used to cleanly butcher. Its razor-sharp edge has been honed for butchering, but has been poorly maintained over the years."
+ attack_verb = list("cleaved", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+
+/obj/item/kitchen/knife/scimiar/Initialize()
+ . = ..()
+ AddComponent(/datum/component/butchering, 90 - force, 100, force - 60) //bonus chance increases depending on force
diff --git a/code/game/objects/items/mop.dm b/code/game/objects/items/mop.dm
index 5d384a93..a8b28f25 100644
--- a/code/game/objects/items/mop.dm
+++ b/code/game/objects/items/mop.dm
@@ -25,7 +25,7 @@
/obj/item/mop/proc/clean(turf/A)
- if(reagents.has_reagent("water", 1) || reagents.has_reagent("holywater", 1) || reagents.has_reagent("vodka", 1) || reagents.has_reagent("cleaner", 1))
+ if(reagents.has_reagent(/datum/reagent/water, 1) || reagents.has_reagent(/datum/reagent/water/holywater, 1) || reagents.has_reagent(/datum/reagent/consumable/ethanol/vodka, 1) || reagents.has_reagent(/datum/reagent/space_cleaner, 1))
SEND_SIGNAL(A, COMSIG_COMPONENT_CLEAN_ACT, CLEAN_MEDIUM)
A.clean_blood()
for(var/obj/effect/O in A)
@@ -98,7 +98,7 @@
stamusage = 1
var/refill_enabled = TRUE //Self-refill toggle for when a janitor decides to mop with something other than water.
var/refill_rate = 1 //Rate per process() tick mop refills itself
- var/refill_reagent = "water" //Determins what reagent to use for refilling, just in case someone wanted to make a HOLY MOP OF PURGING
+ var/refill_reagent = /datum/reagent/water //Determins what reagent to use for refilling, just in case someone wanted to make a HOLY MOP OF PURGING
/obj/item/mop/advanced/New()
..()
diff --git a/code/game/objects/items/religion.dm b/code/game/objects/items/religion.dm
index b792458f..47b766c5 100644
--- a/code/game/objects/items/religion.dm
+++ b/code/game/objects/items/religion.dm
@@ -98,7 +98,7 @@
/obj/item/banner/medical/special_inspiration(mob/living/carbon/human/H)
H.adjustToxLoss(-15)
H.setOxyLoss(0)
- H.reagents.add_reagent("inaprovaline", 5)
+ H.reagents.add_reagent(/datum/reagent/medicine/inaprovaline, 5)
/obj/item/banner/science
name = "sciencia banner"
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 7fcd7eff..5e7081c1 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -1,692 +1,692 @@
-// robot_upgrades.dm
-// Contains various borg upgrades.
-
-/obj/item/borg/upgrade
- name = "borg upgrade module."
- desc = "Protected by FRM."
- icon = 'icons/obj/module.dmi'
- icon_state = "cyborg_upgrade"
- var/locked = FALSE
- var/installed = 0
- var/require_module = 0
- var/module_type = null
- // if true, is not stored in the robot to be ejected
- // if module is reset
- var/one_use = FALSE
-
-/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R, user = usr)
- if(R.stat == DEAD)
- to_chat(user, "[src] will not function on a deceased cyborg.")
- return FALSE
- if(module_type && !istype(R.module, module_type))
- to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
- to_chat(user, "There's no mounting point for the module!")
- return FALSE
- return TRUE
-
-/obj/item/borg/upgrade/proc/deactivate(mob/living/silicon/robot/R, user = usr)
- if (!(src in R.upgrades))
- return FALSE
- return TRUE
-
-/obj/item/borg/upgrade/rename
- name = "cyborg reclassification board"
- desc = "Used to rename a cyborg."
- icon_state = "cyborg_upgrade1"
- var/heldname = ""
- one_use = TRUE
-
-/obj/item/borg/upgrade/rename/attack_self(mob/user)
- heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)
-
-/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R)
- . = ..()
- if(.)
- var/oldname = R.real_name
- R.custom_name = heldname
- R.updatename()
- if(oldname == R.real_name)
- R.notify_ai(RENAME, oldname, R.real_name)
-
-/obj/item/borg/upgrade/restart
- name = "cyborg emergency reboot module"
- desc = "Used to force a reboot of a disabled-but-repaired cyborg, bringing it back online."
- icon_state = "cyborg_upgrade1"
- one_use = TRUE
-
-/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R, user = usr)
- if(R.health < 0)
- to_chat(user, "You have to repair the cyborg before using this module!")
- return FALSE
-
- if(R.mind)
- R.mind.grab_ghost()
- playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
-
- R.revive()
-
-/obj/item/borg/upgrade/vtec
- name = "cyborg VTEC module"
- desc = "Used to kick in a cyborg's VTEC systems, increasing their speed."
- icon_state = "cyborg_upgrade2"
- require_module = 1
-
-/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- if(R.speed < 0)
- to_chat(R, "A VTEC unit is already installed!")
- to_chat(user, "There's no room for another VTEC unit!")
- return FALSE
-
- //R.speed = -2 // Gotta go fast.
- //Citadel change - makes vtecs give an ability rather than reducing the borg's speed instantly
- R.AddAbility(new/obj/effect/proc_holder/silicon/cyborg/vtecControl)
-
-/obj/item/borg/upgrade/vtec/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- R.speed = initial(R.speed)
-
-/obj/item/borg/upgrade/disablercooler
- name = "cyborg rapid disabler cooling module"
- desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- //module_type = /obj/item/robot_module/security
-
-/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules
- if(!T)
- to_chat(user, "There's no disabler in this unit!")
- return FALSE
- if(T.charge_delay <= 2)
- to_chat(R, "A cooling unit is already installed!")
- to_chat(user, "There's no room for another cooling unit!")
- return FALSE
-
- T.charge_delay = max(2 , T.charge_delay - 4)
-
-/obj/item/borg/upgrade/disablercooler/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules
- if(!T)
- return FALSE
- T.charge_delay = initial(T.charge_delay)
-
-/obj/item/borg/upgrade/thrusters
- name = "ion thruster upgrade"
- desc = "An energy-operated thruster system for cyborgs."
- icon_state = "cyborg_upgrade3"
-
-/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- if(R.ionpulse)
- to_chat(user, "This unit already has ion thrusters installed!")
- return FALSE
-
- R.ionpulse = TRUE
-
-/obj/item/borg/upgrade/thrusters/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- R.ionpulse = FALSE
-
-/obj/item/borg/upgrade/ddrill
- name = "mining cyborg diamond drill"
- desc = "A diamond drill replacement for the mining module's standard drill."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/robot_module/miner
-
-/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- for(var/obj/item/pickaxe/drill/cyborg/D in R.module)
- R.module.remove_module(D, TRUE)
- for(var/obj/item/shovel/S in R.module)
- R.module.remove_module(S, TRUE)
-
- var/obj/item/pickaxe/drill/cyborg/diamond/DD = new /obj/item/pickaxe/drill/cyborg/diamond(R.module)
- R.module.basic_modules += DD
- R.module.add_module(DD, FALSE, TRUE)
-
-/obj/item/borg/upgrade/ddrill/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- for(var/obj/item/pickaxe/drill/cyborg/diamond/DD in R.module)
- R.module.remove_module(DD, TRUE)
-
- var/obj/item/pickaxe/drill/cyborg/D = new (R.module)
- R.module.basic_modules += D
- R.module.add_module(D, FALSE, TRUE)
- var/obj/item/shovel/S = new (R.module)
- R.module.basic_modules += S
- R.module.add_module(S, FALSE, TRUE)
-
-/obj/item/borg/upgrade/soh
- name = "mining cyborg satchel of holding"
- desc = "A satchel of holding replacement for mining cyborg's ore satchel module."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/robot_module/miner
-
-/obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R)
- . = ..()
- if(.)
- for(var/obj/item/storage/bag/ore/cyborg/S in R.module)
- R.module.remove_module(S, TRUE)
-
- var/obj/item/storage/bag/ore/holding/H = new /obj/item/storage/bag/ore/holding(R.module)
- R.module.basic_modules += H
- R.module.add_module(H, FALSE, TRUE)
-
-/obj/item/borg/upgrade/soh/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- for(var/obj/item/storage/bag/ore/holding/H in R.module)
- R.module.remove_module(H, TRUE)
-
- var/obj/item/storage/bag/ore/cyborg/S = new (R.module)
- R.module.basic_modules += S
- R.module.add_module(S, FALSE, TRUE)
-
-/obj/item/borg/upgrade/tboh
- name = "janitor cyborg trash bag of holding"
- desc = "A trash bag of holding replacement for the janiborg's standard trash bag."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/robot_module/janitor
-
-/obj/item/borg/upgrade/tboh/action(mob/living/silicon/robot/R)
- . = ..()
- if(.)
- for(var/obj/item/storage/bag/trash/cyborg/TB in R.module.modules)
- R.module.remove_module(TB, TRUE)
-
- var/obj/item/storage/bag/trash/bluespace/cyborg/B = new /obj/item/storage/bag/trash/bluespace/cyborg(R.module)
- R.module.basic_modules += B
- R.module.add_module(B, FALSE, TRUE)
-
-/obj/item/borg/upgrade/tboh/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- for(var/obj/item/storage/bag/trash/bluespace/cyborg/B in R.module.modules)
- R.module.remove_module(B, TRUE)
-
- var/obj/item/storage/bag/trash/cyborg/TB = new (R.module)
- R.module.basic_modules += TB
- R.module.add_module(TB, FALSE, TRUE)
-
-/obj/item/borg/upgrade/amop
- name = "janitor cyborg advanced mop"
- desc = "An advanced mop replacement for the janiborg's standard mop."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/robot_module/janitor
-
-/obj/item/borg/upgrade/amop/action(mob/living/silicon/robot/R)
- . = ..()
- if(.)
- for(var/obj/item/mop/cyborg/M in R.module.modules)
- R.module.remove_module(M, TRUE)
-
- var/obj/item/mop/advanced/cyborg/A = new /obj/item/mop/advanced/cyborg(R.module)
- R.module.basic_modules += A
- R.module.add_module(A, FALSE, TRUE)
-
-/obj/item/borg/upgrade/amop/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- for(var/obj/item/mop/advanced/cyborg/A in R.module.modules)
- R.module.remove_module(A, TRUE)
-
- var/obj/item/mop/cyborg/M = new (R.module)
- R.module.basic_modules += M
- R.module.add_module(M, FALSE, TRUE)
-
-/obj/item/borg/upgrade/syndicate
- name = "illegal equipment module"
- desc = "Unlocks the hidden, deadlier functions of a cyborg."
- icon_state = "cyborg_upgrade3"
- require_module = 1
-
-/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- if(R.emagged)
- return FALSE
-
- R.SetEmagged(1)
-
- return TRUE
-
-/obj/item/borg/upgrade/syndicate/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- R.SetEmagged(FALSE)
-
-/obj/item/borg/upgrade/lavaproof
- name = "mining cyborg lavaproof tracks"
- desc = "An upgrade kit to apply specialized coolant systems and insulation layers to mining cyborg tracks, enabling them to withstand exposure to molten rock."
- icon_state = "ash_plating"
- resistance_flags = LAVA_PROOF | FIRE_PROOF
- require_module = 1
- module_type = /obj/item/robot_module/miner
-
-/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- R.weather_immunities += "lava"
-
-/obj/item/borg/upgrade/lavaproof/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- R.weather_immunities -= "lava"
-
-/obj/item/borg/upgrade/selfrepair
- name = "self-repair module"
- desc = "This module will repair the cyborg over time."
- icon_state = "cyborg_upgrade5"
- require_module = 1
- var/repair_amount = -1
- var/repair_tick = 1
- var/msg_cooldown = 0
- var/on = FALSE
- var/powercost = 10
- var/mob/living/silicon/robot/cyborg
- var/datum/action/toggle_action
-
-/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- var/obj/item/borg/upgrade/selfrepair/U = locate() in R
- if(U)
- to_chat(user, "This unit is already equipped with a self-repair module.")
- return FALSE
-
- cyborg = R
- icon_state = "selfrepair_off"
- toggle_action = new /datum/action/item_action/toggle(src)
- toggle_action.Grant(R)
-
-/obj/item/borg/upgrade/selfrepair/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- toggle_action.Remove(cyborg)
- QDEL_NULL(toggle_action)
- cyborg = null
- deactivate_sr()
-
-/obj/item/borg/upgrade/selfrepair/dropped()
- . = ..()
- addtimer(CALLBACK(src, .proc/check_dropped), 1)
-
-/obj/item/borg/upgrade/selfrepair/proc/check_dropped()
- if(loc != cyborg)
- toggle_action.Remove(cyborg)
- QDEL_NULL(toggle_action)
- cyborg = null
- deactivate_sr()
-
-/obj/item/borg/upgrade/selfrepair/ui_action_click()
- on = !on
- if(on)
- to_chat(cyborg, "You activate the self-repair module.")
- START_PROCESSING(SSobj, src)
- else
- to_chat(cyborg, "You deactivate the self-repair module.")
- STOP_PROCESSING(SSobj, src)
- update_icon()
-
-/obj/item/borg/upgrade/selfrepair/update_icon()
- if(cyborg)
- icon_state = "selfrepair_[on ? "on" : "off"]"
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
- else
- icon_state = "cyborg_upgrade5"
-
-/obj/item/borg/upgrade/selfrepair/proc/deactivate_sr()
- STOP_PROCESSING(SSobj, src)
- on = FALSE
- update_icon()
-
-/obj/item/borg/upgrade/selfrepair/process()
- if(!repair_tick)
- repair_tick = 1
- return
-
- if(cyborg && (cyborg.stat != DEAD) && on)
- if(!cyborg.cell)
- to_chat(cyborg, "Self-repair module deactivated. Please, insert the power cell.")
- deactivate_sr()
- return
-
- if(cyborg.cell.charge < powercost * 2)
- to_chat(cyborg, "Self-repair module deactivated. Please recharge.")
- deactivate_sr()
- return
-
- if(cyborg.health < cyborg.maxHealth)
- if(cyborg.health < 0)
- repair_amount = -2.5
- powercost = 30
- else
- repair_amount = -1
- powercost = 10
- cyborg.adjustBruteLoss(repair_amount)
- cyborg.adjustFireLoss(repair_amount)
- cyborg.updatehealth()
- cyborg.cell.use(powercost)
- else
- cyborg.cell.use(5)
- repair_tick = 0
-
- if((world.time - 2000) > msg_cooldown )
- var/msgmode = "standby"
- if(cyborg.health < 0)
- msgmode = "critical"
- else if(cyborg.health < cyborg.maxHealth)
- msgmode = "normal"
- to_chat(cyborg, "Self-repair is active in [msgmode] mode.")
- msg_cooldown = world.time
- else
- deactivate_sr()
-
-/obj/item/borg/upgrade/hypospray
- name = "medical cyborg hypospray advanced synthesiser"
- desc = "An upgrade to the Medical module cyborg's hypospray, allowing it \
- to produce more advanced and complex medical reagents."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/robot_module/medical
- var/list/additional_reagents = list()
-
-/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
- if(H.accepts_reagent_upgrades)
- for(var/re in additional_reagents)
- H.add_reagent(re)
-
-/obj/item/borg/upgrade/hypospray/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
- if(H.accepts_reagent_upgrades)
- for(var/re in additional_reagents)
- H.del_reagent(re)
-
-/obj/item/borg/upgrade/hypospray/expanded
- name = "medical cyborg expanded hypospray"
- desc = "An upgrade to the Medical module's hypospray, allowing it \
- to treat a wider range of conditions and problems."
- additional_reagents = list("mannitol", "oculine", "inacusiate",
- "mutadone", "haloperidol")
-
-/obj/item/borg/upgrade/hypospray/high_strength
- name = "medical cyborg high-strength hypospray"
- desc = "An upgrade to the Medical module's hypospray, containing \
- stronger versions of existing chemicals."
- additional_reagents = list("oxandrolone", "sal_acid", "rezadone",
- "pen_acid")
-
-/obj/item/borg/upgrade/piercing_hypospray
- name = "cyborg piercing hypospray"
- desc = "An upgrade to a cyborg's hypospray, allowing it to \
- pierce armor and thick material."
- icon_state = "cyborg_upgrade3"
-
-/obj/item/borg/upgrade/piercing_hypospray/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- var/found_hypo = FALSE
- for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
- H.bypass_protection = TRUE
- found_hypo = TRUE
-
- if(!found_hypo)
- return FALSE
-
-/obj/item/borg/upgrade/piercing_hypospray/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
- H.bypass_protection = initial(H.bypass_protection)
-
-/obj/item/borg/upgrade/defib
- name = "medical cyborg defibrillator"
- desc = "An upgrade to the Medical module, installing a built-in \
- defibrillator, for on the scene revival."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/robot_module/medical
-
-/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- var/obj/item/twohanded/shockpaddles/cyborg/S = new(R.module)
- R.module.basic_modules += S
- R.module.add_module(S, FALSE, TRUE)
-
-/obj/item/borg/upgrade/defib/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- var/obj/item/twohanded/shockpaddles/cyborg/S = locate() in R.module
- R.module.remove_module(S, TRUE)
-
-/obj/item/borg/upgrade/processor
- name = "medical cyborg surgical processor"
- desc = "An upgrade to the Medical module, installing a processor \
- capable of scanning surgery disks and carrying \
- out procedures"
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = /obj/item/robot_module/medical
-
-/obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- var/obj/item/surgical_processor/SP = new(R.module)
- R.module.basic_modules += SP
- R.module.add_module(SP, FALSE, TRUE)
-
-/obj/item/borg/upgrade/processor/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- var/obj/item/surgical_processor/SP = locate() in R.module
- R.module.remove_module(SP, TRUE)
-
-/obj/item/borg/upgrade/advhealth
- name = "advanced cyborg health scanner"
- desc = "An upgrade to the Medical modules, installing a built-in \
- advanced health scanner, for better readings on patients."
- icon_state = "cyborg_upgrade3"
- require_module = 1
- module_type = list(
- /obj/item/robot_module/medical,
- /obj/item/robot_module/syndicate_medical,
- /obj/item/robot_module/medihound,
- /obj/item/robot_module/borgi)
-
-/obj/item/borg/upgrade/advhealth/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- var/obj/item/healthanalyzer/advanced/AH = new(R.module)
- R.module.basic_modules += AH
- R.module.add_module(AH, FALSE, TRUE)
-
-/obj/item/borg/upgrade/processor/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- var/obj/item/healthanalyzer/advanced/AH = locate() in R.module
- R.module.remove_module(AH, TRUE)
-
-/obj/item/borg/upgrade/ai
- name = "B.O.R.I.S. module"
- desc = "Bluespace Optimized Remote Intelligence Synchronization. An uplink device which takes the place of an MMI in cyborg endoskeletons, creating a robotic shell controlled by an AI."
- icon_state = "boris"
-
-/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- if(R.shell)
- to_chat(user, "This unit is already an AI shell!")
- return FALSE
- if(R.key) //You cannot replace a player unless the key is completely removed.
- to_chat(user, "Intelligence patterns detected in this [R.braintype]. Aborting.")
- return FALSE
-
- R.make_shell(src)
-
-/obj/item/borg/upgrade/ai/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- if(R.shell)
- R.undeploy()
- R.notify_ai(AI_SHELL)
-
-/obj/item/borg/upgrade/expand
- name = "borg expander"
- desc = "A cyborg resizer, it makes a cyborg huge."
- icon_state = "cyborg_upgrade3"
-
-/obj/item/borg/upgrade/expand/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
-
- if(R.hasExpanded)
- to_chat(usr, "This unit already has an expand module installed!")
- return FALSE
-
- R.notransform = TRUE
- var/prev_lockcharge = R.lockcharge
- R.SetLockdown(1)
- R.anchored = TRUE
- var/datum/effect_system/smoke_spread/smoke = new
- smoke.set_up(1, R.loc)
- smoke.start()
- sleep(2)
- for(var/i in 1 to 4)
- playsound(R, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, 1, -1)
- sleep(12)
- if(!prev_lockcharge)
- R.SetLockdown(0)
- R.anchored = FALSE
- R.notransform = FALSE
- R.resize = 2
- R.hasExpanded = TRUE
- R.update_transform()
-
-/obj/item/borg/upgrade/expand/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- R.resize = 0.5
- R.hasExpanded = FALSE
- R.update_transform()
-
-/obj/item/borg/upgrade/rped
- name = "engineering cyborg RPED"
- desc = "A rapid part exchange device for the engineering cyborg."
- icon = 'icons/obj/storage.dmi'
- icon_state = "borgrped"
- require_module = TRUE
- module_type = /obj/item/robot_module/engineering
-
-/obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
-
- var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R
- if(RPED)
- to_chat(user, "This unit is already equipped with a RPED module.")
- return FALSE
-
- RPED = new(R.module)
- R.module.basic_modules += RPED
- R.module.add_module(RPED, FALSE, TRUE)
-
-/obj/item/borg/upgrade/rped/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R.module
- if (RPED)
- R.module.remove_module(RPED, TRUE)
-
-/obj/item/borg/upgrade/circuit_app
- name = "circuit manipulation apparatus"
- desc = "An engineering cyborg upgrade allowing for manipulation of circuit boards."
- icon_state = "cyborg_upgrade3"
- require_module = TRUE
- module_type = list(/obj/item/robot_module/engineering)
-
-/obj/item/borg/upgrade/circuit_app/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- var/obj/item/borg/apparatus/circuit/C = locate() in R.module.modules
- if(C)
- to_chat(user, "This unit is already equipped with a circuit apparatus!")
- return FALSE
-
- C = new(R.module)
- R.module.basic_modules += C
- R.module.add_module(C, FALSE, TRUE)
-
-/obj/item/borg/upgrade/circuit_app/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- var/obj/item/borg/apparatus/circuit/C = locate() in R.module.modules
- if (C)
- R.module.remove_module(C, TRUE)
-
-/obj/item/borg/upgrade/pinpointer
- name = "medical cyborg crew pinpointer"
- desc = "A crew pinpointer module for the medical cyborg."
- icon = 'icons/obj/device.dmi'
- icon_state = "pinpointer_crew"
- require_module = TRUE
- module_type = /obj/item/robot_module/medical
-
-/obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
-
- var/obj/item/pinpointer/crew/PP = locate() in R
- if(PP)
- to_chat(user, "This unit is already equipped with a pinpointer module.")
- return FALSE
-
- PP = new(R.module)
- R.module.basic_modules += PP
- R.module.add_module(PP, FALSE, TRUE)
-
-/obj/item/borg/upgrade/pinpointer/deactivate(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if (.)
- var/obj/item/pinpointer/crew/PP = locate() in R.module
- if (PP)
- R.module.remove_module(PP, TRUE)
-
-/obj/item/borg/upgrade/transform
- name = "borg module picker (Standard)"
- desc = "Allows you to to turn a cyborg into a standard cyborg."
- icon_state = "cyborg_upgrade3"
- var/obj/item/robot_module/new_module = /obj/item/robot_module/standard
-
-/obj/item/borg/upgrade/transform/action(mob/living/silicon/robot/R, user = usr)
- . = ..()
- if(.)
- R.module.transform_to(new_module)
-
-/obj/item/borg/upgrade/transform/clown
- name = "borg module picker (Clown)"
- desc = "Allows you to to turn a cyborg into a clown, honk."
- icon_state = "cyborg_upgrade3"
- new_module = /obj/item/robot_module/clown
+// robot_upgrades.dm
+// Contains various borg upgrades.
+
+/obj/item/borg/upgrade
+ name = "borg upgrade module."
+ desc = "Protected by FRM."
+ icon = 'icons/obj/module.dmi'
+ icon_state = "cyborg_upgrade"
+ var/locked = FALSE
+ var/installed = 0
+ var/require_module = 0
+ var/module_type = null
+ // if true, is not stored in the robot to be ejected
+ // if module is reset
+ var/one_use = FALSE
+
+/obj/item/borg/upgrade/proc/action(mob/living/silicon/robot/R, user = usr)
+ if(R.stat == DEAD)
+ to_chat(user, "[src] will not function on a deceased cyborg.")
+ return FALSE
+ if(module_type && !istype(R.module, module_type))
+ to_chat(R, "Upgrade mounting error! No suitable hardpoint detected!")
+ to_chat(user, "There's no mounting point for the module!")
+ return FALSE
+ return TRUE
+
+/obj/item/borg/upgrade/proc/deactivate(mob/living/silicon/robot/R, user = usr)
+ if (!(src in R.upgrades))
+ return FALSE
+ return TRUE
+
+/obj/item/borg/upgrade/rename
+ name = "cyborg reclassification board"
+ desc = "Used to rename a cyborg."
+ icon_state = "cyborg_upgrade1"
+ var/heldname = ""
+ one_use = TRUE
+
+/obj/item/borg/upgrade/rename/attack_self(mob/user)
+ heldname = stripped_input(user, "Enter new robot name", "Cyborg Reclassification", heldname, MAX_NAME_LEN)
+
+/obj/item/borg/upgrade/rename/action(mob/living/silicon/robot/R)
+ . = ..()
+ if(.)
+ var/oldname = R.real_name
+ R.custom_name = heldname
+ R.updatename()
+ if(oldname == R.real_name)
+ R.notify_ai(RENAME, oldname, R.real_name)
+
+/obj/item/borg/upgrade/restart
+ name = "cyborg emergency reboot module"
+ desc = "Used to force a reboot of a disabled-but-repaired cyborg, bringing it back online."
+ icon_state = "cyborg_upgrade1"
+ one_use = TRUE
+
+/obj/item/borg/upgrade/restart/action(mob/living/silicon/robot/R, user = usr)
+ if(R.health < 0)
+ to_chat(user, "You have to repair the cyborg before using this module!")
+ return FALSE
+
+ if(R.mind)
+ R.mind.grab_ghost()
+ playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
+
+ R.revive()
+
+/obj/item/borg/upgrade/vtec
+ name = "cyborg VTEC module"
+ desc = "Used to kick in a cyborg's VTEC systems, increasing their speed."
+ icon_state = "cyborg_upgrade2"
+ require_module = 1
+
+/obj/item/borg/upgrade/vtec/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ if(R.speed < 0)
+ to_chat(R, "A VTEC unit is already installed!")
+ to_chat(user, "There's no room for another VTEC unit!")
+ return FALSE
+
+ //R.speed = -2 // Gotta go fast.
+ //Citadel change - makes vtecs give an ability rather than reducing the borg's speed instantly
+ R.AddAbility(new/obj/effect/proc_holder/silicon/cyborg/vtecControl)
+
+/obj/item/borg/upgrade/vtec/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ R.speed = initial(R.speed)
+
+/obj/item/borg/upgrade/disablercooler
+ name = "cyborg rapid disabler cooling module"
+ desc = "Used to cool a mounted disabler, increasing the potential current in it and thus its recharge rate."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ //module_type = /obj/item/robot_module/security
+
+/obj/item/borg/upgrade/disablercooler/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules
+ if(!T)
+ to_chat(user, "There's no disabler in this unit!")
+ return FALSE
+ if(T.charge_delay <= 2)
+ to_chat(R, "A cooling unit is already installed!")
+ to_chat(user, "There's no room for another cooling unit!")
+ return FALSE
+
+ T.charge_delay = max(2 , T.charge_delay - 4)
+
+/obj/item/borg/upgrade/disablercooler/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ var/obj/item/gun/energy/disabler/cyborg/T = locate() in R.module.modules
+ if(!T)
+ return FALSE
+ T.charge_delay = initial(T.charge_delay)
+
+/obj/item/borg/upgrade/thrusters
+ name = "ion thruster upgrade"
+ desc = "An energy-operated thruster system for cyborgs."
+ icon_state = "cyborg_upgrade3"
+
+/obj/item/borg/upgrade/thrusters/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ if(R.ionpulse)
+ to_chat(user, "This unit already has ion thrusters installed!")
+ return FALSE
+
+ R.ionpulse = TRUE
+
+/obj/item/borg/upgrade/thrusters/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ R.ionpulse = FALSE
+
+/obj/item/borg/upgrade/ddrill
+ name = "mining cyborg diamond drill"
+ desc = "A diamond drill replacement for the mining module's standard drill."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/robot_module/miner
+
+/obj/item/borg/upgrade/ddrill/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ for(var/obj/item/pickaxe/drill/cyborg/D in R.module)
+ R.module.remove_module(D, TRUE)
+ for(var/obj/item/shovel/S in R.module)
+ R.module.remove_module(S, TRUE)
+
+ var/obj/item/pickaxe/drill/cyborg/diamond/DD = new /obj/item/pickaxe/drill/cyborg/diamond(R.module)
+ R.module.basic_modules += DD
+ R.module.add_module(DD, FALSE, TRUE)
+
+/obj/item/borg/upgrade/ddrill/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ for(var/obj/item/pickaxe/drill/cyborg/diamond/DD in R.module)
+ R.module.remove_module(DD, TRUE)
+
+ var/obj/item/pickaxe/drill/cyborg/D = new (R.module)
+ R.module.basic_modules += D
+ R.module.add_module(D, FALSE, TRUE)
+ var/obj/item/shovel/S = new (R.module)
+ R.module.basic_modules += S
+ R.module.add_module(S, FALSE, TRUE)
+
+/obj/item/borg/upgrade/soh
+ name = "mining cyborg satchel of holding"
+ desc = "A satchel of holding replacement for mining cyborg's ore satchel module."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/robot_module/miner
+
+/obj/item/borg/upgrade/soh/action(mob/living/silicon/robot/R)
+ . = ..()
+ if(.)
+ for(var/obj/item/storage/bag/ore/cyborg/S in R.module)
+ R.module.remove_module(S, TRUE)
+
+ var/obj/item/storage/bag/ore/holding/H = new /obj/item/storage/bag/ore/holding(R.module)
+ R.module.basic_modules += H
+ R.module.add_module(H, FALSE, TRUE)
+
+/obj/item/borg/upgrade/soh/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ for(var/obj/item/storage/bag/ore/holding/H in R.module)
+ R.module.remove_module(H, TRUE)
+
+ var/obj/item/storage/bag/ore/cyborg/S = new (R.module)
+ R.module.basic_modules += S
+ R.module.add_module(S, FALSE, TRUE)
+
+/obj/item/borg/upgrade/tboh
+ name = "janitor cyborg trash bag of holding"
+ desc = "A trash bag of holding replacement for the janiborg's standard trash bag."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/robot_module/janitor
+
+/obj/item/borg/upgrade/tboh/action(mob/living/silicon/robot/R)
+ . = ..()
+ if(.)
+ for(var/obj/item/storage/bag/trash/cyborg/TB in R.module.modules)
+ R.module.remove_module(TB, TRUE)
+
+ var/obj/item/storage/bag/trash/bluespace/cyborg/B = new /obj/item/storage/bag/trash/bluespace/cyborg(R.module)
+ R.module.basic_modules += B
+ R.module.add_module(B, FALSE, TRUE)
+
+/obj/item/borg/upgrade/tboh/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ for(var/obj/item/storage/bag/trash/bluespace/cyborg/B in R.module.modules)
+ R.module.remove_module(B, TRUE)
+
+ var/obj/item/storage/bag/trash/cyborg/TB = new (R.module)
+ R.module.basic_modules += TB
+ R.module.add_module(TB, FALSE, TRUE)
+
+/obj/item/borg/upgrade/amop
+ name = "janitor cyborg advanced mop"
+ desc = "An advanced mop replacement for the janiborg's standard mop."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/robot_module/janitor
+
+/obj/item/borg/upgrade/amop/action(mob/living/silicon/robot/R)
+ . = ..()
+ if(.)
+ for(var/obj/item/mop/cyborg/M in R.module.modules)
+ R.module.remove_module(M, TRUE)
+
+ var/obj/item/mop/advanced/cyborg/A = new /obj/item/mop/advanced/cyborg(R.module)
+ R.module.basic_modules += A
+ R.module.add_module(A, FALSE, TRUE)
+
+/obj/item/borg/upgrade/amop/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ for(var/obj/item/mop/advanced/cyborg/A in R.module.modules)
+ R.module.remove_module(A, TRUE)
+
+ var/obj/item/mop/cyborg/M = new (R.module)
+ R.module.basic_modules += M
+ R.module.add_module(M, FALSE, TRUE)
+
+/obj/item/borg/upgrade/syndicate
+ name = "illegal equipment module"
+ desc = "Unlocks the hidden, deadlier functions of a cyborg."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+
+/obj/item/borg/upgrade/syndicate/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ if(R.emagged)
+ return FALSE
+
+ R.SetEmagged(1)
+
+ return TRUE
+
+/obj/item/borg/upgrade/syndicate/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ R.SetEmagged(FALSE)
+
+/obj/item/borg/upgrade/lavaproof
+ name = "mining cyborg lavaproof tracks"
+ desc = "An upgrade kit to apply specialized coolant systems and insulation layers to mining cyborg tracks, enabling them to withstand exposure to molten rock."
+ icon_state = "ash_plating"
+ resistance_flags = LAVA_PROOF | FIRE_PROOF
+ require_module = 1
+ module_type = /obj/item/robot_module/miner
+
+/obj/item/borg/upgrade/lavaproof/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ R.weather_immunities += "lava"
+
+/obj/item/borg/upgrade/lavaproof/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ R.weather_immunities -= "lava"
+
+/obj/item/borg/upgrade/selfrepair
+ name = "self-repair module"
+ desc = "This module will repair the cyborg over time."
+ icon_state = "cyborg_upgrade5"
+ require_module = 1
+ var/repair_amount = -1
+ var/repair_tick = 1
+ var/msg_cooldown = 0
+ var/on = FALSE
+ var/powercost = 10
+ var/mob/living/silicon/robot/cyborg
+ var/datum/action/toggle_action
+
+/obj/item/borg/upgrade/selfrepair/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ var/obj/item/borg/upgrade/selfrepair/U = locate() in R
+ if(U)
+ to_chat(user, "This unit is already equipped with a self-repair module.")
+ return FALSE
+
+ cyborg = R
+ icon_state = "selfrepair_off"
+ toggle_action = new /datum/action/item_action/toggle(src)
+ toggle_action.Grant(R)
+
+/obj/item/borg/upgrade/selfrepair/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ toggle_action.Remove(cyborg)
+ QDEL_NULL(toggle_action)
+ cyborg = null
+ deactivate_sr()
+
+/obj/item/borg/upgrade/selfrepair/dropped()
+ . = ..()
+ addtimer(CALLBACK(src, .proc/check_dropped), 1)
+
+/obj/item/borg/upgrade/selfrepair/proc/check_dropped()
+ if(loc != cyborg)
+ toggle_action.Remove(cyborg)
+ QDEL_NULL(toggle_action)
+ cyborg = null
+ deactivate_sr()
+
+/obj/item/borg/upgrade/selfrepair/ui_action_click()
+ on = !on
+ if(on)
+ to_chat(cyborg, "You activate the self-repair module.")
+ START_PROCESSING(SSobj, src)
+ else
+ to_chat(cyborg, "You deactivate the self-repair module.")
+ STOP_PROCESSING(SSobj, src)
+ update_icon()
+
+/obj/item/borg/upgrade/selfrepair/update_icon()
+ if(cyborg)
+ icon_state = "selfrepair_[on ? "on" : "off"]"
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+ else
+ icon_state = "cyborg_upgrade5"
+
+/obj/item/borg/upgrade/selfrepair/proc/deactivate_sr()
+ STOP_PROCESSING(SSobj, src)
+ on = FALSE
+ update_icon()
+
+/obj/item/borg/upgrade/selfrepair/process()
+ if(!repair_tick)
+ repair_tick = 1
+ return
+
+ if(cyborg && (cyborg.stat != DEAD) && on)
+ if(!cyborg.cell)
+ to_chat(cyborg, "Self-repair module deactivated. Please, insert the power cell.")
+ deactivate_sr()
+ return
+
+ if(cyborg.cell.charge < powercost * 2)
+ to_chat(cyborg, "Self-repair module deactivated. Please recharge.")
+ deactivate_sr()
+ return
+
+ if(cyborg.health < cyborg.maxHealth)
+ if(cyborg.health < 0)
+ repair_amount = -2.5
+ powercost = 30
+ else
+ repair_amount = -1
+ powercost = 10
+ cyborg.adjustBruteLoss(repair_amount)
+ cyborg.adjustFireLoss(repair_amount)
+ cyborg.updatehealth()
+ cyborg.cell.use(powercost)
+ else
+ cyborg.cell.use(5)
+ repair_tick = 0
+
+ if((world.time - 2000) > msg_cooldown )
+ var/msgmode = "standby"
+ if(cyborg.health < 0)
+ msgmode = "critical"
+ else if(cyborg.health < cyborg.maxHealth)
+ msgmode = "normal"
+ to_chat(cyborg, "Self-repair is active in [msgmode] mode.")
+ msg_cooldown = world.time
+ else
+ deactivate_sr()
+
+/obj/item/borg/upgrade/hypospray
+ name = "medical cyborg hypospray advanced synthesiser"
+ desc = "An upgrade to the Medical module cyborg's hypospray, allowing it \
+ to produce more advanced and complex medical reagents."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/robot_module/medical
+ var/list/additional_reagents = list()
+
+/obj/item/borg/upgrade/hypospray/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
+ if(H.accepts_reagent_upgrades)
+ for(var/re in additional_reagents)
+ H.add_reagent(re)
+
+/obj/item/borg/upgrade/hypospray/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
+ if(H.accepts_reagent_upgrades)
+ for(var/re in additional_reagents)
+ H.del_reagent(re)
+
+/obj/item/borg/upgrade/hypospray/expanded
+ name = "medical cyborg expanded hypospray"
+ desc = "An upgrade to the Medical module's hypospray, allowing it \
+ to treat a wider range of conditions and problems."
+ additional_reagents = list(/datum/reagent/medicine/mannitol, /datum/reagent/medicine/oculine, /datum/reagent/medicine/inacusiate,
+ /datum/reagent/medicine/mutadone, /datum/reagent/medicine/haloperidol)
+
+/obj/item/borg/upgrade/hypospray/high_strength
+ name = "medical cyborg high-strength hypospray"
+ desc = "An upgrade to the Medical module's hypospray, containing \
+ stronger versions of existing chemicals."
+ additional_reagents = list(/datum/reagent/medicine/oxandrolone, /datum/reagent/medicine/sal_acid,
+ /datum/reagent/medicine/rezadone, /datum/reagent/medicine/pen_acid)
+
+/obj/item/borg/upgrade/piercing_hypospray
+ name = "cyborg piercing hypospray"
+ desc = "An upgrade to a cyborg's hypospray, allowing it to \
+ pierce armor and thick material."
+ icon_state = "cyborg_upgrade3"
+
+/obj/item/borg/upgrade/piercing_hypospray/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ var/found_hypo = FALSE
+ for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
+ H.bypass_protection = TRUE
+ found_hypo = TRUE
+
+ if(!found_hypo)
+ return FALSE
+
+/obj/item/borg/upgrade/piercing_hypospray/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ for(var/obj/item/reagent_containers/borghypo/H in R.module.modules)
+ H.bypass_protection = initial(H.bypass_protection)
+
+/obj/item/borg/upgrade/defib
+ name = "medical cyborg defibrillator"
+ desc = "An upgrade to the Medical module, installing a built-in \
+ defibrillator, for on the scene revival."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/robot_module/medical
+
+/obj/item/borg/upgrade/defib/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ var/obj/item/twohanded/shockpaddles/cyborg/S = new(R.module)
+ R.module.basic_modules += S
+ R.module.add_module(S, FALSE, TRUE)
+
+/obj/item/borg/upgrade/defib/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ var/obj/item/twohanded/shockpaddles/cyborg/S = locate() in R.module
+ R.module.remove_module(S, TRUE)
+
+/obj/item/borg/upgrade/processor
+ name = "medical cyborg surgical processor"
+ desc = "An upgrade to the Medical module, installing a processor \
+ capable of scanning surgery disks and carrying \
+ out procedures"
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = /obj/item/robot_module/medical
+
+/obj/item/borg/upgrade/processor/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ var/obj/item/surgical_processor/SP = new(R.module)
+ R.module.basic_modules += SP
+ R.module.add_module(SP, FALSE, TRUE)
+
+/obj/item/borg/upgrade/processor/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ var/obj/item/surgical_processor/SP = locate() in R.module
+ R.module.remove_module(SP, TRUE)
+
+/obj/item/borg/upgrade/advhealth
+ name = "advanced cyborg health scanner"
+ desc = "An upgrade to the Medical modules, installing a built-in \
+ advanced health scanner, for better readings on patients."
+ icon_state = "cyborg_upgrade3"
+ require_module = 1
+ module_type = list(
+ /obj/item/robot_module/medical,
+ /obj/item/robot_module/syndicate_medical,
+ /obj/item/robot_module/medihound,
+ /obj/item/robot_module/borgi)
+
+/obj/item/borg/upgrade/advhealth/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ var/obj/item/healthanalyzer/advanced/AH = new(R.module)
+ R.module.basic_modules += AH
+ R.module.add_module(AH, FALSE, TRUE)
+
+/obj/item/borg/upgrade/processor/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ var/obj/item/healthanalyzer/advanced/AH = locate() in R.module
+ R.module.remove_module(AH, TRUE)
+
+/obj/item/borg/upgrade/ai
+ name = "B.O.R.I.S. module"
+ desc = "Bluespace Optimized Remote Intelligence Synchronization. An uplink device which takes the place of an MMI in cyborg endoskeletons, creating a robotic shell controlled by an AI."
+ icon_state = "boris"
+
+/obj/item/borg/upgrade/ai/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ if(R.shell)
+ to_chat(user, "This unit is already an AI shell!")
+ return FALSE
+ if(R.key) //You cannot replace a player unless the key is completely removed.
+ to_chat(user, "Intelligence patterns detected in this [R.braintype]. Aborting.")
+ return FALSE
+
+ R.make_shell(src)
+
+/obj/item/borg/upgrade/ai/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ if(R.shell)
+ R.undeploy()
+ R.notify_ai(AI_SHELL)
+
+/obj/item/borg/upgrade/expand
+ name = "borg expander"
+ desc = "A cyborg resizer, it makes a cyborg huge."
+ icon_state = "cyborg_upgrade3"
+
+/obj/item/borg/upgrade/expand/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+
+ if(R.hasExpanded)
+ to_chat(usr, "This unit already has an expand module installed!")
+ return FALSE
+
+ R.notransform = TRUE
+ var/prev_lockcharge = R.lockcharge
+ R.SetLockdown(1)
+ R.anchored = TRUE
+ var/datum/effect_system/smoke_spread/smoke = new
+ smoke.set_up(1, R.loc)
+ smoke.start()
+ sleep(2)
+ for(var/i in 1 to 4)
+ playsound(R, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, 1, -1)
+ sleep(12)
+ if(!prev_lockcharge)
+ R.SetLockdown(0)
+ R.anchored = FALSE
+ R.notransform = FALSE
+ R.resize = 2
+ R.hasExpanded = TRUE
+ R.update_transform()
+
+/obj/item/borg/upgrade/expand/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ R.resize = 0.5
+ R.hasExpanded = FALSE
+ R.update_transform()
+
+/obj/item/borg/upgrade/rped
+ name = "engineering cyborg RPED"
+ desc = "A rapid part exchange device for the engineering cyborg."
+ icon = 'icons/obj/storage.dmi'
+ icon_state = "borgrped"
+ require_module = TRUE
+ module_type = /obj/item/robot_module/engineering
+
+/obj/item/borg/upgrade/rped/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+
+ var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R
+ if(RPED)
+ to_chat(user, "This unit is already equipped with a RPED module.")
+ return FALSE
+
+ RPED = new(R.module)
+ R.module.basic_modules += RPED
+ R.module.add_module(RPED, FALSE, TRUE)
+
+/obj/item/borg/upgrade/rped/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ var/obj/item/storage/part_replacer/cyborg/RPED = locate() in R.module
+ if (RPED)
+ R.module.remove_module(RPED, TRUE)
+
+/obj/item/borg/upgrade/circuit_app
+ name = "circuit manipulation apparatus"
+ desc = "An engineering cyborg upgrade allowing for manipulation of circuit boards."
+ icon_state = "cyborg_upgrade3"
+ require_module = TRUE
+ module_type = list(/obj/item/robot_module/engineering)
+
+/obj/item/borg/upgrade/circuit_app/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ var/obj/item/borg/apparatus/circuit/C = locate() in R.module.modules
+ if(C)
+ to_chat(user, "This unit is already equipped with a circuit apparatus!")
+ return FALSE
+
+ C = new(R.module)
+ R.module.basic_modules += C
+ R.module.add_module(C, FALSE, TRUE)
+
+/obj/item/borg/upgrade/circuit_app/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ var/obj/item/borg/apparatus/circuit/C = locate() in R.module.modules
+ if (C)
+ R.module.remove_module(C, TRUE)
+
+/obj/item/borg/upgrade/pinpointer
+ name = "medical cyborg crew pinpointer"
+ desc = "A crew pinpointer module for the medical cyborg."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "pinpointer_crew"
+ require_module = TRUE
+ module_type = /obj/item/robot_module/medical
+
+/obj/item/borg/upgrade/pinpointer/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+
+ var/obj/item/pinpointer/crew/PP = locate() in R
+ if(PP)
+ to_chat(user, "This unit is already equipped with a pinpointer module.")
+ return FALSE
+
+ PP = new(R.module)
+ R.module.basic_modules += PP
+ R.module.add_module(PP, FALSE, TRUE)
+
+/obj/item/borg/upgrade/pinpointer/deactivate(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if (.)
+ var/obj/item/pinpointer/crew/PP = locate() in R.module
+ if (PP)
+ R.module.remove_module(PP, TRUE)
+
+/obj/item/borg/upgrade/transform
+ name = "borg module picker (Standard)"
+ desc = "Allows you to to turn a cyborg into a standard cyborg."
+ icon_state = "cyborg_upgrade3"
+ var/obj/item/robot_module/new_module = /obj/item/robot_module/standard
+
+/obj/item/borg/upgrade/transform/action(mob/living/silicon/robot/R, user = usr)
+ . = ..()
+ if(.)
+ R.module.transform_to(new_module)
+
+/obj/item/borg/upgrade/transform/clown
+ name = "borg module picker (Clown)"
+ desc = "Allows you to to turn a cyborg into a clown, honk."
+ icon_state = "cyborg_upgrade3"
+ new_module = /obj/item/robot_module/clown
diff --git a/code/game/objects/items/stacks/bscrystal.dm b/code/game/objects/items/stacks/bscrystal.dm
index acf95ada..acfc6100 100644
--- a/code/game/objects/items/stacks/bscrystal.dm
+++ b/code/game/objects/items/stacks/bscrystal.dm
@@ -1,89 +1,89 @@
-//Bluespace crystals, used in telescience and when crushed it will blink you to a random turf.
-/obj/item/stack/ore/bluespace_crystal
- name = "bluespace crystal"
- desc = "A glowing bluespace crystal, not much is known about how they work. It looks very delicate."
- icon = 'icons/obj/telescience.dmi'
- icon_state = "bluespace_crystal"
- singular_name = "bluespace crystal"
- w_class = WEIGHT_CLASS_TINY
- materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
- points = 50
- var/blink_range = 8 // The teleport range when crushed/thrown at someone.
- refined_type = /obj/item/stack/sheet/bluespace_crystal
- grind_results = list("bluespace" = 20)
-
-/obj/item/stack/ore/bluespace_crystal/refined
- name = "refined bluespace crystal"
- points = 0
- refined_type = null
-
-/obj/item/stack/ore/bluespace_crystal/Initialize()
- . = ..()
- pixel_x = rand(-5, 5)
- pixel_y = rand(-5, 5)
-
-/obj/item/stack/ore/bluespace_crystal/get_part_rating()
- return 1
-
-/obj/item/stack/ore/bluespace_crystal/attack_self(mob/user)
- user.visible_message("[user] crushes [src]!", "You crush [src]!")
- new /obj/effect/particle_effect/sparks(loc)
- playsound(loc, "sparks", 50, 1)
- blink_mob(user)
- use(1)
-
-/obj/item/stack/ore/bluespace_crystal/proc/blink_mob(mob/living/L)
- do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
-
-/obj/item/stack/ore/bluespace_crystal/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- if(!..()) // not caught in mid-air
- visible_message("[src] fizzles and disappears upon impact!")
- var/turf/T = get_turf(hit_atom)
- new /obj/effect/particle_effect/sparks(T)
- playsound(loc, "sparks", 50, 1)
- if(isliving(hit_atom))
- blink_mob(hit_atom)
- use(1)
-
-//Artificial bluespace crystal, doesn't give you much research.
-/obj/item/stack/ore/bluespace_crystal/artificial
- name = "artificial bluespace crystal"
- desc = "An artificially made bluespace crystal, it looks delicate."
- materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT*0.5)
- blink_range = 4 // Not as good as the organic stuff!
- points = 0 //nice try
- refined_type = null
- grind_results = list("bluespace" = 10, "silicon" = 20)
-
-//Polycrystals, aka stacks
-/obj/item/stack/sheet/bluespace_crystal
- name = "bluespace polycrystal"
- icon = 'icons/obj/telescience.dmi'
- icon_state = "polycrystal"
- item_state = "sheet-polycrystal"
- singular_name = "bluespace polycrystal"
- desc = "A stable polycrystal, made of fused-together bluespace crystals. You could probably break one off."
- materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
- attack_verb = list("bluespace polybashed", "bluespace polybattered", "bluespace polybludgeoned", "bluespace polythrashed", "bluespace polysmashed")
- novariants = TRUE
- grind_results = list("bluespace" = 20)
- point_value = 30
- var/crystal_type = /obj/item/stack/ore/bluespace_crystal/refined
-
-/obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening
- to_chat(user, "You cannot crush the polycrystal in-hand, try breaking one off.")
-
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/obj/item/stack/sheet/bluespace_crystal/attack_hand(mob/user)
- if(user.get_inactive_held_item() == src)
- if(zero_amount())
- return
- var/BC = new crystal_type(src)
- user.put_in_hands(BC)
- use(1)
- if(!amount)
- to_chat(user, "You break the final crystal off.")
- else
- to_chat(user, "You break off a crystal.")
- else
- ..()
+//Bluespace crystals, used in telescience and when crushed it will blink you to a random turf.
+/obj/item/stack/ore/bluespace_crystal
+ name = "bluespace crystal"
+ desc = "A glowing bluespace crystal, not much is known about how they work. It looks very delicate."
+ icon = 'icons/obj/telescience.dmi'
+ icon_state = "bluespace_crystal"
+ singular_name = "bluespace crystal"
+ w_class = WEIGHT_CLASS_TINY
+ materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
+ points = 50
+ var/blink_range = 8 // The teleport range when crushed/thrown at someone.
+ refined_type = /obj/item/stack/sheet/bluespace_crystal
+ grind_results = list(/datum/reagent/bluespace = 20)
+
+/obj/item/stack/ore/bluespace_crystal/refined
+ name = "refined bluespace crystal"
+ points = 0
+ refined_type = null
+
+/obj/item/stack/ore/bluespace_crystal/Initialize()
+ . = ..()
+ pixel_x = rand(-5, 5)
+ pixel_y = rand(-5, 5)
+
+/obj/item/stack/ore/bluespace_crystal/get_part_rating()
+ return 1
+
+/obj/item/stack/ore/bluespace_crystal/attack_self(mob/user)
+ user.visible_message("[user] crushes [src]!", "You crush [src]!")
+ new /obj/effect/particle_effect/sparks(loc)
+ playsound(loc, "sparks", 50, 1)
+ blink_mob(user)
+ use(1)
+
+/obj/item/stack/ore/bluespace_crystal/proc/blink_mob(mob/living/L)
+ do_teleport(L, get_turf(L), blink_range, asoundin = 'sound/effects/phasein.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
+
+/obj/item/stack/ore/bluespace_crystal/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ if(!..()) // not caught in mid-air
+ visible_message("[src] fizzles and disappears upon impact!")
+ var/turf/T = get_turf(hit_atom)
+ new /obj/effect/particle_effect/sparks(T)
+ playsound(loc, "sparks", 50, 1)
+ if(isliving(hit_atom))
+ blink_mob(hit_atom)
+ use(1)
+
+//Artificial bluespace crystal, doesn't give you much research.
+/obj/item/stack/ore/bluespace_crystal/artificial
+ name = "artificial bluespace crystal"
+ desc = "An artificially made bluespace crystal, it looks delicate."
+ materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT*0.5)
+ blink_range = 4 // Not as good as the organic stuff!
+ points = 0 //nice try
+ refined_type = null
+ grind_results = list(/datum/reagent/bluespace = 10, /datum/reagent/silicon = 20)
+
+//Polycrystals, aka stacks
+/obj/item/stack/sheet/bluespace_crystal
+ name = "bluespace polycrystal"
+ icon = 'icons/obj/telescience.dmi'
+ icon_state = "polycrystal"
+ item_state = "sheet-polycrystal"
+ singular_name = "bluespace polycrystal"
+ desc = "A stable polycrystal, made of fused-together bluespace crystals. You could probably break one off."
+ materials = list(MAT_BLUESPACE=MINERAL_MATERIAL_AMOUNT)
+ attack_verb = list("bluespace polybashed", "bluespace polybattered", "bluespace polybludgeoned", "bluespace polythrashed", "bluespace polysmashed")
+ novariants = TRUE
+ grind_results = list(/datum/reagent/bluespace = 20)
+ point_value = 30
+ var/crystal_type = /obj/item/stack/ore/bluespace_crystal/refined
+
+/obj/item/stack/sheet/bluespace_crystal/attack_self(mob/user)// to prevent the construction menu from ever happening
+ to_chat(user, "You cannot crush the polycrystal in-hand, try breaking one off.")
+
+//ATTACK HAND IGNORING PARENT RETURN VALUE
+/obj/item/stack/sheet/bluespace_crystal/attack_hand(mob/user)
+ if(user.get_inactive_held_item() == src)
+ if(zero_amount())
+ return
+ var/BC = new crystal_type(src)
+ user.put_in_hands(BC)
+ use(1)
+ if(!amount)
+ to_chat(user, "You break the final crystal off.")
+ else
+ to_chat(user, "You break off a crystal.")
+ else
+ ..()
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index caab2855..cc044c18 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -1,192 +1,192 @@
-/obj/item/stack/medical
- name = "medical pack"
- singular_name = "medical pack"
- icon = 'icons/obj/stack_objects.dmi'
- amount = 6
- max_amount = 6
- w_class = WEIGHT_CLASS_TINY
- full_w_class = WEIGHT_CLASS_TINY
- throw_speed = 3
- throw_range = 7
- resistance_flags = FLAMMABLE
- max_integrity = 40
- novariants = FALSE
- var/heal_brute = 0
- var/heal_burn = 0
- var/stop_bleeding = 0
- var/self_delay = 50
- var/fix_bone= 0
-
-/obj/item/stack/medical/attack(mob/living/M, mob/user)
- if(M.stat == DEAD && !stop_bleeding)
- var/t_him = "it"
- if(M.gender == MALE)
- t_him = "him"
- else if(M.gender == FEMALE)
- t_him = "her"
- to_chat(user, "\The [M] is dead, you cannot help [t_him]!")
- return
-
- if(!iscarbon(M) && !isanimal(M))
- to_chat(user, "You don't know how to apply \the [src] to [M]!")
- return 1
-
- var/obj/item/bodypart/affecting
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- affecting = C.get_bodypart(check_zone(user.zone_selected))
- if(!affecting) //Missing limb?
- to_chat(user, "[C] doesn't have \a [parse_zone(user.zone_selected)]!")
- return
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if(stop_bleeding)
- if(H.bleedsuppress)
- to_chat(user, "[H]'s bleeding is already bandaged!")
- return
- else if(!H.bleed_rate)
- to_chat(user, "[H] isn't bleeding!")
- return
-
-
- if(isliving(M))
- if(!M.can_inject(user, 1))
- return
-
- if(user)
- if (M != user)
- if (isanimal(M))
- var/mob/living/simple_animal/critter = M
- if (!(critter.healable))
- to_chat(user, " You cannot use [src] on [M]!")
- return
- else if (critter.health == critter.maxHealth)
- to_chat(user, " [M] is at full health.")
- return
- else if(src.heal_brute < 1)
- to_chat(user, " [src] won't help [M] at all.")
- return
- user.visible_message("[user] applies [src] on [M].", "You apply [src] on [M].")
- else
- var/t_himself = "itself"
- if(user.gender == MALE)
- t_himself = "himself"
- else if(user.gender == FEMALE)
- t_himself = "herself"
- user.visible_message("[user] starts to apply [src] on [t_himself]...", "You begin applying [src] on yourself...")
- if(!do_mob(user, M, self_delay, extra_checks=CALLBACK(M, /mob/living/proc/can_inject,user,1)))
- return
- user.visible_message("[user] applies [src] on [t_himself].", "You apply [src] on yourself.")
-
-
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- affecting = C.get_bodypart(check_zone(user.zone_selected))
- if(!affecting) //Missing limb?
- to_chat(user, "[C] doesn't have \a [parse_zone(user.zone_selected)]!")
- return
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if(stop_bleeding)
- if(!H.bleedsuppress) //so you can't stack bleed suppression
- H.suppress_bloodloss(stop_bleeding)
- if(affecting.status == BODYPART_ORGANIC) //Limb must be organic to be healed - RR
- if(affecting.heal_damage(heal_brute, heal_burn))
- C.update_damage_overlays()
- if (fix_bone) //Fix broken bones on targeted limb
- if(affecting.broken == 1)
- affecting.broken = 0
- affecting.disabled = 0
- else
- to_chat(user, "Medicine won't work on a robotic limb!")
- else
- M.heal_bodypart_damage((src.heal_brute/2), (src.heal_burn/2))
-
- use(1)
-
-/obj/item/stack/medical/plaster_gauze
- name = "plaster gauze"
- gender = PLURAL
- singular_name = "plaster gauze"
- desc = "A roll of plaster of paris that is extremely effective at aiding bone fractures, but does not heal wounds."
- icon_state = "pgauze"
- self_delay = 300
- max_amount = 10
- fix_bone = 1
-
-/obj/item/stack/medical/plaster_gauze/suicide_act(mob/user)
- user.visible_message("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return (BRUTELOSS)
-
-/obj/item/stack/medical/bruise_pack
- name = "bruise pack"
- singular_name = "bruise pack"
- desc = "A therapeutic gel pack and bandages designed to treat blunt-force trauma."
- icon_state = "brutepack"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- heal_brute = 40
- self_delay = 20
- grind_results = list("styptic_powder" = 10)
-
-/obj/item/stack/medical/bruise_pack/suicide_act(mob/user)
- user.visible_message("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return (BRUTELOSS)
-
-/obj/item/stack/medical/gauze
- name = "medical gauze"
- desc = "A roll of elastic cloth that is extremely effective at stopping bleeding, but does not heal wounds."
- gender = PLURAL
- singular_name = "medical gauze"
- icon_state = "gauze"
- stop_bleeding = 1800
- self_delay = 20
- max_amount = 12
-
-
-/obj/item/stack/medical/gauze/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/wirecutters) || I.is_sharp())
- if(get_amount() < 2)
- to_chat(user, "You need at least two gauzes to do this!")
- return
- new /obj/item/stack/sheet/cloth(user.drop_location())
- user.visible_message("[user] cuts [src] into pieces of cloth with [I].", \
- "You cut [src] into pieces of cloth with [I].", \
- "You hear cutting.")
- use(2)
- else
- return ..()
-
-/obj/item/stack/medical/gauze/suicide_act(mob/living/user)
- user.visible_message("[user] begins tightening \the [src] around [user.p_their()] neck! It looks like [user.p_they()] forgot how to use medical supplies!")
- return OXYLOSS
-
-/obj/item/stack/medical/gauze/improvised
- name = "improvised gauze"
- singular_name = "improvised gauze"
- desc = "A roll of cloth roughly cut from something that can stop bleeding, but does not heal wounds."
- stop_bleeding = 900
-
-/obj/item/stack/medical/gauze/cyborg
- materials = list()
- is_cyborg = 1
- cost = 250
-
-/obj/item/stack/medical/ointment
- name = "ointment"
- desc = "Used to treat those nasty burn wounds."
- gender = PLURAL
- singular_name = "ointment"
- icon_state = "ointment"
- lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
- heal_burn = 40
- self_delay = 20
- grind_results = list("silver_sulfadiazine" = 10)
-
-/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
- user.visible_message("[user] is squeezing \the [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?")
- return TOXLOSS
-
-/obj/item/stack/medical/get_belt_overlay()
- return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch")
+/obj/item/stack/medical
+ name = "medical pack"
+ singular_name = "medical pack"
+ icon = 'icons/obj/stack_objects.dmi'
+ amount = 6
+ max_amount = 6
+ w_class = WEIGHT_CLASS_TINY
+ full_w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ resistance_flags = FLAMMABLE
+ max_integrity = 40
+ novariants = FALSE
+ var/heal_brute = 0
+ var/heal_burn = 0
+ var/stop_bleeding = 0
+ var/self_delay = 50
+ var/fix_bone= 0
+
+/obj/item/stack/medical/attack(mob/living/M, mob/user)
+ if(M.stat == DEAD && !stop_bleeding)
+ var/t_him = "it"
+ if(M.gender == MALE)
+ t_him = "him"
+ else if(M.gender == FEMALE)
+ t_him = "her"
+ to_chat(user, "\The [M] is dead, you cannot help [t_him]!")
+ return
+
+ if(!iscarbon(M) && !isanimal(M))
+ to_chat(user, "You don't know how to apply \the [src] to [M]!")
+ return 1
+
+ var/obj/item/bodypart/affecting
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ affecting = C.get_bodypart(check_zone(user.zone_selected))
+ if(!affecting) //Missing limb?
+ to_chat(user, "[C] doesn't have \a [parse_zone(user.zone_selected)]!")
+ return
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if(stop_bleeding)
+ if(H.bleedsuppress)
+ to_chat(user, "[H]'s bleeding is already bandaged!")
+ return
+ else if(!H.bleed_rate)
+ to_chat(user, "[H] isn't bleeding!")
+ return
+
+
+ if(isliving(M))
+ if(!M.can_inject(user, 1))
+ return
+
+ if(user)
+ if (M != user)
+ if (isanimal(M))
+ var/mob/living/simple_animal/critter = M
+ if (!(critter.healable))
+ to_chat(user, " You cannot use [src] on [M]!")
+ return
+ else if (critter.health == critter.maxHealth)
+ to_chat(user, " [M] is at full health.")
+ return
+ else if(src.heal_brute < 1)
+ to_chat(user, " [src] won't help [M] at all.")
+ return
+ user.visible_message("[user] applies [src] on [M].", "You apply [src] on [M].")
+ else
+ var/t_himself = "itself"
+ if(user.gender == MALE)
+ t_himself = "himself"
+ else if(user.gender == FEMALE)
+ t_himself = "herself"
+ user.visible_message("[user] starts to apply [src] on [t_himself]...", "You begin applying [src] on yourself...")
+ if(!do_mob(user, M, self_delay, extra_checks=CALLBACK(M, /mob/living/proc/can_inject,user,1)))
+ return
+ user.visible_message("[user] applies [src] on [t_himself].", "You apply [src] on yourself.")
+
+
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ affecting = C.get_bodypart(check_zone(user.zone_selected))
+ if(!affecting) //Missing limb?
+ to_chat(user, "[C] doesn't have \a [parse_zone(user.zone_selected)]!")
+ return
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if(stop_bleeding)
+ if(!H.bleedsuppress) //so you can't stack bleed suppression
+ H.suppress_bloodloss(stop_bleeding)
+ if(affecting.status == BODYPART_ORGANIC) //Limb must be organic to be healed - RR
+ if(affecting.heal_damage(heal_brute, heal_burn))
+ C.update_damage_overlays()
+ if (fix_bone) //Fix broken bones on targeted limb
+ if(affecting.broken == 1)
+ affecting.broken = 0
+ affecting.disabled = 0
+ else
+ to_chat(user, "Medicine won't work on a robotic limb!")
+ else
+ M.heal_bodypart_damage((src.heal_brute/2), (src.heal_burn/2))
+
+ use(1)
+
+/obj/item/stack/medical/plaster_gauze
+ name = "plaster gauze"
+ gender = PLURAL
+ singular_name = "plaster gauze"
+ desc = "A roll of plaster of paris that is extremely effective at aiding bone fractures, but does not heal wounds."
+ icon_state = "pgauze"
+ self_delay = 300
+ max_amount = 10
+ fix_bone = 1
+
+/obj/item/stack/medical/plaster_gauze/suicide_act(mob/user)
+ user.visible_message("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (BRUTELOSS)
+
+/obj/item/stack/medical/bruise_pack
+ name = "bruise pack"
+ singular_name = "bruise pack"
+ desc = "A therapeutic gel pack and bandages designed to treat blunt-force trauma."
+ icon_state = "brutepack"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ heal_brute = 40
+ self_delay = 20
+ grind_results = list(/datum/reagent/medicine/styptic_powder = 10)
+
+/obj/item/stack/medical/bruise_pack/suicide_act(mob/user)
+ user.visible_message("[user] is bludgeoning [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (BRUTELOSS)
+
+/obj/item/stack/medical/gauze
+ name = "medical gauze"
+ desc = "A roll of elastic cloth that is extremely effective at stopping bleeding, but does not heal wounds."
+ gender = PLURAL
+ singular_name = "medical gauze"
+ icon_state = "gauze"
+ stop_bleeding = 1800
+ self_delay = 20
+ max_amount = 12
+
+
+/obj/item/stack/medical/gauze/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/wirecutters) || I.is_sharp())
+ if(get_amount() < 2)
+ to_chat(user, "You need at least two gauzes to do this!")
+ return
+ new /obj/item/stack/sheet/cloth(user.drop_location())
+ user.visible_message("[user] cuts [src] into pieces of cloth with [I].", \
+ "You cut [src] into pieces of cloth with [I].", \
+ "You hear cutting.")
+ use(2)
+ else
+ return ..()
+
+/obj/item/stack/medical/gauze/suicide_act(mob/living/user)
+ user.visible_message("[user] begins tightening \the [src] around [user.p_their()] neck! It looks like [user.p_they()] forgot how to use medical supplies!")
+ return OXYLOSS
+
+/obj/item/stack/medical/gauze/improvised
+ name = "improvised gauze"
+ singular_name = "improvised gauze"
+ desc = "A roll of cloth roughly cut from something that can stop bleeding, but does not heal wounds."
+ stop_bleeding = 900
+
+/obj/item/stack/medical/gauze/cyborg
+ materials = list()
+ is_cyborg = 1
+ cost = 250
+
+/obj/item/stack/medical/ointment
+ name = "ointment"
+ desc = "Used to treat those nasty burn wounds."
+ gender = PLURAL
+ singular_name = "ointment"
+ icon_state = "ointment"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ heal_burn = 40
+ self_delay = 20
+ grind_results = list(/datum/reagent/medicine/silver_sulfadiazine = 10)
+
+/obj/item/stack/medical/ointment/suicide_act(mob/living/user)
+ user.visible_message("[user] is squeezing \the [src] into [user.p_their()] mouth! [user.p_do(TRUE)]n't [user.p_they()] know that stuff is toxic?")
+ return TOXLOSS
+
+/obj/item/stack/medical/get_belt_overlay()
+ return mutable_appearance('icons/obj/clothing/belt_overlays.dmi', "pouch")
diff --git a/code/game/objects/items/stacks/sheets/light.dm b/code/game/objects/items/stacks/sheets/light.dm
index 49244772..c42cfbe5 100644
--- a/code/game/objects/items/stacks/sheets/light.dm
+++ b/code/game/objects/items/stacks/sheets/light.dm
@@ -1,35 +1,35 @@
-/obj/item/stack/light_w
- name = "wired glass tile"
- singular_name = "wired glass floor tile"
- desc = "A glass tile, which is wired, somehow."
- icon = 'icons/obj/tiles.dmi'
- icon_state = "glass_wire"
- w_class = WEIGHT_CLASS_NORMAL
- force = 3
- throwforce = 5
- throw_speed = 3
- throw_range = 7
- flags_1 = CONDUCT_1
- max_amount = 60
- grind_results = list("silicon" = 20, "copper" = 5)
-
-/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
- if(istype(O, /obj/item/stack/sheet/metal))
- var/obj/item/stack/sheet/metal/M = O
- if (M.use(1))
- var/obj/item/L = new /obj/item/stack/tile/light(user.drop_location())
- to_chat(user, "You make a light tile.")
- L.add_fingerprint(user)
- use(1)
- else
- to_chat(user, "You need one metal sheet to finish the light tile!")
- else
- return ..()
-
-/obj/item/stack/light_w/wirecutter_act(mob/living/user, obj/item/I)
- var/atom/Tsec = user.drop_location()
- var/obj/item/stack/cable_coil/CC = new (Tsec, 5)
- CC.add_fingerprint(user)
- var/obj/item/stack/sheet/glass/G = new (Tsec)
- G.add_fingerprint(user)
- use(1)
+/obj/item/stack/light_w
+ name = "wired glass tile"
+ singular_name = "wired glass floor tile"
+ desc = "A glass tile, which is wired, somehow."
+ icon = 'icons/obj/tiles.dmi'
+ icon_state = "glass_wire"
+ w_class = WEIGHT_CLASS_NORMAL
+ force = 3
+ throwforce = 5
+ throw_speed = 3
+ throw_range = 7
+ flags_1 = CONDUCT_1
+ max_amount = 60
+ grind_results = list(/datum/reagent/silicon = 20, /datum/reagent/copper = 5)
+
+/obj/item/stack/light_w/attackby(obj/item/O, mob/user, params)
+ if(istype(O, /obj/item/stack/sheet/metal))
+ var/obj/item/stack/sheet/metal/M = O
+ if (M.use(1))
+ var/obj/item/L = new /obj/item/stack/tile/light(user.drop_location())
+ to_chat(user, "You make a light tile.")
+ L.add_fingerprint(user)
+ use(1)
+ else
+ to_chat(user, "You need one metal sheet to finish the light tile!")
+ else
+ return ..()
+
+/obj/item/stack/light_w/wirecutter_act(mob/living/user, obj/item/I)
+ var/atom/Tsec = user.drop_location()
+ var/obj/item/stack/cable_coil/CC = new (Tsec, 5)
+ CC.add_fingerprint(user)
+ var/obj/item/stack/sheet/glass/G = new (Tsec)
+ G.add_fingerprint(user)
+ use(1)
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 1f1ceb3b..c27f4e65 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -108,7 +108,7 @@ GLOBAL_LIST_INIT(sandbag_recipes, list ( \
sheettype = "diamond"
materials = list(MAT_DIAMOND=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
- grind_results = list("carbon" = 20)
+ grind_results = list(/datum/reagent/carbon = 20)
point_value = 25
merge_type = /obj/item/stack/sheet/mineral/diamond
@@ -135,7 +135,7 @@ GLOBAL_LIST_INIT(diamond_recipes, list ( \
sheettype = "uranium"
materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
- grind_results = list("uranium" = 20)
+ grind_results = list(/datum/reagent/uranium = 20)
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/uranium
@@ -162,7 +162,7 @@ GLOBAL_LIST_INIT(uranium_recipes, list ( \
resistance_flags = FLAMMABLE
max_integrity = 100
materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
- grind_results = list("plasma" = 20)
+ grind_results = list(/datum/reagent/toxin/plasma = 20)
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/plasma
@@ -203,7 +203,7 @@ GLOBAL_LIST_INIT(plasma_recipes, list ( \
singular_name = "gold bar"
sheettype = "gold"
materials = list(MAT_GOLD=MINERAL_MATERIAL_AMOUNT)
- grind_results = list("gold" = 20)
+ grind_results = list(/datum/reagent/gold = 20)
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/gold
@@ -232,7 +232,7 @@ GLOBAL_LIST_INIT(gold_recipes, list ( \
singular_name = "silver bar"
sheettype = "silver"
materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
- grind_results = list("silver" = 20)
+ grind_results = list(/datum/reagent/silver = 20)
point_value = 20
merge_type = /obj/item/stack/sheet/mineral/silver
tableVariant = /obj/structure/table/optable
@@ -262,7 +262,7 @@ GLOBAL_LIST_INIT(silver_recipes, list ( \
sheettype = "bananium"
materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
novariants = TRUE
- grind_results = list("banana" = 20)
+ grind_results = list(/datum/reagent/consumable/banana = 20)
point_value = 50
merge_type = /obj/item/stack/sheet/mineral/bananium
@@ -342,7 +342,7 @@ GLOBAL_LIST_INIT(plastitanium_recipes, list ( \
singular_name = "snow block"
force = 1
throwforce = 2
- grind_results = list("ice" = 20)
+ grind_results = list(/datum/reagent/consumable/ice = 20)
merge_type = /obj/item/stack/sheet/mineral/snow
GLOBAL_LIST_INIT(snow_recipes, list ( \
@@ -422,7 +422,7 @@ GLOBAL_LIST_INIT(abductor_recipes, list ( \
icon_state = "slag"
singular_name = "coal lump"
merge_type = /obj/item/stack/sheet/mineral/coal
- grind_results = list("carbon" = 20)
+ grind_results = list(/datum/reagent/carbon = 20)
/obj/item/stack/sheet/mineral/coal/attackby(obj/item/W, mob/user, params)
if(W.get_temperature() > 300)//If the temperature of the object is over 300, then ignite
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 850a36a3..dbe94cb8 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -107,7 +107,7 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \
flags_1 = CONDUCT_1
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/metal
- grind_results = list("iron" = 20)
+ grind_results = list(/datum/reagent/iron = 20)
point_value = 2
tableVariant = /obj/structure/table
@@ -170,7 +170,7 @@ GLOBAL_LIST_INIT(plasteel_recipes, list ( \
armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 80)
resistance_flags = FIRE_PROOF
merge_type = /obj/item/stack/sheet/plasteel
- grind_results = list("iron" = 20, "plasma" = 20)
+ grind_results = list(/datum/reagent/iron = 20, /datum/reagent/toxin/plasma = 20)
point_value = 23
tableVariant = /obj/structure/table/reinforced
@@ -235,7 +235,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
resistance_flags = FLAMMABLE
merge_type = /obj/item/stack/sheet/mineral/wood
novariants = TRUE
- grind_results = list("carbon" = 20)
+ grind_results = list(/datum/reagent/carbon = 20)
/obj/item/stack/sheet/mineral/wood/Initialize(mapload, new_amount, merge = TRUE)
recipes = GLOB.wood_recipes
@@ -493,7 +493,7 @@ GLOBAL_LIST_INIT(runed_metal_recipes, list ( \
sheettype = "runed"
merge_type = /obj/item/stack/sheet/runed_metal
novariants = TRUE
- grind_results = list("iron" = 5, "blood" = 15)
+ grind_results = list(/datum/reagent/iron = 5, /datum/reagent/blood = 15)
/obj/item/stack/sheet/runed_metal/ratvar_act()
new /obj/item/stack/tile/brass(loc, amount)
@@ -569,7 +569,7 @@ GLOBAL_LIST_INIT(brass_recipes, list ( \
throw_range = 3
turf_type = /turf/open/floor/clockwork
novariants = FALSE
- grind_results = list("iron" = 5, "teslium" = 15, "holyoil" = 1)
+ grind_results = list(/datum/reagent/iron = 5, /datum/reagent/teslium = 15, /datum/reagent/fuel/holyoil = 1)
merge_type = /obj/item/stack/tile/brass
tableVariant = /obj/structure/table/reinforced/brass
@@ -622,7 +622,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
throw_range = 3
turf_type = /turf/open/floor/bronze
novariants = FALSE
- grind_results = list("iron" = 5, "copper" = 3) //we have no "tin" reagent so this is the closest thing
+ grind_results = list(/datum/reagent/iron = 5, /datum/reagent/copper = 3) //we have no "tin" reagent so this is the closest thing
merge_type = /obj/item/stack/tile/bronze
tableVariant = /obj/structure/table/bronze
@@ -676,7 +676,7 @@ GLOBAL_LIST_INIT(bronze_recipes, list ( \
w_class = WEIGHT_CLASS_NORMAL
throw_speed = 1
throw_range = 3
- grind_results = list("carbon" = 10)
+ grind_results = list(/datum/reagent/carbon = 10)
merge_type = /obj/item/stack/sheet/bone
GLOBAL_LIST_INIT(plastic_recipes, list(
diff --git a/code/game/objects/items/storage/book.dm b/code/game/objects/items/storage/book.dm
index c658eee3..e47021c1 100644
--- a/code/game/objects/items/storage/book.dm
+++ b/code/game/objects/items/storage/book.dm
@@ -163,16 +163,16 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "bible",
for(var/obj/effect/rune/R in orange(2,user))
R.invisibility = 0
if(user.mind && (user.mind.isholy))
- if(A.reagents && A.reagents.has_reagent("water")) // blesses all the water in the holder
+ if(A.reagents && A.reagents.has_reagent(/datum/reagent/water)) // blesses all the water in the holder
to_chat(user, "You bless [A].")
- var/water2holy = A.reagents.get_reagent_amount("water")
- A.reagents.del_reagent("water")
- A.reagents.add_reagent("holywater",water2holy)
- if(A.reagents && A.reagents.has_reagent("unholywater")) // yeah yeah, copy pasted code - sue me
+ var/water2holy = A.reagents.get_reagent_amount(/datum/reagent/water)
+ A.reagents.del_reagent(/datum/reagent/water)
+ A.reagents.add_reagent(/datum/reagent/water/holywater,water2holy)
+ if(A.reagents && A.reagents.has_reagent(/datum/reagent/fuel/unholywater)) // yeah yeah, copy pasted code - sue me
to_chat(user, "You purify [A].")
- var/unholy2clean = A.reagents.get_reagent_amount("unholywater")
- A.reagents.del_reagent("unholywater")
- A.reagents.add_reagent("holywater",unholy2clean)
+ var/unholy2clean = A.reagents.get_reagent_amount(/datum/reagent/fuel/unholywater)
+ A.reagents.del_reagent(/datum/reagent/fuel/unholywater)
+ A.reagents.add_reagent(/datum/reagent/water/holywater,unholy2clean)
if(istype(A, /obj/item/twohanded/required/cult_bastard) && !iscultist(user))
var/obj/item/twohanded/required/cult_bastard/sword = A
to_chat(user, "You begin to exorcise [sword].")
diff --git a/code/game/objects/items/tanks/watertank.dm b/code/game/objects/items/tanks/watertank.dm
index 8f2b8509..59628460 100644
--- a/code/game/objects/items/tanks/watertank.dm
+++ b/code/game/objects/items/tanks/watertank.dm
@@ -148,7 +148,7 @@
/obj/item/watertank/janitor/Initialize()
. = ..()
- reagents.add_reagent("cleaner", 500)
+ reagents.add_reagent(/datum/reagent/space_cleaner, 500)
/obj/item/reagent_containers/spray/mister/janitor
name = "janitor spray nozzle"
@@ -184,7 +184,7 @@
/obj/item/watertank/atmos/Initialize()
. = ..()
- reagents.add_reagent("water", 200)
+ reagents.add_reagent(/datum/reagent/water, 200)
/obj/item/watertank/atmos/make_noz()
return new /obj/item/extinguisher/mini/nozzle(src)
@@ -436,13 +436,13 @@
/obj/item/watertank/op/Initialize()
. = ..()
- reagents.add_reagent("mutagen",350)
- reagents.add_reagent("napalm",125)
- reagents.add_reagent("welding_fuel",125)
- reagents.add_reagent("clf3",300)
- reagents.add_reagent("cryptobiolin",350)
- reagents.add_reagent("plasma",250)
- reagents.add_reagent("condensedcapsaicin",500)
+ reagents.add_reagent(/datum/reagent/toxin/mutagen,350)
+ reagents.add_reagent(/datum/reagent/napalm,125)
+ reagents.add_reagent(/datum/reagent/fuel,125)
+ reagents.add_reagent(/datum/reagent/clf3,300)
+ reagents.add_reagent(/datum/reagent/cryptobiolin,350)
+ reagents.add_reagent(/datum/reagent/toxin/plasma,250)
+ reagents.add_reagent(/datum/reagent/consumable/condensedcapsaicin,500)
/obj/item/reagent_containers/spray/mister/op
desc = "A mister nozzle attached to several extended water tanks. It suspiciously has a compressor in the system and is labelled entirely in New Cyrillic."
diff --git a/code/game/objects/items/tools/weldingtool.dm b/code/game/objects/items/tools/weldingtool.dm
index 9177602f..e3711971 100644
--- a/code/game/objects/items/tools/weldingtool.dm
+++ b/code/game/objects/items/tools/weldingtool.dm
@@ -37,7 +37,7 @@
/obj/item/weldingtool/Initialize()
. = ..()
create_reagents(max_fuel)
- reagents.add_reagent("welding_fuel", max_fuel)
+ reagents.add_reagent(/datum/reagent/fuel, max_fuel)
update_icon()
@@ -97,7 +97,7 @@
/obj/item/weldingtool/proc/explode()
var/turf/T = get_turf(loc)
- var/plasmaAmount = reagents.get_reagent_amount("plasma")
+ var/plasmaAmount = reagents.get_reagent_amount(/datum/reagent/toxin/plasma)
dyn_explosion(T, plasmaAmount/5)//20 plasma in a standard welder has a 4 power explosion. no breaches, but enough to kill/dismember holder
qdel(src)
@@ -142,7 +142,7 @@
/obj/item/weldingtool/attack_self(mob/user)
- if(src.reagents.has_reagent("plasma"))
+ if(src.reagents.has_reagent(/datum/reagent/toxin/plasma))
message_admins("[ADMIN_LOOKUPFLW(user)] activated a rigged welder at [AREACOORD(user)].")
explode()
switched_on(user)
@@ -154,7 +154,7 @@
// Returns the amount of fuel in the welder
/obj/item/weldingtool/proc/get_fuel()
- return reagents.get_reagent_amount("welding_fuel")
+ return reagents.get_reagent_amount(/datum/reagent/fuel)
// Uses fuel from the welding tool.
@@ -165,7 +165,7 @@
if(used)
burned_fuel_for = 0
if(get_fuel() >= used)
- reagents.remove_reagent("welding_fuel", used)
+ reagents.remove_reagent(/datum/reagent/fuel, used)
check_fuel()
return TRUE
else
@@ -331,7 +331,7 @@
/obj/item/weldingtool/abductor/process()
if(get_fuel() <= max_fuel)
- reagents.add_reagent("welding_fuel", 1)
+ reagents.add_reagent(/datum/reagent/fuel, 1)
..()
/obj/item/weldingtool/hugetank
@@ -375,7 +375,7 @@
..()
if(get_fuel() < max_fuel && nextrefueltick < world.time)
nextrefueltick = world.time + 10
- reagents.add_reagent("welding_fuel", 1)
+ reagents.add_reagent(/datum/reagent/fuel, 1)
/obj/item/weldingtool/advanced
name = "advanced welding tool"
@@ -388,7 +388,7 @@
/obj/item/weldingtool/advanced/process()
if(get_fuel() <= max_fuel)
- reagents.add_reagent("welding_fuel", 1)
+ reagents.add_reagent(/datum/reagent/fuel, 1)
..()
#undef WELDER_FUEL_BURN_INTERVAL
diff --git a/code/game/objects/items/trash.dm b/code/game/objects/items/trash.dm
index 734b7b89..89354a01 100644
--- a/code/game/objects/items/trash.dm
+++ b/code/game/objects/items/trash.dm
@@ -1,85 +1,85 @@
-//Added by Jack Rost
-/obj/item/trash
- icon = 'icons/obj/janitor.dmi'
- lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
- desc = "This is rubbish."
- w_class = WEIGHT_CLASS_TINY
- resistance_flags = FLAMMABLE
-
-/obj/item/trash/raisins
- name = "\improper 4no raisins"
- icon_state= "4no_raisins"
-
-/obj/item/trash/candy
- name = "candy"
- icon_state= "candy"
-
-/obj/item/trash/cheesie
- name = "cheesie honkers"
- icon_state = "cheesie_honkers"
-
-/obj/item/trash/chips
- name = "chips"
- icon_state = "chips"
-
-/obj/item/trash/popcorn
- name = "popcorn"
- icon_state = "popcorn"
-
-/obj/item/trash/sosjerky
- name = "\improper Scaredy's Private Reserve Beef Jerky"
- icon_state = "sosjerky"
-
-/obj/item/trash/syndi_cakes
- name = "syndi-cakes"
- icon_state = "syndi_cakes"
-
-/obj/item/trash/waffles
- name = "waffles tray"
- icon_state = "waffles"
-
-/obj/item/trash/plate
- name = "plate"
- icon_state = "plate"
- resistance_flags = NONE
-
-/obj/item/trash/pistachios
- name = "pistachios pack"
- icon_state = "pistachios_pack"
-
-/obj/item/trash/semki
- name = "semki pack"
- icon_state = "semki_pack"
-
-/obj/item/trash/tray
- name = "tray"
- icon_state = "tray"
- resistance_flags = NONE
-
-/obj/item/trash/candle
- name = "candle"
- icon = 'icons/obj/candle.dmi'
- icon_state = "candle4"
-
-/obj/item/trash/can
- name = "crushed can"
- icon_state = "cola"
- resistance_flags = NONE
- grind_results = list("aluminium" = 10)
-
-/obj/item/trash/boritos
- name = "boritos bag"
- icon_state = "boritos"
- grind_results = list("aluminium" = 1) //from the mylar bag
-
-/obj/item/trash/soy_food
- name = "soyfood"
- icon_state = "soy_food"
-
-/obj/item/trash/carbonnanotube_noodles
- name = "carbon nanotube noodles"
- icon_state = "carbonnanotube_noodles"
-
-/obj/item/trash/attack(mob/M, mob/living/user)
- return
+//Added by Jack Rost
+/obj/item/trash
+ icon = 'icons/obj/janitor.dmi'
+ lefthand_file = 'icons/mob/inhands/misc/food_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/food_righthand.dmi'
+ desc = "This is rubbish."
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+
+/obj/item/trash/raisins
+ name = "\improper 4no raisins"
+ icon_state= "4no_raisins"
+
+/obj/item/trash/candy
+ name = "candy"
+ icon_state= "candy"
+
+/obj/item/trash/cheesie
+ name = "cheesie honkers"
+ icon_state = "cheesie_honkers"
+
+/obj/item/trash/chips
+ name = "chips"
+ icon_state = "chips"
+
+/obj/item/trash/popcorn
+ name = "popcorn"
+ icon_state = "popcorn"
+
+/obj/item/trash/sosjerky
+ name = "\improper Scaredy's Private Reserve Beef Jerky"
+ icon_state = "sosjerky"
+
+/obj/item/trash/syndi_cakes
+ name = "syndi-cakes"
+ icon_state = "syndi_cakes"
+
+/obj/item/trash/waffles
+ name = "waffles tray"
+ icon_state = "waffles"
+
+/obj/item/trash/plate
+ name = "plate"
+ icon_state = "plate"
+ resistance_flags = NONE
+
+/obj/item/trash/pistachios
+ name = "pistachios pack"
+ icon_state = "pistachios_pack"
+
+/obj/item/trash/semki
+ name = "semki pack"
+ icon_state = "semki_pack"
+
+/obj/item/trash/tray
+ name = "tray"
+ icon_state = "tray"
+ resistance_flags = NONE
+
+/obj/item/trash/candle
+ name = "candle"
+ icon = 'icons/obj/candle.dmi'
+ icon_state = "candle4"
+
+/obj/item/trash/can
+ name = "crushed can"
+ icon_state = "cola"
+ resistance_flags = NONE
+ grind_results = list(/datum/reagent/aluminium = 10)
+
+/obj/item/trash/boritos
+ name = "boritos bag"
+ icon_state = "boritos"
+ grind_results = list(/datum/reagent/aluminium = 1) //from the mylar bag
+
+/obj/item/trash/soy_food
+ name = "soyfood"
+ icon_state = "soy_food"
+
+/obj/item/trash/carbonnanotube_noodles
+ name = "carbon nanotube noodles"
+ icon_state = "carbonnanotube_noodles"
+
+/obj/item/trash/attack(mob/M, mob/living/user)
+ return
diff --git a/code/game/objects/structures/divine.dm b/code/game/objects/structures/divine.dm
index 5fd480f6..91836b83 100644
--- a/code/game/objects/structures/divine.dm
+++ b/code/game/objects/structures/divine.dm
@@ -39,7 +39,7 @@
return
last_process = world.time
to_chat(user, "The water feels warm and soothing as you touch it. The fountain immediately dries up shortly afterwards.")
- user.reagents.add_reagent("godblood",20)
+ user.reagents.add_reagent(/datum/reagent/medicine/omnizine/godblood,20)
update_icons()
addtimer(CALLBACK(src, .proc/update_icons), time_between_uses)
@@ -48,4 +48,4 @@
if(last_process + time_between_uses > world.time)
icon_state = "fountain"
else
- icon_state = "fountain-red"
\ No newline at end of file
+ icon_state = "fountain-red"
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index 92d9e550..cc201ae9 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -101,7 +101,7 @@
if (!open)
return
var/obj/item/reagent_containers/RG = I
- RG.reagents.add_reagent("water", min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
+ RG.reagents.add_reagent(/datum/reagent/water, min(RG.volume - RG.reagents.total_volume, RG.amount_per_transfer_from_this))
to_chat(user, "You fill [RG] from [src]. Gross.")
else
return ..()
@@ -199,8 +199,7 @@
icon = 'icons/obj/items_and_weapons.dmi'
icon_state = "urinalcake"
w_class = WEIGHT_CLASS_TINY
- list_reagents = list(chlorine = 3, ammonia = 1)
- foodtype = TOXIC | GROSS
+ list_reagents = list(/datum/reagent/chlorine = 3, /datum/reagent/ammonia = 1)
/obj/item/reagent_containers/food/snacks/urinalcake/attack_self(mob/living/user)
user.visible_message("[user] squishes [src]!", "You squish [src].", "You hear a squish.")
@@ -462,7 +461,7 @@
desc = "A sink used for washing one's hands and face."
anchored = TRUE
var/busy = FALSE //Something's being washed at the moment
- var/dispensedreagent = "water" // for whenever plumbing happens
+ var/dispensedreagent = /datum/reagent/water // for whenever plumbing happens
/obj/structure/sink/attack_hand(mob/living/user)
@@ -537,7 +536,7 @@
return
if(istype(O, /obj/item/mop))
- O.reagents.add_reagent("[dispensedreagent]", 5)
+ O.reagents.add_reagent(dispensedreagent, 5)
to_chat(user, "You wet [O] in [src].")
playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
return
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 180ef378..5652e067 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -557,12 +557,10 @@
clear_reagents_to_vomit_pool(C,V)
/proc/clear_reagents_to_vomit_pool(mob/living/carbon/M, obj/effect/decal/cleanable/vomit/V)
+ for(var/datum/reagent/consumable/R in M.reagents.reagent_list) //clears the stomach of anything that might be digested as food
+ if(R.nutriment_factor > 0)
+ M.reagents.del_reagent(R.type)
M.reagents.trans_to(V, M.reagents.total_volume / 10)
- for(var/datum/reagent/R in M.reagents.reagent_list) //clears the stomach of anything that might be digested as food
- if(istype(R, /datum/reagent/consumable))
- var/datum/reagent/consumable/nutri_check = R
- if(nutri_check.nutriment_factor >0)
- M.reagents.remove_reagent(R.id,R.volume)
//Whatever happens after high temperature fire dies out or thermite reaction works.
//Should return new turf
diff --git a/code/modules/antagonists/abductor/equipment/abduction_gear.dm b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
index 2f5ef65e..75cf91f7 100644
--- a/code/modules/antagonists/abductor/equipment/abduction_gear.dm
+++ b/code/modules/antagonists/abductor/equipment/abduction_gear.dm
@@ -757,7 +757,7 @@ Congratulations! You are now trained for invasive xenobiology research!"}
can_buckle = 1
buckle_lying = 1
- var/static/list/injected_reagents = list("corazone")
+ var/static/list/injected_reagents = list(/datum/reagent/medicine/corazone)
/obj/structure/table/optable/abductor/Crossed(atom/movable/AM)
. = ..()
diff --git a/code/modules/antagonists/abductor/equipment/gland.dm b/code/modules/antagonists/abductor/equipment/gland.dm
index 35a1135b..c2b4f548 100644
--- a/code/modules/antagonists/abductor/equipment/gland.dm
+++ b/code/modules/antagonists/abductor/equipment/gland.dm
@@ -297,21 +297,14 @@
var/list/possible_reagents = list()
/obj/item/organ/heart/gland/chem/Initialize()
- ..()
- for(var/X in subtypesof(/datum/reagent/drug))
- var/datum/reagent/R = X
- possible_reagents += initial(R.id)
- for(var/X in subtypesof(/datum/reagent/medicine))
- var/datum/reagent/R = X
- possible_reagents += initial(R.id)
- for(var/X in typesof(/datum/reagent/toxin))
- var/datum/reagent/R = X
- possible_reagents += initial(R.id)
+ . = ..()
+ for(var/R in subtypesof(/datum/reagent/drug) + subtypesof(/datum/reagent/medicine) + typesof(/datum/reagent/toxin))
+ possible_reagents += R
/obj/item/organ/heart/gland/chem/activate()
var/chem_to_add = pick(possible_reagents)
owner.reagents.add_reagent(chem_to_add, 2)
- owner.adjustToxLoss(-2, TRUE, TRUE)
+ owner.adjustToxLoss(-5, TRUE, TRUE)
..()
/obj/item/organ/heart/gland/plasma
diff --git a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm
index 3cb90d64..182fcea0 100644
--- a/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm
+++ b/code/modules/antagonists/blob/blob/blobs/blob_mobs.dm
@@ -143,9 +143,9 @@
create_reagents(10)
if(overmind && overmind.blob_reagent_datum)
- reagents.add_reagent(overmind.blob_reagent_datum.id, 10)
+ reagents.add_reagent(overmind.blob_reagent_datum.type, 10)
else
- reagents.add_reagent("spore", 10)
+ reagents.add_reagent(/datum/reagent/toxin/spore, 10)
// Attach the smoke spreader and setup/start it.
S.attach(location)
diff --git a/code/modules/antagonists/changeling/powers/adrenaline.dm b/code/modules/antagonists/changeling/powers/adrenaline.dm
index 256d3e89..ba403888 100644
--- a/code/modules/antagonists/changeling/powers/adrenaline.dm
+++ b/code/modules/antagonists/changeling/powers/adrenaline.dm
@@ -13,5 +13,5 @@
//Recover from stuns.
/obj/effect/proc_holder/changeling/adrenaline/sting_action(mob/living/user)
- user.do_adrenaline(0, FALSE, 70, 0, TRUE, list("epinephrine" = 3, "changelingmeth" = 10, "mannitol" = 10, "regen_jelly" = 10, "changelingadrenaline" = 5), "Energy rushes through us.", 0, 0.75, 0)
+ user.do_adrenaline(0, FALSE, 70, 0, TRUE, list(/datum/reagent/medicine/epinephrine = 3, /datum/reagent/drug/methamphetamine/changeling = 10, /datum/reagent/medicine/mannitol = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/changelingadrenaline = 5), "Energy rushes through us.", 0, 0.75, 0)
return TRUE
\ No newline at end of file
diff --git a/code/modules/antagonists/changeling/powers/linglink.dm b/code/modules/antagonists/changeling/powers/linglink.dm
index 971c8110..332f5435 100644
--- a/code/modules/antagonists/changeling/powers/linglink.dm
+++ b/code/modules/antagonists/changeling/powers/linglink.dm
@@ -58,7 +58,7 @@
target.mind.linglink = 1
target.say("[MODE_TOKEN_CHANGELING] AAAAARRRRGGGGGHHHHH!!")
to_chat(target, "You can now communicate in the changeling hivemind, say \"[MODE_TOKEN_CHANGELING] message\" to communicate!")
- target.reagents.add_reagent("salbutamol", 40) // So they don't choke to death while you interrogate them
+ target.reagents.add_reagent(/datum/reagent/medicine/salbutamol, 40) // So they don't choke to death while you interrogate them
sleep(1800)
SSblackbox.record_feedback("nested tally", "changeling_powers", 1, list("[name]", "[i]"))
if(!do_mob(user, target, 20))
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index c428c56d..b91c3146 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -500,7 +500,7 @@
/obj/item/clothing/suit/space/changeling/process()
if(ishuman(loc))
var/mob/living/carbon/human/H = loc
- H.reagents.add_reagent("salbutamol", REAGENTS_METABOLISM)
+ H.reagents.add_reagent(/datum/reagent/medicine/salbutamol, REAGENTS_METABOLISM)
/obj/item/clothing/head/helmet/space/changeling
name = "flesh mass"
diff --git a/code/modules/antagonists/changeling/powers/panacea.dm b/code/modules/antagonists/changeling/powers/panacea.dm
index 8d571d21..2a0451bc 100644
--- a/code/modules/antagonists/changeling/powers/panacea.dm
+++ b/code/modules/antagonists/changeling/powers/panacea.dm
@@ -28,10 +28,10 @@
C.vomit(0, toxic = TRUE)
O.forceMove(get_turf(user))
- user.reagents.add_reagent("mutadone", 10)
- user.reagents.add_reagent("pen_jelly", 20)
- user.reagents.add_reagent("antihol", 10)
- user.reagents.add_reagent("mannitol", 25)
+ user.reagents.add_reagent(/datum/reagent/medicine/mutadone, 10)
+ user.reagents.add_reagent(/datum/reagent/medicine/pen_acid/pen_jelly, 20)
+ user.reagents.add_reagent(/datum/reagent/medicine/antihol, 10)
+ user.reagents.add_reagent(/datum/reagent/medicine/mannitol, 25)
if(isliving(user))
var/mob/living/L = user
diff --git a/code/modules/antagonists/changeling/powers/tiny_prick.dm b/code/modules/antagonists/changeling/powers/tiny_prick.dm
index 04e9b8ef..dc7887ee 100644
--- a/code/modules/antagonists/changeling/powers/tiny_prick.dm
+++ b/code/modules/antagonists/changeling/powers/tiny_prick.dm
@@ -1,266 +1,266 @@
-/obj/effect/proc_holder/changeling/sting
- name = "Tiny Prick"
- desc = "Stabby stabby."
- var/sting_icon = null
-
-/obj/effect/proc_holder/changeling/sting/Click()
- var/mob/user = usr
- if(!user || !user.mind)
- return
- var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
- if(!changeling)
- return
- if(!changeling.chosen_sting)
- set_sting(user)
- else
- unset_sting(user)
- return
-
-/obj/effect/proc_holder/changeling/sting/proc/set_sting(mob/user)
- to_chat(user, "We prepare our sting, use alt+click or middle mouse button on target to sting them.")
- var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
- changeling.chosen_sting = src
-
- user.hud_used.lingstingdisplay.icon_state = sting_icon
- user.hud_used.lingstingdisplay.invisibility = 0
-
-/obj/effect/proc_holder/changeling/sting/proc/unset_sting(mob/user)
- to_chat(user, "We retract our sting, we can't sting anyone for now.")
- var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
- changeling.chosen_sting = null
-
- user.hud_used.lingstingdisplay.icon_state = null
- user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
-
-/mob/living/carbon/proc/unset_sting()
- if(mind)
- var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling && changeling.chosen_sting)
- changeling.chosen_sting.unset_sting(src)
-
-/obj/effect/proc_holder/changeling/sting/can_sting(mob/user, mob/target)
- if(!..())
- return
- var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
- if(!changeling.chosen_sting)
- to_chat(user, "We haven't prepared our sting yet!")
- if(!iscarbon(target))
- return
- if(!isturf(user.loc))
- return
- if(!AStar(user, target.loc, /turf/proc/Distance, changeling.sting_range, simulated_only = 0))
- return
- return 1
-
-/obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target)
- if(!target)
- return
- to_chat(user, "We stealthily sting [target.name].")
- if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
- to_chat(target, "You feel a tiny prick.")
- return 1
-
-
-/obj/effect/proc_holder/changeling/sting/transformation
- name = "Temporary Transformation Sting"
- desc = "We silently sting a human, injecting a chemical that forces them to transform into a chosen being for a limited time. Additional stings extend the duration."
- helptext = "The victim will transform much like a changeling would for a limited time. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is loud, and might cause our blood to react violently to heat."
- sting_icon = "sting_transform"
- chemical_cost = 10
- dna_cost = 2
- loudness = 1
- var/datum/changelingprofile/selected_dna = null
- action_icon = 'icons/mob/actions/actions_changeling.dmi'
- action_icon_state = "ling_sting_transform"
- action_background_icon_state = "bg_ling"
-
-/obj/effect/proc_holder/changeling/sting/transformation/Click()
- var/mob/user = usr
- var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling.chosen_sting)
- unset_sting(user)
- return
- selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
- if(!selected_dna)
- return
- if(NOTRANSSTING in selected_dna.dna.species.species_traits)
- to_chat(user, "That DNA is not compatible with changeling retrovirus!")
- return
- ..()
-
-/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
- if(!..())
- return
- if((HAS_TRAIT(target, TRAIT_HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
- to_chat(user, "Our sting appears ineffective against its DNA.")
- return 0
- return 1
-
-/obj/effect/proc_holder/changeling/sting/transformation/sting_action(mob/user, mob/target)
-
- if(ismonkey(target))
- to_chat(user, "Our genes cry out as we sting [target.name]!")
-
- var/mob/living/carbon/C = target
- . = TRUE
- if(istype(C))
- if(C.reagents.has_reagent("changeling_sting_real"))
- C.reagents.add_reagent("changeling_sting_real",120)
- log_combat(user, target, "stung", "transformation sting", ", extending the duration.")
- else
- C.reagents.add_reagent("changeling_sting_real",120,list("desired_dna" = selected_dna.dna))
- log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'")
-
-
-/obj/effect/proc_holder/changeling/sting/false_armblade
- name = "False Armblade Sting"
- desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade."
- helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
- sting_icon = "sting_armblade"
- chemical_cost = 20
- dna_cost = 1
- loudness = 1
- action_icon = 'icons/mob/actions/actions_changeling.dmi'
- action_icon_state = "ling_sting_fake"
- action_background_icon_state = "bg_ling"
-
-/obj/item/melee/arm_blade/false
- desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
- force = 5 //Basically as strong as a punch
- fake = TRUE
-
-/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
- if(!..())
- return
- if(isliving(target))
- var/mob/living/L = target
- if((HAS_TRAIT(L, TRAIT_HUSK)) || !L.has_dna())
- to_chat(user, "Our sting appears ineffective against its DNA.")
- return 0
- return 1
-
-/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
- log_combat(user, target, "stung", object="false armblade sting")
-
- var/obj/item/held = target.get_active_held_item()
- if(held && !target.dropItemToGround(held))
- to_chat(user, "[held] is stuck to [target.p_their()] hand, you cannot grow a false armblade over it!")
- return
-
- if(ismonkey(target))
- to_chat(user, "Our genes cry out as we sting [target.name]!")
-
- var/obj/item/melee/arm_blade/false/blade = new(target,1)
- target.put_in_hands(blade)
- target.visible_message("A grotesque blade forms around [target.name]\'s arm!", "Your arm twists and mutates, transforming into a horrific monstrosity!", "You hear organic matter ripping and tearing!")
- playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
-
- addtimer(CALLBACK(src, .proc/remove_fake, target, blade), 600)
- return TRUE
-
-/obj/effect/proc_holder/changeling/sting/false_armblade/proc/remove_fake(mob/target, obj/item/melee/arm_blade/false/blade)
- playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
- target.visible_message("With a sickening crunch, \
- [target] reforms [target.p_their()] [blade.name] into an arm!",
- "[blade] reforms back to normal.",
- "Your eyes burn horrifically!")
- target.become_nearsighted(EYE_DAMAGE)
- target.blind_eyes(20)
- target.blur_eyes(40)
- return TRUE
-
-/obj/effect/proc_holder/changeling/sting/LSD
- name = "Hallucination Sting"
- desc = "Causes terror in the target and deals a minor amount of toxin damage."
- helptext = "We evolve the ability to sting a target with a powerful toxic hallucinogenic chemical. The target does not notice they have been stung, and the effect begins instantaneously. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
- sting_icon = "sting_lsd"
- chemical_cost = 10
- dna_cost = 1
- loudness = 1
- action_icon = 'icons/mob/actions/actions_changeling.dmi'
- action_icon_state = "ling_sting_lsd"
- action_background_icon_state = "bg_ling"
-
-/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/target)
- log_combat(user, target, "stung", "LSD sting")
- if(target.reagents)
- target.reagents.add_reagent("regenerative_materia", 5)
- target.reagents.add_reagent("mindbreaker", 5)
- return TRUE
-
-/obj/effect/proc_holder/changeling/sting/cryo
- name = "Cryogenic Sting"
- desc = "We silently sting a human with a cocktail of chemicals that freeze them."
- helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
- sting_icon = "sting_cryo"
- chemical_cost = 15
- dna_cost = 2
- loudness = 1
- action_icon = 'icons/mob/actions/actions_changeling.dmi'
- action_icon_state = "ling_sting_cryo"
- action_background_icon_state = "bg_ling"
-
-/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
- log_combat(user, target, "stung", "cryo sting")
- if(target.reagents)
- target.reagents.add_reagent("frostoil", 30)
- return TRUE
+/obj/effect/proc_holder/changeling/sting
+ name = "Tiny Prick"
+ desc = "Stabby stabby."
+ var/sting_icon = null
+
+/obj/effect/proc_holder/changeling/sting/Click()
+ var/mob/user = usr
+ if(!user || !user.mind)
+ return
+ var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
+ if(!changeling)
+ return
+ if(!changeling.chosen_sting)
+ set_sting(user)
+ else
+ unset_sting(user)
+ return
+
+/obj/effect/proc_holder/changeling/sting/proc/set_sting(mob/user)
+ to_chat(user, "We prepare our sting, use alt+click or middle mouse button on target to sting them.")
+ var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
+ changeling.chosen_sting = src
+
+ user.hud_used.lingstingdisplay.icon_state = sting_icon
+ user.hud_used.lingstingdisplay.invisibility = 0
+
+/obj/effect/proc_holder/changeling/sting/proc/unset_sting(mob/user)
+ to_chat(user, "We retract our sting, we can't sting anyone for now.")
+ var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
+ changeling.chosen_sting = null
+
+ user.hud_used.lingstingdisplay.icon_state = null
+ user.hud_used.lingstingdisplay.invisibility = INVISIBILITY_ABSTRACT
+
+/mob/living/carbon/proc/unset_sting()
+ if(mind)
+ var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling && changeling.chosen_sting)
+ changeling.chosen_sting.unset_sting(src)
+
+/obj/effect/proc_holder/changeling/sting/can_sting(mob/user, mob/target)
+ if(!..())
+ return
+ var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
+ if(!changeling.chosen_sting)
+ to_chat(user, "We haven't prepared our sting yet!")
+ if(!iscarbon(target))
+ return
+ if(!isturf(user.loc))
+ return
+ if(!AStar(user, target.loc, /turf/proc/Distance, changeling.sting_range, simulated_only = 0))
+ return
+ return 1
+
+/obj/effect/proc_holder/changeling/sting/sting_feedback(mob/user, mob/target)
+ if(!target)
+ return
+ to_chat(user, "We stealthily sting [target.name].")
+ if(target.mind && target.mind.has_antag_datum(/datum/antagonist/changeling))
+ to_chat(target, "You feel a tiny prick.")
+ return 1
+
+
+/obj/effect/proc_holder/changeling/sting/transformation
+ name = "Temporary Transformation Sting"
+ desc = "We silently sting a human, injecting a chemical that forces them to transform into a chosen being for a limited time. Additional stings extend the duration."
+ helptext = "The victim will transform much like a changeling would for a limited time. Does not provide a warning to others. Mutations will not be transferred, and monkeys will become human. This ability is loud, and might cause our blood to react violently to heat."
+ sting_icon = "sting_transform"
+ chemical_cost = 10
+ dna_cost = 2
+ loudness = 1
+ var/datum/changelingprofile/selected_dna = null
+ action_icon = 'icons/mob/actions/actions_changeling.dmi'
+ action_icon_state = "ling_sting_transform"
+ action_background_icon_state = "bg_ling"
+
+/obj/effect/proc_holder/changeling/sting/transformation/Click()
+ var/mob/user = usr
+ var/datum/antagonist/changeling/changeling = user.mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling.chosen_sting)
+ unset_sting(user)
+ return
+ selected_dna = changeling.select_dna("Select the target DNA: ", "Target DNA")
+ if(!selected_dna)
+ return
+ if(NOTRANSSTING in selected_dna.dna.species.species_traits)
+ to_chat(user, "That DNA is not compatible with changeling retrovirus!")
+ return
+ ..()
+
+/obj/effect/proc_holder/changeling/sting/transformation/can_sting(mob/user, mob/living/carbon/target)
+ if(!..())
+ return
+ if((HAS_TRAIT(target, TRAIT_HUSK)) || !iscarbon(target) || (NOTRANSSTING in target.dna.species.species_traits))
+ to_chat(user, "Our sting appears ineffective against its DNA.")
+ return 0
+ return 1
+
+/obj/effect/proc_holder/changeling/sting/transformation/sting_action(mob/user, mob/target)
+
+ if(ismonkey(target))
+ to_chat(user, "Our genes cry out as we sting [target.name]!")
+
+ var/mob/living/carbon/C = target
+ . = TRUE
+ if(istype(C))
+ if(C.reagents.has_reagent(/datum/reagent/changeling_string))
+ C.reagents.add_reagent(/datum/reagent/changeling_string,120)
+ log_combat(user, target, "stung", "transformation sting", ", extending the duration.")
+ else
+ C.reagents.add_reagent(/datum/reagent/changeling_string,120,list("desired_dna" = selected_dna.dna))
+ log_combat(user, target, "stung", "transformation sting", " new identity is '[selected_dna.dna.real_name]'")
+
+
+/obj/effect/proc_holder/changeling/sting/false_armblade
+ name = "False Armblade Sting"
+ desc = "We silently sting a human, injecting a retrovirus that mutates their arm to temporarily appear as an armblade."
+ helptext = "The victim will form an armblade much like a changeling would, except the armblade is dull and useless. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
+ sting_icon = "sting_armblade"
+ chemical_cost = 20
+ dna_cost = 1
+ loudness = 1
+ action_icon = 'icons/mob/actions/actions_changeling.dmi'
+ action_icon_state = "ling_sting_fake"
+ action_background_icon_state = "bg_ling"
+
+/obj/item/melee/arm_blade/false
+ desc = "A grotesque mass of flesh that used to be your arm. Although it looks dangerous at first, you can tell it's actually quite dull and useless."
+ force = 5 //Basically as strong as a punch
+ fake = TRUE
+
+/obj/effect/proc_holder/changeling/sting/false_armblade/can_sting(mob/user, mob/target)
+ if(!..())
+ return
+ if(isliving(target))
+ var/mob/living/L = target
+ if((HAS_TRAIT(L, TRAIT_HUSK)) || !L.has_dna())
+ to_chat(user, "Our sting appears ineffective against its DNA.")
+ return 0
+ return 1
+
+/obj/effect/proc_holder/changeling/sting/false_armblade/sting_action(mob/user, mob/target)
+ log_combat(user, target, "stung", object="false armblade sting")
+
+ var/obj/item/held = target.get_active_held_item()
+ if(held && !target.dropItemToGround(held))
+ to_chat(user, "[held] is stuck to [target.p_their()] hand, you cannot grow a false armblade over it!")
+ return
+
+ if(ismonkey(target))
+ to_chat(user, "Our genes cry out as we sting [target.name]!")
+
+ var/obj/item/melee/arm_blade/false/blade = new(target,1)
+ target.put_in_hands(blade)
+ target.visible_message("A grotesque blade forms around [target.name]\'s arm!", "Your arm twists and mutates, transforming into a horrific monstrosity!", "You hear organic matter ripping and tearing!")
+ playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
+
+ addtimer(CALLBACK(src, .proc/remove_fake, target, blade), 600)
+ return TRUE
+
+/obj/effect/proc_holder/changeling/sting/false_armblade/proc/remove_fake(mob/target, obj/item/melee/arm_blade/false/blade)
+ playsound(target, 'sound/effects/blobattack.ogg', 30, 1)
+ target.visible_message("With a sickening crunch, \
+ [target] reforms [target.p_their()] [blade.name] into an arm!",
+ "[blade] reforms back to normal.",
+ "Your eyes burn horrifically!")
+ target.become_nearsighted(EYE_DAMAGE)
+ target.blind_eyes(20)
+ target.blur_eyes(40)
+ return TRUE
+
+/obj/effect/proc_holder/changeling/sting/LSD
+ name = "Hallucination Sting"
+ desc = "Causes terror in the target and deals a minor amount of toxin damage."
+ helptext = "We evolve the ability to sting a target with a powerful toxic hallucinogenic chemical. The target does not notice they have been stung, and the effect begins instantaneously. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
+ sting_icon = "sting_lsd"
+ chemical_cost = 10
+ dna_cost = 1
+ loudness = 1
+ action_icon = 'icons/mob/actions/actions_changeling.dmi'
+ action_icon_state = "ling_sting_lsd"
+ action_background_icon_state = "bg_ling"
+
+/obj/effect/proc_holder/changeling/sting/LSD/sting_action(mob/user, mob/target)
+ log_combat(user, target, "stung", "LSD sting")
+ if(target.reagents)
+ target.reagents.add_reagent(/datum/reagent/blob/regenerative_materia, 5)
+ target.reagents.add_reagent(/datum/reagent/toxin/mindbreaker, 5)
+ return TRUE
+
+/obj/effect/proc_holder/changeling/sting/cryo
+ name = "Cryogenic Sting"
+ desc = "We silently sting a human with a cocktail of chemicals that freeze them."
+ helptext = "Does not provide a warning to the victim, though they will likely realize they are suddenly freezing. This ability is somewhat loud, and carries a small risk of our blood gaining violent sensitivity to heat."
+ sting_icon = "sting_cryo"
+ chemical_cost = 15
+ dna_cost = 2
+ loudness = 1
+ action_icon = 'icons/mob/actions/actions_changeling.dmi'
+ action_icon_state = "ling_sting_cryo"
+ action_background_icon_state = "bg_ling"
+
+/obj/effect/proc_holder/changeling/sting/cryo/sting_action(mob/user, mob/target)
+ log_combat(user, target, "stung", "cryo sting")
+ if(target.reagents)
+ target.reagents.add_reagent(/datum/reagent/consumable/frostoil, 30)
+ return TRUE
diff --git a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
index 23caa788..3cb409a4 100644
--- a/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
+++ b/code/modules/antagonists/clockcult/clock_helpers/slab_abilities.dm
@@ -100,7 +100,7 @@
var/burndamage = L.getFireLoss()
var/oxydamage = L.getOxyLoss()
var/totaldamage = brutedamage + burndamage + oxydamage
- if(!totaldamage && (!L.reagents || !L.reagents.has_reagent("holywater")))
+ if(!totaldamage && (!L.reagents || !L.reagents.has_reagent(/datum/reagent/water/holywater)))
to_chat(ranged_ability_user, "\"[L] is unhurt and untainted.\"")
return TRUE
@@ -108,7 +108,7 @@
to_chat(ranged_ability_user, "You bathe [L == ranged_ability_user ? "yourself":"[L]"] in Inath-neq's power!")
var/targetturf = get_turf(L)
- var/has_holy_water = (L.reagents && L.reagents.has_reagent("holywater"))
+ var/has_holy_water = (L.reagents && L.reagents.has_reagent(/datum/reagent/water/holywater))
var/healseverity = max(round(totaldamage*0.05, 1), 1) //shows the general severity of the damage you just healed, 1 glow per 20
for(var/i in 1 to healseverity)
new /obj/effect/temp_visual/heal(targetturf, "#1E8CE1")
@@ -129,7 +129,7 @@
playsound(targetturf, 'sound/magic/staff_healing.ogg', 50, 1)
if(has_holy_water)
- L.reagents.remove_reagent("holywater", 1000)
+ L.reagents.del_reagent(/datum/reagent/water/holywater)
remove_ranged_ability()
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index b638372d..47e7d201 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -502,7 +502,7 @@
icon = 'icons/obj/drinks.dmi'
icon_state = "holyflask"
color = "#333333"
- list_reagents = list("unholywater" = 50)
+ list_reagents = list(/datum/reagent/fuel/unholywater = 50)
/obj/item/shuttle_curse
name = "cursed orb"
@@ -809,7 +809,7 @@
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(H.stat != DEAD)
- H.reagents.add_reagent("unholywater", 4)
+ H.reagents.add_reagent(/datum/reagent/fuel/unholywater, 4)
if(isshade(target) || isconstruct(target))
var/mob/living/simple_animal/M = target
if(M.health+5 < M.maxHealth)
@@ -910,7 +910,7 @@
if(ishuman(target))
var/mob/living/carbon/human/H = target
if(H.stat != DEAD)
- H.reagents.add_reagent("unholywater", 7)
+ H.reagents.add_reagent(/datum/reagent/fuel/unholywater, 7)
if(isshade(target) || isconstruct(target))
var/mob/living/simple_animal/M = target
if(M.health+15 < M.maxHealth)
diff --git a/code/modules/antagonists/cult/ritual.dm b/code/modules/antagonists/cult/ritual.dm
index 805b6f82..7ca0071c 100644
--- a/code/modules/antagonists/cult/ritual.dm
+++ b/code/modules/antagonists/cult/ritual.dm
@@ -24,11 +24,11 @@ This file contains the cult dagger and rune list code
/obj/item/melee/cultblade/dagger/attack(mob/living/M, mob/living/user)
if(iscultist(M))
- if(M.reagents && M.reagents.has_reagent("holywater")) //allows cultists to be rescued from the clutches of ordained religion
+ if(M.reagents && M.reagents.has_reagent(/datum/reagent/water/holywater)) //allows cultists to be rescued from the clutches of ordained religion
to_chat(user, "You remove the taint from [M]." )
- var/holy2unholy = M.reagents.get_reagent_amount("holywater")
- M.reagents.del_reagent("holywater")
- M.reagents.add_reagent("unholywater",holy2unholy)
+ var/holy2unholy = M.reagents.get_reagent_amount(/datum/reagent/water/holywater)
+ M.reagents.del_reagent(/datum/reagent/water/holywater)
+ M.reagents.add_reagent(/datum/reagent/fuel/unholywater,holy2unholy)
log_combat(user, M, "smacked", src, " removing the holy water from them")
return FALSE
. = ..()
diff --git a/code/modules/antagonists/devil/devil.dm b/code/modules/antagonists/devil/devil.dm
index dc649025..08db3208 100644
--- a/code/modules/antagonists/devil/devil.dm
+++ b/code/modules/antagonists/devil/devil.dm
@@ -384,14 +384,14 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
if(BANISH_WATER)
if(iscarbon(body))
var/mob/living/carbon/H = body
- return H.reagents.has_reagent("holy water")
+ return H.reagents.has_reagent(/datum/reagent/water/holywater)
return 0
if(BANISH_COFFIN)
return (body && istype(body.loc, /obj/structure/closet/crate/coffin))
if(BANISH_FORMALDYHIDE)
if(iscarbon(body))
var/mob/living/carbon/H = body
- return H.reagents.has_reagent("formaldehyde")
+ return H.reagents.has_reagent(/datum/reagent/toxin/formaldehyde)
return 0
if(BANISH_RUNES)
if(body)
diff --git a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
index 69b4f7e9..2c50b419 100644
--- a/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
+++ b/code/modules/antagonists/nukeop/equipment/nuclearbomb.dm
@@ -513,7 +513,7 @@
/obj/machinery/nuclearbomb/beer/proc/fizzbuzz()
var/datum/reagents/R = new/datum/reagents(1000)
R.my_atom = src
- R.add_reagent("beer", 100)
+ R.add_reagent(/datum/reagent/consumable/ethanol/beer, 100)
var/datum/effect_system/foam_spread/foam = new
foam.set_up(200, get_turf(src), R)
diff --git a/code/modules/antagonists/revenant/revenant_abilities.dm b/code/modules/antagonists/revenant/revenant_abilities.dm
index dba4c23c..481d200f 100644
--- a/code/modules/antagonists/revenant/revenant_abilities.dm
+++ b/code/modules/antagonists/revenant/revenant_abilities.dm
@@ -351,7 +351,7 @@
to_chat(H, "You feel [pick("suddenly sick", "a surge of nausea", "like your skin is wrong")].")
else
if(mob.reagents)
- mob.reagents.add_reagent("plasma", 5)
+ mob.reagents.add_reagent(/datum/reagent/toxin/plasma, 5)
else
mob.adjustToxLoss(5)
for(var/obj/structure/spacevine/vine in T) //Fucking with botanists, the ability.
diff --git a/code/modules/awaymissions/mission_code/snowdin.dm b/code/modules/awaymissions/mission_code/snowdin.dm
index 7cb77173..24f83ba9 100644
--- a/code/modules/awaymissions/mission_code/snowdin.dm
+++ b/code/modules/awaymissions/mission_code/snowdin.dm
@@ -175,7 +175,7 @@
if(C.reagents.total_volume >= C.volume)
to_chat(user, "[C] is full.")
return
- C.reagents.add_reagent("plasma", rand(5, 10))
+ C.reagents.add_reagent(/datum/reagent/toxin/plasma, rand(5, 10))
user.visible_message("[user] scoops some plasma from the [src] with \the [C].", "You scoop out some plasma from the [src] using \the [C].")
/turf/open/lava/plasma/burn_stuff(AM)
diff --git a/code/modules/cargo/bounties/reagent.dm b/code/modules/cargo/bounties/reagent.dm
index ee122a11..35bd95c1 100644
--- a/code/modules/cargo/bounties/reagent.dm
+++ b/code/modules/cargo/bounties/reagent.dm
@@ -12,7 +12,7 @@
/datum/bounty/reagent/applies_to(obj/O)
if(!istype(O, /obj/item/reagent_containers))
return FALSE
- if(!O.reagents || !O.reagents.has_reagent(wanted_reagent.id))
+ if(!O.reagents || !O.reagents.has_reagent(wanted_reagent.type))
return FALSE
if(O.flags_1 & HOLOGRAM_1)
return FALSE
@@ -21,7 +21,7 @@
/datum/bounty/reagent/ship(obj/O)
if(!applies_to(O))
return
- shipped_volume += O.reagents.get_reagent_amount(wanted_reagent.id)
+ shipped_volume += O.reagents.get_reagent_amount(wanted_reagent.type)
if(shipped_volume > required_volume)
shipped_volume = required_volume
@@ -29,7 +29,7 @@
if(!istype(other_bounty, /datum/bounty/reagent))
return TRUE
var/datum/bounty/reagent/R = other_bounty
- return wanted_reagent.id != R.wanted_reagent.id
+ return wanted_reagent.type != R.wanted_reagent.type
/datum/bounty/reagent/simple_drink
name = "Simple Drink"
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 7a3de0b6..0e0d3e5e 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -144,7 +144,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"balls_cum_rate" = CUM_RATE,
"balls_cum_mult" = CUM_RATE_MULT,
"balls_efficiency" = CUM_EFFICIENCY,
- "balls_fluid" = "semen",
+ "balls_fluid" = /datum/reagent/consumable/semen,
"has_ovi" = FALSE,
"ovi_shape" = "knotted",
"ovi_length" = 6,
@@ -159,7 +159,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"breasts_color" = "fff",
"breasts_size" = "C",
"breasts_shape" = "Pair",
- "breasts_fluid" = "milk",
+ "breasts_fluid" = /datum/reagent/consumable/milk,
"breasts_producing" = FALSE,
"has_vag" = FALSE,
"vag_shape" = "Human",
@@ -171,7 +171,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
"womb_cum_rate" = CUM_RATE,
"womb_cum_mult" = CUM_RATE_MULT,
"womb_efficiency" = CUM_EFFICIENCY,
- "womb_fluid" = "femcum",
+ "womb_fluid" = /datum/reagent/consumable/femcum,
"ipc_screen" = "Sunburst",
"ipc_antenna" = "None",
"flavor_text" = ""
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 4b3b222d..1de8ccf0 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -5,7 +5,7 @@
// You do not need to raise this if you are adding new values that have sane defaults.
// Only raise this value when changing the meaning/format/name/layout of an existing value
// where you would want the updater procs below to run
-#define SAVEFILE_VERSION_MAX 21
+#define SAVEFILE_VERSION_MAX 22
/*
SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Carn
@@ -51,6 +51,11 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
pda_style = "mono"
if(current_version < 20)
pda_color = "#808000"
+ if(current_version < 22)
+ if(features["balls_fluid"])
+ features["balls_fluid"] = /datum/reagent/consumable/semen
+ if(features["breasts_fluid"])
+ features["breasts_fluid"] = /datum/reagent/consumable/milk
/datum/preferences/proc/load_path(ckey,filename="preferences.sav")
if(!ckey)
diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm
index 9829d3b3..a28b15f8 100644
--- a/code/modules/clothing/clothing.dm
+++ b/code/modules/clothing/clothing.dm
@@ -1,407 +1,407 @@
-/obj/item/clothing
- name = "clothing"
- resistance_flags = FLAMMABLE
- max_integrity = 200
- integrity_failure = 80
- var/damaged_clothes = 0 //similar to machine's BROKEN stat and structure's broken var
- var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
- var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect
- var/up = 0 //but separated to allow items to protect but not impair vision, like space helmets
- var/visor_flags = 0 //flags that are added/removed when an item is adjusted up/down
- var/visor_flags_inv = 0 //same as visor_flags, but for flags_inv
- var/visor_flags_cover = 0 //same as above, but for flags_cover
-//what to toggle when toggled with weldingvisortoggle()
- var/visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT | VISOR_VISIONFLAGS | VISOR_DARKNESSVIEW | VISOR_INVISVIEW
- lefthand_file = 'icons/mob/inhands/clothing_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/clothing_righthand.dmi'
- var/alt_desc = null
- var/toggle_message = null
- var/alt_toggle_message = null
- var/active_sound = null
- var/toggle_cooldown = null
- var/cooldown = 0
- var/obj/item/flashlight/F = null
- var/can_flashlight = 0
-
- var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down.
-
- var/clothing_flags = NONE
-
- //Var modification - PLEASE be careful with this I know who you are and where you live
- var/list/user_vars_to_edit //VARNAME = VARVALUE eg: "name" = "butts"
- var/list/user_vars_remembered //Auto built by the above + dropped() + equipped()
-
- var/pocket_storage_component_path
-
- //These allow head/mask items to dynamically alter the user's hair
- // and facial hair, checking hair_extensions.dmi and facialhair_extensions.dmi
- // for a state matching hair_state+dynamic_hair_suffix
- // THESE OVERRIDE THE HIDEHAIR FLAGS
- var/dynamic_hair_suffix = ""//head > mask for head hair
- var/dynamic_fhair_suffix = ""//mask > head for facial hair
-
-
- //basically a restriction list.
- var/list/species_restricted = null
- //Basically syntax is species_restricted = list("Species Name","Species Name")
- //Add a "exclude" string to do the opposite, making it only only species listed that can't wear it.
- //You append this to clothing objects.
- //Hyper change// - Variables for HS13 checks
- var/roomy = 0 //0 For false
-
-
-/obj/item/clothing/Initialize()
- . = ..()
- if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE))
- actions_types += /datum/action/item_action/toggle_voice_box
- if(ispath(pocket_storage_component_path))
- LoadComponent(pocket_storage_component_path)
-
-/obj/item/clothing/MouseDrop(atom/over_object)
- . = ..()
- var/mob/M = usr
-
- if(ismecha(M.loc)) // stops inventory actions in a mech
- return
-
- if(!M.incapacitated() && loc == M && istype(over_object, /obj/screen/inventory/hand))
- var/obj/screen/inventory/hand/H = over_object
- if(M.putItemFromInventoryInHandIfPossible(src, H.held_index))
- add_fingerprint(usr)
-
-/obj/item/reagent_containers/food/snacks/clothing
- name = "oops"
- desc = "If you're reading this it means I messed up. This is related to moths eating clothes and I didn't know a better way to do it than making a new food object."
- list_reagents = list("nutriment" = 1)
- tastes = list("dust" = 1, "lint" = 1)
- foodtype = CLOTH
-
-/obj/item/clothing/attack(mob/M, mob/user, def_zone)
- if(user.a_intent != INTENT_HARM && (ismoth(M) || isinsect(M)))
- var/obj/item/reagent_containers/food/snacks/clothing/clothing_as_food = new
- clothing_as_food.name = name
- if(clothing_as_food.attack(M, user, def_zone))
- take_damage(15, sound_effect=FALSE)
- qdel(clothing_as_food)
- else
- return ..()
-
-/obj/item/clothing/attackby(obj/item/W, mob/user, params)
- if(damaged_clothes && istype(W, /obj/item/stack/sheet/cloth))
- var/obj/item/stack/sheet/cloth/C = W
- C.use(1)
- update_clothes_damaged_state(FALSE)
- obj_integrity = max_integrity
- to_chat(user, "You fix the damage on [src] with [C].")
- return 1
- //Hyper Change//
- if(istype(W, /obj/item/bluespace_thread))
- var/obj/item/bluespace_thread/B = W
- if ((istype(src, /obj/item/clothing/under) || istype(src, /obj/item/clothing/suit)) && roomy != 1) //Make sure the thread is used on an item that could be ripped off in the first place
- roomy = TRUE //True
- user.show_message("You add a few stiches to your clothing, and find them to fit a little looser.", 1)
- B.uses -= 1 //One use has been used
- if(B.uses <= 0)
- user.show_message("The thread has been used up!", 1)
- qdel(B)
- else
- user.show_message("You probably don't need any more room in that.", 1)
- return ..()
-
-/obj/item/clothing/Destroy()
- user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up
- return ..()
-
-/obj/item/clothing/dropped(mob/user)
- ..()
- if(!istype(user))
- return
- if(LAZYLEN(user_vars_remembered))
- for(var/variable in user_vars_remembered)
- if(variable in user.vars)
- if(user.vars[variable] == user_vars_to_edit[variable]) //Is it still what we set it to? (if not we best not change it)
- user.vars[variable] = user_vars_remembered[variable]
- user_vars_remembered = initial(user_vars_remembered) // Effectively this sets it to null.
-
-/obj/item/clothing/equipped(mob/user, slot)
- ..()
- if (!istype(user))
- return
- if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item?
- if (LAZYLEN(user_vars_to_edit))
- for(var/variable in user_vars_to_edit)
- if(variable in user.vars)
- LAZYSET(user_vars_remembered, variable, user.vars[variable])
- user.vv_edit_var(variable, user_vars_to_edit[variable])
-
-/obj/item/clothing/examine(mob/user)
- . = ..()
- if(damaged_clothes)
- . += "It looks damaged!"
- var/datum/component/storage/pockets = GetComponent(/datum/component/storage)
- if(pockets)
- var/list/how_cool_are_your_threads = list("")
- if(pockets.attack_hand_interact)
- how_cool_are_your_threads += "[src]'s storage opens when clicked.\n"
- else
- how_cool_are_your_threads += "[src]'s storage opens when dragged to yourself.\n"
- how_cool_are_your_threads += "[src] can store [pockets.max_items] item\s.\n"
- how_cool_are_your_threads += "[src] can store items that are [weightclass2text(pockets.max_w_class)] or smaller.\n"
- if(pockets.quickdraw)
- how_cool_are_your_threads += "You can quickly remove an item from [src] using Alt-Click.\n"
- if(pockets.silent)
- how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n"
- how_cool_are_your_threads += ""
- . += how_cool_are_your_threads.Join()
-
-/obj/item/clothing/obj_break(damage_flag)
- if(!damaged_clothes)
- update_clothes_damaged_state(TRUE)
- if(ismob(loc)) //It's not important enough to warrant a message if nobody's wearing it
- var/mob/M = loc
- to_chat(M, "Your [name] starts to fall apart!")
-
-/obj/item/clothing/proc/update_clothes_damaged_state(damaging = TRUE)
- var/index = "[REF(initial(icon))]-[initial(icon_state)]"
- var/static/list/damaged_clothes_icons = list()
- if(damaging)
- damaged_clothes = 1
- var/icon/damaged_clothes_icon = damaged_clothes_icons[index]
- if(!damaged_clothes_icon)
- damaged_clothes_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply damaged effect to the initial icon_state for each object
- damaged_clothes_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
- damaged_clothes_icon.Blend(icon('icons/effects/item_damage.dmi', "itemdamaged"), ICON_MULTIPLY) //adds damage effect and the remaining white areas become transparant
- damaged_clothes_icon = fcopy_rsc(damaged_clothes_icon)
- damaged_clothes_icons[index] = damaged_clothes_icon
- add_overlay(damaged_clothes_icon, 1)
- else
- damaged_clothes = 0
- cut_overlay(damaged_clothes_icons[index], TRUE)
-
-
-/*
-SEE_SELF // can see self, no matter what
-SEE_MOBS // can see all mobs, no matter what
-SEE_OBJS // can see all objs, no matter what
-SEE_TURFS // can see all turfs (and areas), no matter what
-SEE_PIXELS// if an object is located on an unlit area, but some of its pixels are
- // in a lit area (via pixel_x,y or smooth movement), can see those pixels
-BLIND // can't see anything
-*/
-
-/proc/generate_female_clothing(index,t_color,icon,type)
- var/icon/female_clothing_icon = icon("icon"=icon, "icon_state"=t_color)
- var/icon/female_s = icon("icon"='icons/mob/uniform.dmi', "icon_state"="[(type == FEMALE_UNIFORM_FULL) ? "female_full" : "female_top"]")
- female_clothing_icon.Blend(female_s, ICON_MULTIPLY)
- female_clothing_icon = fcopy_rsc(female_clothing_icon)
- GLOB.female_clothing_icons[index] = female_clothing_icon
-
-/obj/item/clothing/under/verb/toggle()
- set name = "Adjust Suit Sensors"
- set category = "Object"
- set src in usr
- var/mob/M = usr
- if (istype(M, /mob/dead/))
- return
- if (!can_use(M))
- return
- if(src.has_sensor == LOCKED_SENSORS)
- to_chat(usr, "The controls are locked.")
- return 0
- if(src.has_sensor == BROKEN_SENSORS)
- to_chat(usr, "The sensors have shorted out!")
- return 0
- if(src.has_sensor <= NO_SENSORS)
- to_chat(usr, "This suit does not have any sensors.")
- return 0
-
- var/list/modes = list("Off", "Binary vitals", "Exact vitals", "Tracking beacon")
- var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes
- if(get_dist(usr, src) > 1)
- to_chat(usr, "You have moved too far away!")
- return
- sensor_mode = modes.Find(switchMode) - 1
-
- if (src.loc == usr)
- switch(sensor_mode)
- if(0)
- to_chat(usr, "You disable your suit's remote sensing equipment.")
- if(1)
- to_chat(usr, "Your suit will now only report whether you are alive or dead.")
- if(2)
- to_chat(usr, "Your suit will now only report your exact vital lifesigns.")
- if(3)
- to_chat(usr, "Your suit will now report your exact vital lifesigns as well as your coordinate position.")
-
- if(ishuman(loc))
- var/mob/living/carbon/human/H = loc
- if(H.w_uniform == src)
- H.update_suit_sensors()
-
- ..()
-
-/obj/item/clothing/under/CtrlClick(mob/user)
- . = ..()
-
- if (!(item_flags & IN_INVENTORY))
- return
-
- if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
- return
-
- if(has_sensor == LOCKED_SENSORS)
- to_chat(user, "The controls are locked.")
- return
- if(has_sensor == BROKEN_SENSORS)
- to_chat(user, "The sensors have shorted out!")
- return
- if(has_sensor <= NO_SENSORS)
- to_chat(user, "This suit does not have any sensors.")
- return
-
- sensor_mode = SENSOR_COORDS
-
- to_chat(user, "Your suit will now report your exact vital lifesigns as well as your coordinate position.")
-
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- if(H.w_uniform == src)
- H.update_suit_sensors()
-
-/obj/item/clothing/under/AltClick(mob/user)
- if(..())
- return 1
-
- if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
- return
- else
- if(attached_accessory)
- remove_accessory(user)
- else
- rolldown()
-
-/obj/item/clothing/under/verb/jumpsuit_adjust()
- set name = "Adjust Jumpsuit Style"
- set category = null
- set src in usr
- rolldown()
-
-/obj/item/clothing/under/proc/rolldown()
- if(!can_use(usr))
- return
- if(!can_adjust)
- to_chat(usr, "You cannot wear this suit any differently!")
- return
- if(toggle_jumpsuit_adjust())
- to_chat(usr, "You adjust the suit to wear it more casually.")
- else
- to_chat(usr, "You adjust the suit back to normal.")
- if(ishuman(usr))
- var/mob/living/carbon/human/H = usr
- H.update_inv_w_uniform()
- H.update_body()
-
-/obj/item/clothing/under/proc/toggle_jumpsuit_adjust()
- adjusted = !adjusted
-
- if(adjusted)
- if(fitted != FEMALE_UNIFORM_TOP)
- fitted = NO_FEMALE_UNIFORM
- if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted
- body_parts_covered &= ~CHEST
- else
- fitted = initial(fitted)
- if(!alt_covers_chest)
- body_parts_covered |= CHEST
-
- return adjusted
-
-/obj/item/clothing/proc/weldingvisortoggle(mob/user) //proc to toggle welding visors on helmets, masks, goggles, etc.
- if(!can_use(user))
- return FALSE
-
- visor_toggling()
-
- to_chat(user, "You adjust \the [src] [up ? "up" : "down"].")
-
- if(iscarbon(user))
- var/mob/living/carbon/C = user
- C.head_update(src, forced = 1)
- for(var/X in actions)
- var/datum/action/A = X
- A.UpdateButtonIcon()
- return TRUE
-
-/obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags
- up = !up
- clothing_flags ^= visor_flags
- flags_inv ^= visor_flags_inv
- flags_cover ^= initial(flags_cover)
- icon_state = "[initial(icon_state)][up ? "up" : ""]"
- if(visor_vars_to_toggle & VISOR_FLASHPROTECT)
- flash_protect ^= initial(flash_protect)
- if(visor_vars_to_toggle & VISOR_TINT)
- tint ^= initial(tint)
-
-/obj/item/clothing/head/helmet/space/plasmaman/visor_toggling() //handles all the actual toggling of flags
- up = !up
- clothing_flags ^= visor_flags
- flags_inv ^= visor_flags_inv
- icon_state = "[initial(icon_state)]"
- if(visor_vars_to_toggle & VISOR_FLASHPROTECT)
- flash_protect ^= initial(flash_protect)
- if(visor_vars_to_toggle & VISOR_TINT)
- tint ^= initial(tint)
-
-/obj/item/clothing/proc/can_use(mob/user)
- if(user && ismob(user))
- if(!user.incapacitated())
- return 1
- return 0
-
-
-/obj/item/clothing/obj_destruction(damage_flag)
- if(damage_flag == "bomb" || damage_flag == "melee")
- var/turf/T = get_turf(src)
- spawn(1) //so the shred survives potential turf change from the explosion.
- var/obj/effect/decal/cleanable/shreds/Shreds = new(T)
- Shreds.desc = "The sad remains of what used to be [name]."
- deconstruct(FALSE)
- else
- ..()
-
-
-
-//Species-restricted clothing check. - Thanks Oraclestation, BS13, /vg/station etc.
-/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = TRUE)
-
- //if we can't equip the item anyway, don't bother with species_restricted (also cuts down on spam)
- if(!..())
- return FALSE
-
- // Skip species restriction checks on non-equipment slots
- if(slot in list(SLOT_IN_BACKPACK, SLOT_L_STORE, SLOT_R_STORE))
- return TRUE
-
- if(species_restricted && ishuman(M))
-
- var/wearable = null
- var/exclusive = null
- var/mob/living/carbon/human/H = M
-
- if("exclude" in species_restricted) //TURNS IT INTO A BLACKLIST - AKA ALL MINUS SPECIES LISTED.
- exclusive = TRUE
-
- if(H.dna.species)
- if(exclusive)
- if(!(H.dna.species.name in species_restricted))
- wearable = TRUE
- else
- if(H.dna.species.name in species_restricted)
- wearable = TRUE
-
- if(!wearable)
- to_chat(M, "Your species cannot wear [src].")
- return FALSE
-
- return TRUE
+/obj/item/clothing
+ name = "clothing"
+ resistance_flags = FLAMMABLE
+ max_integrity = 200
+ integrity_failure = 80
+ var/damaged_clothes = 0 //similar to machine's BROKEN stat and structure's broken var
+ var/flash_protect = 0 //What level of bright light protection item has. 1 = Flashers, Flashes, & Flashbangs | 2 = Welding | -1 = OH GOD WELDING BURNT OUT MY RETINAS
+ var/tint = 0 //Sets the item's level of visual impairment tint, normally set to the same as flash_protect
+ var/up = 0 //but separated to allow items to protect but not impair vision, like space helmets
+ var/visor_flags = 0 //flags that are added/removed when an item is adjusted up/down
+ var/visor_flags_inv = 0 //same as visor_flags, but for flags_inv
+ var/visor_flags_cover = 0 //same as above, but for flags_cover
+//what to toggle when toggled with weldingvisortoggle()
+ var/visor_vars_to_toggle = VISOR_FLASHPROTECT | VISOR_TINT | VISOR_VISIONFLAGS | VISOR_DARKNESSVIEW | VISOR_INVISVIEW
+ lefthand_file = 'icons/mob/inhands/clothing_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/clothing_righthand.dmi'
+ var/alt_desc = null
+ var/toggle_message = null
+ var/alt_toggle_message = null
+ var/active_sound = null
+ var/toggle_cooldown = null
+ var/cooldown = 0
+ var/obj/item/flashlight/F = null
+ var/can_flashlight = 0
+
+ var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down.
+
+ var/clothing_flags = NONE
+
+ //Var modification - PLEASE be careful with this I know who you are and where you live
+ var/list/user_vars_to_edit //VARNAME = VARVALUE eg: "name" = "butts"
+ var/list/user_vars_remembered //Auto built by the above + dropped() + equipped()
+
+ var/pocket_storage_component_path
+
+ //These allow head/mask items to dynamically alter the user's hair
+ // and facial hair, checking hair_extensions.dmi and facialhair_extensions.dmi
+ // for a state matching hair_state+dynamic_hair_suffix
+ // THESE OVERRIDE THE HIDEHAIR FLAGS
+ var/dynamic_hair_suffix = ""//head > mask for head hair
+ var/dynamic_fhair_suffix = ""//mask > head for facial hair
+
+
+ //basically a restriction list.
+ var/list/species_restricted = null
+ //Basically syntax is species_restricted = list("Species Name","Species Name")
+ //Add a "exclude" string to do the opposite, making it only only species listed that can't wear it.
+ //You append this to clothing objects.
+ //Hyper change// - Variables for HS13 checks
+ var/roomy = 0 //0 For false
+
+
+/obj/item/clothing/Initialize()
+ . = ..()
+ if(CHECK_BITFIELD(clothing_flags, VOICEBOX_TOGGLABLE))
+ actions_types += /datum/action/item_action/toggle_voice_box
+ if(ispath(pocket_storage_component_path))
+ LoadComponent(pocket_storage_component_path)
+
+/obj/item/clothing/MouseDrop(atom/over_object)
+ . = ..()
+ var/mob/M = usr
+
+ if(ismecha(M.loc)) // stops inventory actions in a mech
+ return
+
+ if(!M.incapacitated() && loc == M && istype(over_object, /obj/screen/inventory/hand))
+ var/obj/screen/inventory/hand/H = over_object
+ if(M.putItemFromInventoryInHandIfPossible(src, H.held_index))
+ add_fingerprint(usr)
+
+/obj/item/reagent_containers/food/snacks/clothing
+ name = "oops"
+ desc = "If you're reading this it means I messed up. This is related to moths eating clothes and I didn't know a better way to do it than making a new food object."
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
+ tastes = list("dust" = 1, "lint" = 1)
+ foodtype = CLOTH
+
+/obj/item/clothing/attack(mob/M, mob/user, def_zone)
+ if(user.a_intent != INTENT_HARM && (ismoth(M) || isinsect(M)))
+ var/obj/item/reagent_containers/food/snacks/clothing/clothing_as_food = new
+ clothing_as_food.name = name
+ if(clothing_as_food.attack(M, user, def_zone))
+ take_damage(15, sound_effect=FALSE)
+ qdel(clothing_as_food)
+ else
+ return ..()
+
+/obj/item/clothing/attackby(obj/item/W, mob/user, params)
+ if(damaged_clothes && istype(W, /obj/item/stack/sheet/cloth))
+ var/obj/item/stack/sheet/cloth/C = W
+ C.use(1)
+ update_clothes_damaged_state(FALSE)
+ obj_integrity = max_integrity
+ to_chat(user, "You fix the damage on [src] with [C].")
+ return 1
+ //Hyper Change//
+ if(istype(W, /obj/item/bluespace_thread))
+ var/obj/item/bluespace_thread/B = W
+ if ((istype(src, /obj/item/clothing/under) || istype(src, /obj/item/clothing/suit)) && roomy != 1) //Make sure the thread is used on an item that could be ripped off in the first place
+ roomy = TRUE //True
+ user.show_message("You add a few stiches to your clothing, and find them to fit a little looser.", 1)
+ B.uses -= 1 //One use has been used
+ if(B.uses <= 0)
+ user.show_message("The thread has been used up!", 1)
+ qdel(B)
+ else
+ user.show_message("You probably don't need any more room in that.", 1)
+ return ..()
+
+/obj/item/clothing/Destroy()
+ user_vars_remembered = null //Oh god somebody put REFERENCES in here? not to worry, we'll clean it up
+ return ..()
+
+/obj/item/clothing/dropped(mob/user)
+ ..()
+ if(!istype(user))
+ return
+ if(LAZYLEN(user_vars_remembered))
+ for(var/variable in user_vars_remembered)
+ if(variable in user.vars)
+ if(user.vars[variable] == user_vars_to_edit[variable]) //Is it still what we set it to? (if not we best not change it)
+ user.vars[variable] = user_vars_remembered[variable]
+ user_vars_remembered = initial(user_vars_remembered) // Effectively this sets it to null.
+
+/obj/item/clothing/equipped(mob/user, slot)
+ ..()
+ if (!istype(user))
+ return
+ if(slot_flags & slotdefine2slotbit(slot)) //Was equipped to a valid slot for this item?
+ if (LAZYLEN(user_vars_to_edit))
+ for(var/variable in user_vars_to_edit)
+ if(variable in user.vars)
+ LAZYSET(user_vars_remembered, variable, user.vars[variable])
+ user.vv_edit_var(variable, user_vars_to_edit[variable])
+
+/obj/item/clothing/examine(mob/user)
+ . = ..()
+ if(damaged_clothes)
+ . += "It looks damaged!"
+ var/datum/component/storage/pockets = GetComponent(/datum/component/storage)
+ if(pockets)
+ var/list/how_cool_are_your_threads = list("")
+ if(pockets.attack_hand_interact)
+ how_cool_are_your_threads += "[src]'s storage opens when clicked.\n"
+ else
+ how_cool_are_your_threads += "[src]'s storage opens when dragged to yourself.\n"
+ how_cool_are_your_threads += "[src] can store [pockets.max_items] item\s.\n"
+ how_cool_are_your_threads += "[src] can store items that are [weightclass2text(pockets.max_w_class)] or smaller.\n"
+ if(pockets.quickdraw)
+ how_cool_are_your_threads += "You can quickly remove an item from [src] using Alt-Click.\n"
+ if(pockets.silent)
+ how_cool_are_your_threads += "Adding or removing items from [src] makes no noise.\n"
+ how_cool_are_your_threads += ""
+ . += how_cool_are_your_threads.Join()
+
+/obj/item/clothing/obj_break(damage_flag)
+ if(!damaged_clothes)
+ update_clothes_damaged_state(TRUE)
+ if(ismob(loc)) //It's not important enough to warrant a message if nobody's wearing it
+ var/mob/M = loc
+ to_chat(M, "Your [name] starts to fall apart!")
+
+/obj/item/clothing/proc/update_clothes_damaged_state(damaging = TRUE)
+ var/index = "[REF(initial(icon))]-[initial(icon_state)]"
+ var/static/list/damaged_clothes_icons = list()
+ if(damaging)
+ damaged_clothes = 1
+ var/icon/damaged_clothes_icon = damaged_clothes_icons[index]
+ if(!damaged_clothes_icon)
+ damaged_clothes_icon = icon(initial(icon), initial(icon_state), , 1) //we only want to apply damaged effect to the initial icon_state for each object
+ damaged_clothes_icon.Blend("#fff", ICON_ADD) //fills the icon_state with white (except where it's transparent)
+ damaged_clothes_icon.Blend(icon('icons/effects/item_damage.dmi', "itemdamaged"), ICON_MULTIPLY) //adds damage effect and the remaining white areas become transparant
+ damaged_clothes_icon = fcopy_rsc(damaged_clothes_icon)
+ damaged_clothes_icons[index] = damaged_clothes_icon
+ add_overlay(damaged_clothes_icon, 1)
+ else
+ damaged_clothes = 0
+ cut_overlay(damaged_clothes_icons[index], TRUE)
+
+
+/*
+SEE_SELF // can see self, no matter what
+SEE_MOBS // can see all mobs, no matter what
+SEE_OBJS // can see all objs, no matter what
+SEE_TURFS // can see all turfs (and areas), no matter what
+SEE_PIXELS// if an object is located on an unlit area, but some of its pixels are
+ // in a lit area (via pixel_x,y or smooth movement), can see those pixels
+BLIND // can't see anything
+*/
+
+/proc/generate_female_clothing(index,t_color,icon,type)
+ var/icon/female_clothing_icon = icon("icon"=icon, "icon_state"=t_color)
+ var/icon/female_s = icon("icon"='icons/mob/uniform.dmi', "icon_state"="[(type == FEMALE_UNIFORM_FULL) ? "female_full" : "female_top"]")
+ female_clothing_icon.Blend(female_s, ICON_MULTIPLY)
+ female_clothing_icon = fcopy_rsc(female_clothing_icon)
+ GLOB.female_clothing_icons[index] = female_clothing_icon
+
+/obj/item/clothing/under/verb/toggle()
+ set name = "Adjust Suit Sensors"
+ set category = "Object"
+ set src in usr
+ var/mob/M = usr
+ if (istype(M, /mob/dead/))
+ return
+ if (!can_use(M))
+ return
+ if(src.has_sensor == LOCKED_SENSORS)
+ to_chat(usr, "The controls are locked.")
+ return 0
+ if(src.has_sensor == BROKEN_SENSORS)
+ to_chat(usr, "The sensors have shorted out!")
+ return 0
+ if(src.has_sensor <= NO_SENSORS)
+ to_chat(usr, "This suit does not have any sensors.")
+ return 0
+
+ var/list/modes = list("Off", "Binary vitals", "Exact vitals", "Tracking beacon")
+ var/switchMode = input("Select a sensor mode:", "Suit Sensor Mode", modes[sensor_mode + 1]) in modes
+ if(get_dist(usr, src) > 1)
+ to_chat(usr, "You have moved too far away!")
+ return
+ sensor_mode = modes.Find(switchMode) - 1
+
+ if (src.loc == usr)
+ switch(sensor_mode)
+ if(0)
+ to_chat(usr, "You disable your suit's remote sensing equipment.")
+ if(1)
+ to_chat(usr, "Your suit will now only report whether you are alive or dead.")
+ if(2)
+ to_chat(usr, "Your suit will now only report your exact vital lifesigns.")
+ if(3)
+ to_chat(usr, "Your suit will now report your exact vital lifesigns as well as your coordinate position.")
+
+ if(ishuman(loc))
+ var/mob/living/carbon/human/H = loc
+ if(H.w_uniform == src)
+ H.update_suit_sensors()
+
+ ..()
+
+/obj/item/clothing/under/CtrlClick(mob/user)
+ . = ..()
+
+ if (!(item_flags & IN_INVENTORY))
+ return
+
+ if(!isliving(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+
+ if(has_sensor == LOCKED_SENSORS)
+ to_chat(user, "The controls are locked.")
+ return
+ if(has_sensor == BROKEN_SENSORS)
+ to_chat(user, "The sensors have shorted out!")
+ return
+ if(has_sensor <= NO_SENSORS)
+ to_chat(user, "This suit does not have any sensors.")
+ return
+
+ sensor_mode = SENSOR_COORDS
+
+ to_chat(user, "Your suit will now report your exact vital lifesigns as well as your coordinate position.")
+
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ if(H.w_uniform == src)
+ H.update_suit_sensors()
+
+/obj/item/clothing/under/AltClick(mob/user)
+ if(..())
+ return 1
+
+ if(!istype(user) || !user.canUseTopic(src, BE_CLOSE, ismonkey(user)))
+ return
+ else
+ if(attached_accessory)
+ remove_accessory(user)
+ else
+ rolldown()
+
+/obj/item/clothing/under/verb/jumpsuit_adjust()
+ set name = "Adjust Jumpsuit Style"
+ set category = null
+ set src in usr
+ rolldown()
+
+/obj/item/clothing/under/proc/rolldown()
+ if(!can_use(usr))
+ return
+ if(!can_adjust)
+ to_chat(usr, "You cannot wear this suit any differently!")
+ return
+ if(toggle_jumpsuit_adjust())
+ to_chat(usr, "You adjust the suit to wear it more casually.")
+ else
+ to_chat(usr, "You adjust the suit back to normal.")
+ if(ishuman(usr))
+ var/mob/living/carbon/human/H = usr
+ H.update_inv_w_uniform()
+ H.update_body()
+
+/obj/item/clothing/under/proc/toggle_jumpsuit_adjust()
+ adjusted = !adjusted
+
+ if(adjusted)
+ if(fitted != FEMALE_UNIFORM_TOP)
+ fitted = NO_FEMALE_UNIFORM
+ if(!alt_covers_chest) // for the special snowflake suits that expose the chest when adjusted
+ body_parts_covered &= ~CHEST
+ else
+ fitted = initial(fitted)
+ if(!alt_covers_chest)
+ body_parts_covered |= CHEST
+
+ return adjusted
+
+/obj/item/clothing/proc/weldingvisortoggle(mob/user) //proc to toggle welding visors on helmets, masks, goggles, etc.
+ if(!can_use(user))
+ return FALSE
+
+ visor_toggling()
+
+ to_chat(user, "You adjust \the [src] [up ? "up" : "down"].")
+
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.head_update(src, forced = 1)
+ for(var/X in actions)
+ var/datum/action/A = X
+ A.UpdateButtonIcon()
+ return TRUE
+
+/obj/item/clothing/proc/visor_toggling() //handles all the actual toggling of flags
+ up = !up
+ clothing_flags ^= visor_flags
+ flags_inv ^= visor_flags_inv
+ flags_cover ^= initial(flags_cover)
+ icon_state = "[initial(icon_state)][up ? "up" : ""]"
+ if(visor_vars_to_toggle & VISOR_FLASHPROTECT)
+ flash_protect ^= initial(flash_protect)
+ if(visor_vars_to_toggle & VISOR_TINT)
+ tint ^= initial(tint)
+
+/obj/item/clothing/head/helmet/space/plasmaman/visor_toggling() //handles all the actual toggling of flags
+ up = !up
+ clothing_flags ^= visor_flags
+ flags_inv ^= visor_flags_inv
+ icon_state = "[initial(icon_state)]"
+ if(visor_vars_to_toggle & VISOR_FLASHPROTECT)
+ flash_protect ^= initial(flash_protect)
+ if(visor_vars_to_toggle & VISOR_TINT)
+ tint ^= initial(tint)
+
+/obj/item/clothing/proc/can_use(mob/user)
+ if(user && ismob(user))
+ if(!user.incapacitated())
+ return 1
+ return 0
+
+
+/obj/item/clothing/obj_destruction(damage_flag)
+ if(damage_flag == "bomb" || damage_flag == "melee")
+ var/turf/T = get_turf(src)
+ spawn(1) //so the shred survives potential turf change from the explosion.
+ var/obj/effect/decal/cleanable/shreds/Shreds = new(T)
+ Shreds.desc = "The sad remains of what used to be [name]."
+ deconstruct(FALSE)
+ else
+ ..()
+
+
+
+//Species-restricted clothing check. - Thanks Oraclestation, BS13, /vg/station etc.
+/obj/item/clothing/mob_can_equip(mob/M, slot, disable_warning = TRUE)
+
+ //if we can't equip the item anyway, don't bother with species_restricted (also cuts down on spam)
+ if(!..())
+ return FALSE
+
+ // Skip species restriction checks on non-equipment slots
+ if(slot in list(SLOT_IN_BACKPACK, SLOT_L_STORE, SLOT_R_STORE))
+ return TRUE
+
+ if(species_restricted && ishuman(M))
+
+ var/wearable = null
+ var/exclusive = null
+ var/mob/living/carbon/human/H = M
+
+ if("exclude" in species_restricted) //TURNS IT INTO A BLACKLIST - AKA ALL MINUS SPECIES LISTED.
+ exclusive = TRUE
+
+ if(H.dna.species)
+ if(exclusive)
+ if(!(H.dna.species.name in species_restricted))
+ wearable = TRUE
+ else
+ if(H.dna.species.name in species_restricted)
+ wearable = TRUE
+
+ if(!wearable)
+ to_chat(M, "Your species cannot wear [src].")
+ return FALSE
+
+ return TRUE
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index 377ac910..bb89aae2 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -53,7 +53,7 @@
return
var/obj/item/reagent_containers/glass/bucket/bucket = H.get_item_for_held_index(1)
- bucket.reagents.add_reagent("water",70)
+ bucket.reagents.add_reagent(/datum/reagent/water,70)
/datum/outfit/laser_tag
name = "Laser Tag Red"
diff --git a/code/modules/events/holiday/vday.dm b/code/modules/events/holiday/vday.dm
index a95bd2fd..ac0a7605 100644
--- a/code/modules/events/holiday/vday.dm
+++ b/code/modules/events/holiday/vday.dm
@@ -157,7 +157,7 @@
icon = 'icons/obj/holiday_misc.dmi'
icon_state = "candyheart"
desc = "A heart-shaped candy that reads: "
- list_reagents = list("sugar" = 2)
+ list_reagents = list(/datum/reagent/consumable/sugar = 2)
junkiness = 5
/obj/item/reagent_containers/food/snacks/candyheart/New()
diff --git a/code/modules/events/vent_clog.dm b/code/modules/events/vent_clog.dm
index 3f4b7661..6ec2865f 100644
--- a/code/modules/events/vent_clog.dm
+++ b/code/modules/events/vent_clog.dm
@@ -1,213 +1,211 @@
-/datum/round_event_control/vent_clog
- name = "Clogged Vents: Normal"
- typepath = /datum/round_event/vent_clog
- weight = 8
- max_occurrences = 1
- min_players = 25
-
-/datum/round_event/vent_clog
- announceWhen = 1
- startWhen = 5
- endWhen = 35
- var/interval = 2
- var/list/vents = list()
- var/randomProbability = 1
- var/reagentsAmount = 100
- var/list/saferChems = list(
- "water",
- "carbon",
- "flour",
- "cleaner",
- "nutriment",
- "condensedcapsaicin",
- "mushroomhallucinogen",
- "lube",
- "pink_glitter",
- "cryptobiolin",
- "plantbgone",
- "blood",
- "charcoal",
- "space_drugs",
- "morphine",
- "holywater",
- "ethanol",
- "hot_coco",
- "sacid",
- "mindbreaker",
- "rotatium",
- "bluespace",
- "pax",
- "laughter",
- "concentrated_barbers_aid",
- "colorful_reagent",
- "dizzysolution",
- "tiresolution",
- "sodiumchloride",
- "beer",
- "sugar",
- "white_glitter",
- "growthchem",
- "shrinkchem",
- "cornoil",
- "uranium",
- "carpet",
- "firefighting_foam",
- "semen",
- "femcum",
- "tearjuice",
- "strange_reagent"
-
- )
- //needs to be chemid unit checked at some point
-
-/datum/round_event/vent_clog/announce()
- priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert")
-
-/datum/round_event/vent_clog/setup()
- endWhen = rand(120, 180)
- for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/temp_vent in GLOB.machines)
- var/turf/T = get_turf(temp_vent)
- var/area/A = T.loc
- if(T && is_station_level(T.z) && !temp_vent.welded && !A.safe)
- vents += temp_vent
-
- if(!vents.len)
- return kill()
-
-/datum/round_event/vent_clog/tick()
-
- if(!vents.len)
- return kill()
-
- CHECK_TICK
-
- var/obj/machinery/atmospherics/components/unary/vent = pick(vents)
- vents -= vent
-
- if(!vent || vent.welded)
- return
-
- var/turf/T = get_turf(vent)
- if(!T)
- return
-
- var/datum/reagents/R = new/datum/reagents(1000)
- R.my_atom = vent
- if (prob(randomProbability))
- R.add_reagent(get_random_reagent_id(), reagentsAmount)
- else
- R.add_reagent(pick(saferChems), reagentsAmount)
-
- var/datum/effect_system/smoke_spread/chem/smoke_machine/C = new
- C.set_up(R,16,1,T)
- C.start()
- playsound(T, 'sound/effects/smoke.ogg', 50, 1, -3)
-
-/datum/round_event_control/vent_clog/threatening
- name = "Clogged Vents: Threatening"
- typepath = /datum/round_event/vent_clog/threatening
- weight = 4
- min_players = 35
- max_occurrences = 1
- earliest_start = 35 MINUTES
-
-/datum/round_event/vent_clog/threatening
- randomProbability = 10
- reagentsAmount = 200
-
-/datum/round_event_control/vent_clog/catastrophic
- name = "Clogged Vents: Catastrophic"
- typepath = /datum/round_event/vent_clog/catastrophic
- weight = 2
- min_players = 45
- max_occurrences = 1
- earliest_start = 45 MINUTES
-
-/datum/round_event/vent_clog/catastrophic
- randomProbability = 30
- reagentsAmount = 250
-
-/datum/round_event_control/vent_clog/beer
- name = "Clogged Vents: Beer"
- typepath = /datum/round_event/vent_clog/beer
- max_occurrences = 0
-
-/datum/round_event/vent_clog/beer
- reagentsAmount = 100
-
-/datum/round_event_control/vent_clog/plasma_decon
- name = "Anti-Plasma Flood"
- typepath = /datum/round_event/vent_clog/plasma_decon
- max_occurrences = 0
-
-/datum/round_event_control/vent_clog/female
- name = "Clogged Vents; Girlcum"
- typepath = /datum/round_event/vent_clog/female
- max_occurrences = 0
-
-/datum/round_event/vent_clog/female
- reagentsAmount = 100
-
-/datum/round_event_control/vent_clog/male
- name = "Clogged Vents: Semen"
- typepath = /datum/round_event/vent_clog/male
- max_occurrences = 0
-
-/datum/round_event/vent_clog/male
- reagentsAmount = 100
-
-/datum/round_event/vent_clog/beer/announce()
- priority_announce("The scrubbers network is experiencing an unexpected surge of pressurized beer. Some ejection of contents may occur.", "Atmospherics alert")
-
-/datum/round_event/vent_clog/beer/start()
- for(var/obj/machinery/atmospherics/components/unary/vent in vents)
- if(vent && vent.loc && !vent.welded)
- var/datum/reagents/R = new/datum/reagents(1000)
- R.my_atom = vent
- R.add_reagent("beer", reagentsAmount)
-
- var/datum/effect_system/foam_spread/foam = new
- foam.set_up(200, get_turf(vent), R)
- foam.start()
- CHECK_TICK
-
-/datum/round_event/vent_clog/male/announce()
- priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejaculation of contents may occur.", "Atmospherics alert")
-
-/datum/round_event/vent_clog/male/start()
- for(var/obj/machinery/atmospherics/components/unary/vent in vents)
- if(vent && vent.loc && !vent.welded)
- var/datum/reagents/R = new/datum/reagents(1000)
- R.my_atom = vent
- R.add_reagent("semen", reagentsAmount)
-
- var/datum/effect_system/foam_spread/foam = new
- foam.set_up(200, get_turf(vent), R)
- foam.start()
- CHECK_TICK
-
-/datum/round_event/vent_clog/female/announce()
- priority_announce("The scrubbers network is experiencing a backpressure squirt. Some ejection of contents may occur.", "Atmospherics alert")
-
-/datum/round_event/vent_clog/female/start()
- for(var/obj/machinery/atmospherics/components/unary/vent in vents)
- if(vent && vent.loc && !vent.welded)
- var/datum/reagents/R = new/datum/reagents(1000)
- R.my_atom = vent
- R.add_reagent("femcum", reagentsAmount)
-
- var/datum/effect_system/foam_spread/foam = new
- foam.set_up(200, get_turf(vent), R)
- foam.start()
- CHECK_TICK
-
-/datum/round_event/vent_clog/plasma_decon/announce()
- priority_announce("We are deploying an experimental plasma decontamination system. Please stand away from the vents and do not breathe the smoke that comes out.", "Central Command Update")
-
-/datum/round_event/vent_clog/plasma_decon/start()
- for(var/obj/machinery/atmospherics/components/unary/vent in vents)
- if(vent && vent.loc && !vent.welded)
- var/datum/effect_system/smoke_spread/freezing/decon/smoke = new
- smoke.set_up(7, get_turf(vent), 7)
- smoke.start()
- CHECK_TICK
+/datum/round_event_control/vent_clog
+ name = "Clogged Vents: Normal"
+ typepath = /datum/round_event/vent_clog
+ weight = 8
+ max_occurrences = 1
+ min_players = 25
+
+/datum/round_event/vent_clog
+ announceWhen = 1
+ startWhen = 5
+ endWhen = 35
+ var/interval = 2
+ var/list/vents = list()
+ var/randomProbability = 1
+ var/reagentsAmount = 100
+ var/list/saferChems = list(
+ /datum/reagent/water,
+ /datum/reagent/carbon,
+ /datum/reagent/consumable/flour,
+ /datum/reagent/space_cleaner,
+ /datum/reagent/consumable/nutriment,
+ /datum/reagent/consumable/condensedcapsaicin,
+ /datum/reagent/drug/mushroomhallucinogen,
+ /datum/reagent/lube,
+ /datum/reagent/glitter/pink,
+ /datum/reagent/cryptobiolin,
+ /datum/reagent/toxin/plantbgone,
+ /datum/reagent/blood,
+ /datum/reagent/medicine/charcoal,
+ /datum/reagent/drug/space_drugs,
+ /datum/reagent/medicine/morphine,
+ /datum/reagent/water/holywater,
+ /datum/reagent/consumable/ethanol,
+ /datum/reagent/consumable/hot_coco,
+ /datum/reagent/toxin/acid,
+ /datum/reagent/toxin/mindbreaker,
+ /datum/reagent/toxin/rotatium,
+ /datum/reagent/bluespace,
+ /datum/reagent/pax,
+ /datum/reagent/consumable/laughter,
+ /datum/reagent/concentrated_barbers_aid,
+ /datum/reagent/colorful_reagent,
+ /datum/reagent/peaceborg_confuse,
+ /datum/reagent/peaceborg_tire,
+ /datum/reagent/consumable/sodiumchloride,
+ /datum/reagent/consumable/ethanol/beer,
+ /datum/reagent/hair_dye,
+ /datum/reagent/consumable/sugar,
+ /datum/reagent/glitter/white,
+ /datum/reagent/growthserum,
+ /datum/reagent/consumable/cornoil,
+ /datum/reagent/uranium,
+ /datum/reagent/carpet,
+ /datum/reagent/firefighting_foam,
+ /datum/reagent/consumable/tearjuice,
+ /datum/reagent/medicine/strange_reagent
+
+ )
+ //needs to be chemid unit checked at some point
+
+/datum/round_event/vent_clog/announce()
+ priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejection of contents may occur.", "Atmospherics alert")
+
+/datum/round_event/vent_clog/setup()
+ endWhen = rand(120, 180)
+ for(var/obj/machinery/atmospherics/components/unary/vent_scrubber/temp_vent in GLOB.machines)
+ var/turf/T = get_turf(temp_vent)
+ var/area/A = T.loc
+ if(T && is_station_level(T.z) && !temp_vent.welded && !A.safe)
+ vents += temp_vent
+
+ if(!vents.len)
+ return kill()
+
+/datum/round_event/vent_clog/tick()
+
+ if(!vents.len)
+ return kill()
+
+ CHECK_TICK
+
+ var/obj/machinery/atmospherics/components/unary/vent = pick(vents)
+ vents -= vent
+
+ if(!vent || vent.welded)
+ return
+
+ var/turf/T = get_turf(vent)
+ if(!T)
+ return
+
+ var/datum/reagents/R = new/datum/reagents(1000)
+ R.my_atom = vent
+ if (prob(randomProbability))
+ R.add_reagent(get_random_reagent_id(), reagentsAmount)
+ else
+ R.add_reagent(pick(saferChems), reagentsAmount)
+
+ var/datum/effect_system/smoke_spread/chem/smoke_machine/C = new
+ C.set_up(R,16,1,T)
+ C.start()
+ playsound(T, 'sound/effects/smoke.ogg', 50, 1, -3)
+
+/datum/round_event_control/vent_clog/threatening
+ name = "Clogged Vents: Threatening"
+ typepath = /datum/round_event/vent_clog/threatening
+ weight = 4
+ min_players = 35
+ max_occurrences = 1
+ earliest_start = 35 MINUTES
+
+/datum/round_event/vent_clog/threatening
+ randomProbability = 10
+ reagentsAmount = 200
+
+/datum/round_event_control/vent_clog/catastrophic
+ name = "Clogged Vents: Catastrophic"
+ typepath = /datum/round_event/vent_clog/catastrophic
+ weight = 2
+ min_players = 45
+ max_occurrences = 1
+ earliest_start = 45 MINUTES
+
+/datum/round_event/vent_clog/catastrophic
+ randomProbability = 30
+ reagentsAmount = 250
+
+/datum/round_event_control/vent_clog/beer
+ name = "Clogged Vents: Beer"
+ typepath = /datum/round_event/vent_clog/beer
+ max_occurrences = 0
+
+/datum/round_event/vent_clog/beer
+ reagentsAmount = 100
+
+/datum/round_event_control/vent_clog/plasma_decon
+ name = "Anti-Plasma Flood"
+ typepath = /datum/round_event/vent_clog/plasma_decon
+ max_occurrences = 0
+
+/datum/round_event_control/vent_clog/female
+ name = "Clogged Vents; Girlcum"
+ typepath = /datum/round_event/vent_clog/female
+ max_occurrences = 0
+
+/datum/round_event/vent_clog/female
+ reagentsAmount = 100
+
+/datum/round_event_control/vent_clog/male
+ name = "Clogged Vents: Semen"
+ typepath = /datum/round_event/vent_clog/male
+ max_occurrences = 0
+
+/datum/round_event/vent_clog/male
+ reagentsAmount = 100
+
+/datum/round_event/vent_clog/beer/announce()
+ priority_announce("The scrubbers network is experiencing an unexpected surge of pressurized beer. Some ejection of contents may occur.", "Atmospherics alert")
+
+/datum/round_event/vent_clog/beer/start()
+ for(var/obj/machinery/atmospherics/components/unary/vent in vents)
+ if(vent && vent.loc && !vent.welded)
+ var/datum/reagents/R = new/datum/reagents(1000)
+ R.my_atom = vent
+ R.add_reagent(/datum/reagent/consumable/ethanol/beer, reagentsAmount)
+
+ var/datum/effect_system/foam_spread/foam = new
+ foam.set_up(200, get_turf(vent), R)
+ foam.start()
+ CHECK_TICK
+
+/datum/round_event/vent_clog/male/announce()
+ priority_announce("The scrubbers network is experiencing a backpressure surge. Some ejaculation of contents may occur.", "Atmospherics alert")
+
+/datum/round_event/vent_clog/male/start()
+ for(var/obj/machinery/atmospherics/components/unary/vent in vents)
+ if(vent && vent.loc && !vent.welded)
+ var/datum/reagents/R = new/datum/reagents(1000)
+ R.my_atom = vent
+ R.add_reagent(/datum/reagent/consumable/semen, reagentsAmount)
+
+ var/datum/effect_system/foam_spread/foam = new
+ foam.set_up(200, get_turf(vent), R)
+ foam.start()
+ CHECK_TICK
+
+/datum/round_event/vent_clog/female/announce()
+ priority_announce("The scrubbers network is experiencing a backpressure squirt. Some ejection of contents may occur.", "Atmospherics alert")
+
+/datum/round_event/vent_clog/female/start()
+ for(var/obj/machinery/atmospherics/components/unary/vent in vents)
+ if(vent && vent.loc && !vent.welded)
+ var/datum/reagents/R = new/datum/reagents(1000)
+ R.my_atom = vent
+ R.add_reagent(/datum/reagent/consumable/femcum, reagentsAmount)
+
+ var/datum/effect_system/foam_spread/foam = new
+ foam.set_up(200, get_turf(vent), R)
+ foam.start()
+ CHECK_TICK
+
+/datum/round_event/vent_clog/plasma_decon/announce()
+ priority_announce("We are deploying an experimental plasma decontamination system. Please stand away from the vents and do not breathe the smoke that comes out.", "Central Command Update")
+
+/datum/round_event/vent_clog/plasma_decon/start()
+ for(var/obj/machinery/atmospherics/components/unary/vent in vents)
+ if(vent && vent.loc && !vent.welded)
+ var/datum/effect_system/smoke_spread/freezing/decon/smoke = new
+ smoke.set_up(7, get_turf(vent), 7)
+ smoke.start()
+ CHECK_TICK
diff --git a/code/modules/events/wizard/invincible.dm b/code/modules/events/wizard/invincible.dm
index 209bdd26..6ba9b44e 100644
--- a/code/modules/events/wizard/invincible.dm
+++ b/code/modules/events/wizard/invincible.dm
@@ -8,5 +8,5 @@
/datum/round_event/wizard/invincible/start()
for(var/mob/living/carbon/human/H in GLOB.alive_mob_list)
- H.reagents.add_reagent("adminordrazine", 40) //100 ticks of absolute invinciblity (barring gibs)
+ H.reagents.add_reagent(/datum/reagent/medicine/adminordrazine, 40) //100 ticks of absolute invinciblity (barring gibs)
to_chat(H, "You feel invincible, nothing can hurt you!")
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/drinks/drinks.dm b/code/modules/food_and_drinks/drinks/drinks.dm
index 12db17f4..ad99e583 100644
--- a/code/modules/food_and_drinks/drinks/drinks.dm
+++ b/code/modules/food_and_drinks/drinks/drinks.dm
@@ -201,7 +201,7 @@
name = "robust coffee"
desc = "Careful, the beverage you're about to enjoy is extremely hot."
icon_state = "coffee"
- list_reagents = list("coffee" = 30)
+ list_reagents = list(/datum/reagent/consumable/coffee = 30)
spillable = TRUE
resistance_flags = FREEZE_PROOF
isGlass = FALSE
@@ -219,7 +219,7 @@
name = "ice cup"
desc = "Careful, cold ice, do not chew."
icon_state = "coffee"
- list_reagents = list("ice" = 30)
+ list_reagents = list(/datum/reagent/consumable/ice = 30)
spillable = TRUE
isGlass = FALSE
@@ -245,12 +245,12 @@
/obj/item/reagent_containers/food/drinks/mug/tea
name = "Duke Purple tea"
desc = "An insult to Duke Purple is an insult to the Space Queen! Any proper gentleman will fight you, if you sully this tea."
- list_reagents = list("tea" = 30)
+ list_reagents = list(/datum/reagent/consumable/tea = 30)
/obj/item/reagent_containers/food/drinks/mug/coco
name = "Dutch hot coco"
desc = "Made in Space South America."
- list_reagents = list("hot_coco" = 30, "sugar" = 5)
+ list_reagents = list(/datum/reagent/consumable/hot_coco = 30, /datum/reagent/consumable/sugar = 5)
foodtype = SUGAR
resistance_flags = FREEZE_PROOF
@@ -260,7 +260,7 @@
name = "cup ramen"
desc = "Just add 10ml of water, self heats! A taste that reminds you of your school years."
icon_state = "ramen"
- list_reagents = list("dry_ramen" = 30)
+ list_reagents = list(/datum/reagent/consumable/dry_ramen = 30)
foodtype = GRAIN
isGlass = FALSE
@@ -268,20 +268,20 @@
name = "space beer"
desc = "Beer. In space."
icon_state = "beer"
- list_reagents = list("beer" = 30)
+ list_reagents = list(/datum/reagent/consumable/ethanol/beer = 30)
foodtype = GRAIN | ALCOHOL
/obj/item/reagent_containers/food/drinks/beer/light
name = "Carp Lite"
desc = "Brewed with \"Pure Ice Asteroid Spring Water\"."
- list_reagents = list("light_beer" = 30)
+ list_reagents = list(/datum/reagent/consumable/ethanol/beer/light = 30)
/obj/item/reagent_containers/food/drinks/ale
name = "Magm-Ale"
desc = "A true dorf's drink of choice."
icon_state = "alebottle"
item_state = "beer"
- list_reagents = list("ale" = 30)
+ list_reagents = list(/datum/reagent/consumable/ethanol/ale = 30)
foodtype = GRAIN | ALCOHOL
/obj/item/reagent_containers/food/drinks/sillycup
@@ -404,7 +404,7 @@
name = "detective's flask"
desc = "The detective's only true friend."
icon_state = "detflask"
- list_reagents = list("whiskey" = 30)
+ list_reagents = list(/datum/reagent/consumable/ethanol/whiskey = 30)
/obj/item/reagent_containers/food/drinks/britcup
name = "cup"
@@ -454,27 +454,26 @@
name = "Space Cola"
desc = "Cola. in space."
icon_state = "cola"
- list_reagents = list("cola" = 30)
+ list_reagents = list(/datum/reagent/consumable/space_cola = 30)
foodtype = SUGAR
/obj/item/reagent_containers/food/drinks/soda_cans/tonic
name = "T-Borg's tonic water"
desc = "Quinine tastes funny, but at least it'll keep that Space Malaria away."
icon_state = "tonic"
- list_reagents = list("tonic" = 50)
- foodtype = ALCOHOL
+ list_reagents = list(/datum/reagent/consumable/tonic = 50)
/obj/item/reagent_containers/food/drinks/soda_cans/sodawater
name = "soda water"
desc = "A can of soda water. Why not make a scotch and soda?"
icon_state = "sodawater"
- list_reagents = list("sodawater" = 50)
+ list_reagents = list(/datum/reagent/consumable/sodawater = 50)
/obj/item/reagent_containers/food/drinks/soda_cans/lemon_lime
name = "orange soda"
desc = "You wanted ORANGE. It gave you Lemon Lime."
icon_state = "lemon-lime"
- list_reagents = list("lemon_lime" = 30)
+ list_reagents = list(/datum/reagent/consumable/lemon_lime = 30)
foodtype = FRUIT
/obj/item/reagent_containers/food/drinks/soda_cans/lemon_lime/Initialize()
@@ -485,66 +484,66 @@
name = "Space-Up!"
desc = "Tastes like a hull breach in your mouth."
icon_state = "space-up"
- list_reagents = list("space_up" = 30)
+ list_reagents = list(/datum/reagent/consumable/space_up = 30)
foodtype = SUGAR | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/starkist
name = "Star-kist"
desc = "The taste of a star in liquid form. And, a bit of tuna...?"
icon_state = "starkist"
- list_reagents = list("cola" = 15, "orangejuice" = 15)
+ list_reagents = list(/datum/reagent/consumable/space_cola = 15, /datum/reagent/consumable/orangejuice = 15)
foodtype = SUGAR | FRUIT | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/space_mountain_wind
name = "Space Mountain Wind"
desc = "Blows right through you like a space wind."
icon_state = "space_mountain_wind"
- list_reagents = list("spacemountainwind" = 30)
+ list_reagents = list(/datum/reagent/consumable/spacemountainwind = 30)
foodtype = SUGAR | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/thirteenloko
name = "Thirteen Loko"
desc = "The CMO has advised crew members that consumption of Thirteen Loko may result in seizures, blindness, drunkenness, or even death. Please Drink Responsibly."
icon_state = "thirteen_loko"
- list_reagents = list("thirteenloko" = 30)
+ list_reagents = list(/datum/reagent/consumable/ethanol/thirteenloko = 30)
foodtype = SUGAR | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/dr_gibb
name = "Dr. Gibb"
desc = "A delicious mixture of 42 different flavors."
icon_state = "dr_gibb"
- list_reagents = list("dr_gibb" = 30)
+ list_reagents = list(/datum/reagent/consumable/dr_gibb = 30)
foodtype = SUGAR | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/pwr_game
name = "Pwr Game"
desc = "The only drink with the PWR that true gamers crave."
icon_state = "purple_can"
- list_reagents = list("pwr_game" = 30)
+ list_reagents = list(/datum/reagent/consumable/pwr_game = 30)
/obj/item/reagent_containers/food/drinks/soda_cans/shamblers
name = "Shambler's juice"
desc = "~Shake me up some of that Shambler's Juice!~"
icon_state = "shamblers"
- list_reagents = list("shamblers" = 30)
+ list_reagents = list(/datum/reagent/consumable/shamblers = 30)
foodtype = SUGAR | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/grey_bull
name = "Grey Bull"
desc = "Grey Bull, it gives you gloves!"
icon_state = "energy_drink"
- list_reagents = list("grey_bull" = 20)
+ list_reagents = list(/datum/reagent/consumable/grey_bull = 20)
foodtype = SUGAR | JUNKFOOD
/obj/item/reagent_containers/food/drinks/soda_cans/air
name = "canned air"
desc = "There is no air shortage. Do not drink."
icon_state = "air"
- list_reagents = list("nitrogen" = 24, "oxygen" = 6)
+ list_reagents = list(/datum/reagent/nitrogen = 24, /datum/reagent/oxygen = 6)
/obj/item/reagent_containers/food/drinks/soda_cans/monkey_energy
name = "Monkey Energy"
desc = "Unleash the ape!"
icon_state = "monkey_energy"
- list_reagents = list("monkey_energy" = 50)
+ list_reagents = list(/datum/reagent/consumable/monkey_energy = 50)
foodtype = SUGAR | JUNKFOOD
diff --git a/code/modules/food_and_drinks/drinks/drinks/bottle.dm b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
index bab2d677..2e2a4b34 100644
--- a/code/modules/food_and_drinks/drinks/drinks/bottle.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/bottle.dm
@@ -131,88 +131,87 @@
name = "Griffeater gin"
desc = "A bottle of high quality gin, produced in the New London Space Station."
icon_state = "ginbottle"
- list_reagents = list("gin" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/gin = 100)
/obj/item/reagent_containers/food/drinks/bottle/gin/empty
- list_reagents = list("gin" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/whiskey
name = "Uncle Git's special reserve"
desc = "A premium single-malt whiskey, gently matured inside the tunnels of a nuclear shelter. TUNNEL WHISKEY RULES."
icon_state = "whiskeybottle"
- list_reagents = list("whiskey" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/whiskey = 100)
/obj/item/reagent_containers/food/drinks/bottle/whiskey/empty
- list_reagents = list("whiskey" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/vodka
name = "Tunguska triple distilled"
desc = "Aah, vodka. Prime choice of drink AND fuel by Russians worldwide."
icon_state = "vodkabottle"
- list_reagents = list("vodka" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/vodka = 100)
/obj/item/reagent_containers/food/drinks/bottle/vodka/empty
- list_reagents = list("vodka" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/vodka/badminka
name = "Badminka vodka"
desc = "The label's written in Cyrillic. All you can make out is the name and a word that looks vaguely like 'Vodka'."
icon_state = "badminka"
- list_reagents = list("vodka" = 100)
/obj/item/reagent_containers/food/drinks/bottle/tequila
name = "Caccavo guaranteed quality tequila"
desc = "Made from premium petroleum distillates, pure thalidomide and other fine quality ingredients!"
icon_state = "tequilabottle"
- list_reagents = list("tequila" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/tequila = 100)
/obj/item/reagent_containers/food/drinks/bottle/tequila/empty
- list_reagents = list("tequila" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing
name = "bottle of nothing"
desc = "A bottle filled with nothing."
icon_state = "bottleofnothing"
- list_reagents = list("nothing" = 100)
+ list_reagents = list(/datum/reagent/consumable/nothing = 100)
foodtype = NONE
/obj/item/reagent_containers/food/drinks/bottle/bottleofnothing/empty
- list_reagents = list("nothing" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/patron
name = "Wrapp Artiste Patron"
desc = "Silver laced tequila, served in space night clubs across the galaxy."
icon_state = "patronbottle"
- list_reagents = list("patron" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/patron = 100)
/obj/item/reagent_containers/food/drinks/bottle/patron/empty
- list_reagents = list("patron" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/rum
name = "Captain Pete's Cuban spiced rum"
desc = "This isn't just rum, oh no. It's practically GRIFF in a bottle."
icon_state = "rumbottle"
- list_reagents = list("rum" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/rum = 100)
/obj/item/reagent_containers/food/drinks/bottle/rum/empty
- list_reagents = list("rum" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/holywater
name = "flask of holy water"
desc = "A flask of the chaplain's holy water."
icon_state = "holyflask"
- list_reagents = list("holywater" = 100)
+ list_reagents = list(/datum/reagent/water/holywater = 100)
foodtype = NONE
/obj/item/reagent_containers/food/drinks/bottle/holywater/hell
desc = "A flask of holy water...it's been sitting in the Necropolis a while though."
- list_reagents = list("hell_water" = 100)
+ list_reagents = list(/datum/reagent/hellwater = 100)
/obj/item/reagent_containers/food/drinks/bottle/holyoil
name = "flask of zelus oil"
desc = "A brass flask of Zelus oil, a viscous fluid scenting of brass. Can be thrown to deal damage from afar."
icon_state = "zelusflask"
- list_reagents = list("holyoil" = 30)
+ list_reagents = list(/datum/reagent/fuel/holyoil = 30)
volume = 30
foodtype = NONE
force = 18
@@ -220,63 +219,63 @@
knockdown_duration = 18
/obj/item/reagent_containers/food/drinks/bottle/holyoil/empty
- list_reagents = list("holyoil" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/vermouth
name = "Goldeneye vermouth"
desc = "Sweet, sweet dryness~"
icon_state = "vermouthbottle"
- list_reagents = list("vermouth" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/vermouth = 100)
/obj/item/reagent_containers/food/drinks/bottle/vermouth/empty
- list_reagents = list("vermouth" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/kahlua
name = "Robert Robust's coffee liqueur"
desc = "A widely known, Mexican coffee-flavoured liqueur. In production since 1936, HONK."
icon_state = "kahluabottle"
- list_reagents = list("kahlua" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/kahlua = 100)
foodtype = VEGETABLES
/obj/item/reagent_containers/food/drinks/bottle/kahlua/empty
- list_reagents = list("kahlua" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/goldschlager
name = "College Girl goldschlager"
desc = "Because they are the only ones who will drink 100 proof cinnamon schnapps."
icon_state = "goldschlagerbottle"
- list_reagents = list("goldschlager" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/goldschlager = 100)
/obj/item/reagent_containers/food/drinks/bottle/goldschlager/empty
- list_reagents = list("goldschlager" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/cognac
name = "Chateau de Baton premium cognac"
desc = "A sweet and strongly alchoholic drink, made after numerous distillations and years of maturing. You might as well not scream 'SHITCURITY' this time."
icon_state = "cognacbottle"
- list_reagents = list("cognac" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/cognac = 100)
/obj/item/reagent_containers/food/drinks/bottle/cognac/empty
- list_reagents = list("cognac" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/wine
name = "Doublebeard's bearded special wine"
desc = "A faint aura of unease and asspainery surrounds the bottle."
icon_state = "winebottle"
- list_reagents = list("wine" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/wine = 100)
foodtype = FRUIT | ALCOHOL
/obj/item/reagent_containers/food/drinks/bottle/wine/empty
- list_reagents = list("wine" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/absinthe
name = "extra-strong absinthe"
desc = "An strong alcoholic drink brewed and distributed by"
icon_state = "absinthebottle"
- list_reagents = list("absinthe" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/absinthe = 100)
/obj/item/reagent_containers/food/drinks/bottle/absinthe/empty
- list_reagents = list("absinthe" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/absinthe/Initialize()
. = ..()
@@ -329,7 +328,7 @@
name = "bottle of lizard wine"
desc = "An alcoholic beverage from Space China, made by infusing lizard tails in ethanol. Inexplicably popular among command staff."
icon_state = "lizardwine"
- list_reagents = list("lizardwine" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/lizardwine = 100)
foodtype = FRUIT | ALCOHOL
/obj/item/reagent_containers/food/drinks/bottle/hcider
@@ -337,28 +336,28 @@
desc = "Apple juice for adults."
icon_state = "hcider"
volume = 50
- list_reagents = list("hcider" = 50)
+ list_reagents = list(/datum/reagent/consumable/ethanol/hcider = 50)
/obj/item/reagent_containers/food/drinks/bottle/hcider/empty
- list_reagents = list("hcider" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/grappa
name = "Phillipes well-aged Grappa"
desc = "Bottle of Grappa."
icon_state = "grappabottle"
- list_reagents = list("grappa" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/grappa = 100)
/obj/item/reagent_containers/food/drinks/bottle/grappa/empty
- list_reagents = list("grappa" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/sake
name = "Ryo's traditional sake"
desc = "Sweet as can be, and burns like fire going down."
icon_state = "sakebottle"
- list_reagents = list("sake" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/sake = 100)
/obj/item/reagent_containers/food/drinks/bottle/sake/empty
- list_reagents = list("sake" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/sake/Initialize()
. = ..()
@@ -375,48 +374,48 @@
name = "Fernet Bronca"
desc = "A bottle of pure Fernet Bronca, produced in Cordoba Space Station"
icon_state = "fernetbottle"
- list_reagents = list("fernet" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/fernet = 100)
/obj/item/reagent_containers/food/drinks/bottle/fernet/empty
- list_reagents = list("fernet" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/applejack
name = "Buckin' Bronco's Applejack"
desc = "Kicks like a horse, tastes like an apple!"
icon_state = "applejack_bottle"
- list_reagents = list("applejack" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/applejack = 100)
foodtype = FRUIT
/obj/item/reagent_containers/food/drinks/bottle/applejack/empty
- list_reagents = list("applejack" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/champagne
name = "Eau d' Dandy Brut Champagne"
desc = "Finely sourced from only the most pretentious French vineyards."
icon_state = "champagne_bottle"
- list_reagents = list("champagne" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/champagne = 100)
/obj/item/reagent_containers/food/drinks/bottle/champagne/empty
- list_reagents = list("champagne" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/blazaam
name = "Ginbad's Blazaam"
desc = "You feel like you should give the bottle a good rub before opening."
icon_state = "blazaambottle"
- list_reagents = list("blazaam" = 100)
+ list_reagents = list(/datum/reagent/consumable/ethanol/blazaam = 100)
/obj/item/reagent_containers/food/drinks/bottle/blazaam/empty
- list_reagents = list("blazaam" = 0)
+ list_reagents = null
/obj/item/reagent_containers/food/drinks/bottle/trappist
name = "Mont de Requin Trappistes Bleu"
desc = "Brewed in space-Belgium. Fancy!"
icon_state = "trappistbottle"
volume = 50
- list_reagents = list("trappist" = 50)
+ list_reagents = list(/datum/reagent/consumable/ethanol/trappist = 50)
/obj/item/reagent_containers/food/drinks/bottle/trappist/empty
- list_reagents = list("trappist" = 0)
+ list_reagents = null
//////////////////////////JUICES AND STUFF ///////////////////////
@@ -428,7 +427,7 @@
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
isGlass = FALSE
- list_reagents = list("orangejuice" = 100)
+ list_reagents = list(/datum/reagent/consumable/orangejuice = 100)
foodtype = FRUIT| BREAKFAST
/obj/item/reagent_containers/food/drinks/bottle/cream
@@ -439,7 +438,7 @@
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
isGlass = FALSE
- list_reagents = list("cream" = 100)
+ list_reagents = list(/datum/reagent/consumable/cream = 100)
foodtype = DAIRY
/obj/item/reagent_containers/food/drinks/bottle/tomatojuice
@@ -450,7 +449,7 @@
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
isGlass = FALSE
- list_reagents = list("tomatojuice" = 100)
+ list_reagents = list(/datum/reagent/consumable/tomatojuice = 100)
foodtype = VEGETABLES
/obj/item/reagent_containers/food/drinks/bottle/limejuice
@@ -461,7 +460,7 @@
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
isGlass = FALSE
- list_reagents = list("limejuice" = 100)
+ list_reagents = list(/datum/reagent/consumable/limejuice = 100)
foodtype = FRUIT
/obj/item/reagent_containers/food/drinks/bottle/menthol
@@ -472,7 +471,7 @@
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
isGlass = FALSE
- list_reagents = list("menthol" = 100)
+ list_reagents = list(/datum/reagent/consumable/menthol = 100)
/obj/item/reagent_containers/food/drinks/bottle/pineapplejuice
name = "pineapple juice"
@@ -501,11 +500,11 @@
desc = "Contains 0% real cherries!"
icon_state = "grenadine"
isGlass = TRUE
- list_reagents = list("grenadine" = 100)
+ list_reagents = list(/datum/reagent/consumable/grenadine = 100)
foodtype = FRUIT
/obj/item/reagent_containers/food/drinks/bottle/grenadine/empty
- list_reagents = list("grenadine" = 0)
+ list_reagents = null
////////////////////////// MOLOTOV ///////////////////////
/obj/item/reagent_containers/food/drinks/bottle/molotov
diff --git a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
index 1e5c2eaf..0d769932 100644
--- a/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
+++ b/code/modules/food_and_drinks/drinks/drinks/drinkingglass.dm
@@ -81,19 +81,19 @@
/obj/item/reagent_containers/food/drinks/drinkingglass/filled/soda
name = "Soda Water"
- list_reagents = list("sodawater" = 50)
+ list_reagents = list(/datum/reagent/consumable/sodawater = 50)
/obj/item/reagent_containers/food/drinks/drinkingglass/filled/cola
name = "Space Cola"
- list_reagents = list("cola" = 50)
+ list_reagents = list(/datum/reagent/consumable/space_cola = 50)
/obj/item/reagent_containers/food/drinks/drinkingglass/filled/nuka_cola
name = "Nuka Cola"
- list_reagents = list("nuka_cola" = 50)
+ list_reagents = list(/datum/reagent/consumable/nuka_cola = 50)
/obj/item/reagent_containers/food/drinks/drinkingglass/filled/syndicatebomb
name = "Syndicat Bomb"
- list_reagents = list("syndicatebomb" = 50)
+ list_reagents = list(/datum/reagent/consumable/ethanol/syndicatebomb = 50)
/obj/item/reagent_containers/food/drinks/drinkingglass/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers/food/snacks/egg)) //breaking eggs
@@ -103,7 +103,7 @@
to_chat(user, "[src] is full.")
else
to_chat(user, "You break [E] in [src].")
- reagents.add_reagent("eggyolk", 5)
+ reagents.add_reagent(/datum/reagent/consumable/eggyolk, 5)
qdel(E)
return
else
diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm
index 71ad4c86..d8dafb7b 100644
--- a/code/modules/food_and_drinks/food/condiment.dm
+++ b/code/modules/food_and_drinks/food/condiment.dm
@@ -15,21 +15,18 @@
volume = 50
//Possible_states has the reagent id as key and a list of, in order, the icon_state, the name and the desc as values. Used in the on_reagent_change(changetype) to change names, descs and sprites.
var/list/possible_states = list(
- "slimejelly" = list("slimejelly", "slime jelly jar", "Ooey, gooey, toxic goodness."),
- "cherryjelly" = list("cherryjelly", "cherry jelly jar", "A sugary spread made from cherries. Delicious!"),
- "bluecherryjelly" = list("bluecherryjelly", "blue cherry jelly jar", "A crazy sweet jelly made from blue cherries! It's blue da ba dee-licious!"),
- "ketchup" = list("ketchup", "ketchup bottle", "You feel more American already."),
- "capsaicin" = list("hotsauce", "hotsauce bottle", "You can almost TASTE the stomach ulcers now!"),
- "enzyme" = list("enzyme", "universal enzyme bottle", "Used in cooking various dishes"),
- "soysauce" = list("soysauce", "soy sauce bottle", "A salty soy-based flavoring"),
- "frostoil" = list("coldsauce", "coldsauce bottle", "Leaves the tongue numb in its passage"),
- "sodiumchloride" = list("saltshakersmall", "salt shaker", "Salt. From space oceans, presumably"),
- "blackpepper" = list("peppermillsmall", "pepper mill", "Often used to flavor food or make people sneeze"),
- "cornoil" = list("oliveoil", "corn oil bottle", "A delicious oil used in cooking. Made from corn"),
- "sugar" = list("emptycondiment", "sugar bottle", "Tasty spacey sugar!"),
- "mayonnaise" = list("mayonnaise", "mayonnaise jar", "An oily condiment made from egg yolks."),
- "bbqsauce" = list("condi_bbq", "BBQ sauce", "Hand wipes not included."),
- "peanut_butter" = list("peanutbutter", "peanut butter jar", "A deliciously and sticky spread made from peanuts."))
+ /datum/reagent/consumable/ketchup = list("ketchup", "ketchup bottle", "You feel more American already."),
+ /datum/reagent/consumable/capsaicin = list("hotsauce", "hotsauce bottle", "You can almost TASTE the stomach ulcers now!"),
+ /datum/reagent/consumable/enzyme = list("enzyme", "universal enzyme bottle", "Used in cooking various dishes"),
+ /datum/reagent/consumable/soysauce = list("soysauce", "soy sauce bottle", "A salty soy-based flavoring"),
+ /datum/reagent/consumable/frostoil = list("coldsauce", "coldsauce bottle", "Leaves the tongue numb in its passage"),
+ /datum/reagent/consumable/sodiumchloride = list("saltshakersmall", "salt shaker", "Salt. From space oceans, presumably"),
+ /datum/reagent/consumable/blackpepper = list("peppermillsmall", "pepper mill", "Often used to flavor food or make people sneeze"),
+ /datum/reagent/consumable/cornoil = list("oliveoil", "corn oil bottle", "A delicious oil used in cooking. Made from corn"),
+ /datum/reagent/consumable/sugar = list("emptycondiment", "sugar bottle", "Tasty spacey sugar!"),
+ /datum/reagent/consumable/mayonnaise = list("mayonnaise", "mayonnaise jar", "An oily condiment made from egg yolks."),
+ /datum/reagent/consumable/bbqsauce = list("bbqsauce", "BBQ sauce", "Hand wipes not included."),
+ /datum/reagent/consumable/peanut_butter = list("peanutbutter", "peanut butter jar", "A deliciously and sticky spread made from peanuts."))
var/originalname = "condiment" //Can't use initial(name) for this. This stores the name set by condimasters.
/obj/item/reagent_containers/food/condiment/suicide_act(mob/living/carbon/user)
@@ -119,12 +116,12 @@
name = "universal enzyme"
desc = "Used in cooking various dishes."
icon_state = "enzyme"
- list_reagents = list("enzyme" = 50)
+ list_reagents = list(/datum/reagent/consumable/enzyme = 50)
/obj/item/reagent_containers/food/condiment/sugar
name = "sugar bottle"
desc = "Tasty spacey sugar!"
- list_reagents = list("sugar" = 50)
+ list_reagents = list(/datum/reagent/consumable/sugar = 50)
/obj/item/reagent_containers/food/condiment/saltshaker //Separate from above since it's a small shaker rather then
name = "salt shaker" // a large one.
@@ -133,7 +130,7 @@
possible_transfer_amounts = list(1,20) //for clown turning the lid off
amount_per_transfer_from_this = 1
volume = 20
- list_reagents = list("sodiumchloride" = 20)
+ list_reagents = list(/datum/reagent/consumable/sodiumchloride = 20)
possible_states = list()
/obj/item/reagent_containers/food/condiment/saltshaker/on_reagent_change(changetype)
@@ -156,11 +153,11 @@
if(!proximity)
return
if(isturf(target))
- if(!reagents.has_reagent("sodiumchloride", 2))
+ if(!reagents.has_reagent(/datum/reagent/consumable/sodiumchloride, 2))
to_chat(user, "You don't have enough salt to make a pile!")
return
user.visible_message("[user] shakes some salt onto [target].", "You shake some salt onto [target].")
- reagents.remove_reagent("sodiumchloride", 2)
+ reagents.remove_reagent(/datum/reagent/consumable/sodiumchloride, 2)
new/obj/effect/decal/cleanable/salt(target)
return
@@ -171,7 +168,7 @@
possible_transfer_amounts = list(1,20) //for clown turning the lid off
amount_per_transfer_from_this = 1
volume = 20
- list_reagents = list("blackpepper" = 20)
+ list_reagents = list(/datum/reagent/consumable/blackpepper = 20)
possible_states = list()
/obj/item/reagent_containers/food/condiment/peppermill/on_reagent_change(changetype)
@@ -187,7 +184,7 @@
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
- list_reagents = list("milk" = 50)
+ list_reagents = list(/datum/reagent/consumable/milk = 50)
possible_states = list()
/obj/item/reagent_containers/food/condiment/flour
@@ -195,7 +192,7 @@
desc = "A big bag of flour. Good for baking!"
icon_state = "flour"
item_state = "flour"
- list_reagents = list("flour" = 30)
+ list_reagents = list(/datum/reagent/consumable/flour = 30)
possible_states = list()
/obj/item/reagent_containers/food/condiment/soymilk
@@ -205,7 +202,7 @@
item_state = "carton"
lefthand_file = 'icons/mob/inhands/equipment/kitchen_lefthand.dmi'
righthand_file = 'icons/mob/inhands/equipment/kitchen_righthand.dmi'
- list_reagents = list("soymilk" = 50)
+ list_reagents = list(/datum/reagent/consumable/soymilk = 50)
possible_states = list()
/obj/item/reagent_containers/food/condiment/rice
@@ -213,21 +210,21 @@
desc = "A big bag of rice. Good for cooking!"
icon_state = "rice"
item_state = "flour"
- list_reagents = list("rice" = 30)
+ list_reagents = list(/datum/reagent/consumable/rice = 30)
possible_states = list()
/obj/item/reagent_containers/food/condiment/soysauce
name = "soy sauce"
desc = "A salty soy-based flavoring."
icon_state = "soysauce"
- list_reagents = list("soysauce" = 50)
+ list_reagents = list(/datum/reagent/consumable/soysauce = 50)
possible_states = list()
/obj/item/reagent_containers/food/condiment/mayonnaise
name = "mayonnaise"
desc = "An oily condiment made from egg yolks."
icon_state = "mayonnaise"
- list_reagents = list("mayonnaise" = 50)
+ list_reagents = list(/datum/reagent/consumable/mayonnaise = 50)
possible_states = list()
@@ -241,7 +238,17 @@
volume = 10
amount_per_transfer_from_this = 10
possible_transfer_amounts = list()
- possible_states = list("ketchup" = list("condi_ketchup", "Ketchup", "You feel more American already."), "capsaicin" = list("condi_hotsauce", "Hotsauce", "You can almost TASTE the stomach ulcers now!"), "soysauce" = list("condi_soysauce", "Soy Sauce", "A salty soy-based flavoring"), "frostoil" = list("condi_frostoil", "Coldsauce", "Leaves the tongue numb in it's passage"), "sodiumchloride" = list("condi_salt", "Salt Shaker", "Salt. From space oceans, presumably"), "blackpepper" = list("condi_pepper", "Pepper Mill", "Often used to flavor food or make people sneeze"), "cornoil" = list("condi_cornoil", "Corn Oil", "A delicious oil used in cooking. Made from corn"), "sugar" = list("condi_sugar", "Sugar", "Tasty spacey sugar!"), "astrotame" = list("condi_astrotame", "Astrotame", "The sweetness of a thousand sugars but none of the calories."))
+ possible_states = list(/datum/reagent/consumable/ketchup = list("condi_ketchup", "Ketchup", "You feel more American already."),
+ /datum/reagent/consumable/capsaicin = list("condi_hotsauce", "Hotsauce", "You can almost TASTE the stomach ulcers now!"),
+ /datum/reagent/consumable/soysauce = list("condi_soysauce", "Soy Sauce", "A salty soy-based flavoring"),
+ /datum/reagent/consumable/frostoil = list("condi_frostoil", "Coldsauce", "Leaves the tongue numb in it's passage"),
+ /datum/reagent/consumable/sodiumchloride = list("condi_salt", "Salt Shaker", "Salt. From space oceans, presumably"),
+ /datum/reagent/consumable/blackpepper = list("condi_pepper", "Pepper Mill", "Often used to flavor food or make people sneeze"),
+ /datum/reagent/consumable/cornoil = list("condi_cornoil", "Corn Oil", "A delicious oil used in cooking. Made from corn"),
+ /datum/reagent/consumable/sugar = list("condi_sugar", "Sugar", "Tasty spacey sugar!"),
+ /datum/reagent/consumable/astrotame = list("condi_astrotame", "Astrotame", "The sweetness of a thousand sugars but none of the calories."),
+ /datum/reagent/consumable/mustard = list("condi_mustard", "Mustard", "A spice mixed with enzymes and water."),
+ /datum/reagent/consumable/bbqsauce = list("condi_bbq", "BBQ sauce", "Hand wipes not included."))
/obj/item/reagent_containers/food/condiment/pack/attack(mob/M, mob/user, def_zone) //Can't feed these to people directly.
return
@@ -284,20 +291,26 @@
/obj/item/reagent_containers/food/condiment/pack/ketchup
name = "ketchup pack"
originalname = "ketchup"
- list_reagents = list("ketchup" = 10)
+ list_reagents = list(/datum/reagent/consumable/ketchup = 10)
+
+//Mustard
+/obj/item/reagent_containers/food/condiment/pack/mustard
+ name = "mustard pack"
+ originalname = "mustard"
+ list_reagents = list(/datum/reagent/consumable/mustard = 10)
//Hot sauce
/obj/item/reagent_containers/food/condiment/pack/hotsauce
name = "hotsauce pack"
originalname = "hotsauce"
- list_reagents = list("capsaicin" = 10)
+ list_reagents = list(/datum/reagent/consumable/capsaicin = 10)
/obj/item/reagent_containers/food/condiment/pack/astrotame
name = "astrotame pack"
originalname = "astrotame"
- list_reagents = list("astrotame" = 5)
+ list_reagents = list(/datum/reagent/consumable/astrotame = 5)
/obj/item/reagent_containers/food/condiment/pack/bbqsauce
name = "bbq sauce pack"
originalname = "bbq sauce"
- list_reagents = list("bbqsauce" = 10)
+ list_reagents = list(/datum/reagent/consumable/bbqsauce = 10)
diff --git a/code/modules/food_and_drinks/food/customizables.dm b/code/modules/food_and_drinks/food/customizables.dm
index df5e6a87..2ad46b80 100644
--- a/code/modules/food_and_drinks/food/customizables.dm
+++ b/code/modules/food_and_drinks/food/customizables.dm
@@ -187,7 +187,7 @@
desc = "Delicious food on a stick."
ingredients_placement = INGREDIENTS_LINE
trash = /obj/item/stack/rods
- list_reagents = list("nutriment" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
ingMax = 6
icon_state = "rod"
@@ -302,7 +302,7 @@
else if(contents.len >= 20)
to_chat(user, "You can't add more ingredients to [src]!")
else
- if(reagents.has_reagent("water", 10)) //are we starting a soup or a salad?
+ if(reagents.has_reagent(/datum/reagent/water, 10)) //are we starting a soup or a salad?
var/obj/item/reagent_containers/food/snacks/customizable/A = new/obj/item/reagent_containers/food/snacks/customizable/soup(get_turf(src))
A.initialize_custom_food(src, S, user)
else
diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm
index 5be34a0e..be09a91d 100644
--- a/code/modules/food_and_drinks/food/snacks.dm
+++ b/code/modules/food_and_drinks/food/snacks.dm
@@ -19,11 +19,9 @@ Here is an example of the new formatting for anyone who wants to add more food i
name = "Xenoburger" //Name that displays in the UI.
desc = "Smells caustic. Tastes like heresy." //Duh
icon_state = "xburger" //Refers to an icon in food.dmi
-/obj/item/reagent_containers/food/snacks/xenoburger/Initialize() //Don't mess with this. | nO I WILL MESS WITH THIS
- . = ..() //Same here.
- reagents.add_reagent("xenomicrobes", 10) //This is what is in the food item. you may copy/paste
- reagents.add_reagent("nutriment", 2) //this line of code for all the contents.
- bitesize = 3 //This is the amount each bite consumes.
+ list_reagents = list(/datum/reagent/xenomicrobes = 10,
+ /datum/reagent/consumable/nutriment = 2) //What's inside the snack.
+ bitesize = 3 //This is the amount each bite consumes.
```
All foods are distributed among various categories. Use common sense.
@@ -62,7 +60,7 @@ All foods are distributed among various categories. Use common sense.
if(list_reagents)
for(var/rid in list_reagents)
var/amount = list_reagents[rid]
- if(rid == "nutriment" || rid == "vitamin")
+ if(rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin)
reagents.add_reagent(rid, amount, tastes.Copy())
else
reagents.add_reagent(rid, amount)
@@ -208,7 +206,7 @@ All foods are distributed among various categories. Use common sense.
if(bonus_reagents && bonus_reagents.len)
for(var/r_id in bonus_reagents)
var/amount = bonus_reagents[r_id]
- if(r_id == "nutriment" || r_id == "vitamin")
+ if(r_id == /datum/reagent/consumable/nutriment || r_id == /datum/reagent/consumable/nutriment/vitamin)
reagents.add_reagent(r_id, amount, tastes)
else
reagents.add_reagent(r_id, amount)
@@ -287,7 +285,7 @@ All foods are distributed among various categories. Use common sense.
if(S.bonus_reagents && S.bonus_reagents.len)
for(var/r_id in S.bonus_reagents)
var/amount = S.bonus_reagents[r_id] * cooking_efficiency
- if(r_id == "nutriment" || r_id == "vitamin")
+ if(r_id == /datum/reagent/consumable/nutriment || r_id == /datum/reagent/consumable/nutriment/vitamin)
S.reagents.add_reagent(r_id, amount, tastes)
else
S.reagents.add_reagent(r_id, amount)
diff --git a/code/modules/food_and_drinks/food/snacks/dough.dm b/code/modules/food_and_drinks/food/snacks/dough.dm
index 6ae8836b..e071fb3d 100644
--- a/code/modules/food_and_drinks/food/snacks/dough.dm
+++ b/code/modules/food_and_drinks/food/snacks/dough.dm
@@ -8,7 +8,7 @@
icon = 'icons/obj/food/food_ingredients.dmi'
icon_state = "dough"
cooked_type = /obj/item/reagent_containers/food/snacks/store/bread/plain
- list_reagents = list("nutriment" = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
w_class = WEIGHT_CLASS_NORMAL
tastes = list("dough" = 1)
foodtype = GRAIN
@@ -36,7 +36,7 @@
slice_path = /obj/item/reagent_containers/food/snacks/doughslice
slices_num = 3
cooked_type = /obj/item/reagent_containers/food/snacks/pizzabread
- list_reagents = list("nutriment" = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
w_class = WEIGHT_CLASS_NORMAL
tastes = list("dough" = 1)
foodtype = GRAIN
@@ -47,7 +47,7 @@
icon = 'icons/obj/food/food_ingredients.dmi'
icon_state = "pizzabread"
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/pizza
- list_reagents = list("nutriment" = 7)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7)
w_class = WEIGHT_CLASS_NORMAL
tastes = list("bread" = 1)
foodtype = GRAIN
@@ -69,7 +69,7 @@
desc = "A base for any self-respecting burger."
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "bun"
- list_reagents = list("nutriment" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/burger
filling_color = "#CD853F"
tastes = list("bun" = 1) // the bun tastes of bun.
@@ -81,7 +81,7 @@
icon = 'icons/obj/food/food_ingredients.dmi'
icon_state = "cakebatter"
cooked_type = /obj/item/reagent_containers/food/snacks/store/cake/plain
- list_reagents = list("nutriment" = 9)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 9)
w_class = WEIGHT_CLASS_NORMAL
tastes = list("batter" = 1)
foodtype = GRAIN | DAIRY
@@ -106,7 +106,7 @@
slice_path = /obj/item/reagent_containers/food/snacks/rawpastrybase
slices_num = 3
cooked_type = /obj/item/reagent_containers/food/snacks/pie/plain
- list_reagents = list("nutriment" = 9)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 9)
w_class = WEIGHT_CLASS_NORMAL
tastes = list("dough" = 1)
foodtype = GRAIN | DAIRY
@@ -118,7 +118,7 @@
icon_state = "rawpastrybase"
cooked_type = /obj/item/reagent_containers/food/snacks/pastrybase
filling_color = "#CD853F"
- list_reagents = list("nutriment" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
tastes = list("raw pastry" = 1)
foodtype = GRAIN | DAIRY
@@ -127,7 +127,7 @@
desc = "A base for any self-respecting pastry."
icon = 'icons/obj/food/food_ingredients.dmi'
icon_state = "pastrybase"
- list_reagents = list("nutriment" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
filling_color = "#CD853F"
tastes = list("pastry" = 1)
foodtype = GRAIN | DAIRY
diff --git a/code/modules/food_and_drinks/food/snacks/meat.dm b/code/modules/food_and_drinks/food/snacks/meat.dm
index 159f25f0..a62ab42d 100644
--- a/code/modules/food_and_drinks/food/snacks/meat.dm
+++ b/code/modules/food_and_drinks/food/snacks/meat.dm
@@ -8,7 +8,7 @@
icon_state = "meat"
dried_type = /obj/item/reagent_containers/food/snacks/sosjerky/healthy
bitesize = 3
- list_reagents = list("nutriment" = 3, "cooking_oil" = 2) //Meat has fats that a food processor can process into cooking oil
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/cooking_oil = 2) //Meat has fats that a food processor can process into cooking oil
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/plain
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/plain
slices_num = 3
@@ -63,7 +63,7 @@
icon_state = "crabmeatraw"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/crab
bitesize = 3
- list_reagents = list("nutriment" = 1, "cooking_oil" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/cooking_oil = 3)
filling_color = "#EAD079"
tastes = list("raw crab" = 1)
foodtype = RAW | MEAT
@@ -72,8 +72,8 @@
name = "crab meat"
desc = "Some deliciously cooked crab meat."
icon_state = "crabmeat"
- list_reagents = list("nutriment" = 2)
- bonus_reagents = list("nutriment" = 3, "vitamin" = 2, "cooking_oil" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/cooking_oil = 2)
filling_color = "#DFB73A"
tastes = list("crab" = 1)
foodtype = MEAT
@@ -88,7 +88,7 @@
/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
icon_state = "slimemeat"
desc = "Because jello wasn't offensive enough to vegans."
- list_reagents = list("nutriment" = 3, "slimejelly" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/toxin/slimejelly = 3)
filling_color = "#00FFFF"
tastes = list("slime" = 1, "jelly" = 1)
foodtype = MEAT | RAW | TOXIC
@@ -96,7 +96,7 @@
/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/golem
icon_state = "golemmeat"
desc = "Edible rocks, welcome to the future."
- list_reagents = list("nutriment" = 3, "iron" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/iron = 3)
filling_color = "#A9A9A9"
tastes = list("rock" = 1)
foodtype = MEAT | RAW | GROSS
@@ -131,7 +131,7 @@
/obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/fly
icon_state = "flymeat"
desc = "Nothing says tasty like maggot filled radioactive mutant flesh."
- list_reagents = list("nutriment" = 3, "uranium" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/uranium = 3)
tastes = list("maggots" = 1, "the inside of a reactor" = 1)
foodtype = MEAT | RAW | GROSS
@@ -192,7 +192,7 @@
name = "killer tomato meat"
desc = "A slice from a huge tomato."
icon_state = "tomatomeat"
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
filling_color = "#FF0000"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/killertomato
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/killertomato
@@ -203,7 +203,7 @@
name = "bear meat"
desc = "A very manly slab of meat."
icon_state = "bearmeat"
- list_reagents = list("nutriment" = 12, "morphine" = 5, "vitamin" = 2, "cooking_oil" = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 12, /datum/reagent/medicine/morphine = 5, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/cooking_oil = 6)
filling_color = "#FFB6C1"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/bear
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/bear
@@ -214,7 +214,7 @@
name = "xeno meat"
desc = "A slab of meat."
icon_state = "xenomeat"
- list_reagents = list("nutriment" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
bitesize = 4
filling_color = "#32CD32"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/xeno
@@ -226,7 +226,7 @@
name = "spider meat"
desc = "A slab of spider meat."
icon_state = "spidermeat"
- list_reagents = list("nutriment" = 3, "toxin" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/toxin = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#7CFC00"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/spider
slice_path = /obj/item/reagent_containers/food/snacks/meat/rawcutlet/spider
@@ -236,7 +236,7 @@
/obj/item/reagent_containers/food/snacks/meat/slab/goliath
name = "goliath meat"
desc = "A slab of goliath meat. It's not very edible now, but it cooks great in lava."
- list_reagents = list("nutriment" = 3, "toxin" = 5, "cooking_oil" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/toxin = 5, /datum/reagent/consumable/cooking_oil = 3)
icon_state = "goliathmeat"
tastes = list("meat" = 1)
foodtype = RAW | MEAT | TOXIC
@@ -249,7 +249,7 @@
/obj/item/reagent_containers/food/snacks/meat/slab/meatwheat
name = "meatwheat clump"
desc = "This doesn't look like meat, but your standards aren't that high to begin with."
- list_reagents = list("nutriment" = 3, "vitamin" = 2, "cooking_oil" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/cooking_oil = 1)
filling_color = rgb(150, 0, 0)
icon_state = "meatwheat_clump"
bitesize = 4
@@ -259,7 +259,7 @@
/obj/item/reagent_containers/food/snacks/meat/slab/gorilla
name = "gorilla meat"
desc = "Much meatier than monkey meat."
- list_reagents = list("nutriment" = 5, "vitamin" = 1, "cooking_oil" = 5) //Plenty of fat!
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1, /datum/reagent/consumable/cooking_oil = 5) //Plenty of fat!
/obj/item/reagent_containers/food/snacks/meat/rawbacon
name = "raw piece of bacon"
@@ -267,7 +267,7 @@
icon_state = "bacon"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/bacon
bitesize = 2
- list_reagents = list("nutriment" = 1, "cooking_oil" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/cooking_oil = 3)
filling_color = "#B22222"
tastes = list("bacon" = 1)
foodtype = RAW | MEAT
@@ -276,8 +276,8 @@
name = "piece of bacon"
desc = "A delicious piece of bacon."
icon_state = "baconcooked"
- list_reagents = list("nutriment" = 2)
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1, "cooking_oil" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1, /datum/reagent/consumable/cooking_oil = 2)
filling_color = "#854817"
tastes = list("bacon" = 1)
foodtype = MEAT | BREAKFAST
@@ -285,7 +285,7 @@
/obj/item/reagent_containers/food/snacks/meat/slab/gondola
name = "gondola meat"
desc = "According to legends of old, consuming raw gondola flesh grants one inner peace."
- list_reagents = list("nutriment" = 3, "tranquility" = 5, "cooking_oil" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/tranquility = 5, /datum/reagent/consumable/cooking_oil = 3)
tastes = list("meat" = 4, "tranquility" = 1)
filling_color = "#9A6750"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/steak/gondola
@@ -299,8 +299,8 @@
name = "steak"
desc = "A piece of hot spicy meat."
icon_state = "meatsteak"
- list_reagents = list("nutriment" = 5)
- bonus_reagents = list("nutriment" = 2, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
trash = /obj/item/trash/plate
filling_color = "#B22222"
foodtype = MEAT
@@ -361,7 +361,7 @@
icon_state = "rawcutlet"
cooked_type = /obj/item/reagent_containers/food/snacks/meat/cutlet/plain
bitesize = 2
- list_reagents = list("nutriment" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
filling_color = "#B22222"
tastes = list("meat" = 1)
var/meat_type = "meat"
@@ -425,8 +425,8 @@
desc = "A cooked meat cutlet."
icon_state = "cutlet"
bitesize = 2
- list_reagents = list("nutriment" = 2)
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#B22222"
tastes = list("meat" = 1)
foodtype = MEAT
diff --git a/code/modules/food_and_drinks/food/snacks_bread.dm b/code/modules/food_and_drinks/food/snacks_bread.dm
index 69f1a11b..b0644dc3 100644
--- a/code/modules/food_and_drinks/food/snacks_bread.dm
+++ b/code/modules/food_and_drinks/food/snacks_bread.dm
@@ -12,7 +12,7 @@
bitesize = 2
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/sandwich
filling_color = "#FFA500"
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
slot_flags = ITEM_SLOT_HEAD
customfoodfilling = 0 //to avoid infinite bread-ception
foodtype = GRAIN
@@ -22,8 +22,8 @@
name = "bread"
desc = "Some plain old earthen bread."
icon_state = "bread"
- bonus_reagents = list("nutriment" = 7)
- list_reagents = list("nutriment" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 7)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10)
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/bread
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/plain
tastes = list("bread" = 10)
@@ -41,8 +41,8 @@
desc = "The culinary base of every self-respecting eloquen/tg/entleman."
icon_state = "meatbread"
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/meat
- bonus_reagents = list("nutriment" = 5, "vitamin" = 10)
- list_reagents = list("nutriment" = 30, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 30, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("bread" = 10, "meat" = 10)
foodtype = GRAIN | MEAT
@@ -57,8 +57,8 @@
desc = "The culinary base of every self-respecting eloquen/tg/entleman. Extra Heretical."
icon_state = "xenomeatbread"
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/xenomeat
- bonus_reagents = list("nutriment" = 5, "vitamin" = 10)
- list_reagents = list("nutriment" = 30, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 30, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("bread" = 10, "acid" = 10)
foodtype = GRAIN | MEAT
@@ -67,7 +67,7 @@
desc = "A slice of delicious meatbread. Extra Heretical."
icon_state = "xenobreadslice"
filling_color = "#32CD32"
- list_reagents = list("nutriment" = 6, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/store/bread/spidermeat
@@ -75,8 +75,8 @@
desc = "Reassuringly green meatloaf made from spider meat."
icon_state = "spidermeatbread"
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/spidermeat
- bonus_reagents = list("nutriment" = 5, "vitamin" = 10)
- list_reagents = list("nutriment" = 30, "toxin" = 15, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 30, /datum/reagent/toxin = 15, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("bread" = 10, "cobwebs" = 5)
foodtype = GRAIN | MEAT | TOXIC
@@ -85,7 +85,7 @@
desc = "A slice of meatloaf made from an animal that most likely still wants you dead."
icon_state = "xenobreadslice"
filling_color = "#7CFC00"
- list_reagents = list("nutriment" = 6, "toxin" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/toxin = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | MEAT | TOXIC
/obj/item/reagent_containers/food/snacks/store/bread/banana
@@ -93,8 +93,8 @@
desc = "A heavenly and filling treat."
icon_state = "bananabread"
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/banana
- bonus_reagents = list("nutriment" = 5, "banana" = 20)
- list_reagents = list("nutriment" = 20, "banana" = 20)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/banana = 20)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/consumable/banana = 20)
tastes = list("bread" = 10) // bananjuice will also flavour
foodtype = GRAIN | FRUIT
@@ -104,7 +104,7 @@
desc = "A slice of delicious banana bread."
icon_state = "bananabreadslice"
filling_color = "#FFD700"
- list_reagents = list("nutriment" = 4, "banana" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/banana = 4)
foodtype = GRAIN | FRUIT
/obj/item/reagent_containers/food/snacks/store/bread/tofu
@@ -112,8 +112,8 @@
desc = "Like meatbread but for vegetarians. Not guaranteed to give superpowers."
icon_state = "tofubread"
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/tofu
- bonus_reagents = list("nutriment" = 5, "vitamin" = 10)
- list_reagents = list("nutriment" = 20, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("bread" = 10, "tofu" = 10)
foodtype = GRAIN | VEGETABLES
@@ -122,7 +122,7 @@
desc = "A slice of delicious tofubread."
icon_state = "tofubreadslice"
filling_color = "#FF8C00"
- list_reagents = list("nutriment" = 4, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | VEGETABLES
/obj/item/reagent_containers/food/snacks/store/bread/creamcheese
@@ -130,8 +130,8 @@
desc = "Yum yum yum!"
icon_state = "creamcheesebread"
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/creamcheese
- bonus_reagents = list("nutriment" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 20, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("bread" = 10, "cheese" = 10)
foodtype = GRAIN | DAIRY
@@ -140,7 +140,7 @@
desc = "A slice of yum!"
icon_state = "creamcheesebreadslice"
filling_color = "#FF8C00"
- list_reagents = list("nutriment" = 4, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | DAIRY
/obj/item/reagent_containers/food/snacks/store/bread/mimana
@@ -148,8 +148,8 @@
desc = "Best eaten in silence."
icon_state = "mimanabread"
slice_path = /obj/item/reagent_containers/food/snacks/breadslice/mimana
- bonus_reagents = list("nutriment" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 20, "mutetoxin" = 5, "nothing" = 5, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/toxin/mutetoxin = 5, /datum/reagent/consumable/nothing = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("bread" = 10, "silence" = 10)
foodtype = GRAIN | FRUIT
@@ -158,7 +158,7 @@
desc = "A slice of silence!"
icon_state = "mimanabreadslice"
filling_color = "#C0C0C0"
- list_reagents = list("nutriment" = 2, "mutetoxin" = 1, "nothing" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin/mutetoxin = 1, /datum/reagent/consumable/nothing = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | FRUIT
/obj/item/reagent_containers/food/snacks/breadslice/custom
@@ -172,8 +172,8 @@
desc = "Bon appetit!"
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "baguette"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
bitesize = 3
w_class = WEIGHT_CLASS_NORMAL
tastes = list("bread" = 1)
@@ -201,12 +201,12 @@
GLOBAL_VAR_INIT(frying_hardmode, TRUE)
GLOBAL_VAR_INIT(frying_bad_chem_add_volume, TRUE)
GLOBAL_LIST_INIT(frying_bad_chems, list(
-"bad_food" = 10,
-"clf3" = 2,
-"aranesp" = 2,
-"blackpowder" = 10,
-"phlogiston" = 3,
-"cyanide" = 3,
+/datum/reagent/toxin/bad_food = 10,
+/datum/reagent/clf3 = 2,
+/datum/reagent/drug/aranesp = 2,
+/datum/reagent/blackpowder = 10,
+/datum/reagent/phlogiston = 3,
+/datum/reagent/toxin/cyanide = 3,
))
/obj/item/reagent_containers/food/snacks/deepfryholder/Initialize(mapload, obj/item/fried)
@@ -280,8 +280,8 @@ GLOBAL_LIST_INIT(frying_bad_chems, list(
icon_state = "butteredtoast"
bitesize = 3
filling_color = "#FFA500"
- list_reagents = list("nutriment" = 4)
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("butter" = 1, "toast" = 1)
foodtype = GRAIN | BREAKFAST
@@ -291,8 +291,8 @@ GLOBAL_LIST_INIT(frying_bad_chems, list(
icon = 'icons/obj/food/food.dmi'
icon_state = "butterbiscuit"
filling_color = "#F0E68C"
- list_reagents = list("nutriment" = 5)
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("butter" = 1, "biscuit" = 1)
foodtype = GRAIN | BREAKFAST
@@ -303,8 +303,8 @@ GLOBAL_LIST_INIT(frying_bad_chems, list(
icon_state = "butterdog"
bitesize = 1
filling_color = "#F1F49A"
- list_reagents = list("nutriment" = 5)
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("butter", "exotic butter")
/obj/item/reagent_containers/food/snacks/butterdog/ComponentInitialize()
diff --git a/code/modules/food_and_drinks/food/snacks_burgers.dm b/code/modules/food_and_drinks/food/snacks_burgers.dm
index 1935a2de..515da570 100644
--- a/code/modules/food_and_drinks/food/snacks_burgers.dm
+++ b/code/modules/food_and_drinks/food/snacks_burgers.dm
@@ -3,14 +3,14 @@
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "hburger"
bitesize = 3
- list_reagents = list("nutriment" = 6, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("bun" = 4)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/plain
name = "burger"
desc = "The cornerstone of every nutritious breakfast."
- bonus_reagents = list("vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/plain/Initialize()
@@ -31,7 +31,7 @@
var/subjectjob = null
name = "human burger"
desc = "A bloody burger."
- bonus_reagents = list("vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 4)
foodtype = MEAT | GRAIN | GROSS
/obj/item/reagent_containers/food/snacks/burger/human/CheckParts(list/parts_list)
@@ -50,13 +50,13 @@
/obj/item/reagent_containers/food/snacks/burger/corgi
name = "corgi burger"
desc = "You monster."
- bonus_reagents = list("vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | MEAT | GROSS
/obj/item/reagent_containers/food/snacks/burger/appendix
name = "appendix burger"
desc = "Tastes like appendicitis."
- bonus_reagents = list("nutriment" = 6, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 6)
icon_state = "appendixburger"
tastes = list("bun" = 4, "grass" = 2)
foodtype = GRAIN | MEAT | GROSS
@@ -65,7 +65,7 @@
name = "fillet -o- carp sandwich"
desc = "Almost like a carp is yelling somewhere... Give me back that fillet -o- carp, give me that carp."
icon_state = "fishburger"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("bun" = 4, "fish" = 4)
foodtype = GRAIN | MEAT
@@ -73,7 +73,7 @@
name = "tofu burger"
desc = "What.. is that meat?"
icon_state = "tofuburger"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("bun" = 4, "tofu" = 4)
foodtype = GRAIN | VEGETABLES
@@ -81,8 +81,8 @@
name = "roburger"
desc = "The lettuce is the only organic component. Beep."
icon_state = "roburger"
- bonus_reagents = list("nutriment" = 2, "nanomachines" = 2, "vitamin" = 5)
- list_reagents = list("nutriment" = 6, "nanomachines" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/nanomachines = 2, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/nanomachines = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("bun" = 4, "lettuce" = 2, "sludge" = 1)
foodtype = GRAIN | TOXIC
@@ -91,8 +91,8 @@
desc = "This massive patty looks like poison. Beep."
icon_state = "roburger"
volume = 120
- bonus_reagents = list("nutriment" = 5, "nanomachines" = 70, "vitamin" = 10)
- list_reagents = list("nutriment" = 6, "nanomachines" = 70, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/nanomachines = 70, /datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/nanomachines = 70, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("bun" = 4, "lettuce" = 2, "sludge" = 1)
foodtype = GRAIN | TOXIC
@@ -100,7 +100,7 @@
name = "xenoburger"
desc = "Smells caustic. Tastes like heresy."
icon_state = "xburger"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("bun" = 4, "acid" = 4)
foodtype = GRAIN | MEAT
@@ -108,29 +108,29 @@
name = "bearger"
desc = "Best served rawr."
icon_state = "bearger"
- bonus_reagents = list("nutriment" = 3, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 6)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/clown
name = "clown burger"
desc = "This tastes funny..."
icon_state = "clownburger"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 6, "banana" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 6, /datum/reagent/consumable/banana = 6)
foodtype = GRAIN | FRUIT
/obj/item/reagent_containers/food/snacks/burger/mime
name = "mime burger"
desc = "Its taste defies language."
icon_state = "mimeburger"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 6, "nothing" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 6, /datum/reagent/consumable/nothing = 6)
foodtype = GRAIN
/obj/item/reagent_containers/food/snacks/burger/brain
name = "brainburger"
desc = "A strange looking burger. It looks almost sentient."
icon_state = "brainburger"
- bonus_reagents = list("nutriment" = 6, "mannitol" = 6, "vitamin" = 5)
- list_reagents = list("nutriment" = 6, "mannitol" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/medicine/mannitol = 6, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/medicine/mannitol = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("bun" = 4, "brains" = 2)
foodtype = GRAIN | MEAT | GROSS
@@ -139,7 +139,7 @@
name = "ghost burger"
desc = "Too Spooky!"
icon_state = "ghostburger"
- bonus_reagents = list("nutriment" = 5, "vitamin" = 12)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 12)
tastes = list("bun" = 4, "ectoplasm" = 2)
foodtype = GRAIN
alpha = 170
@@ -188,7 +188,7 @@
desc = "Perfect for hiding the fact it's burnt to a crisp."
icon_state = "cburger"
color = "#DA0000FF"
- bonus_reagents = list("redcrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/red = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/orange
@@ -196,7 +196,7 @@
desc = "Contains 0% juice."
icon_state = "cburger"
color = "#FF9300FF"
- bonus_reagents = list("orangecrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/orange = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/yellow
@@ -204,7 +204,7 @@
desc = "Bright to the last bite."
icon_state = "cburger"
color = "#FFF200FF"
- bonus_reagents = list("yellowcrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/yellow = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/green
@@ -212,7 +212,7 @@
desc = "It's not tainted meat, it's painted meat!"
icon_state = "cburger"
color = "#A8E61DFF"
- bonus_reagents = list("greencrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/green = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/blue
@@ -220,7 +220,7 @@
desc = "Is this blue rare?"
icon_state = "cburger"
color = "#00B7EFFF"
- bonus_reagents = list("bluecrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/blue = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/purple
@@ -228,7 +228,7 @@
desc = "Regal and low class at the same time."
icon_state = "cburger"
color = "#DA00FFFF"
- bonus_reagents = list("purplecrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/purple = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/black
@@ -236,7 +236,7 @@
desc = "This is overcooked."
icon_state = "cburger"
color = "#1C1C1C"
- bonus_reagents = list("blackcrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/black = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/white
@@ -244,14 +244,14 @@
desc = "Delicous Titanium!"
icon_state = "cburger"
color = "#FFFFFF"
- bonus_reagents = list("whitecrayonpowder" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/colorful_reagent/crayonpowder/white = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/spell
name = "spell burger"
desc = "This is absolutely Ei Nath."
icon_state = "spellburger"
- bonus_reagents = list("nutriment" = 6, "vitamin" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 10)
tastes = list("bun" = 4, "magic" = 2)
foodtype = GRAIN | MEAT
@@ -259,8 +259,8 @@
name = "big bite burger"
desc = "Forget the Big Mac. THIS is the future!"
icon_state = "bigbiteburger"
- bonus_reagents = list("vitamin" = 6)
- list_reagents = list("nutriment" = 10, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 2)
w_class = WEIGHT_CLASS_NORMAL
foodtype = GRAIN | MEAT
@@ -272,21 +272,21 @@
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/jelly/slime
- bonus_reagents = list("slimejelly" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 6, "slimejelly" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | TOXIC
/obj/item/reagent_containers/food/snacks/burger/jelly/cherry
- bonus_reagents = list("cherryjelly" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 6, "cherryjelly" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | FRUIT
/obj/item/reagent_containers/food/snacks/burger/superbite
name = "super bite burger"
desc = "This is a mountain of a burger. FOOD!"
icon_state = "superbiteburger"
- bonus_reagents = list("vitamin" = 10)
- list_reagents = list("nutriment" = 40, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 40, /datum/reagent/consumable/nutriment/vitamin = 5)
w_class = WEIGHT_CLASS_NORMAL
bitesize = 7
volume = 100
@@ -297,29 +297,29 @@
name = "five alarm burger"
desc = "HOT! HOT!"
icon_state = "fivealarmburger"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 5)
- list_reagents = list("nutriment" = 6, "capsaicin" = 5, "condensedcapsaicin" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/capsaicin = 5, /datum/reagent/consumable/condensedcapsaicin = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | MEAT
/obj/item/reagent_containers/food/snacks/burger/rat
name = "rat burger"
desc = "Pretty much what you'd expect..."
icon_state = "ratburger"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | MEAT | GROSS
/obj/item/reagent_containers/food/snacks/burger/baseball
name = "home run baseball burger"
desc = "It's still warm. The steam coming off of it looks like baseball."
icon_state = "baseball"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
foodtype = GRAIN | GROSS
/obj/item/reagent_containers/food/snacks/burger/baconburger
name = "bacon burger"
desc = "The perfect combination of all things American."
icon_state = "baconburger"
- bonus_reagents = list("nutriment" = 8, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("bun" = 4, "bacon" = 2)
foodtype = GRAIN | MEAT
@@ -328,13 +328,14 @@
desc = "A sticky and salty burger."
icon_state = "cumburger"
tastes = list("bun" = 4, "salt" = 5)
- bonus_reagents = list("nutriment" = 3, "vitamin" = 10, "semen" = 10, "aphro" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/semen = 10, /datum/reagent/drug/anaphrodisiac = 3)
foodtype = GRAIN
+
/obj/item/reagent_containers/food/snacks/burger/soylent
name = "soylent burger"
desc = "A eco-friendly burger made using upcycled low value biomass."
icon_state = "soylentburger"
- bonus_reagents = list("nutriment" = 5, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("bun" = 2, "assistant" = 4)
foodtype = GRAIN | MEAT | DAIRY
@@ -342,7 +343,7 @@
name = "mcrib"
desc = "An elusive rib shaped burger with limited availablity across the galaxy. Not as good as you remember it."
icon_state = "mcrib"
- bonus_reagents = list("bbqsauce" = 5, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/bbqsauce = 5, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("bun" = 2, "pork patty" = 4)
foodtype = GRAIN | MEAT
@@ -351,7 +352,7 @@
desc = "A cheap and greasy imitation of an eggs benedict."
icon_state = "mcguffin"
tastes = list("muffin" = 2, "bacon" = 3)
- bonus_reagents = list("eggyolk" = 3, "nutriment" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/eggyolk = 3, /datum/reagent/consumable/nutriment = 1)
foodtype = GRAIN | MEAT | BREAKFAST
/obj/item/reagent_containers/food/snacks/burger/chicken
@@ -359,7 +360,7 @@
desc = "A delicious chicken sandwich, it is said the proceeds from this treat helps criminalize homosexuality on the space frontier."
icon_state = "chickenburger"
tastes = list("bun" = 2, "chicken" = 4, "God's covenant" = 1)
- bonus_reagents = list("mayonnaise" = 3, "cooking_oil" = 2, "nutriment" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/mayonnaise = 3, /datum/reagent/consumable/cooking_oil = 2, /datum/reagent/consumable/nutriment = 2)
foodtype = GRAIN | MEAT | FRIED
/obj/item/reagent_containers/food/snacks/burger/cheese
@@ -367,7 +368,7 @@
desc = "This noble burger stands proudly clad in golden cheese."
icon_state = "cheeseburger"
tastes = list("bun" = 2, "beef patty" = 4, "cheese" = 3)
- bonus_reagents = list("nutriment" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1)
foodtype = GRAIN | MEAT | DAIRY
/obj/item/reagent_containers/food/snacks/burger/cheese/Initialize()
diff --git a/code/modules/food_and_drinks/food/snacks_cake.dm b/code/modules/food_and_drinks/food/snacks_cake.dm
index 1b24512f..e08e8f3e 100644
--- a/code/modules/food_and_drinks/food/snacks_cake.dm
+++ b/code/modules/food_and_drinks/food/snacks_cake.dm
@@ -4,14 +4,14 @@
slices_num = 5
bitesize = 3
volume = 80
- list_reagents = list("nutriment" = 20, "vitamin" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("cake" = 1)
foodtype = GRAIN | DAIRY
/obj/item/reagent_containers/food/snacks/cakeslice
icon = 'icons/obj/food/piecake.dmi'
trash = /obj/item/trash/plate
- list_reagents = list("nutriment" = 4, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1)
customfoodfilling = 0 //to avoid infinite cake-ception
tastes = list("cake" = 1)
foodtype = GRAIN | DAIRY
@@ -21,7 +21,7 @@
desc = "A plain cake, not a lie."
icon_state = "plaincake"
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/cake
- bonus_reagents = list("nutriment" = 10, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("sweetness" = 2,"cake" = 5)
foodtype = GRAIN | DAIRY | SUGAR
@@ -40,8 +40,8 @@
icon_state = "carrotcake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/carrot
slices_num = 5
- bonus_reagents = list("nutriment" = 3, "oculine" = 5, "vitamin" = 10)
- list_reagents = list("nutriment" = 20, "oculine" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/medicine/oculine = 5, /datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/medicine/oculine = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("cake" = 5, "sweetness" = 2, "carrot" = 1)
foodtype = GRAIN | DAIRY | VEGETABLES | SUGAR
@@ -50,7 +50,7 @@
desc = "Carrotty slice of Carrot Cake, carrots are good for your eyes! Also not a lie."
icon_state = "carrotcake_slice"
filling_color = "#FFA500"
- list_reagents = list("nutriment" = 4, "oculine" = 2, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/medicine/oculine = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("cake" = 5, "sweetness" = 2, "carrot" = 1)
foodtype = GRAIN | DAIRY | VEGETABLES | SUGAR
@@ -60,8 +60,8 @@
icon_state = "braincake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/brain
slices_num = 5
- bonus_reagents = list("nutriment" = 5, "mannitol" = 10, "vitamin" = 10)
- list_reagents = list("nutriment" = 20, "mannitol" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/medicine/mannitol = 10, /datum/reagent/consumable/nutriment/vitamin = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/medicine/mannitol = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("cake" = 5, "sweetness" = 2, "brains" = 1)
foodtype = GRAIN | DAIRY | MEAT | GROSS | SUGAR
@@ -71,7 +71,7 @@
desc = "Lemme tell you something about prions. THEY'RE DELICIOUS."
icon_state = "braincakeslice"
filling_color = "#FF69B4"
- list_reagents = list("nutriment" = 4, "mannitol" = 2, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/medicine/mannitol = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("cake" = 5, "sweetness" = 2, "brains" = 1)
foodtype = GRAIN | DAIRY | MEAT | GROSS | SUGAR
@@ -81,7 +81,7 @@
icon_state = "cheesecake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/cheese
slices_num = 5
- bonus_reagents = list("vitamin" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 10)
tastes = list("cake" = 4, "cream cheese" = 3)
foodtype = GRAIN | DAIRY
@@ -99,7 +99,7 @@
icon_state = "orangecake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/orange
slices_num = 5
- bonus_reagents = list("nutriment" = 3, "vitamin" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 10)
tastes = list("cake" = 5, "sweetness" = 2, "oranges" = 2)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
@@ -117,7 +117,7 @@
icon_state = "limecake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/lime
slices_num = 5
- bonus_reagents = list("nutriment" = 3, "vitamin" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 10)
tastes = list("cake" = 5, "sweetness" = 2, "unbearable sourness" = 2)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
@@ -135,7 +135,7 @@
icon_state = "lemoncake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/lemon
slices_num = 5
- bonus_reagents = list("nutriment" = 3, "vitamin" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 10)
tastes = list("cake" = 5, "sweetness" = 2, "sourness" = 2)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
@@ -153,7 +153,7 @@
icon_state = "chocolatecake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/chocolate
slices_num = 5
- bonus_reagents = list("nutriment" = 3, "vitamin" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 10)
tastes = list("cake" = 5, "sweetness" = 1, "chocolate" = 4)
foodtype = GRAIN | DAIRY | JUNKFOOD | SUGAR
@@ -171,8 +171,8 @@
icon_state = "birthdaycake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/birthday
slices_num = 5
- bonus_reagents = list("nutriment" = 7, "sprinkles" = 10, "vitamin" = 5)
- list_reagents = list("nutriment" = 20, "sprinkles" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/sprinkles = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 20, /datum/reagent/consumable/sprinkles = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("cake" = 5, "sweetness" = 1)
foodtype = GRAIN | DAIRY | JUNKFOOD | SUGAR
@@ -181,7 +181,7 @@
desc = "A slice of your birthday."
icon_state = "birthdaycakeslice"
filling_color = "#DC143C"
- list_reagents = list("nutriment" = 4, "sprinkles" = 2, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/sprinkles = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("cake" = 5, "sweetness" = 1)
foodtype = GRAIN | DAIRY | JUNKFOOD | SUGAR
@@ -191,7 +191,7 @@
icon_state = "applecake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/apple
slices_num = 5
- bonus_reagents = list("nutriment" = 3, "vitamin" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 10)
tastes = list("cake" = 5, "sweetness" = 1, "apple" = 1)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
@@ -214,7 +214,7 @@
desc = "A cake made of slimes. Probably not electrified."
icon_state = "slimecake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/slimecake
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("cake" = 5, "sweetness" = 1, "slime" = 1)
foodtype = GRAIN | DAIRY | SUGAR
@@ -231,7 +231,7 @@
desc = "A hollow cake with real pumpkin."
icon_state = "pumpkinspicecake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/pumpkinspice
- bonus_reagents = list("nutriment" = 3, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("cake" = 5, "sweetness" = 1, "pumpkin" = 1)
foodtype = GRAIN | DAIRY | VEGETABLES | SUGAR
@@ -248,7 +248,7 @@
desc = "A plain cake, filled with assortment of blackberries and strawberries!"
icon_state = "blackbarry_strawberries_cake_vanilla_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/bsvc
- bonus_reagents = list("nutriment" = 14, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 14, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("blackbarry" = 2, "strawberries" = 2, "vanilla" = 2, "sweetness" = 2, "cake" = 3)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
@@ -265,7 +265,7 @@
desc = "A plain cake, filled with assortment of blackberries and strawberries!"
icon_state = "blackbarry_strawberries_cake_coco_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/bscc
- bonus_reagents = list("nutriment" = 14, "vitamin" = 4, "cocoa" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 14, /datum/reagent/consumable/nutriment/vitamin = 4, /datum/reagent/consumable/coco = 5)
tastes = list("blackberry" = 2, "strawberries" = 2, "chocolate" = 2, "sweetness" = 2,"cake" = 3)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
@@ -282,7 +282,7 @@
desc = "A cake made for angels and chaplains alike! Contains holy water."
icon_state = "holy_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/holy_cake_slice
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3, "holy_water" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3, /datum/reagent/water/holywater = 10)
tastes = list("cake" = 5, "sweetness" = 1, "clouds" = 1)
foodtype = GRAIN | DAIRY | SUGAR
@@ -300,7 +300,7 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake
icon_state = "pound_cake"
slices_num = 7 //Its ment to feed the party
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/pound_cake_slice
- bonus_reagents = list("nutriment" = 60)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 60)
tastes = list("cake" = 5, "sweetness" = 1, "batter" = 1)
foodtype = GRAIN | DAIRY | SUGAR | JUNKFOOD
@@ -317,7 +317,7 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake
desc = "A cake that is made with electronic boards and leaks acid..."
icon_state = "hardware_cake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/hardware_cake_slice
- bonus_reagents = list("sacid" = 15, "oil" = 15)
+ bonus_reagents = list(/datum/reagent/toxin/acid = 15, /datum/reagent/oil = 15)
tastes = list("acid" = 1, "metal" = 1, "regret" = 10)
foodtype = GRAIN | GROSS
@@ -334,8 +334,8 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake
desc = "A vanilla frosted cake."
icon_state = "vanillacake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/vanilla_slice
- bonus_reagents = list("sugar" = 15, "vanilla" = 15)
- tastes = list("caje" = 1, "sugar" = 1, "vanilla" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/sugar = 15, /datum/reagent/consumable/vanilla = 15)
+ tastes = list("cake" = 1, "sugar" = 1, "vanilla" = 10)
foodtype = GRAIN | SUGAR | DAIRY
/obj/item/reagent_containers/food/snacks/cakeslice/vanilla_slice
@@ -351,7 +351,7 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake
desc = "A funny cake with a clown face on it."
icon_state = "clowncake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/clown_slice
- bonus_reagents = list("sugar" = 15, "laugher" = 15)
+ bonus_reagents = list(/datum/reagent/consumable/sugar = 15, /datum/reagent/consumable/laughter = 15)
tastes = list("cake" = 1, "sugar" = 1, "joy" = 10)
foodtype = GRAIN | SUGAR | DAIRY
@@ -368,7 +368,7 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake
desc = "A peach filled cake."
icon_state = "peachcake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/peach_slice
- bonus_reagents = list("sugar" = 5, "peachjuice" = 15)
+ bonus_reagents = list(/datum/reagent/consumable/sugar = 5, /datum/reagent/consumable/peachjuice = 15)
tastes = list("cake" = 1, "sugar" = 1, "peachjuice" = 10)
foodtype = GRAIN | SUGAR | DAIRY
@@ -385,7 +385,7 @@ obj/item/reagent_containers/food/snacks/store/cake/pound_cake
desc = "A spaceman's trumpet frosted cake."
icon_state = "trumpetcake"
slice_path = /obj/item/reagent_containers/food/snacks/cakeslice/trumpet
- bonus_reagents = list("polypyr" = 15, "cream" = 5, "vitamin" = 5, "berryjuice" = 5)
+ bonus_reagents = list(/datum/reagent/medicine/polypyr = 15, /datum/reagent/consumable/cream = 5, /datum/reagent/consumable/nutriment/vitamin = 5, /datum/reagent/consumable/berryjuice = 5)
filling_color = "#7A3D80"
tastes = list("cake" = 4, "violets" = 2, "jam" = 2)
foodtype = GRAIN | DAIRY | FRUIT | SUGAR
diff --git a/code/modules/food_and_drinks/food/snacks_egg.dm b/code/modules/food_and_drinks/food/snacks_egg.dm
index 273168fb..f01966a0 100644
--- a/code/modules/food_and_drinks/food/snacks_egg.dm
+++ b/code/modules/food_and_drinks/food/snacks_egg.dm
@@ -5,8 +5,8 @@
name = "chocolate egg"
desc = "Such, sweet, fattening food."
icon_state = "chocolateegg"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 4, "sugar" = 2, "cocoa" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/sugar = 2, /datum/reagent/consumable/coco = 2)
filling_color = "#A0522D"
tastes = list("chocolate" = 4, "sweetness" = 1)
foodtype = JUNKFOOD | SUGAR
@@ -15,7 +15,7 @@
name = "egg"
desc = "An egg!"
icon_state = "egg"
- list_reagents = list("eggyolk" = 5)
+ list_reagents = list(/datum/reagent/consumable/eggyolk = 5)
cooked_type = /obj/item/reagent_containers/food/snacks/boiledegg
filling_color = "#F0E68C"
foodtype = MEAT
@@ -89,10 +89,10 @@
name = "fried egg"
desc = "A fried egg, with a touch of salt and pepper."
icon_state = "friedegg"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
bitesize = 1
filling_color = "#FFFFF0"
- list_reagents = list("nutriment" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3)
tastes = list("egg" = 4, "salt" = 1, "pepper" = 1)
foodtype = MEAT | FRIED | BREAKFAST
@@ -100,9 +100,9 @@
name = "boiled egg"
desc = "A hard boiled egg."
icon_state = "egg"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#FFFFF0"
- list_reagents = list("nutriment" = 2, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("egg" = 1)
foodtype = MEAT | BREAKFAST
@@ -111,8 +111,8 @@
desc = "That's all you can say!"
icon_state = "omelette"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 8, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 1)
bitesize = 1
w_class = WEIGHT_CLASS_NORMAL
tastes = list("egg" = 1, "cheese" = 1)
@@ -129,7 +129,7 @@
"You take a piece of omelette with your fork.")
var/datum/reagent/R = pick(reagents.reagent_list)
- reagents.remove_reagent(R.id, 1)
+ reagents.remove_reagent(R.type, 1)
F.forkload = R
if(reagents.total_volume <= 0)
qdel(src)
@@ -140,9 +140,9 @@
name = "eggs benedict"
desc = "There is only one egg on this, how rude."
icon_state = "benedict"
- bonus_reagents = list("vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 4)
trash = /obj/item/trash/plate
w_class = WEIGHT_CLASS_NORMAL
- list_reagents = list("nutriment" = 6, "vitamin" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("egg" = 1, "bacon" = 1, "bun" = 1)
foodtype = MEAT | BREAKFAST
diff --git a/code/modules/food_and_drinks/food/snacks_frozen.dm b/code/modules/food_and_drinks/food/snacks_frozen.dm
index 45e5dbe7..8de7e170 100644
--- a/code/modules/food_and_drinks/food/snacks_frozen.dm
+++ b/code/modules/food_and_drinks/food/snacks_frozen.dm
@@ -3,8 +3,8 @@
desc = "Portable Ice-cream in its own packaging."
icon = 'icons/obj/food/food.dmi'
icon_state = "icecreamsandwich"
- bonus_reagents = list("nutriment" = 1, "ice" = 2)
- list_reagents = list("nutriment" = 2, "ice" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/ice = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/ice = 2)
tastes = list("ice cream" = 1)
foodtype = GRAIN | DAIRY
@@ -12,8 +12,8 @@
name = "sundae"
desc = "A classic dessert."
icon_state = "sundae"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 1)
- list_reagents = list("nutriment" = 6, "banana" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/banana = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#FFFACD"
tastes = list("ice cream" = 1, "banana" = 1)
foodtype = FRUIT | DAIRY | SUGAR
@@ -22,8 +22,8 @@
name = "honkdae"
desc = "The clown's favorite dessert."
icon_state = "honkdae"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "banana" = 10, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/banana = 10, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#FFFACD"
tastes = list("ice cream" = 1, "banana" = 1, "a bad joke" = 1)
foodtype = FRUIT | DAIRY | SUGAR
@@ -32,8 +32,8 @@
name = "space freezy"
desc = "The best icecream in space."
icon_state = "spacefreezy"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "bluecherryjelly" = 5, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/bluecherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#87CEFA"
tastes = list("blue cherries" = 2, "ice cream" = 2)
foodtype = FRUIT | DAIRY
@@ -47,8 +47,8 @@
icon = 'icons/obj/food/snowcones.dmi'
icon_state = "flavorless_sc"
trash = /obj/item/reagent_containers/food/drinks/sillycup //We dont eat paper cups
- bonus_reagents = list("water" = 10) //Base line will allways give water
- list_reagents = list("water" = 1) // We dont get food for water/juices
+ bonus_reagents = list(/datum/reagent/water = 10) //Base line will allways give water
+ list_reagents = list(/datum/reagent/water = 1) // We dont get food for water/juices
filling_color = "#FFFFFF" //Ice is white
tastes = list("ice" = 1, "water" = 1)
foodtype = SUGAR //We use SUGAR as a base line to act in as junkfood, other wise we use fruit
@@ -57,7 +57,7 @@
name = "lime snowcone"
desc = "Lime syrup drizzled over a snowball in a paper cup."
icon_state = "lime_sc"
- list_reagents = list("nutriment" = 1, "limejuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/limejuice = 5)
tastes = list("ice" = 1, "water" = 1, "limes" = 5)
foodtype = FRUIT
@@ -65,7 +65,7 @@
name = "lemon snowcone"
desc = "Lemon syrup drizzled over a snowball in a paper cup."
icon_state = "lemon_sc"
- list_reagents = list("nutriment" = 1, "lemonjuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/lemonjuice = 5)
tastes = list("ice" = 1, "water" = 1, "lemons" = 5)
foodtype = FRUIT
@@ -73,7 +73,7 @@
name = "apple snowcone"
desc = "Apple syrup drizzled over a snowball in a paper cup."
icon_state = "amber_sc"
- list_reagents = list("nutriment" = 1, "applejuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/applejuice = 5)
tastes = list("ice" = 1, "water" = 1, "apples" = 5)
foodtype = FRUIT
@@ -81,7 +81,7 @@
name = "grape snowcone"
desc = "Grape syrup drizzled over a snowball in a paper cup."
icon_state = "grape_sc"
- list_reagents = list("nutriment" = 1, "grapejuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/grapejuice = 5)
tastes = list("ice" = 1, "water" = 1, "grape" = 5)
foodtype = FRUIT
@@ -89,7 +89,7 @@
name = "orange snowcone"
desc = "Orange syrup drizzled over a snowball in a paper cup."
icon_state = "orange_sc"
- list_reagents = list("nutriment" = 1, "orangejuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/orangejuice = 5)
tastes = list("ice" = 1, "water" = 1, "orange" = 5)
foodtype = FRUIT
@@ -97,7 +97,7 @@
name = "bluecherry snowcone"
desc = "Bluecherry syrup drizzled over a snowball in a paper cup, how rare!"
icon_state = "blue_sc"
- list_reagents = list("nutriment" = 1, "bluecherryjelly" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/bluecherryjelly = 5)
tastes = list("ice" = 1, "water" = 1, "blue" = 5, "cherries" = 5)
foodtype = FRUIT
@@ -105,7 +105,7 @@
name = "cherry snowcone"
desc = "Cherry syrup drizzled over a snowball in a paper cup."
icon_state = "red_sc"
- list_reagents = list("nutriment" = 1, "cherryjelly" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/cherryjelly = 5)
tastes = list("ice" = 1, "water" = 1, "red" = 5, "cherries" = 5)
foodtype = FRUIT
@@ -113,7 +113,7 @@
name = "kiwi snowcone"
desc = "A kiwi snowball in a paper cup."
icon_state = "kiwi_sc"
- list_reagents = list("nutriment" = 3, "vitamin" = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("ice" = 1, "space" = 3, "kiwi" = 5)
foodtype = FRUIT
@@ -121,7 +121,7 @@
name = "peach snowcone"
desc = "A peach snowball in a paper cup."
icon_state = "peach_sc"
- list_reagents = list("nutriment" = 1, "peachjuice" = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/peachjuice = 10)
tastes = list("ice" = 1, "water" = 1, " peach" = 5)
foodtype = FRUIT
@@ -129,7 +129,7 @@
name = "strawberry snowcone"
desc = "A strawberry snowball in a paper cup."
icon_state = "blue_sc"
- list_reagents = list("nutriment" = 1, "berryjuice" = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/berryjuice = 10)
tastes = list("ice" = 1, "water" = 1, " strawberry" = 5)
foodtype = FRUIT
@@ -137,7 +137,7 @@
name = "berry snowcone"
desc = "Berry syrup drizzled over a snowball in a paper cup."
icon_state = "berry_sc"
- list_reagents = list("nutriment" = 1, "berryjuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/berryjuice = 5)
tastes = list("ice" = 1, "water" = 1, "berries" = 5)
foodtype = FRUIT
@@ -145,7 +145,7 @@
name = "fruit salad snowcone"
desc = "A delightful mix of citrus syrups drizzled over a snowball in a paper cup."
icon_state = "fruitsalad_sc"
- list_reagents = list("nutriment" = 1, "lemonjuice" = 5, "limejuice" = 5, "orangejuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/lemonjuice = 5, /datum/reagent/consumable/limejuice = 5, /datum/reagent/consumable/orangejuice = 5)
tastes = list("ice" = 1, "water" = 1, "oranges" = 5, "limes" = 5, "lemons" = 5, "citrus" = 5, "salad" = 5)
foodtype = FRUIT
@@ -153,7 +153,7 @@
name = "pineapple snowcone"
desc = "Pineapple syrup drizzled over a snowball in a paper cup."
icon_state = "pineapple_sc"
- list_reagents = list("nutriment" = 1, "pineapplejuice" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/water = 10)
tastes = list("ice" = 1, "water" = 1, "pineapples" = 5)
foodtype = PINEAPPLE //Pineapple to allow all that like pineapple to enjoy
@@ -161,47 +161,47 @@
name = "mime snowcone"
desc = "..."
icon_state = "mime_sc"
- list_reagents = list("nutriment" = 1, "nothing" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nothing = 5)
tastes = list("ice" = 1, "water" = 1, "nothing" = 5)
/obj/item/reagent_containers/food/snacks/snowcones/clown
name = "clown snowcone"
desc = "Laughter drizzled over a snowball in a paper cup."
icon_state = "clown_sc"
- list_reagents = list("nutriment" = 1, "laughter" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/laughter = 5)
tastes = list("ice" = 1, "water" = 1, "jokes" = 5, "brainfreeze" = 5, "joy" = 5)
/obj/item/reagent_containers/food/snacks/snowcones/soda
name = "space cola snowcone"
desc = "Space Cola drizzled over a snowball in a paper cup."
icon_state = "soda_sc"
- list_reagents = list("nutriment" = 1, "space_cola" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/space_cola = 5)
tastes = list("ice" = 1, "water" = 1, "cola" = 5)
/obj/item/reagent_containers/food/snacks/snowcones/spacemountainwind
name = "Space Mountain Wind snowcone"
desc = "Space Mountain Wind drizzled over a snowball in a paper cup."
icon_state = "kiwi_sc"
- list_reagents = list("nutriment" = 1, "spacemountainwind" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/spacemountainwind = 5)
tastes = list("ice" = 1, "water" = 1, "mountain wind" = 5)
/obj/item/reagent_containers/food/snacks/snowcones/pwrgame
name = "pwrgame snowcone"
desc = "Pwrgame soda drizzled over a snowball in a paper cup."
icon_state = "pwrgame_sc"
- list_reagents = list("nutriment" = 1, "pwr_game" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/pwr_game = 5)
tastes = list("ice" = 1, "water" = 1, "valid" = 5, "salt" = 5, "wats" = 5)
/obj/item/reagent_containers/food/snacks/snowcones/honey
name = "honey snowcone"
desc = "Honey drizzled over a snowball in a paper cup."
icon_state = "amber_sc"
- list_reagents = list("nutriment" = 1, "honey" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/honey = 5)
tastes = list("ice" = 1, "water" = 1, "flowers" = 5, "sweetness" = 5, "wax" = 1)
/obj/item/reagent_containers/food/snacks/snowcones/rainbow
name = "rainbow snowcone"
desc = "A very colorful snowball in a paper cup."
icon_state = "rainbow_sc"
- list_reagents = list("nutriment" = 5, "laughter" = 25)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/laughter = 25)
tastes = list("ice" = 1, "water" = 1, "sunlight" = 5, "light" = 5, "slime" = 5, "paint" = 3, "clouds" = 3)
diff --git a/code/modules/food_and_drinks/food/snacks_meat.dm b/code/modules/food_and_drinks/food/snacks_meat.dm
index bd01d4c7..6f3b3b3b 100644
--- a/code/modules/food_and_drinks/food/snacks_meat.dm
+++ b/code/modules/food_and_drinks/food/snacks_meat.dm
@@ -8,10 +8,10 @@
desc = "A grifftastic sandwich that burns your tongue and then leaves it numb!"
icon_state = "cubancarp"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
bitesize = 3
filling_color = "#CD853F"
- list_reagents = list("nutriment" = 6, "capsaicin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/capsaicin = 1)
tastes = list("fish" = 4, "batter" = 1, "hot peppers" = 1)
foodtype = MEAT
@@ -19,7 +19,7 @@
name = "carp fillet"
desc = "A fillet of spess carp meat."
icon_state = "fishfillet"
- list_reagents = list("nutriment" = 3, "carpotoxin" = 2, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/toxin/carpotoxin = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
bitesize = 6
filling_color = "#FA8072"
tastes = list("fish" = 1)
@@ -37,8 +37,8 @@
name = "fish fingers"
desc = "A finger of fish."
icon_state = "fishfingers"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
bitesize = 1
filling_color = "#CD853F"
tastes = list("fish" = 1, "breadcrumbs" = 1)
@@ -48,8 +48,8 @@
name = "fish and chips"
desc = "I do say so myself chap."
icon_state = "fishandchips"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
filling_color = "#FA8072"
tastes = list("fish" = 1, "chips" = 1)
foodtype = MEAT | VEGETABLES | FRIED
@@ -59,8 +59,8 @@
desc = "A small cylindrical kudzu skin, filled with rice and fish."
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_basic"
- bonus_reagents = list("vitamin" = 2)
- list_reagents = list("nutriment" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
bitesize = 10
filling_color = "#F2EEEA" //rgb(242, 238, 234)
tastes = list("fish" = 1, "rice" = 2, "salt" = 1)
@@ -71,8 +71,8 @@
desc = "A peace of carp lightly placed on some rice."
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_adv"
- bonus_reagents = list("vitamin" = 2)
- list_reagents = list("nutriment" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
bitesize = 10
filling_color = "#F2EEEA" //rgb(242, 238, 234)
tastes = list("fish" = 2, "rice" = 2, "salt" = 1)
@@ -83,8 +83,8 @@
desc = "A well prepared peace of the best of the carp fillet placed on rice. Looks fancy and fresh!"
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_pro"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2)
bitesize = 10
filling_color = "#F2EEEA" //rgb(242, 238, 234)
tastes = list("fish" = 3, "rice" = 2, "salt" = 1)
@@ -97,7 +97,7 @@
name = "tofu"
desc = "We all love tofu."
icon_state = "tofu"
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
filling_color = "#F0E68C"
tastes = list("tofu" = 1)
foodtype = VEGETABLES
@@ -106,7 +106,7 @@
name = "spider leg"
desc = "A still twitching leg of a giant spider... you don't really want to eat this, do you?"
icon_state = "spiderleg"
- list_reagents = list("nutriment" = 2, "toxin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin = 2)
cooked_type = /obj/item/reagent_containers/food/snacks/boiledspiderleg
filling_color = "#000000"
tastes = list("cobwebs" = 1)
@@ -117,8 +117,8 @@
desc = "Now you can feel like a real tourist vacationing in Ireland."
icon_state = "cornedbeef"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
tastes = list("meat" = 1, "cabbage" = 1)
foodtype = MEAT | VEGETABLES
@@ -127,8 +127,8 @@
desc = "Because eating bear wasn't manly enough."
icon_state = "bearsteak"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 2, "vitamin" = 6)
- list_reagents = list("nutriment" = 2, "vitamin" = 5, "manlydorf" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 5, /datum/reagent/consumable/ethanol/manly_dorf = 5)
tastes = list("meat" = 1, "salmon" = 1)
foodtype = MEAT | ALCOHOL
@@ -136,7 +136,7 @@
name = "meatball"
desc = "A ball of meat."
icon_state = "meatball"
- list_reagents = list("nutriment" = 4, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#800000"
tastes = list("meat" = 1)
foodtype = MEAT
@@ -146,8 +146,8 @@
desc = "A piece of mixed, long meat."
icon_state = "sausage"
filling_color = "#CD5C5C"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 6, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("meat" = 1)
foodtype = MEAT | BREAKFAST
var/roasted = FALSE
@@ -160,35 +160,35 @@
trash = /obj/item/stack/rods
icon_state = "kebab"
w_class = WEIGHT_CLASS_NORMAL
- list_reagents = list("nutriment" = 8)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8)
tastes = list("meat" = 3, "metal" = 1)
foodtype = MEAT
/obj/item/reagent_containers/food/snacks/kebab/human
name = "human-kebab"
desc = "A human meat, on a stick."
- bonus_reagents = list("nutriment" = 1, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("tender meat" = 3, "metal" = 1)
foodtype = MEAT | GROSS
/obj/item/reagent_containers/food/snacks/kebab/monkey
name = "meat-kebab"
desc = "Delicious meat, on a stick."
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("meat" = 3, "metal" = 1)
foodtype = MEAT
/obj/item/reagent_containers/food/snacks/kebab/tofu
name = "tofu-kebab"
desc = "Vegan meat, on a stick."
- bonus_reagents = list("nutriment" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1)
tastes = list("tofu" = 3, "metal" = 1)
foodtype = VEGETABLES
/obj/item/reagent_containers/food/snacks/kebab/tail
name = "lizard-tail kebab"
desc = "Severed lizard tail on a stick."
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("meat" = 8, "metal" = 4, "scales" = 1)
foodtype = MEAT
@@ -196,7 +196,7 @@
name = "raw khinkali"
desc = "One hundred khinkalis? Do I look like a pig?"
icon_state = "khinkali"
- list_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
cooked_type = /obj/item/reagent_containers/food/snacks/khinkali
tastes = list("meat" = 1, "onions" = 1, "garlic" = 1)
foodtype = MEAT
@@ -205,7 +205,7 @@
name = "khinkali"
desc = "One hundred khinkalis? Do I look like a pig?"
icon_state = "khinkali"
- list_reagents = list("nutriment" = 4, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 2)
bitesize = 3
filling_color = "#F0F0F0"
tastes = list("meat" = 1, "onions" = 1, "garlic" = 1)
@@ -216,7 +216,7 @@
desc = "Just add water!"
icon_state = "monkeycube"
bitesize = 12
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
filling_color = "#CD853F"
tastes = list("the jungle" = 1, "bananas" = 1)
foodtype = MEAT | SUGAR
@@ -245,10 +245,10 @@
name = "enchiladas"
desc = "Viva La Mexico!"
icon_state = "enchiladas"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
bitesize = 4
filling_color = "#FFA07A"
- list_reagents = list("nutriment" = 8, "capsaicin" = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/capsaicin = 6)
tastes = list("hot peppers" = 1, "meat" = 3, "cheese" = 1, "sour cream" = 1)
foodtype = MEAT
@@ -257,8 +257,8 @@
desc = "Even non-vegetarians will LOVE this!"
icon_state = "stewedsoymeat"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1)
- list_reagents = list("nutriment" = 8)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8)
filling_color = "#D2691E"
tastes = list("soy" = 1, "vegetables" = 1)
foodtype = VEGETABLES
@@ -272,8 +272,8 @@
desc = "A giant spider's leg that's still twitching after being cooked. Gross!"
icon_state = "spiderlegcooked"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "capsaicin" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 3, "capsaicin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/capsaicin = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/capsaicin = 2)
filling_color = "#000000"
tastes = list("hot peppers" = 1, "cobwebs" = 1)
foodtype = MEAT
@@ -283,8 +283,8 @@
desc = "Would you eat them on a train? Would you eat them on a plane? Would you eat them on a state of the art corporate deathtrap floating through space?"
icon_state = "spidereggsham"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
- list_reagents = list("nutriment" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
bitesize = 4
filling_color = "#7FFF00"
tastes = list("meat" = 1, "the colour green" = 1)
@@ -294,8 +294,8 @@
name = "carp sashimi"
desc = "Celebrate surviving attack from hostile alien lifeforms by hospitalising yourself."
icon_state = "sashimi"
- bonus_reagents = list("nutriment" = 1, "capsaicin" = 4, "vitamin" = 4)
- list_reagents = list("nutriment" = 6, "capsaicin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/capsaicin = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/capsaicin = 5)
filling_color = "#FA8072"
tastes = list("fish" = 1, "hot peppers" = 1)
foodtype = MEAT | TOXIC
@@ -303,8 +303,8 @@
/obj/item/reagent_containers/food/snacks/nugget
name = "chicken nugget"
filling_color = "#B22222"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
tastes = list("\"chicken\"" = 1)
foodtype = MEAT
@@ -318,8 +318,8 @@
name = "pig in a blanket"
desc = "A tiny sausage wrapped in a flakey, buttery roll. Free this pig from its blanket prison by eating it."
icon_state = "pigblanket"
- list_reagents = list("nutriment" = 6, "vitamin" = 1)
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#800000"
tastes = list("meat" = 1, "butter" = 1)
@@ -328,7 +328,7 @@
desc = "Not so delicious rat meat, on a stick."
icon_state = "ratkebab"
w_class = WEIGHT_CLASS_NORMAL
- list_reagents = list("nutriment" = 6, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("rat meat" = 1, "metal" = 1)
foodtype = MEAT | GROSS
@@ -336,20 +336,20 @@
name = "double rat-kebab"
icon_state = "doubleratkebab"
tastes = list("rat meat" = 2, "metal" = 1)
- bonus_reagents = list("nutriment" = 6, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2)
/obj/item/reagent_containers/food/snacks/kebab/fiesta
name = "fiesta skewer"
icon_state = "fiestaskewer"
tastes = list("tex-mex" = 3, "cumin" = 2)
- bonus_reagents = list("vitamin" = 5, "capsaicin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 5, /datum/reagent/consumable/capsaicin = 3)
/obj/item/reagent_containers/food/snacks/bbqribs
name = "bbq ribs"
desc = "BBQ ribs, slathered in a healthy coating of BBQ sauce. The least vegan thing to ever exist."
icon_state = "ribs"
w_class = WEIGHT_CLASS_NORMAL
- list_reagents = list("nutriment" = 8, "vitamin" = 2, "bbqsauce" = 5)
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/bbqsauce = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("meat" = 3, "smokey sauce" = 1)
- foodtype = MEAT
\ No newline at end of file
+ foodtype = MEAT
diff --git a/code/modules/food_and_drinks/food/snacks_other.dm b/code/modules/food_and_drinks/food/snacks_other.dm
index d86643db..ba145ca2 100644
--- a/code/modules/food_and_drinks/food/snacks_other.dm
+++ b/code/modules/food_and_drinks/food/snacks_other.dm
@@ -7,7 +7,7 @@
icon_state = "cheesewheel"
slice_path = /obj/item/reagent_containers/food/snacks/cheesewedge
slices_num = 5
- list_reagents = list("nutriment" = 15, "vitamin" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 15, /datum/reagent/consumable/nutriment/vitamin = 5)
w_class = WEIGHT_CLASS_NORMAL
tastes = list("cheese" = 1)
foodtype = DAIRY
@@ -17,7 +17,7 @@
desc = "A wedge of delicious Cheddar. The cheese wheel it was cut from can't have gone far."
icon_state = "cheesewedge"
filling_color = "#FFD700"
- list_reagents = list("nutriment" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("cheese" = 1)
foodtype = DAIRY
@@ -28,13 +28,13 @@
filling_color = "#FF1493"
tastes = list("watermelon" = 1)
foodtype = FRUIT
- juice_results = list("watermelonjuice" = 5)
+ juice_results = list(/datum/reagent/consumable/watermelonjuice = 5)
/obj/item/reagent_containers/food/snacks/candy_corn
name = "candy corn"
desc = "It's a handful of candy corn. Can be stored in a detective's hat."
icon_state = "candy_corn"
- list_reagents = list("nutriment" = 4, "sugar" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/sugar = 2)
filling_color = "#FF8C00"
tastes = list("candy corn" = 1)
foodtype = JUNKFOOD | SUGAR
@@ -43,7 +43,7 @@
name = "chocolate bar"
desc = "Such, sweet, fattening food."
icon_state = "chocolatebar"
- list_reagents = list("nutriment" = 2, "sugar" = 2, "cocoa" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/sugar = 2, /datum/reagent/consumable/coco = 2)
filling_color = "#A0522D"
tastes = list("chocolate" = 1)
foodtype = JUNKFOOD | SUGAR
@@ -53,7 +53,7 @@
name = "huge mushroom slice"
desc = "A slice from a huge mushroom."
icon_state = "hugemushroomslice"
- list_reagents = list("nutriment" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("mushroom" = 1)
foodtype = VEGETABLES
@@ -62,7 +62,7 @@
desc = "Now let's find some cinema."
icon_state = "popcorn"
trash = /obj/item/trash/popcorn
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
bitesize = 0.1 //this snack is supposed to be eating during looooong time. And this it not dinner food! --rastaf0
filling_color = "#FFEFD5"
tastes = list("popcorn" = 3, "butter" = 1)
@@ -76,8 +76,8 @@
name = "loaded baked potato"
desc = "Totally baked."
icon_state = "loadedbakedpotato"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
filling_color = "#D2B48C"
tastes = list("potato" = 1)
foodtype = VEGETABLES | DAIRY
@@ -87,7 +87,7 @@
desc = "AKA: French Fries, Freedom Fries, etc."
icon_state = "fries"
trash = /obj/item/trash/plate
- list_reagents = list("nutriment" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
filling_color = "#FFD700"
tastes = list("fries" = 3, "salt" = 1)
foodtype = VEGETABLES | GRAIN | FRIED
@@ -97,7 +97,7 @@
name = "tator tot"
desc = "A large fried potato nugget that may or may not try to valid you."
icon_state = "tatortot"
- list_reagents = list("nutriment" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
filling_color = "FFD700"
tastes = list("potato" = 3, "valids" = 1)
foodtype = FRIED | VEGETABLES
@@ -108,7 +108,7 @@
desc = "Dope from a soy."
icon_state = "soydope"
trash = /obj/item/trash/plate
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
filling_color = "#DEB887"
tastes = list("soy" = 1)
foodtype = VEGETABLES
@@ -119,8 +119,8 @@
desc = "Fries. Covered in cheese. Duh."
icon_state = "cheesyfries"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
filling_color = "#FFD700"
tastes = list("fries" = 3, "cheese" = 1)
foodtype = VEGETABLES | GRAIN
@@ -129,7 +129,7 @@
name = "burned mess"
desc = "Someone should be demoted from cook for this."
icon_state = "badrecipe"
- list_reagents = list("bad_food" = 30)
+ list_reagents = list(/datum/reagent/toxin/bad_food = 30)
filling_color = "#8B4513"
foodtype = GROSS
dunkable = TRUE
@@ -139,7 +139,7 @@
desc = "Tasty fries from fresh Carrots."
icon_state = "carrotfries"
trash = /obj/item/trash/plate
- list_reagents = list("nutriment" = 3, "oculine" = 3, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/medicine/oculine = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#FFA500"
tastes = list("carrots" = 3, "salt" = 1)
foodtype = VEGETABLES
@@ -149,8 +149,8 @@
desc = "An apple coated in sugary sweetness."
icon_state = "candiedapple"
bitesize = 3
- bonus_reagents = list("nutriment" = 2, "sugar" = 3)
- list_reagents = list("nutriment" = 3, "sugar" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/sugar = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sugar = 2)
filling_color = "#FF4500"
tastes = list("apple" = 2, "sweetness" = 2)
foodtype = JUNKFOOD | FRUIT | SUGAR
@@ -161,7 +161,7 @@
icon_state = "mint"
bitesize = 1
trash = /obj/item/trash/plate
- list_reagents = list("minttoxin" = 2)
+ list_reagents = list(/datum/reagent/toxin/minttoxin = 2)
filling_color = "#800000"
foodtype = TOXIC | SUGAR
@@ -169,8 +169,8 @@
name = "egg wrap"
desc = "The precursor to Pigs in a Blanket."
icon_state = "eggwrap"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
- list_reagents = list("nutriment" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
filling_color = "#F0E68C"
tastes = list("egg" = 1)
foodtype = MEAT | GRAIN
@@ -179,8 +179,8 @@
name = "tin of beans"
desc = "Musical fruit in a slightly less musical container."
icon_state = "beans"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10)
filling_color = "#B22222"
tastes = list("beans" = 1)
foodtype = VEGETABLES
@@ -189,7 +189,7 @@
name = "spider eggs"
desc = "A cluster of juicy spider eggs. A great side dish for when you care not for your health."
icon_state = "spidereggs"
- list_reagents = list("nutriment" = 2, "toxin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin = 2)
filling_color = "#008000"
tastes = list("cobwebs" = 1)
foodtype = MEAT | TOXIC
@@ -198,7 +198,7 @@
name = "spiderling"
desc = "It's slightly twitching in your hand. Ew..."
icon_state = "spiderling"
- list_reagents = list("nutriment" = 1, "toxin" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/toxin = 4)
filling_color = "#00800"
tastes = list("cobwebs" = 1, "guts" = 2)
foodtype = MEAT | TOXIC
@@ -207,7 +207,7 @@
name = "spider lollipop"
desc = "Still gross, but at least it has a mountain of sugar on it."
icon_state = "spiderlollipop"
- list_reagents = list("nutriment" = 1, "toxin" = 1, "iron" = 10, "sugar" = 5, "omnizine" = 2) //lollipop, but vitamins = toxins
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/toxin = 1, /datum/reagent/iron = 10, /datum/reagent/consumable/sugar = 5, /datum/reagent/medicine/omnizine = 2) //lollipop, but vitamins = toxins
filling_color = "#00800"
tastes = list("cobwebs" = 1, "sugar" = 2)
foodtype = JUNKFOOD | SUGAR
@@ -217,7 +217,7 @@
desc = "Spider eggs wrapped in a thin salted Kudzu pod"
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_egg"
- list_reagents = list("nutriment" = 6, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#FF3333" // R225 G051 B051
tastes = list("seaweed" = 1, "cobwebs" = 1, "salty" = 2)
foodtype = MEAT | VEGETABLES
@@ -226,8 +226,8 @@
name = "chocolate coin"
desc = "A completely edible but nonflippable festive coin."
icon_state = "chococoin"
- bonus_reagents = list("nutriment" = 1, "sugar" = 1)
- list_reagents = list("nutriment" = 3, "cocoa" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/coco = 1)
filling_color = "#A0522D"
tastes = list("chocolate" = 1)
foodtype = JUNKFOOD | SUGAR
@@ -236,8 +236,8 @@
name = "fudge dice"
desc = "A little cube of chocolate that tends to have a less intense taste if you eat too many at once."
icon_state = "chocodice"
- bonus_reagents = list("nutriment" = 1, "sugar" = 1)
- list_reagents = list("nutriment" = 3, "cocoa" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/coco = 1)
filling_color = "#A0522D"
trash = /obj/item/dice/fudge
tastes = list("fudge" = 1)
@@ -247,8 +247,8 @@
name = "chocolate orange"
desc = "A festive chocolate orange."
icon_state = "chocoorange"
- bonus_reagents = list("nutriment" = 1, "sugar" = 1)
- list_reagents = list("nutriment" = 3, "sugar" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sugar = 1)
filling_color = "#A0522D"
tastes = list("chocolate" = 3, "oranges" = 1)
foodtype = JUNKFOOD | SUGAR
@@ -258,8 +258,8 @@
desc = "The only good recipe for eggplant."
icon_state = "eggplantparm"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
- list_reagents = list("nutriment" = 6, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#BA55D3"
tastes = list("eggplant" = 3, "cheese" = 1)
foodtype = VEGETABLES | DAIRY
@@ -269,7 +269,7 @@
desc = "The base for all your burritos."
icon = 'icons/obj/food/food_ingredients.dmi'
icon_state = "tortilla"
- list_reagents = list("nutriment" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#FFEFD5"
tastes = list("tortilla" = 1)
foodtype = GRAIN
@@ -278,8 +278,8 @@
name = "burrito"
desc = "Tortilla wrapped goodness."
icon_state = "burrito"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 4, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#FFEFD5"
tastes = list("torilla" = 2, "meat" = 3)
foodtype = GRAIN | MEAT
@@ -288,8 +288,8 @@
name = "cheesy burrito"
desc = "It's a burrito filled with cheese."
icon_state = "cheesyburrito"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 4, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#FFD800"
tastes = list("torilla" = 2, "meat" = 3, "cheese" = 1)
foodtype = GRAIN | MEAT | DAIRY
@@ -298,8 +298,8 @@
name = "carne asada burrito"
desc = "The best burrito for meat lovers."
icon_state = "carneburrito"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 1)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#A0522D"
tastes = list("torilla" = 2, "meat" = 4)
foodtype = GRAIN | MEAT
@@ -308,8 +308,8 @@
name = "fuego plasma burrito"
desc = "A super spicy burrito."
icon_state = "fuegoburrito"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 3)
- list_reagents = list("nutriment" = 4, "capsaicin" = 5, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/capsaicin = 5, /datum/reagent/consumable/nutriment/vitamin = 3)
filling_color = "#FF2000"
tastes = list("torilla" = 2, "meat" = 3, "hot peppers" = 1)
foodtype = GRAIN | MEAT
@@ -319,7 +319,7 @@
desc = "Made with roasted sweet potatoes!"
icon_state = "yakiimo"
trash = /obj/item/trash/plate
- list_reagents = list("nutriment" = 5, "vitamin" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#8B1105"
tastes = list("sweet potato" = 1)
foodtype = GRAIN | VEGETABLES | SUGAR
@@ -329,7 +329,7 @@
desc = "Sweet and crunchy."
icon_state = "roastparsnip"
trash = /obj/item/trash/plate
- list_reagents = list("nutriment" = 3, "vitamin" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#FF5500"
tastes = list("parsnip" = 1)
foodtype = VEGETABLES
@@ -338,8 +338,8 @@
name = "melon fruit bowl"
desc = "For people who wants edible fruit bowls."
icon_state = "melonfruitbowl"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#FF5500"
w_class = WEIGHT_CLASS_NORMAL
tastes = list("melon" = 1)
@@ -349,8 +349,8 @@
name = "nachos"
desc = "Chips from Space Mexico."
icon_state = "nachos"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 6, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#F4A460"
tastes = list("nachos" = 1)
foodtype = VEGETABLES | FRIED
@@ -359,8 +359,8 @@
name = "cheesy nachos"
desc = "The delicious combination of nachos and melting cheese."
icon_state = "cheesynachos"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 3)
filling_color = "#FFD700"
tastes = list("nachos" = 2, "cheese" = 1)
foodtype = VEGETABLES | FRIED | DAIRY
@@ -369,8 +369,8 @@
name = "Cuban nachos"
desc = "That's some dangerously spicy nachos."
icon_state = "cubannachos"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 3)
- list_reagents = list("nutriment" = 7, "capsaicin" = 8, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/capsaicin = 8, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#DC143C"
tastes = list("nachos" = 2, "hot pepper" = 1)
foodtype = VEGETABLES | FRIED | DAIRY
@@ -379,8 +379,8 @@
name = "melon keg"
desc = "Who knew vodka was a fruit?"
icon_state = "melonkeg"
- bonus_reagents = list("nutriment" = 3, "vitamin" = 3)
- list_reagents = list("nutriment" = 9, "vodka" = 15, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 9, /datum/reagent/consumable/ethanol/vodka = 15, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#FFD700"
volume = 80
bitesize = 5
@@ -391,8 +391,8 @@
name = "honey nut bar"
desc = "Oats and nuts compressed together into a bar, held together with a honey glaze."
icon_state = "honeybar"
- bonus_reagents = list("nutriment" = 2, "honey" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 5, "honey" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/honey = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/honey = 5)
filling_color = "#F2CE91"
tastes = list("oats" = 3, "nuts" = 2, "honey" = 1)
foodtype = FRUIT | SUGAR
@@ -401,8 +401,8 @@
name = "stuffed legion"
desc = "The former skull of a damned human, filled with goliath meat. It has a decorative lava pool made of ketchup and hotsauce."
icon_state = "stuffed_legion"
- bonus_reagents = list("vitamin" = 3, "capsaicin" = 1, "tricordrazine" = 5)
- list_reagents = list("nutriment" = 5, "vitamin" = 5, "capsaicin" = 2, "tricordrazine" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 3, /datum/reagent/consumable/capsaicin = 1, /datum/reagent/medicine/tricordrazine = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5, /datum/reagent/consumable/capsaicin = 2, /datum/reagent/medicine/tricordrazine = 10)
tastes = list("death" = 2, "rock" = 1, "meat" = 1, "hot peppers" = 1)
foodtype = MEAT
@@ -410,8 +410,8 @@
name = "Powercrepe"
desc = "With great power, comes great crepes. It looks like a pancake filled with jelly but packs quite a punch."
icon_state = "powercrepe"
- bonus_reagents = list("nutriment" = 5, "vitamin" = 3, "iron" = 10)
- list_reagents = list("nutriment" = 10, "vitamin" = 5, "cherryjelly" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 3, /datum/reagent/iron = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 5, /datum/reagent/consumable/cherryjelly = 5)
force = 20
throwforce = 10
block_chance = 50
@@ -426,7 +426,7 @@
desc = "A delicious lollipop. Makes for a great Valentine's present."
icon = 'icons/obj/lollipop.dmi'
icon_state = "lollipop_stick"
- list_reagents = list("nutriment" = 1, "vitamin" = 1, "iron" = 10, "sugar" = 5, "omnizine" = 2) //Honk
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1, /datum/reagent/iron = 10, /datum/reagent/consumable/sugar = 5, /datum/reagent/medicine/omnizine = 2) //Honk
var/mutable_appearance/head
var/headcolor = rgb(0, 0, 0)
tastes = list("candy" = 1)
@@ -468,7 +468,7 @@
desc = "A colorful, sugary gumball."
icon = 'icons/obj/lollipop.dmi'
icon_state = "gumball"
- list_reagents = list("sugar" = 5, "bicaridine" = 2, "kelotane" = 2) //Kek
+ list_reagents = list(/datum/reagent/consumable/sugar = 5, /datum/reagent/medicine/bicaridine = 2, /datum/reagent/medicine/kelotane = 2) //Kek
tastes = list("candy")
foodtype = JUNKFOOD
@@ -495,8 +495,8 @@
name = "taco"
desc = "A traditional taco with meat, cheese, and lettuce."
icon_state = "taco"
- bonus_reagents = list("nutriment" = 3, "vitamin" = 2)
- list_reagents = list("nutriment" = 4, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "F0D830"
tastes = list("taco" = 4, "meat" = 2, "cheese" = 2, "lettuce" = 1)
foodtype = MEAT | DAIRY | GRAIN | VEGETABLES
@@ -504,8 +504,8 @@
/obj/item/reagent_containers/food/snacks/taco/plain
desc = "A traditional taco with meat and cheese, minus the rabbit food."
icon_state = "taco_plain"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 3, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("taco" = 4, "meat" = 2, "cheese" = 2)
foodtype = MEAT | DAIRY | GRAIN
@@ -513,8 +513,8 @@
name = "Bran Requests Cereal"
desc = "A dry cereal that satiates your requests for bran. Tastes uniquely like raisins and salt."
icon_state = "bran_requests"
- list_reagents = list("nutriment" = 3, "vitamin" = 2, "sodiumchloride" = 5)
- bonus_reagents = list("sodiumchloride" = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/sodiumchloride = 5)
+ bonus_reagents = list(/datum/reagent/consumable/sodiumchloride = 10)
tastes = list("bran" = 4, "raisins" = 3, "salt" = 1)
foodtype = GRAIN | FRUIT
@@ -522,7 +522,7 @@
name = "stick of butter"
desc = "A stick of delicious, golden, fatty goodness."
icon_state = "butter"
- list_reagents = list("nutriment" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
filling_color = "#FFD700"
tastes = list("butter" = 1)
foodtype = DAIRY
@@ -531,7 +531,7 @@
name = "onion rings"
desc = "Onion slices coated in batter."
icon_state = "onionrings"
- list_reagents = list("nutriment" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3)
filling_color = "#C0C9A0"
gender = PLURAL
tastes = list("batter" = 3, "onion" = 1)
@@ -550,7 +550,7 @@
name = "chocolate"
desc = "A tiny and sweet chocolate. Has a 'strawberry' filling!"
icon_state = "tiny_chocolate"
- list_reagents = list("nutriment" = 1, "sugar" = 1, "cocoa" = 1, "aphro" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 1, /datum/reagent/consumable/coco = 1, /datum/reagent/drug/aphrodisiac = 1)
filling_color = "#A0522D"
tastes = list("chocolate" = 1)
foodtype = JUNKFOOD | SUGAR
@@ -560,7 +560,7 @@
desc = "A ball of rice with some light salt and a wrap of Kudzu skin."
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "riceball"
- list_reagents = list("nutriment" = 6, "sodiumchloride" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/sodiumchloride = 2)
tastes = list("rice" = 3, "salt" = 1)
foodtype = GRAIN
@@ -568,7 +568,7 @@
name = "Canned Peaches"
desc = "Just a nice can of ripe peaches swimming in their own juices."
icon_state = "peachcan"
- list_reagents = list("peachjuice" = 20, "sugar" = 8, "nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/peachjuice = 20, /datum/reagent/consumable/sugar = 8, /datum/reagent/consumable/nutriment = 2)
filling_color = "#ffdf26"
w_class = WEIGHT_CLASS_NORMAL
tastes = list("peaches" = 7, "tin" = 1)
@@ -584,7 +584,7 @@
name = "Chocolate dipped strawberries"
desc = "A strawberry dipped in a bit of chocolate."
icon_state = "chocolatestrawberry"
- list_reagents = list("sugar" = 5, "nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/sugar = 5, /datum/reagent/consumable/nutriment = 2)
filling_color = "#ffdf26"
w_class = WEIGHT_CLASS_NORMAL
tastes = list("strawberries" = 5, "chocolate" = 3)
@@ -595,7 +595,7 @@
name = "Chocolate dipped banana"
desc = "A banana dipped in a bit of chocolate and held on a stick."
icon_state = "banana_coco"
- list_reagents = list("sugar" = 5, "nutriment" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/sugar = 5, /datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#ffdf26"
tastes = list("banana" = 5, "chocolate" = 3)
foodtype = FRUIT | SUGAR
@@ -607,7 +607,7 @@
icon_state = "boritos"
trash = /obj/item/trash/boritos
bitesize = 2
- list_reagents = list("nutriment" = 3, "cooking_oil" = 2, "sodiumchloride" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/cooking_oil = 2, /datum/reagent/consumable/sodiumchloride = 3)
filling_color = "#ECA735"
tastes = list("fried corn" = 1)
foodtype = JUNKFOOD | FRIED
diff --git a/code/modules/food_and_drinks/food/snacks_pastry.dm b/code/modules/food_and_drinks/food/snacks_pastry.dm
index 5c93f45f..045bfd08 100644
--- a/code/modules/food_and_drinks/food/snacks_pastry.dm
+++ b/code/modules/food_and_drinks/food/snacks_pastry.dm
@@ -8,8 +8,8 @@
icon = 'icons/obj/food/donut.dmi'
icon_state = "donut"
bitesize = 5
- bonus_reagents = list("sugar" = 1)
- list_reagents = list("nutriment" = 3, "sprinkles" = 1, "sugar" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/sugar = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/sugar = 2)
filling_color = "#D2691E"
tastes = list("donut" = 1)
foodtype = JUNKFOOD | GRAIN | FRIED | SUGAR | BREAKFAST
@@ -30,7 +30,7 @@
is_decorated = TRUE
name = "[decorated_adjective] [name]"
icon_state = decorated_icon //delish~!
- reagents.add_reagent("sprinkles", 1)
+ reagents.add_reagent(/datum/reagent/consumable/sprinkles, 1)
filling_color = "#FF69B4"
return TRUE
@@ -58,15 +58,18 @@
/obj/item/reagent_containers/food/snacks/donut/chaos/Initialize()
. = ..()
- extra_reagent = pick("nutriment", "capsaicin", "frostoil", "krokodil", "plasma", "cocoa", "slimejelly", "banana", "berryjuice", "omnizine")
+ extra_reagent = pick(/datum/reagent/consumable/nutriment, /datum/reagent/consumable/capsaicin, /datum/reagent/consumable/frostoil,
+ /datum/reagent/drug/krokodil, /datum/reagent/toxin/plasma, /datum/reagent/consumable/coco,
+ /datum/reagent/toxin/slimejelly, /datum/reagent/consumable/banana, /datum/reagent/consumable/berryjuice,
+ /datum/reagent/medicine/omnizine)
reagents.add_reagent(extra_reagent, 3)
/obj/item/reagent_containers/food/snacks/donut/meat
name = "Meat Donut"
desc = "Tastes as gross as it looks."
icon_state = "donut_meat"
- bonus_reagents = list("ketchup" = 1)
- list_reagents = list("nutriment" = 3, "ketchup" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/ketchup = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/ketchup = 2)
tastes = list("meat" = 1)
foodtype = JUNKFOOD | MEAT | GROSS | FRIED | BREAKFAST
@@ -74,7 +77,7 @@
name = "pink donut"
desc = "Goes great with a soy latte."
icon_state = "donut_pink"
- bonus_reagents = list("berryjuice" = 3, "sprinkles" = 1) //Extra sprinkles to reward frosting
+ bonus_reagents = list(/datum/reagent/consumable/berryjuice = 3, /datum/reagent/consumable/sprinkles = 1) //Extra sprinkles to reward frosting
filling_color = "#E57d9A"
decorated_icon = "donut_homer"
@@ -82,7 +85,7 @@
name = "spaceman's donut"
desc = "Goes great with a cold beaker of malk."
icon_state = "donut_purple"
- bonus_reagents = list("polypyr" = 3, "sprinkles" = 1)
+ bonus_reagents = list(/datum/reagent/medicine/polypyr = 3, /datum/reagent/consumable/sprinkles = 1)
tastes = list("donut" = 3, "violets" = 1)
is_decorated = TRUE
filling_color = "#8739BF"
@@ -91,7 +94,7 @@
name = "apple donut"
desc = "Goes great with a shot of cinnamon schnapps."
icon_state = "donut_green"
- bonus_reagents = list("applejuice" = 3, "sprinkles" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/applejuice = 3, /datum/reagent/consumable/sprinkles = 1)
tastes = list("donut" = 3, "green apples" = 1)
is_decorated = TRUE
filling_color = "#6ABE30"
@@ -100,7 +103,7 @@
name = "caramel donut"
desc = "Goes great with a mug of hot coco."
icon_state = "donut_beige"
- bonus_reagents = list("caramel" = 3, "sprinkles" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/caramel = 3, /datum/reagent/consumable/sprinkles = 1)
tastes = list("donut" = 3, "buttery sweetness" = 1)
is_decorated = TRUE
filling_color = "#D4AD5B"
@@ -109,7 +112,7 @@
name = "chocolate donut"
desc = "Goes great with a glass of warm milk."
icon_state = "donut_choc"
- bonus_reagents = list("hot_coco" = 3, "sprinkles" = 1) //the coco reagent is just bitter.
+ bonus_reagents = list(/datum/reagent/consumable/hot_coco = 3, /datum/reagent/consumable/sprinkles = 1) //the coco reagent is just bitter.
tastes = list("donut" = 4, "bitterness" = 1)
decorated_icon = "donut_choc_sprinkles"
filling_color = "#4F230D"
@@ -118,7 +121,7 @@
name = "blumpkin donut"
desc = "Goes great with a mug of soothing drunken blumpkin."
icon_state = "donut_blue"
- bonus_reagents = list("blumpkinjuice" = 3, "sprinkles" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/blumpkinjuice = 3, /datum/reagent/consumable/sprinkles = 1)
tastes = list("donut" = 2, "blumpkin" = 1)
is_decorated = TRUE
filling_color = "#2788C4"
@@ -127,7 +130,7 @@
name = "bungo donut"
desc = "Goes great with a mason jar of hippie's delight."
icon_state = "donut_yellow"
- bonus_reagents = list("bungojuice" = 3, "sprinkles" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/bungojuice = 3, /datum/reagent/consumable/sprinkles = 1)
tastes = list("donut" = 3, "tropical sweetness" = 1)
is_decorated = TRUE
filling_color = "#DEC128"
@@ -136,7 +139,7 @@
name = "matcha donut"
desc = "Goes great with a cup of tea."
icon_state = "donut_olive"
- bonus_reagents = list("teapowder = 3", "sprinkles" = 1)
+ bonus_reagents = list(/datum/reagent/toxin/teapowder = 3, /datum/reagent/consumable/sprinkles = 1)
tastes = list("donut" = 3, "matcha" = 1)
is_decorated = TRUE
filling_color = "#879630"
@@ -146,8 +149,8 @@
desc = "That cream looks a little runny..."
icon_state = "donut_cum"
bitesize = 10
- bonus_reagents = list("semen" = 1)
- list_reagents = list("nutriment" = 3, "sugar" = 2, "semen" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/semen = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sugar = 2, /datum/reagent/consumable/semen = 5)
filling_color = "#FFFFFF"
tastes = list("donut" = 1, "salt" = 3)
foodtype = JUNKFOOD | GRAIN | FRIED | SUGAR
@@ -159,7 +162,7 @@
desc = "You jelly?"
icon_state = "jelly"
decorated_icon = "jelly_homer"
- bonus_reagents = list("sugar" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/sugar = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
extra_reagent = "berryjuice"
tastes = list("jelly" = 1, "donut" = 3)
foodtype = JUNKFOOD | GRAIN | FRIED | FRUIT | SUGAR | BREAKFAST
@@ -167,7 +170,7 @@
/obj/item/reagent_containers/food/snacks/donut/jelly/Initialize()
. = ..()
if(extra_reagent)
- reagents.add_reagent("[extra_reagent]", 3)
+ reagents.add_reagent(extra_reagent, 3)
/obj/item/reagent_containers/food/snacks/donut/jelly/plain //use this ingame to avoid inheritance related crafting issues.
@@ -175,7 +178,7 @@
name = "pink jelly donut"
desc = "Goes great with a soy latte."
icon_state = "jelly_pink"
- bonus_reagents = list("berryjuice" = 3, "sprinkles" = 1, "vitamin" = 1) //Extra sprinkles to reward frosting.
+ bonus_reagents = list(/datum/reagent/consumable/berryjuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1) //Extra sprinkles to reward frosting.
filling_color = "#E57d9A"
decorated_icon = "jelly_homer"
@@ -183,7 +186,7 @@
name = "spaceman's jelly donut"
desc = "Goes great with a cold beaker of malk."
icon_state = "jelly_purple"
- bonus_reagents = list("polypyr" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/medicine/polypyr = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "violets" = 1)
is_decorated = TRUE
filling_color = "#8739BF"
@@ -192,7 +195,7 @@
name = "apple jelly donut"
desc = "Goes great with a shot of cinnamon schnapps."
icon_state = "jelly_green"
- bonus_reagents = list("applejuice" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/applejuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "green apples" = 1)
is_decorated = TRUE
filling_color = "#6ABE30"
@@ -201,7 +204,7 @@
name = "caramel jelly donut"
desc = "Goes great with a mug of hot coco."
icon_state = "jelly_beige"
- bonus_reagents = list("caramel" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/caramel = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "buttery sweetness" = 1)
is_decorated = TRUE
filling_color = "#D4AD5B"
@@ -209,8 +212,8 @@
/obj/item/reagent_containers/food/snacks/donut/jelly/choco
name = "chocolate jelly donut"
desc = "Goes great with a glass of warm milk."
- icon_state = "jelly_choco"
- bonus_reagents = list("hot_coco" = 3, "sprinkles" = 1, "vitamin" = 1) //the coco reagent is just bitter.
+ icon_state = "jelly_choc"
+ bonus_reagents = list(/datum/reagent/consumable/hot_coco = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1) //the coco reagent is just bitter.
tastes = list("jelly" = 1, "donut" = 4, "bitterness" = 1)
decorated_icon = "jelly_choco_sprinkles"
filling_color = "#4F230D"
@@ -219,7 +222,7 @@
name = "blumpkin jelly donut"
desc = "Goes great with a mug of soothing drunken blumpkin."
icon_state = "jelly_blue"
- bonus_reagents = list("blumpkinjuice" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/blumpkinjuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 2, "blumpkin" = 1)
is_decorated = TRUE
filling_color = "#2788C4"
@@ -228,7 +231,7 @@
name = "bungo jelly donut"
desc = "Goes great with a mason jar of hippie's delight."
icon_state = "jelly_yellow"
- bonus_reagents = list("bungojuice" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/bungojuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "tropical sweetness" = 1)
is_decorated = TRUE
filling_color = "#DEC128"
@@ -237,7 +240,7 @@
name = "matcha jelly donut"
desc = "Goes great with a cup of tea."
icon_state = "jelly_olive"
- bonus_reagents = list("teapowder" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/toxin/teapowder = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "matcha" = 1)
is_decorated = TRUE
filling_color = "#879630"
@@ -257,14 +260,14 @@
name = "pink jelly donut"
desc = "Goes great with a soy latte."
icon_state = "jelly_pink"
- bonus_reagents = list("berryjuice" = 3, "sprinkles" = 1, "vitamin" = 1) //Extra sprinkles to reward frosting
+ bonus_reagents = list(/datum/reagent/consumable/berryjuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1) //Extra sprinkles to reward frosting
filling_color = "#E57d9A"
/obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly/trumpet
name = "spaceman's jelly donut"
desc = "Goes great with a cold beaker of malk."
icon_state = "jelly_purple"
- bonus_reagents = list("polypyr" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/medicine/polypyr = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "violets" = 1)
is_decorated = TRUE
filling_color = "#8739BF"
@@ -273,7 +276,7 @@
name = "apple jelly donut"
desc = "Goes great with a shot of cinnamon schnapps."
icon_state = "jelly_green"
- bonus_reagents = list("applejuice" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/applejuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "green apples" = 1)
is_decorated = TRUE
filling_color = "#6ABE30"
@@ -282,7 +285,7 @@
name = "caramel jelly donut"
desc = "Goes great with a mug of hot coco."
icon_state = "jelly_beige"
- bonus_reagents = list("caramel" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/caramel = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "buttery sweetness" = 1)
is_decorated = TRUE
filling_color = "#D4AD5B"
@@ -290,8 +293,8 @@
/obj/item/reagent_containers/food/snacks/donut/jelly/slimejelly/choco
name = "chocolate jelly donut"
desc = "Goes great with a glass of warm milk."
- icon_state = "jelly_choco"
- bonus_reagents = list("hot_coco" = 3, "sprinkles" = 1, "vitamin" = 1) //the coco reagent is just bitter.
+ icon_state = "jelly_choc"
+ bonus_reagents = list(/datum/reagent/consumable/hot_coco = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1) //the coco reagent is just bitter.
tastes = list("jelly" = 1, "donut" = 4, "bitterness" = 1)
decorated_icon = "jelly_choco_sprinkles"
filling_color = "#4F230D"
@@ -300,7 +303,7 @@
name = "blumpkin jelly donut"
desc = "Goes great with a mug of soothing drunken blumpkin."
icon_state = "jelly_blue"
- bonus_reagents = list("blumpkinjuice" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/blumpkinjuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 2, "blumpkin" = 1)
is_decorated = TRUE
filling_color = "#2788C4"
@@ -309,7 +312,7 @@
name = "bungo jelly donut"
desc = "Goes great with a mason jar of hippie's delight."
icon_state = "jelly_yellow"
- bonus_reagents = list("bungojuice" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/bungojuice = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "tropical sweetness" = 1)
is_decorated = TRUE
filling_color = "#DEC128"
@@ -318,7 +321,7 @@
name = "matcha jelly donut"
desc = "Goes great with a cup of tea."
icon_state = "jelly_olive"
- bonus_reagents = list("teapowder" = 3, "sprinkles" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/toxin/teapowder = 3, /datum/reagent/consumable/sprinkles = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("jelly" = 1, "donut" = 3, "matcha" = 1)
is_decorated = TRUE
filling_color = "#879630"
@@ -328,8 +331,8 @@
desc = "A sugar glazed donut."
icon_state = "donut_glaze"
bitesize = 10
- bonus_reagents = list("sugar" = 3)
- list_reagents = list("nutriment" = 3, "sugar" = 8)
+ bonus_reagents = list(/datum/reagent/consumable/sugar = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sugar = 8)
filling_color = "#FFFFFF"
tastes = list("donut" = 1, "salt" = 3)
foodtype = JUNKFOOD | GRAIN | FRIED | SUGAR
@@ -340,8 +343,8 @@
name = "muffin"
desc = "A delicious and spongy little cake."
icon_state = "muffin"
- bonus_reagents = list("vitamin" = 1)
- list_reagents = list("nutriment" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
filling_color = "#F4A460"
tastes = list("muffin" = 1)
foodtype = GRAIN | SUGAR | BREAKFAST
@@ -365,8 +368,8 @@
name = "chawanmushi"
desc = "A legendary egg custard that makes friends out of enemies. Probably too hot for a cat to eat."
icon_state = "chawanmushi"
- bonus_reagents = list("vitamin" = 1)
- list_reagents = list("nutriment" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
filling_color = "#FFE4E1"
tastes = list("custard" = 1)
foodtype = GRAIN | MEAT | VEGETABLES
@@ -378,8 +381,8 @@
desc = "Mmm, waffles."
icon_state = "waffles"
trash = /obj/item/trash/waffles
- bonus_reagents = list("vitamin" = 1)
- list_reagents = list("nutriment" = 8, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#D2691E"
tastes = list("waffles" = 1)
foodtype = GRAIN | SUGAR | BREAKFAST
@@ -389,8 +392,8 @@
desc = "Not made of people. Honest." //Totally people.
icon_state = "soylent_green"
trash = /obj/item/trash/waffles
- bonus_reagents = list("vitamin" = 1)
- list_reagents = list("nutriment" = 10, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#9ACD32"
tastes = list("waffles" = 7, "people" = 1)
foodtype = GRAIN | MEAT
@@ -400,8 +403,8 @@
desc = "Not made of people. Honest." //Actually honest for once.
icon_state = "soylent_yellow"
trash = /obj/item/trash/waffles
- bonus_reagents = list("vitamin" = 1)
- list_reagents = list("nutriment" = 10, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#9ACD32"
tastes = list("waffles" = 7, "the colour green" = 1)
foodtype = GRAIN
@@ -412,8 +415,8 @@
icon_state = "rofflewaffles"
trash = /obj/item/trash/waffles
bitesize = 4
- bonus_reagents = list("vitamin" = 2)
- list_reagents = list("nutriment" = 8, "mushroomhallucinogen" = 2, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/drug/mushroomhallucinogen = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#00BFFF"
tastes = list("waffle" = 1, "mushrooms" = 1)
foodtype = GRAIN | VEGETABLES | SUGAR | BREAKFAST
@@ -425,8 +428,8 @@
desc = "COOKIE!!!"
icon_state = "COOKIE!!!"
bitesize = 1
- bonus_reagents = list("nutriment" = 1)
- list_reagents = list("nutriment" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
filling_color = "#F0E68C"
tastes = list("cookie" = 1)
foodtype = GRAIN | SUGAR
@@ -436,7 +439,7 @@
name = "\improper Donk-pocket"
desc = "The food of choice for the seasoned traitor."
icon_state = "donkpocket"
- list_reagents = list("nutriment" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
cooked_type = /obj/item/reagent_containers/food/snacks/donkpocket/warm
filling_color = "#CD853F"
tastes = list("meat" = 2, "dough" = 2, "laziness" = 1)
@@ -445,8 +448,8 @@
/obj/item/reagent_containers/food/snacks/donkpocket/warm
name = "warm Donk-pocket"
desc = "The heated food of choice for the seasoned traitor."
- bonus_reagents = list("omnizine" = 3)
- list_reagents = list("nutriment" = 4, "omnizine" = 3)
+ bonus_reagents = list(/datum/reagent/medicine/omnizine = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/medicine/omnizine = 3)
cooked_type = null
tastes = list("meat" = 2, "dough" = 2, "laziness" = 1)
foodtype = GRAIN
@@ -455,7 +458,7 @@
name = "\improper Dank-pocket"
desc = "The food of choice for the seasoned botanist."
icon_state = "dankpocket"
- list_reagents = list("lipolicide" = 3, "space_drugs" = 3, "nutriment" = 4)
+ list_reagents = list(/datum/reagent/toxin/lipolicide = 3, /datum/reagent/drug/space_drugs = 3, /datum/reagent/consumable/nutriment = 4)
filling_color = "#00FF00"
tastes = list("meat" = 2, "dough" = 2)
foodtype = GRAIN | VEGETABLES
@@ -578,8 +581,8 @@
name = "fortune cookie"
desc = "A true prophecy in each cookie!"
icon_state = "fortune_cookie"
- bonus_reagents = list("nutriment" = 2)
- list_reagents = list("nutriment" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3)
filling_color = "#F4A460"
tastes = list("cookie" = 1)
foodtype = GRAIN | SUGAR
@@ -588,8 +591,8 @@
name = "poppy pretzel"
desc = "It's all twisted up!"
icon_state = "poppypretzel"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
filling_color = "#F0E68C"
tastes = list("pretzel" = 1)
foodtype = GRAIN | SUGAR
@@ -598,8 +601,8 @@
name = "plump helmet biscuit"
desc = "This is a finely-prepared plump helmet biscuit. The ingredients are exceptionally minced plump helmet, and well-minced dwarven wheat flour."
icon_state = "phelmbiscuit"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
filling_color = "#F0E68C"
tastes = list("mushroom" = 1, "biscuit" = 1)
foodtype = GRAIN | VEGETABLES
@@ -609,18 +612,18 @@
if(fey)
name = "exceptional plump helmet biscuit"
desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump helmet biscuit!"
- bonus_reagents = list("omnizine" = 5, "nutriment" = 1, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/medicine/omnizine = 5, /datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
. = ..()
if(fey)
- reagents.add_reagent("omnizine", 5)
+ reagents.add_reagent(/datum/reagent/medicine/omnizine, 5)
/obj/item/reagent_containers/food/snacks/cracker
name = "cracker"
desc = "It's a salted cracker."
icon_state = "cracker"
bitesize = 1
- bonus_reagents = list("nutriment" = 1)
- list_reagents = list("nutriment" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
filling_color = "#F0E68C"
tastes = list("cracker" = 1)
foodtype = GRAIN
@@ -630,8 +633,8 @@
desc = "Fresh footlong ready to go down on."
icon_state = "hotdog"
bitesize = 3
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
- list_reagents = list("nutriment" = 6, "ketchup" = 3, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/ketchup = 3, /datum/reagent/consumable/nutriment/vitamin = 3)
filling_color = "#8B0000"
tastes = list("bun" = 3, "meat" = 2)
foodtype = GRAIN | MEAT | VEGETABLES
@@ -640,8 +643,8 @@
name = "meat bun"
desc = "Has the potential to not be Dog."
icon_state = "meatbun"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#8B0000"
tastes = list("bun" = 3, "meat" = 2)
foodtype = GRAIN | MEAT | VEGETABLES
@@ -650,7 +653,7 @@
name = "khachapuri"
desc = "Bread with egg and cheese?"
icon_state = "khachapuri"
- list_reagents = list("nutriment" = 12, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 12, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#FFFF4D"
tastes = list("bread" = 1, "egg" = 1, "cheese" = 1)
foodtype = GRAIN | MEAT | DAIRY
@@ -659,8 +662,8 @@
name = "sugar cookie"
desc = "Just like your little sister used to make."
icon_state = "sugarcookie"
- bonus_reagents = list("nutriment" = 1, "sugar" = 3)
- list_reagents = list("nutriment" = 3, "sugar" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/sugar = 3)
filling_color = "#CD853F"
tastes = list("sweetness" = 1)
foodtype = GRAIN | JUNKFOOD | SUGAR
@@ -670,8 +673,8 @@
name = "chocolate cornet"
desc = "Which side's the head, the fat end or the thin end?"
icon_state = "chococornet"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#FFE4C4"
tastes = list("biscuit" = 3, "chocolate" = 1)
foodtype = GRAIN | JUNKFOOD
@@ -680,8 +683,8 @@
name = "oatmeal cookie"
desc = "The best of both cookie and oat."
icon_state = "oatmealcookie"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#D2691E"
tastes = list("cookie" = 2, "oat" = 1)
foodtype = GRAIN
@@ -691,8 +694,8 @@
name = "raisin cookie"
desc = "Why would you put raisins on a cookie?"
icon_state = "raisincookie"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#F0E68C"
tastes = list("cookie" = 1, "raisins" = 1)
foodtype = GRAIN | FRUIT
@@ -702,8 +705,8 @@
name = "cherry cupcake"
desc = "A sweet cupcake with cherry bits."
icon_state = "cherrycupcake"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#F0E68C"
tastes = list("cake" = 3, "cherry" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -712,8 +715,8 @@
name = "blue cherry cupcake"
desc = "Blue cherries inside a delicious cupcake."
icon_state = "bluecherrycupcake"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#F0E68C"
tastes = list("cake" = 3, "blue cherry" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -722,8 +725,8 @@
name = "strawberry cupcake"
desc = "Strawberry inside a delicious cupcake."
icon_state = "strawberrycupcake"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#F0E68C"
tastes = list("cake" = 2, "strawberry" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -732,8 +735,8 @@
name = "honey bun"
desc = "A sticky pastry bun glazed with honey."
icon_state = "honeybun"
- bonus_reagents = list("nutriment" = 1, "honey" = 1)
- list_reagents = list("nutriment" = 5, "honey" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/honey = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/honey = 5)
filling_color = "#F2CE91"
tastes = list("pastry" = 1, "sweetness" = 1)
foodtype = GRAIN | SUGAR
@@ -745,8 +748,8 @@
desc = "A fluffy pancake. The softer, superior relative of the waffle."
icon_state = "pancakes_1"
item_state = "pancakes"
- bonus_reagents = list("vitamin" = 1)
- list_reagents = list("nutriment" = 4, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 1)
filling_color = "#D2691E"
tastes = list("pancakes" = 1)
foodtype = GRAIN | SUGAR | BREAKFAST
@@ -756,8 +759,8 @@
desc = "A fluffy and delicious blueberry pancake."
icon_state = "bbpancakes_1"
item_state = "bbpancakes"
- bonus_reagents = list("vitamin" = 2)
- list_reagents = list("nutriment" = 6, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("pancakes" = 1, "blueberries" = 1)
/obj/item/reagent_containers/food/snacks/pancakes/chocolatechip
@@ -765,8 +768,8 @@
desc = "A fluffy and delicious chocolate chip pancake."
icon_state = "ccpancakes_1"
item_state = "ccpancakes"
- bonus_reagents = list("vitamin" = 2)
- list_reagents = list("nutriment" = 6, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("pancakes" = 1, "chocolate" = 1)
/obj/item/reagent_containers/food/snacks/pancakes/Initialize()
diff --git a/code/modules/food_and_drinks/food/snacks_pie.dm b/code/modules/food_and_drinks/food/snacks_pie.dm
index a920b467..4d4a4f00 100644
--- a/code/modules/food_and_drinks/food/snacks_pie.dm
+++ b/code/modules/food_and_drinks/food/snacks_pie.dm
@@ -5,7 +5,7 @@
bitesize = 3
w_class = WEIGHT_CLASS_NORMAL
volume = 80
- list_reagents = list("nutriment" = 10, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("pie" = 1)
foodtype = GRAIN
@@ -14,7 +14,7 @@
desc = "A simple pie, still delicious."
icon_state = "pie"
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/pie
- bonus_reagents = list("nutriment" = 8, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("pie" = 1)
foodtype = GRAIN
@@ -23,8 +23,8 @@
desc = "Just like back home, on clown planet! HONK!"
icon_state = "pie"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "banana" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/banana = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("pie" = 1)
foodtype = GRAIN | DAIRY | SUGAR
var/stunning = TRUE
@@ -61,7 +61,7 @@
qdel(src)
/obj/item/reagent_containers/food/snacks/pie/cream/nostun
- list_reagents = list("laughter" = 15)
+ list_reagents = list(/datum/reagent/consumable/laughter = 15)
stunning = FALSE
/obj/item/reagent_containers/food/snacks/pie/cream/body
@@ -90,8 +90,8 @@
name = "berry clafoutis"
desc = "No black birds, this is a good sign."
icon_state = "berryclafoutis"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 10, "berryjuice" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/berryjuice = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("pie" = 1, "blackberries" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -99,8 +99,8 @@
name = "beary pie"
desc = "No brown bears, this is a good sign."
icon_state = "bearypie"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 3)
- list_reagents = list("nutriment" = 2, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("pie" = 1, "meat" = 1, "salmon" = 1)
foodtype = GRAIN | SUGAR
@@ -108,7 +108,7 @@
name = "meat-pie"
icon_state = "meatpie"
desc = "An old barber recipe, very delicious!"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("pie" = 1, "meat" = 1)
foodtype = GRAIN | MEAT
@@ -117,7 +117,7 @@
name = "tofu-pie"
icon_state = "meatpie"
desc = "A delicious tofu pie."
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("pie" = 1, "tofu" = 1)
foodtype = GRAIN
@@ -127,8 +127,8 @@
desc = "Sweet and tasty poison pie."
icon_state = "amanita_pie"
bitesize = 4
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 6, "amatoxin" = 3, "mushroomhallucinogen" = 1, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/toxin/amatoxin = 3, /datum/reagent/drug/mushroomhallucinogen = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("pie" = 1, "mushroom" = 1)
foodtype = GRAIN | VEGETABLES | TOXIC | GROSS
@@ -137,7 +137,7 @@
name = "plump pie"
desc = "I bet you love stuff made out of plump helmets!"
icon_state = "plump_pie"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("pie" = 1, "mushroom" = 1)
foodtype = GRAIN | VEGETABLES
@@ -148,9 +148,9 @@
if(fey)
name = "exceptional plump pie"
desc = "Microwave is taken by a fey mood! It has cooked an exceptional plump pie!"
- bonus_reagents = list("nutriment" = 1, "omnizine" = 5, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/medicine/omnizine = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
if(fey)
- reagents.add_reagent("omnizine", 5)
+ reagents.add_reagent(/datum/reagent/medicine/omnizine, 5)
/obj/item/reagent_containers/food/snacks/pie/xemeatpie
@@ -158,7 +158,7 @@
icon_state = "xenomeatpie"
desc = "A delicious meatpie. Probably heretical."
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("pie" = 1, "meat" = 1, "acid" = 1)
foodtype = GRAIN | MEAT
@@ -167,7 +167,7 @@
name = "apple pie"
desc = "A pie containing sweet sweet love...or apple."
icon_state = "applepie"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("pie" = 1, "apple" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -175,7 +175,7 @@
name = "cherry pie"
desc = "Taste so good, make a grown man cry."
icon_state = "cherrypie"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("pie" = 7, "Nicole Paige Brooks" = 2)
foodtype = GRAIN | FRUIT | SUGAR
@@ -186,7 +186,7 @@
icon_state = "pumpkinpie"
slice_path = /obj/item/reagent_containers/food/snacks/pumpkinpieslice
slices_num = 5
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("pie" = 1, "pumpkin" = 1)
foodtype = GRAIN | VEGETABLES
@@ -197,7 +197,7 @@
icon_state = "pumpkinpieslice"
trash = /obj/item/trash/plate
filling_color = "#FFA500"
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
tastes = list("pie" = 1, "pumpkin" = 1)
foodtype = GRAIN | VEGETABLES
@@ -205,8 +205,8 @@
name = "golden apple streusel tart"
desc = "A tasty dessert that won't make it through a metal detector."
icon_state = "gappletart"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 8, "gold" = 5, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/gold = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("pie" = 1, "apple" = 1, "expensive metal" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -214,8 +214,8 @@
name = "grape tart"
desc = "A tasty dessert that reminds you of the wine you didn't make."
icon_state = "grapetart"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 4, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("pie" = 1, "grape" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -223,8 +223,8 @@
name = "mime tart"
desc = "..."
icon_state = "mimetart"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4, "nothing" = 10)
- list_reagents = list("nutriment" = 5, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4, /datum/reagent/consumable/nothing = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("pie" = 1, "nothing" = 1)
foodtype = GRAIN
@@ -232,8 +232,8 @@
name = "berry tart"
desc = "A tasty dessert of many different small barries on a thin pie crust."
icon_state = "berrytart"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 3, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("pie" = 1, "berries" = 2)
foodtype = GRAIN | FRUIT
@@ -241,8 +241,8 @@
name = "chocolate lava tart"
desc = "A tasty dessert made of chocaloate, with a liquid core."
icon_state = "cocolavatart"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 4, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("pie" = 1, "grape" = 1)
foodtype = GRAIN | SUGAR
@@ -252,7 +252,7 @@
icon_state = "blumpkinpie"
slice_path = /obj/item/reagent_containers/food/snacks/blumpkinpieslice
slices_num = 5
- bonus_reagents = list("nutriment" = 3, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("pie" = 1, "a mouthful of pool water" = 1)
foodtype = GRAIN | VEGETABLES
@@ -263,7 +263,7 @@
icon_state = "blumpkinpieslice"
trash = /obj/item/trash/plate
filling_color = "#1E90FF"
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
tastes = list("pie" = 1, "a mouthful of pool water" = 1)
foodtype = GRAIN | VEGETABLES
@@ -273,7 +273,7 @@
icon_state = "dulcedebatata"
slice_path = /obj/item/reagent_containers/food/snacks/dulcedebatataslice
slices_num = 5
- bonus_reagents = list("nutriment" = 4, "vitamin" = 8)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 8)
tastes = list("jelly" = 1, "sweet potato" = 1)
foodtype = GRAIN | VEGETABLES | SUGAR
@@ -284,7 +284,7 @@
icon_state = "dulcedebatataslice"
trash = /obj/item/trash/plate
filling_color = "#8B4513"
- list_reagents = list("nutriment" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
tastes = list("jelly" = 1, "sweet potato" = 1)
foodtype = GRAIN | VEGETABLES | SUGAR
@@ -292,7 +292,7 @@
name = "frosty pie"
desc = "Tastes like blue and cold."
icon_state = "frostypie"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("mint" = 1, "pie" = 1)
foodtype = GRAIN | FRUIT | SUGAR
@@ -302,7 +302,7 @@
icon_state = "baklava"
slice_path = /obj/item/reagent_containers/food/snacks/baklavaslice
slices_num = 6
- bonus_reagents = list("nutriment" = 2, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("nuts" = 1, "pie" = 1)
foodtype = GRAIN
@@ -313,7 +313,7 @@
icon_state = "baklavaslice"
trash = /obj/item/trash/plate
filling_color = "#1E90FF"
- list_reagents = list("nutriment" = 2, "vitamin" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("nuts" = 1, "pie" = 1)
foodtype = GRAIN
@@ -321,6 +321,6 @@
name = "strawberry pie"
desc = "A strawberry.pie."
icon_state = "strawberrypie"
- bonus_reagents = list("nutriment" = 6, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("strawberry" = 1, "pie" = 1)
foodtype = GRAIN | FRUIT | SUGAR
diff --git a/code/modules/food_and_drinks/food/snacks_pizza.dm b/code/modules/food_and_drinks/food/snacks_pizza.dm
index b75f8787..6aebe303 100644
--- a/code/modules/food_and_drinks/food/snacks_pizza.dm
+++ b/code/modules/food_and_drinks/food/snacks_pizza.dm
@@ -6,13 +6,13 @@
w_class = WEIGHT_CLASS_NORMAL
slices_num = 6
volume = 80
- list_reagents = list("nutriment" = 30, "tomatojuice" = 6, "vitamin" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 30, /datum/reagent/consumable/tomatojuice = 6, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1)
foodtype = GRAIN | DAIRY | VEGETABLES
/obj/item/reagent_containers/food/snacks/pizzaslice
icon = 'icons/obj/food/pizzaspaghetti.dmi'
- list_reagents = list("nutriment" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5)
foodtype = GRAIN | DAIRY | VEGETABLES
/obj/item/reagent_containers/food/snacks/pizza/margherita
@@ -20,7 +20,7 @@
desc = "The most cheezy pizza in galaxy."
icon_state = "pizzamargherita"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/margherita
- bonus_reagents = list("nutriment" = 5, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1)
foodtype = GRAIN | VEGETABLES
@@ -41,8 +41,8 @@
desc = "Greasy pizza with delicious meat."
icon_state = "meatpizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/meat
- bonus_reagents = list("nutriment" = 5, "vitamin" = 8)
- list_reagents = list("nutriment" = 30, "tomatojuice" = 6, "vitamin" = 8)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 8)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 30, /datum/reagent/consumable/tomatojuice = 6, /datum/reagent/consumable/nutriment/vitamin = 8)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "meat" = 1)
foodtype = GRAIN | VEGETABLES| DAIRY | MEAT
@@ -59,8 +59,8 @@
desc = "Very special pizza."
icon_state = "mushroompizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/mushroom
- bonus_reagents = list("nutriment" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 30, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 30, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "mushroom" = 1)
foodtype = GRAIN | VEGETABLES | DAIRY
@@ -77,8 +77,8 @@
desc = "No one of Tomatos Sapiens were harmed during making this pizza."
icon_state = "vegetablepizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/vegetable
- bonus_reagents = list("nutriment" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 25, "tomatojuice" = 6, "oculine" = 12, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 25, /datum/reagent/consumable/tomatojuice = 6, /datum/reagent/medicine/oculine = 12, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("crust" = 1, "tomato" = 2, "cheese" = 1, "carrot" = 1)
foodtype = GRAIN | VEGETABLES | DAIRY
@@ -95,8 +95,8 @@
desc = "Who thought this would be a good idea?"
icon_state = "donkpocketpizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/donkpocket
- bonus_reagents = list("nutriment" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 25, "tomatojuice" = 6, "omnizine" = 10, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 25, /datum/reagent/consumable/tomatojuice = 6, /datum/reagent/medicine/omnizine = 10, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "meat" = 1, "laziness" = 1)
foodtype = GRAIN | VEGETABLES | DAIRY | MEAT | JUNKFOOD
@@ -113,8 +113,8 @@
desc = "The hippie's pizza of choice."
icon_state = "dankpizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/dank
- bonus_reagents = list("nutriment" = 2, "vitamin" = 6)
- list_reagents = list("nutriment" = 25, "doctorsdelight" = 5, "tomatojuice" = 6, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 25, /datum/reagent/consumable/doctor_delight = 5, /datum/reagent/consumable/tomatojuice = 6, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "meat" = 1)
foodtype = GRAIN | VEGETABLES | FRUIT | DAIRY
@@ -131,7 +131,7 @@
desc = "You can really smell the sassiness."
icon_state = "sassysagepizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/sassysage
- bonus_reagents = list("nutriment" = 6, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "meat" = 1)
foodtype = GRAIN | VEGETABLES | DAIRY
@@ -148,7 +148,7 @@
desc = "The pizza equivalent of Einstein's riddle."
icon_state = "pineapplepizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/pineapple
- bonus_reagents = list("nutriment" = 6, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "pineapple" = 6, "ham" = 2)
foodtype = PINEAPPLE //Over powering tast of gods fruit
@@ -162,7 +162,7 @@
/obj/item/reagent_containers/food/snacks/pizza/pineapple/anomaly
desc = "A anomaly made pizza with pineapple..."
- bonus_reagents = list("nutriment" = 16, "vitamin" = 16)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 16, /datum/reagent/consumable/nutriment/vitamin = 16)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "pineapple" = 6, "ham" = 2, "good" = 10)
/obj/item/reagent_containers/food/snacks/pizzaslice/pineapple/anomaly
@@ -174,7 +174,7 @@
desc = "Hello, you've reached Arnold's pizza shop. I'm not here now, I'm out killing pepperoni."
icon_state = "arnoldpizza"
slice_path = /obj/item/reagent_containers/food/snacks/pizzaslice/arnold
- bonus_reagents = list("nutriment" = 30, "vitamin" = 6, "iron" = 10, "omnizine" = 30)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 30, /datum/reagent/consumable/nutriment/vitamin = 6, /datum/reagent/iron = 10, /datum/reagent/medicine/omnizine = 30)
tastes = list("crust" = 1, "tomato" = 1, "cheese" = 1, "pepperoni" = 2, "9 millimeter bullets" = 2)
/obj/item/reagent_containers/food/snacks/proc/try_break_off(mob/living/M, mob/living/user) //maybe i give you a pizza maybe i break off your arm
diff --git a/code/modules/food_and_drinks/food/snacks_salad.dm b/code/modules/food_and_drinks/food/snacks_salad.dm
index f5fcec0a..e2727332 100644
--- a/code/modules/food_and_drinks/food/snacks_salad.dm
+++ b/code/modules/food_and_drinks/food/snacks_salad.dm
@@ -5,7 +5,7 @@
trash = /obj/item/reagent_containers/glass/bowl
bitesize = 3
w_class = WEIGHT_CLASS_NORMAL
- list_reagents = list("nutriment" = 7, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("leaves" = 1)
foodtype = VEGETABLES
@@ -17,8 +17,8 @@
name = "\improper Aesir salad"
desc = "Probably too incredible for mortal men to fully enjoy."
icon_state = "aesirsalad"
- bonus_reagents = list("omnizine" = 2, "vitamin" = 6)
- list_reagents = list("nutriment" = 8, "omnizine" = 8, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/medicine/omnizine = 2, /datum/reagent/consumable/nutriment/vitamin = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/medicine/omnizine = 8, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("leaves" = 1)
foodtype = VEGETABLES
@@ -26,8 +26,8 @@
name = "herb salad"
desc = "A tasty salad with apples on top."
icon_state = "herbsalad"
- bonus_reagents = list("vitamin" = 4)
- list_reagents = list("nutriment" = 8, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("leaves" = 1, "apple" = 1)
foodtype = VEGETABLES | FRUIT
@@ -35,8 +35,8 @@
name = "valid salad"
desc = "It's just an herb salad with meatballs and fried potato slices. Nothing suspicious about it."
icon_state = "validsalad"
- bonus_reagents = list("doctorsdelight" = 5, "vitamin" = 4)
- list_reagents = list("nutriment" = 8, "doctorsdelight" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/doctor_delight = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/doctor_delight = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("leaves" = 1, "potato" = 1, "meat" = 1, "valids" = 1)
foodtype = VEGETABLES | MEAT | FRIED | JUNKFOOD | FRUIT
@@ -44,8 +44,8 @@
name = "oatmeal"
desc = "A nice bowl of oatmeal."
icon_state = "oatmeal"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 4)
- list_reagents = list("nutriment" = 7, "milk" = 10, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/milk = 10, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("oats" = 1, "milk" = 1)
foodtype = DAIRY | GRAIN | BREAKFAST
@@ -53,7 +53,7 @@
name = "fruit salad"
desc = "Your standard fruit salad."
icon_state = "fruitsalad"
- bonus_reagents = list("nutriment" = 2, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("fruit" = 1)
foodtype = FRUIT | BREAKFAST
@@ -61,8 +61,8 @@
name = "jungle salad"
desc = "Exotic fruits in a bowl."
icon_state = "junglesalad"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 4)
- list_reagents = list("nutriment" = 7, "banana" = 5, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/banana = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("fruit" = 1, "the jungle" = 1)
foodtype = FRUIT | BREAKFAST
@@ -70,8 +70,8 @@
name = "citrus delight"
desc = "Citrus overload!"
icon_state = "citrusdelight"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 4)
- list_reagents = list("nutriment" = 7, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("sourness" = 1, "leaves" = 1)
foodtype = FRUIT | BREAKFAST
@@ -80,7 +80,7 @@
desc = "A bowl of raw rice."
icon_state = "ricebowl"
cooked_type = /obj/item/reagent_containers/food/snacks/salad/boiledrice
- list_reagents = list("nutriment" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4)
tastes = list("rice" = 1)
foodtype = GRAIN | RAW
@@ -88,8 +88,8 @@
name = "boiled rice"
desc = "A warm bowl of rice."
icon_state = "boiledrice"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 5, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("rice" = 1)
foodtype = GRAIN | BREAKFAST
@@ -97,7 +97,7 @@
name = "rice pudding"
desc = "Everybody loves rice pudding!"
icon_state = "ricepudding"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("rice" = 1, "sweetness" = 1)
foodtype = GRAIN | DAIRY
@@ -105,7 +105,7 @@
name = "rice and pork"
desc = "Well, it looks like pork..."
icon_state = "riceporkbowl"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("rice" = 1, "meat" = 1)
foodtype = GRAIN | MEAT
@@ -113,6 +113,6 @@
name = "egg bowl"
desc = "A bowl of rice with a fried egg."
icon_state = "eggbowl"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("rice" = 1, "egg" = 1)
foodtype = GRAIN | MEAT //EGG = MEAT -NinjaNomNom 2017
diff --git a/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm b/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm
index 17a710ad..3cc4cfe6 100644
--- a/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm
+++ b/code/modules/food_and_drinks/food/snacks_sandwichtoast.dm
@@ -4,8 +4,8 @@
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "sandwich"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 6, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
cooked_type = /obj/item/reagent_containers/food/snacks/toastedsandwich
tastes = list("meat" = 2, "cheese" = 1, "bread" = 2, "lettuce" = 1)
foodtype = GRAIN | VEGETABLES
@@ -16,8 +16,8 @@
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "toastedsandwich"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "carbon" = 2)
- list_reagents = list("nutriment" = 6, "carbon" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/carbon = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/carbon = 2)
tastes = list("toast" = 1)
foodtype = GRAIN
@@ -27,8 +27,8 @@
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "toastedsandwich"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 1)
- list_reagents = list("nutriment" = 7, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("toast" = 1, "cheese" = 1)
foodtype = GRAIN | DAIRY
@@ -43,13 +43,13 @@
foodtype = GRAIN
/obj/item/reagent_containers/food/snacks/jellysandwich/slime
- bonus_reagents = list("slimejelly" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 2, "slimejelly" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GRAIN | TOXIC
/obj/item/reagent_containers/food/snacks/jellysandwich/cherry
- bonus_reagents = list("cherryjelly" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 2, "cherryjelly" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GRAIN | FRUIT
/obj/item/reagent_containers/food/snacks/jellysandwich/pbj
@@ -59,13 +59,13 @@
tastes = list("bread" = 1, "jelly" = 1, "peanuts" = 1)
/obj/item/reagent_containers/food/snacks/jellysandwich/pbj/cherry
- bonus_reagents = list("cherryjelly" = 5, "peanut_butter" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 2, "cherryjelly" = 5, "peanut_butter" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GRAIN | FRUIT
/obj/item/reagent_containers/food/snacks/jellysandwich/pbj/slime
- bonus_reagents = list("slimejelly" = 5, "peanut_butter" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 2, "slimejelly" = 5, "peanut_butter" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GRAIN | TOXIC
/obj/item/reagent_containers/food/snacks/peanutbutter_sandwich
@@ -75,8 +75,8 @@
icon_state = "peanutbuttersandwich"
trash = /obj/item/trash/plate
bitesize = 3
- bonus_reagents = list("peanut_butter" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 2, "peanut_butter" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GRAIN
/obj/item/reagent_containers/food/snacks/notasandwich
@@ -85,8 +85,8 @@
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "notasandwich"
trash = /obj/item/trash/plate
- bonus_reagents = list("vitamin" = 6)
- list_reagents = list("nutriment" = 6, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("nothing suspicious" = 1)
foodtype = GRAIN | GROSS
@@ -101,13 +101,13 @@
foodtype = GRAIN
/obj/item/reagent_containers/food/snacks/jelliedtoast/cherry
- bonus_reagents = list("cherryjelly" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 1, "cherryjelly" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/cherryjelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GRAIN | FRUIT | SUGAR
/obj/item/reagent_containers/food/snacks/jelliedtoast/slime
- bonus_reagents = list("slimejelly" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 1, "slimejelly" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GRAIN | TOXIC | SUGAR
/obj/item/reagent_containers/food/snacks/peanut_buttertoast
@@ -117,8 +117,8 @@
icon_state = "peanutbuttertoast"
trash = /obj/item/trash/plate
bitesize = 3
- bonus_reagents = list("peanut_butter" = 5, "vitamin" = 2)
- list_reagents = list("nutriment" = 1, "peanut_butter" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/peanut_butter = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("toast" = 1, "peanuts" = 1)
foodtype = GRAIN
@@ -128,8 +128,8 @@
desc = "This seems awfully bitter."
icon = 'icons/obj/food/burgerbread.dmi'
icon_state = "twobread"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 2, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("bread" = 2)
foodtype = GRAIN
@@ -139,6 +139,6 @@
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "tunasandwich"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("tuna" = 4, "mayonnaise" = 2, "bread" = 2)
foodtype = GRAIN | MEAT
diff --git a/code/modules/food_and_drinks/food/snacks_soup.dm b/code/modules/food_and_drinks/food/snacks_soup.dm
index 06cc5594..8a1b2c0a 100644
--- a/code/modules/food_and_drinks/food/snacks_soup.dm
+++ b/code/modules/food_and_drinks/food/snacks_soup.dm
@@ -4,7 +4,7 @@
trash = /obj/item/reagent_containers/glass/bowl
bitesize = 5
volume = 80
- list_reagents = list("nutriment" = 8, "water" = 5, "vitamin" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/water = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("tasteless soup" = 1)
foodtype = VEGETABLES
@@ -16,7 +16,7 @@
name = "wish soup"
desc = "I wish this was soup."
icon_state = "wishsoup"
- list_reagents = list("water" = 10)
+ list_reagents = list(/datum/reagent/water = 10)
tastes = list("wishes" = 1)
/obj/item/reagent_containers/food/snacks/soup/wish/Initialize()
@@ -24,17 +24,17 @@
var/wish_true = prob(25)
if(wish_true)
desc = "A wish come true!"
- bonus_reagents = list("nutriment" = 9, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 9, /datum/reagent/consumable/nutriment/vitamin = 1)
if(wish_true)
- reagents.add_reagent("nutriment", 9)
- reagents.add_reagent("vitamin", 1)
+ reagents.add_reagent(/datum/reagent/consumable/nutriment, 9)
+ reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 1)
foodtype = VEGETABLES
/obj/item/reagent_containers/food/snacks/soup/meatball
name = "meatball soup"
desc = "You've got balls kid, BALLS!"
icon_state = "meatballsoup"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("meat" = 1)
foodtype = MEAT
@@ -42,8 +42,8 @@
name = "slime soup"
desc = "If no water is available, you may substitute tears."
icon_state = "slimesoup"
- bonus_reagents = list("nutriment" = 1, "slimejelly" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 5, "slimejelly" = 5, "water" = 5, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/toxin/slimejelly = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/toxin/slimejelly = 5, /datum/reagent/water = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("slime" = 1)
foodtype = TOXIC | SUGAR
@@ -51,8 +51,8 @@
name = "tomato soup"
desc = "Smells like copper."
icon_state = "tomatosoup"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 6)
- list_reagents = list("nutriment" = 2, "blood" = 10, "water" = 5, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/blood = 10, /datum/reagent/water = 5, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("iron" = 1)
foodtype = GROSS
@@ -61,8 +61,8 @@
desc = "A savory dish of alien wing wang in soy."
icon_state = "wingfangchu"
trash = /obj/item/reagent_containers/glass/bowl
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 6, "soysauce" = 5, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/soysauce = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("soy" = 1)
foodtype = MEAT
@@ -70,8 +70,8 @@
name = "clown's tears"
desc = "Not very funny."
icon_state = "clownstears"
- bonus_reagents = list("nutriment" = 1, "banana" = 5, "vitamin" = 8, "clownstears" = 10)
- list_reagents = list("nutriment" = 4, "banana" = 5, "water" = 5, "vitamin" = 8, "clownstears" = 10)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/banana = 5, /datum/reagent/consumable/nutriment/vitamin = 8, /datum/reagent/consumable/clownstears = 10)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/banana = 5, /datum/reagent/water = 5, /datum/reagent/consumable/nutriment/vitamin = 8, /datum/reagent/consumable/clownstears = 10)
tastes = list("a bad joke" = 1)
foodtype = FRUIT | SUGAR
@@ -79,7 +79,7 @@
name = "vegetable soup"
desc = "A true vegan meal."
icon_state = "vegetablesoup"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("vegetables" = 1)
foodtype = VEGETABLES
@@ -87,7 +87,7 @@
name = "nettle soup"
desc = "To think, the botanist would've beat you to death with one of these."
icon_state = "nettlesoup"
- bonus_reagents = list("nutriment" = 1, "omnizine" = 5, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/medicine/omnizine = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("nettles" = 1)
foodtype = VEGETABLES
@@ -96,21 +96,23 @@
desc = "The mystery is, why aren't you eating it?"
icon_state = "mysterysoup"
var/extra_reagent = null
- list_reagents = list("nutriment" = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6)
tastes = list("chaos" = 1)
/obj/item/reagent_containers/food/snacks/soup/mystery/Initialize()
. = ..()
- extra_reagent = pick("capsaicin", "frostoil", "omnizine", "banana", "blood", "slimejelly", "toxin", "banana", "carbon", "oculine")
- bonus_reagents = list("[extra_reagent]" = 5, "nutriment" = 6)
- reagents.add_reagent("[extra_reagent]", 5)
+ extra_reagent = pick(/datum/reagent/consumable/capsaicin, /datum/reagent/consumable/frostoil,
+ /datum/reagent/medicine/omnizine, /datum/reagent/consumable/banana, /datum/reagent/blood,
+ /datum/reagent/toxin/slimejelly, /datum/reagent/toxin, /datum/reagent/carbon, /datum/reagent/medicine/oculine)
+ bonus_reagents = list(extra_reagent = 5, /datum/reagent/consumable/nutriment = 6)
+ reagents.add_reagent(extra_reagent, 5)
/obj/item/reagent_containers/food/snacks/soup/hotchili
name = "hot chili"
desc = "A five alarm Texan Chili!"
icon_state = "hotchili"
- bonus_reagents = list("nutriment" = 1, "tomatojuice" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 5, "capsaicin" = 1, "tomatojuice" = 2, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/tomatojuice = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/capsaicin = 1, /datum/reagent/consumable/tomatojuice = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("hot peppers" = 1)
foodtype = VEGETABLES
@@ -118,8 +120,8 @@
name = "cold chili"
desc = "This slush is barely a liquid!"
icon_state = "coldchili"
- bonus_reagents = list("nutriment" = 1, "tomatojuice" = 2, "vitamin" = 2)
- list_reagents = list("nutriment" = 5, "frostoil" = 1, "tomatojuice" = 2, "vitamin" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/tomatojuice = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/frostoil = 1, /datum/reagent/consumable/tomatojuice = 2, /datum/reagent/consumable/nutriment/vitamin = 2)
tastes = list("tomato" = 1, "mint" = 1)
foodtype = VEGETABLES
@@ -127,8 +129,8 @@
name = "monkey's delight"
desc = "A delicious soup with dumplings and hunks of monkey meat simmered to perfection, in a broth that tastes faintly of bananas."
icon_state = "monkeysdelight"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
- list_reagents = list("nutriment" = 10, "banana" = 5, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/consumable/banana = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("the jungle" = 1, "banana" = 1)
foodtype = FRUIT
@@ -136,8 +138,8 @@
name = "tomato soup"
desc = "Drinking this feels like being a vampire! A tomato vampire..."
icon_state = "tomatosoup"
- bonus_reagents = list("nutriment" = 1, "tomatojuice" = 10, "vitamin" = 3)
- list_reagents = list("nutriment" = 5, "tomatojuice" = 10, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/tomatojuice = 10, /datum/reagent/consumable/nutriment/vitamin = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/tomatojuice = 10, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("tomato" = 1)
foodtype = VEGETABLES
@@ -145,7 +147,7 @@
name = "eyeball soup"
desc = "It looks back at you..."
icon_state = "eyeballsoup"
- bonus_reagents = list("nutriment" = 1, "liquidgibs" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/liquidgibs = 3)
tastes = list("tomato" = 1, "squirming" = 1)
foodtype = MEAT | GROSS
@@ -153,7 +155,7 @@
name = "milosoup"
desc = "The universes best soup! Yum!!!"
icon_state = "milosoup"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 3)
tastes = list("milo" = 1) // wtf is milo
foodtype = GROSS
@@ -161,8 +163,8 @@
name = "chantrelle soup"
desc = "A delicious and hearty mushroom soup."
icon_state = "mushroomsoup"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
- list_reagents = list("nutriment" = 8, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 4)
tastes = list("mushroom" = 1)
foodtype = VEGETABLES
@@ -170,7 +172,7 @@
name = "beet soup"
desc = "Wait, how do you spell it again..?"
icon_state = "beetsoup"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
foodtype = VEGETABLES
/obj/item/reagent_containers/food/snacks/soup/beet/Initialize()
@@ -184,8 +186,8 @@
desc = "Jello gelatin, from Alfred Hubbard's cookbook."
icon_state = "spacylibertyduff"
bitesize = 3
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
- list_reagents = list("nutriment" = 6, "mushroomhallucinogen" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/drug/mushroomhallucinogen = 6)
tastes = list("jelly" = 1, "mushroom" = 1)
foodtype = VEGETABLES
@@ -194,8 +196,8 @@
desc = "Looks curiously toxic."
icon_state = "amanitajelly"
bitesize = 3
- bonus_reagents = list("nutriment" = 1, "vitamin" = 5)
- list_reagents = list("nutriment" = 6, "mushroomhallucinogen" = 3, "amatoxin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/drug/mushroomhallucinogen = 3, /datum/reagent/toxin/amatoxin = 6)
tastes = list("jelly" = 1, "mushroom" = 1)
foodtype = VEGETABLES | TOXIC
@@ -203,8 +205,8 @@
name = "stew"
desc = "A nice and warm stew. Healthy and strong."
icon_state = "stew"
- bonus_reagents = list("nutriment" = 1, "tomatojuice" = 5, "vitamin" = 5)
- list_reagents = list("nutriment" = 10, "oculine" = 5, "tomatojuice" = 5, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/tomatojuice = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 10, /datum/reagent/medicine/oculine = 5, /datum/reagent/consumable/tomatojuice = 5, /datum/reagent/consumable/nutriment/vitamin = 5)
bitesize = 7
volume = 100
tastes = list("tomato" = 1, "carrot" = 1)
@@ -214,7 +216,7 @@
name = "sweet potato soup"
desc = "Delicious sweet potato in soup form."
icon_state = "sweetpotatosoup"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 5)
tastes = list("sweet potato" = 1)
foodtype = VEGETABLES | SUGAR
@@ -222,7 +224,7 @@
name = "red beet soup"
desc = "Quite a delicacy."
icon_state = "redbeetsoup"
- bonus_reagents = list("nutriment" = 4, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("beet" = 1)
foodtype = VEGETABLES
@@ -238,8 +240,8 @@
name = "electron soup"
desc = "A gastronomic curiosity of ethereal origin. It is famed for the minature weather system formed over a properly prepared soup."
icon_state = "electronsoup"
- list_reagents = list("nutriment" = 3, "liquidelectricity" = 5)
- tastes = list("mushroom" = 1, "electrons" = 4, "shockingly good")
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/liquidelectricity = 5)
+ tastes = list("mushroom" = 1, "electrons" = 4, "shockingly good" = 1)
filling_color = "#CC2B52"
foodtype = VEGETABLES | TOXIC
@@ -247,8 +249,8 @@
name = "bungo curry"
desc = "A spicy vegetable curry made with the humble bungo fruit, Exotic!"
icon_state = "bungocurry"
- bonus_reagents = list("vitamin" = 11)
- list_reagents = list("nutriment" = 6, "capsaicin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 11)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/capsaicin = 5)
tastes = list("bungo" = 2, "hot curry" = 4, "tropical sweetness" = 1)
filling_color = "#E6A625"
foodtype = VEGETABLES | FRUIT | DAIRY
diff --git a/code/modules/food_and_drinks/food/snacks_spaghetti.dm b/code/modules/food_and_drinks/food/snacks_spaghetti.dm
index 70a19220..d54ba6f0 100644
--- a/code/modules/food_and_drinks/food/snacks_spaghetti.dm
+++ b/code/modules/food_and_drinks/food/snacks_spaghetti.dm
@@ -4,7 +4,7 @@
desc = "Now that's a nic'e pasta!"
icon = 'icons/obj/food/pizzaspaghetti.dmi'
icon_state = "spaghetti"
- list_reagents = list("nutriment" = 1, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 1)
cooked_type = /obj/item/reagent_containers/food/snacks/boiledspaghetti
filling_color = "#F0E68C"
tastes = list("pasta" = 1)
@@ -16,8 +16,8 @@
icon = 'icons/obj/food/pizzaspaghetti.dmi'
icon_state = "spaghettiboiled"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 2)
- list_reagents = list("nutriment" = 2, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/nutriment/vitamin = 1)
custom_food_type = /obj/item/reagent_containers/food/snacks/customizable/pasta
filling_color = "#F0E68C"
tastes = list("pasta" = 1)
@@ -30,8 +30,8 @@
icon_state = "pastatomato"
trash = /obj/item/trash/plate
bitesize = 4
- bonus_reagents = list("nutriment" = 1, "tomatojuice" = 10, "vitamin" = 4)
- list_reagents = list("nutriment" = 6, "tomatojuice" = 10, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/tomatojuice = 10, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/tomatojuice = 10, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#DC143C"
tastes = list("pasta" = 1, "tomato" = 1)
foodtype = GRAIN | VEGETABLES
@@ -43,8 +43,8 @@
icon_state = "copypasta"
trash = /obj/item/trash/plate
bitesize = 4
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 12, "tomatojuice" = 20, "vitamin" = 8)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 12, /datum/reagent/consumable/tomatojuice = 20, /datum/reagent/consumable/nutriment/vitamin = 8)
filling_color = "#DC143C"
tastes = list("pasta" = 1, "tomato" = 1)
foodtype = GRAIN | VEGETABLES
@@ -55,8 +55,8 @@
icon = 'icons/obj/food/pizzaspaghetti.dmi'
icon_state = "meatballspaghetti"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 4)
- list_reagents = list("nutriment" = 8, "vitamin" = 4)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 4)
filling_color = "#F0E68C"
tastes = list("pasta" = 1, "tomato" = 1, "meat" = 1)
foodtype = GRAIN | MEAT
@@ -67,8 +67,8 @@
icon = 'icons/obj/food/pizzaspaghetti.dmi'
icon_state = "spesslaw"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 1, "vitamin" = 6)
- list_reagents = list("nutriment" = 8, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 6)
filling_color = "#F0E68C"
tastes = list("pasta" = 1, "tomato" = 1, "meat" = 1)
foodtype = GRAIN
@@ -79,8 +79,8 @@
icon = 'icons/obj/food/pizzaspaghetti.dmi'
icon_state = "chowmein"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 3, "vitamin" = 4)
- list_reagents = list("nutriment" = 7, "vitamin" = 6)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 7, /datum/reagent/consumable/nutriment/vitamin = 6)
tastes = list("noodle" = 1, "tomato" = 1)
foodtype = GRAIN
@@ -90,7 +90,7 @@
icon = 'icons/obj/food/pizzaspaghetti.dmi'
icon_state = "beefnoodle"
trash = /obj/item/reagent_containers/glass/bowl
- bonus_reagents = list("nutriment" = 5, "vitamin" = 6, "liquidgibs" = 3)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 6, /datum/reagent/liquidgibs = 3)
tastes = list("noodle" = 1, "meat" = 1)
foodtype = GRAIN | MEAT
@@ -100,6 +100,6 @@
icon = 'icons/obj/food/pizzaspaghetti.dmi'
icon_state = "butternoodles"
trash = /obj/item/trash/plate
- bonus_reagents = list("nutriment" = 8, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 1)
tastes = list("noodle" = 1, "butter" = 1)
foodtype = GRAIN | DAIRY
diff --git a/code/modules/food_and_drinks/food/snacks_sushi.dm b/code/modules/food_and_drinks/food/snacks_sushi.dm
index a4cbc5e3..d16ca790 100644
--- a/code/modules/food_and_drinks/food/snacks_sushi.dm
+++ b/code/modules/food_and_drinks/food/snacks_sushi.dm
@@ -5,7 +5,7 @@
desc = "A bowl of sticky rice for making sushi."
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushi_rice"
- list_reagents = list("sodiumchloride" = 5)
+ list_reagents = list(/datum/reagent/consumable/sodiumchloride = 5)
tastes = list("rice" = 5, "salt" = 1)
foodtype = GRAIN
@@ -14,7 +14,7 @@
desc = "A thin, light salt sheet of plant mater. This is commenly used in sushi recipes,"
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sea_weed"
- list_reagents = list("sodiumchloride" = 2)
+ list_reagents = list(/datum/reagent/consumable/sodiumchloride = 2)
tastes = list("plants" = 2, "salt" = 1)
foodtype = VEGETABLES
@@ -24,7 +24,7 @@
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "tuna_can"
//trash = /obj/item/trash/tuna_used //I dont know if I like this idea - A Masked Cat
- list_reagents = list("sodiumchloride" = 5, "mercury" = 2)
+ list_reagents = list(/datum/reagent/consumable/sodiumchloride = 5, /datum/reagent/mercury = 2)
tastes = list("tuna" = 15, "mercury" = 1, "salt" = 3)
foodtype = MEAT
@@ -34,8 +34,8 @@
desc = "A small cylindrical filled with rice and fish."
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_basic"
- bonus_reagents = list("vitamin" = 2)
- list_reagents = list("nutriment" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1)
bitesize = 1
filling_color = "#F2EEEA" //rgb(242, 238, 234)
tastes = list("fish" = 1, "rice" = 1, "salt" = 1)
@@ -46,8 +46,8 @@
desc = "A pice of carp lightly placed on some rice."
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_adv"
- bonus_reagents = list("vitamin" = 2)
- list_reagents = list("nutriment" = 2)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2)
bitesize = 1
filling_color = "#F2EEEA" //rgb(242, 238, 234)
tastes = list("fish" = 1, "rice" = 1, "salt" = 1)
@@ -58,8 +58,8 @@
desc = "A well prepared pice of the best of the carp fillet placed on rice. Looks fancy and fresh!"
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_pro"
- bonus_reagents = list("nutriment" = 1, "vitamin" = 2)
- list_reagents = list("nutriment" = 8, "vitamin" = 1)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/nutriment/vitamin = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 8, /datum/reagent/consumable/nutriment/vitamin = 1)
bitesize = 1
filling_color = "#F2EEEA" //rgb(242, 238, 234)
tastes = list("fish" = 1, "rice" = 1, "salt" = 1)
@@ -70,7 +70,7 @@
desc = "Spider eggs wrapped in a thin salted Kudzu pod"
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "sushie_egg"
- list_reagents = list("nutriment" = 3, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#FF3333" // R225 G051 B051
tastes = list("seaweed" = 1, "salty" = 2)
foodtype = MEAT | VEGETABLES
@@ -80,7 +80,7 @@
desc = "A ball of rice with some light salt and a wrap of Kudzu skin."
icon = 'modular_citadel/icons/obj/food/food.dmi'
icon_state = "riceball"
- list_reagents = list("nutriment" = 5, "sodiumchloride" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/sodiumchloride = 2)
tastes = list("rice" = 4, "salt" = 1)
foodtype = GRAIN
@@ -88,8 +88,8 @@
name = "carp sashimi"
desc = "Celebrate surviving attack from hostile alien lifeforms by hospitalising yourself."
icon_state = "sashimi"
- bonus_reagents = list("nutriment" = 1, "capsaicin" = 4, "vitamin" = 4)
- list_reagents = list("nutriment" = 6, "capsaicin" = 5)
+ bonus_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/capsaicin = 4, /datum/reagent/consumable/nutriment/vitamin = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/capsaicin = 5)
filling_color = "#FA8072"
tastes = list("fish" = 1, "hot peppers" = 1)
foodtype = MEAT | TOXIC
\ No newline at end of file
diff --git a/code/modules/food_and_drinks/food/snacks_vend.dm b/code/modules/food_and_drinks/food/snacks_vend.dm
index 2800d6c4..40daa8c8 100644
--- a/code/modules/food_and_drinks/food/snacks_vend.dm
+++ b/code/modules/food_and_drinks/food/snacks_vend.dm
@@ -7,7 +7,7 @@
desc = "Nougat love it or hate it."
icon_state = "candy"
trash = /obj/item/trash/candy
- list_reagents = list("nutriment" = 1, "sugar" = 3, "cocoa" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 3, /datum/reagent/consumable/coco = 3)
junkiness = 25
filling_color = "#D2691E"
tastes = list("candy" = 1)
@@ -18,7 +18,7 @@
icon_state = "sosjerky"
desc = "Beef jerky made from the finest space cows."
trash = /obj/item/trash/sosjerky
- list_reagents = list("nutriment" = 1, "sugar" = 3, "sodiumchloride" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 3, /datum/reagent/consumable/sodiumchloride = 2)
junkiness = 25
filling_color = "#8B0000"
tastes = list("dried meat" = 1)
@@ -27,7 +27,7 @@
/obj/item/reagent_containers/food/snacks/sosjerky/healthy
name = "homemade beef jerky"
desc = "Homemade beef jerky made from the finest space cows."
- list_reagents = list("nutriment" = 3, "vitamin" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 1)
junkiness = 0
/obj/item/reagent_containers/food/snacks/chips
@@ -36,7 +36,7 @@
icon_state = "chips"
trash = /obj/item/trash/chips
bitesize = 1
- list_reagents = list("nutriment" = 1, "sugar" = 3, "sodiumchloride" = 1)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 3, /datum/reagent/consumable/sodiumchloride = 1)
junkiness = 20
filling_color = "#FFD700"
tastes = list("salt" = 1, "crisps" = 1)
@@ -47,7 +47,7 @@
icon_state = "4no_raisins"
desc = "Best raisins in the universe. Not sure why."
trash = /obj/item/trash/raisins
- list_reagents = list("nutriment" = 2, "sugar" = 4)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/sugar = 4)
junkiness = 25
filling_color = "#8B0000"
tastes = list("dried raisins" = 1)
@@ -56,7 +56,7 @@
/obj/item/reagent_containers/food/snacks/no_raisin/healthy
name = "homemade raisins"
desc = "Homemade raisins, the best in all of spess."
- list_reagents = list("nutriment" = 3, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
junkiness = 0
foodtype = FRUIT
@@ -64,7 +64,7 @@
name = "space twinkie"
icon_state = "space_twinkie"
desc = "Guaranteed to survive longer than you will."
- list_reagents = list("sugar" = 4)
+ list_reagents = list(/datum/reagent/consumable/sugar = 4)
junkiness = 25
filling_color = "#FFD700"
foodtype = JUNKFOOD | GRAIN | SUGAR
@@ -74,7 +74,7 @@
desc = "Bite sized cheesie snacks that will honk all over your mouth."
icon_state = "cheesie_honkers"
trash = /obj/item/trash/cheesie
- list_reagents = list("nutriment" = 1, "sugar" = 3)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 1, /datum/reagent/consumable/sugar = 3)
junkiness = 25
filling_color = "#FFD700"
tastes = list("cheese" = 5, "crisps" = 2)
@@ -96,7 +96,7 @@
icon_state = "syndi_cakes"
desc = "An extremely moist snack cake that tastes just as good after being nuked."
trash = /obj/item/trash/syndi_cakes
- list_reagents = list("nutriment" = 4, "doctorsdelight" = 5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 4, /datum/reagent/consumable/doctor_delight = 5)
filling_color = "#F5F5DC"
tastes = list("sweetness" = 3, "cake" = 1)
foodtype = GRAIN | FRUIT | VEGETABLES
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index ff803b5f..27ee5481 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -52,7 +52,7 @@ God bless America.
/obj/machinery/deepfryer/Initialize()
. = ..()
create_reagents(50, OPENCONTAINER)
- reagents.add_reagent("cooking_oil", 25)
+ reagents.add_reagent(/datum/reagent/consumable/cooking_oil, 25)
component_parts = list()
component_parts += new /obj/item/circuitboard/machine/deep_fryer(null)
component_parts += new /obj/item/stock_parts/micro_laser(null)
@@ -83,7 +83,7 @@ God bless America.
if(istype(I,/obj/item/clothing/head/mob_holder))
to_chat(user, "This does not fit in the fryer.") // TODO: Deepfrying instakills mobs, spawns a whole deep-fried mob.
return
- if(!reagents.has_reagent("cooking_oil"))
+ if(!reagents.has_reagent(/datum/reagent/consumable/cooking_oil))
to_chat(user, "[src] has no cooking oil to fry with!")
return
if(I.resistance_flags & INDESTRUCTIBLE)
@@ -107,7 +107,7 @@ God bless America.
/obj/machinery/deepfryer/process()
..()
- var/datum/reagent/consumable/cooking_oil/C = reagents.has_reagent("cooking_oil")
+ var/datum/reagent/consumable/cooking_oil/C = reagents.has_reagent(/datum/reagent/consumable/cooking_oil)
if(!C)
return
reagents.chem_temp = C.fry_temperature
diff --git a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
index 4dda9dd7..68cc84c6 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/food_cart.dm
@@ -35,16 +35,16 @@
dat += "Portion: [portion] "
for(var/datum/reagent/R in reagents.reagent_list)
dat += "[R.name]: [R.volume] "
- dat += "Purge"
+ dat += "Purge"
if (glasses > 0)
- dat += "Pour in a glass"
- dat += "Add to the mixer "
+ dat += "Pour in a glass"
+ dat += "Add to the mixer "
dat += " MIXER CONTENTS
"
for(var/datum/reagent/R in mixer.reagents.reagent_list)
dat += "[R.name]: [R.volume] "
- dat += "Transfer back"
+ dat += "Transfer back"
if (glasses > 0)
- dat += "Pour in a glass"
+ dat += "Pour in a glass"
dat += " "
dat += "
"
- for(var/V in categories[cat])
- var/datum/design/D = V
- dat += "[D.name]: Make"
- if(cat in timesFiveCategories)
- dat += "x5"
- if(ispath(D.build_path, /obj/item/stack))
- dat += "x10"
- dat += "([D.materials[MAT_BIOMASS]/efficiency]) "
- dat += "
"
+ for(var/V in categories[cat])
+ var/datum/design/D = V
+ dat += "[D.name]: Make"
+ if(cat in timesFiveCategories)
+ dat += "x5"
+ if(ispath(D.build_path, /obj/item/stack))
+ dat += "x10"
+ dat += "([D.materials[MAT_BIOMASS]/efficiency]) "
+ dat += "
"
+ else
+ dat += "
No container inside, please insert container.
"
+
+ var/datum/browser/popup = new(user, "biogen", name, 350, 520)
+ popup.set_content(dat)
+ popup.open()
+
+/obj/machinery/biogenerator/proc/activate()
+ if (usr.stat != CONSCIOUS)
+ return
+ if (src.stat != NONE) //NOPOWER etc
+ return
+ if(processing)
+ to_chat(usr, "The biogenerator is in the process of working.")
+ return
+ var/S = 0
+ for(var/obj/item/reagent_containers/food/snacks/grown/I in contents)
+ S += 5
+ if(I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment) < 0.1)
+ points += 1*productivity
+ else points += I.reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)*10*productivity
+ qdel(I)
+ if(S)
+ processing = TRUE
+ update_icon()
+ updateUsrDialog()
+ playsound(src.loc, 'sound/machines/blender.ogg', 50, 1)
+ use_power(S*30)
+ sleep(S+15/productivity)
+ processing = FALSE
+ update_icon()
+ else
+ menustat = "void"
+
+/obj/machinery/biogenerator/proc/check_cost(list/materials, multiplier = 1, remove_points = 1)
+ if(materials.len != 1 || materials[1] != MAT_BIOMASS)
+ return FALSE
+ if (materials[MAT_BIOMASS]*multiplier/efficiency > points)
+ menustat = "nopoints"
+ return FALSE
+ else
+ if(remove_points)
+ points -= materials[MAT_BIOMASS]*multiplier/efficiency
+ update_icon()
+ updateUsrDialog()
+ return TRUE
+
+/obj/machinery/biogenerator/proc/check_container_volume(list/reagents, multiplier = 1)
+ var/sum_reagents = 0
+ for(var/R in reagents)
+ sum_reagents += reagents[R]
+ sum_reagents *= multiplier
+
+ if(beaker.reagents.total_volume + sum_reagents > beaker.reagents.maximum_volume)
+ menustat = "nobeakerspace"
+ return FALSE
+
+ return TRUE
+
+/obj/machinery/biogenerator/proc/create_product(datum/design/D, amount)
+ if(!beaker || !loc)
+ return FALSE
+
+ if(ispath(D.build_path, /obj/item/stack))
+ if(!check_container_volume(D.make_reagents, amount))
+ return FALSE
+ if(!check_cost(D.materials, amount))
+ return FALSE
+
+ new D.build_path(drop_location(), amount)
+ for(var/R in D.make_reagents)
+ beaker.reagents.add_reagent(R, D.make_reagents[R]*amount)
+ else
+ var/i = amount
+ while(i > 0)
+ if(!check_container_volume(D.make_reagents))
+ return .
+ if(!check_cost(D.materials))
+ return .
+ if(D.build_path)
+ new D.build_path(loc)
+ for(var/R in D.make_reagents)
+ beaker.reagents.add_reagent(R, D.make_reagents[R])
+ . = 1
+ --i
+
+ menustat = "complete"
+ update_icon()
+ return .
+
+/obj/machinery/biogenerator/proc/detach()
+ if(beaker)
+ beaker.forceMove(drop_location())
+ beaker = null
+ update_icon()
+
+/obj/machinery/biogenerator/Topic(href, href_list)
+ if(..() || panel_open)
+ return
+
+ usr.set_machine(src)
+
+ if(href_list["activate"])
+ activate()
+ updateUsrDialog()
+
+ else if(href_list["detach"])
+ detach()
+ updateUsrDialog()
+
+ else if(href_list["create"])
+ var/amount = (text2num(href_list["amount"]))
+ //Can't be outside these (if you change this keep a sane limit)
+ amount = CLAMP(amount, 1, 50)
+ var/datum/design/D = locate(href_list["create"])
+ create_product(D, amount)
+ updateUsrDialog()
+
+ else if(href_list["menu"])
+ menustat = "menu"
+ updateUsrDialog()
diff --git a/code/modules/hydroponics/fermenting_barrel.dm b/code/modules/hydroponics/fermenting_barrel.dm
index e9001322..ab6625b4 100644
--- a/code/modules/hydroponics/fermenting_barrel.dm
+++ b/code/modules/hydroponics/fermenting_barrel.dm
@@ -33,7 +33,7 @@
data["tastes"] = list(fruit.wine_flavor = 1)
else
data["tastes"] = list(fruit.tastes[1] = 1)
- reagents.add_reagent("fruit_wine", amount, data)
+ reagents.add_reagent(/datum/reagent/consumable/ethanol/fruit_wine, amount, data)
qdel(fruit)
playsound(src, 'sound/effects/bubbles.ogg', 50, TRUE)
diff --git a/code/modules/hydroponics/grown.dm b/code/modules/hydroponics/grown.dm
index 6961a1cb..9dddb622 100644
--- a/code/modules/hydroponics/grown.dm
+++ b/code/modules/hydroponics/grown.dm
@@ -1,169 +1,169 @@
-// ***********************************************************
-// Foods that are produced from hydroponics ~~~~~~~~~~
-// Data from the seeds carry over to these grown foods
-// ***********************************************************
-
-// Base type. Subtypes are found in /grown dir.
-/obj/item/reagent_containers/food/snacks/grown
- icon = 'icons/obj/hydroponics/harvest.dmi'
- var/obj/item/seeds/seed = null // type path, gets converted to item on New(). It's safe to assume it's always a seed item.
- var/plantname = ""
- var/bitesize_mod = 0
- var/splat_type = /obj/effect/decal/cleanable/plant_smudge
- // If set, bitesize = 1 + round(reagents.total_volume / bitesize_mod)
- dried_type = -1
- // Saves us from having to define each stupid grown's dried_type as itself.
- // If you don't want a plant to be driable (watermelons) set this to null in the time definition.
- resistance_flags = FLAMMABLE
- var/dry_grind = FALSE //If TRUE, this object needs to be dry to be ground up
- var/can_distill = TRUE //If FALSE, this object cannot be distilled into an alcohol.
- var/distill_reagent //If NULL and this object can be distilled, it uses a generic fruit_wine reagent and adjusts its variables.
- var/wine_flavor //If NULL, this is automatically set to the fruit's flavor. Determines the flavor of the wine if distill_reagent is NULL.
- var/wine_power = 10 //Determines the boozepwr of the wine if distill_reagent is NULL.
-
-/obj/item/reagent_containers/food/snacks/grown/Initialize(mapload, obj/item/seeds/new_seed)
- . = ..()
- if(!tastes)
- tastes = list("[name]" = 1)
-
- if(new_seed)
- seed = new_seed.Copy()
- else if(ispath(seed))
- // This is for adminspawn or map-placed growns. They get the default stats of their seed type.
- seed = new seed()
- seed.adjust_potency(50-seed.potency)
-
- pixel_x = rand(-5, 5)
- pixel_y = rand(-5, 5)
-
- if(dried_type == -1)
- dried_type = src.type
-
- if(seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_new(src, loc)
- seed.prepare_result(src)
- transform *= TRANSFORM_USING_VARIABLE(seed.potency, 100) + 0.5 //Makes the resulting produce's sprite larger or smaller based on potency!
- add_juice()
-
-
-
-/obj/item/reagent_containers/food/snacks/grown/proc/add_juice()
- if(reagents)
- if(bitesize_mod)
- bitesize = 1 + round(reagents.total_volume / bitesize_mod)
- return 1
- return 0
-
-/obj/item/reagent_containers/food/snacks/grown/examine(user)
- . = ..()
- if(seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- if(T.examine_line)
- . += T.examine_line
-
-/obj/item/reagent_containers/food/snacks/grown/attackby(obj/item/O, mob/user, params)
- ..()
- if (istype(O, /obj/item/plant_analyzer))
- var/msg = "*---------*\n This is \a [src].\n"
- if(seed)
- msg += seed.get_analyzer_text()
- var/reag_txt = ""
- if(seed)
- for(var/reagent_id in seed.reagents_add)
- var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
- var/amt = reagents.get_reagent_amount(reagent_id)
- reag_txt += "\n- [R.name]: [amt]"
-
- if(reag_txt)
- msg += reag_txt
- msg += " *---------*"
- to_chat(user, msg)
- else
- if(seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_attackby(src, O, user)
-
-
-// Various gene procs
-/obj/item/reagent_containers/food/snacks/grown/attack_self(mob/user)
- if(seed && seed.get_gene(/datum/plant_gene/trait/squash))
- squash(user)
- ..()
-
-/obj/item/reagent_containers/food/snacks/grown/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- if(!..()) //was it caught by a mob?
- if(seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_throw_impact(src, hit_atom)
- if(seed.get_gene(/datum/plant_gene/trait/squash))
- squash(hit_atom)
-
-/obj/item/reagent_containers/food/snacks/grown/proc/squash(atom/target)
- var/turf/T = get_turf(target)
- if(ispath(splat_type, /obj/effect/decal/cleanable/plant_smudge))
- if(filling_color)
- var/obj/O = new splat_type(T)
- O.color = filling_color
- O.name = "[name] smudge"
- else if(splat_type)
- new splat_type(T)
-
- if(trash)
- generate_trash(T)
-
- visible_message("[src] has been squashed.","You hear a smack.")
- if(seed)
- for(var/datum/plant_gene/trait/trait in seed.genes)
- trait.on_squash(src, target)
-
- reagents.reaction(T)
- for(var/A in T)
- reagents.reaction(A)
-
- qdel(src)
-
-/obj/item/reagent_containers/food/snacks/grown/On_Consume()
- if(iscarbon(usr))
- if(seed)
- for(var/datum/plant_gene/trait/T in seed.genes)
- T.on_consume(src, usr)
- ..()
-
-/obj/item/reagent_containers/food/snacks/grown/generate_trash(atom/location)
- if(trash && (ispath(trash, /obj/item/grown) || ispath(trash, /obj/item/reagent_containers/food/snacks/grown)))
- . = new trash(location, seed)
- trash = null
- return
- return ..()
-
-/obj/item/reagent_containers/food/snacks/grown/grind_requirements()
- if(dry_grind && !dry)
- to_chat(usr, "[src] needs to be dry before it can be ground up!")
- return
- return TRUE
-
-/obj/item/reagent_containers/food/snacks/grown/on_grind()
- var/nutriment = reagents.get_reagent_amount("nutriment")
- if(grind_results&&grind_results.len)
- for(var/i in 1 to grind_results.len)
- grind_results[grind_results[i]] = nutriment
- reagents.del_reagent("nutriment")
- reagents.del_reagent("vitamin")
-
-/obj/item/reagent_containers/food/snacks/grown/on_juice()
- var/nutriment = reagents.get_reagent_amount("nutriment")
- if(juice_results&&juice_results.len)
- for(var/i in 1 to juice_results.len)
- juice_results[juice_results[i]] = nutriment
- reagents.del_reagent("nutriment")
- reagents.del_reagent("vitamin")
-
-// For item-containing growns such as eggy or gatfruit
-/obj/item/reagent_containers/food/snacks/grown/shell/attack_self(mob/user)
- var/obj/item/T
- if(trash)
- T = generate_trash()
- qdel(src)
- user.putItemFromInventoryInHandIfPossible(T, user.active_hand_index, TRUE)
- to_chat(user, "You open [src]\'s shell, revealing \a [T].")
+// ***********************************************************
+// Foods that are produced from hydroponics ~~~~~~~~~~
+// Data from the seeds carry over to these grown foods
+// ***********************************************************
+
+// Base type. Subtypes are found in /grown dir.
+/obj/item/reagent_containers/food/snacks/grown
+ icon = 'icons/obj/hydroponics/harvest.dmi'
+ var/obj/item/seeds/seed = null // type path, gets converted to item on New(). It's safe to assume it's always a seed item.
+ var/plantname = ""
+ var/bitesize_mod = 0
+ var/splat_type = /obj/effect/decal/cleanable/plant_smudge
+ // If set, bitesize = 1 + round(reagents.total_volume / bitesize_mod)
+ dried_type = -1
+ // Saves us from having to define each stupid grown's dried_type as itself.
+ // If you don't want a plant to be driable (watermelons) set this to null in the time definition.
+ resistance_flags = FLAMMABLE
+ var/dry_grind = FALSE //If TRUE, this object needs to be dry to be ground up
+ var/can_distill = TRUE //If FALSE, this object cannot be distilled into an alcohol.
+ var/distill_reagent //If NULL and this object can be distilled, it uses a generic fruit_wine reagent and adjusts its variables.
+ var/wine_flavor //If NULL, this is automatically set to the fruit's flavor. Determines the flavor of the wine if distill_reagent is NULL.
+ var/wine_power = 10 //Determines the boozepwr of the wine if distill_reagent is NULL.
+
+/obj/item/reagent_containers/food/snacks/grown/Initialize(mapload, obj/item/seeds/new_seed)
+ . = ..()
+ if(!tastes)
+ tastes = list("[name]" = 1)
+
+ if(new_seed)
+ seed = new_seed.Copy()
+ else if(ispath(seed))
+ // This is for adminspawn or map-placed growns. They get the default stats of their seed type.
+ seed = new seed()
+ seed.adjust_potency(50-seed.potency)
+
+ pixel_x = rand(-5, 5)
+ pixel_y = rand(-5, 5)
+
+ if(dried_type == -1)
+ dried_type = src.type
+
+ if(seed)
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_new(src, loc)
+ seed.prepare_result(src)
+ transform *= TRANSFORM_USING_VARIABLE(seed.potency, 100) + 0.5 //Makes the resulting produce's sprite larger or smaller based on potency!
+ add_juice()
+
+
+
+/obj/item/reagent_containers/food/snacks/grown/proc/add_juice()
+ if(reagents)
+ if(bitesize_mod)
+ bitesize = 1 + round(reagents.total_volume / bitesize_mod)
+ return 1
+ return 0
+
+/obj/item/reagent_containers/food/snacks/grown/examine(user)
+ . = ..()
+ if(seed)
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ if(T.examine_line)
+ . += T.examine_line
+
+/obj/item/reagent_containers/food/snacks/grown/attackby(obj/item/O, mob/user, params)
+ ..()
+ if (istype(O, /obj/item/plant_analyzer))
+ var/msg = "*---------*\n This is \a [src].\n"
+ if(seed)
+ msg += seed.get_analyzer_text()
+ var/reag_txt = ""
+ if(seed)
+ for(var/reagent_id in seed.reagents_add)
+ var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
+ var/amt = reagents.get_reagent_amount(reagent_id)
+ reag_txt += "\n- [R.name]: [amt]"
+
+ if(reag_txt)
+ msg += reag_txt
+ msg += " *---------*"
+ to_chat(user, msg)
+ else
+ if(seed)
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_attackby(src, O, user)
+
+
+// Various gene procs
+/obj/item/reagent_containers/food/snacks/grown/attack_self(mob/user)
+ if(seed && seed.get_gene(/datum/plant_gene/trait/squash))
+ squash(user)
+ ..()
+
+/obj/item/reagent_containers/food/snacks/grown/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ if(!..()) //was it caught by a mob?
+ if(seed)
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_throw_impact(src, hit_atom)
+ if(seed.get_gene(/datum/plant_gene/trait/squash))
+ squash(hit_atom)
+
+/obj/item/reagent_containers/food/snacks/grown/proc/squash(atom/target)
+ var/turf/T = get_turf(target)
+ if(ispath(splat_type, /obj/effect/decal/cleanable/plant_smudge))
+ if(filling_color)
+ var/obj/O = new splat_type(T)
+ O.color = filling_color
+ O.name = "[name] smudge"
+ else if(splat_type)
+ new splat_type(T)
+
+ if(trash)
+ generate_trash(T)
+
+ visible_message("[src] has been squashed.","You hear a smack.")
+ if(seed)
+ for(var/datum/plant_gene/trait/trait in seed.genes)
+ trait.on_squash(src, target)
+
+ reagents.reaction(T)
+ for(var/A in T)
+ reagents.reaction(A)
+
+ qdel(src)
+
+/obj/item/reagent_containers/food/snacks/grown/On_Consume()
+ if(iscarbon(usr))
+ if(seed)
+ for(var/datum/plant_gene/trait/T in seed.genes)
+ T.on_consume(src, usr)
+ ..()
+
+/obj/item/reagent_containers/food/snacks/grown/generate_trash(atom/location)
+ if(trash && (ispath(trash, /obj/item/grown) || ispath(trash, /obj/item/reagent_containers/food/snacks/grown)))
+ . = new trash(location, seed)
+ trash = null
+ return
+ return ..()
+
+/obj/item/reagent_containers/food/snacks/grown/grind_requirements()
+ if(dry_grind && !dry)
+ to_chat(usr, "[src] needs to be dry before it can be ground up!")
+ return
+ return TRUE
+
+/obj/item/reagent_containers/food/snacks/grown/on_grind()
+ var/nutriment = reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)
+ if(grind_results&&grind_results.len)
+ for(var/i in 1 to grind_results.len)
+ grind_results[grind_results[i]] = nutriment
+ reagents.del_reagent(/datum/reagent/consumable/nutriment)
+ reagents.del_reagent(/datum/reagent/consumable/nutriment/vitamin)
+
+/obj/item/reagent_containers/food/snacks/grown/on_juice()
+ var/nutriment = reagents.get_reagent_amount(/datum/reagent/consumable/nutriment)
+ if(juice_results&&juice_results.len)
+ for(var/i in 1 to juice_results.len)
+ juice_results[juice_results[i]] = nutriment
+ reagents.del_reagent(/datum/reagent/consumable/nutriment)
+ reagents.del_reagent(/datum/reagent/consumable/nutriment/vitamin)
+
+// For item-containing growns such as eggy or gatfruit
+/obj/item/reagent_containers/food/snacks/grown/shell/attack_self(mob/user)
+ var/obj/item/T
+ if(trash)
+ T = generate_trash()
+ qdel(src)
+ user.putItemFromInventoryInHandIfPossible(T, user.active_hand_index, TRUE)
+ to_chat(user, "You open [src]\'s shell, revealing \a [T].")
diff --git a/code/modules/hydroponics/grown/ambrosia.dm b/code/modules/hydroponics/grown/ambrosia.dm
index a3b93db1..e8402520 100644
--- a/code/modules/hydroponics/grown/ambrosia.dm
+++ b/code/modules/hydroponics/grown/ambrosia.dm
@@ -25,7 +25,7 @@
icon_dead = "ambrosia-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/ambrosia/deus)
- reagents_add = list("space_drugs" = 0.15, "bicaridine" = 0.1, "kelotane" = 0.1, "vitamin" = 0.04, "nutriment" = 0.05, "toxin" = 0.1)
+ reagents_add = list(/datum/reagent/drug/space_drugs = 0.15, /datum/reagent/medicine/bicaridine = 0.1, /datum/reagent/medicine/kelotane = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05, /datum/reagent/toxin = 0.1)
/obj/item/reagent_containers/food/snacks/grown/ambrosia/vulgaris
seed = /obj/item/seeds/ambrosia
@@ -42,7 +42,7 @@
plantname = "Ambrosia Deus"
product = /obj/item/reagent_containers/food/snacks/grown/ambrosia/deus
mutatelist = list(/obj/item/seeds/ambrosia/gaia)
- reagents_add = list("omnizine" = 0.15, "synaptizine" = 0.15, "space_drugs" = 0.1, "vitamin" = 0.04, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/medicine/omnizine = 0.15, /datum/reagent/medicine/synaptizine = 0.15, /datum/reagent/drug/space_drugs = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05)
rarity = 40
/obj/item/reagent_containers/food/snacks/grown/ambrosia/deus
@@ -62,7 +62,7 @@
plantname = "Ambrosia Gaia"
product = /obj/item/reagent_containers/food/snacks/grown/ambrosia/gaia
mutatelist = list(/obj/item/seeds/ambrosia/deus)
- reagents_add = list("earthsblood" = 0.05, "nutriment" = 0.06, "vitamin" = 0.05)
+ reagents_add = list(/datum/reagent/medicine/earthsblood = 0.05, /datum/reagent/consumable/nutriment = 0.06, /datum/reagent/consumable/nutriment/vitamin = 0.05)
rarity = 30 //These are some pretty good plants right here
genes = list()
weed_rate = 4
diff --git a/code/modules/hydroponics/grown/apple.dm b/code/modules/hydroponics/grown/apple.dm
index 007c0b24..f8e58aee 100644
--- a/code/modules/hydroponics/grown/apple.dm
+++ b/code/modules/hydroponics/grown/apple.dm
@@ -14,7 +14,7 @@
icon_dead = "apple-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/apple/gold)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/apple
seed = /obj/item/seeds/apple
@@ -24,9 +24,9 @@
filling_color = "#FF4500"
bitesize = 100 // Always eat the apple in one bite
foodtype = FRUIT
- juice_results = list("applejuice" = 0)
+ juice_results = list(/datum/reagent/consumable/applejuice = 0)
tastes = list("apple" = 1)
- distill_reagent = "hcider"
+ distill_reagent = /datum/reagent/consumable/ethanol/hcider
// Gold Apple
/obj/item/seeds/apple/gold
@@ -39,7 +39,7 @@
maturation = 10
production = 10
mutatelist = list()
- reagents_add = list("gold" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/gold = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 40 // Alchemy!
/obj/item/reagent_containers/food/snacks/grown/apple/gold
diff --git a/code/modules/hydroponics/grown/banana.dm b/code/modules/hydroponics/grown/banana.dm
index 251d9de5..cc66e188 100644
--- a/code/modules/hydroponics/grown/banana.dm
+++ b/code/modules/hydroponics/grown/banana.dm
@@ -11,8 +11,8 @@
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
icon_dead = "banana-dead"
genes = list(/datum/plant_gene/trait/slip, /datum/plant_gene/trait/repeated_harvest)
- mutatelist = list(/obj/item/seeds/banana/mime, /obj/item/seeds/banana/bluespace)
- reagents_add = list("banana" = 0.1, "potassium" = 0.1, "vitamin" = 0.04, "nutriment" = 0.02)
+ mutatelist = list(/obj/item/seeds/banana/mime, /obj/item/seeds/banana/bluespace, /obj/item/seeds/banana/exotic_banana)
+ reagents_add = list(/datum/reagent/consumable/banana = 0.1, /datum/reagent/potassium = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.02)
/obj/item/reagent_containers/food/snacks/grown/banana
seed = /obj/item/seeds/banana
@@ -24,8 +24,8 @@
filling_color = "#FFFF00"
bitesize = 5
foodtype = FRUIT
- juice_results = list("banana" = 0)
- distill_reagent = "bananahonk"
+ juice_results = list(/datum/reagent/consumable/banana = 0)
+ distill_reagent = /datum/reagent/consumable/ethanol/bananahonk
/obj/item/reagent_containers/food/snacks/grown/banana/suicide_act(mob/user)
user.visible_message("[user] is aiming [src] at [user.p_them()]self! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -70,7 +70,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/banana/mime
growthstages = 4
mutatelist = list()
- reagents_add = list("nothing" = 0.1, "mutetoxin" = 0.1, "nutriment" = 0.02)
+ reagents_add = list(/datum/reagent/consumable/nothing = 0.1, /datum/reagent/toxin/mutetoxin = 0.1, /datum/reagent/consumable/nutriment = 0.02)
rarity = 15
/obj/item/reagent_containers/food/snacks/grown/banana/mime
@@ -80,7 +80,7 @@
icon_state = "mimana"
trash = /obj/item/grown/bananapeel/mimanapeel
filling_color = "#FFFFEE"
- distill_reagent = "silencer"
+ distill_reagent = /datum/reagent/consumable/ethanol/silencer
/obj/item/grown/bananapeel/mimanapeel
seed = /obj/item/seeds/banana/mime
@@ -100,7 +100,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/banana/bluespace
mutatelist = list()
genes = list(/datum/plant_gene/trait/slip, /datum/plant_gene/trait/teleport, /datum/plant_gene/trait/repeated_harvest)
- reagents_add = list("bluespace" = 0.2, "banana" = 0.1, "vitamin" = 0.04, "nutriment" = 0.02)
+ reagents_add = list(/datum/reagent/bluespace = 0.2, /datum/reagent/consumable/banana = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.02)
rarity = 30
/obj/item/reagent_containers/food/snacks/grown/banana/bluespace
diff --git a/code/modules/hydroponics/grown/beans.dm b/code/modules/hydroponics/grown/beans.dm
index 4338e3b0..3e5fee41 100644
--- a/code/modules/hydroponics/grown/beans.dm
+++ b/code/modules/hydroponics/grown/beans.dm
@@ -15,7 +15,7 @@
icon_dead = "soybean-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/soya/koi)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.05, "cooking_oil" = 0.03) //Vegetable oil!
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05, /datum/reagent/consumable/cooking_oil = 0.03) //Vegetable oil!
/obj/item/reagent_containers/food/snacks/grown/soybeans
seed = /obj/item/seeds/soya
@@ -26,7 +26,7 @@
filling_color = "#F0E68C"
bitesize_mod = 2
foodtype = VEGETABLES
- grind_results = list("soymilk" = 0)
+ grind_results = list(/datum/reagent/consumable/soymilk = 0)
tastes = list("soy" = 1)
wine_power = 20
@@ -40,7 +40,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/koibeans
potency = 10
mutatelist = list()
- reagents_add = list("carpotoxin" = 0.1, "vitamin" = 0.04, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/toxin/carpotoxin = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/koibeans
diff --git a/code/modules/hydroponics/grown/berries.dm b/code/modules/hydroponics/grown/berries.dm
index 9b93bc57..ec7fcef6 100644
--- a/code/modules/hydroponics/grown/berries.dm
+++ b/code/modules/hydroponics/grown/berries.dm
@@ -15,7 +15,7 @@
icon_dead = "berry-dead" // Same for the dead icon
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/berry/glow, /obj/item/seeds/berry/poison)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/berries
seed = /obj/item/seeds/berry
@@ -26,9 +26,9 @@
filling_color = "#FF00FF"
bitesize_mod = 2
foodtype = FRUIT
- juice_results = list("berryjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/berryjuice = 0)
tastes = list("berry" = 1)
- distill_reagent = "gin"
+ distill_reagent = /datum/reagent/consumable/ethanol/gin
// Poison Berries
/obj/item/seeds/berry/poison
@@ -39,7 +39,7 @@
plantname = "Poison-Berry Bush"
product = /obj/item/reagent_containers/food/snacks/grown/berries/poison
mutatelist = list(/obj/item/seeds/berry/death)
- reagents_add = list("cyanide" = 0.15, "tirizene" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/toxin/cyanide = 0.15, /datum/reagent/toxin/staminatoxin = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 10 // Mildly poisonous berries are common in reality
/obj/item/reagent_containers/food/snacks/grown/berries/poison
@@ -49,7 +49,7 @@
icon_state = "poisonberrypile"
filling_color = "#C71585"
foodtype = FRUIT | TOXIC
- juice_results = list("poisonberryjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/poisonberryjuice = 0)
tastes = list("poison-berry" = 1)
distill_reagent = null
wine_power = 35
@@ -65,7 +65,7 @@
lifespan = 30
potency = 50
mutatelist = list()
- reagents_add = list("coniine" = 0.08, "tirizene" = 0.1, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/toxin/coniine = 0.08, /datum/reagent/toxin/staminatoxin = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 30
/obj/item/reagent_containers/food/snacks/grown/berries/death
@@ -90,8 +90,8 @@
lifespan = 30
endurance = 25
mutatelist = list()
- genes = list(/datum/plant_gene/trait/glow/white , /datum/plant_gene/trait/noreact, /datum/plant_gene/trait/repeated_harvest)
- reagents_add = list("uranium" = 0.25, "iodine" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ genes = list(/datum/plant_gene/trait/glow/white, /datum/plant_gene/trait/noreact, /datum/plant_gene/trait/repeated_harvest)
+ reagents_add = list(/datum/reagent/uranium = 0.25, /datum/reagent/iodine = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/berries/glow
@@ -124,7 +124,7 @@
icon_harvest = "cherry-harvest"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/cherry/blue, /obj/item/seeds/cherry/bulb)
- reagents_add = list("nutriment" = 0.07, "sugar" = 0.07)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.07, /datum/reagent/consumable/sugar = 0.07)
/obj/item/reagent_containers/food/snacks/grown/cherries
seed = /obj/item/seeds/cherry
@@ -135,7 +135,7 @@
filling_color = "#FF0000"
bitesize_mod = 2
foodtype = FRUIT
- grind_results = list("cherryjelly" = 0)
+ grind_results = list(/datum/reagent/consumable/cherryjelly = 0)
tastes = list("cherry" = 1)
wine_power = 30
@@ -148,7 +148,7 @@
plantname = "Blue Cherry Tree"
product = /obj/item/reagent_containers/food/snacks/grown/bluecherries
mutatelist = list()
- reagents_add = list("nutriment" = 0.07, "sugar" = 0.07)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.07, /datum/reagent/consumable/sugar = 0.07)
rarity = 10
/obj/item/reagent_containers/food/snacks/grown/bluecherries
@@ -159,7 +159,7 @@
filling_color = "#6495ED"
bitesize_mod = 2
foodtype = FRUIT
- grind_results = list("bluecherryjelly" = 0)
+ grind_results = list(/datum/reagent/consumable/bluecherryjelly = 0)
tastes = list("blue cherry" = 1)
wine_power = 50
@@ -173,7 +173,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/cherrybulbs
genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/pink)
mutatelist = list()
- reagents_add = list("nutriment" = 0.07, "sugar" = 0.07)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.07, /datum/reagent/consumable/sugar = 0.07)
rarity = 10
/obj/item/reagent_containers/food/snacks/grown/cherrybulbs
@@ -207,7 +207,7 @@
icon_dead = "grape-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/grape/green)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1, "sugar" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1, /datum/reagent/consumable/sugar = 0.1)
/obj/item/reagent_containers/food/snacks/grown/grapes
seed = /obj/item/seeds/grape
@@ -218,9 +218,9 @@
filling_color = "#FF1493"
bitesize_mod = 2
foodtype = FRUIT
- juice_results = list("grapejuice" = 0)
+ juice_results = list(/datum/reagent/consumable/grapejuice = 0)
tastes = list("grape" = 1)
- distill_reagent = "wine"
+ distill_reagent = /datum/reagent/consumable/ethanol/wine
// Green Grapes
/obj/item/seeds/grape/green
@@ -230,7 +230,7 @@
species = "greengrape"
plantname = "Green-Grape Vine"
product = /obj/item/reagent_containers/food/snacks/grown/grapes/green
- reagents_add = list("kelotane" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1, "sugar" = 0.1)
+ reagents_add = list(/datum/reagent/medicine/kelotane = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1, /datum/reagent/consumable/sugar = 0.1)
// No rarity: technically it's a beneficial mutant, but it's not exactly "new"...
mutatelist = list()
@@ -240,7 +240,7 @@
icon_state = "greengrapes"
filling_color = "#7FFF00"
tastes = list("green grape" = 1)
- distill_reagent = "cognac"
+ distill_reagent = /datum/reagent/consumable/ethanol/cognac
// Strawberry
/obj/item/seeds/strawberry
@@ -254,7 +254,7 @@
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
icon_grow = "strawberry-grow"
icon_dead = "berry-dead"
- reagents_add = list("vitamin" = 0.07, "nutriment" = 0.1, "sugar" = 0.2)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.07, /datum/reagent/consumable/nutriment = 0.1, /datum/reagent/consumable/sugar = 0.2)
mutatelist = list()
/obj/item/reagent_containers/food/snacks/grown/strawberry
diff --git a/code/modules/hydroponics/grown/cannabis.dm b/code/modules/hydroponics/grown/cannabis.dm
index 67c5e61d..a7e571d7 100644
--- a/code/modules/hydroponics/grown/cannabis.dm
+++ b/code/modules/hydroponics/grown/cannabis.dm
@@ -17,7 +17,7 @@
/obj/item/seeds/cannabis/death,
/obj/item/seeds/cannabis/white,
/obj/item/seeds/cannabis/ultimate)
- reagents_add = list("space_drugs" = 0.15, "lipolicide" = 0.35) // gives u the munchies
+ reagents_add = list(/datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.35) // gives u the munchies
/obj/item/seeds/cannabis/rainbow
@@ -28,7 +28,7 @@
plantname = "Rainbow Weed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/rainbow
mutatelist = list()
- reagents_add = list("mindbreaker" = 0.15, "lipolicide" = 0.35)
+ reagents_add = list(/datum/reagent/toxin/mindbreaker = 0.15, /datum/reagent/toxin/lipolicide = 0.35)
rarity = 40
/obj/item/seeds/cannabis/death
@@ -39,7 +39,7 @@
plantname = "Deathweed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/death
mutatelist = list()
- reagents_add = list("cyanide" = 0.35, "space_drugs" = 0.15, "lipolicide" = 0.15)
+ reagents_add = list(/datum/reagent/toxin/cyanide = 0.35, /datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.15)
rarity = 40
/obj/item/seeds/cannabis/white
@@ -50,7 +50,7 @@
plantname = "Lifeweed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/white
mutatelist = list()
- reagents_add = list("omnizine" = 0.35, "space_drugs" = 0.15, "lipolicide" = 0.15)
+ reagents_add = list(/datum/reagent/medicine/omnizine = 0.35, /datum/reagent/drug/space_drugs = 0.15, /datum/reagent/toxin/lipolicide = 0.15)
rarity = 40
@@ -62,21 +62,21 @@
plantname = "Omega Weed"
product = /obj/item/reagent_containers/food/snacks/grown/cannabis/ultimate
mutatelist = list()
- reagents_add = list("space_drugs" = 0.3,
- "mindbreaker" = 0.3,
- "mercury" = 0.15,
- "lithium" = 0.15,
- "atropine" = 0.15,
- "haloperidol" = 0.15,
- "methamphetamine" = 0.15,
- "capsaicin" = 0.15,
- "barbers_aid" = 0.15,
- "bath_salts" = 0.15,
- "itching_powder" = 0.15,
- "crank" = 0.15,
- "krokodil" = 0.15,
- "histamine" = 0.15,
- "lipolicide" = 0.15)
+ reagents_add = list(/datum/reagent/drug/space_drugs = 0.3,
+ /datum/reagent/toxin/mindbreaker = 0.3,
+ /datum/reagent/mercury = 0.15,
+ /datum/reagent/lithium = 0.15,
+ /datum/reagent/medicine/atropine = 0.15,
+ /datum/reagent/medicine/haloperidol = 0.15,
+ /datum/reagent/drug/methamphetamine = 0.15,
+ /datum/reagent/consumable/capsaicin = 0.15,
+ /datum/reagent/barbers_aid = 0.15,
+ /datum/reagent/drug/bath_salts = 0.15,
+ /datum/reagent/toxin/itching_powder = 0.15,
+ /datum/reagent/drug/crank = 0.15,
+ /datum/reagent/drug/krokodil = 0.15,
+ /datum/reagent/toxin/histamine = 0.15,
+ /datum/reagent/toxin/lipolicide = 0.15)
rarity = 69
diff --git a/code/modules/hydroponics/grown/cereals.dm b/code/modules/hydroponics/grown/cereals.dm
index c53cd671..c5a7e079 100644
--- a/code/modules/hydroponics/grown/cereals.dm
+++ b/code/modules/hydroponics/grown/cereals.dm
@@ -11,7 +11,7 @@
potency = 15
icon_dead = "wheat-dead"
mutatelist = list(/obj/item/seeds/wheat/oat, /obj/item/seeds/wheat/meat)
- reagents_add = list("nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.04)
/obj/item/reagent_containers/food/snacks/grown/wheat
seed = /obj/item/seeds/wheat
@@ -22,9 +22,9 @@
filling_color = "#F0E68C"
bitesize_mod = 2
foodtype = GRAIN
- grind_results = list("flour" = 0)
+ grind_results = list(/datum/reagent/consumable/flour = 0)
tastes = list("wheat" = 1)
- distill_reagent = "beer"
+ distill_reagent = /datum/reagent/consumable/ethanol/beer
// Oat
/obj/item/seeds/wheat/oat
@@ -45,9 +45,9 @@
filling_color = "#556B2F"
bitesize_mod = 2
foodtype = GRAIN
- grind_results = list("flour" = 0)
+ grind_results = list(/datum/reagent/consumable/flour = 0)
tastes = list("oat" = 1)
- distill_reagent = "ale"
+ distill_reagent = /datum/reagent/consumable/ethanol/ale
// Rice
/obj/item/seeds/wheat/rice
@@ -69,9 +69,9 @@
filling_color = "#FAFAD2"
bitesize_mod = 2
foodtype = GRAIN
- grind_results = list("rice" = 0)
+ grind_results = list(/datum/reagent/consumable/rice = 0)
tastes = list("rice" = 1)
- distill_reagent = "sake"
+ distill_reagent = /datum/reagent/consumable/ethanol/sake
//Meatwheat - grows into synthetic meat
/obj/item/seeds/wheat/meat
@@ -92,7 +92,7 @@
bitesize_mod = 2
seed = /obj/item/seeds/wheat/meat
foodtype = MEAT | GRAIN
- grind_results = list("flour" = 0, "blood" = 0)
+ grind_results = list(/datum/reagent/consumable/flour = 0, /datum/reagent/blood = 0)
tastes = list("meatwheat" = 1)
can_distill = FALSE
diff --git a/code/modules/hydroponics/grown/chili.dm b/code/modules/hydroponics/grown/chili.dm
index 16675292..d48c5c10 100644
--- a/code/modules/hydroponics/grown/chili.dm
+++ b/code/modules/hydroponics/grown/chili.dm
@@ -16,7 +16,7 @@
icon_dead = "chili-dead" // Same for the dead icon
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/chili/ice, /obj/item/seeds/chili/ghost)
- reagents_add = list("capsaicin" = 0.25, "vitamin" = 0.04, "nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/consumable/capsaicin = 0.25, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.04)
/obj/item/reagent_containers/food/snacks/grown/chili
seed = /obj/item/seeds/chili
@@ -41,7 +41,7 @@
production = 4
rarity = 20
mutatelist = list()
- reagents_add = list("frostoil" = 0.25, "vitamin" = 0.02, "nutriment" = 0.02)
+ reagents_add = list(/datum/reagent/consumable/frostoil = 0.25, /datum/reagent/consumable/nutriment/vitamin = 0.02, /datum/reagent/consumable/nutriment = 0.02)
/obj/item/reagent_containers/food/snacks/grown/icepepper
seed = /obj/item/seeds/chili/ice
@@ -67,7 +67,7 @@
yield = 3
rarity = 20
mutatelist = list()
- reagents_add = list("condensedcapsaicin" = 0.3, "capsaicin" = 0.55, "nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/consumable/condensedcapsaicin = 0.3, /datum/reagent/consumable/capsaicin = 0.55, /datum/reagent/consumable/nutriment = 0.04)
/obj/item/reagent_containers/food/snacks/grown/ghost_chili
seed = /obj/item/seeds/chili/ghost
diff --git a/code/modules/hydroponics/grown/citrus.dm b/code/modules/hydroponics/grown/citrus.dm
index 49cd2798..61c81aa2 100644
--- a/code/modules/hydroponics/grown/citrus.dm
+++ b/code/modules/hydroponics/grown/citrus.dm
@@ -23,7 +23,7 @@
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/orange)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/citrus/lime
seed = /obj/item/seeds/lime
@@ -31,7 +31,7 @@
desc = "It's so sour, your face will twist."
icon_state = "lime"
filling_color = "#00FF00"
- juice_results = list("limejuice" = 0)
+ juice_results = list(/datum/reagent/consumable/limejuice = 0)
// Orange
/obj/item/seeds/orange
@@ -50,7 +50,7 @@
icon_dead = "lime-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/lime, /obj/item/seeds/orange_3d)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/citrus/orange
seed = /obj/item/seeds/orange
@@ -58,8 +58,8 @@
desc = "It's a tangy fruit."
icon_state = "orange"
filling_color = "#FFA500"
- juice_results = list("orangejuice" = 0)
- distill_reagent = "triple_sec"
+ juice_results = list(/datum/reagent/consumable/orangejuice = 0)
+ distill_reagent = /datum/reagent/consumable/ethanol/triple_sec
//3D Orange
/obj/item/seeds/orange_3d
@@ -77,7 +77,7 @@
icon_grow = "lime-grow"
icon_dead = "lime-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.05, "haloperidol" = 0.15)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05, /datum/reagent/medicine/haloperidol = 0.15)
/obj/item/reagent_containers/food/snacks/grown/citrus/orange_3d
seed = /obj/item/seeds/orange
@@ -85,8 +85,8 @@
desc = "You can hardly wrap your head around this thing."
icon_state = "orang"
filling_color = "#FFA500"
- juice_results = list("orangejuice" = 0)
- distill_reagent = "triple_sec"
+ juice_results = list(/datum/reagent/consumable/orangejuice = 0)
+ distill_reagent = /datum/reagent/consumable/ethanol/triple_sec
tastes = list("polygons" = 1, "oranges" = 1)
/obj/item/reagent_containers/food/snacks/grown/citrus/orange_3d/pickup(mob/user)
@@ -112,7 +112,7 @@
icon_grow = "lime-grow"
icon_dead = "lime-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/citrus/lemon
seed = /obj/item/seeds/lemon
@@ -120,7 +120,7 @@
desc = "When life gives you lemons, make lemonade."
icon_state = "lemon"
filling_color = "#FFD700"
- juice_results = list("lemonjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/lemonjuice = 0)
// Combustible lemon
/obj/item/seeds/firelemon //combustible lemon is too long so firelemon
@@ -137,7 +137,7 @@
lifespan = 55
endurance = 45
yield = 4
- reagents_add = list("nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/firelemon
seed = /obj/item/seeds/firelemon
diff --git a/code/modules/hydroponics/grown/cocoa_vanilla.dm b/code/modules/hydroponics/grown/cocoa_vanilla.dm
index a05c7869..4ea247f4 100644
--- a/code/modules/hydroponics/grown/cocoa_vanilla.dm
+++ b/code/modules/hydroponics/grown/cocoa_vanilla.dm
@@ -15,8 +15,8 @@
icon_grow = "cocoapod-grow"
icon_dead = "cocoapod-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
- mutatelist = list(/obj/item/seeds/cocoapod/vanillapod,/obj/item/seeds/cocoapod/bungotree)
- reagents_add = list("cocoa" = 0.25, "nutriment" = 0.1)
+ mutatelist = list(/obj/item/seeds/cocoapod/vanillapod, /obj/item/seeds/cocoapod/bungotree)
+ reagents_add = list(/datum/reagent/consumable/coco = 0.25, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/cocoapod
seed = /obj/item/seeds/cocoapod
@@ -27,7 +27,7 @@
bitesize_mod = 2
foodtype = FRUIT
tastes = list("cocoa" = 1)
- distill_reagent = "creme_de_cacao"
+ distill_reagent = /datum/reagent/consumable/ethanol/creme_de_cacao
// Vanilla Pod
/obj/item/seeds/cocoapod/vanillapod
@@ -39,7 +39,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/vanillapod
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list()
- reagents_add = list("vanilla" = 0.25, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/vanilla = 0.25, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/vanillapod
seed = /obj/item/seeds/cocoapod/vanillapod
@@ -49,7 +49,7 @@
filling_color = "#FFD700"
foodtype = FRUIT
tastes = list("vanilla" = 1)
- distill_reagent = "vanilla" //Takes longer, but you can get even more vanilla from it.
+ distill_reagent = /datum/reagent/consumable/vanilla //Takes longer, but you can get even more vanilla from it.
/obj/item/seeds/cocoapod/bungotree
name = "pack of bungo tree seeds"
@@ -64,7 +64,7 @@
production = 7
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list()
- reagents_add = list("enzyme" = 0.1, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/enzyme = 0.1, /datum/reagent/consumable/nutriment = 0.1)
growthstages = 4
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
icon_grow = "bungotree-grow"
@@ -79,6 +79,7 @@
trash = /obj/item/reagent_containers/food/snacks/grown/bungopit
filling_color = "#E8C22F"
foodtype = FRUIT
+ juice_results = list(/datum/reagent/consumable/bungojuice = 0)
tastes = list("bungo" = 2, "tropical fruitiness" = 1)
distill_reagent = null
@@ -97,5 +98,5 @@
/obj/item/reagent_containers/food/snacks/grown/bungopit/Initialize()
. =..()
reagents.clear_reagents()
- reagents.add_reagent("bungotoxin", seed.potency * 0.10) //More than this will kill at too low potency
- reagents.add_reagent("nutriment", seed.potency * 0.04)
\ No newline at end of file
+ reagents.add_reagent(/datum/reagent/toxin/bungotoxin, seed.potency * 0.10) //More than this will kill at too low potency
+ reagents.add_reagent(/datum/reagent/consumable/nutriment, seed.potency * 0.04)
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown/corn.dm b/code/modules/hydroponics/grown/corn.dm
index c259baaf..691cbb83 100644
--- a/code/modules/hydroponics/grown/corn.dm
+++ b/code/modules/hydroponics/grown/corn.dm
@@ -13,7 +13,7 @@
icon_grow = "corn-grow" // Uses one growth icons set for all the subtypes
icon_dead = "corn-dead" // Same for the dead icon
mutatelist = list(/obj/item/seeds/corn/snapcorn)
- reagents_add = list("cornoil" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/cornoil = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/corn
seed = /obj/item/seeds/corn
@@ -25,9 +25,9 @@
trash = /obj/item/grown/corncob
bitesize_mod = 2
foodtype = VEGETABLES
- juice_results = list("corn_starch" = 0)
+ juice_results = list(/datum/reagent/consumable/corn_starch = 0)
tastes = list("corn" = 1)
- distill_reagent = "whiskey"
+ distill_reagent = /datum/reagent/consumable/ethanol/whiskey
/obj/item/grown/corncob
name = "corn cob"
diff --git a/code/modules/hydroponics/grown/eggplant.dm b/code/modules/hydroponics/grown/eggplant.dm
index 7c01a68f..f893ad9e 100644
--- a/code/modules/hydroponics/grown/eggplant.dm
+++ b/code/modules/hydroponics/grown/eggplant.dm
@@ -13,7 +13,7 @@
icon_dead = "eggplant-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/eggplant/eggy)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/eggplant
seed = /obj/item/seeds/eggplant
@@ -36,7 +36,7 @@
lifespan = 75
production = 12
mutatelist = list()
- reagents_add = list("nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/shell/eggy
seed = /obj/item/seeds/eggplant/eggy
@@ -47,4 +47,4 @@
filling_color = "#F8F8FF"
bitesize_mod = 2
foodtype = MEAT
- distill_reagent = "eggnog"
+ distill_reagent = /datum/reagent/consumable/ethanol/eggnog
diff --git a/code/modules/hydroponics/grown/flowers.dm b/code/modules/hydroponics/grown/flowers.dm
index bf975a15..1646a401 100644
--- a/code/modules/hydroponics/grown/flowers.dm
+++ b/code/modules/hydroponics/grown/flowers.dm
@@ -15,7 +15,7 @@
icon_grow = "poppy-grow"
icon_dead = "poppy-dead"
mutatelist = list(/obj/item/seeds/poppy/geranium, /obj/item/seeds/poppy/lily)
- reagents_add = list("bicaridine" = 0.2, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/medicine/bicaridine = 0.2, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/poppy
seed = /obj/item/seeds/poppy
@@ -27,7 +27,7 @@
bitesize_mod = 3
tastes = list("sesame seeds" = 1)
foodtype = VEGETABLES | GROSS
- distill_reagent = "vermouth"
+ distill_reagent = /datum/reagent/consumable/ethanol/vermouth
// Lily
/obj/item/seeds/poppy/lily
@@ -69,7 +69,7 @@
icon_dead = "spacemanstrumpet-dead"
mutatelist = list()
genes = list(/datum/plant_gene/reagent/polypyr)
- reagents_add = list("nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.05)
rarity = 30
/obj/item/seeds/poppy/lily/trumpet/Initialize(mapload, nogenes = FALSE)
@@ -121,7 +121,7 @@
growthstages = 4
genes = list(/datum/plant_gene/trait/plant_type/weed_hardy)
growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi'
- reagents_add = list("nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.04)
/obj/item/reagent_containers/food/snacks/grown/harebell
seed = /obj/item/seeds/harebell
@@ -132,7 +132,7 @@
slot_flags = ITEM_SLOT_HEAD
filling_color = "#E6E6FA"
bitesize_mod = 3
- distill_reagent = "vermouth"
+ distill_reagent = /datum/reagent/consumable/ethanol/vermouth
// Sunflower
/obj/item/seeds/sunflower
@@ -150,7 +150,7 @@
icon_grow = "sunflower-grow"
icon_dead = "sunflower-dead"
mutatelist = list(/obj/item/seeds/sunflower/moonflower, /obj/item/seeds/sunflower/novaflower)
- reagents_add = list("cornoil" = 0.08, "nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/consumable/cooking_oil = 0.08, /datum/reagent/consumable/nutriment = 0.04)
/obj/item/grown/sunflower // FLOWER POWER!
seed = /obj/item/seeds/sunflower
@@ -186,7 +186,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/moonflower
genes = list(/datum/plant_gene/trait/glow/purple)
mutatelist = list()
- reagents_add = list("moonshine" = 0.2, "vitamin" = 0.02, "nutriment" = 0.02)
+ reagents_add = list(/datum/reagent/consumable/ethanol/moonshine = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.02, /datum/reagent/consumable/nutriment = 0.02)
rarity = 15
/obj/item/reagent_containers/food/snacks/grown/moonflower
@@ -197,7 +197,7 @@
slot_flags = ITEM_SLOT_HEAD
filling_color = "#E6E6FA"
bitesize_mod = 2
- distill_reagent = "absinthe" //It's made from flowers.
+ distill_reagent = /datum/reagent/consumable/ethanol/absinthe //It's made from flowers.
tastes = list("glowbugs" = 1)
// Novaflower
@@ -211,7 +211,7 @@
icon_dead = "sunflower-dead"
product = /obj/item/grown/novaflower
mutatelist = list()
- reagents_add = list("condensedcapsaicin" = 0.25, "capsaicin" = 0.3, "nutriment" = 0)
+ reagents_add = list(/datum/reagent/consumable/condensedcapsaicin = 0.25, /datum/reagent/consumable/capsaicin = 0.3, /datum/reagent/consumable/nutriment = 0)
rarity = 20
/obj/item/grown/novaflower
@@ -229,7 +229,7 @@
throw_speed = 1
throw_range = 3
attack_verb = list("roasted", "scorched", "burned")
- grind_results = list("capsaicin" = 0, "condensedcapsaicin" = 0)
+ grind_results = list(/datum/reagent/consumable/capsaicin = 0, /datum/reagent/consumable/condensedcapsaicin = 0)
tastes = list("cooked sunflower" = 1)
/obj/item/grown/novaflower/add_juice()
@@ -279,7 +279,7 @@
icon_grow = "bee_balm-grow"
icon_dead = "bee_balm-dead"
mutatelist = list(/obj/item/seeds/poppy/geranium, /obj/item/seeds/bee_balm/honey) //Lower odds of becoming honey
- reagents_add = list("spaceacillin" = 0.1, "sterilizine" = 0.05)
+ reagents_add = list(/datum/reagent/medicine/spaceacillin = 0.1, /datum/reagent/space_cleaner/sterilizine = 0.05)
/obj/item/reagent_containers/food/snacks/grown/bee_balm
seed = /obj/item/seeds/bee_balm
@@ -307,7 +307,7 @@
growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi'
icon_grow = "bee_balmalt-grow"
icon_dead = "bee_balmalt-dead"
- reagents_add = list("honey" = 0.1, "lye" = 0.3) //To make wax
+ reagents_add = list(/datum/reagent/consumable/honey = 0.1, /datum/reagent/lye = 0.3) //To make wax
rarity = 30
/obj/item/reagent_containers/food/snacks/grown/bee_balm/honey
diff --git a/code/modules/hydroponics/grown/grass_carpet.dm b/code/modules/hydroponics/grown/grass_carpet.dm
index 08ce71ad..6b01eeb3 100644
--- a/code/modules/hydroponics/grown/grass_carpet.dm
+++ b/code/modules/hydroponics/grown/grass_carpet.dm
@@ -16,7 +16,7 @@
icon_dead = "grass-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/grass/carpet, /obj/item/seeds/grass/fairy)
- reagents_add = list("nutriment" = 0.02, "hydrogen" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.02, /datum/reagent/hydrogen = 0.05)
/obj/item/reagent_containers/food/snacks/grown/grass
seed = /obj/item/seeds/grass
@@ -51,7 +51,7 @@
icon_grow = "fairygrass-grow"
icon_dead = "fairygrass-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/glow/blue)
- reagents_add = list("nutriment" = 0.02, "hydrogen" = 0.05, "space_drugs" = 0.15)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.02, /datum/reagent/hydrogen = 0.05, /datum/reagent/drug/space_drugs = 0.15)
/obj/item/reagent_containers/food/snacks/grown/grass/fairy
seed = /obj/item/seeds/grass/fairy
diff --git a/code/modules/hydroponics/grown/kudzu.dm b/code/modules/hydroponics/grown/kudzu.dm
index 6ceb6953..5f1fdcda 100644
--- a/code/modules/hydroponics/grown/kudzu.dm
+++ b/code/modules/hydroponics/grown/kudzu.dm
@@ -14,7 +14,7 @@
growthstages = 4
rarity = 30
var/list/mutations = list()
- reagents_add = list("charcoal" = 0.04, "nutriment" = 0.02)
+ reagents_add = list(/datum/reagent/medicine/charcoal = 0.04, /datum/reagent/consumable/nutriment = 0.02)
/obj/item/seeds/kudzu/Copy()
var/obj/item/seeds/kudzu/S = ..()
@@ -58,7 +58,7 @@
/obj/item/seeds/kudzu/on_chem_reaction(datum/reagents/S)
var/list/temp_mut_list = list()
- if(S.has_reagent("sterilizine", 5))
+ if(S.has_reagent(/datum/reagent/space_cleaner/sterilizine, 5))
for(var/datum/spacevine_mutation/SM in mutations)
if(SM.quality == NEGATIVE)
temp_mut_list += SM
@@ -66,7 +66,7 @@
mutations.Remove(pick(temp_mut_list))
temp_mut_list.Cut()
- if(S.has_reagent("welding_fuel", 5))
+ if(S.has_reagent(/datum/reagent/fuel, 5))
for(var/datum/spacevine_mutation/SM in mutations)
if(SM.quality == POSITIVE)
temp_mut_list += SM
@@ -74,7 +74,7 @@
mutations.Remove(pick(temp_mut_list))
temp_mut_list.Cut()
- if(S.has_reagent("phenol", 5))
+ if(S.has_reagent(/datum/reagent/phenol, 5))
for(var/datum/spacevine_mutation/SM in mutations)
if(SM.quality == MINOR_NEGATIVE)
temp_mut_list += SM
@@ -82,16 +82,16 @@
mutations.Remove(pick(temp_mut_list))
temp_mut_list.Cut()
- if(S.has_reagent("blood", 15))
+ if(S.has_reagent(/datum/reagent/blood, 15))
adjust_production(rand(15, -5))
- if(S.has_reagent("amatoxin", 5))
+ if(S.has_reagent(/datum/reagent/toxin/amatoxin, 5))
adjust_production(rand(5, -15))
- if(S.has_reagent("plasma", 5))
+ if(S.has_reagent(/datum/reagent/toxin/plasma, 5))
adjust_potency(rand(5, -15))
- if(S.has_reagent("holywater", 10))
+ if(S.has_reagent(/datum/reagent/water/holywater, 10))
adjust_potency(rand(15, -5))
diff --git a/code/modules/hydroponics/grown/melon.dm b/code/modules/hydroponics/grown/melon.dm
index cfd56d02..001997a7 100644
--- a/code/modules/hydroponics/grown/melon.dm
+++ b/code/modules/hydroponics/grown/melon.dm
@@ -12,7 +12,7 @@
icon_dead = "watermelon-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/watermelon/holy)
- reagents_add = list("water" = 0.2, "vitamin" = 0.04, "nutriment" = 0.2)
+ reagents_add = list(/datum/reagent/water = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.2)
/obj/item/seeds/watermelon/suicide_act(mob/user)
user.visible_message("[user] is swallowing [src]! It looks like [user.p_theyre()] trying to commit suicide!")
@@ -33,7 +33,7 @@
filling_color = "#008000"
bitesize_mod = 3
foodtype = FRUIT
- juice_results = list("watermelonjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/watermelonjuice = 0)
wine_power = 40
// Holymelon
@@ -46,7 +46,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/holymelon
genes = list(/datum/plant_gene/trait/glow/yellow)
mutatelist = list()
- reagents_add = list("holywater" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/water/holywater = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/holymelon
diff --git a/code/modules/hydroponics/grown/misc.dm b/code/modules/hydroponics/grown/misc.dm
index 55faff8c..606504e1 100644
--- a/code/modules/hydroponics/grown/misc.dm
+++ b/code/modules/hydroponics/grown/misc.dm
@@ -12,6 +12,7 @@
yield = 2
potency = 10
growthstages = 3
+ grind_results = list(/datum/reagent/mustardgrind = 1)
growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi'
genes = list(/datum/plant_gene/trait/plant_type/weed_hardy)
mutatelist = list()//add /obj/item/seeds/starthistle/corpse_flower when corpse flowers work.
@@ -81,7 +82,7 @@
growing_icon = 'icons/obj/hydroponics/growing_flowers.dmi'
genes = list(/datum/plant_gene/trait/plant_type/weed_hardy, /datum/plant_gene/trait/invasive)
mutatelist = list()
- reagents_add = list("nutriment" = 0.05, "silibinin" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.05, /datum/reagent/medicine/silibinin = 0.1)
/obj/item/seeds/galaxythistle/Initialize(mapload, nogenes = FALSE)
. = ..()
@@ -116,7 +117,7 @@
growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/replicapod)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/cabbage
seed = /obj/item/seeds/cabbage
@@ -141,8 +142,8 @@
endurance = 50
maturation = 3
yield = 4
- growthstages = 3
- reagents_add = list("sugar" = 0.25)
+ growthstages = 2
+ reagents_add = list(/datum/reagent/consumable/sugar = 0.25)
mutatelist = list(/obj/item/seeds/bamboo)
/obj/item/reagent_containers/food/snacks/grown/sugarcane
@@ -153,7 +154,7 @@
filling_color = "#FFD700"
bitesize_mod = 2
foodtype = VEGETABLES | SUGAR
- distill_reagent = "rum"
+ distill_reagent = /datum/reagent/consumable/ethanol/rum
// Gatfruit
/obj/item/seeds/gatfruit
@@ -173,7 +174,7 @@
growthstages = 2
rarity = 60 // Obtainable only with xenobio+superluck.
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
- reagents_add = list("sulfur" = 0.1, "carbon" = 0.1, "nitrogen" = 0.07, "potassium" = 0.05)
+ reagents_add = list(/datum/reagent/sulfur = 0.1, /datum/reagent/carbon = 0.1, /datum/reagent/nitrogen = 0.07, /datum/reagent/potassium = 0.05)
/obj/item/reagent_containers/food/snacks/grown/shell/gatfruit
seed = /obj/item/seeds/gatfruit
@@ -195,7 +196,7 @@
plantname = "Cherry Bomb Tree"
product = /obj/item/reagent_containers/food/snacks/grown/cherry_bomb
mutatelist = list()
- reagents_add = list("nutriment" = 0.1, "sugar" = 0.1, "blackpowder" = 0.7)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.1, /datum/reagent/consumable/sugar = 0.1, /datum/reagent/blackpowder = 0.7)
rarity = 60 //See above
/obj/item/reagent_containers/food/snacks/grown/cherry_bomb
@@ -257,7 +258,7 @@
icon_dead = "coconut-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
forbiddengenes = list(/datum/plant_gene/trait/squash, /datum/plant_gene/trait/stinging)
- reagents_add = list("coconutmilk" = 0.3)
+ reagents_add = list(/datum/reagent/consumable/coconutmilk = 0.3)
/obj/item/reagent_containers/food/snacks/grown/coconut
seed = /obj/item/seeds/coconut
@@ -427,21 +428,30 @@
to_chat(user, "[src] is empty!")
return
- if(istype(M))
- if(user.a_intent == INTENT_HARM && spillable == TRUE)
- var/R
- M.visible_message("[user] splashes the contents of [src] onto [M]!", \
- "[user] splashes the contents of [src] onto [M]!")
- if(reagents)
- for(var/datum/reagent/A in reagents.reagent_list)
- R += A.id + " ("
- R += num2text(A.volume) + "),"
- if(isturf(target) && reagents.reagent_list.len && thrownby)
- log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]")
- message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] at [ADMIN_VERBOSEJMP(target)].")
- reagents.reaction(M, TOUCH)
- log_combat(user, M, "splashed", R)
- reagents.clear_reagents()
+ if(user.a_intent == INTENT_HARM && spillable)
+ var/R
+ M.visible_message("[user] splashes the contents of [src] onto [M]!", \
+ "[user] splashes the contents of [src] onto [M]!")
+ if(reagents)
+ for(var/datum/reagent/A in reagents.reagent_list)
+ R += A.type + " ("
+ R += num2text(A.volume) + "),"
+ if(isturf(target) && reagents.reagent_list.len && thrownby)
+ log_combat(thrownby, target, "splashed (thrown) [english_list(reagents.reagent_list)]")
+ message_admins("[ADMIN_LOOKUPFLW(thrownby)] splashed (thrown) [english_list(reagents.reagent_list)] on [target] at [ADMIN_VERBOSEJMP(target)].")
+ reagents.reaction(M, TOUCH)
+ log_combat(user, M, "splashed", R)
+ reagents.clear_reagents()
+ else
+ if(M != user)
+ M.visible_message("[user] attempts to feed something to [M].", \
+ "[user] attempts to feed something to you.")
+ if(!do_mob(user, M))
+ return
+ if(!reagents || !reagents.total_volume)
+ return // The drink might be empty after the delay, such as by spam-feeding
+ M.visible_message("[user] feeds something to [M].", "[user] feeds something to you.")
+ log_combat(user, M, "fed", reagents.log_list())
else
if(M != user)
M.visible_message("[user] attempts to feed something to [M].", \
diff --git a/code/modules/hydroponics/grown/mushrooms.dm b/code/modules/hydroponics/grown/mushrooms.dm
index ed54dc8a..3f61dcdf 100644
--- a/code/modules/hydroponics/grown/mushrooms.dm
+++ b/code/modules/hydroponics/grown/mushrooms.dm
@@ -21,7 +21,7 @@
growthstages = 4
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
- reagents_add = list("morphine" = 0.35, "charcoal" = 0.35, "nutriment" = 0)
+ reagents_add = list(/datum/reagent/medicine/morphine = 0.35, /datum/reagent/medicine/charcoal = 0.35, /datum/reagent/consumable/nutriment = 0)
/obj/item/reagent_containers/food/snacks/grown/mushroom/reishi
seed = /obj/item/seeds/reishi
@@ -47,7 +47,7 @@
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
mutatelist = list(/obj/item/seeds/angel)
- reagents_add = list("mushroomhallucinogen" = 0.04, "amatoxin" = 0.35, "nutriment" = 0, "growthserum" = 0.1)
+ reagents_add = list(/datum/reagent/drug/mushroomhallucinogen = 0.04, /datum/reagent/toxin/amatoxin = 0.35, /datum/reagent/consumable/nutriment = 0, /datum/reagent/growthserum = 0.1)
/obj/item/reagent_containers/food/snacks/grown/mushroom/amanita
seed = /obj/item/seeds/amanita
@@ -73,7 +73,7 @@
growthstages = 3
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
- reagents_add = list("mushroomhallucinogen" = 0.04, "amatoxin" = 0.1, "nutriment" = 0, "amanitin" = 0.2)
+ reagents_add = list(/datum/reagent/drug/mushroomhallucinogen = 0.04, /datum/reagent/toxin/amatoxin = 0.1, /datum/reagent/consumable/nutriment = 0, /datum/reagent/toxin/amanitin = 0.2)
rarity = 30
/obj/item/reagent_containers/food/snacks/grown/mushroom/angel
@@ -99,7 +99,7 @@
growthstages = 3
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
- reagents_add = list("mushroomhallucinogen" = 0.25, "nutriment" = 0.02)
+ reagents_add = list(/datum/reagent/drug/mushroomhallucinogen = 0.25, /datum/reagent/consumable/nutriment = 0.02)
/obj/item/reagent_containers/food/snacks/grown/mushroom/libertycap
seed = /obj/item/seeds/liberty
@@ -125,7 +125,7 @@
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
mutatelist = list(/obj/item/seeds/plump/walkingmushroom)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/mushroom/plumphelmet
seed = /obj/item/seeds/plump
@@ -133,7 +133,7 @@
desc = "Plumus Hellmus: Plump, soft and s-so inviting~"
icon_state = "plumphelmet"
filling_color = "#9370DB"
- distill_reagent = "manlydorf"
+ distill_reagent = /datum/reagent/consumable/ethanol/manly_dorf
// Walking Mushroom
/obj/item/seeds/plump/walkingmushroom
@@ -149,7 +149,7 @@
yield = 1
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
mutatelist = list()
- reagents_add = list("vitamin" = 0.05, "nutriment" = 0.15)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.05, /datum/reagent/consumable/nutriment = 0.15)
rarity = 30
/obj/item/reagent_containers/food/snacks/grown/mushroom/walkingmushroom
@@ -189,7 +189,7 @@
growthstages = 3
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
- reagents_add = list("nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.1)
mutatelist = list(/obj/item/seeds/chanterelle/jupitercup)
/obj/item/reagent_containers/food/snacks/grown/mushroom/chanterelle
@@ -214,7 +214,7 @@
growthstages = 2
genes = list(/datum/plant_gene/trait/plant_type/fungal_metabolism, /datum/plant_gene/reagent/teslium, /datum/plant_gene/trait/plant_type/carnivory)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
- reagents_add = list("nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.1)
/obj/item/seeds/chanterelle/jupitercup/Initialize(mapload, nogenes = FALSE)
. = ..()
@@ -248,7 +248,7 @@
genes = list(/datum/plant_gene/trait/glow, /datum/plant_gene/trait/plant_type/fungal_metabolism)
growing_icon = 'icons/obj/hydroponics/growing_mushrooms.dmi'
mutatelist = list(/obj/item/seeds/glowshroom/glowcap, /obj/item/seeds/glowshroom/shadowshroom)
- reagents_add = list("radium" = 0.1, "phosphorus" = 0.1, "nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/radium = 0.1, /datum/reagent/phosphorus = 0.1, /datum/reagent/consumable/nutriment = 0.04)
/obj/item/reagent_containers/food/snacks/grown/mushroom/glowshroom
seed = /obj/item/seeds/glowshroom
@@ -293,7 +293,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/mushroom/glowshroom/glowcap
genes = list(/datum/plant_gene/trait/glow/red, /datum/plant_gene/trait/cell_charge, /datum/plant_gene/trait/plant_type/fungal_metabolism)
mutatelist = list()
- reagents_add = list("teslium" = 0.1, "nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/teslium = 0.1, /datum/reagent/consumable/nutriment = 0.04)
rarity = 30
/obj/item/reagent_containers/food/snacks/grown/mushroom/glowshroom/glowcap
@@ -318,7 +318,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/mushroom/glowshroom/shadowshroom
genes = list(/datum/plant_gene/trait/glow/shadow, /datum/plant_gene/trait/plant_type/fungal_metabolism)
mutatelist = list()
- reagents_add = list("radium" = 0.2, "nutriment" = 0.04)
+ reagents_add = list(/datum/reagent/radium = 0.2, /datum/reagent/consumable/nutriment = 0.04)
rarity = 30
/obj/item/reagent_containers/food/snacks/grown/mushroom/glowshroom/shadowshroom
@@ -350,7 +350,7 @@
potency = 15
growthstages = 3
rarity = 20
- reagents_add = list("nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment = 0.1)
resistance_flags = FIRE_PROOF
/obj/item/seeds/lavaland/polypore
diff --git a/code/modules/hydroponics/grown/nettle.dm b/code/modules/hydroponics/grown/nettle.dm
index dbcce283..c3bd82c6 100644
--- a/code/modules/hydroponics/grown/nettle.dm
+++ b/code/modules/hydroponics/grown/nettle.dm
@@ -11,7 +11,7 @@
growthstages = 5
genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/plant_type/weed_hardy)
mutatelist = list(/obj/item/seeds/nettle/death)
- reagents_add = list("sacid" = 0.5)
+ reagents_add = list(/datum/reagent/toxin/acid = 0.5)
/obj/item/seeds/nettle/death
name = "pack of death-nettle seeds"
@@ -25,7 +25,7 @@
yield = 2
genes = list(/datum/plant_gene/trait/repeated_harvest, /datum/plant_gene/trait/plant_type/weed_hardy, /datum/plant_gene/trait/stinging)
mutatelist = list()
- reagents_add = list("facid" = 0.5, "sacid" = 0.5)
+ reagents_add = list(/datum/reagent/toxin/acid/fluacid = 0.5, /datum/reagent/toxin/acid = 0.5)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/nettle // "snack"
diff --git a/code/modules/hydroponics/grown/onion.dm b/code/modules/hydroponics/grown/onion.dm
index 9cb8d1a6..2ebaa6d5 100644
--- a/code/modules/hydroponics/grown/onion.dm
+++ b/code/modules/hydroponics/grown/onion.dm
@@ -13,7 +13,7 @@
growthstages = 3
weed_chance = 3
growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
mutatelist = list(/obj/item/seeds/onion/red)
/obj/item/reagent_containers/food/snacks/grown/onion
@@ -36,7 +36,7 @@
plantname = "Red Onion Sprouts"
weed_chance = 1
product = /obj/item/reagent_containers/food/snacks/grown/onion/red
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1, "tearjuice" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1, /datum/reagent/consumable/tearjuice = 0.05)
/obj/item/reagent_containers/food/snacks/grown/onion/red
seed = /obj/item/seeds/onion/red
@@ -61,7 +61,7 @@
name = "onion slices"
desc = "Rings, not for wearing."
icon_state = "onionslice"
- list_reagents = list("nutriment" = 5, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 2)
filling_color = "#C0C9A0"
gender = PLURAL
cooked_type = /obj/item/reagent_containers/food/snacks/onionrings
@@ -71,4 +71,4 @@
desc = "They shine like exceptionally low quality amethyst."
icon_state = "onionslice_red"
filling_color = "#C29ACF"
- list_reagents = list("nutriment" = 5, "vitamin" = 2, "tearjuice" = 2.5)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 5, /datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/tearjuice = 2.5)
diff --git a/code/modules/hydroponics/grown/peach.dm b/code/modules/hydroponics/grown/peach.dm
index 6fbf933b..1f48ab55 100644
--- a/code/modules/hydroponics/grown/peach.dm
+++ b/code/modules/hydroponics/grown/peach.dm
@@ -13,7 +13,7 @@
icon_grow = "peach-grow"
icon_dead = "peach-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/peach
seed = /obj/item/seeds/peach
@@ -23,5 +23,5 @@
filling_color = "#FF4500"
bitesize = 25
foodtype = FRUIT
- juice_results = list("peachjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/peachjuice = 0)
tastes = list("peach" = 1)
diff --git a/code/modules/hydroponics/grown/peanuts.dm b/code/modules/hydroponics/grown/peanuts.dm
index 2423300c..3ac14971 100644
--- a/code/modules/hydroponics/grown/peanuts.dm
+++ b/code/modules/hydroponics/grown/peanuts.dm
@@ -8,7 +8,7 @@
yield = 6
growthstages = 4
growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
- reagents_add = list("vitamin" = 0.02, "nutriment" = 0.15, "cooking_oil" = 0.03)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.02, /datum/reagent/consumable/nutriment = 0.15, /datum/reagent/consumable/cooking_oil = 0.03)
/obj/item/reagent_containers/food/snacks/grown/peanut
seed = /obj/item/seeds/peanutseed
@@ -26,5 +26,5 @@
desc = "A handful of roasted peanuts, with or without salt."
icon_state = "roasted_peanuts"
foodtype = VEGETABLES
- list_reagents = list("nutriment" = 6, "vitamin" = 1)
- juice_results = list("peanut_butter" = 3)
\ No newline at end of file
+ list_reagents = list(/datum/reagent/consumable/nutriment = 6, /datum/reagent/consumable/nutriment/vitamin = 1)
+ juice_results = list(/datum/reagent/consumable/peanut_butter = 3)
\ No newline at end of file
diff --git a/code/modules/hydroponics/grown/pineapple.dm b/code/modules/hydroponics/grown/pineapple.dm
index 0ca4242c..7dc25392 100644
--- a/code/modules/hydroponics/grown/pineapple.dm
+++ b/code/modules/hydroponics/grown/pineapple.dm
@@ -12,7 +12,7 @@
growing_icon = 'icons/obj/hydroponics/growing_fruits.dmi'
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/apple)
- reagents_add = list("vitamin" = 0.02, "nutriment" = 0.2, "water" = 0.04)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.02, /datum/reagent/consumable/nutriment = 0.2, /datum/reagent/water = 0.04)
/obj/item/reagent_containers/food/snacks/grown/pineapple
seed = /obj/item/seeds/pineapple
diff --git a/code/modules/hydroponics/grown/potato.dm b/code/modules/hydroponics/grown/potato.dm
index 15378b36..20f2a357 100644
--- a/code/modules/hydroponics/grown/potato.dm
+++ b/code/modules/hydroponics/grown/potato.dm
@@ -16,7 +16,7 @@
icon_dead = "potato-dead"
genes = list(/datum/plant_gene/trait/battery)
mutatelist = list(/obj/item/seeds/potato/sweet)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/potato
seed = /obj/item/seeds/potato
@@ -26,8 +26,8 @@
filling_color = "#E9967A"
bitesize = 100
foodtype = VEGETABLES
- juice_results = list("potato" = 0)
- distill_reagent = "vodka"
+ juice_results = list(/datum/reagent/consumable/potato_juice = 0)
+ distill_reagent = /datum/reagent/consumable/ethanol/vodka
/obj/item/reagent_containers/food/snacks/grown/potato/wedges
name = "potato wedges"
@@ -57,11 +57,11 @@
plantname = "Sweet Potato Plants"
product = /obj/item/reagent_containers/food/snacks/grown/potato/sweet
mutatelist = list()
- reagents_add = list("vitamin" = 0.1, "sugar" = 0.1, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.1, /datum/reagent/consumable/sugar = 0.1, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/potato/sweet
seed = /obj/item/seeds/potato/sweet
name = "sweet potato"
desc = "It's sweet."
icon_state = "sweetpotato"
- distill_reagent = "sbiten"
+ distill_reagent = /datum/reagent/consumable/ethanol/sbiten
diff --git a/code/modules/hydroponics/grown/pumpkin.dm b/code/modules/hydroponics/grown/pumpkin.dm
index 644dedff..e26d1c1d 100644
--- a/code/modules/hydroponics/grown/pumpkin.dm
+++ b/code/modules/hydroponics/grown/pumpkin.dm
@@ -14,7 +14,7 @@
icon_dead = "pumpkin-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/pumpkin/blumpkin)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.2)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.2)
/obj/item/reagent_containers/food/snacks/grown/pumpkin
seed = /obj/item/seeds/pumpkin
@@ -24,7 +24,7 @@
filling_color = "#FFA500"
bitesize_mod = 2
foodtype = FRUIT
- juice_results = list("pumpkinjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/pumpkinjuice = 0)
wine_power = 20
/obj/item/reagent_containers/food/snacks/grown/pumpkin/attackby(obj/item/W as obj, mob/user as mob, params)
@@ -45,7 +45,7 @@
plantname = "Blumpkin Vines"
product = /obj/item/reagent_containers/food/snacks/grown/blumpkin
mutatelist = list()
- reagents_add = list("ammonia" = 0.2, "chlorine" = 0.1, "nutriment" = 0.2)
+ reagents_add = list(/datum/reagent/ammonia = 0.2, /datum/reagent/chlorine = 0.1, /datum/reagent/consumable/nutriment = 0.2)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/blumpkin
@@ -56,5 +56,5 @@
filling_color = "#87CEFA"
bitesize_mod = 2
foodtype = FRUIT
- juice_results = list("blumpkinjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/blumpkinjuice = 0)
wine_power = 50
diff --git a/code/modules/hydroponics/grown/replicapod.dm b/code/modules/hydroponics/grown/replicapod.dm
index bac480be..3769f9ea 100644
--- a/code/modules/hydroponics/grown/replicapod.dm
+++ b/code/modules/hydroponics/grown/replicapod.dm
@@ -31,7 +31,7 @@
/obj/item/seeds/replicapod/on_reagent_change(changetype)
if(changetype == ADD_REAGENT)
- var/datum/reagent/blood/B = reagents.has_reagent("blood")
+ var/datum/reagent/blood/B = reagents.has_reagent(/datum/reagent/blood)
if(B)
if(B.data["mind"] && B.data["cloneable"])
mind = B.data["mind"]
@@ -47,7 +47,7 @@
else
visible_message("The [src] rejects the sample!")
- if(!reagents.has_reagent("blood"))
+ if(!reagents.has_reagent(/datum/reagent/blood))
mind = null
ckey = null
realName = null
diff --git a/code/modules/hydroponics/grown/root.dm b/code/modules/hydroponics/grown/root.dm
index 090809ca..871d1535 100644
--- a/code/modules/hydroponics/grown/root.dm
+++ b/code/modules/hydroponics/grown/root.dm
@@ -12,7 +12,7 @@
growthstages = 3
growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
mutatelist = list(/obj/item/seeds/carrot/parsnip)
- reagents_add = list("oculine" = 0.25, "vitamin" = 0.04, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/medicine/oculine = 0.25, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/carrot
seed = /obj/item/seeds/carrot
@@ -22,7 +22,7 @@
filling_color = "#FFA500"
bitesize_mod = 2
foodtype = VEGETABLES
- juice_results = list("carrotjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/carrotjuice = 0)
wine_power = 30
/obj/item/reagent_containers/food/snacks/grown/carrot/attackby(obj/item/I, mob/user, params)
@@ -45,7 +45,7 @@
product = /obj/item/reagent_containers/food/snacks/grown/parsnip
icon_dead = "carrot-dead"
mutatelist = list()
- reagents_add = list("vitamin" = 0.05, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.05, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/parsnip
seed = /obj/item/seeds/carrot/parsnip
@@ -54,7 +54,7 @@
icon_state = "parsnip"
bitesize_mod = 2
foodtype = VEGETABLES
- juice_results = list("parsnipjuice" = 0)
+ juice_results = list(/datum/reagent/consumable/parsnipjuice = 0)
wine_power = 35
@@ -72,7 +72,7 @@
growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
icon_dead = "whitebeet-dead"
mutatelist = list(/obj/item/seeds/redbeet)
- reagents_add = list("vitamin" = 0.04, "sugar" = 0.2, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/sugar = 0.2, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/whitebeet
seed = /obj/item/seeds/whitebeet
@@ -98,7 +98,7 @@
growing_icon = 'icons/obj/hydroponics/growing_vegetables.dmi'
icon_dead = "whitebeet-dead"
genes = list(/datum/plant_gene/trait/maxchem)
- reagents_add = list("vitamin" = 0.05, "nutriment" = 0.05)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.05, /datum/reagent/consumable/nutriment = 0.05)
/obj/item/reagent_containers/food/snacks/grown/redbeet
seed = /obj/item/seeds/redbeet
diff --git a/code/modules/hydroponics/grown/tea_coffee.dm b/code/modules/hydroponics/grown/tea_coffee.dm
index c9e2bc6a..2c518770 100644
--- a/code/modules/hydroponics/grown/tea_coffee.dm
+++ b/code/modules/hydroponics/grown/tea_coffee.dm
@@ -14,7 +14,7 @@
icon_dead = "tea-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/tea/astra)
- reagents_add = list("teapowder" = 0.1)
+ reagents_add = list(/datum/reagent/toxin/teapowder = 0.1)
/obj/item/reagent_containers/food/snacks/grown/tea
seed = /obj/item/seeds/tea
@@ -22,7 +22,7 @@
desc = "These aromatic tips of the tea plant can be dried to make tea."
icon_state = "tea_aspera_leaves"
filling_color = "#008000"
- grind_results = list("teapowder" = 0)
+ grind_results = list(/datum/reagent/toxin/teapowder = 0)
dry_grind = TRUE
can_distill = FALSE
@@ -34,7 +34,7 @@
plantname = "Tea Astra Plant"
product = /obj/item/reagent_containers/food/snacks/grown/tea/astra
mutatelist = list(/obj/item/seeds/tea/catnip)
- reagents_add = list("synaptizine" = 0.1, "vitamin" = 0.04, "teapowder" = 0.1)
+ reagents_add = list(/datum/reagent/medicine/synaptizine = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/toxin/teapowder = 0.1)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/tea/astra
@@ -42,7 +42,7 @@
name = "Tea Astra tips"
icon_state = "tea_astra_leaves"
filling_color = "#4582B4"
- grind_results = list("teapowder" = 0, "salglu_solution" = 0)
+ grind_results = list(/datum/reagent/toxin/teapowder = 0, /datum/reagent/medicine/salglu_solution = 0)
// Kitty drugs
@@ -53,7 +53,7 @@
species = "catnip"
plantname = "Catnip Plant"
product = /obj/item/reagent_containers/food/snacks/grown/tea/catnip
- reagents_add = list("catnip" = 0.1, "vitamin" = 0.06, "teapowder" = 0.3)
+ reagents_add = list(/datum/reagent/pax/catnip = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.06, /datum/reagent/toxin/teapowder = 0.3)
rarity = 50
/obj/item/reagent_containers/food/snacks/grown/tea/catnip
@@ -61,7 +61,8 @@
name = "Catnip buds"
icon_state = "catnip"
filling_color = "#4582B4"
- grind_results = list("catnp" = 2, "water" = 1)
+ grind_results = list(/datum/reagent/pax/catnip = 2, /datum/reagent/water = 1)
+
// Coffee
/obj/item/seeds/coffee
name = "pack of coffee arabica seeds"
@@ -79,7 +80,7 @@
icon_dead = "coffee-dead"
genes = list(/datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/coffee/robusta)
- reagents_add = list("vitamin" = 0.04, "coffeepowder" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/toxin/coffeepowder = 0.1)
/obj/item/reagent_containers/food/snacks/grown/coffee
seed = /obj/item/seeds/coffee
@@ -89,8 +90,8 @@
filling_color = "#DC143C"
bitesize_mod = 2
dry_grind = TRUE
- grind_results = list("coffeepowder" = 0)
- distill_reagent = "kahlua"
+ grind_results = list(/datum/reagent/toxin/coffeepowder = 0)
+ distill_reagent = /datum/reagent/consumable/ethanol/kahlua
// Coffee Robusta
/obj/item/seeds/coffee/robusta
@@ -101,7 +102,7 @@
plantname = "Coffee Robusta Bush"
product = /obj/item/reagent_containers/food/snacks/grown/coffee/robusta
mutatelist = list()
- reagents_add = list("ephedrine" = 0.1, "vitamin" = 0.04, "coffeepowder" = 0.1)
+ reagents_add = list(/datum/reagent/medicine/ephedrine = 0.1, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/toxin/coffeepowder = 0.1)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/coffee/robusta
@@ -109,4 +110,4 @@
name = "coffee robusta beans"
desc = "Increases robustness by 37 percent!"
icon_state = "coffee_robusta"
- grind_results = list("coffeepowder" = 0, "morphine" = 0)
+ grind_results = list(/datum/reagent/toxin/coffeepowder = 0, /datum/reagent/medicine/morphine = 0)
diff --git a/code/modules/hydroponics/grown/tobacco.dm b/code/modules/hydroponics/grown/tobacco.dm
index 684271fa..1e2d25d8 100644
--- a/code/modules/hydroponics/grown/tobacco.dm
+++ b/code/modules/hydroponics/grown/tobacco.dm
@@ -13,7 +13,7 @@
growthstages = 3
icon_dead = "tobacco-dead"
mutatelist = list(/obj/item/seeds/tobacco/space)
- reagents_add = list("nicotine" = 0.03, "nutriment" = 0.03)
+ reagents_add = list(/datum/reagent/drug/nicotine = 0.03, /datum/reagent/consumable/nutriment = 0.03)
/obj/item/reagent_containers/food/snacks/grown/tobacco
seed = /obj/item/seeds/tobacco
@@ -21,7 +21,7 @@
desc = "Dry them out to make some smokes."
icon_state = "tobacco_leaves"
filling_color = "#008000"
- distill_reagent = "creme_de_menthe" //Menthol, I guess.
+ distill_reagent = /datum/reagent/consumable/ethanol/creme_de_menthe //Menthol, I guess.
// Space Tobacco
/obj/item/seeds/tobacco/space
@@ -32,7 +32,7 @@
plantname = "Space Tobacco Plant"
product = /obj/item/reagent_containers/food/snacks/grown/tobacco/space
mutatelist = list()
- reagents_add = list("salbutamol" = 0.05, "nicotine" = 0.08, "nutriment" = 0.03)
+ reagents_add = list(/datum/reagent/medicine/salbutamol = 0.05, /datum/reagent/drug/nicotine = 0.08, /datum/reagent/consumable/nutriment = 0.03)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/tobacco/space
diff --git a/code/modules/hydroponics/grown/tomato.dm b/code/modules/hydroponics/grown/tomato.dm
index d07f5d4d..53c33896 100644
--- a/code/modules/hydroponics/grown/tomato.dm
+++ b/code/modules/hydroponics/grown/tomato.dm
@@ -12,7 +12,7 @@
icon_dead = "tomato-dead"
genes = list(/datum/plant_gene/trait/squash, /datum/plant_gene/trait/repeated_harvest)
mutatelist = list(/obj/item/seeds/tomato/blue, /obj/item/seeds/tomato/blood, /obj/item/seeds/tomato/killer)
- reagents_add = list("vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
/obj/item/reagent_containers/food/snacks/grown/tomato
seed = /obj/item/seeds/tomato
@@ -23,9 +23,9 @@
filling_color = "#FF6347"
bitesize_mod = 2
foodtype = FRUIT
- grind_results = list("ketchup" = 0)
- juice_results = list("tomatojuice" = 0)
- distill_reagent = "enzyme"
+ grind_results = list(/datum/reagent/consumable/ketchup = 0)
+ juice_results = list(/datum/reagent/consumable/tomatojuice = 0)
+ distill_reagent = /datum/reagent/consumable/enzyme
// Blood Tomato
/obj/item/seeds/tomato/blood
@@ -36,7 +36,7 @@
plantname = "Blood-Tomato Plants"
product = /obj/item/reagent_containers/food/snacks/grown/tomato/blood
mutatelist = list()
- reagents_add = list("blood" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/blood = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/tomato/blood
@@ -47,8 +47,8 @@
splat_type = /obj/effect/gibspawner/generic
filling_color = "#FF0000"
foodtype = FRUIT | GROSS
- grind_results = list("ketchup" = 0, "blood" = 0)
- distill_reagent = "bloodymary"
+ grind_results = list(/datum/reagent/consumable/ketchup = 0, /datum/reagent/blood = 0)
+ distill_reagent = /datum/reagent/consumable/ethanol/bloody_mary
// Blue Tomato
/obj/item/seeds/tomato/blue
@@ -62,7 +62,7 @@
icon_grow = "bluetomato-grow"
mutatelist = list(/obj/item/seeds/tomato/blue/bluespace)
genes = list(/datum/plant_gene/trait/slip, /datum/plant_gene/trait/repeated_harvest)
- reagents_add = list("lube" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/lube = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 20
/obj/item/reagent_containers/food/snacks/grown/tomato/blue
@@ -72,7 +72,7 @@
icon_state = "bluetomato"
splat_type = /obj/effect/decal/cleanable/oil
filling_color = "#0000FF"
- distill_reagent = "laughter"
+ distill_reagent = /datum/reagent/consumable/laughter
// Bluespace Tomato
/obj/item/seeds/tomato/blue/bluespace
@@ -85,7 +85,7 @@
yield = 2
mutatelist = list()
genes = list(/datum/plant_gene/trait/squash, /datum/plant_gene/trait/slip, /datum/plant_gene/trait/teleport, /datum/plant_gene/trait/repeated_harvest)
- reagents_add = list("lube" = 0.2, "bluespace" = 0.2, "vitamin" = 0.04, "nutriment" = 0.1)
+ reagents_add = list(/datum/reagent/lube = 0.2, /datum/reagent/bluespace = 0.2, /datum/reagent/consumable/nutriment/vitamin = 0.04, /datum/reagent/consumable/nutriment = 0.1)
rarity = 50
/obj/item/reagent_containers/food/snacks/grown/tomato/blue/bluespace
@@ -120,7 +120,7 @@
icon_state = "killertomato"
var/awakening = 0
filling_color = "#FF0000"
- distill_reagent = "demonsblood"
+ distill_reagent = /datum/reagent/consumable/ethanol/demonsblood
/obj/item/reagent_containers/food/snacks/grown/tomato/killer/attack(mob/M, mob/user, def_zone)
if(awakening)
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index ea56ed60..9655b138 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -1,195 +1,195 @@
-// Plant analyzer
-/obj/item/plant_analyzer
- name = "plant analyzer"
- desc = "A scanner used to evaluate a plant's various areas of growth."
- icon = 'icons/obj/device.dmi'
- icon_state = "hydro"
- item_state = "analyzer"
- lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
- w_class = WEIGHT_CLASS_TINY
- slot_flags = ITEM_SLOT_BELT
- materials = list(MAT_METAL=30, MAT_GLASS=20)
-
-// *************************************
-// Hydroponics Tools
-// *************************************
-
-/obj/item/reagent_containers/spray/weedspray // -- Skie
- desc = "It's a toxic mixture, in spray form, to kill small weeds."
- icon = 'icons/obj/hydroponics/equipment.dmi'
- name = "weed spray"
- icon_state = "weedspray"
- item_state = "spraycan"
- lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
- volume = 100
- list_reagents = list("weedkiller" = 100)
-
-/obj/item/reagent_containers/spray/weedspray/suicide_act(mob/user)
- user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return (TOXLOSS)
-
-/obj/item/reagent_containers/spray/pestspray // -- Skie
- desc = "It's some pest eliminator spray! Do not inhale!"
- icon = 'icons/obj/hydroponics/equipment.dmi'
- name = "pest spray"
- icon_state = "pestspray"
- item_state = "plantbgone"
- lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
- volume = 100
- list_reagents = list("pestkiller" = 100)
-
-/obj/item/reagent_containers/spray/pestspray/suicide_act(mob/user)
- user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return (TOXLOSS)
-
-/obj/item/cultivator
- name = "cultivator"
- desc = "It's used for removing weeds or scratching your back."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "cultivator"
- item_state = "cultivator"
- lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
- flags_1 = CONDUCT_1
- force = 5
- throwforce = 7
- w_class = WEIGHT_CLASS_SMALL
- materials = list(MAT_METAL=50)
- attack_verb = list("slashed", "sliced", "cut", "clawed")
- hitsound = 'sound/weapons/bladeslice.ogg'
-
-/obj/item/cultivator/suicide_act(mob/user)
- user.visible_message("[user] is scratching [user.p_their()] back as hard as [user.p_they()] can with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- return (BRUTELOSS)
-
-/obj/item/hatchet
- name = "hatchet"
- desc = "A very sharp axe blade upon a short fibremetal handle. It has a long history of chopping things, but now it is used for chopping wood."
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "hatchet"
- item_state = "hatchet"
- lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
- flags_1 = CONDUCT_1
- force = 12
- w_class = WEIGHT_CLASS_SMALL
- throwforce = 15
- throw_speed = 3
- throw_range = 4
- materials = list(MAT_METAL = 15000)
- attack_verb = list("chopped", "torn", "cut")
- hitsound = 'sound/weapons/bladeslice.ogg'
- sharpness = IS_SHARP
-
-/obj/item/hatchet/Initialize()
- . = ..()
- AddComponent(/datum/component/butchering, 70, 100)
-
-/obj/item/hatchet/suicide_act(mob/user)
- user.visible_message("[user] is chopping at [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- playsound(src, 'sound/weapons/bladeslice.ogg', 50, 1, -1)
- return (BRUTELOSS)
-
-/obj/item/scythe
- icon_state = "scythe0"
- lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi'
- name = "scythe"
- desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow."
- force = 13
- throwforce = 5
- throw_speed = 2
- throw_range = 3
- w_class = WEIGHT_CLASS_BULKY
- flags_1 = CONDUCT_1
- armour_penetration = 20
- slot_flags = ITEM_SLOT_BACK
- attack_verb = list("chopped", "sliced", "cut", "reaped")
- hitsound = 'sound/weapons/bladeslice.ogg'
- var/swiping = FALSE
-
-/obj/item/scythe/Initialize()
- . = ..()
- AddComponent(/datum/component/butchering, 90, 105)
-
-/obj/item/scythe/suicide_act(mob/user)
- user.visible_message("[user] is beheading [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
- if(iscarbon(user))
- var/mob/living/carbon/C = user
- var/obj/item/bodypart/BP = C.get_bodypart(BODY_ZONE_HEAD)
- if(BP)
- BP.drop_limb()
- playsound(src,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
- return (BRUTELOSS)
-
-/obj/item/scythe/pre_attack(atom/A, mob/living/user, params)
- if(swiping || !istype(A, /obj/structure/spacevine) || get_turf(A) == get_turf(user))
- return ..()
- else
- var/turf/user_turf = get_turf(user)
- var/dir_to_target = get_dir(user_turf, get_turf(A))
- var/stam_gain = 0
- swiping = TRUE
- var/static/list/scythe_slash_angles = list(0, 45, 90, -45, -90)
- for(var/i in scythe_slash_angles)
- var/turf/T = get_step(user_turf, turn(dir_to_target, i))
- for(var/obj/structure/spacevine/V in T)
- if(user.Adjacent(V))
- melee_attack_chain(user, V)
- stam_gain += 5 //should be hitcost
- swiping = FALSE
- stam_gain += 2 //Initial hitcost
- user.adjustStaminaLoss(-stam_gain)
-
-// *************************************
-// Nutrient defines for hydroponics
-// *************************************
-
-
-/obj/item/reagent_containers/glass/bottle/nutrient
- name = "bottle of nutrient"
- volume = 50
- amount_per_transfer_from_this = 10
- possible_transfer_amounts = list(1,2,5,10,15,25,50)
-
-/obj/item/reagent_containers/glass/bottle/nutrient/Initialize()
- . = ..()
- pixel_x = rand(-5, 5)
- pixel_y = rand(-5, 5)
-
-
-/obj/item/reagent_containers/glass/bottle/nutrient/ez
- name = "bottle of E-Z-Nutrient"
- desc = "Contains a fertilizer that causes mild mutations with each harvest."
- list_reagents = list("eznutriment" = 50)
-
-/obj/item/reagent_containers/glass/bottle/nutrient/l4z
- name = "bottle of Left 4 Zed"
- desc = "Contains a fertilizer that limits plant yields to no more than one and causes significant mutations in plants."
- list_reagents = list("left4zednutriment" = 50)
-
-/obj/item/reagent_containers/glass/bottle/nutrient/rh
- name = "bottle of Robust Harvest"
- desc = "Contains a fertilizer that increases the yield of a plant by 30% while causing no mutations."
- list_reagents = list("robustharvestnutriment" = 50)
-
-/obj/item/reagent_containers/glass/bottle/nutrient/empty
- name = "bottle"
-
-/obj/item/reagent_containers/glass/bottle/killer
- volume = 50
- amount_per_transfer_from_this = 10
- possible_transfer_amounts = list(1,2,5,10,15,25,50)
-
-/obj/item/reagent_containers/glass/bottle/killer/weedkiller
- name = "bottle of weed killer"
- desc = "Contains a herbicide."
- list_reagents = list("weedkiller" = 50)
-
-/obj/item/reagent_containers/glass/bottle/killer/pestkiller
- name = "bottle of pest spray"
- desc = "Contains a pesticide."
- list_reagents = list("pestkiller" = 50)
\ No newline at end of file
+// Plant analyzer
+/obj/item/plant_analyzer
+ name = "plant analyzer"
+ desc = "A scanner used to evaluate a plant's various areas of growth."
+ icon = 'icons/obj/device.dmi'
+ icon_state = "hydro"
+ item_state = "analyzer"
+ lefthand_file = 'icons/mob/inhands/equipment/tools_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/tools_righthand.dmi'
+ w_class = WEIGHT_CLASS_TINY
+ slot_flags = ITEM_SLOT_BELT
+ materials = list(MAT_METAL=30, MAT_GLASS=20)
+
+// *************************************
+// Hydroponics Tools
+// *************************************
+
+/obj/item/reagent_containers/spray/weedspray // -- Skie
+ desc = "It's a toxic mixture, in spray form, to kill small weeds."
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ name = "weed spray"
+ icon_state = "weedspray"
+ item_state = "spraycan"
+ lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
+ volume = 100
+ list_reagents = list(/datum/reagent/toxin/plantbgone/weedkiller = 100)
+
+/obj/item/reagent_containers/spray/weedspray/suicide_act(mob/user)
+ user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (TOXLOSS)
+
+/obj/item/reagent_containers/spray/pestspray // -- Skie
+ desc = "It's some pest eliminator spray! Do not inhale!"
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ name = "pest spray"
+ icon_state = "pestspray"
+ item_state = "plantbgone"
+ lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
+ volume = 100
+ list_reagents = list(/datum/reagent/toxin/pestkiller = 100)
+
+/obj/item/reagent_containers/spray/pestspray/suicide_act(mob/user)
+ user.visible_message("[user] is huffing [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (TOXLOSS)
+
+/obj/item/cultivator
+ name = "cultivator"
+ desc = "It's used for removing weeds or scratching your back."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "cultivator"
+ item_state = "cultivator"
+ lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
+ flags_1 = CONDUCT_1
+ force = 5
+ throwforce = 7
+ w_class = WEIGHT_CLASS_SMALL
+ materials = list(MAT_METAL=50)
+ attack_verb = list("slashed", "sliced", "cut", "clawed")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+
+/obj/item/cultivator/suicide_act(mob/user)
+ user.visible_message("[user] is scratching [user.p_their()] back as hard as [user.p_they()] can with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (BRUTELOSS)
+
+/obj/item/hatchet
+ name = "hatchet"
+ desc = "A very sharp axe blade upon a short fibremetal handle. It has a long history of chopping things, but now it is used for chopping wood."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "hatchet"
+ item_state = "hatchet"
+ lefthand_file = 'icons/mob/inhands/equipment/hydroponics_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/hydroponics_righthand.dmi'
+ flags_1 = CONDUCT_1
+ force = 12
+ w_class = WEIGHT_CLASS_SMALL
+ throwforce = 15
+ throw_speed = 3
+ throw_range = 4
+ materials = list(MAT_METAL = 15000)
+ attack_verb = list("chopped", "torn", "cut")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ sharpness = IS_SHARP
+
+/obj/item/hatchet/Initialize()
+ . = ..()
+ AddComponent(/datum/component/butchering, 70, 100)
+
+/obj/item/hatchet/suicide_act(mob/user)
+ user.visible_message("[user] is chopping at [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ playsound(src, 'sound/weapons/bladeslice.ogg', 50, 1, -1)
+ return (BRUTELOSS)
+
+/obj/item/scythe
+ icon_state = "scythe0"
+ lefthand_file = 'icons/mob/inhands/weapons/polearms_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/polearms_righthand.dmi'
+ name = "scythe"
+ desc = "A sharp and curved blade on a long fibremetal handle, this tool makes it easy to reap what you sow."
+ force = 13
+ throwforce = 5
+ throw_speed = 2
+ throw_range = 3
+ w_class = WEIGHT_CLASS_BULKY
+ flags_1 = CONDUCT_1
+ armour_penetration = 20
+ slot_flags = ITEM_SLOT_BACK
+ attack_verb = list("chopped", "sliced", "cut", "reaped")
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ var/swiping = FALSE
+
+/obj/item/scythe/Initialize()
+ . = ..()
+ AddComponent(/datum/component/butchering, 90, 105)
+
+/obj/item/scythe/suicide_act(mob/user)
+ user.visible_message("[user] is beheading [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ var/obj/item/bodypart/BP = C.get_bodypart(BODY_ZONE_HEAD)
+ if(BP)
+ BP.drop_limb()
+ playsound(src,pick('sound/misc/desceration-01.ogg','sound/misc/desceration-02.ogg','sound/misc/desceration-01.ogg') ,50, 1, -1)
+ return (BRUTELOSS)
+
+/obj/item/scythe/pre_attack(atom/A, mob/living/user, params)
+ if(swiping || !istype(A, /obj/structure/spacevine) || get_turf(A) == get_turf(user))
+ return ..()
+ else
+ var/turf/user_turf = get_turf(user)
+ var/dir_to_target = get_dir(user_turf, get_turf(A))
+ var/stam_gain = 0
+ swiping = TRUE
+ var/static/list/scythe_slash_angles = list(0, 45, 90, -45, -90)
+ for(var/i in scythe_slash_angles)
+ var/turf/T = get_step(user_turf, turn(dir_to_target, i))
+ for(var/obj/structure/spacevine/V in T)
+ if(user.Adjacent(V))
+ melee_attack_chain(user, V)
+ stam_gain += 5 //should be hitcost
+ swiping = FALSE
+ stam_gain += 2 //Initial hitcost
+ user.adjustStaminaLoss(-stam_gain)
+
+// *************************************
+// Nutrient defines for hydroponics
+// *************************************
+
+
+/obj/item/reagent_containers/glass/bottle/nutrient
+ name = "bottle of nutrient"
+ volume = 50
+ amount_per_transfer_from_this = 10
+ possible_transfer_amounts = list(1,2,5,10,15,25,50)
+
+/obj/item/reagent_containers/glass/bottle/nutrient/Initialize()
+ . = ..()
+ pixel_x = rand(-5, 5)
+ pixel_y = rand(-5, 5)
+
+
+/obj/item/reagent_containers/glass/bottle/nutrient/ez
+ name = "bottle of E-Z-Nutrient"
+ desc = "Contains a fertilizer that causes mild mutations with each harvest."
+ list_reagents = list(/datum/reagent/plantnutriment/eznutriment = 50)
+
+/obj/item/reagent_containers/glass/bottle/nutrient/l4z
+ name = "bottle of Left 4 Zed"
+ desc = "Contains a fertilizer that limits plant yields to no more than one and causes significant mutations in plants."
+ list_reagents = list(/datum/reagent/plantnutriment/left4zednutriment = 50)
+
+/obj/item/reagent_containers/glass/bottle/nutrient/rh
+ name = "bottle of Robust Harvest"
+ desc = "Contains a fertilizer that increases the yield of a plant by 30% while causing no mutations."
+ list_reagents = list(/datum/reagent/plantnutriment/robustharvestnutriment = 50)
+
+/obj/item/reagent_containers/glass/bottle/nutrient/empty
+ name = "bottle"
+
+/obj/item/reagent_containers/glass/bottle/killer
+ volume = 50
+ amount_per_transfer_from_this = 10
+ possible_transfer_amounts = list(1,2,5,10,15,25,50)
+
+/obj/item/reagent_containers/glass/bottle/killer/weedkiller
+ name = "bottle of weed killer"
+ desc = "Contains a herbicide."
+ list_reagents = list(/datum/reagent/toxin/plantbgone/weedkiller = 50)
+
+/obj/item/reagent_containers/glass/bottle/killer/pestkiller
+ name = "bottle of pest spray"
+ desc = "Contains a pesticide."
+ list_reagents = list(/datum/reagent/toxin/pestkiller = 50)
\ No newline at end of file
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 3167c495..9c594260 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -1,947 +1,947 @@
-/obj/machinery/hydroponics
- name = "hydroponics tray"
- icon = 'icons/obj/hydroponics/equipment.dmi'
- icon_state = "hydrotray"
- density = TRUE
- pixel_z = 8
- obj_flags = CAN_BE_HIT | UNIQUE_RENAME
- circuit = /obj/item/circuitboard/machine/hydroponics
- var/waterlevel = 100 //The amount of water in the tray (max 100)
- var/maxwater = 100 //The maximum amount of water in the tray
- var/nutrilevel = 10 //The amount of nutrient in the tray (max 10)
- var/maxnutri = 10 //The maximum nutrient of water in the tray
- var/pestlevel = 0 //The amount of pests in the tray (max 10)
- var/weedlevel = 0 //The amount of weeds in the tray (max 10)
- var/yieldmod = 1 //Nutriment's effect on yield
- var/mutmod = 1 //Nutriment's effect on mutations
- var/toxic = 0 //Toxicity in the tray?
- var/age = 0 //Current age
- var/dead = 0 //Is it dead?
- var/plant_health //Its health
- var/lastproduce = 0 //Last time it was harvested
- var/lastcycle = 0 //Used for timing of cycles.
- var/cycledelay = 200 //About 10 seconds / cycle
- var/harvest = 0 //Ready to harvest?
- var/obj/item/seeds/myseed = null //The currently planted seed
- var/rating = 1
- var/unwrenchable = 1
- var/recent_bee_visit = FALSE //Have we been visited by a bee recently, so bees dont overpollinate one plant
- var/using_irrigation = FALSE //If the tray is connected to other trays via irrigation hoses
- var/self_sufficiency_req = 20 //Required total dose to make a self-sufficient hydro tray. 1:1 with earthsblood.
- var/self_sufficiency_progress = 0
- var/self_sustaining = FALSE //If the tray generates nutrients and water on its own
-
-
-/obj/machinery/hydroponics/constructable
- name = "hydroponics tray"
- icon = 'icons/obj/hydroponics/equipment.dmi'
- icon_state = "hydrotray3"
-
-/obj/machinery/hydroponics/constructable/RefreshParts()
- var/tmp_capacity = 0
- for (var/obj/item/stock_parts/matter_bin/M in component_parts)
- tmp_capacity += M.rating
- for (var/obj/item/stock_parts/manipulator/M in component_parts)
- rating = M.rating
- maxwater = tmp_capacity * 50 // Up to 300
- maxnutri = tmp_capacity * 5 // Up to 30
-
-/obj/machinery/hydroponics/Destroy()
- if(myseed)
- qdel(myseed)
- myseed = null
- return ..()
-
-/obj/machinery/hydroponics/constructable/attackby(obj/item/I, mob/user, params)
- if (user.a_intent != INTENT_HARM)
- // handle opening the panel
- if(default_deconstruction_screwdriver(user, icon_state, icon_state, I))
- return
-
- // handle deconstructing the machine, if permissible
- if (I.tool_behaviour == TOOL_CROWBAR && using_irrigation)
- to_chat(user, "Disconnect the hoses first!")
- return
- else if(default_deconstruction_crowbar(I))
- return
-
- return ..()
-
-/obj/machinery/hydroponics/proc/FindConnected()
- var/list/connected = list()
- var/list/processing_atoms = list(src)
-
- while(processing_atoms.len)
- var/atom/a = processing_atoms[1]
- for(var/step_dir in GLOB.cardinals)
- var/obj/machinery/hydroponics/h = locate() in get_step(a, step_dir)
- // Soil plots aren't dense
- if(h && h.using_irrigation && h.density && !(h in connected) && !(h in processing_atoms))
- processing_atoms += h
-
- processing_atoms -= a
- connected += a
-
- return connected
-
-
-/obj/machinery/hydroponics/bullet_act(obj/item/projectile/Proj) //Works with the Somatoray to modify plant variables.
- if(!myseed)
- return ..()
- if(istype(Proj , /obj/item/projectile/energy/floramut))
- mutate()
- else if(istype(Proj , /obj/item/projectile/energy/florayield))
- return myseed.bullet_act(Proj)
- else
- return ..()
-
-/obj/machinery/hydroponics/process()
- var/needs_update = 0 // Checks if the icon needs updating so we don't redraw empty trays every time
-
- if(myseed && (myseed.loc != src))
- myseed.forceMove(src)
-
- if(self_sustaining)
- adjustNutri(1)
- adjustWater(rand(3,5))
- adjustWeeds(-2)
- adjustPests(-2)
- adjustToxic(-2)
-
- if(world.time > (lastcycle + cycledelay))
- lastcycle = world.time
- if(myseed && !dead)
- // Advance age
- age++
- if(age < myseed.maturation)
- lastproduce = age
-
- needs_update = 1
-
-//Nutrients//////////////////////////////////////////////////////////////
- // Nutrients deplete slowly
- if(prob(50))
- adjustNutri(-1 / rating)
-
- // Lack of nutrients hurts non-weeds
- if(nutrilevel <= 0 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
- adjustHealth(-rand(1,3))
-
-//Photosynthesis/////////////////////////////////////////////////////////
- // Lack of light hurts non-mushrooms
- if(isturf(loc))
- var/turf/currentTurf = loc
- var/lightAmt = currentTurf.get_lumcount()
- if(myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
- if(lightAmt < 0.2)
- adjustHealth(-1 / rating)
- else // Non-mushroom
- if(lightAmt < 0.4)
- adjustHealth(-2 / rating)
-
-//Water//////////////////////////////////////////////////////////////////
- // Drink random amount of water
- adjustWater(-rand(1,6) / rating)
-
- // If the plant is dry, it loses health pretty fast, unless mushroom
- if(waterlevel <= 10 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
- adjustHealth(-rand(0,1) / rating)
- if(waterlevel <= 0)
- adjustHealth(-rand(0,2) / rating)
-
- // Sufficient water level and nutrient level = plant healthy but also spawns weeds
- else if(waterlevel > 10 && nutrilevel > 0)
- adjustHealth(rand(1,2) / rating)
- if(myseed && prob(myseed.weed_chance))
- adjustWeeds(myseed.weed_rate)
- else if(prob(5)) //5 percent chance the weed population will increase
- adjustWeeds(1 / rating)
-
-//Toxins/////////////////////////////////////////////////////////////////
-
- // Too much toxins cause harm, but when the plant drinks the contaiminated water, the toxins disappear slowly
- if(toxic >= 40 && toxic < 80)
- adjustHealth(-1 / rating)
- adjustToxic(-rand(1,10) / rating)
- else if(toxic >= 80) // I don't think it ever gets here tbh unless above is commented out
- adjustHealth(-3)
- adjustToxic(-rand(1,10) / rating)
-
-//Pests & Weeds//////////////////////////////////////////////////////////
-
- if(pestlevel >= 8)
- if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/carnivory))
- adjustHealth(-2 / rating)
-
- else
- adjustHealth(2 / rating)
- adjustPests(-1 / rating)
-
- else if(pestlevel >= 4)
- if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/carnivory))
- adjustHealth(-1 / rating)
-
- else
- adjustHealth(1 / rating)
- if(prob(50))
- adjustPests(-1 / rating)
-
- else if(pestlevel < 4 && myseed.get_gene(/datum/plant_gene/trait/plant_type/carnivory))
- adjustHealth(-2 / rating)
- if(prob(5))
- adjustPests(-1 / rating)
-
- // If it's a weed, it doesn't stunt the growth
- if(weedlevel >= 5 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
- adjustHealth(-1 / rating)
-
-//Health & Age///////////////////////////////////////////////////////////
-
- // Plant dies if plant_health <= 0
- if(plant_health <= 0)
- plantdies()
- adjustWeeds(1 / rating) // Weeds flourish
-
- // If the plant is too old, lose health fast
- if(age > myseed.lifespan)
- adjustHealth(-rand(1,5) / rating)
-
- // Harvest code
- if(age > myseed.production && (age - lastproduce) > myseed.production && (!harvest && !dead))
- nutrimentMutation()
- if(myseed && myseed.yield != -1) // Unharvestable shouldn't be harvested
- harvest = 1
- else
- lastproduce = age
- if(prob(5)) // On each tick, there's a 5 percent chance the pest population will increase
- adjustPests(1 / rating)
- else
- if(waterlevel > 10 && nutrilevel > 0 && prob(10)) // If there's no plant, the percentage chance is 10%
- adjustWeeds(1 / rating)
-
- // Weeeeeeeeeeeeeeedddssss
- if(weedlevel >= 10 && prob(50)) // At this point the plant is kind of fucked. Weeds can overtake the plant spot.
- if(myseed)
- if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) // If a normal plant
- weedinvasion()
- else
- weedinvasion() // Weed invasion into empty tray
- needs_update = 1
- if (needs_update)
- update_icon()
-
- if(myseed && prob(5 * (11-myseed.production)))
- for(var/g in myseed.genes)
- if(istype(g, /datum/plant_gene/trait))
- var/datum/plant_gene/trait/selectedtrait = g
- selectedtrait.on_grow(src)
- return
-
-/obj/machinery/hydroponics/proc/nutrimentMutation()
- if (mutmod == 0)
- return
- if (mutmod == 1)
- if(prob(80)) //80%
- mutate()
- else if(prob(75)) //15%
- hardmutate()
- return
- if (mutmod == 2)
- if(prob(50)) //50%
- mutate()
- else if(prob(50)) //25%
- hardmutate()
- else if(prob(50)) //12.5%
- mutatespecie()
- return
- return
-
-/obj/machinery/hydroponics/update_icon()
- //Refreshes the icon and sets the luminosity
- cut_overlays()
-
- if(self_sustaining)
- if(istype(src, /obj/machinery/hydroponics/soil))
- add_atom_colour(rgb(255, 175, 0), FIXED_COLOUR_PRIORITY)
- else
- add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "gaia_blessing"))
- set_light(3)
-
- update_icon_hoses()
-
- if(myseed)
- update_icon_plant()
- update_icon_lights()
-
- if(!self_sustaining)
- if(myseed && myseed.get_gene(/datum/plant_gene/trait/glow))
- var/datum/plant_gene/trait/glow/G = myseed.get_gene(/datum/plant_gene/trait/glow)
- set_light(G.glow_range(myseed), G.glow_power(myseed), G.glow_color)
- else
- set_light(0)
-
- return
-
-/obj/machinery/hydroponics/proc/update_icon_hoses()
- var/n = 0
- for(var/Dir in GLOB.cardinals)
- var/obj/machinery/hydroponics/t = locate() in get_step(src,Dir)
- if(t && t.using_irrigation && using_irrigation)
- n += Dir
-
- icon_state = "hoses-[n]"
-
-/obj/machinery/hydroponics/proc/update_icon_plant()
- var/mutable_appearance/plant_overlay = mutable_appearance(myseed.growing_icon, layer = OBJ_LAYER + 0.01)
- if(dead)
- plant_overlay.icon_state = myseed.icon_dead
- else if(harvest)
- if(!myseed.icon_harvest)
- plant_overlay.icon_state = "[myseed.icon_grow][myseed.growthstages]"
- else
- plant_overlay.icon_state = myseed.icon_harvest
- else
- var/t_growthstate = min(round((age / myseed.maturation) * myseed.growthstages), myseed.growthstages)
- plant_overlay.icon_state = "[myseed.icon_grow][t_growthstate]"
- add_overlay(plant_overlay)
-
-/obj/machinery/hydroponics/proc/update_icon_lights()
- if(waterlevel <= 10)
- add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_lowwater3"))
- if(nutrilevel <= 2)
- add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_lownutri3"))
- if(plant_health <= (myseed.endurance / 2))
- add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_lowhealth3"))
- if(weedlevel >= 5 || pestlevel >= 5 || toxic >= 40)
- add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_alert3"))
- if(harvest)
- add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_harvest3"))
-
-
-/obj/machinery/hydroponics/examine(user)
- . = ..()
- if(myseed)
- . += "It has [myseed.plantname] planted."
- if (dead)
- . += "It's dead!"
- else if (harvest)
- . += "It's ready to harvest."
- else if (plant_health <= (myseed.endurance / 2))
- . += "It looks unhealthy."
- else
- . += "It's empty."
-
- if(!self_sustaining)
- . += "Water: [waterlevel]/[maxwater]."
- . += "Nutrient: [nutrilevel]/[maxnutri]."
- if(self_sufficiency_progress > 0)
- var/percent_progress = round(self_sufficiency_progress * 100 / self_sufficiency_req)
- . += "Treatment for self-sustenance are [percent_progress]% complete."
- else
- . += "It doesn't require any water or nutrients."
-
- if(weedlevel >= 5)
- . += "It's filled with weeds!"
- if(pestlevel >= 5)
- . += "It's filled with tiny worms!"
-
-/obj/machinery/hydroponics/proc/weedinvasion() // If a weed growth is sufficient, this happens.
- dead = 0
- var/oldPlantName
- if(myseed) // In case there's nothing in the tray beforehand
- oldPlantName = myseed.plantname
- qdel(myseed)
- myseed = null
- else
- oldPlantName = "empty tray"
- switch(rand(1,18)) // randomly pick predominative weed
- if(16 to 18)
- myseed = new /obj/item/seeds/reishi(src)
- if(14 to 15)
- myseed = new /obj/item/seeds/nettle(src)
- if(12 to 13)
- myseed = new /obj/item/seeds/harebell(src)
- if(10 to 11)
- myseed = new /obj/item/seeds/amanita(src)
- if(8 to 9)
- myseed = new /obj/item/seeds/chanter(src)
- if(6 to 7)
- myseed = new /obj/item/seeds/tower(src)
- if(4 to 5)
- myseed = new /obj/item/seeds/plump(src)
- else
- myseed = new /obj/item/seeds/starthistle(src)
- age = 0
- plant_health = myseed.endurance
- lastcycle = world.time
- harvest = 0
- weedlevel = 0 // Reset
- pestlevel = 0 // Reset
- update_icon()
- visible_message("The [oldPlantName] is overtaken by some [myseed.plantname]!")
-
-
-/obj/machinery/hydroponics/proc/mutate(lifemut = 2, endmut = 5, productmut = 1, yieldmut = 2, potmut = 25, wrmut = 2, wcmut = 5, traitmut = 0) // Mutates the current seed
- if(!myseed)
- return
- myseed.mutate(lifemut, endmut, productmut, yieldmut, potmut, wrmut, wcmut, traitmut)
-
-/obj/machinery/hydroponics/proc/hardmutate()
- mutate(4, 10, 2, 4, 50, 4, 10, 3)
-
-
-/obj/machinery/hydroponics/proc/mutatespecie() // Mutagent produced a new plant!
- if(!myseed || dead)
- return
-
- var/oldPlantName = myseed.plantname
- if(myseed.mutatelist.len > 0)
- var/mutantseed = pick(myseed.mutatelist)
- qdel(myseed)
- myseed = null
- myseed = new mutantseed
- else
- return
-
- hardmutate()
- age = 0
- plant_health = myseed.endurance
- lastcycle = world.time
- harvest = 0
- weedlevel = 0 // Reset
-
- sleep(5) // Wait a while
- update_icon()
- visible_message("[oldPlantName] suddenly mutates into [myseed.plantname]!")
-
-
-/obj/machinery/hydroponics/proc/mutateweed() // If the weeds gets the mutagent instead. Mind you, this pretty much destroys the old plant
- if( weedlevel > 5 )
- if(myseed)
- qdel(myseed)
- myseed = null
- var/newWeed = pick(/obj/item/seeds/liberty, /obj/item/seeds/angel, /obj/item/seeds/nettle/death, /obj/item/seeds/kudzu)
- myseed = new newWeed
- dead = 0
- hardmutate()
- age = 0
- plant_health = myseed.endurance
- lastcycle = world.time
- harvest = 0
- weedlevel = 0 // Reset
-
- sleep(5) // Wait a while
- update_icon()
- visible_message("The mutated weeds in [src] spawn some [myseed.plantname]!")
- else
- to_chat(usr, "The few weeds in [src] seem to react, but only for a moment...")
-
-
-/obj/machinery/hydroponics/proc/plantdies() // OH NOES!!!!! I put this all in one function to make things easier
- plant_health = 0
- harvest = 0
- pestlevel = 0 // Pests die
- if(!dead)
- update_icon()
- dead = 1
-
-
-
-/obj/machinery/hydroponics/proc/mutatepest(mob/user)
- if(pestlevel > 5)
- message_admins("[ADMIN_LOOKUPFLW(user)] caused spiderling pests to spawn in a hydro tray")
- log_game("[key_name(user)] caused spiderling pests to spawn in a hydro tray")
- visible_message("The pests seem to behave oddly...")
- spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, src, 3, FALSE)
- else
- to_chat(user, "The pests seem to behave oddly, but quickly settle down...")
-
-/obj/machinery/hydroponics/proc/applyChemicals(datum/reagents/S, mob/user)
- if(myseed)
- myseed.on_chem_reaction(S) //In case seeds have some special interactions with special chems, currently only used by vines
-
- // Requires 5 mutagen to possibly change species.// Poor man's mutagen.
- if(S.has_reagent("mutagen", 5) || S.has_reagent("radium", 10) || S.has_reagent("uranium", 10))
- switch(rand(100))
- if(91 to 100)
- adjustHealth(-10)
- to_chat(user, "The plant shrivels and burns.")
- if(81 to 90)
- mutatespecie()
- if(66 to 80)
- hardmutate()
- if(41 to 65)
- mutate()
- if(21 to 41)
- to_chat(user, "The plants don't seem to react...")
- if(11 to 20)
- mutateweed()
- if(1 to 10)
- mutatepest(user)
- else
- to_chat(user, "Nothing happens...")
-
- // 2 or 1 units is enough to change the yield and other stats.// Can change the yield and other stats, but requires more than mutagen
- else if(S.has_reagent("mutagen", 2) || S.has_reagent("radium", 5) || S.has_reagent("uranium", 5))
- hardmutate()
- else if(S.has_reagent("mutagen", 1) || S.has_reagent("radium", 2) || S.has_reagent("uranium", 2))
- mutate()
-
- // After handling the mutating, we now handle the damage from adding crude radioactives...
- if(S.has_reagent("uranium", 1))
- adjustHealth(-round(S.get_reagent_amount("uranium") * 1))
- adjustToxic(round(S.get_reagent_amount("uranium") * 2))
- if(S.has_reagent("radium", 1))
- adjustHealth(-round(S.get_reagent_amount("radium") * 1))
- adjustToxic(round(S.get_reagent_amount("radium") * 3)) // Radium is harsher (OOC: also easier to produce)
-
- // Nutriments
- if(S.has_reagent("eznutriment", 1))
- yieldmod = 1
- mutmod = 1
- adjustNutri(round(S.get_reagent_amount("eznutriment") * 1))
-
- if(S.has_reagent("left4zednutriment", 1))
- yieldmod = 0
- mutmod = 2
- adjustNutri(round(S.get_reagent_amount("left4zednutriment") * 1))
-
- if(S.has_reagent("robustharvestnutriment", 1))
- yieldmod = 1.3
- mutmod = 0
- adjustNutri(round(S.get_reagent_amount("robustharvestnutriment") *1 ))
-
- // Ambrosia Gaia produces earthsblood.
- if(S.has_reagent("earthsblood"))
- self_sufficiency_progress += S.get_reagent_amount("earthsblood")
- if(self_sufficiency_progress >= self_sufficiency_req)
- become_self_sufficient()
- else if(!self_sustaining)
- to_chat(user, "[src] warms as it might on a spring day under a genuine Sun.")
-
- // Antitoxin binds shit pretty well. So the tox goes significantly down
- if(S.has_reagent("charcoal", 1))
- adjustToxic(-round(S.get_reagent_amount("charcoal") * 2))
-
- // NIGGA, YOU JUST WENT ON FULL RETARD.
- if(S.has_reagent("toxin", 1))
- adjustToxic(round(S.get_reagent_amount("toxin") * 2))
-
- // Milk is good for humans, but bad for plants. The sugars canot be used by plants, and the milk fat fucks up growth. Not shrooms though. I can't deal with this now...
- if(S.has_reagent("milk", 1))
- adjustNutri(round(S.get_reagent_amount("milk") * 0.1))
- adjustWater(round(S.get_reagent_amount("milk") * 0.9))
-
- // Beer is a chemical composition of alcohol and various other things. It's a shitty nutrient but hey, it's still one. Also alcohol is bad, mmmkay?
- if(S.has_reagent("beer", 1))
- adjustHealth(-round(S.get_reagent_amount("beer") * 0.05))
- adjustNutri(round(S.get_reagent_amount("beer") * 0.25))
- adjustWater(round(S.get_reagent_amount("beer") * 0.7))
-
- // You're an idiot for thinking that one of the most corrosive and deadly gasses would be beneficial
- if(S.has_reagent("fluorine", 1))
- adjustHealth(-round(S.get_reagent_amount("fluorine") * 2))
- adjustToxic(round(S.get_reagent_amount("fluorine") * 2.5))
- adjustWater(-round(S.get_reagent_amount("fluorine") * 0.5))
- adjustWeeds(-rand(1,4))
-
- // You're an idiot for thinking that one of the most corrosive and deadly gasses would be beneficial
- if(S.has_reagent("chlorine", 1))
- adjustHealth(-round(S.get_reagent_amount("chlorine") * 1))
- adjustToxic(round(S.get_reagent_amount("chlorine") * 1.5))
- adjustWater(-round(S.get_reagent_amount("chlorine") * 0.5))
- adjustWeeds(-rand(1,3))
-
- // White Phosphorous + water -> phosphoric acid. That's not a good thing really.
- // Phosphoric salts are beneficial though. And even if the plant suffers, in the long run the tray gets some nutrients. The benefit isn't worth that much.
- if(S.has_reagent("phosphorus", 1))
- adjustHealth(-round(S.get_reagent_amount("phosphorus") * 0.75))
- adjustNutri(round(S.get_reagent_amount("phosphorus") * 0.1))
- adjustWater(-round(S.get_reagent_amount("phosphorus") * 0.5))
- adjustWeeds(-rand(1,2))
-
- // Plants should not have sugar, they can't use it and it prevents them getting water/ nutients, it is good for mold though...
- if(S.has_reagent("sugar", 1))
- adjustWeeds(rand(1,2))
- adjustPests(rand(1,2))
- adjustNutri(round(S.get_reagent_amount("sugar") * 0.1))
-
- // It is water!
- if(S.has_reagent("water", 1))
- adjustWater(round(S.get_reagent_amount("water") * 1))
-
- // Holy water. Mostly the same as water, it also heals the plant a little with the power of the spirits~
- if(S.has_reagent("holywater", 1))
- adjustWater(round(S.get_reagent_amount("holywater") * 1))
- adjustHealth(round(S.get_reagent_amount("holywater") * 0.1))
-
- // A variety of nutrients are dissolved in club soda, without sugar.
- // These nutrients include carbon, oxygen, hydrogen, phosphorous, potassium, sulfur and sodium, all of which are needed for healthy plant growth.
- if(S.has_reagent("sodawater", 1))
- adjustWater(round(S.get_reagent_amount("sodawater") * 1))
- adjustHealth(round(S.get_reagent_amount("sodawater") * 0.1))
- adjustNutri(round(S.get_reagent_amount("sodawater") * 0.1))
-
- // Man, you guys are retards
- if(S.has_reagent("sacid", 1))
- adjustHealth(-round(S.get_reagent_amount("sacid") * 1))
- adjustToxic(round(S.get_reagent_amount("sacid") * 1.5))
- adjustWeeds(-rand(1,2))
-
- // SERIOUSLY
- if(S.has_reagent("facid", 1))
- adjustHealth(-round(S.get_reagent_amount("facid") * 2))
- adjustToxic(round(S.get_reagent_amount("facid") * 3))
- adjustWeeds(-rand(1,4))
-
- // Plant-B-Gone is just as bad
- if(S.has_reagent("plantbgone", 1))
- adjustHealth(-round(S.get_reagent_amount("plantbgone") * 5))
- adjustToxic(round(S.get_reagent_amount("plantbgone") * 6))
- adjustWeeds(-rand(4,8))
-
- // why, just why
- if(S.has_reagent("napalm", 1))
- if(!(myseed.resistance_flags & FIRE_PROOF))
- adjustHealth(-round(S.get_reagent_amount("napalm") * 6))
- adjustToxic(round(S.get_reagent_amount("napalm") * 7))
- adjustWeeds(-rand(5,9))
-
- //Weed Spray
- if(S.has_reagent("weedkiller", 1))
- adjustToxic(round(S.get_reagent_amount("weedkiller") * 0.5))
- //old toxicity was 4, each spray is default 10 (minimal of 5) so 5 and 2.5 are the new ammounts
- adjustWeeds(-rand(1,2))
-
- //Pest Spray
- if(S.has_reagent("pestkiller", 1))
- adjustToxic(round(S.get_reagent_amount("pestkiller") * 0.5))
- adjustPests(-rand(1,2))
-
- // Healing
- if(S.has_reagent("cryoxadone", 1))
- adjustHealth(round(S.get_reagent_amount("cryoxadone") * 3))
- adjustToxic(-round(S.get_reagent_amount("cryoxadone") * 3))
-
- // Ammonia is bad ass.
- if(S.has_reagent("ammonia", 1))
- adjustHealth(round(S.get_reagent_amount("ammonia") * 0.5))
- adjustNutri(round(S.get_reagent_amount("ammonia") * 1))
- if(myseed)
- myseed.adjust_yield(round(S.get_reagent_amount("ammonia") * 0.01))
-
- // Saltpetre is used for gardening IRL, to simplify highly, it speeds up growth and strengthens plants
- if(S.has_reagent("saltpetre", 1))
- var/salt = S.get_reagent_amount("saltpetre")
- adjustHealth(round(salt * 0.25))
- if (myseed)
- myseed.adjust_production(-round(salt/100)-prob(salt%100))
- myseed.adjust_potency(round(salt*0.5))
- // Ash is also used IRL in gardening, as a fertilizer enhancer and weed killer
- if(S.has_reagent("ash", 1))
- adjustHealth(round(S.get_reagent_amount("ash") * 0.25))
- adjustNutri(round(S.get_reagent_amount("ash") * 0.5))
- adjustWeeds(-1)
-
- // This is more bad ass, and pests get hurt by the corrosive nature of it, not the plant.
- if(S.has_reagent("diethylamine", 1))
- adjustHealth(round(S.get_reagent_amount("diethylamine") * 1))
- adjustNutri(round(S.get_reagent_amount("diethylamine") * 2))
- if(myseed)
- myseed.adjust_yield(round(S.get_reagent_amount("diethylamine") * 0.02))
- adjustPests(-rand(1,2))
-
- // Compost, effectively
- if(S.has_reagent("nutriment", 1))
- adjustHealth(round(S.get_reagent_amount("nutriment") * 0.5))
- adjustNutri(round(S.get_reagent_amount("nutriment") * 1))
-
- // Compost for EVERYTHING
- if(S.has_reagent("virusfood", 1))
- adjustNutri(round(S.get_reagent_amount("virusfood") * 0.5))
- adjustHealth(-round(S.get_reagent_amount("virusfood") * 0.5))
-
- // FEED ME
- if(S.has_reagent("blood", 1))
- adjustNutri(round(S.get_reagent_amount("blood") * 1))
- adjustPests(rand(2,4))
-
- // FEED ME SEYMOUR
- if(S.has_reagent("strangereagent", 1))
- spawnplant()
-
- // The best stuff there is. For testing/debugging.
- if(S.has_reagent("adminordrazine", 1))
- adjustWater(round(S.get_reagent_amount("adminordrazine") * 1))
- adjustHealth(round(S.get_reagent_amount("adminordrazine") * 1))
- adjustNutri(round(S.get_reagent_amount("adminordrazine") * 1))
- adjustPests(-rand(1,5))
- adjustWeeds(-rand(1,5))
- if(S.has_reagent("adminordrazine", 5))
- switch(rand(100))
- if(66 to 100)
- mutatespecie()
- if(33 to 65)
- mutateweed()
- if(1 to 32)
- mutatepest(user)
- else
- to_chat(user, "Nothing happens...")
-
-/obj/machinery/hydroponics/attackby(obj/item/O, mob/user, params)
- //Called when mob user "attacks" it with object O
- if(istype(O, /obj/item/reagent_containers) ) // Syringe stuff (and other reagent containers now too)
- var/obj/item/reagent_containers/reagent_source = O
-
- if(istype(reagent_source, /obj/item/reagent_containers/syringe))
- var/obj/item/reagent_containers/syringe/syr = reagent_source
- if(syr.mode != 1)
- to_chat(user, "You can't get any extract out of this plant." )
- return
-
- if(!reagent_source.reagents.total_volume)
- to_chat(user, "[reagent_source] is empty.")
- return 1
-
- var/list/trays = list(src)//makes the list just this in cases of syringes and compost etc
- var/target = myseed ? myseed.plantname : src
- var/visi_msg = ""
- var/irrigate = 0 //How am I supposed to irrigate pill contents?
- var/transfer_amount
-
- if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill))
- visi_msg="[user] composts [reagent_source], spreading it through [target]"
- transfer_amount = reagent_source.reagents.total_volume
- else
- transfer_amount = reagent_source.amount_per_transfer_from_this
- if(istype(reagent_source, /obj/item/reagent_containers/syringe/))
- var/obj/item/reagent_containers/syringe/syr = reagent_source
- visi_msg="[user] injects [target] with [syr]"
- if(syr.reagents.total_volume <= syr.amount_per_transfer_from_this)
- syr.mode = 0
- else if(istype(reagent_source, /obj/item/reagent_containers/spray/))
- visi_msg="[user] sprays [target] with [reagent_source]"
- playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6)
- irrigate = 1
- else if(transfer_amount) // Droppers, cans, beakers, what have you.
- visi_msg="[user] uses [reagent_source] on [target]"
- irrigate = 1
- // Beakers, bottles, buckets, etc.
- if(reagent_source.is_drainable())
- playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
-
- if(irrigate && transfer_amount > 30 && reagent_source.reagents.total_volume >= 30 && using_irrigation)
- trays = FindConnected()
- if (trays.len > 1)
- visi_msg += ", setting off the irrigation system"
-
- if(visi_msg)
- visible_message("[visi_msg].")
-
- var/split = round(transfer_amount/trays.len)
-
- for(var/obj/machinery/hydroponics/H in trays)
- //cause I don't want to feel like im juggling 15 tamagotchis and I can get to my real work of ripping flooring apart in hopes of validating my life choices of becoming a space-gardener
-
- var/datum/reagents/S = new /datum/reagents() //This is a strange way, but I don't know of a better one so I can't fix it at the moment...
- S.my_atom = H
-
- reagent_source.reagents.trans_to(S,split)
- if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill))
- qdel(reagent_source)
-
- H.applyChemicals(S, user)
-
- S.clear_reagents()
- qdel(S)
- H.update_icon()
- if(reagent_source) // If the source wasn't composted and destroyed
- reagent_source.update_icon()
- return 1
-
- else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/sample))
- if(!myseed)
- if(istype(O, /obj/item/seeds/kudzu))
- investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)]","kudzu")
- if(!user.transferItemToLoc(O, src))
- return
- to_chat(user, "You plant [O].")
- dead = 0
- myseed = O
- age = 1
- plant_health = myseed.endurance
- lastcycle = world.time
- update_icon()
- else
- to_chat(user, "[src] already has seeds in it!")
-
- else if(istype(O, /obj/item/plant_analyzer))
- if(myseed)
- to_chat(user, "*** [myseed.plantname] ***" )
- to_chat(user, "- Plant Age: [age]")
- var/list/text_string = myseed.get_analyzer_text()
- if(text_string)
- to_chat(user, text_string)
- else
- to_chat(user, "No plant found.")
- to_chat(user, "- Weed level: [weedlevel] / 10")
- to_chat(user, "- Pest level: [pestlevel] / 10")
- to_chat(user, "- Toxicity level: [toxic] / 100")
- to_chat(user, "- Water level: [waterlevel] / [maxwater]")
- to_chat(user, "- Nutrition level: [nutrilevel] / [maxnutri]")
- to_chat(user, "")
-
- else if(istype(O, /obj/item/cultivator))
- if(weedlevel > 0)
- user.visible_message("[user] uproots the weeds.", "You remove the weeds from [src].")
- weedlevel = 0
- update_icon()
- else
- to_chat(user, "This plot is completely devoid of weeds! It doesn't need uprooting.")
-
- else if(istype(O, /obj/item/storage/bag/plants))
- attack_hand(user)
- for(var/obj/item/reagent_containers/food/snacks/grown/G in locate(user.x,user.y,user.z))
- SEND_SIGNAL(O, COMSIG_TRY_STORAGE_INSERT, G, user, TRUE)
-
- else if(default_unfasten_wrench(user, O))
- return
-
- else if(istype(O, /obj/item/wirecutters) && unwrenchable)
- if (!anchored)
- to_chat(user, "Anchor the tray first!")
- return
- using_irrigation = !using_irrigation
- O.play_tool_sound(src)
- user.visible_message("[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.", \
- "You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.")
- for(var/obj/machinery/hydroponics/h in range(1,src))
- h.update_icon()
-
- else if(istype(O, /obj/item/shovel/spade))
- if(!myseed && !weedlevel)
- to_chat(user, "[src] doesn't have any plants or weeds!")
- return
- user.visible_message("[user] starts digging out [src]'s plants...",
- "You start digging out [src]'s plants...")
- if(O.use_tool(src, user, 50, volume=50) || (!myseed && !weedlevel))
- user.visible_message("[user] digs out the plants in [src]!", "You dig out all of [src]'s plants!")
- if(myseed) //Could be that they're just using it as a de-weeder
- age = 0
- plant_health = 0
- if(harvest)
- harvest = FALSE //To make sure they can't just put in another seed and insta-harvest it
- qdel(myseed)
- myseed = null
- weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
- update_icon()
-
- else
- return ..()
-
-/obj/machinery/hydroponics/can_be_unfasten_wrench(mob/user, silent)
- if (!unwrenchable) // case also covered by NODECONSTRUCT checks in default_unfasten_wrench
- return CANT_UNFASTEN
-
- if (using_irrigation)
- if (!silent)
- to_chat(user, "Disconnect the hoses first!")
- return FAILED_UNFASTEN
-
- return ..()
-
-/obj/machinery/hydroponics/attack_hand(mob/user)
- . = ..()
- if(.)
- return
- if(issilicon(user)) //How does AI know what plant is?
- return
- if(harvest)
- return myseed.harvest(user)
-
- else if(dead)
- dead = 0
- to_chat(user, "You remove the dead plant from [src].")
- qdel(myseed)
- myseed = null
- update_icon()
- else
- if(user)
- examine(user)
-
-/obj/machinery/hydroponics/proc/update_tray(mob/user)
- harvest = 0
- lastproduce = age
- if(istype(myseed, /obj/item/seeds/replicapod))
- to_chat(user, "You harvest from the [myseed.plantname].")
- else if(myseed.getYield() <= 0)
- to_chat(user, "You fail to harvest anything useful!")
- else
- to_chat(user, "You harvest [myseed.getYield()] items from the [myseed.plantname].")
- if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest))
- qdel(myseed)
- myseed = null
- dead = 0
- update_icon()
-
-/// Tray Setters - The following procs adjust the tray or plants variables, and make sure that the stat doesn't go out of bounds.///
-/obj/machinery/hydroponics/proc/adjustNutri(adjustamt)
- nutrilevel = CLAMP(nutrilevel + adjustamt, 0, maxnutri)
-
-/obj/machinery/hydroponics/proc/adjustWater(adjustamt)
- waterlevel = CLAMP(waterlevel + adjustamt, 0, maxwater)
-
- if(adjustamt>0)
- adjustToxic(-round(adjustamt/4))//Toxicity dilutation code. The more water you put in, the lesser the toxin concentration.
-
-/obj/machinery/hydroponics/proc/adjustHealth(adjustamt)
- if(myseed && !dead)
- plant_health = CLAMP(plant_health + adjustamt, 0, myseed.endurance)
-
-/obj/machinery/hydroponics/proc/adjustToxic(adjustamt)
- toxic = CLAMP(toxic + adjustamt, 0, 100)
-
-/obj/machinery/hydroponics/proc/adjustPests(adjustamt)
- pestlevel = CLAMP(pestlevel + adjustamt, 0, 10)
-
-/obj/machinery/hydroponics/proc/adjustWeeds(adjustamt)
- weedlevel = CLAMP(weedlevel + adjustamt, 0, 10)
-
-/obj/machinery/hydroponics/proc/spawnplant() // why would you put strange reagent in a hydro tray you monster I bet you also feed them blood
- var/list/livingplants = list(/mob/living/simple_animal/hostile/tree, /mob/living/simple_animal/hostile/killertomato)
- var/chosen = pick(livingplants)
- var/mob/living/simple_animal/hostile/C = new chosen
- C.faction = list("plants")
-
-/obj/machinery/hydroponics/proc/become_self_sufficient() // Ambrosia Gaia effect
- visible_message("[src] begins to glow with a beautiful light!")
- self_sustaining = TRUE
- update_icon()
-
-///////////////////////////////////////////////////////////////////////////////
-/obj/machinery/hydroponics/soil //Not actually hydroponics at all! Honk!
- name = "soil"
- desc = "A patch of dirt."
- icon = 'icons/obj/hydroponics/equipment.dmi'
- icon_state = "soil"
- circuit = null
- density = FALSE
- use_power = NO_POWER_USE
- flags_1 = NODECONSTRUCT_1
- unwrenchable = FALSE
- var/buildstacktype = /obj/item/stack/sheet/mineral/sandstone
- var/buildstackamount = 3
-
-/obj/machinery/hydroponics/soil/update_icon_hoses()
- return // Has no hoses
-
-/obj/machinery/hydroponics/soil/update_icon_lights()
- return // Has no lights
-
-/obj/machinery/hydroponics/soil/attackby(obj/item/O, mob/user, params)
- if(istype(O, /obj/item/shovel) && !istype(O, /obj/item/shovel/spade)) //Doesn't include spades because of uprooting plants
- to_chat(user, "You clear up [src]!")
- new buildstacktype(loc,buildstackamount)
- qdel(src)
- else
- return ..()
+/obj/machinery/hydroponics
+ name = "hydroponics tray"
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ icon_state = "hydrotray"
+ density = TRUE
+ pixel_z = 8
+ obj_flags = CAN_BE_HIT | UNIQUE_RENAME
+ circuit = /obj/item/circuitboard/machine/hydroponics
+ var/waterlevel = 100 //The amount of water in the tray (max 100)
+ var/maxwater = 100 //The maximum amount of water in the tray
+ var/nutrilevel = 10 //The amount of nutrient in the tray (max 10)
+ var/maxnutri = 10 //The maximum nutrient of water in the tray
+ var/pestlevel = 0 //The amount of pests in the tray (max 10)
+ var/weedlevel = 0 //The amount of weeds in the tray (max 10)
+ var/yieldmod = 1 //Nutriment's effect on yield
+ var/mutmod = 1 //Nutriment's effect on mutations
+ var/toxic = 0 //Toxicity in the tray?
+ var/age = 0 //Current age
+ var/dead = 0 //Is it dead?
+ var/plant_health //Its health
+ var/lastproduce = 0 //Last time it was harvested
+ var/lastcycle = 0 //Used for timing of cycles.
+ var/cycledelay = 200 //About 10 seconds / cycle
+ var/harvest = 0 //Ready to harvest?
+ var/obj/item/seeds/myseed = null //The currently planted seed
+ var/rating = 1
+ var/unwrenchable = 1
+ var/recent_bee_visit = FALSE //Have we been visited by a bee recently, so bees dont overpollinate one plant
+ var/using_irrigation = FALSE //If the tray is connected to other trays via irrigation hoses
+ var/self_sufficiency_req = 20 //Required total dose to make a self-sufficient hydro tray. 1:1 with earthsblood.
+ var/self_sufficiency_progress = 0
+ var/self_sustaining = FALSE //If the tray generates nutrients and water on its own
+
+
+/obj/machinery/hydroponics/constructable
+ name = "hydroponics tray"
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ icon_state = "hydrotray3"
+
+/obj/machinery/hydroponics/constructable/RefreshParts()
+ var/tmp_capacity = 0
+ for (var/obj/item/stock_parts/matter_bin/M in component_parts)
+ tmp_capacity += M.rating
+ for (var/obj/item/stock_parts/manipulator/M in component_parts)
+ rating = M.rating
+ maxwater = tmp_capacity * 50 // Up to 300
+ maxnutri = tmp_capacity * 5 // Up to 30
+
+/obj/machinery/hydroponics/Destroy()
+ if(myseed)
+ qdel(myseed)
+ myseed = null
+ return ..()
+
+/obj/machinery/hydroponics/constructable/attackby(obj/item/I, mob/user, params)
+ if (user.a_intent != INTENT_HARM)
+ // handle opening the panel
+ if(default_deconstruction_screwdriver(user, icon_state, icon_state, I))
+ return
+
+ // handle deconstructing the machine, if permissible
+ if (I.tool_behaviour == TOOL_CROWBAR && using_irrigation)
+ to_chat(user, "Disconnect the hoses first!")
+ return
+ else if(default_deconstruction_crowbar(I))
+ return
+
+ return ..()
+
+/obj/machinery/hydroponics/proc/FindConnected()
+ var/list/connected = list()
+ var/list/processing_atoms = list(src)
+
+ while(processing_atoms.len)
+ var/atom/a = processing_atoms[1]
+ for(var/step_dir in GLOB.cardinals)
+ var/obj/machinery/hydroponics/h = locate() in get_step(a, step_dir)
+ // Soil plots aren't dense
+ if(h && h.using_irrigation && h.density && !(h in connected) && !(h in processing_atoms))
+ processing_atoms += h
+
+ processing_atoms -= a
+ connected += a
+
+ return connected
+
+
+/obj/machinery/hydroponics/bullet_act(obj/item/projectile/Proj) //Works with the Somatoray to modify plant variables.
+ if(!myseed)
+ return ..()
+ if(istype(Proj , /obj/item/projectile/energy/floramut))
+ mutate()
+ else if(istype(Proj , /obj/item/projectile/energy/florayield))
+ return myseed.bullet_act(Proj)
+ else
+ return ..()
+
+/obj/machinery/hydroponics/process()
+ var/needs_update = 0 // Checks if the icon needs updating so we don't redraw empty trays every time
+
+ if(myseed && (myseed.loc != src))
+ myseed.forceMove(src)
+
+ if(self_sustaining)
+ adjustNutri(1)
+ adjustWater(rand(3,5))
+ adjustWeeds(-2)
+ adjustPests(-2)
+ adjustToxic(-2)
+
+ if(world.time > (lastcycle + cycledelay))
+ lastcycle = world.time
+ if(myseed && !dead)
+ // Advance age
+ age++
+ if(age < myseed.maturation)
+ lastproduce = age
+
+ needs_update = 1
+
+//Nutrients//////////////////////////////////////////////////////////////
+ // Nutrients deplete slowly
+ if(prob(50))
+ adjustNutri(-1 / rating)
+
+ // Lack of nutrients hurts non-weeds
+ if(nutrilevel <= 0 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
+ adjustHealth(-rand(1,3))
+
+//Photosynthesis/////////////////////////////////////////////////////////
+ // Lack of light hurts non-mushrooms
+ if(isturf(loc))
+ var/turf/currentTurf = loc
+ var/lightAmt = currentTurf.get_lumcount()
+ if(myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
+ if(lightAmt < 0.2)
+ adjustHealth(-1 / rating)
+ else // Non-mushroom
+ if(lightAmt < 0.4)
+ adjustHealth(-2 / rating)
+
+//Water//////////////////////////////////////////////////////////////////
+ // Drink random amount of water
+ adjustWater(-rand(1,6) / rating)
+
+ // If the plant is dry, it loses health pretty fast, unless mushroom
+ if(waterlevel <= 10 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
+ adjustHealth(-rand(0,1) / rating)
+ if(waterlevel <= 0)
+ adjustHealth(-rand(0,2) / rating)
+
+ // Sufficient water level and nutrient level = plant healthy but also spawns weeds
+ else if(waterlevel > 10 && nutrilevel > 0)
+ adjustHealth(rand(1,2) / rating)
+ if(myseed && prob(myseed.weed_chance))
+ adjustWeeds(myseed.weed_rate)
+ else if(prob(5)) //5 percent chance the weed population will increase
+ adjustWeeds(1 / rating)
+
+//Toxins/////////////////////////////////////////////////////////////////
+
+ // Too much toxins cause harm, but when the plant drinks the contaiminated water, the toxins disappear slowly
+ if(toxic >= 40 && toxic < 80)
+ adjustHealth(-1 / rating)
+ adjustToxic(-rand(1,10) / rating)
+ else if(toxic >= 80) // I don't think it ever gets here tbh unless above is commented out
+ adjustHealth(-3)
+ adjustToxic(-rand(1,10) / rating)
+
+//Pests & Weeds//////////////////////////////////////////////////////////
+
+ if(pestlevel >= 8)
+ if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/carnivory))
+ adjustHealth(-2 / rating)
+
+ else
+ adjustHealth(2 / rating)
+ adjustPests(-1 / rating)
+
+ else if(pestlevel >= 4)
+ if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/carnivory))
+ adjustHealth(-1 / rating)
+
+ else
+ adjustHealth(1 / rating)
+ if(prob(50))
+ adjustPests(-1 / rating)
+
+ else if(pestlevel < 4 && myseed.get_gene(/datum/plant_gene/trait/plant_type/carnivory))
+ adjustHealth(-2 / rating)
+ if(prob(5))
+ adjustPests(-1 / rating)
+
+ // If it's a weed, it doesn't stunt the growth
+ if(weedlevel >= 5 && !myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
+ adjustHealth(-1 / rating)
+
+//Health & Age///////////////////////////////////////////////////////////
+
+ // Plant dies if plant_health <= 0
+ if(plant_health <= 0)
+ plantdies()
+ adjustWeeds(1 / rating) // Weeds flourish
+
+ // If the plant is too old, lose health fast
+ if(age > myseed.lifespan)
+ adjustHealth(-rand(1,5) / rating)
+
+ // Harvest code
+ if(age > myseed.production && (age - lastproduce) > myseed.production && (!harvest && !dead))
+ nutrimentMutation()
+ if(myseed && myseed.yield != -1) // Unharvestable shouldn't be harvested
+ harvest = 1
+ else
+ lastproduce = age
+ if(prob(5)) // On each tick, there's a 5 percent chance the pest population will increase
+ adjustPests(1 / rating)
+ else
+ if(waterlevel > 10 && nutrilevel > 0 && prob(10)) // If there's no plant, the percentage chance is 10%
+ adjustWeeds(1 / rating)
+
+ // Weeeeeeeeeeeeeeedddssss
+ if(weedlevel >= 10 && prob(50)) // At this point the plant is kind of fucked. Weeds can overtake the plant spot.
+ if(myseed)
+ if(!myseed.get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !myseed.get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism)) // If a normal plant
+ weedinvasion()
+ else
+ weedinvasion() // Weed invasion into empty tray
+ needs_update = 1
+ if (needs_update)
+ update_icon()
+
+ if(myseed && prob(5 * (11-myseed.production)))
+ for(var/g in myseed.genes)
+ if(istype(g, /datum/plant_gene/trait))
+ var/datum/plant_gene/trait/selectedtrait = g
+ selectedtrait.on_grow(src)
+ return
+
+/obj/machinery/hydroponics/proc/nutrimentMutation()
+ if (mutmod == 0)
+ return
+ if (mutmod == 1)
+ if(prob(80)) //80%
+ mutate()
+ else if(prob(75)) //15%
+ hardmutate()
+ return
+ if (mutmod == 2)
+ if(prob(50)) //50%
+ mutate()
+ else if(prob(50)) //25%
+ hardmutate()
+ else if(prob(50)) //12.5%
+ mutatespecie()
+ return
+ return
+
+/obj/machinery/hydroponics/update_icon()
+ //Refreshes the icon and sets the luminosity
+ cut_overlays()
+
+ if(self_sustaining)
+ if(istype(src, /obj/machinery/hydroponics/soil))
+ add_atom_colour(rgb(255, 175, 0), FIXED_COLOUR_PRIORITY)
+ else
+ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "gaia_blessing"))
+ set_light(3)
+
+ update_icon_hoses()
+
+ if(myseed)
+ update_icon_plant()
+ update_icon_lights()
+
+ if(!self_sustaining)
+ if(myseed && myseed.get_gene(/datum/plant_gene/trait/glow))
+ var/datum/plant_gene/trait/glow/G = myseed.get_gene(/datum/plant_gene/trait/glow)
+ set_light(G.glow_range(myseed), G.glow_power(myseed), G.glow_color)
+ else
+ set_light(0)
+
+ return
+
+/obj/machinery/hydroponics/proc/update_icon_hoses()
+ var/n = 0
+ for(var/Dir in GLOB.cardinals)
+ var/obj/machinery/hydroponics/t = locate() in get_step(src,Dir)
+ if(t && t.using_irrigation && using_irrigation)
+ n += Dir
+
+ icon_state = "hoses-[n]"
+
+/obj/machinery/hydroponics/proc/update_icon_plant()
+ var/mutable_appearance/plant_overlay = mutable_appearance(myseed.growing_icon, layer = OBJ_LAYER + 0.01)
+ if(dead)
+ plant_overlay.icon_state = myseed.icon_dead
+ else if(harvest)
+ if(!myseed.icon_harvest)
+ plant_overlay.icon_state = "[myseed.icon_grow][myseed.growthstages]"
+ else
+ plant_overlay.icon_state = myseed.icon_harvest
+ else
+ var/t_growthstate = min(round((age / myseed.maturation) * myseed.growthstages), myseed.growthstages)
+ plant_overlay.icon_state = "[myseed.icon_grow][t_growthstate]"
+ add_overlay(plant_overlay)
+
+/obj/machinery/hydroponics/proc/update_icon_lights()
+ if(waterlevel <= 10)
+ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_lowwater3"))
+ if(nutrilevel <= 2)
+ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_lownutri3"))
+ if(plant_health <= (myseed.endurance / 2))
+ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_lowhealth3"))
+ if(weedlevel >= 5 || pestlevel >= 5 || toxic >= 40)
+ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_alert3"))
+ if(harvest)
+ add_overlay(mutable_appearance('icons/obj/hydroponics/equipment.dmi', "over_harvest3"))
+
+
+/obj/machinery/hydroponics/examine(user)
+ . = ..()
+ if(myseed)
+ . += "It has [myseed.plantname] planted."
+ if (dead)
+ . += "It's dead!"
+ else if (harvest)
+ . += "It's ready to harvest."
+ else if (plant_health <= (myseed.endurance / 2))
+ . += "It looks unhealthy."
+ else
+ . += "It's empty."
+
+ if(!self_sustaining)
+ . += "Water: [waterlevel]/[maxwater]."
+ . += "Nutrient: [nutrilevel]/[maxnutri]."
+ if(self_sufficiency_progress > 0)
+ var/percent_progress = round(self_sufficiency_progress * 100 / self_sufficiency_req)
+ . += "Treatment for self-sustenance are [percent_progress]% complete."
+ else
+ . += "It doesn't require any water or nutrients."
+
+ if(weedlevel >= 5)
+ . += "It's filled with weeds!"
+ if(pestlevel >= 5)
+ . += "It's filled with tiny worms!"
+
+/obj/machinery/hydroponics/proc/weedinvasion() // If a weed growth is sufficient, this happens.
+ dead = 0
+ var/oldPlantName
+ if(myseed) // In case there's nothing in the tray beforehand
+ oldPlantName = myseed.plantname
+ qdel(myseed)
+ myseed = null
+ else
+ oldPlantName = "empty tray"
+ switch(rand(1,18)) // randomly pick predominative weed
+ if(16 to 18)
+ myseed = new /obj/item/seeds/reishi(src)
+ if(14 to 15)
+ myseed = new /obj/item/seeds/nettle(src)
+ if(12 to 13)
+ myseed = new /obj/item/seeds/harebell(src)
+ if(10 to 11)
+ myseed = new /obj/item/seeds/amanita(src)
+ if(8 to 9)
+ myseed = new /obj/item/seeds/chanter(src)
+ if(6 to 7)
+ myseed = new /obj/item/seeds/tower(src)
+ if(4 to 5)
+ myseed = new /obj/item/seeds/plump(src)
+ else
+ myseed = new /obj/item/seeds/starthistle(src)
+ age = 0
+ plant_health = myseed.endurance
+ lastcycle = world.time
+ harvest = 0
+ weedlevel = 0 // Reset
+ pestlevel = 0 // Reset
+ update_icon()
+ visible_message("The [oldPlantName] is overtaken by some [myseed.plantname]!")
+
+
+/obj/machinery/hydroponics/proc/mutate(lifemut = 2, endmut = 5, productmut = 1, yieldmut = 2, potmut = 25, wrmut = 2, wcmut = 5, traitmut = 0) // Mutates the current seed
+ if(!myseed)
+ return
+ myseed.mutate(lifemut, endmut, productmut, yieldmut, potmut, wrmut, wcmut, traitmut)
+
+/obj/machinery/hydroponics/proc/hardmutate()
+ mutate(4, 10, 2, 4, 50, 4, 10, 3)
+
+
+/obj/machinery/hydroponics/proc/mutatespecie() // Mutagent produced a new plant!
+ if(!myseed || dead)
+ return
+
+ var/oldPlantName = myseed.plantname
+ if(myseed.mutatelist.len > 0)
+ var/mutantseed = pick(myseed.mutatelist)
+ qdel(myseed)
+ myseed = null
+ myseed = new mutantseed
+ else
+ return
+
+ hardmutate()
+ age = 0
+ plant_health = myseed.endurance
+ lastcycle = world.time
+ harvest = 0
+ weedlevel = 0 // Reset
+
+ sleep(5) // Wait a while
+ update_icon()
+ visible_message("[oldPlantName] suddenly mutates into [myseed.plantname]!")
+
+
+/obj/machinery/hydroponics/proc/mutateweed() // If the weeds gets the mutagent instead. Mind you, this pretty much destroys the old plant
+ if( weedlevel > 5 )
+ if(myseed)
+ qdel(myseed)
+ myseed = null
+ var/newWeed = pick(/obj/item/seeds/liberty, /obj/item/seeds/angel, /obj/item/seeds/nettle/death, /obj/item/seeds/kudzu)
+ myseed = new newWeed
+ dead = 0
+ hardmutate()
+ age = 0
+ plant_health = myseed.endurance
+ lastcycle = world.time
+ harvest = 0
+ weedlevel = 0 // Reset
+
+ sleep(5) // Wait a while
+ update_icon()
+ visible_message("The mutated weeds in [src] spawn some [myseed.plantname]!")
+ else
+ to_chat(usr, "The few weeds in [src] seem to react, but only for a moment...")
+
+
+/obj/machinery/hydroponics/proc/plantdies() // OH NOES!!!!! I put this all in one function to make things easier
+ plant_health = 0
+ harvest = 0
+ pestlevel = 0 // Pests die
+ if(!dead)
+ update_icon()
+ dead = 1
+
+
+
+/obj/machinery/hydroponics/proc/mutatepest(mob/user)
+ if(pestlevel > 5)
+ message_admins("[ADMIN_LOOKUPFLW(user)] caused spiderling pests to spawn in a hydro tray")
+ log_game("[key_name(user)] caused spiderling pests to spawn in a hydro tray")
+ visible_message("The pests seem to behave oddly...")
+ spawn_atom_to_turf(/obj/structure/spider/spiderling/hunter, src, 3, FALSE)
+ else
+ to_chat(user, "The pests seem to behave oddly, but quickly settle down...")
+
+/obj/machinery/hydroponics/proc/applyChemicals(datum/reagents/S, mob/user)
+ if(myseed)
+ myseed.on_chem_reaction(S) //In case seeds have some special interactions with special chems, currently only used by vines
+
+ // Requires 5 mutagen to possibly change species.// Poor man's mutagen.
+ if(S.has_reagent(/datum/reagent/toxin/mutagen, 5) || S.has_reagent(/datum/reagent/radium, 10) || S.has_reagent(/datum/reagent/uranium, 10))
+ switch(rand(100))
+ if(91 to 100)
+ adjustHealth(-10)
+ to_chat(user, "The plant shrivels and burns.")
+ if(81 to 90)
+ mutatespecie()
+ if(66 to 80)
+ hardmutate()
+ if(41 to 65)
+ mutate()
+ if(21 to 41)
+ to_chat(user, "The plants don't seem to react...")
+ if(11 to 20)
+ mutateweed()
+ if(1 to 10)
+ mutatepest(user)
+ else
+ to_chat(user, "Nothing happens...")
+
+ // 2 or 1 units is enough to change the yield and other stats.// Can change the yield and other stats, but requires more than mutagen
+ else if(S.has_reagent(/datum/reagent/toxin/mutagen, 2) || S.has_reagent(/datum/reagent/radium, 5) || S.has_reagent(/datum/reagent/uranium, 5))
+ hardmutate()
+ else if(S.has_reagent(/datum/reagent/toxin/mutagen, 1) || S.has_reagent(/datum/reagent/radium, 2) || S.has_reagent(/datum/reagent/uranium, 2))
+ mutate()
+
+ // After handling the mutating, we now handle the damage from adding crude radioactives...
+ if(S.has_reagent(/datum/reagent/uranium, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/uranium) * 1))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/uranium) * 2))
+ if(S.has_reagent(/datum/reagent/radium, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/radium) * 1))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/radium) * 3)) // Radium is harsher (OOC: also easier to produce)
+
+ // Nutriments
+ if(S.has_reagent(/datum/reagent/plantnutriment/eznutriment, 1))
+ yieldmod = 1
+ mutmod = 1
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/eznutriment) * 1))
+
+ if(S.has_reagent(/datum/reagent/plantnutriment/left4zednutriment, 1))
+ yieldmod = 0
+ mutmod = 2
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/left4zednutriment) * 1))
+
+ if(S.has_reagent(/datum/reagent/plantnutriment/robustharvestnutriment, 1))
+ yieldmod = 1.3
+ mutmod = 0
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/plantnutriment/robustharvestnutriment) *1 ))
+
+ // Ambrosia Gaia produces earthsblood.
+ if(S.has_reagent(/datum/reagent/medicine/earthsblood))
+ self_sufficiency_progress += S.get_reagent_amount(/datum/reagent/medicine/earthsblood)
+ if(self_sufficiency_progress >= self_sufficiency_req)
+ become_self_sufficient()
+ else if(!self_sustaining)
+ to_chat(user, "[src] warms as it might on a spring day under a genuine Sun.")
+
+ // Antitoxin binds shit pretty well. So the tox goes significantly down
+ if(S.has_reagent(/datum/reagent/medicine/charcoal, 1))
+ adjustToxic(-round(S.get_reagent_amount(/datum/reagent/medicine/charcoal) * 2))
+
+ // Toxins, not good for anything
+ if(S.has_reagent(/datum/reagent/toxin, 1))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin) * 2))
+
+ // Milk is good for humans, but bad for plants. The sugars canot be used by plants, and the milk fat fucks up growth. Not shrooms though. I can't deal with this now...
+ if(S.has_reagent(/datum/reagent/consumable/milk, 1))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/milk) * 0.1))
+ adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/milk) * 0.9))
+
+ // Beer is a chemical composition of alcohol and various other things. It's a shitty nutrient but hey, it's still one. Also alcohol is bad, mmmkay?
+ if(S.has_reagent(/datum/reagent/consumable/ethanol/beer, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.05))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.25))
+ adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/ethanol/beer) * 0.7))
+
+ // Fluorine one of the most corrosive and deadly gasses
+ if(S.has_reagent(/datum/reagent/fluorine, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/fluorine) * 2))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/fluorine) * 2.5))
+ adjustWater(-round(S.get_reagent_amount(/datum/reagent/fluorine) * 0.5))
+ adjustWeeds(-rand(1,4))
+
+ // Chlorine one of the most corrosive and deadly gasses
+ if(S.has_reagent(/datum/reagent/chlorine, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/chlorine) * 1))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/chlorine) * 1.5))
+ adjustWater(-round(S.get_reagent_amount(/datum/reagent/chlorine) * 0.5))
+ adjustWeeds(-rand(1,3))
+
+ // White Phosphorous + water -> phosphoric acid. That's not a good thing really.
+ // Phosphoric salts are beneficial though. And even if the plant suffers, in the long run the tray gets some nutrients. The benefit isn't worth that much.
+ if(S.has_reagent(/datum/reagent/phosphorus, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.75))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.1))
+ adjustWater(-round(S.get_reagent_amount(/datum/reagent/phosphorus) * 0.5))
+ adjustWeeds(-rand(1,2))
+
+ // Plants should not have sugar, they can't use it and it prevents them getting water/nutients, it is good for mold though...
+ if(S.has_reagent(/datum/reagent/consumable/sugar, 1))
+ adjustWeeds(rand(1,2))
+ adjustPests(rand(1,2))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/sugar) * 0.1))
+
+ // It is water!
+ if(S.has_reagent(/datum/reagent/water, 1))
+ adjustWater(round(S.get_reagent_amount(/datum/reagent/water) * 1))
+
+ // Holy water. Mostly the same as water, it also heals the plant a little with the power of the spirits~
+ if(S.has_reagent(/datum/reagent/water/holywater, 1))
+ adjustWater(round(S.get_reagent_amount(/datum/reagent/water/holywater) * 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/water/holywater) * 0.1))
+
+ // A variety of nutrients are dissolved in club soda, without sugar.
+ // These nutrients include carbon, oxygen, hydrogen, phosphorous, potassium, sulfur and sodium, all of which are needed for healthy plant growth.
+ if(S.has_reagent(/datum/reagent/consumable/sodawater, 1))
+ adjustWater(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 0.1))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/sodawater) * 0.1))
+
+ // Sulphuric Acid
+ if(S.has_reagent(/datum/reagent/toxin/acid, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/acid) * 1))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/acid) * 1.5))
+ adjustWeeds(-rand(1,2))
+
+ // Acid
+ if(S.has_reagent(/datum/reagent/toxin/acid/fluacid, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/acid/fluacid) * 2))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/acid/fluacid) * 3))
+ adjustWeeds(-rand(1,4))
+
+ // Plant-B-Gone is just as bad
+ if(S.has_reagent(/datum/reagent/toxin/plantbgone, 1))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone) * 5))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone) * 6))
+ adjustWeeds(-rand(4,8))
+
+ // Napalm, not known for being good for anything organic
+ if(S.has_reagent(/datum/reagent/napalm, 1))
+ if(!(myseed.resistance_flags & FIRE_PROOF))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/napalm) * 6))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/napalm) * 7))
+ adjustWeeds(-rand(5,9))
+
+ //Weed Spray
+ if(S.has_reagent(/datum/reagent/toxin/plantbgone/weedkiller, 1))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/plantbgone/weedkiller) * 0.5))
+ //old toxicity was 4, each spray is default 10 (minimal of 5) so 5 and 2.5 are the new ammounts
+ adjustWeeds(-rand(1,2))
+
+ //Pest Spray
+ if(S.has_reagent(/datum/reagent/toxin/pestkiller, 1))
+ adjustToxic(round(S.get_reagent_amount(/datum/reagent/toxin/pestkiller) * 0.5))
+ adjustPests(-rand(1,2))
+
+ // Healing
+ if(S.has_reagent(/datum/reagent/medicine/cryoxadone, 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/medicine/cryoxadone) * 3))
+ adjustToxic(-round(S.get_reagent_amount(/datum/reagent/medicine/cryoxadone) * 3))
+
+ // Ammonia is bad ass.
+ if(S.has_reagent(/datum/reagent/ammonia, 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/ammonia) * 0.5))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/ammonia) * 1))
+ if(myseed)
+ myseed.adjust_yield(round(S.get_reagent_amount(/datum/reagent/ammonia) * 0.01))
+
+ // Saltpetre is used for gardening IRL, to simplify highly, it speeds up growth and strengthens plants
+ if(S.has_reagent(/datum/reagent/saltpetre, 1))
+ var/salt = S.get_reagent_amount(/datum/reagent/saltpetre)
+ adjustHealth(round(salt * 0.25))
+ if (myseed)
+ myseed.adjust_production(-round(salt/100)-prob(salt%100))
+ myseed.adjust_potency(round(salt*0.5))
+ // Ash is also used IRL in gardening, as a fertilizer enhancer and weed killer
+ if(S.has_reagent(/datum/reagent/ash, 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/ash) * 0.25))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/ash) * 0.5))
+ adjustWeeds(-1)
+
+ // Diethylamine is more bad ass, and pests get hurt by the corrosive nature of it, not the plant.
+ if(S.has_reagent(/datum/reagent/diethylamine, 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 1))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 2))
+ if(myseed)
+ myseed.adjust_yield(round(S.get_reagent_amount(/datum/reagent/diethylamine) * 0.02))
+ adjustPests(-rand(1,2))
+
+ // Nutriment Compost, effectively
+ if(S.has_reagent(/datum/reagent/consumable/nutriment, 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/consumable/nutriment) * 0.5))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/consumable/nutriment) * 1))
+
+ // Virusfood Compost for EVERYTHING
+ if(S.has_reagent(/datum/reagent/toxin/mutagen/mutagenvirusfood, 1))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/toxin/mutagen/mutagenvirusfood) * 0.5))
+ adjustHealth(-round(S.get_reagent_amount(/datum/reagent/toxin/mutagen/mutagenvirusfood) * 0.5))
+
+ // Blood
+ if(S.has_reagent(/datum/reagent/blood, 1))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/blood) * 1))
+ adjustPests(rand(2,4))
+
+ // Strange reagent
+ if(S.has_reagent(/datum/reagent/medicine/strange_reagent, 1))
+ spawnplant()
+
+ // Adminordrazine the best stuff there is. For testing/debugging.
+ if(S.has_reagent(/datum/reagent/medicine/adminordrazine, 1))
+ adjustWater(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1))
+ adjustHealth(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1))
+ adjustNutri(round(S.get_reagent_amount(/datum/reagent/medicine/adminordrazine) * 1))
+ adjustPests(-rand(1,5))
+ adjustWeeds(-rand(1,5))
+ if(S.has_reagent(/datum/reagent/medicine/adminordrazine, 5))
+ switch(rand(100))
+ if(66 to 100)
+ mutatespecie()
+ if(33 to 65)
+ mutateweed()
+ if(1 to 32)
+ mutatepest(user)
+ else
+ to_chat(user, "Nothing happens...")
+
+/obj/machinery/hydroponics/attackby(obj/item/O, mob/user, params)
+ //Called when mob user "attacks" it with object O
+ if(istype(O, /obj/item/reagent_containers) ) // Syringe stuff (and other reagent containers now too)
+ var/obj/item/reagent_containers/reagent_source = O
+
+ if(istype(reagent_source, /obj/item/reagent_containers/syringe))
+ var/obj/item/reagent_containers/syringe/syr = reagent_source
+ if(syr.mode != 1)
+ to_chat(user, "You can't get any extract out of this plant." )
+ return
+
+ if(!reagent_source.reagents.total_volume)
+ to_chat(user, "[reagent_source] is empty.")
+ return 1
+
+ var/list/trays = list(src)//makes the list just this in cases of syringes and compost etc
+ var/target = myseed ? myseed.plantname : src
+ var/visi_msg = ""
+ var/irrigate = 0 //How am I supposed to irrigate pill contents?
+ var/transfer_amount
+
+ if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill))
+ visi_msg="[user] composts [reagent_source], spreading it through [target]"
+ transfer_amount = reagent_source.reagents.total_volume
+ else
+ transfer_amount = reagent_source.amount_per_transfer_from_this
+ if(istype(reagent_source, /obj/item/reagent_containers/syringe/))
+ var/obj/item/reagent_containers/syringe/syr = reagent_source
+ visi_msg="[user] injects [target] with [syr]"
+ if(syr.reagents.total_volume <= syr.amount_per_transfer_from_this)
+ syr.mode = 0
+ else if(istype(reagent_source, /obj/item/reagent_containers/spray/))
+ visi_msg="[user] sprays [target] with [reagent_source]"
+ playsound(loc, 'sound/effects/spray3.ogg', 50, 1, -6)
+ irrigate = 1
+ else if(transfer_amount) // Droppers, cans, beakers, what have you.
+ visi_msg="[user] uses [reagent_source] on [target]"
+ irrigate = 1
+ // Beakers, bottles, buckets, etc.
+ if(reagent_source.is_drainable())
+ playsound(loc, 'sound/effects/slosh.ogg', 25, 1)
+
+ if(irrigate && transfer_amount > 30 && reagent_source.reagents.total_volume >= 30 && using_irrigation)
+ trays = FindConnected()
+ if (trays.len > 1)
+ visi_msg += ", setting off the irrigation system"
+
+ if(visi_msg)
+ visible_message("[visi_msg].")
+
+ var/split = round(transfer_amount/trays.len)
+
+ for(var/obj/machinery/hydroponics/H in trays)
+ //cause I don't want to feel like im juggling 15 tamagotchis and I can get to my real work of ripping flooring apart in hopes of validating my life choices of becoming a space-gardener
+
+ var/datum/reagents/S = new /datum/reagents() //This is a strange way, but I don't know of a better one so I can't fix it at the moment...
+ S.my_atom = H
+
+ reagent_source.reagents.trans_to(S,split)
+ if(istype(reagent_source, /obj/item/reagent_containers/food/snacks) || istype(reagent_source, /obj/item/reagent_containers/pill))
+ qdel(reagent_source)
+
+ H.applyChemicals(S, user)
+
+ S.clear_reagents()
+ qdel(S)
+ H.update_icon()
+ if(reagent_source) // If the source wasn't composted and destroyed
+ reagent_source.update_icon()
+ return 1
+
+ else if(istype(O, /obj/item/seeds) && !istype(O, /obj/item/seeds/sample))
+ if(!myseed)
+ if(istype(O, /obj/item/seeds/kudzu))
+ investigate_log("had Kudzu planted in it by [key_name(user)] at [AREACOORD(src)]","kudzu")
+ if(!user.transferItemToLoc(O, src))
+ return
+ to_chat(user, "You plant [O].")
+ dead = 0
+ myseed = O
+ age = 1
+ plant_health = myseed.endurance
+ lastcycle = world.time
+ update_icon()
+ else
+ to_chat(user, "[src] already has seeds in it!")
+
+ else if(istype(O, /obj/item/plant_analyzer))
+ if(myseed)
+ to_chat(user, "*** [myseed.plantname] ***" )
+ to_chat(user, "- Plant Age: [age]")
+ var/list/text_string = myseed.get_analyzer_text()
+ if(text_string)
+ to_chat(user, text_string)
+ else
+ to_chat(user, "No plant found.")
+ to_chat(user, "- Weed level: [weedlevel] / 10")
+ to_chat(user, "- Pest level: [pestlevel] / 10")
+ to_chat(user, "- Toxicity level: [toxic] / 100")
+ to_chat(user, "- Water level: [waterlevel] / [maxwater]")
+ to_chat(user, "- Nutrition level: [nutrilevel] / [maxnutri]")
+ to_chat(user, "")
+
+ else if(istype(O, /obj/item/cultivator))
+ if(weedlevel > 0)
+ user.visible_message("[user] uproots the weeds.", "You remove the weeds from [src].")
+ weedlevel = 0
+ update_icon()
+ else
+ to_chat(user, "This plot is completely devoid of weeds! It doesn't need uprooting.")
+
+ else if(istype(O, /obj/item/storage/bag/plants))
+ attack_hand(user)
+ for(var/obj/item/reagent_containers/food/snacks/grown/G in locate(user.x,user.y,user.z))
+ SEND_SIGNAL(O, COMSIG_TRY_STORAGE_INSERT, G, user, TRUE)
+
+ else if(default_unfasten_wrench(user, O))
+ return
+
+ else if(istype(O, /obj/item/wirecutters) && unwrenchable)
+ if (!anchored)
+ to_chat(user, "Anchor the tray first!")
+ return
+ using_irrigation = !using_irrigation
+ O.play_tool_sound(src)
+ user.visible_message("[user] [using_irrigation ? "" : "dis"]connects [src]'s irrigation hoses.", \
+ "You [using_irrigation ? "" : "dis"]connect [src]'s irrigation hoses.")
+ for(var/obj/machinery/hydroponics/h in range(1,src))
+ h.update_icon()
+
+ else if(istype(O, /obj/item/shovel/spade))
+ if(!myseed && !weedlevel)
+ to_chat(user, "[src] doesn't have any plants or weeds!")
+ return
+ user.visible_message("[user] starts digging out [src]'s plants...",
+ "You start digging out [src]'s plants...")
+ if(O.use_tool(src, user, 50, volume=50) || (!myseed && !weedlevel))
+ user.visible_message("[user] digs out the plants in [src]!", "You dig out all of [src]'s plants!")
+ if(myseed) //Could be that they're just using it as a de-weeder
+ age = 0
+ plant_health = 0
+ if(harvest)
+ harvest = FALSE //To make sure they can't just put in another seed and insta-harvest it
+ qdel(myseed)
+ myseed = null
+ weedlevel = 0 //Has a side effect of cleaning up those nasty weeds
+ update_icon()
+
+ else
+ return ..()
+
+/obj/machinery/hydroponics/can_be_unfasten_wrench(mob/user, silent)
+ if (!unwrenchable) // case also covered by NODECONSTRUCT checks in default_unfasten_wrench
+ return CANT_UNFASTEN
+
+ if (using_irrigation)
+ if (!silent)
+ to_chat(user, "Disconnect the hoses first!")
+ return FAILED_UNFASTEN
+
+ return ..()
+
+/obj/machinery/hydroponics/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
+ if(issilicon(user)) //How does AI know what plant is?
+ return
+ if(harvest)
+ return myseed.harvest(user)
+
+ else if(dead)
+ dead = 0
+ to_chat(user, "You remove the dead plant from [src].")
+ qdel(myseed)
+ myseed = null
+ update_icon()
+ else
+ if(user)
+ examine(user)
+
+/obj/machinery/hydroponics/proc/update_tray(mob/user)
+ harvest = 0
+ lastproduce = age
+ if(istype(myseed, /obj/item/seeds/replicapod))
+ to_chat(user, "You harvest from the [myseed.plantname].")
+ else if(myseed.getYield() <= 0)
+ to_chat(user, "You fail to harvest anything useful!")
+ else
+ to_chat(user, "You harvest [myseed.getYield()] items from the [myseed.plantname].")
+ if(!myseed.get_gene(/datum/plant_gene/trait/repeated_harvest))
+ qdel(myseed)
+ myseed = null
+ dead = 0
+ update_icon()
+
+/// Tray Setters - The following procs adjust the tray or plants variables, and make sure that the stat doesn't go out of bounds.///
+/obj/machinery/hydroponics/proc/adjustNutri(adjustamt)
+ nutrilevel = CLAMP(nutrilevel + adjustamt, 0, maxnutri)
+
+/obj/machinery/hydroponics/proc/adjustWater(adjustamt)
+ waterlevel = CLAMP(waterlevel + adjustamt, 0, maxwater)
+
+ if(adjustamt>0)
+ adjustToxic(-round(adjustamt/4))//Toxicity dilutation code. The more water you put in, the lesser the toxin concentration.
+
+/obj/machinery/hydroponics/proc/adjustHealth(adjustamt)
+ if(myseed && !dead)
+ plant_health = CLAMP(plant_health + adjustamt, 0, myseed.endurance)
+
+/obj/machinery/hydroponics/proc/adjustToxic(adjustamt)
+ toxic = CLAMP(toxic + adjustamt, 0, 100)
+
+/obj/machinery/hydroponics/proc/adjustPests(adjustamt)
+ pestlevel = CLAMP(pestlevel + adjustamt, 0, 10)
+
+/obj/machinery/hydroponics/proc/adjustWeeds(adjustamt)
+ weedlevel = CLAMP(weedlevel + adjustamt, 0, 10)
+
+/obj/machinery/hydroponics/proc/spawnplant() // why would you put strange reagent in a hydro tray you monster I bet you also feed them blood
+ var/list/livingplants = list(/mob/living/simple_animal/hostile/tree, /mob/living/simple_animal/hostile/killertomato)
+ var/chosen = pick(livingplants)
+ var/mob/living/simple_animal/hostile/C = new chosen
+ C.faction = list("plants")
+
+/obj/machinery/hydroponics/proc/become_self_sufficient() // Ambrosia Gaia effect
+ visible_message("[src] begins to glow with a beautiful light!")
+ self_sustaining = TRUE
+ update_icon()
+
+///////////////////////////////////////////////////////////////////////////////
+/obj/machinery/hydroponics/soil //Not actually hydroponics at all! Honk!
+ name = "soil"
+ desc = "A patch of dirt."
+ icon = 'icons/obj/hydroponics/equipment.dmi'
+ icon_state = "soil"
+ circuit = null
+ density = FALSE
+ use_power = NO_POWER_USE
+ flags_1 = NODECONSTRUCT_1
+ unwrenchable = FALSE
+ var/buildstacktype = /obj/item/stack/sheet/mineral/sandstone
+ var/buildstackamount = 3
+
+/obj/machinery/hydroponics/soil/update_icon_hoses()
+ return // Has no hoses
+
+/obj/machinery/hydroponics/soil/update_icon_lights()
+ return // Has no lights
+
+/obj/machinery/hydroponics/soil/attackby(obj/item/O, mob/user, params)
+ if(istype(O, /obj/item/shovel) && !istype(O, /obj/item/shovel/spade)) //Doesn't include spades because of uprooting plants
+ to_chat(user, "You clear up [src]!")
+ new buildstacktype(loc,buildstackamount)
+ qdel(src)
+ else
+ return ..()
diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm
index da83aab3..604fa3e4 100644
--- a/code/modules/hydroponics/plant_genes.dm
+++ b/code/modules/hydroponics/plant_genes.dm
@@ -129,7 +129,7 @@
name = "UNKNOWN"
var/datum/reagent/R = GLOB.chemical_reagents_list[reag_id]
- if(R && R.id == reagent_id)
+ if(R && R.type == reagent_id)
name = R.name
/datum/plant_gene/reagent/New(reag_id = null, reag_rate = 0)
@@ -228,7 +228,7 @@
var/obj/item/seeds/seed = G.seed
var/stun_len = seed.potency * rate
- if(!istype(G, /obj/item/grown/bananapeel) && (!G.reagents || !G.reagents.has_reagent("lube")))
+ if(!istype(G, /obj/item/grown/bananapeel) && (!G.reagents || !G.reagents.has_reagent(/datum/reagent/lube)))
stun_len /= 3
G.AddComponent(/datum/component/slippery, min(stun_len,140), NONE, CALLBACK(src, .proc/handle_slip, G))
@@ -415,7 +415,7 @@ datum/plant_gene/trait/glow/white
pocell.name = "[G.name] battery"
pocell.desc = "A rechargeable plant-based power cell. This one has a rating of [DisplayEnergy(pocell.maxcharge)], and you should not swallow it."
- if(G.reagents.has_reagent("plasma", 2))
+ if(G.reagents.has_reagent(/datum/reagent/toxin/plasma, 2))
pocell.rigged = TRUE
qdel(G)
diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm
index 300b8c58..2c1f6a8f 100644
--- a/code/modules/hydroponics/seeds.dm
+++ b/code/modules/hydroponics/seeds.dm
@@ -1,410 +1,410 @@
-// ********************************************************
-// Here's all the seeds (plants) that can be used in hydro
-// ********************************************************
-
-/obj/item/seeds
- icon = 'icons/obj/hydroponics/seeds.dmi'
- icon_state = "seed" // Unknown plant seed - these shouldn't exist in-game.
- w_class = WEIGHT_CLASS_TINY
- resistance_flags = FLAMMABLE
- var/plantname = "Plants" // Name of plant when planted.
- var/product // A type path. The thing that is created when the plant is harvested.
- var/species = "" // Used to update icons. Should match the name in the sprites unless all icon_* are overridden.
-
- var/growing_icon = 'icons/obj/hydroponics/growing.dmi' //the file that stores the sprites of the growing plant from this seed.
- var/icon_grow // Used to override grow icon (default is "[species]-grow"). You can use one grow icon for multiple closely related plants with it.
- var/icon_dead // Used to override dead icon (default is "[species]-dead"). You can use one dead icon for multiple closely related plants with it.
- var/icon_harvest // Used to override harvest icon (default is "[species]-harvest"). If null, plant will use [icon_grow][growthstages].
-
- var/lifespan = 25 // How long before the plant begins to take damage from age.
- var/endurance = 15 // Amount of health the plant has.
- var/maturation = 6 // Used to determine which sprite to switch to when growing.
- var/production = 6 // Changes the amount of time needed for a plant to become harvestable.
- var/yield = 3 // Amount of growns created per harvest. If is -1, the plant/shroom/weed is never meant to be harvested.
- var/potency = 10 // The 'power' of a plant. Generally effects the amount of reagent in a plant, also used in other ways.
- var/growthstages = 6 // Amount of growth sprites the plant has.
- var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to CentCom.
- var/list/mutatelist = list() // The type of plants that this plant can mutate into.
- var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info.
- var/list/forbiddengenes = list() // Plant genes that the seed may be forbidden from having.
- var/list/reagents_add = list()
- // A list of reagents to add to product.
- // Format: "reagent_id" = potency multiplier
- // Stronger reagents must always come first to avoid being displaced by weaker ones.
- // Total amount of any reagent in plant is calculated by formula: 1 + round(potency * multiplier)
-
- var/weed_rate = 1 //If the chance below passes, then this many weeds sprout during growth
- var/weed_chance = 5 //Percentage chance per tray update to grow weeds
-
-/obj/item/seeds/Initialize(mapload, nogenes = 0)
- . = ..()
- pixel_x = rand(-8, 8)
- pixel_y = rand(-8, 8)
-
- if(!icon_grow)
- icon_grow = "[species]-grow"
-
- if(!icon_dead)
- icon_dead = "[species]-dead"
-
- if(!icon_harvest && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && yield != -1)
- icon_harvest = "[species]-harvest"
-
- if(!nogenes) // not used on Copy()
- genes += new /datum/plant_gene/core/lifespan(lifespan)
- genes += new /datum/plant_gene/core/endurance(endurance)
- genes += new /datum/plant_gene/core/weed_rate(weed_rate)
- genes += new /datum/plant_gene/core/weed_chance(weed_chance)
- if(yield != -1)
- genes += new /datum/plant_gene/core/yield(yield)
- genes += new /datum/plant_gene/core/production(production)
- if(potency != -1)
- genes += new /datum/plant_gene/core/potency(potency)
-
- for(var/p in genes)
- if(ispath(p))
- genes -= p
- genes += new p
-
- for(var/reag_id in reagents_add)
- genes += new /datum/plant_gene/reagent(reag_id, reagents_add[reag_id])
- reagents_from_genes() //quality coding
-
-/obj/item/seeds/proc/Copy()
- var/obj/item/seeds/S = new type(null, 1)
- // Copy all the stats
- S.lifespan = lifespan
- S.endurance = endurance
- S.maturation = maturation
- S.production = production
- S.yield = yield
- S.potency = potency
- S.weed_rate = weed_rate
- S.weed_chance = weed_chance
- S.genes = list()
- for(var/g in genes)
- var/datum/plant_gene/G = g
- S.genes += G.Copy()
- S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
- return S
-
-/obj/item/seeds/proc/get_gene(typepath)
- return (locate(typepath) in genes)
-
-obj/item/seeds/proc/is_gene_forbidden(typepath)
- return (locate(typepath) in forbiddengenes)
-
-
-/obj/item/seeds/proc/reagents_from_genes()
- reagents_add = list()
- for(var/datum/plant_gene/reagent/R in genes)
- reagents_add[R.reagent_id] = R.rate
-
-///This proc adds a mutability_flag to a gene
-/obj/item/seeds/proc/set_mutability(typepath, mutability)
- var/datum/plant_gene/g = get_gene(typepath)
- if(g)
- g.mutability_flags |= mutability
-
-///This proc removes a mutability_flag from a gene
-/obj/item/seeds/proc/unset_mutability(typepath, mutability)
- var/datum/plant_gene/g = get_gene(typepath)
- if(g)
- g.mutability_flags &= ~mutability
-
-/obj/item/seeds/proc/mutate(lifemut = 2, endmut = 5, productmut = 1, yieldmut = 2, potmut = 25, wrmut = 2, wcmut = 5, traitmut = 0)
- adjust_lifespan(rand(-lifemut,lifemut))
- adjust_endurance(rand(-endmut,endmut))
- adjust_production(rand(-productmut,productmut))
- adjust_yield(rand(-yieldmut,yieldmut))
- adjust_potency(rand(-potmut,potmut))
- adjust_weed_rate(rand(-wrmut, wrmut))
- adjust_weed_chance(rand(-wcmut, wcmut))
- if(prob(traitmut))
- add_random_traits(1, 1)
-
-
-
-/obj/item/seeds/bullet_act(obj/item/projectile/Proj) //Works with the Somatoray to modify plant variables.
- if(istype(Proj, /obj/item/projectile/energy/florayield))
- var/rating = 1
- if(istype(loc, /obj/machinery/hydroponics))
- var/obj/machinery/hydroponics/H = loc
- rating = H.rating
-
- if(yield == 0)//Oh god don't divide by zero you'll doom us all.
- adjust_yield(1 * rating)
- else if(prob(1/(yield * yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2...
- adjust_yield(1 * rating)
- else
- return ..()
-
-
-// Harvest procs
-/obj/item/seeds/proc/getYield()
- var/return_yield = yield
-
- var/obj/machinery/hydroponics/parent = loc
- if(istype(loc, /obj/machinery/hydroponics))
- if(parent.yieldmod == 0)
- return_yield = min(return_yield, 1)//1 if above zero, 0 otherwise
- else
- return_yield *= (parent.yieldmod)
-
- return return_yield
-
-
-/obj/item/seeds/proc/harvest(mob/user)
- var/obj/machinery/hydroponics/parent = loc //for ease of access
- var/t_amount = 0
- var/list/result = list()
- var/output_loc = parent.Adjacent(user) ? user.loc : parent.loc //needed for TK
- var/product_name
- while(t_amount < getYield())
- var/obj/item/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, src)
- result.Add(t_prod) // User gets a consumable
- if(!t_prod)
- return
- t_amount++
- product_name = t_prod.name
- if(getYield() >= 1)
- SSblackbox.record_feedback("tally", "food_harvested", getYield(), product_name)
- parent.update_tray(user)
-
- return result
-
-
-/obj/item/seeds/proc/prepare_result(var/obj/item/reagent_containers/food/snacks/grown/T)
- if(!T.reagents)
- CRASH("[T] has no reagents.")
-
- for(var/rid in reagents_add)
- var/amount = 1 + round(potency * reagents_add[rid], 1)
-
- var/list/data = null
- if(rid == "blood") // Hack to make blood in plants always O-
- data = list("blood_type" = "O-")
- if(rid == "nutriment" || rid == "vitamin")
- // apple tastes of apple.
- data = T.tastes
-
- T.reagents.add_reagent(rid, amount, data)
-
-
-/// Setters procs ///
-/obj/item/seeds/proc/adjust_yield(adjustamt)
- if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
- yield = CLAMP(yield + adjustamt, 0, 10)
-
- if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
- yield = 1 // Mushrooms always have a minimum yield of 1.
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/yield)
- if(C)
- C.value = yield
-
-/obj/item/seeds/proc/adjust_lifespan(adjustamt)
- lifespan = CLAMP(lifespan + adjustamt, 10, 100)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
- if(C)
- C.value = lifespan
-
-/obj/item/seeds/proc/adjust_endurance(adjustamt)
- endurance = CLAMP(endurance + adjustamt, 10, 100)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
- if(C)
- C.value = endurance
-
-/obj/item/seeds/proc/adjust_production(adjustamt)
- if(yield != -1)
- production = CLAMP(production + adjustamt, 1, 10)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
- if(C)
- C.value = production
-
-/obj/item/seeds/proc/adjust_potency(adjustamt)
- if(potency != -1)
- potency = CLAMP(potency + adjustamt, 0, 100)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
- if(C)
- C.value = potency
-
-/obj/item/seeds/proc/adjust_weed_rate(adjustamt)
- weed_rate = CLAMP(weed_rate + adjustamt, 0, 10)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
- if(C)
- C.value = weed_rate
-
-/obj/item/seeds/proc/adjust_weed_chance(adjustamt)
- weed_chance = CLAMP(weed_chance + adjustamt, 0, 67)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
- if(C)
- C.value = weed_chance
-
-//Directly setting stats
-
-/obj/item/seeds/proc/set_yield(adjustamt)
- if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
- yield = CLAMP(adjustamt, 0, 10)
-
- if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
- yield = 1 // Mushrooms always have a minimum yield of 1.
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/yield)
- if(C)
- C.value = yield
-
-/obj/item/seeds/proc/set_lifespan(adjustamt)
- lifespan = CLAMP(adjustamt, 10, 100)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
- if(C)
- C.value = lifespan
-
-/obj/item/seeds/proc/set_endurance(adjustamt)
- endurance = CLAMP(adjustamt, 10, 100)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
- if(C)
- C.value = endurance
-
-/obj/item/seeds/proc/set_production(adjustamt)
- if(yield != -1)
- production = CLAMP(adjustamt, 1, 10)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
- if(C)
- C.value = production
-
-/obj/item/seeds/proc/set_potency(adjustamt)
- if(potency != -1)
- potency = CLAMP(adjustamt, 0, 100)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
- if(C)
- C.value = potency
-
-/obj/item/seeds/proc/set_weed_rate(adjustamt)
- weed_rate = CLAMP(adjustamt, 0, 10)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
- if(C)
- C.value = weed_rate
-
-/obj/item/seeds/proc/set_weed_chance(adjustamt)
- weed_chance = CLAMP(adjustamt, 0, 67)
- var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
- if(C)
- C.value = weed_chance
-
-
-/obj/item/seeds/proc/get_analyzer_text() //in case seeds have something special to tell to the analyzer
- var/text = ""
- if(!get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && !get_gene(/datum/plant_gene/trait/plant_type/alien_properties))
- text += "- Plant type: Normal plant\n"
- if(get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
- text += "- Plant type: Weed. Can grow in nutrient-poor soil.\n"
- if(get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
- text += "- Plant type: Mushroom. Can grow in dry soil.\n"
- if(get_gene(/datum/plant_gene/trait/plant_type/alien_properties))
- text += "- Plant type: UNKNOWN \n"
- if(potency != -1)
- text += "- Potency: [potency]\n"
- if(yield != -1)
- text += "- Yield: [yield]\n"
- text += "- Maturation speed: [maturation]\n"
- if(yield != -1)
- text += "- Production speed: [production]\n"
- text += "- Endurance: [endurance]\n"
- text += "- Lifespan: [lifespan]\n"
- text += "- Weed Growth Rate: [weed_rate]\n"
- text += "- Weed Vulnerability: [weed_chance]\n"
- if(rarity)
- text += "- Species Discovery Value: [rarity]\n"
- var/all_traits = ""
- for(var/datum/plant_gene/trait/traits in genes)
- if(istype(traits, /datum/plant_gene/trait/plant_type))
- continue
- all_traits += " [traits.get_name()]"
- text += "- Plant Traits:[all_traits]\n"
-
- text += "*---------*"
-
- return text
-
-/obj/item/seeds/proc/on_chem_reaction(datum/reagents/S) //in case seeds have some special interaction with special chems
- return
-
-/obj/item/seeds/attackby(obj/item/O, mob/user, params)
- if (istype(O, /obj/item/plant_analyzer))
- to_chat(user, "*---------*\n This is \a [src].")
- var/text = get_analyzer_text()
- if(text)
- to_chat(user, "[text]")
-
- return
- ..() // Fallthrough to item/attackby() so that bags can pick seeds up
-
-
-
-
-
-
-
-// Checks plants for broken tray icons. Use Advanced Proc Call to activate.
-// Maybe some day it would be used as unit test.
-/proc/check_plants_growth_stages_icons()
- var/list/states = icon_states('icons/obj/hydroponics/growing.dmi')
- states |= icon_states('icons/obj/hydroponics/growing_fruits.dmi')
- states |= icon_states('icons/obj/hydroponics/growing_flowers.dmi')
- states |= icon_states('icons/obj/hydroponics/growing_mushrooms.dmi')
- states |= icon_states('icons/obj/hydroponics/growing_vegetables.dmi')
- var/list/paths = typesof(/obj/item/seeds) - /obj/item/seeds - typesof(/obj/item/seeds/sample)
-
- for(var/seedpath in paths)
- var/obj/item/seeds/seed = new seedpath
-
- for(var/i in 1 to seed.growthstages)
- if("[seed.icon_grow][i]" in states)
- continue
- to_chat(world, "[seed.name] ([seed.type]) lacks the [seed.icon_grow][i] icon!")
-
- if(!(seed.icon_dead in states))
- to_chat(world, "[seed.name] ([seed.type]) lacks the [seed.icon_dead] icon!")
-
- if(seed.icon_harvest) // mushrooms have no grown sprites, same for items with no product
- if(!(seed.icon_harvest in states))
- to_chat(world, "[seed.name] ([seed.type]) lacks the [seed.icon_harvest] icon!")
-
-/obj/item/seeds/proc/randomize_stats()
- set_lifespan(rand(25, 60))
- set_endurance(rand(15, 35))
- set_production(rand(2, 10))
- set_yield(rand(1, 10))
- set_potency(rand(10, 35))
- set_weed_rate(rand(1, 10))
- set_weed_chance(rand(5, 100))
- maturation = rand(6, 12)
-
-/obj/item/seeds/proc/add_random_reagents(lower = 0, upper = 2)
- var/amount_random_reagents = rand(lower, upper)
- for(var/i in 1 to amount_random_reagents)
- var/random_amount = rand(4, 15) * 0.01 // this must be multiplied by 0.01, otherwise, it will not properly associate
- var/datum/plant_gene/reagent/R = new(get_random_reagent_id(), random_amount)
- if(R.can_add(src))
- genes += R
- else
- qdel(R)
- reagents_from_genes()
-
-/obj/item/seeds/proc/add_random_traits(lower = 0, upper = 2)
- var/amount_random_traits = rand(lower, upper)
- for(var/i in 1 to amount_random_traits)
- var/random_trait = pick((subtypesof(/datum/plant_gene/trait)-typesof(/datum/plant_gene/trait/plant_type)))
- var/datum/plant_gene/trait/T = new random_trait
- if(T.can_add(src) && !is_gene_forbidden(T))
- genes += T
- else
- qdel(T)
-
-/obj/item/seeds/proc/add_random_plant_type(normal_plant_chance = 75)
- if(prob(normal_plant_chance))
- var/random_plant_type = pick(subtypesof(/datum/plant_gene/trait/plant_type))
- var/datum/plant_gene/trait/plant_type/P = new random_plant_type
- if(P.can_add(src))
- genes += P
- else
- qdel(P)
+// ********************************************************
+// Here's all the seeds (plants) that can be used in hydro
+// ********************************************************
+
+/obj/item/seeds
+ icon = 'icons/obj/hydroponics/seeds.dmi'
+ icon_state = "seed" // Unknown plant seed - these shouldn't exist in-game.
+ w_class = WEIGHT_CLASS_TINY
+ resistance_flags = FLAMMABLE
+ var/plantname = "Plants" // Name of plant when planted.
+ var/product // A type path. The thing that is created when the plant is harvested.
+ var/species = "" // Used to update icons. Should match the name in the sprites unless all icon_* are overridden.
+
+ var/growing_icon = 'icons/obj/hydroponics/growing.dmi' //the file that stores the sprites of the growing plant from this seed.
+ var/icon_grow // Used to override grow icon (default is "[species]-grow"). You can use one grow icon for multiple closely related plants with it.
+ var/icon_dead // Used to override dead icon (default is "[species]-dead"). You can use one dead icon for multiple closely related plants with it.
+ var/icon_harvest // Used to override harvest icon (default is "[species]-harvest"). If null, plant will use [icon_grow][growthstages].
+
+ var/lifespan = 25 // How long before the plant begins to take damage from age.
+ var/endurance = 15 // Amount of health the plant has.
+ var/maturation = 6 // Used to determine which sprite to switch to when growing.
+ var/production = 6 // Changes the amount of time needed for a plant to become harvestable.
+ var/yield = 3 // Amount of growns created per harvest. If is -1, the plant/shroom/weed is never meant to be harvested.
+ var/potency = 10 // The 'power' of a plant. Generally effects the amount of reagent in a plant, also used in other ways.
+ var/growthstages = 6 // Amount of growth sprites the plant has.
+ var/rarity = 0 // How rare the plant is. Used for giving points to cargo when shipping off to CentCom.
+ var/list/mutatelist = list() // The type of plants that this plant can mutate into.
+ var/list/genes = list() // Plant genes are stored here, see plant_genes.dm for more info.
+ var/list/forbiddengenes = list() // Plant genes that the seed may be forbidden from having.
+ var/list/reagents_add = list()
+ // A list of reagents to add to product.
+ // Format: "reagent_id" = potency multiplier
+ // Stronger reagents must always come first to avoid being displaced by weaker ones.
+ // Total amount of any reagent in plant is calculated by formula: 1 + round(potency * multiplier)
+
+ var/weed_rate = 1 //If the chance below passes, then this many weeds sprout during growth
+ var/weed_chance = 5 //Percentage chance per tray update to grow weeds
+
+/obj/item/seeds/Initialize(mapload, nogenes = 0)
+ . = ..()
+ pixel_x = rand(-8, 8)
+ pixel_y = rand(-8, 8)
+
+ if(!icon_grow)
+ icon_grow = "[species]-grow"
+
+ if(!icon_dead)
+ icon_dead = "[species]-dead"
+
+ if(!icon_harvest && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && yield != -1)
+ icon_harvest = "[species]-harvest"
+
+ if(!nogenes) // not used on Copy()
+ genes += new /datum/plant_gene/core/lifespan(lifespan)
+ genes += new /datum/plant_gene/core/endurance(endurance)
+ genes += new /datum/plant_gene/core/weed_rate(weed_rate)
+ genes += new /datum/plant_gene/core/weed_chance(weed_chance)
+ if(yield != -1)
+ genes += new /datum/plant_gene/core/yield(yield)
+ genes += new /datum/plant_gene/core/production(production)
+ if(potency != -1)
+ genes += new /datum/plant_gene/core/potency(potency)
+
+ for(var/p in genes)
+ if(ispath(p))
+ genes -= p
+ genes += new p
+
+ for(var/reag_id in reagents_add)
+ genes += new /datum/plant_gene/reagent(reag_id, reagents_add[reag_id])
+ reagents_from_genes() //quality coding
+
+/obj/item/seeds/proc/Copy()
+ var/obj/item/seeds/S = new type(null, 1)
+ // Copy all the stats
+ S.lifespan = lifespan
+ S.endurance = endurance
+ S.maturation = maturation
+ S.production = production
+ S.yield = yield
+ S.potency = potency
+ S.weed_rate = weed_rate
+ S.weed_chance = weed_chance
+ S.genes = list()
+ for(var/g in genes)
+ var/datum/plant_gene/G = g
+ S.genes += G.Copy()
+ S.reagents_add = reagents_add.Copy() // Faster than grabbing the list from genes.
+ return S
+
+/obj/item/seeds/proc/get_gene(typepath)
+ return (locate(typepath) in genes)
+
+obj/item/seeds/proc/is_gene_forbidden(typepath)
+ return (locate(typepath) in forbiddengenes)
+
+
+/obj/item/seeds/proc/reagents_from_genes()
+ reagents_add = list()
+ for(var/datum/plant_gene/reagent/R in genes)
+ reagents_add[R.reagent_id] = R.rate
+
+///This proc adds a mutability_flag to a gene
+/obj/item/seeds/proc/set_mutability(typepath, mutability)
+ var/datum/plant_gene/g = get_gene(typepath)
+ if(g)
+ g.mutability_flags |= mutability
+
+///This proc removes a mutability_flag from a gene
+/obj/item/seeds/proc/unset_mutability(typepath, mutability)
+ var/datum/plant_gene/g = get_gene(typepath)
+ if(g)
+ g.mutability_flags &= ~mutability
+
+/obj/item/seeds/proc/mutate(lifemut = 2, endmut = 5, productmut = 1, yieldmut = 2, potmut = 25, wrmut = 2, wcmut = 5, traitmut = 0)
+ adjust_lifespan(rand(-lifemut,lifemut))
+ adjust_endurance(rand(-endmut,endmut))
+ adjust_production(rand(-productmut,productmut))
+ adjust_yield(rand(-yieldmut,yieldmut))
+ adjust_potency(rand(-potmut,potmut))
+ adjust_weed_rate(rand(-wrmut, wrmut))
+ adjust_weed_chance(rand(-wcmut, wcmut))
+ if(prob(traitmut))
+ add_random_traits(1, 1)
+
+
+
+/obj/item/seeds/bullet_act(obj/item/projectile/Proj) //Works with the Somatoray to modify plant variables.
+ if(istype(Proj, /obj/item/projectile/energy/florayield))
+ var/rating = 1
+ if(istype(loc, /obj/machinery/hydroponics))
+ var/obj/machinery/hydroponics/H = loc
+ rating = H.rating
+
+ if(yield == 0)//Oh god don't divide by zero you'll doom us all.
+ adjust_yield(1 * rating)
+ else if(prob(1/(yield * yield) * 100))//This formula gives you diminishing returns based on yield. 100% with 1 yield, decreasing to 25%, 11%, 6, 4, 2...
+ adjust_yield(1 * rating)
+ else
+ return ..()
+
+
+// Harvest procs
+/obj/item/seeds/proc/getYield()
+ var/return_yield = yield
+
+ var/obj/machinery/hydroponics/parent = loc
+ if(istype(loc, /obj/machinery/hydroponics))
+ if(parent.yieldmod == 0)
+ return_yield = min(return_yield, 1)//1 if above zero, 0 otherwise
+ else
+ return_yield *= (parent.yieldmod)
+
+ return return_yield
+
+
+/obj/item/seeds/proc/harvest(mob/user)
+ var/obj/machinery/hydroponics/parent = loc //for ease of access
+ var/t_amount = 0
+ var/list/result = list()
+ var/output_loc = parent.Adjacent(user) ? user.loc : parent.loc //needed for TK
+ var/product_name
+ while(t_amount < getYield())
+ var/obj/item/reagent_containers/food/snacks/grown/t_prod = new product(output_loc, src)
+ result.Add(t_prod) // User gets a consumable
+ if(!t_prod)
+ return
+ t_amount++
+ product_name = t_prod.name
+ if(getYield() >= 1)
+ SSblackbox.record_feedback("tally", "food_harvested", getYield(), product_name)
+ parent.update_tray(user)
+
+ return result
+
+
+/obj/item/seeds/proc/prepare_result(var/obj/item/reagent_containers/food/snacks/grown/T)
+ if(!T.reagents)
+ CRASH("[T] has no reagents.")
+
+ for(var/rid in reagents_add)
+ var/amount = 1 + round(potency * reagents_add[rid], 1)
+
+ var/list/data = null
+ if(rid == "blood") // Hack to make blood in plants always O-
+ data = list("blood_type" = "O-")
+ if(rid == /datum/reagent/consumable/nutriment || rid == /datum/reagent/consumable/nutriment/vitamin)
+ // apple tastes of apple.
+ data = T.tastes
+
+ T.reagents.add_reagent(rid, amount, data)
+
+
+/// Setters procs ///
+/obj/item/seeds/proc/adjust_yield(adjustamt)
+ if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
+ yield = CLAMP(yield + adjustamt, 0, 10)
+
+ if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
+ yield = 1 // Mushrooms always have a minimum yield of 1.
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/yield)
+ if(C)
+ C.value = yield
+
+/obj/item/seeds/proc/adjust_lifespan(adjustamt)
+ lifespan = CLAMP(lifespan + adjustamt, 10, 100)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
+ if(C)
+ C.value = lifespan
+
+/obj/item/seeds/proc/adjust_endurance(adjustamt)
+ endurance = CLAMP(endurance + adjustamt, 10, 100)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
+ if(C)
+ C.value = endurance
+
+/obj/item/seeds/proc/adjust_production(adjustamt)
+ if(yield != -1)
+ production = CLAMP(production + adjustamt, 1, 10)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
+ if(C)
+ C.value = production
+
+/obj/item/seeds/proc/adjust_potency(adjustamt)
+ if(potency != -1)
+ potency = CLAMP(potency + adjustamt, 0, 100)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
+ if(C)
+ C.value = potency
+
+/obj/item/seeds/proc/adjust_weed_rate(adjustamt)
+ weed_rate = CLAMP(weed_rate + adjustamt, 0, 10)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
+ if(C)
+ C.value = weed_rate
+
+/obj/item/seeds/proc/adjust_weed_chance(adjustamt)
+ weed_chance = CLAMP(weed_chance + adjustamt, 0, 67)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
+ if(C)
+ C.value = weed_chance
+
+//Directly setting stats
+
+/obj/item/seeds/proc/set_yield(adjustamt)
+ if(yield != -1) // Unharvestable shouldn't suddenly turn harvestable
+ yield = CLAMP(adjustamt, 0, 10)
+
+ if(yield <= 0 && get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
+ yield = 1 // Mushrooms always have a minimum yield of 1.
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/yield)
+ if(C)
+ C.value = yield
+
+/obj/item/seeds/proc/set_lifespan(adjustamt)
+ lifespan = CLAMP(adjustamt, 10, 100)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/lifespan)
+ if(C)
+ C.value = lifespan
+
+/obj/item/seeds/proc/set_endurance(adjustamt)
+ endurance = CLAMP(adjustamt, 10, 100)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/endurance)
+ if(C)
+ C.value = endurance
+
+/obj/item/seeds/proc/set_production(adjustamt)
+ if(yield != -1)
+ production = CLAMP(adjustamt, 1, 10)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/production)
+ if(C)
+ C.value = production
+
+/obj/item/seeds/proc/set_potency(adjustamt)
+ if(potency != -1)
+ potency = CLAMP(adjustamt, 0, 100)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/potency)
+ if(C)
+ C.value = potency
+
+/obj/item/seeds/proc/set_weed_rate(adjustamt)
+ weed_rate = CLAMP(adjustamt, 0, 10)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_rate)
+ if(C)
+ C.value = weed_rate
+
+/obj/item/seeds/proc/set_weed_chance(adjustamt)
+ weed_chance = CLAMP(adjustamt, 0, 67)
+ var/datum/plant_gene/core/C = get_gene(/datum/plant_gene/core/weed_chance)
+ if(C)
+ C.value = weed_chance
+
+
+/obj/item/seeds/proc/get_analyzer_text() //in case seeds have something special to tell to the analyzer
+ var/text = ""
+ if(!get_gene(/datum/plant_gene/trait/plant_type/weed_hardy) && !get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism) && !get_gene(/datum/plant_gene/trait/plant_type/alien_properties))
+ text += "- Plant type: Normal plant\n"
+ if(get_gene(/datum/plant_gene/trait/plant_type/weed_hardy))
+ text += "- Plant type: Weed. Can grow in nutrient-poor soil.\n"
+ if(get_gene(/datum/plant_gene/trait/plant_type/fungal_metabolism))
+ text += "- Plant type: Mushroom. Can grow in dry soil.\n"
+ if(get_gene(/datum/plant_gene/trait/plant_type/alien_properties))
+ text += "- Plant type: UNKNOWN \n"
+ if(potency != -1)
+ text += "- Potency: [potency]\n"
+ if(yield != -1)
+ text += "- Yield: [yield]\n"
+ text += "- Maturation speed: [maturation]\n"
+ if(yield != -1)
+ text += "- Production speed: [production]\n"
+ text += "- Endurance: [endurance]\n"
+ text += "- Lifespan: [lifespan]\n"
+ text += "- Weed Growth Rate: [weed_rate]\n"
+ text += "- Weed Vulnerability: [weed_chance]\n"
+ if(rarity)
+ text += "- Species Discovery Value: [rarity]\n"
+ var/all_traits = ""
+ for(var/datum/plant_gene/trait/traits in genes)
+ if(istype(traits, /datum/plant_gene/trait/plant_type))
+ continue
+ all_traits += " [traits.get_name()]"
+ text += "- Plant Traits:[all_traits]\n"
+
+ text += "*---------*"
+
+ return text
+
+/obj/item/seeds/proc/on_chem_reaction(datum/reagents/S) //in case seeds have some special interaction with special chems
+ return
+
+/obj/item/seeds/attackby(obj/item/O, mob/user, params)
+ if (istype(O, /obj/item/plant_analyzer))
+ to_chat(user, "*---------*\n This is \a [src].")
+ var/text = get_analyzer_text()
+ if(text)
+ to_chat(user, "[text]")
+
+ return
+ ..() // Fallthrough to item/attackby() so that bags can pick seeds up
+
+
+
+
+
+
+
+// Checks plants for broken tray icons. Use Advanced Proc Call to activate.
+// Maybe some day it would be used as unit test.
+/proc/check_plants_growth_stages_icons()
+ var/list/states = icon_states('icons/obj/hydroponics/growing.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_fruits.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_flowers.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_mushrooms.dmi')
+ states |= icon_states('icons/obj/hydroponics/growing_vegetables.dmi')
+ var/list/paths = typesof(/obj/item/seeds) - /obj/item/seeds - typesof(/obj/item/seeds/sample)
+
+ for(var/seedpath in paths)
+ var/obj/item/seeds/seed = new seedpath
+
+ for(var/i in 1 to seed.growthstages)
+ if("[seed.icon_grow][i]" in states)
+ continue
+ to_chat(world, "[seed.name] ([seed.type]) lacks the [seed.icon_grow][i] icon!")
+
+ if(!(seed.icon_dead in states))
+ to_chat(world, "[seed.name] ([seed.type]) lacks the [seed.icon_dead] icon!")
+
+ if(seed.icon_harvest) // mushrooms have no grown sprites, same for items with no product
+ if(!(seed.icon_harvest in states))
+ to_chat(world, "[seed.name] ([seed.type]) lacks the [seed.icon_harvest] icon!")
+
+/obj/item/seeds/proc/randomize_stats()
+ set_lifespan(rand(25, 60))
+ set_endurance(rand(15, 35))
+ set_production(rand(2, 10))
+ set_yield(rand(1, 10))
+ set_potency(rand(10, 35))
+ set_weed_rate(rand(1, 10))
+ set_weed_chance(rand(5, 100))
+ maturation = rand(6, 12)
+
+/obj/item/seeds/proc/add_random_reagents(lower = 0, upper = 2)
+ var/amount_random_reagents = rand(lower, upper)
+ for(var/i in 1 to amount_random_reagents)
+ var/random_amount = rand(4, 15) * 0.01 // this must be multiplied by 0.01, otherwise, it will not properly associate
+ var/datum/plant_gene/reagent/R = new(get_random_reagent_id(), random_amount)
+ if(R.can_add(src))
+ genes += R
+ else
+ qdel(R)
+ reagents_from_genes()
+
+/obj/item/seeds/proc/add_random_traits(lower = 0, upper = 2)
+ var/amount_random_traits = rand(lower, upper)
+ for(var/i in 1 to amount_random_traits)
+ var/random_trait = pick((subtypesof(/datum/plant_gene/trait)-typesof(/datum/plant_gene/trait/plant_type)))
+ var/datum/plant_gene/trait/T = new random_trait
+ if(T.can_add(src) && !is_gene_forbidden(T))
+ genes += T
+ else
+ qdel(T)
+
+/obj/item/seeds/proc/add_random_plant_type(normal_plant_chance = 75)
+ if(prob(normal_plant_chance))
+ var/random_plant_type = pick(subtypesof(/datum/plant_gene/trait/plant_type))
+ var/datum/plant_gene/trait/plant_type/P = new random_plant_type
+ if(P.can_add(src))
+ genes += P
+ else
+ qdel(P)
diff --git a/code/modules/integrated_electronics/passive/power.dm b/code/modules/integrated_electronics/passive/power.dm
index d4899a46..f3c00f9e 100644
--- a/code/modules/integrated_electronics/passive/power.dm
+++ b/code/modules/integrated_electronics/passive/power.dm
@@ -96,7 +96,8 @@
activators = list("push ref" = IC_PINTYPE_PULSE_IN)
spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH
var/volume = 60
- var/list/fuel = list("plasma" = 50000, "welding_fuel" = 15000, "carbon" = 10000, "ethanol" = 10000, "nutriment" = 8000)
+ var/list/fuel = list(/datum/reagent/toxin/plasma = 50000, /datum/reagent/fuel = 15000, /datum/reagent/carbon = 10000,
+ /datum/reagent/consumable/ethanol = 10000, /datum/reagent/consumable/nutriment = 8000)
var/multi = 1
var/lfwb =TRUE
@@ -119,7 +120,7 @@
if(assembly)
if(assembly.battery)
var/bp = 5000
- if(reagents.get_reagent_amount("blood")) //only blood is powerful enough to power the station(c)
+ if(reagents.get_reagent_amount(/datum/reagent/blood)) //only blood is powerful enough to power the station(c)
var/datum/reagent/blood/B = locate() in reagents.reagent_list
if(lfwb)
if(B && B.data["cloneable"])
@@ -127,7 +128,7 @@
if(M && (M.stat != DEAD) && (M.client))
bp = 500000
if((assembly.battery.maxcharge-assembly.battery.charge) / GLOB.CELLRATE > bp)
- if(reagents.remove_reagent("blood", 1))
+ if(reagents.remove_reagent(/datum/reagent/blood, 1))
assembly.give_power(bp)
for(var/I in fuel)
if((assembly.battery.maxcharge-assembly.battery.charge) / GLOB.CELLRATE > fuel[I])
diff --git a/code/modules/integrated_electronics/subtypes/reagents.dm b/code/modules/integrated_electronics/subtypes/reagents.dm
index 027a0365..0fc9f58d 100644
--- a/code/modules/integrated_electronics/subtypes/reagents.dm
+++ b/code/modules/integrated_electronics/subtypes/reagents.dm
@@ -424,7 +424,7 @@
if(1)
var/cont[0]
for(var/datum/reagent/RE in reagents.reagent_list)
- cont += RE.id
+ cont += RE.type
set_pin_data(IC_OUTPUT, 3, cont)
push_data()
if(2)
@@ -492,11 +492,11 @@
for(var/datum/reagent/G in source.reagents.reagent_list)
if(!direction_mode)
- if(G.id in demand)
- source.reagents.trans_id_to(target, G.id, transfer_amount)
+ if(G.type in demand)
+ source.reagents.trans_id_to(target, G.type, transfer_amount)
else
- if(!(G.id in demand))
- source.reagents.trans_id_to(target, G.id, transfer_amount)
+ if(!(G.type in demand))
+ source.reagents.trans_id_to(target, G.type, transfer_amount)
activate_pin(2)
push_data()
diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm
index 4077f21e..ea0174d2 100644
--- a/code/modules/mining/lavaland/ash_flora.dm
+++ b/code/modules/mining/lavaland/ash_flora.dm
@@ -148,7 +148,7 @@
desc = "Some shavings from a tall mushroom. With enough, might serve as a bowl."
icon = 'icons/obj/lavaland/ash_flora.dmi'
icon_state = "mushroom_shavings"
- list_reagents = list("sugar" = 3, "ethanol" = 2, "stabilizing_agent" = 3, "minttoxin" = 2)
+ list_reagents = list(/datum/reagent/consumable/sugar = 3, /datum/reagent/consumable/ethanol = 2, /datum/reagent/stabilizing_agent = 3, /datum/reagent/toxin/minttoxin = 2)
w_class = WEIGHT_CLASS_TINY
resistance_flags = FLAMMABLE
max_integrity = 100
@@ -166,7 +166,7 @@
/obj/item/reagent_containers/food/snacks/grown/ash_flora/mushroom_leaf
name = "mushroom leaf"
desc = "A leaf, from a mushroom."
- list_reagents = list("nutriment" = 3, "vitfro" = 2, "nicotine" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/vitfro = 2, /datum/reagent/drug/nicotine = 2)
icon_state = "mushroom_leaf"
seed = /obj/item/seeds/lavaland/porcini
wine_power = 40
@@ -174,7 +174,7 @@
/obj/item/reagent_containers/food/snacks/grown/ash_flora/mushroom_cap
name = "mushroom cap"
desc = "The cap of a large mushroom."
- list_reagents = list("mindbreaker" = 2, "entpoly" = 4, "mushroomhallucinogen" = 2)
+ list_reagents = list(/datum/reagent/toxin/mindbreaker = 2, /datum/reagent/consumable/entpoly = 4, /datum/reagent/drug/mushroomhallucinogen = 2)
icon_state = "mushroom_cap"
seed = /obj/item/seeds/lavaland/inocybe
wine_power = 70
@@ -182,14 +182,14 @@
/obj/item/reagent_containers/food/snacks/grown/ash_flora/mushroom_stem
name = "mushroom stem"
desc = "A long mushroom stem. It's slightly glowing."
- list_reagents = list("tinlux" = 2, "vitamin" = 1, "space_drugs" = 1)
+ list_reagents = list(/datum/reagent/consumable/tinlux = 2, /datum/reagent/consumable/nutriment/vitamin = 1, /datum/reagent/drug/space_drugs = 1)
icon_state = "mushroom_stem"
seed = /obj/item/seeds/lavaland/ember
wine_power = 60
/obj/item/reagent_containers/food/snacks/grown/ash_flora/cactus_fruit
name = "cactus fruit"
- list_reagents = list("vitamin" = 2, "nutriment" = 2, "vitfro" = 6)
+ list_reagents = list(/datum/reagent/consumable/nutriment/vitamin = 2, /datum/reagent/consumable/nutriment = 2, /datum/reagent/consumable/vitfro = 6)
desc = "A cactus fruit covered in a thick, reddish skin. And some ash."
icon_state = "cactus_fruit"
seed = /obj/item/seeds/lavaland/cactus
@@ -218,7 +218,7 @@
else if(contents.len >= 20)
to_chat(user, "You can't add more ingredients to [src]!")
else
- if(reagents.has_reagent("water", 10)) //are we starting a soup or a salad?
+ if(reagents.has_reagent(/datum/reagent/water, 10)) //are we starting a soup or a salad?
var/obj/item/reagent_containers/food/snacks/customizable/A = new/obj/item/reagent_containers/food/snacks/customizable/soup/ashsoup(get_turf(src))
A.initialize_custom_food(src, S, user)
else
diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm
index 8790e171..efac7976 100644
--- a/code/modules/mining/lavaland/necropolis_chests.dm
+++ b/code/modules/mining/lavaland/necropolis_chests.dm
@@ -577,7 +577,7 @@
/obj/item/reagent_containers/glass/bottle/potion/flight
name = "strange elixir"
desc = "A flask with an almost-holy aura emitting from it. The label on the bottle says: 'erqo'hyy tvi'rf lbh jv'atf'."
- list_reagents = list("flightpotion" = 5)
+ list_reagents = list(/datum/reagent/flightpotion = 5)
/obj/item/reagent_containers/glass/bottle/potion/update_icon()
if(reagents.total_volume)
@@ -587,7 +587,6 @@
/datum/reagent/flightpotion
name = "Flight Potion"
- id = "flightpotion"
description = "Strange mutagenic compound of unknown origins."
reagent_state = LIQUID
color = "#FFEBEB"
diff --git a/code/modules/mining/ores_coins.dm b/code/modules/mining/ores_coins.dm
index 952b4992..2363e6a3 100644
--- a/code/modules/mining/ores_coins.dm
+++ b/code/modules/mining/ores_coins.dm
@@ -1,487 +1,487 @@
-
-#define GIBTONITE_QUALITY_HIGH 3
-#define GIBTONITE_QUALITY_MEDIUM 2
-#define GIBTONITE_QUALITY_LOW 1
-
-#define ORESTACK_OVERLAYS_MAX 10
-
-/**********************Mineral ores**************************/
-
-/obj/item/stack/ore
- name = "rock"
- icon = 'icons/obj/mining.dmi'
- icon_state = "ore"
- item_state = "ore"
- full_w_class = WEIGHT_CLASS_BULKY
- singular_name = "ore chunk"
- var/points = 0 //How many points this ore gets you from the ore redemption machine
- var/refined_type = null //What this ore defaults to being refined into
- novariants = TRUE // Ore stacks handle their icon updates themselves to keep the illusion that there's more going
- var/list/stack_overlays
-
-/obj/item/stack/ore/update_icon()
- var/difference = min(ORESTACK_OVERLAYS_MAX, amount) - (LAZYLEN(stack_overlays)+1)
- if(difference == 0)
- return
- else if(difference < 0 && LAZYLEN(stack_overlays)) //amount < stack_overlays, remove excess.
- cut_overlays()
- if (LAZYLEN(stack_overlays)-difference <= 0)
- stack_overlays = null;
- else
- stack_overlays.len += difference
- else if(difference > 0) //amount > stack_overlays, add some.
- cut_overlays()
- for(var/i in 1 to difference)
- var/mutable_appearance/newore = mutable_appearance(icon, icon_state)
- newore.pixel_x = rand(-8,8)
- newore.pixel_y = rand(-8,8)
- LAZYADD(stack_overlays, newore)
- if (stack_overlays)
- add_overlay(stack_overlays)
-
-/obj/item/stack/ore/welder_act(mob/living/user, obj/item/I)
- if(!refined_type)
- return TRUE
-
- if(I.use_tool(src, user, 0, volume=50, amount=15))
- new refined_type(drop_location())
- use(1)
-
- return TRUE
-
-/obj/item/stack/ore/fire_act(exposed_temperature, exposed_volume)
- . = ..()
- if(isnull(refined_type))
- return
- else
- var/probability = (rand(0,100))/100
- var/burn_value = probability*amount
- var/amountrefined = round(burn_value, 1)
- if(amountrefined < 1)
- qdel(src)
- else
- new refined_type(drop_location(),amountrefined)
- qdel(src)
-
-/obj/item/stack/ore/uranium
- name = "uranium ore"
- icon_state = "Uranium ore"
- item_state = "Uranium ore"
- singular_name = "uranium ore chunk"
- points = 30
- materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/mineral/uranium
-
-/obj/item/stack/ore/iron
- name = "iron ore"
- icon_state = "Iron ore"
- item_state = "Iron ore"
- singular_name = "iron ore chunk"
- points = 1
- materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/metal
-
-/obj/item/stack/ore/glass
- name = "sand pile"
- icon_state = "Glass ore"
- item_state = "Glass ore"
- singular_name = "sand pile"
- points = 1
- materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/glass
- w_class = WEIGHT_CLASS_TINY
-
-GLOBAL_LIST_INIT(sand_recipes, list(\
- new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50)\
- ))
-
-/obj/item/stack/ore/glass/Initialize(mapload, new_amount, merge = TRUE)
- recipes = GLOB.sand_recipes
- . = ..()
-
-/obj/item/stack/ore/glass/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
- if(..() || !ishuman(hit_atom))
- return
- var/mob/living/carbon/human/C = hit_atom
- if(C.head && C.head.flags_cover & HEADCOVERSEYES)
- visible_message("[C]'s headgear blocks the sand!")
- return
- if(C.wear_mask && C.wear_mask.flags_cover & MASKCOVERSEYES)
- visible_message("[C]'s mask blocks the sand!")
- return
- if(C.glasses && C.glasses.flags_cover & GLASSESCOVERSEYES)
- visible_message("[C]'s glasses block the sand!")
- return
- C.adjust_blurriness(6)
- C.adjustStaminaLoss(15)//the pain from your eyes burning does stamina damage
- C.confused += 5
- to_chat(C, "\The [src] gets into your eyes! The pain, it burns!")
- qdel(src)
-
-/obj/item/stack/ore/glass/ex_act(severity, target)
- if (severity == EXPLODE_NONE)
- return
- qdel(src)
-
-/obj/item/stack/ore/glass/basalt
- name = "volcanic ash"
- icon_state = "volcanic_sand"
- icon_state = "volcanic_sand"
- singular_name = "volcanic ash pile"
-
-/obj/item/stack/ore/plasma
- name = "plasma ore"
- icon_state = "Plasma ore"
- item_state = "Plasma ore"
- singular_name = "plasma ore chunk"
- points = 15
- materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/mineral/plasma
-
-/obj/item/stack/ore/plasma/welder_act(mob/living/user, obj/item/I)
- to_chat(user, "You can't hit a high enough temperature to smelt [src] properly!")
- return TRUE
-
-
-/obj/item/stack/ore/silver
- name = "silver ore"
- icon_state = "Silver ore"
- item_state = "Silver ore"
- singular_name = "silver ore chunk"
- points = 16
- materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/mineral/silver
-
-/obj/item/stack/ore/gold
- name = "gold ore"
- icon_state = "Gold ore"
- icon_state = "Gold ore"
- singular_name = "gold ore chunk"
- points = 18
- materials = list(MAT_GOLD=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/mineral/gold
-
-/obj/item/stack/ore/diamond
- name = "diamond ore"
- icon_state = "Diamond ore"
- item_state = "Diamond ore"
- singular_name = "diamond ore chunk"
- points = 50
- materials = list(MAT_DIAMOND=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/mineral/diamond
-
-/obj/item/stack/ore/bananium
- name = "bananium ore"
- icon_state = "Bananium ore"
- item_state = "Bananium ore"
- singular_name = "bananium ore chunk"
- points = 60
- materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/mineral/bananium
-
-/obj/item/stack/ore/titanium
- name = "titanium ore"
- icon_state = "Titanium ore"
- item_state = "Titanium ore"
- singular_name = "titanium ore chunk"
- points = 50
- materials = list(MAT_TITANIUM=MINERAL_MATERIAL_AMOUNT)
- refined_type = /obj/item/stack/sheet/mineral/titanium
-
-/obj/item/stack/ore/slag
- name = "slag"
- desc = "Completely useless."
- icon_state = "slag"
- item_state = "slag"
- singular_name = "slag chunk"
-
-/obj/item/twohanded/required/gibtonite
- name = "gibtonite ore"
- desc = "Extremely explosive if struck with mining equipment, Gibtonite is often used by miners to speed up their work by using it as a mining charge. This material is illegal to possess by unauthorized personnel under space law."
- icon = 'icons/obj/mining.dmi'
- icon_state = "Gibtonite ore"
- item_state = "Gibtonite ore"
- w_class = WEIGHT_CLASS_BULKY
- throw_range = 0
- var/primed = FALSE
- var/det_time = 100
- var/quality = GIBTONITE_QUALITY_LOW //How pure this gibtonite is, determines the explosion produced by it and is derived from the det_time of the rock wall it was taken from, higher value = better
- var/attacher = "UNKNOWN"
- var/det_timer
-
-/obj/item/twohanded/required/gibtonite/Destroy()
- qdel(wires)
- wires = null
- return ..()
-
-/obj/item/twohanded/required/gibtonite/attackby(obj/item/I, mob/user, params)
- if(!wires && istype(I, /obj/item/assembly/igniter))
- user.visible_message("[user] attaches [I] to [src].", "You attach [I] to [src].")
- wires = new /datum/wires/explosive/gibtonite(src)
- attacher = key_name(user)
- qdel(I)
- add_overlay("Gibtonite_igniter")
- return
-
- if(wires && !primed)
- if(is_wire_tool(I))
- wires.interact(user)
- return
-
- if(I.tool_behaviour == TOOL_MINING || istype(I, /obj/item/resonator) || I.force >= 10)
- GibtoniteReaction(user)
- return
- if(primed)
- if(istype(I, /obj/item/mining_scanner) || istype(I, /obj/item/t_scanner/adv_mining_scanner) || istype(I, /obj/item/multitool))
- primed = FALSE
- if(det_timer)
- deltimer(det_timer)
- user.visible_message("The chain reaction was stopped! ...The ore's quality looks diminished.", "You stopped the chain reaction. ...The ore's quality looks diminished.")
- icon_state = "Gibtonite ore"
- quality = GIBTONITE_QUALITY_LOW
- return
- ..()
-
-/obj/item/twohanded/required/gibtonite/attack_self(user)
- if(wires)
- wires.interact(user)
- else
- ..()
-
-/obj/item/twohanded/required/gibtonite/bullet_act(obj/item/projectile/P)
- GibtoniteReaction(P.firer)
- ..()
-
-/obj/item/twohanded/required/gibtonite/ex_act()
- GibtoniteReaction(null, 1)
-
-
-
-/obj/item/twohanded/required/gibtonite/proc/GibtoniteReaction(mob/user, triggered_by = 0)
- if(!primed)
- primed = TRUE
- playsound(src,'sound/effects/hit_on_shattered_glass.ogg',50,1)
- icon_state = "Gibtonite active"
- var/turf/bombturf = get_turf(src)
- var/notify_admins = 0
- if(z != 5)//Only annoy the admins ingame if we're triggered off the mining zlevel
- notify_admins = 1
-
- if(notify_admins)
- if(triggered_by == 1)
- message_admins("An explosion has triggered a [name] to detonate at [ADMIN_VERBOSEJMP(bombturf)].")
- else if(triggered_by == 2)
- message_admins("A signal has triggered a [name] to detonate at [ADMIN_VERBOSEJMP(bombturf)]. Igniter attacher: [ADMIN_LOOKUPFLW(attacher)]")
- else
- message_admins("[ADMIN_LOOKUPFLW(attacher)] has triggered a [name] to detonate at [ADMIN_VERBOSEJMP(bombturf)].")
- if(triggered_by == 1)
- log_game("An explosion has primed a [name] for detonation at [AREACOORD(bombturf)]")
- else if(triggered_by == 2)
- log_game("A signal has primed a [name] for detonation at [AREACOORD(bombturf)]. Igniter attacher: [key_name(attacher)].")
- else
- user.visible_message("[user] strikes \the [src], causing a chain reaction!", "You strike \the [src], causing a chain reaction.")
- log_game("[key_name(user)] has primed a [name] for detonation at [AREACOORD(bombturf)]")
- det_timer = addtimer(CALLBACK(src, .proc/detonate, notify_admins), det_time, TIMER_STOPPABLE)
-
-/obj/item/twohanded/required/gibtonite/proc/detonate(notify_admins)
- if(primed)
- switch(quality)
- if(GIBTONITE_QUALITY_HIGH)
- explosion(src,2,4,9,adminlog = notify_admins)
- if(GIBTONITE_QUALITY_MEDIUM)
- explosion(src,1,2,5,adminlog = notify_admins)
- if(GIBTONITE_QUALITY_LOW)
- explosion(src,0,1,3,adminlog = notify_admins)
- qdel(src)
-
-/obj/item/stack/ore/Initialize()
- . = ..()
- pixel_x = rand(0,16)-8
- pixel_y = rand(0,8)-8
-
-/obj/item/stack/ore/ex_act(severity, target)
- if (!severity || severity >= 2)
- return
- qdel(src)
-
-
-/*****************************Coin********************************/
-
-// The coin's value is a value of it's materials.
-// Yes, the gold standard makes a come-back!
-// This is the only way to make coins that are possible to produce on station actually worth anything.
-/obj/item/coin
- icon = 'icons/obj/economy.dmi'
- name = "coin"
- icon_state = "coin__heads"
- flags_1 = CONDUCT_1
- force = 1
- throwforce = 2
- w_class = WEIGHT_CLASS_TINY
- var/string_attached
- var/list/sideslist = list("heads","tails")
- var/cmineral = null
- var/cooldown = 0
- var/value = 1
- var/coinflip
-
-/obj/item/coin/suicide_act(mob/living/user)
- user.visible_message("[user] contemplates suicide with \the [src]!")
- if (!attack_self(user))
- user.visible_message("[user] couldn't flip \the [src]!")
- return SHAME
- addtimer(CALLBACK(src, .proc/manual_suicide, user), 10)//10 = time takes for flip animation
- return MANUAL_SUICIDE
-
-/obj/item/coin/proc/manual_suicide(mob/living/user)
- var/index = sideslist.Find(coinflip)
- if (index==2)//tails
- user.visible_message("\the [src] lands on [coinflip]! [user] promptly falls over, dead!")
- user.adjustOxyLoss(200)
- user.death(0)
- else
- user.visible_message("\the [src] lands on [coinflip]! [user] keeps on living!")
-
-/obj/item/coin/Initialize()
- . = ..()
- pixel_x = rand(0,16)-8
- pixel_y = rand(0,8)-8
-
-/obj/item/coin/examine(mob/user)
- . = ..()
- if(value)
- . += "It's worth [value] credit\s."
-
-/obj/item/coin/gold
- name = "gold coin"
- cmineral = "gold"
- icon_state = "coin_gold_heads"
- value = 50
- materials = list(MAT_GOLD = MINERAL_MATERIAL_AMOUNT*0.2)
- grind_results = list("gold" = 4)
-
-/obj/item/coin/silver
- name = "silver coin"
- cmineral = "silver"
- icon_state = "coin_silver_heads"
- value = 20
- materials = list(MAT_SILVER = MINERAL_MATERIAL_AMOUNT*0.2)
- grind_results = list("silver" = 4)
-
-/obj/item/coin/diamond
- name = "diamond coin"
- cmineral = "diamond"
- icon_state = "coin_diamond_heads"
- value = 500
- materials = list(MAT_DIAMOND = MINERAL_MATERIAL_AMOUNT*0.2)
- grind_results = list("carbon" = 4)
-
-/obj/item/coin/iron
- name = "iron coin"
- cmineral = "iron"
- icon_state = "coin_iron_heads"
- value = 1
- materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT*0.2)
- grind_results = list("iron" = 4)
-
-/obj/item/coin/plasma
- name = "plasma coin"
- cmineral = "plasma"
- icon_state = "coin_plasma_heads"
- value = 100
- materials = list(MAT_PLASMA = MINERAL_MATERIAL_AMOUNT*0.2)
- grind_results = list("plasma" = 4)
-
-/obj/item/coin/uranium
- name = "uranium coin"
- cmineral = "uranium"
- icon_state = "coin_uranium_heads"
- value = 80
- materials = list(MAT_URANIUM = MINERAL_MATERIAL_AMOUNT*0.2)
- grind_results = list("uranium" = 4)
-
-/obj/item/coin/bananium
- name = "bananium coin"
- cmineral = "bananium"
- icon_state = "coin_bananium_heads"
- value = 1000 //makes the clown cry
- materials = list(MAT_BANANIUM = MINERAL_MATERIAL_AMOUNT*0.2)
- grind_results = list("banana" = 4)
-
-/obj/item/coin/adamantine
- name = "adamantine coin"
- cmineral = "adamantine"
- icon_state = "coin_adamantine_heads"
- value = 1500
-
-/obj/item/coin/mythril
- name = "mythril coin"
- cmineral = "mythril"
- icon_state = "coin_mythril_heads"
- value = 3000
-
-/obj/item/coin/twoheaded
- cmineral = "iron"
- icon_state = "coin_iron_heads"
- desc = "Hey, this coin's the same on both sides!"
- sideslist = list("heads")
- materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT*0.2)
- value = 1
- grind_results = list("iron" = 4)
-
-/obj/item/coin/antagtoken
- name = "antag token"
- icon_state = "coin_valid_valid"
- cmineral = "valid"
- desc = "A novelty coin that helps the heart know what hard evidence cannot prove."
- sideslist = list("valid", "salad")
- value = 0
- grind_results = list("sodiumchloride" = 4)
-
-/obj/item/coin/attackby(obj/item/W, mob/user, params)
- if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/CC = W
- if(string_attached)
- to_chat(user, "There already is a string attached to this coin!")
- return
-
- if (CC.use(1))
- add_overlay("coin_string_overlay")
- string_attached = 1
- to_chat(user, "You attach a string to the coin.")
- else
- to_chat(user, "You need one length of cable to attach a string to the coin!")
- return
- else
- ..()
-
-/obj/item/coin/wirecutter_act(mob/living/user, obj/item/I)
- if(!string_attached)
- return TRUE
-
- new /obj/item/stack/cable_coil(drop_location(), 1)
- overlays = list()
- string_attached = null
- to_chat(user, "You detach the string from the coin.")
- return TRUE
-
-/obj/item/coin/attack_self(mob/user)
- if(cooldown < world.time)
- if(string_attached) //does the coin have a wire attached
- to_chat(user, "The coin won't flip very well with something attached!" )
- return FALSE//do not flip the coin
- coinflip = pick(sideslist)
- cooldown = world.time + 15
- flick("coin_[cmineral]_flip", src)
- icon_state = "coin_[cmineral]_[coinflip]"
- playsound(user.loc, 'sound/items/coinflip.ogg', 50, 1)
- var/oldloc = loc
- sleep(15)
- if(loc == oldloc && user && !user.incapacitated())
- user.visible_message("[user] has flipped [src]. It lands on [coinflip].", \
- "You flip [src]. It lands on [coinflip].", \
- "You hear the clattering of loose change.")
- return TRUE//did the coin flip? useful for suicide_act
-
-
-#undef ORESTACK_OVERLAYS_MAX
+
+#define GIBTONITE_QUALITY_HIGH 3
+#define GIBTONITE_QUALITY_MEDIUM 2
+#define GIBTONITE_QUALITY_LOW 1
+
+#define ORESTACK_OVERLAYS_MAX 10
+
+/**********************Mineral ores**************************/
+
+/obj/item/stack/ore
+ name = "rock"
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "ore"
+ item_state = "ore"
+ full_w_class = WEIGHT_CLASS_BULKY
+ singular_name = "ore chunk"
+ var/points = 0 //How many points this ore gets you from the ore redemption machine
+ var/refined_type = null //What this ore defaults to being refined into
+ novariants = TRUE // Ore stacks handle their icon updates themselves to keep the illusion that there's more going
+ var/list/stack_overlays
+
+/obj/item/stack/ore/update_icon()
+ var/difference = min(ORESTACK_OVERLAYS_MAX, amount) - (LAZYLEN(stack_overlays)+1)
+ if(difference == 0)
+ return
+ else if(difference < 0 && LAZYLEN(stack_overlays)) //amount < stack_overlays, remove excess.
+ cut_overlays()
+ if (LAZYLEN(stack_overlays)-difference <= 0)
+ stack_overlays = null;
+ else
+ stack_overlays.len += difference
+ else if(difference > 0) //amount > stack_overlays, add some.
+ cut_overlays()
+ for(var/i in 1 to difference)
+ var/mutable_appearance/newore = mutable_appearance(icon, icon_state)
+ newore.pixel_x = rand(-8,8)
+ newore.pixel_y = rand(-8,8)
+ LAZYADD(stack_overlays, newore)
+ if (stack_overlays)
+ add_overlay(stack_overlays)
+
+/obj/item/stack/ore/welder_act(mob/living/user, obj/item/I)
+ if(!refined_type)
+ return TRUE
+
+ if(I.use_tool(src, user, 0, volume=50, amount=15))
+ new refined_type(drop_location())
+ use(1)
+
+ return TRUE
+
+/obj/item/stack/ore/fire_act(exposed_temperature, exposed_volume)
+ . = ..()
+ if(isnull(refined_type))
+ return
+ else
+ var/probability = (rand(0,100))/100
+ var/burn_value = probability*amount
+ var/amountrefined = round(burn_value, 1)
+ if(amountrefined < 1)
+ qdel(src)
+ else
+ new refined_type(drop_location(),amountrefined)
+ qdel(src)
+
+/obj/item/stack/ore/uranium
+ name = "uranium ore"
+ icon_state = "Uranium ore"
+ item_state = "Uranium ore"
+ singular_name = "uranium ore chunk"
+ points = 30
+ materials = list(MAT_URANIUM=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/mineral/uranium
+
+/obj/item/stack/ore/iron
+ name = "iron ore"
+ icon_state = "Iron ore"
+ item_state = "Iron ore"
+ singular_name = "iron ore chunk"
+ points = 1
+ materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/metal
+
+/obj/item/stack/ore/glass
+ name = "sand pile"
+ icon_state = "Glass ore"
+ item_state = "Glass ore"
+ singular_name = "sand pile"
+ points = 1
+ materials = list(MAT_GLASS=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/glass
+ w_class = WEIGHT_CLASS_TINY
+
+GLOBAL_LIST_INIT(sand_recipes, list(\
+ new /datum/stack_recipe("sandstone", /obj/item/stack/sheet/mineral/sandstone, 1, 1, 50)\
+ ))
+
+/obj/item/stack/ore/glass/Initialize(mapload, new_amount, merge = TRUE)
+ recipes = GLOB.sand_recipes
+ . = ..()
+
+/obj/item/stack/ore/glass/throw_impact(atom/hit_atom, datum/thrownthing/throwingdatum)
+ if(..() || !ishuman(hit_atom))
+ return
+ var/mob/living/carbon/human/C = hit_atom
+ if(C.head && C.head.flags_cover & HEADCOVERSEYES)
+ visible_message("[C]'s headgear blocks the sand!")
+ return
+ if(C.wear_mask && C.wear_mask.flags_cover & MASKCOVERSEYES)
+ visible_message("[C]'s mask blocks the sand!")
+ return
+ if(C.glasses && C.glasses.flags_cover & GLASSESCOVERSEYES)
+ visible_message("[C]'s glasses block the sand!")
+ return
+ C.adjust_blurriness(6)
+ C.adjustStaminaLoss(15)//the pain from your eyes burning does stamina damage
+ C.confused += 5
+ to_chat(C, "\The [src] gets into your eyes! The pain, it burns!")
+ qdel(src)
+
+/obj/item/stack/ore/glass/ex_act(severity, target)
+ if (severity == EXPLODE_NONE)
+ return
+ qdel(src)
+
+/obj/item/stack/ore/glass/basalt
+ name = "volcanic ash"
+ icon_state = "volcanic_sand"
+ icon_state = "volcanic_sand"
+ singular_name = "volcanic ash pile"
+
+/obj/item/stack/ore/plasma
+ name = "plasma ore"
+ icon_state = "Plasma ore"
+ item_state = "Plasma ore"
+ singular_name = "plasma ore chunk"
+ points = 15
+ materials = list(MAT_PLASMA=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/mineral/plasma
+
+/obj/item/stack/ore/plasma/welder_act(mob/living/user, obj/item/I)
+ to_chat(user, "You can't hit a high enough temperature to smelt [src] properly!")
+ return TRUE
+
+
+/obj/item/stack/ore/silver
+ name = "silver ore"
+ icon_state = "Silver ore"
+ item_state = "Silver ore"
+ singular_name = "silver ore chunk"
+ points = 16
+ materials = list(MAT_SILVER=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/mineral/silver
+
+/obj/item/stack/ore/gold
+ name = "gold ore"
+ icon_state = "Gold ore"
+ icon_state = "Gold ore"
+ singular_name = "gold ore chunk"
+ points = 18
+ materials = list(MAT_GOLD=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/mineral/gold
+
+/obj/item/stack/ore/diamond
+ name = "diamond ore"
+ icon_state = "Diamond ore"
+ item_state = "Diamond ore"
+ singular_name = "diamond ore chunk"
+ points = 50
+ materials = list(MAT_DIAMOND=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/mineral/diamond
+
+/obj/item/stack/ore/bananium
+ name = "bananium ore"
+ icon_state = "Bananium ore"
+ item_state = "Bananium ore"
+ singular_name = "bananium ore chunk"
+ points = 60
+ materials = list(MAT_BANANIUM=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/mineral/bananium
+
+/obj/item/stack/ore/titanium
+ name = "titanium ore"
+ icon_state = "Titanium ore"
+ item_state = "Titanium ore"
+ singular_name = "titanium ore chunk"
+ points = 50
+ materials = list(MAT_TITANIUM=MINERAL_MATERIAL_AMOUNT)
+ refined_type = /obj/item/stack/sheet/mineral/titanium
+
+/obj/item/stack/ore/slag
+ name = "slag"
+ desc = "Completely useless."
+ icon_state = "slag"
+ item_state = "slag"
+ singular_name = "slag chunk"
+
+/obj/item/twohanded/required/gibtonite
+ name = "gibtonite ore"
+ desc = "Extremely explosive if struck with mining equipment, Gibtonite is often used by miners to speed up their work by using it as a mining charge. This material is illegal to possess by unauthorized personnel under space law."
+ icon = 'icons/obj/mining.dmi'
+ icon_state = "Gibtonite ore"
+ item_state = "Gibtonite ore"
+ w_class = WEIGHT_CLASS_BULKY
+ throw_range = 0
+ var/primed = FALSE
+ var/det_time = 100
+ var/quality = GIBTONITE_QUALITY_LOW //How pure this gibtonite is, determines the explosion produced by it and is derived from the det_time of the rock wall it was taken from, higher value = better
+ var/attacher = "UNKNOWN"
+ var/det_timer
+
+/obj/item/twohanded/required/gibtonite/Destroy()
+ qdel(wires)
+ wires = null
+ return ..()
+
+/obj/item/twohanded/required/gibtonite/attackby(obj/item/I, mob/user, params)
+ if(!wires && istype(I, /obj/item/assembly/igniter))
+ user.visible_message("[user] attaches [I] to [src].", "You attach [I] to [src].")
+ wires = new /datum/wires/explosive/gibtonite(src)
+ attacher = key_name(user)
+ qdel(I)
+ add_overlay("Gibtonite_igniter")
+ return
+
+ if(wires && !primed)
+ if(is_wire_tool(I))
+ wires.interact(user)
+ return
+
+ if(I.tool_behaviour == TOOL_MINING || istype(I, /obj/item/resonator) || I.force >= 10)
+ GibtoniteReaction(user)
+ return
+ if(primed)
+ if(istype(I, /obj/item/mining_scanner) || istype(I, /obj/item/t_scanner/adv_mining_scanner) || istype(I, /obj/item/multitool))
+ primed = FALSE
+ if(det_timer)
+ deltimer(det_timer)
+ user.visible_message("The chain reaction was stopped! ...The ore's quality looks diminished.", "You stopped the chain reaction. ...The ore's quality looks diminished.")
+ icon_state = "Gibtonite ore"
+ quality = GIBTONITE_QUALITY_LOW
+ return
+ ..()
+
+/obj/item/twohanded/required/gibtonite/attack_self(user)
+ if(wires)
+ wires.interact(user)
+ else
+ ..()
+
+/obj/item/twohanded/required/gibtonite/bullet_act(obj/item/projectile/P)
+ GibtoniteReaction(P.firer)
+ ..()
+
+/obj/item/twohanded/required/gibtonite/ex_act()
+ GibtoniteReaction(null, 1)
+
+
+
+/obj/item/twohanded/required/gibtonite/proc/GibtoniteReaction(mob/user, triggered_by = 0)
+ if(!primed)
+ primed = TRUE
+ playsound(src,'sound/effects/hit_on_shattered_glass.ogg',50,1)
+ icon_state = "Gibtonite active"
+ var/turf/bombturf = get_turf(src)
+ var/notify_admins = 0
+ if(z != 5)//Only annoy the admins ingame if we're triggered off the mining zlevel
+ notify_admins = 1
+
+ if(notify_admins)
+ if(triggered_by == 1)
+ message_admins("An explosion has triggered a [name] to detonate at [ADMIN_VERBOSEJMP(bombturf)].")
+ else if(triggered_by == 2)
+ message_admins("A signal has triggered a [name] to detonate at [ADMIN_VERBOSEJMP(bombturf)]. Igniter attacher: [ADMIN_LOOKUPFLW(attacher)]")
+ else
+ message_admins("[ADMIN_LOOKUPFLW(attacher)] has triggered a [name] to detonate at [ADMIN_VERBOSEJMP(bombturf)].")
+ if(triggered_by == 1)
+ log_game("An explosion has primed a [name] for detonation at [AREACOORD(bombturf)]")
+ else if(triggered_by == 2)
+ log_game("A signal has primed a [name] for detonation at [AREACOORD(bombturf)]. Igniter attacher: [key_name(attacher)].")
+ else
+ user.visible_message("[user] strikes \the [src], causing a chain reaction!", "You strike \the [src], causing a chain reaction.")
+ log_game("[key_name(user)] has primed a [name] for detonation at [AREACOORD(bombturf)]")
+ det_timer = addtimer(CALLBACK(src, .proc/detonate, notify_admins), det_time, TIMER_STOPPABLE)
+
+/obj/item/twohanded/required/gibtonite/proc/detonate(notify_admins)
+ if(primed)
+ switch(quality)
+ if(GIBTONITE_QUALITY_HIGH)
+ explosion(src,2,4,9,adminlog = notify_admins)
+ if(GIBTONITE_QUALITY_MEDIUM)
+ explosion(src,1,2,5,adminlog = notify_admins)
+ if(GIBTONITE_QUALITY_LOW)
+ explosion(src,0,1,3,adminlog = notify_admins)
+ qdel(src)
+
+/obj/item/stack/ore/Initialize()
+ . = ..()
+ pixel_x = rand(0,16)-8
+ pixel_y = rand(0,8)-8
+
+/obj/item/stack/ore/ex_act(severity, target)
+ if (!severity || severity >= 2)
+ return
+ qdel(src)
+
+
+/*****************************Coin********************************/
+
+// The coin's value is a value of it's materials.
+// Yes, the gold standard makes a come-back!
+// This is the only way to make coins that are possible to produce on station actually worth anything.
+/obj/item/coin
+ icon = 'icons/obj/economy.dmi'
+ name = "coin"
+ icon_state = "coin__heads"
+ flags_1 = CONDUCT_1
+ force = 1
+ throwforce = 2
+ w_class = WEIGHT_CLASS_TINY
+ var/string_attached
+ var/list/sideslist = list("heads","tails")
+ var/cmineral = null
+ var/cooldown = 0
+ var/value = 1
+ var/coinflip
+
+/obj/item/coin/suicide_act(mob/living/user)
+ user.visible_message("[user] contemplates suicide with \the [src]!")
+ if (!attack_self(user))
+ user.visible_message("[user] couldn't flip \the [src]!")
+ return SHAME
+ addtimer(CALLBACK(src, .proc/manual_suicide, user), 10)//10 = time takes for flip animation
+ return MANUAL_SUICIDE
+
+/obj/item/coin/proc/manual_suicide(mob/living/user)
+ var/index = sideslist.Find(coinflip)
+ if (index==2)//tails
+ user.visible_message("\the [src] lands on [coinflip]! [user] promptly falls over, dead!")
+ user.adjustOxyLoss(200)
+ user.death(0)
+ else
+ user.visible_message("\the [src] lands on [coinflip]! [user] keeps on living!")
+
+/obj/item/coin/Initialize()
+ . = ..()
+ pixel_x = rand(0,16)-8
+ pixel_y = rand(0,8)-8
+
+/obj/item/coin/examine(mob/user)
+ . = ..()
+ if(value)
+ . += "It's worth [value] credit\s."
+
+/obj/item/coin/gold
+ name = "gold coin"
+ cmineral = "gold"
+ icon_state = "coin_gold_heads"
+ value = 50
+ materials = list(MAT_GOLD = MINERAL_MATERIAL_AMOUNT*0.2)
+ grind_results = list(/datum/reagent/gold = 4)
+
+/obj/item/coin/silver
+ name = "silver coin"
+ cmineral = "silver"
+ icon_state = "coin_silver_heads"
+ value = 20
+ materials = list(MAT_SILVER = MINERAL_MATERIAL_AMOUNT*0.2)
+ grind_results = list(/datum/reagent/silver = 4)
+
+/obj/item/coin/diamond
+ name = "diamond coin"
+ cmineral = "diamond"
+ icon_state = "coin_diamond_heads"
+ value = 500
+ materials = list(MAT_DIAMOND = MINERAL_MATERIAL_AMOUNT*0.2)
+ grind_results = list(/datum/reagent/carbon = 4)
+
+/obj/item/coin/iron
+ name = "iron coin"
+ cmineral = "iron"
+ icon_state = "coin_iron_heads"
+ value = 1
+ materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT*0.2)
+ grind_results = list(/datum/reagent/iron = 4)
+
+/obj/item/coin/plasma
+ name = "plasma coin"
+ cmineral = "plasma"
+ icon_state = "coin_plasma_heads"
+ value = 100
+ materials = list(MAT_PLASMA = MINERAL_MATERIAL_AMOUNT*0.2)
+ grind_results = list(/datum/reagent/toxin/plasma = 4)
+
+/obj/item/coin/uranium
+ name = "uranium coin"
+ cmineral = "uranium"
+ icon_state = "coin_uranium_heads"
+ value = 80
+ materials = list(MAT_URANIUM = MINERAL_MATERIAL_AMOUNT*0.2)
+ grind_results = list(/datum/reagent/uranium = 4)
+
+/obj/item/coin/bananium
+ name = "bananium coin"
+ cmineral = "bananium"
+ icon_state = "coin_bananium_heads"
+ value = 1000 //makes the clown cry
+ materials = list(MAT_BANANIUM = MINERAL_MATERIAL_AMOUNT*0.2)
+ grind_results = list(/datum/reagent/consumable/banana = 4)
+
+/obj/item/coin/adamantine
+ name = "adamantine coin"
+ cmineral = "adamantine"
+ icon_state = "coin_adamantine_heads"
+ value = 1500
+
+/obj/item/coin/mythril
+ name = "mythril coin"
+ cmineral = "mythril"
+ icon_state = "coin_mythril_heads"
+ value = 3000
+
+/obj/item/coin/twoheaded
+ cmineral = "iron"
+ icon_state = "coin_iron_heads"
+ desc = "Hey, this coin's the same on both sides!"
+ sideslist = list("heads")
+ materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT*0.2)
+ value = 1
+ grind_results = list(/datum/reagent/iron = 4)
+
+/obj/item/coin/antagtoken
+ name = "antag token"
+ icon_state = "coin_valid_valid"
+ cmineral = "valid"
+ desc = "A novelty coin that helps the heart know what hard evidence cannot prove."
+ sideslist = list("valid", "salad")
+ value = 0
+ grind_results = list(/datum/reagent/consumable/sodiumchloride = 4)
+
+/obj/item/coin/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/CC = W
+ if(string_attached)
+ to_chat(user, "There already is a string attached to this coin!")
+ return
+
+ if (CC.use(1))
+ add_overlay("coin_string_overlay")
+ string_attached = 1
+ to_chat(user, "You attach a string to the coin.")
+ else
+ to_chat(user, "You need one length of cable to attach a string to the coin!")
+ return
+ else
+ ..()
+
+/obj/item/coin/wirecutter_act(mob/living/user, obj/item/I)
+ if(!string_attached)
+ return TRUE
+
+ new /obj/item/stack/cable_coil(drop_location(), 1)
+ overlays = list()
+ string_attached = null
+ to_chat(user, "You detach the string from the coin.")
+ return TRUE
+
+/obj/item/coin/attack_self(mob/user)
+ if(cooldown < world.time)
+ if(string_attached) //does the coin have a wire attached
+ to_chat(user, "The coin won't flip very well with something attached!" )
+ return FALSE//do not flip the coin
+ coinflip = pick(sideslist)
+ cooldown = world.time + 15
+ flick("coin_[cmineral]_flip", src)
+ icon_state = "coin_[cmineral]_[coinflip]"
+ playsound(user.loc, 'sound/items/coinflip.ogg', 50, 1)
+ var/oldloc = loc
+ sleep(15)
+ if(loc == oldloc && user && !user.incapacitated())
+ user.visible_message("[user] has flipped [src]. It lands on [coinflip].", \
+ "You flip [src]. It lands on [coinflip].", \
+ "You hear the clattering of loose change.")
+ return TRUE//did the coin flip? useful for suicide_act
+
+
+#undef ORESTACK_OVERLAYS_MAX
diff --git a/code/modules/mob/living/blood.dm b/code/modules/mob/living/blood.dm
index a1984b03..5887d10e 100644
--- a/code/modules/mob/living/blood.dm
+++ b/code/modules/mob/living/blood.dm
@@ -155,7 +155,7 @@
if(iscarbon(AM))
var/mob/living/carbon/C = AM
if(blood_id == C.get_blood_id())//both mobs have the same blood substance
- if(blood_id == "blood" || blood_id == "jellyblood") //normal blood
+ if(blood_id == /datum/reagent/blood || blood_id == /datum/reagent/blood/jellyblood) //normal blood
if(blood_data["viruses"])
for(var/thing in blood_data["viruses"])
var/datum/disease/D = thing
@@ -175,7 +175,7 @@
return
/mob/living/carbon/get_blood_data(blood_id)
- if(blood_id == "blood" || blood_id == "jellyblood") //actual blood reagent
+ if(blood_id == /datum/reagent/blood || /datum/reagent/blood/jellyblood) //actual blood reagent
var/blood_data = list()
//set the blood data
blood_data["donor"] = src
@@ -191,7 +191,7 @@
blood_data["resistances"] = disease_resistances.Copy()
var/list/temp_chem = list()
for(var/datum/reagent/R in reagents.reagent_list)
- temp_chem[R.id] = R.volume
+ temp_chem[R.type] = R.volume
blood_data["trace_chem"] = list2params(temp_chem)
if(mind)
blood_data["mind"] = mind
@@ -226,21 +226,21 @@
/mob/living/simple_animal/get_blood_id()
if(blood_volume)
- return "blood"
+ return /datum/reagent/blood
/mob/living/carbon/monkey/get_blood_id()
if(!(HAS_TRAIT(src, TRAIT_NOCLONE)))
- return "blood"
+ return /datum/reagent/blood
/mob/living/carbon/get_blood_id()
if(isjellyperson(src))
- return "jellyblood"
+ return /datum/reagent/blood/jellyblood
if(dna?.species?.exotic_blood)
return dna.species.exotic_blood
else if((NOBLOOD in dna.species.species_traits) || (HAS_TRAIT(src, TRAIT_NOCLONE)))
return
else
- return "blood"
+ return /datum/reagent/blood
// This is has more potential uses, and is probably faster than the old proc.
/proc/get_safe_blood(bloodtype)
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index 19500653..f3e8c734 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -73,7 +73,7 @@
if(victim.stat == CONSCIOUS)
src.visible_message("[victim] kicks free of the blood pool just before entering it!", null, "You hear splashing and struggling.")
- else if(victim.reagents && victim.reagents.has_reagent("demonsblood"))
+ else if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/demonsblood))
visible_message("Something prevents [victim] from entering the pool!", "A strange force is blocking [victim] from entering!", "You hear a splash and a thud.")
else
victim.forceMove(src)
@@ -104,7 +104,7 @@
if(!victim)
return FALSE
- if(victim.reagents && victim.reagents.has_reagent("devilskiss"))
+ if(victim.reagents && victim.reagents.has_reagent(/datum/reagent/consumable/ethanol/devilskiss))
to_chat(src, "AAH! THEIR FLESH! IT BURNS!")
adjustBruteLoss(25) //I can't use adjustHealth() here because bloodcrawl affects /mob/living and adjustHealth() only affects simple mobs
var/found_bloodpool = FALSE
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index f9dff7ad..e9a3538e 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -102,16 +102,16 @@
if(istype(O, /obj/item/organ_storage)) //BUG_PROBABLE_CAUSE
return //Borg organ bags shouldn't be killing brains
- if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent("neurine")) //Neurine fixes dead brains
+ if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent(/datum/reagent/medicine/neurine)) //Neurine fixes dead brains
. = TRUE //don't do attack animation.
var/cached_Bdamage = brainmob?.health
- var/datum/reagent/medicine/neurine/N = O.reagents.has_reagent("neurine")
- var/datum/reagent/medicine/mannitol/M1 = O.reagents.has_reagent("mannitol")
+ var/datum/reagent/medicine/neurine/N = reagents.has_reagent(/datum/reagent/medicine/neurine)
+ var/datum/reagent/medicine/mannitol/M1 = reagents.has_reagent(/datum/reagent/medicine/mannitol)
- if(O.reagents.has_reagent("mannitol"))//Just a quick way to bolster the effects if someone mixes up a batch.
+ if(O.reagents.has_reagent(/datum/reagent/medicine/mannitol))//Just a quick way to bolster the effects if someone mixes up a batch.
N.volume *= (M1.volume*0.5)
- if(!O.reagents.has_reagent("neurine", 10))
+ if(!O.reagents.has_reagent(/datum/reagent/medicine/neurine, 10))
to_chat(user, "There's not enough neurine in [O] to restore [src]!")
return
@@ -134,14 +134,14 @@
gain_trauma_type(BRAIN_TRAUMA_SPECIAL)
return
- if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent("mannitol")) //attempt to heal the brain
+ if((organ_flags & ORGAN_FAILING) && O.is_drainable() && O.reagents.has_reagent(/datum/reagent/medicine/mannitol)) //attempt to heal the brain
. = TRUE //don't do attack animation.
- var/datum/reagent/medicine/mannitol/M = O.reagents.has_reagent("mannitol")
+ var/datum/reagent/medicine/mannitol/M = reagents.has_reagent(/datum/reagent/medicine/mannitol)
if(brain_death || brainmob?.health <= HEALTH_THRESHOLD_DEAD) //if the brain is fucked anyway, do nothing
to_chat(user, "[src] is far too damaged, you'll have to use neurine on it!")
return
- if(!O.reagents.has_reagent("mannitol", 10))
+ if(!O.reagents.has_reagent(/datum/reagent/medicine/mannitol, 10))
to_chat(user, "There's not enough mannitol in [O] to restore [src]!")
return
diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm
index 7b696279..2994d5e3 100644
--- a/code/modules/mob/living/carbon/alien/organs.dm
+++ b/code/modules/mob/living/carbon/alien/organs.dm
@@ -27,7 +27,7 @@
/obj/item/organ/alien/prepare_eat()
var/obj/S = ..()
- S.reagents.add_reagent("sacid", 10)
+ S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
return S
@@ -46,7 +46,7 @@
/obj/item/organ/alien/plasmavessel/prepare_eat()
var/obj/S = ..()
- S.reagents.add_reagent("plasma", storedPlasma/10)
+ S.reagents.add_reagent(/datum/reagent/toxin/plasma, storedPlasma/10)
return S
/obj/item/organ/alien/plasmavessel/large
diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
index 22ad146d..4ada8834 100644
--- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
+++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm
@@ -1,137 +1,137 @@
-// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability
-// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
-/obj/item/organ/body_egg/alien_embryo
- name = "alien embryo"
- icon = 'icons/mob/alien.dmi'
- icon_state = "larva0_dead"
- var/stage = 0
- var/bursting = FALSE
-
-/obj/item/organ/body_egg/alien_embryo/on_find(mob/living/finder)
- ..()
- if(stage < 4)
- to_chat(finder, "It's small and weak, barely the size of a foetus.")
- else
- to_chat(finder, "It's grown quite large, and writhes slightly as you look at it.")
- if(prob(10))
- AttemptGrow(0)
-
-/obj/item/organ/body_egg/alien_embryo/prepare_eat()
- var/obj/S = ..()
- S.reagents.add_reagent("sacid", 10)
- return S
-
-/obj/item/organ/body_egg/alien_embryo/on_life()
- .=..()
- switch(stage)
- if(2, 3)
- if(prob(2))
- owner.emote("sneeze")
- if(prob(2))
- owner.emote("cough")
- if(prob(2))
- to_chat(owner, "Your throat feels sore.")
- if(prob(2))
- to_chat(owner, "Mucous runs down the back of your throat.")
- if(4)
- if(prob(2))
- owner.emote("sneeze")
- if(prob(2))
- owner.emote("cough")
- if(prob(4))
- to_chat(owner, "Your muscles ache.")
- if(prob(20))
- owner.take_bodypart_damage(1)
- if(prob(4))
- to_chat(owner, "Your stomach hurts.")
- if(prob(20))
- owner.adjustToxLoss(1)
- if(5)
- to_chat(owner, "You feel something tearing its way out of your stomach...")
- owner.adjustToxLoss(10)
-
-/obj/item/organ/body_egg/alien_embryo/egg_process()
- if(stage < 5 && prob(3))
- stage++
- INVOKE_ASYNC(src, .proc/RefreshInfectionImage)
-
- if(stage == 5 && prob(50))
- for(var/datum/surgery/S in owner.surgeries)
- if(S.location == BODY_ZONE_CHEST && istype(S.get_surgery_step(), /datum/surgery_step/manipulate_organs))
- AttemptGrow(0)
- return
- AttemptGrow()
-
-
-
-/obj/item/organ/body_egg/alien_embryo/proc/AttemptGrow(var/kill_on_sucess=TRUE)
- if(!owner || bursting)
- return
-
- bursting = TRUE
-
- var/list/candidates = pollGhostCandidates("Do you want to play as an alien larva that will burst out of [owner]?", ROLE_ALIEN, null, ROLE_ALIEN, 100, POLL_IGNORE_ALIEN_LARVA)
-
- if(QDELETED(src) || QDELETED(owner))
- return
-
- if(!candidates.len || !owner)
- bursting = FALSE
- stage = 4
- return
-
- var/mob/dead/observer/ghost = pick(candidates)
-
- var/mutable_appearance/overlay = mutable_appearance('icons/mob/alien.dmi', "burst_lie")
- owner.add_overlay(overlay)
-
- var/atom/xeno_loc = get_turf(owner)
- var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
- new_xeno.key = ghost.key
- SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
- new_xeno.canmove = 0 //so we don't move during the bursting animation
- new_xeno.notransform = 1
- new_xeno.invisibility = INVISIBILITY_MAXIMUM
-
- sleep(6)
-
- if(QDELETED(src) || QDELETED(owner))
- return
-
- if(new_xeno)
- new_xeno.canmove = 1
- new_xeno.notransform = 0
- new_xeno.invisibility = 0
-
- if(kill_on_sucess) //ITS TOO LATE
- new_xeno.visible_message("[new_xeno] bursts out of [owner]!", "You exit [owner], your previous host.", "You hear organic matter ripping and tearing!")
- owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
- owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
- owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
- else //When it is removed via surgery at a late stage, rather than forced.
- new_xeno.visible_message("[new_xeno] wriggles out of [owner]!", "You exit [owner], your previous host.")
- owner.adjustBruteLoss(40)
- owner.cut_overlay(overlay)
- qdel(src)
-
-
-/*----------------------------------------
-Proc: AddInfectionImages(C)
-Des: Adds the infection image to all aliens for this embryo
-----------------------------------------*/
-/obj/item/organ/body_egg/alien_embryo/AddInfectionImages()
- for(var/mob/living/carbon/alien/alien in GLOB.player_list)
- if(alien.client)
- var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
- alien.client.images += I
-
-/*----------------------------------------
-Proc: RemoveInfectionImage(C)
-Des: Removes all images from the mob infected by this embryo
-----------------------------------------*/
-/obj/item/organ/body_egg/alien_embryo/RemoveInfectionImages()
- for(var/mob/living/carbon/alien/alien in GLOB.player_list)
- if(alien.client)
- for(var/image/I in alien.client.images)
- if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
- qdel(I)
+// This is to replace the previous datum/disease/alien_embryo for slightly improved handling and maintainability
+// It functions almost identically (see code/datums/diseases/alien_embryo.dm)
+/obj/item/organ/body_egg/alien_embryo
+ name = "alien embryo"
+ icon = 'icons/mob/alien.dmi'
+ icon_state = "larva0_dead"
+ var/stage = 0
+ var/bursting = FALSE
+
+/obj/item/organ/body_egg/alien_embryo/on_find(mob/living/finder)
+ ..()
+ if(stage < 4)
+ to_chat(finder, "It's small and weak, barely the size of a foetus.")
+ else
+ to_chat(finder, "It's grown quite large, and writhes slightly as you look at it.")
+ if(prob(10))
+ AttemptGrow(0)
+
+/obj/item/organ/body_egg/alien_embryo/prepare_eat()
+ var/obj/S = ..()
+ S.reagents.add_reagent(/datum/reagent/toxin/acid, 10)
+ return S
+
+/obj/item/organ/body_egg/alien_embryo/on_life()
+ .=..()
+ switch(stage)
+ if(2, 3)
+ if(prob(2))
+ owner.emote("sneeze")
+ if(prob(2))
+ owner.emote("cough")
+ if(prob(2))
+ to_chat(owner, "Your throat feels sore.")
+ if(prob(2))
+ to_chat(owner, "Mucous runs down the back of your throat.")
+ if(4)
+ if(prob(2))
+ owner.emote("sneeze")
+ if(prob(2))
+ owner.emote("cough")
+ if(prob(4))
+ to_chat(owner, "Your muscles ache.")
+ if(prob(20))
+ owner.take_bodypart_damage(1)
+ if(prob(4))
+ to_chat(owner, "Your stomach hurts.")
+ if(prob(20))
+ owner.adjustToxLoss(1)
+ if(5)
+ to_chat(owner, "You feel something tearing its way out of your stomach...")
+ owner.adjustToxLoss(10)
+
+/obj/item/organ/body_egg/alien_embryo/egg_process()
+ if(stage < 5 && prob(3))
+ stage++
+ INVOKE_ASYNC(src, .proc/RefreshInfectionImage)
+
+ if(stage == 5 && prob(50))
+ for(var/datum/surgery/S in owner.surgeries)
+ if(S.location == BODY_ZONE_CHEST && istype(S.get_surgery_step(), /datum/surgery_step/manipulate_organs))
+ AttemptGrow(0)
+ return
+ AttemptGrow()
+
+
+
+/obj/item/organ/body_egg/alien_embryo/proc/AttemptGrow(var/kill_on_sucess=TRUE)
+ if(!owner || bursting)
+ return
+
+ bursting = TRUE
+
+ var/list/candidates = pollGhostCandidates("Do you want to play as an alien larva that will burst out of [owner]?", ROLE_ALIEN, null, ROLE_ALIEN, 100, POLL_IGNORE_ALIEN_LARVA)
+
+ if(QDELETED(src) || QDELETED(owner))
+ return
+
+ if(!candidates.len || !owner)
+ bursting = FALSE
+ stage = 4
+ return
+
+ var/mob/dead/observer/ghost = pick(candidates)
+
+ var/mutable_appearance/overlay = mutable_appearance('icons/mob/alien.dmi', "burst_lie")
+ owner.add_overlay(overlay)
+
+ var/atom/xeno_loc = get_turf(owner)
+ var/mob/living/carbon/alien/larva/new_xeno = new(xeno_loc)
+ new_xeno.key = ghost.key
+ SEND_SOUND(new_xeno, sound('sound/voice/hiss5.ogg',0,0,0,100)) //To get the player's attention
+ new_xeno.canmove = 0 //so we don't move during the bursting animation
+ new_xeno.notransform = 1
+ new_xeno.invisibility = INVISIBILITY_MAXIMUM
+
+ sleep(6)
+
+ if(QDELETED(src) || QDELETED(owner))
+ return
+
+ if(new_xeno)
+ new_xeno.canmove = 1
+ new_xeno.notransform = 0
+ new_xeno.invisibility = 0
+
+ if(kill_on_sucess) //ITS TOO LATE
+ new_xeno.visible_message("[new_xeno] bursts out of [owner]!", "You exit [owner], your previous host.", "You hear organic matter ripping and tearing!")
+ owner.apply_damage(rand(100,300),BRUTE,zone,FALSE) //Random high damage to torso so health sensors don't metagame.
+ owner.spill_organs(TRUE,FALSE,TRUE) //Lets still make the death gruesome and impossible to just simply defib someone.
+ owner.death(FALSE) //Just in case some freak occurance occurs where you somehow survive all your organs being removed from you and the 100-300 brute damage.
+ else //When it is removed via surgery at a late stage, rather than forced.
+ new_xeno.visible_message("[new_xeno] wriggles out of [owner]!", "You exit [owner], your previous host.")
+ owner.adjustBruteLoss(40)
+ owner.cut_overlay(overlay)
+ qdel(src)
+
+
+/*----------------------------------------
+Proc: AddInfectionImages(C)
+Des: Adds the infection image to all aliens for this embryo
+----------------------------------------*/
+/obj/item/organ/body_egg/alien_embryo/AddInfectionImages()
+ for(var/mob/living/carbon/alien/alien in GLOB.player_list)
+ if(alien.client)
+ var/I = image('icons/mob/alien.dmi', loc = owner, icon_state = "infected[stage]")
+ alien.client.images += I
+
+/*----------------------------------------
+Proc: RemoveInfectionImage(C)
+Des: Removes all images from the mob infected by this embryo
+----------------------------------------*/
+/obj/item/organ/body_egg/alien_embryo/RemoveInfectionImages()
+ for(var/mob/living/carbon/alien/alien in GLOB.player_list)
+ if(alien.client)
+ for(var/image/I in alien.client.images)
+ if(dd_hasprefix_case(I.icon_state, "infected") && I.loc == owner)
+ qdel(I)
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 60010a92..32f9ef73 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -518,7 +518,7 @@
add_splatter_floor(T)
if(stun)
adjustBruteLoss(3)
- else if(src.reagents.has_reagent("blazaam"))
+ else if(src.reagents.has_reagent(/datum/reagent/consumable/ethanol/blazaam))
if(T)
T.add_vomit_floor(src, VOMIT_PURPLE)
else
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index fa6cc85f..d75da018 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -1,486 +1,486 @@
-
-/mob/living/carbon/get_eye_protection()
- var/number = ..()
-
- if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
- var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
- number += HFP.flash_protect
-
- if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
- var/obj/item/clothing/glasses/GFP = src.glasses
- number += GFP.flash_protect
-
- if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
- var/obj/item/clothing/mask/MFP = src.wear_mask
- number += MFP.flash_protect
-
- var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
- if(!E)
- number = INFINITY //Can't get flashed without eyes
- else
- number += E.flash_protect
-
- return number
-
-/mob/living/carbon/get_ear_protection()
- var/number = ..()
- var/obj/item/organ/ears/E = getorganslot(ORGAN_SLOT_EARS)
- if(!E)
- number = INFINITY
- else
- number += E.bang_protect
- return number
-
-/mob/living/carbon/is_mouth_covered(head_only = 0, mask_only = 0)
- if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
- return TRUE
-
-/mob/living/carbon/is_eyes_covered(check_glasses = 1, check_head = 1, check_mask = 1)
- if(check_glasses && glasses && (glasses.flags_cover & GLASSESCOVERSEYES))
- return TRUE
- if(check_head && head && (head.flags_cover & HEADCOVERSEYES))
- return TRUE
- if(check_mask && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH))
- return TRUE
-
-/mob/living/carbon/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
- var/obj/item/bodypart/affecting = get_bodypart(def_zone)
- if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
- affecting.dismember(P.damtype)
-
-/mob/living/carbon/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
- . = ..()
- if(!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) && !skip_throw_mode_check && !in_throw_mode)
- return
- if(get_active_held_item() || restrained())
- return
- I.attack_hand(src)
- if(get_active_held_item() == I) //if our attack_hand() picks up the item...
- visible_message("[src] catches [I]!") //catch that sucker!
- throw_mode_off()
- return TRUE
-
-/mob/living/carbon/embed_item(obj/item/I)
- throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
- var/obj/item/bodypart/L = pick(bodyparts)
- L.embedded_objects |= I
- I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
- I.forceMove(src)
- L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
- visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
-
-/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
- //CIT CHANGES START HERE - combatmode and resting checks
- var/totitemdamage = I.force
- if(iscarbon(user))
- var/mob/living/carbon/tempcarb = user
- if(!tempcarb.combatmode)
- totitemdamage *= 0.5
- if(user.resting)
- totitemdamage *= 0.5
- if(!combatmode)
- totitemdamage *= 1.5
- //CIT CHANGES END HERE
- if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
- return FALSE
- var/obj/item/bodypart/affecting
- if(user == src)
- affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay!
- else
- affecting = get_bodypart(ran_zone(user.zone_selected))
- if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
- affecting = bodyparts[1]
- SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
- send_item_attack_message(I, user, affecting.name)
- if(I.force)
- apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
- if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
- var/basebloodychance = affecting.brute_dam + totitemdamage
- if(prob(basebloodychance))
- I.add_mob_blood(src)
- bleed(totitemdamage)
- if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
- user.add_mob_blood(src)
-
- if(affecting.body_zone == BODY_ZONE_HEAD)
- if(wear_mask && prob(basebloodychance))
- wear_mask.add_mob_blood(src)
- update_inv_wear_mask()
- if(wear_neck && prob(basebloodychance))
- wear_neck.add_mob_blood(src)
- update_inv_neck()
- if(head && prob(basebloodychance))
- head.add_mob_blood(src)
- update_inv_head()
-
- //dismemberment
- var/probability = I.get_dismemberment_chance(affecting)
- if(prob(probability))
- if(affecting.dismember(I.damtype))
- I.add_mob_blood(src)
- playsound(get_turf(src), I.get_dismember_sound(), 80, 1)
- return TRUE //successful attack
-
-/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user)
- return //so we don't call the carbon's attack_hand().
-
-//ATTACK HAND IGNORING PARENT RETURN VALUE
-/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
- . = ..()
- if(.) //was the attack blocked?
- return
- for(var/thing in diseases)
- var/datum/disease/D = thing
- if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
- user.ContactContractDisease(D)
-
- for(var/thing in user.diseases)
- var/datum/disease/D = thing
- if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
- ContactContractDisease(D)
-
- if(lying && surgeries.len)
- if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
- for(var/datum/surgery/S in surgeries)
- if(S.next_step(user, user.a_intent))
- return TRUE
-
-
-/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
-
- if(can_inject(M, TRUE))
- for(var/thing in diseases)
- var/datum/disease/D = thing
- if((D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) && prob(85))
- M.ContactContractDisease(D)
-
- for(var/thing in M.diseases)
- var/datum/disease/D = thing
- if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
- ContactContractDisease(D)
-
- if(M.a_intent == INTENT_HELP)
- help_shake_act(M)
- return 0
-
- . = ..()
- if(.) //successful monkey bite.
- for(var/thing in M.diseases)
- var/datum/disease/D = thing
- ForceContractDisease(D)
- return 1
-
-
-/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
- . = ..()
- if(!.)
- return
- if(M.powerlevel > 0)
- var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
- if(prob(stunprob))
- M.powerlevel -= 3
- if(M.powerlevel < 0)
- M.powerlevel = 0
-
- visible_message("The [M.name] has shocked [src]!", \
- "The [M.name] has shocked [src]!")
-
- do_sparks(5, TRUE, src)
- var/power = M.powerlevel + rand(0,3)
- Knockdown(power*20)
- if(stuttering < power)
- stuttering = power
- if (prob(stunprob) && M.powerlevel >= 8)
- adjustFireLoss(M.powerlevel * rand(6,10))
- updatehealth()
-
-/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
- if(!attacker.limb_destroyer)
- return dam_zone
- var/obj/item/bodypart/affecting
- if(dam_zone && attacker.client)
- affecting = get_bodypart(ran_zone(dam_zone))
- else
- var/list/things_to_ruin = shuffle(bodyparts.Copy())
- for(var/B in things_to_ruin)
- var/obj/item/bodypart/bodypart = B
- if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST)
- continue
- if(!affecting || ((affecting.get_damage() / affecting.max_damage) < (bodypart.get_damage() / bodypart.max_damage)))
- affecting = bodypart
- if(affecting)
- dam_zone = affecting.body_zone
- if(affecting.get_damage() >= affecting.max_damage)
- affecting.dismember()
- return null
- return affecting.body_zone
- return dam_zone
-
-
-/mob/living/carbon/blob_act(obj/structure/blob/B)
- if (stat == DEAD)
- return
- else
- show_message("The blob attacks!")
- adjustBruteLoss(10)
-
-/mob/living/carbon/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_CONTENTS)
- return
- for(var/X in internal_organs)
- var/obj/item/organ/O = X
- O.emp_act(severity)
-
-/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
- if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
- return FALSE
- if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
- return FALSE
- shock_damage *= siemens_coeff
- if(dna && dna.species)
- shock_damage *= dna.species.siemens_coeff
- if(shock_damage<1 && !override)
- return 0
- if(reagents.has_reagent("teslium"))
- shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
- if(illusion)
- adjustStaminaLoss(shock_damage)
- else
- take_overall_damage(0,shock_damage)
- visible_message(
- "[src] was shocked by \the [source]!", \
- "You feel a powerful shock coursing through your body!", \
- "You hear a heavy electrical crack." \
- )
- jitteriness += 1000 //High numbers for violent convulsions
- do_jitter_animation(jitteriness)
- stuttering += 2
- if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
- Stun(40)
- spawn(20)
- jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
- if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
- Knockdown(60)
- if(override)
- return override
- else
- return shock_damage
-
-/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
- if(on_fire)
- to_chat(M, "You can't put [p_them()] out with just your bare hands!")
- return
-
- if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
-
- if(lying)
- if(buckled)
- to_chat(M, "You need to unbuckle [src] first to do that!")
- return
- M.visible_message("[M] shakes [src] trying to get [p_them()] up!", \
- "You shake [src] trying to get [p_them()] up!")
-
- else if(check_zone(M.zone_selected) == "head")
- var/mob/living/carbon/human/H = src
- var/datum/species/pref_species = H.dna.species
-
- if(HAS_TRAIT(H, TRAIT_HEADPAT_SLUT))
- M.visible_message("[M] gives [H] a pat on the head to make [p_them()] feel better! They seem incredibly pleased!", \
- "You give [H] a pat on the head to make [p_them()] feel better! They seem to like it way too much")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "lewd_headpat", /datum/mood_event/lewd_headpat)
- H.adjustArousalLoss(5) //Headpats are hot af
- else
- M.visible_message("[M] gives [H] a pat on the head to make [p_them()] feel better!", \
- "You give [H] a pat on the head to make [p_them()] feel better!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
-
- if(HAS_TRAIT(M, TRAIT_FRIENDLY))
- var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
- if (mood.sanity >= SANITY_GREAT)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
- else if (mood.sanity >= SANITY_DISTURBED)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
- if(H.dna.species.can_wag_tail(H))
- if("tail_human" in pref_species.default_features)
- if(H.dna.features["tail_human"] == "None")
- return
- else
- if(!H.dna.species.is_wagging_tail())
- H.emote("wag")
-
- if("tail_lizard" in pref_species.default_features)
- if(H.dna.features["tail_lizard"] == "None")
- return
- else
- if(!H.dna.species.is_wagging_tail())
- H.emote("wag")
-
- if("mam_tail" in pref_species.default_features)
- if(H.dna.features["mam_tail"] == "None")
- return
- else
- if(!H.dna.species.is_wagging_tail())
- H.emote("wag")
-
- else
- return
-
-
- else if(check_zone(M.zone_selected) == "mouth")
- var/mob/living/carbon/human/H = src
- var/datum/species/pref_species = H.dna.species
-
- M.visible_message("[M] gives [H] a boop on the nose.", \
- "You give [H] a boop on the nose!")
-
- if(H.dna.species.can_wag_tail(H))
- if("tail_human" in pref_species.default_features)
- if(H.dna.features["tail_human"] == "None")
- return
- else
- if(!H.dna.species.is_wagging_tail())
- H.emote("wag")
-
- if("tail_lizard" in pref_species.default_features)
- if(H.dna.features["tail_lizard"] == "None")
- return
- else
- if(!H.dna.species.is_wagging_tail())
- H.emote("wag")
-
- if("mam_tail" in pref_species.default_features)
- if(H.dna.features["mam_tail"] == "None")
- return
- else
- if(!H.dna.species.is_wagging_tail())
- H.emote("wag")
-
- else
- return
-
-
- else
- M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \
- "You hug [src] to make [p_them()] feel better!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
- if(HAS_TRAIT(M, TRAIT_FRIENDLY))
- var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
- if (mood.sanity >= SANITY_GREAT)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
- else if (mood.sanity >= SANITY_DISTURBED)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
-
- AdjustStun(-60)
- AdjustKnockdown(-60)
- AdjustUnconscious(-60)
- AdjustSleeping(-100)
- if(recoveringstam)
- adjustStaminaLoss(-15)
- else if(resting)
- resting = 0
- update_canmove()
-
- playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
-
-/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
- . = ..()
-
- var/damage = intensity - get_eye_protection()
- if(.) // we've been flashed
- var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
- if (!eyes)
- return
- if(visual)
- return
-
- if (damage == 1)
- to_chat(src, "Your eyes sting a little.")
- if(prob(40))
- adjust_eye_damage(1)
-
- else if (damage == 2)
- to_chat(src, "Your eyes burn.")
- adjust_eye_damage(rand(2, 4))
-
- else if( damage >= 3)
- to_chat(src, "Your eyes itch and burn severely!")
- adjust_eye_damage(rand(12, 16))
-
- if(eyes.eye_damage > 10)
- blind_eyes(damage)
- blur_eyes(damage * rand(3, 6))
-
- if(eyes.eye_damage > 20)
- if(prob(eyes.eye_damage - 20))
- if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
- to_chat(src, "Your eyes start to burn badly!")
- become_nearsighted(EYE_DAMAGE)
-
- else if(prob(eyes.eye_damage - 25))
- if(!HAS_TRAIT(src, TRAIT_BLIND))
- to_chat(src, "You can't see anything!")
- become_blind(EYE_DAMAGE)
-
- else
- to_chat(src, "Your eyes are really starting to hurt. This can't be good for you!")
- if(has_bane(BANE_LIGHT))
- mind.disrupt_spells(-500)
- return 1
- else if(damage == 0) // just enough protection
- if(prob(20))
- to_chat(src, "Something bright flashes in the corner of your vision!")
- if(has_bane(BANE_LIGHT))
- mind.disrupt_spells(0)
-
-
-/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 20, damage_pwr = 5, deafen_pwr = 15)
- var/list/reflist = list(intensity) // Need to wrap this in a list so we can pass a reference
- SEND_SIGNAL(src, COMSIG_CARBON_SOUNDBANG, reflist)
- intensity = reflist[1]
- var/ear_safety = get_ear_protection()
- var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
- var/effect_amount = intensity - ear_safety
- if(effect_amount > 0)
- if(stun_pwr)
- Knockdown(stun_pwr*effect_amount)
-
- if(istype(ears) && (deafen_pwr || damage_pwr))
- var/ear_damage = damage_pwr * effect_amount
- var/deaf = deafen_pwr * effect_amount
- adjustEarDamage(ear_damage,deaf)
-
- if(ears.damage >= 15)
- to_chat(src, "Your ears start to ring badly!")
- if(prob(ears.damage - 5))
- to_chat(src, "You can't hear anything!")
- ears.damage = min(ears.damage, ears.maxHealth)
- // you need earmuffs, inacusiate, or replacement
- else if(ears.damage >= 5)
- to_chat(src, "Your ears start to ring!")
- SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250))
- return effect_amount //how soundbanged we are
-
-
-/mob/living/carbon/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
- if(damage_type != BRUTE && damage_type != BURN)
- return
- damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed
- if(!def_zone || def_zone == BODY_ZONE_HEAD)
- var/obj/item/clothing/hit_clothes
- if(wear_mask)
- hit_clothes = wear_mask
- if(wear_neck)
- hit_clothes = wear_neck
- if(head)
- hit_clothes = head
- if(hit_clothes)
- hit_clothes.take_damage(damage_amount, damage_type, damage_flag, 0)
-
-/mob/living/carbon/can_hear()
- . = FALSE
- var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
- if(istype(ears) && !ears.deaf)
- . = TRUE
+
+/mob/living/carbon/get_eye_protection()
+ var/number = ..()
+
+ if(istype(src.head, /obj/item/clothing/head)) //are they wearing something on their head
+ var/obj/item/clothing/head/HFP = src.head //if yes gets the flash protection value from that item
+ number += HFP.flash_protect
+
+ if(istype(src.glasses, /obj/item/clothing/glasses)) //glasses
+ var/obj/item/clothing/glasses/GFP = src.glasses
+ number += GFP.flash_protect
+
+ if(istype(src.wear_mask, /obj/item/clothing/mask)) //mask
+ var/obj/item/clothing/mask/MFP = src.wear_mask
+ number += MFP.flash_protect
+
+ var/obj/item/organ/eyes/E = getorganslot(ORGAN_SLOT_EYES)
+ if(!E)
+ number = INFINITY //Can't get flashed without eyes
+ else
+ number += E.flash_protect
+
+ return number
+
+/mob/living/carbon/get_ear_protection()
+ var/number = ..()
+ var/obj/item/organ/ears/E = getorganslot(ORGAN_SLOT_EARS)
+ if(!E)
+ number = INFINITY
+ else
+ number += E.bang_protect
+ return number
+
+/mob/living/carbon/is_mouth_covered(head_only = 0, mask_only = 0)
+ if( (!mask_only && head && (head.flags_cover & HEADCOVERSMOUTH)) || (!head_only && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH)) )
+ return TRUE
+
+/mob/living/carbon/is_eyes_covered(check_glasses = 1, check_head = 1, check_mask = 1)
+ if(check_glasses && glasses && (glasses.flags_cover & GLASSESCOVERSEYES))
+ return TRUE
+ if(check_head && head && (head.flags_cover & HEADCOVERSEYES))
+ return TRUE
+ if(check_mask && wear_mask && (wear_mask.flags_cover & MASKCOVERSMOUTH))
+ return TRUE
+
+/mob/living/carbon/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
+ var/obj/item/bodypart/affecting = get_bodypart(def_zone)
+ if(affecting && affecting.dismemberable && affecting.get_damage() >= (affecting.max_damage - P.dismemberment))
+ affecting.dismember(P.damtype)
+
+/mob/living/carbon/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
+ . = ..()
+ if(!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) && !skip_throw_mode_check && !in_throw_mode)
+ return
+ if(get_active_held_item() || restrained())
+ return
+ I.attack_hand(src)
+ if(get_active_held_item() == I) //if our attack_hand() picks up the item...
+ visible_message("[src] catches [I]!") //catch that sucker!
+ throw_mode_off()
+ return TRUE
+
+/mob/living/carbon/embed_item(obj/item/I)
+ throw_alert("embeddedobject", /obj/screen/alert/embeddedobject)
+ var/obj/item/bodypart/L = pick(bodyparts)
+ L.embedded_objects |= I
+ I.add_mob_blood(src)//it embedded itself in you, of course it's bloody!
+ I.forceMove(src)
+ L.receive_damage(I.w_class*I.embedding.embedded_impact_pain_multiplier)
+ visible_message("[I] embeds itself in [src]'s [L.name]!","[I] embeds itself in your [L.name]!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "embedded", /datum/mood_event/embedded)
+
+/mob/living/carbon/attacked_by(obj/item/I, mob/living/user)
+ //CIT CHANGES START HERE - combatmode and resting checks
+ var/totitemdamage = I.force
+ if(iscarbon(user))
+ var/mob/living/carbon/tempcarb = user
+ if(!tempcarb.combatmode)
+ totitemdamage *= 0.5
+ if(user.resting)
+ totitemdamage *= 0.5
+ if(!combatmode)
+ totitemdamage *= 1.5
+ //CIT CHANGES END HERE
+ if(user != src && check_shields(I, totitemdamage, "the [I.name]", MELEE_ATTACK, I.armour_penetration))
+ return FALSE
+ var/obj/item/bodypart/affecting
+ if(user == src)
+ affecting = get_bodypart(check_zone(user.zone_selected)) //we're self-mutilating! yay!
+ else
+ affecting = get_bodypart(ran_zone(user.zone_selected))
+ if(!affecting) //missing limb? we select the first bodypart (you can never have zero, because of chest)
+ affecting = bodyparts[1]
+ SEND_SIGNAL(I, COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
+ send_item_attack_message(I, user, affecting.name)
+ if(I.force)
+ apply_damage(totitemdamage, I.damtype, affecting) //CIT CHANGE - replaces I.force with totitemdamage
+ if(I.damtype == BRUTE && affecting.status == BODYPART_ORGANIC)
+ var/basebloodychance = affecting.brute_dam + totitemdamage
+ if(prob(basebloodychance))
+ I.add_mob_blood(src)
+ bleed(totitemdamage)
+ if(totitemdamage >= 10 && get_dist(user, src) <= 1) //people with TK won't get smeared with blood
+ user.add_mob_blood(src)
+
+ if(affecting.body_zone == BODY_ZONE_HEAD)
+ if(wear_mask && prob(basebloodychance))
+ wear_mask.add_mob_blood(src)
+ update_inv_wear_mask()
+ if(wear_neck && prob(basebloodychance))
+ wear_neck.add_mob_blood(src)
+ update_inv_neck()
+ if(head && prob(basebloodychance))
+ head.add_mob_blood(src)
+ update_inv_head()
+
+ //dismemberment
+ var/probability = I.get_dismemberment_chance(affecting)
+ if(prob(probability))
+ if(affecting.dismember(I.damtype))
+ I.add_mob_blood(src)
+ playsound(get_turf(src), I.get_dismember_sound(), 80, 1)
+ return TRUE //successful attack
+
+/mob/living/carbon/attack_drone(mob/living/simple_animal/drone/user)
+ return //so we don't call the carbon's attack_hand().
+
+//ATTACK HAND IGNORING PARENT RETURN VALUE
+/mob/living/carbon/attack_hand(mob/living/carbon/human/user)
+ . = ..()
+ if(.) //was the attack blocked?
+ return
+ for(var/thing in diseases)
+ var/datum/disease/D = thing
+ if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
+ user.ContactContractDisease(D)
+
+ for(var/thing in user.diseases)
+ var/datum/disease/D = thing
+ if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
+ ContactContractDisease(D)
+
+ if(lying && surgeries.len)
+ if(user.a_intent == INTENT_HELP || user.a_intent == INTENT_DISARM)
+ for(var/datum/surgery/S in surgeries)
+ if(S.next_step(user, user.a_intent))
+ return TRUE
+
+
+/mob/living/carbon/attack_paw(mob/living/carbon/monkey/M)
+
+ if(can_inject(M, TRUE))
+ for(var/thing in diseases)
+ var/datum/disease/D = thing
+ if((D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN) && prob(85))
+ M.ContactContractDisease(D)
+
+ for(var/thing in M.diseases)
+ var/datum/disease/D = thing
+ if(D.spread_flags & DISEASE_SPREAD_CONTACT_SKIN)
+ ContactContractDisease(D)
+
+ if(M.a_intent == INTENT_HELP)
+ help_shake_act(M)
+ return 0
+
+ . = ..()
+ if(.) //successful monkey bite.
+ for(var/thing in M.diseases)
+ var/datum/disease/D = thing
+ ForceContractDisease(D)
+ return 1
+
+
+/mob/living/carbon/attack_slime(mob/living/simple_animal/slime/M)
+ . = ..()
+ if(!.)
+ return
+ if(M.powerlevel > 0)
+ var/stunprob = M.powerlevel * 7 + 10 // 17 at level 1, 80 at level 10
+ if(prob(stunprob))
+ M.powerlevel -= 3
+ if(M.powerlevel < 0)
+ M.powerlevel = 0
+
+ visible_message("The [M.name] has shocked [src]!", \
+ "The [M.name] has shocked [src]!")
+
+ do_sparks(5, TRUE, src)
+ var/power = M.powerlevel + rand(0,3)
+ Knockdown(power*20)
+ if(stuttering < power)
+ stuttering = power
+ if (prob(stunprob) && M.powerlevel >= 8)
+ adjustFireLoss(M.powerlevel * rand(6,10))
+ updatehealth()
+
+/mob/living/carbon/proc/dismembering_strike(mob/living/attacker, dam_zone)
+ if(!attacker.limb_destroyer)
+ return dam_zone
+ var/obj/item/bodypart/affecting
+ if(dam_zone && attacker.client)
+ affecting = get_bodypart(ran_zone(dam_zone))
+ else
+ var/list/things_to_ruin = shuffle(bodyparts.Copy())
+ for(var/B in things_to_ruin)
+ var/obj/item/bodypart/bodypart = B
+ if(bodypart.body_zone == BODY_ZONE_HEAD || bodypart.body_zone == BODY_ZONE_CHEST)
+ continue
+ if(!affecting || ((affecting.get_damage() / affecting.max_damage) < (bodypart.get_damage() / bodypart.max_damage)))
+ affecting = bodypart
+ if(affecting)
+ dam_zone = affecting.body_zone
+ if(affecting.get_damage() >= affecting.max_damage)
+ affecting.dismember()
+ return null
+ return affecting.body_zone
+ return dam_zone
+
+
+/mob/living/carbon/blob_act(obj/structure/blob/B)
+ if (stat == DEAD)
+ return
+ else
+ show_message("The blob attacks!")
+ adjustBruteLoss(10)
+
+/mob/living/carbon/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_CONTENTS)
+ return
+ for(var/X in internal_organs)
+ var/obj/item/organ/O = X
+ O.emp_act(severity)
+
+/mob/living/carbon/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, override = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
+ if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
+ return FALSE
+ if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
+ return FALSE
+ shock_damage *= siemens_coeff
+ if(dna && dna.species)
+ shock_damage *= dna.species.siemens_coeff
+ if(shock_damage<1 && !override)
+ return 0
+ if(reagents.has_reagent(/datum/reagent/teslium))
+ shock_damage *= 1.5 //If the mob has teslium in their body, shocks are 50% more damaging!
+ if(illusion)
+ adjustStaminaLoss(shock_damage)
+ else
+ take_overall_damage(0,shock_damage)
+ visible_message(
+ "[src] was shocked by \the [source]!", \
+ "You feel a powerful shock coursing through your body!", \
+ "You hear a heavy electrical crack." \
+ )
+ jitteriness += 1000 //High numbers for violent convulsions
+ do_jitter_animation(jitteriness)
+ stuttering += 2
+ if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
+ Stun(40)
+ spawn(20)
+ jitteriness = max(jitteriness - 990, 10) //Still jittery, but vastly less
+ if((!tesla_shock || (tesla_shock && siemens_coeff > 0.5)) && stun)
+ Knockdown(60)
+ if(override)
+ return override
+ else
+ return shock_damage
+
+/mob/living/carbon/proc/help_shake_act(mob/living/carbon/M)
+ if(on_fire)
+ to_chat(M, "You can't put [p_them()] out with just your bare hands!")
+ return
+
+ if(health >= 0 && !(HAS_TRAIT(src, TRAIT_FAKEDEATH)))
+
+ if(lying)
+ if(buckled)
+ to_chat(M, "You need to unbuckle [src] first to do that!")
+ return
+ M.visible_message("[M] shakes [src] trying to get [p_them()] up!", \
+ "You shake [src] trying to get [p_them()] up!")
+
+ else if(check_zone(M.zone_selected) == "head")
+ var/mob/living/carbon/human/H = src
+ var/datum/species/pref_species = H.dna.species
+
+ if(HAS_TRAIT(H, TRAIT_HEADPAT_SLUT))
+ M.visible_message("[M] gives [H] a pat on the head to make [p_them()] feel better! They seem incredibly pleased!", \
+ "You give [H] a pat on the head to make [p_them()] feel better! They seem to like it way too much")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "lewd_headpat", /datum/mood_event/lewd_headpat)
+ H.adjustArousalLoss(5) //Headpats are hot af
+ else
+ M.visible_message("[M] gives [H] a pat on the head to make [p_them()] feel better!", \
+ "You give [H] a pat on the head to make [p_them()] feel better!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
+
+ if(HAS_TRAIT(M, TRAIT_FRIENDLY))
+ var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
+ if (mood.sanity >= SANITY_GREAT)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
+ else if (mood.sanity >= SANITY_DISTURBED)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
+ if(H.dna.species.can_wag_tail(H))
+ if("tail_human" in pref_species.default_features)
+ if(H.dna.features["tail_human"] == "None")
+ return
+ else
+ if(!H.dna.species.is_wagging_tail())
+ H.emote("wag")
+
+ if("tail_lizard" in pref_species.default_features)
+ if(H.dna.features["tail_lizard"] == "None")
+ return
+ else
+ if(!H.dna.species.is_wagging_tail())
+ H.emote("wag")
+
+ if("mam_tail" in pref_species.default_features)
+ if(H.dna.features["mam_tail"] == "None")
+ return
+ else
+ if(!H.dna.species.is_wagging_tail())
+ H.emote("wag")
+
+ else
+ return
+
+
+ else if(check_zone(M.zone_selected) == "mouth")
+ var/mob/living/carbon/human/H = src
+ var/datum/species/pref_species = H.dna.species
+
+ M.visible_message("[M] gives [H] a boop on the nose.", \
+ "You give [H] a boop on the nose!")
+
+ if(H.dna.species.can_wag_tail(H))
+ if("tail_human" in pref_species.default_features)
+ if(H.dna.features["tail_human"] == "None")
+ return
+ else
+ if(!H.dna.species.is_wagging_tail())
+ H.emote("wag")
+
+ if("tail_lizard" in pref_species.default_features)
+ if(H.dna.features["tail_lizard"] == "None")
+ return
+ else
+ if(!H.dna.species.is_wagging_tail())
+ H.emote("wag")
+
+ if("mam_tail" in pref_species.default_features)
+ if(H.dna.features["mam_tail"] == "None")
+ return
+ else
+ if(!H.dna.species.is_wagging_tail())
+ H.emote("wag")
+
+ else
+ return
+
+
+ else
+ M.visible_message("[M] hugs [src] to make [p_them()] feel better!", \
+ "You hug [src] to make [p_them()] feel better!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "hug", /datum/mood_event/hug)
+ if(HAS_TRAIT(M, TRAIT_FRIENDLY))
+ var/datum/component/mood/mood = M.GetComponent(/datum/component/mood)
+ if (mood.sanity >= SANITY_GREAT)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/besthug, M)
+ else if (mood.sanity >= SANITY_DISTURBED)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "friendly_hug", /datum/mood_event/betterhug, M)
+
+ AdjustStun(-60)
+ AdjustKnockdown(-60)
+ AdjustUnconscious(-60)
+ AdjustSleeping(-100)
+ if(recoveringstam)
+ adjustStaminaLoss(-15)
+ else if(resting)
+ resting = 0
+ update_canmove()
+
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
+
+/mob/living/carbon/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0)
+ . = ..()
+
+ var/damage = intensity - get_eye_protection()
+ if(.) // we've been flashed
+ var/obj/item/organ/eyes/eyes = getorganslot(ORGAN_SLOT_EYES)
+ if (!eyes)
+ return
+ if(visual)
+ return
+
+ if (damage == 1)
+ to_chat(src, "Your eyes sting a little.")
+ if(prob(40))
+ adjust_eye_damage(1)
+
+ else if (damage == 2)
+ to_chat(src, "Your eyes burn.")
+ adjust_eye_damage(rand(2, 4))
+
+ else if( damage >= 3)
+ to_chat(src, "Your eyes itch and burn severely!")
+ adjust_eye_damage(rand(12, 16))
+
+ if(eyes.eye_damage > 10)
+ blind_eyes(damage)
+ blur_eyes(damage * rand(3, 6))
+
+ if(eyes.eye_damage > 20)
+ if(prob(eyes.eye_damage - 20))
+ if(!HAS_TRAIT(src, TRAIT_NEARSIGHT))
+ to_chat(src, "Your eyes start to burn badly!")
+ become_nearsighted(EYE_DAMAGE)
+
+ else if(prob(eyes.eye_damage - 25))
+ if(!HAS_TRAIT(src, TRAIT_BLIND))
+ to_chat(src, "You can't see anything!")
+ become_blind(EYE_DAMAGE)
+
+ else
+ to_chat(src, "Your eyes are really starting to hurt. This can't be good for you!")
+ if(has_bane(BANE_LIGHT))
+ mind.disrupt_spells(-500)
+ return 1
+ else if(damage == 0) // just enough protection
+ if(prob(20))
+ to_chat(src, "Something bright flashes in the corner of your vision!")
+ if(has_bane(BANE_LIGHT))
+ mind.disrupt_spells(0)
+
+
+/mob/living/carbon/soundbang_act(intensity = 1, stun_pwr = 20, damage_pwr = 5, deafen_pwr = 15)
+ var/list/reflist = list(intensity) // Need to wrap this in a list so we can pass a reference
+ SEND_SIGNAL(src, COMSIG_CARBON_SOUNDBANG, reflist)
+ intensity = reflist[1]
+ var/ear_safety = get_ear_protection()
+ var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
+ var/effect_amount = intensity - ear_safety
+ if(effect_amount > 0)
+ if(stun_pwr)
+ Knockdown(stun_pwr*effect_amount)
+
+ if(istype(ears) && (deafen_pwr || damage_pwr))
+ var/ear_damage = damage_pwr * effect_amount
+ var/deaf = deafen_pwr * effect_amount
+ adjustEarDamage(ear_damage,deaf)
+
+ if(ears.damage >= 15)
+ to_chat(src, "Your ears start to ring badly!")
+ if(prob(ears.damage - 5))
+ to_chat(src, "You can't hear anything!")
+ ears.damage = min(ears.damage, ears.maxHealth)
+ // you need earmuffs, inacusiate, or replacement
+ else if(ears.damage >= 5)
+ to_chat(src, "Your ears start to ring!")
+ SEND_SOUND(src, sound('sound/weapons/flash_ring.ogg',0,1,0,250))
+ return effect_amount //how soundbanged we are
+
+
+/mob/living/carbon/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
+ if(damage_type != BRUTE && damage_type != BURN)
+ return
+ damage_amount *= 0.5 //0.5 multiplier for balance reason, we don't want clothes to be too easily destroyed
+ if(!def_zone || def_zone == BODY_ZONE_HEAD)
+ var/obj/item/clothing/hit_clothes
+ if(wear_mask)
+ hit_clothes = wear_mask
+ if(wear_neck)
+ hit_clothes = wear_neck
+ if(head)
+ hit_clothes = head
+ if(hit_clothes)
+ hit_clothes.take_damage(damage_amount, damage_type, damage_flag, 0)
+
+/mob/living/carbon/can_hear()
+ . = FALSE
+ var/obj/item/organ/ears/ears = getorganslot(ORGAN_SLOT_EARS)
+ if(istype(ears) && !ears.deaf)
+ . = TRUE
diff --git a/code/modules/mob/living/carbon/human/examine.dm b/code/modules/mob/living/carbon/human/examine.dm
index 9dbf731e..cbda3597 100644
--- a/code/modules/mob/living/carbon/human/examine.dm
+++ b/code/modules/mob/living/carbon/human/examine.dm
@@ -1,421 +1,420 @@
-/mob/living/carbon/human/examine(mob/user) //User is the person being examined
-//this is very slightly better than it was because you can use it more places. still can't do \his[src] though.
- var/t_He = p_they(TRUE)
- var/t_His = p_their(TRUE)
- var/t_his = p_their()
- var/t_him = p_them()
- var/t_has = p_have()
- var/t_is = p_are()
- var/obscure_name
- var/dispSize = round(12*size_multiplier) // gets the character's sprite size percent and converts it to the nearest half foot
-
- if(isliving(user))
- var/mob/living/L = user
- if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA))
- obscure_name = TRUE
-
- . = list("*---------*\nThis is [!obscure_name ? name : "Unknown"]!")
-
- var/vampDesc = ReturnVampExamine(user) // Vamps recognize the names of other vamps.
- var/vassDesc = ReturnVassalExamine(user) // Vassals recognize each other's marks.
- if (vampDesc != "") // If we don't do it this way, we add a blank space to the string...something to do with this --> . += ""
- . += vampDesc
- if (vassDesc != "")
- . += vassDesc
-
- var/list/obscured = check_obscured_slots()
- var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
-
- if(ishuman(src)) //user just returned, y'know, the user's own species. dumb.
- var/mob/living/carbon/human/H = src
- var/datum/species/pref_species = H.dna.species
- if(get_visible_name() == "Unknown") // same as flavor text, but hey it works.
- . += "You can't make out what species they are."
- else if(skipface)
- . += "You can't make out what species they are."
- else
- . += "[t_He] [t_is] a [H.dna.custom_species ? H.dna.custom_species : pref_species.name]!"
-
- //uniform
- if(w_uniform && !(SLOT_W_UNIFORM in obscured))
- //accessory
- var/accessory_msg
- if(istype(w_uniform, /obj/item/clothing/under))
- var/obj/item/clothing/under/U = w_uniform
- if(U.attached_accessory)
- accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]"
-
- . += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg]."
- //head
- if(head)
- . += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head."
- //suit/armor
- if(wear_suit)
- . += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)]."
- //suit/armor storage
- if(s_store && !(SLOT_S_STORE in obscured))
- . += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name]."
- //back
- if(back)
- . += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back."
-
- //Hands
- for(var/obj/item/I in held_items)
- if(!(I.item_flags & ABSTRACT))
- . += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))]."
-
- //gloves
- if(gloves && !(SLOT_GLOVES in obscured))
- . += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
- else if(length(blood_DNA))
- var/hand_number = get_num_arms(FALSE)
- if(hand_number)
- . += "[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!"
- //handcuffed?
- if(handcuffed)
- if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
- . += "[t_He] [t_is] [icon2html(handcuffed, user)] restrained with cable!"
- else
- . += "[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!"
-
- //belt
- if(belt)
- . += "[t_He] [t_has] [belt.get_examine_string(user)] about [t_his] waist."
-
- //shoes
- if(shoes && !(SLOT_SHOES in obscured))
- . += "[t_He] [t_is] wearing [shoes.get_examine_string(user)] on [t_his] feet."
-
- //mask
- if(wear_mask && !(SLOT_WEAR_MASK in obscured))
- . += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face."
-
- if(wear_neck && !(SLOT_NECK in obscured))
- . += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck."
-
- //eyes
- if(!(SLOT_GLASSES in obscured))
- if(glasses)
- . += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes."
- else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, TRAIT_CULT_EYES))
- . += "[t_His] eyes are glowing an unnatural red!"
-
- //ears
- if(ears && !(SLOT_EARS in obscured))
- . += "[t_He] [t_has] [ears.get_examine_string(user)] on [t_his] ears."
-
- //ID
- if(wear_id)
- . += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)]."
-
- //Status effects
- var/effects_exam = status_effect_examines()
- if(!isnull(effects_exam))
- . += effects_exam
-
- //Approximate character height based on current sprite scale
- if(dispSize % 2) // returns 1 or 0. 1 meaning the height is not exact and the code below will execute, 0 meaning the height is exact and the else will trigger.
- dispSize = dispSize - 1 //makes it even
- dispSize = dispSize / 2 //rounds it out
- . += "[t_He] appears to be around [dispSize] and a half feet tall."
- else
- dispSize = dispSize / 2
- . += "[t_He] appears to be around [dispSize] feet tall."
-
- //Can be picked up?
- if(can_be_held)
- . += "[t_He] might be able to be picked up with Alt+Click!\n"
-
- //CIT CHANGES START HERE - adds genital details to examine text
- if(LAZYLEN(internal_organs))
- for(var/obj/item/organ/genital/dicc in internal_organs)
- if(istype(dicc) && dicc.is_exposed())
- . += "[dicc.desc]"
-
- var/cursed_stuff = attempt_vr(src,"examine_bellies",args) //vore Code
- if(!isnull(cursed_stuff))
- . += cursed_stuff
-//END OF CIT CHANGES
-
- //Jitters
- switch(jitteriness)
- if(300 to INFINITY)
- . += "[t_He] [t_is] convulsing violently!"
- if(200 to 300)
- . += "[t_He] [t_is] extremely jittery."
- if(100 to 200)
- . += "[t_He] [t_is] twitching ever so slightly."
-
- var/appears_dead = 0
- if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
- appears_dead = 1
- if(suiciding)
- . += "[t_He] appear[p_s()] to have committed suicide... there is no hope of recovery."
- if(hellbound)
- . += "[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible."
- if(getorgan(/obj/item/organ/brain) && !key && !get_ghost(FALSE, TRUE))
- . += "[t_He] [t_is] limp and unresponsive; there are no signs of life and [t_his] soul has departed..."
- else
- . += "[t_He] [t_is] limp and unresponsive; there are no signs of life..."
-
- if(get_bodypart(BODY_ZONE_HEAD) && !getorgan(/obj/item/organ/brain))
- . += "It appears that [t_his] brain is missing..."
-
- var/temp = getBruteLoss() //no need to calculate each of these twice
-
- var/list/msg = list()
-
- var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
- var/list/disabled = list()
- for(var/X in bodyparts)
- var/obj/item/bodypart/BP = X
- if(BP.disabled)
- disabled += BP
- missing -= BP.body_zone
- for(var/obj/item/I in BP.embedded_objects)
- msg += "[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!\n"
- if(BP.broken)
- msg += "[t_He] [t_has] \a [I] broken [BP.name]!\n"
-
- for(var/X in disabled)
- var/obj/item/bodypart/BP = X
- var/damage_text
- if(!(BP.get_damage(include_stamina = FALSE) >= BP.max_damage)) //Stamina is disabling the limb
- damage_text = "limp and lifeless"
- else
- damage_text = (BP.brute_dam >= BP.burn_dam) ? BP.heavy_brute_msg : BP.heavy_burn_msg
- msg += "[capitalize(t_his)] [BP.name] is [damage_text]!\n"
-
- //stores missing limbs
- var/l_limbs_missing = 0
- var/r_limbs_missing = 0
- for(var/t in missing)
- if(t==BODY_ZONE_HEAD)
- msg += "[t_His] [parse_zone(t)] is missing!\n"
- continue
- if(t == BODY_ZONE_L_ARM || t == BODY_ZONE_L_LEG)
- l_limbs_missing++
- else if(t == BODY_ZONE_R_ARM || t == BODY_ZONE_R_LEG)
- r_limbs_missing++
-
- msg += "[capitalize(t_his)] [parse_zone(t)] is missing!\n"
-
- if(l_limbs_missing >= 2 && r_limbs_missing == 0)
- msg += "[t_He] look[p_s()] all right now.\n"
- else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
- msg += "[t_He] really keeps to the left.\n"
- else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
- msg += "[t_He] [p_do()]n't seem all there.\n"
-
- if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor bruising.\n"
- else if(temp < 50)
- msg += "[t_He] [t_has] moderate bruising!\n"
- else
- msg += "[t_He] [t_has] severe bruising!\n"
-
- temp = getFireLoss()
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor burns.\n"
- else if (temp < 50)
- msg += "[t_He] [t_has] moderate burns!\n"
- else
- msg += "[t_He] [t_has] severe burns!\n"
-
- temp = getCloneLoss()
- if(temp)
- if(temp < 25)
- msg += "[t_He] [t_has] minor cellular damage.\n"
- else if(temp < 50)
- msg += "[t_He] [t_has] moderate cellular damage!\n"
- else
- msg += "[t_He] [t_has] severe cellular damage!\n"
-
-
- if(fire_stacks > 0)
- msg += "[t_He] [t_is] covered in something flammable.\n"
- if(fire_stacks < 0)
- msg += "[t_He] look[p_s()] a little soaked.\n"
-
-
- if(pulledby && pulledby.grab_state)
- msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
-
- if(nutrition < NUTRITION_LEVEL_STARVING - 50)
- msg += "[t_He] [t_is] severely malnourished.\n"
- else if(nutrition >= NUTRITION_LEVEL_FAT)
- if(user.nutrition < NUTRITION_LEVEL_STARVING - 50)
- msg += "[t_He] [t_is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
- else
- msg += "[t_He] [t_is] quite chubby.\n"
- switch(disgust)
- if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
- msg += "[t_He] look[p_s()] a bit grossed out.\n"
- if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
- msg += "[t_He] look[p_s()] really grossed out.\n"
- if(DISGUST_LEVEL_DISGUSTED to INFINITY)
- msg += "[t_He] look[p_s()] extremely disgusted.\n"
-
- if(ShowAsPaleExamine())
- msg += "[t_He] [t_has] pale skin.\n"
-
- if(bleedsuppress)
- msg += "[t_He] [t_is] bandaged with something.\n"
- else if(bleed_rate)
- if(reagents.has_reagent("heparin"))
- msg += "[t_He] [t_is] bleeding uncontrollably!\n"
- else
- msg += "[t_He] [t_is] bleeding!\n"
-
- if(reagents.has_reagent("teslium"))
- msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
-
- if(islist(stun_absorption))
- for(var/i in stun_absorption)
- if(stun_absorption[i]["end_time"] > world.time && stun_absorption[i]["examine_message"])
- msg += "[t_He] [t_is][stun_absorption[i]["examine_message"]]\n"
-
- if(drunkenness && !skipface && !appears_dead) //Drunkenness
- switch(drunkenness)
- if(11 to 21)
- msg += "[t_He] [t_is] slightly flushed.\n"
- if(21.01 to 41) //.01s are used in case drunkenness ends up to be a small decimal
- msg += "[t_He] [t_is] flushed.\n"
- if(41.01 to 51)
- msg += "[t_He] [t_is] quite flushed and [t_his] breath smells of alcohol.\n"
- if(51.01 to 61)
- msg += "[t_He] [t_is] very flushed and [t_his] movements jerky, with breath reeking of alcohol.\n"
- if(61.01 to 91)
- msg += "[t_He] look[p_s()] like a drunken mess.\n"
- if(91.01 to INFINITY)
- msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
-
- if(reagents.has_reagent("astral"))
- msg += "[t_He] have wild, spacey eyes"
- if(mind)
- msg += " and have a strange, abnormal look to them.\n"
- else
- msg += " and don't look like they're all there.\n"
-
- if(isliving(user))
- var/mob/living/L = user
- if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead)
- if (a_intent != INTENT_HELP)
- msg += "[t_He] seem[p_s()] to be on guard.\n"
- if (getOxyLoss() >= 10)
- msg += "[t_He] seem[p_s()] winded.\n"
- if (getToxLoss() >= 10)
- msg += "[t_He] seem[p_s()] sickly.\n"
- var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
- if(mood.sanity <= SANITY_DISTURBED)
- msg += "[t_He] seem[p_s()] distressed.\n"
- SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empath", /datum/mood_event/sad_empath, src)
- if(mood.shown_mood >= 6) //So roundstart people aren't all "happy" and that antags don't show their true happiness.
- msg += "[t_He] seem[p_s()] to have had something nice happen to them recently.\n"
- SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empathH", /datum/mood_event/happy_empath, src)
- if (HAS_TRAIT(src, TRAIT_BLIND))
- msg += "[t_He] appear[p_s()] to be staring off into space.\n"
- if (HAS_TRAIT(src, TRAIT_DEAF))
- msg += "[t_He] appear[p_s()] to not be responding to noises.\n"
-
- msg += ""
-
- var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
- if(Vc)
- if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
- if(client?.prefs.lewdchem)
- msg += "You feel your chords resonate looking at them.\n"
-
-
- if(!appears_dead)
- if(stat == UNCONSCIOUS)
- msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n"
- else
- if(HAS_TRAIT(src, TRAIT_DUMB))
- msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n"
- if(InCritical())
- msg += "[t_He] [t_is] barely conscious.\n"
- if(getorgan(/obj/item/organ/brain))
- if(!key)
- msg += "[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.\n"
- else if(!client)
- msg += "[t_He] [t_has] a blank, absent-minded stare and appears completely unresponsive to anything. [t_He] may snap out of it soon.\n"
-
- if(digitalcamo)
- msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
-
- if (length(msg))
- . += "[msg.Join("")]"
-
- var/traitstring = get_trait_string()
- if(ishuman(user))
- var/mob/living/carbon/human/H = user
- var/obj/item/organ/cyberimp/eyes/hud/CIH = H.getorgan(/obj/item/organ/cyberimp/eyes/hud)
- if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH)
- var/perpname = get_face_name(get_id_name(""))
- if(perpname)
- var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
- if(R)
- . += "Rank: [R.fields["rank"]]\n\[Front photo\]\[Side photo\]"
- if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/medical))
- var/cyberimp_detect
- for(var/obj/item/organ/cyberimp/CI in internal_organs)
- if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
- cyberimp_detect += "[name] is modified with a [CI.name]."
- if(cyberimp_detect)
- . += "Detected cybernetic modifications:"
- . += cyberimp_detect
- if(R)
- var/health_r = R.fields["p_stat"]
- . += "\[[health_r]\]"
- health_r = R.fields["m_stat"]
- . += "\[[health_r]\]"
- R = find_record("name", perpname, GLOB.data_core.medical)
- if(R)
- . += "\[Medical evaluation\]"
- if(traitstring)
- . += "Detected physiological traits:\n[traitstring]"
-
-
- if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/security))
- if(!user.stat && user != src)
- //|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
- var/criminal = "None"
-
- R = find_record("name", perpname, GLOB.data_core.security)
- if(R)
- criminal = R.fields["criminal"]
-
- . += jointext(list("Criminal status:\[[criminal]\]",
- "Security record:\[View\]",
- "\[Add crime\]",
- "\[View comment log\]",
- "\[Add comment\]"), "")
- else if(isobserver(user) && traitstring)
- . += "Traits: [traitstring]"
-
- if(print_flavor_text())
- if(get_visible_name() == "Unknown") //Are we sure we know who this is? Don't show flavor text unless we can recognize them. Prevents certain metagaming with impersonation.
- . += "...?"
- else if(skipface) //Sometimes we're not unknown, but impersonating someone in a hardsuit, let's not reveal our flavor text then either.
- . += "...?"
- else
- . += "[print_flavor_text()]"
- SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, msg)
- . += "*---------*"
-
-/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
- var/list/dat = list()
- if(!pronoun_replacement)
- pronoun_replacement = p_they(TRUE)
- for(var/V in status_effects)
- var/datum/status_effect/E = V
- if(E.examine_text)
- var/new_text = replacetext(E.examine_text, "SUBJECTPRONOUN", pronoun_replacement)
- new_text = replacetext(new_text, "[pronoun_replacement] is", "[pronoun_replacement] [p_are()]") //To make sure something become "They are" or "She is", not "They are" and "She are"
- dat += "[new_text]\n" //dat.Join("\n") doesn't work here, for some reason
- if(dat.len)
- return dat.Join()
+/mob/living/carbon/human/examine(mob/user) //User is the person being examined
+//this is very slightly better than it was because you can use it more places. still can't do \his[src] though.
+ var/t_He = p_they(TRUE)
+ var/t_His = p_their(TRUE)
+ var/t_his = p_their()
+ var/t_him = p_them()
+ var/t_has = p_have()
+ var/t_is = p_are()
+ var/obscure_name
+ var/dispSize = round(12*size_multiplier) // gets the character's sprite size percent and converts it to the nearest half foot
+
+ if(isliving(user))
+ var/mob/living/L = user
+ if(HAS_TRAIT(L, TRAIT_PROSOPAGNOSIA))
+ obscure_name = TRUE
+
+ . = list("*---------*\nThis is [!obscure_name ? name : "Unknown"]!")
+
+ var/vampDesc = ReturnVampExamine(user) // Vamps recognize the names of other vamps.
+ var/vassDesc = ReturnVassalExamine(user) // Vassals recognize each other's marks.
+ if (vampDesc != "") // If we don't do it this way, we add a blank space to the string...something to do with this --> . += ""
+ . += vampDesc
+ if (vassDesc != "")
+ . += vassDesc
+
+ var/list/obscured = check_obscured_slots()
+ var/skipface = (wear_mask && (wear_mask.flags_inv & HIDEFACE)) || (head && (head.flags_inv & HIDEFACE))
+
+ if(ishuman(src)) //user just returned, y'know, the user's own species. dumb.
+ var/mob/living/carbon/human/H = src
+ var/datum/species/pref_species = H.dna.species
+ if(get_visible_name() == "Unknown") // same as flavor text, but hey it works.
+ . += "You can't make out what species they are."
+ else if(skipface)
+ . += "You can't make out what species they are."
+ else
+ . += "[t_He] [t_is] a [H.dna.custom_species ? H.dna.custom_species : pref_species.name]!"
+
+ //uniform
+ if(w_uniform && !(SLOT_W_UNIFORM in obscured))
+ //accessory
+ var/accessory_msg
+ if(istype(w_uniform, /obj/item/clothing/under))
+ var/obj/item/clothing/under/U = w_uniform
+ if(U.attached_accessory)
+ accessory_msg += " with [icon2html(U.attached_accessory, user)] \a [U.attached_accessory]"
+
+ . += "[t_He] [t_is] wearing [w_uniform.get_examine_string(user)][accessory_msg]."
+ //head
+ if(head)
+ . += "[t_He] [t_is] wearing [head.get_examine_string(user)] on [t_his] head."
+ //suit/armor
+ if(wear_suit)
+ . += "[t_He] [t_is] wearing [wear_suit.get_examine_string(user)]."
+ //suit/armor storage
+ if(s_store && !(SLOT_S_STORE in obscured))
+ . += "[t_He] [t_is] carrying [s_store.get_examine_string(user)] on [t_his] [wear_suit.name]."
+ //back
+ if(back)
+ . += "[t_He] [t_has] [back.get_examine_string(user)] on [t_his] back."
+
+ //Hands
+ for(var/obj/item/I in held_items)
+ if(!(I.item_flags & ABSTRACT))
+ . += "[t_He] [t_is] holding [I.get_examine_string(user)] in [t_his] [get_held_index_name(get_held_index_of_item(I))]."
+
+ //gloves
+ if(gloves && !(SLOT_GLOVES in obscured))
+ . += "[t_He] [t_has] [gloves.get_examine_string(user)] on [t_his] hands."
+ else if(length(blood_DNA))
+ var/hand_number = get_num_arms(FALSE)
+ if(hand_number)
+ . += "[t_He] [t_has] [hand_number > 1 ? "" : "a"] blood-stained hand[hand_number > 1 ? "s" : ""]!"
+ //handcuffed?
+ if(handcuffed)
+ if(istype(handcuffed, /obj/item/restraints/handcuffs/cable))
+ . += "[t_He] [t_is] [icon2html(handcuffed, user)] restrained with cable!"
+ else
+ . += "[t_He] [t_is] [icon2html(handcuffed, user)] handcuffed!"
+
+ //belt
+ if(belt)
+ . += "[t_He] [t_has] [belt.get_examine_string(user)] about [t_his] waist."
+
+ //shoes
+ if(shoes && !(SLOT_SHOES in obscured))
+ . += "[t_He] [t_is] wearing [shoes.get_examine_string(user)] on [t_his] feet."
+
+ //mask
+ if(wear_mask && !(SLOT_WEAR_MASK in obscured))
+ . += "[t_He] [t_has] [wear_mask.get_examine_string(user)] on [t_his] face."
+
+ if(wear_neck && !(SLOT_NECK in obscured))
+ . += "[t_He] [t_is] wearing [wear_neck.get_examine_string(user)] around [t_his] neck."
+
+ //eyes
+ if(!(SLOT_GLASSES in obscured))
+ if(glasses)
+ . += "[t_He] [t_has] [glasses.get_examine_string(user)] covering [t_his] eyes."
+ else if(eye_color == BLOODCULT_EYE && iscultist(src) && HAS_TRAIT(src, TRAIT_CULT_EYES))
+ . += "[t_His] eyes are glowing an unnatural red!"
+
+ //ears
+ if(ears && !(SLOT_EARS in obscured))
+ . += "[t_He] [t_has] [ears.get_examine_string(user)] on [t_his] ears."
+
+ //ID
+ if(wear_id)
+ . += "[t_He] [t_is] wearing [wear_id.get_examine_string(user)]."
+
+ //Status effects
+ var/effects_exam = status_effect_examines()
+ if(!isnull(effects_exam))
+ . += effects_exam
+
+ //Approximate character height based on current sprite scale
+ if(dispSize % 2) // returns 1 or 0. 1 meaning the height is not exact and the code below will execute, 0 meaning the height is exact and the else will trigger.
+ dispSize = dispSize - 1 //makes it even
+ dispSize = dispSize / 2 //rounds it out
+ . += "[t_He] appears to be around [dispSize] and a half feet tall."
+ else
+ dispSize = dispSize / 2
+ . += "[t_He] appears to be around [dispSize] feet tall."
+
+ //Can be picked up?
+ if(can_be_held)
+ . += "[t_He] might be able to be picked up with Alt+Click!\n"
+
+ //CIT CHANGES START HERE - adds genital details to examine text
+ if(LAZYLEN(internal_organs))
+ for(var/obj/item/organ/genital/dicc in internal_organs)
+ if(istype(dicc) && dicc.is_exposed())
+ . += "[dicc.desc]"
+
+ var/cursed_stuff = attempt_vr(src,"examine_bellies",args) //vore Code
+ if(!isnull(cursed_stuff))
+ . += cursed_stuff
+//END OF CIT CHANGES
+
+ //Jitters
+ switch(jitteriness)
+ if(300 to INFINITY)
+ . += "[t_He] [t_is] convulsing violently!"
+ if(200 to 300)
+ . += "[t_He] [t_is] extremely jittery."
+ if(100 to 200)
+ . += "[t_He] [t_is] twitching ever so slightly."
+
+ var/appears_dead = 0
+ if(stat == DEAD || (HAS_TRAIT(src, TRAIT_FAKEDEATH)))
+ appears_dead = 1
+ if(suiciding)
+ . += "[t_He] appear[p_s()] to have committed suicide... there is no hope of recovery."
+ if(hellbound)
+ . += "[t_His] soul seems to have been ripped out of [t_his] body. Revival is impossible."
+ if(getorgan(/obj/item/organ/brain) && !key && !get_ghost(FALSE, TRUE))
+ . += "[t_He] [t_is] limp and unresponsive; there are no signs of life and [t_his] soul has departed..."
+ else
+ . += "[t_He] [t_is] limp and unresponsive; there are no signs of life..."
+
+ if(get_bodypart(BODY_ZONE_HEAD) && !getorgan(/obj/item/organ/brain))
+ . += "It appears that [t_his] brain is missing..."
+
+ var/temp = getBruteLoss() //no need to calculate each of these twice
+
+ var/list/msg = list()
+
+ var/list/missing = list(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_L_ARM, BODY_ZONE_R_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_LEG)
+ var/list/disabled = list()
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ if(BP.disabled)
+ disabled += BP
+ missing -= BP.body_zone
+ for(var/obj/item/I in BP.embedded_objects)
+ msg += "[t_He] [t_has] \a [icon2html(I, user)] [I] embedded in [t_his] [BP.name]!\n"
+ if(BP.broken)
+ msg += "[t_He] [t_has] \a [I] broken [BP.name]!\n"
+
+ for(var/X in disabled)
+ var/obj/item/bodypart/BP = X
+ var/damage_text
+ if(!(BP.get_damage(include_stamina = FALSE) >= BP.max_damage)) //Stamina is disabling the limb
+ damage_text = "limp and lifeless"
+ else
+ damage_text = (BP.brute_dam >= BP.burn_dam) ? BP.heavy_brute_msg : BP.heavy_burn_msg
+ msg += "[capitalize(t_his)] [BP.name] is [damage_text]!\n"
+
+ //stores missing limbs
+ var/l_limbs_missing = 0
+ var/r_limbs_missing = 0
+ for(var/t in missing)
+ if(t==BODY_ZONE_HEAD)
+ msg += "[t_His] [parse_zone(t)] is missing!\n"
+ continue
+ if(t == BODY_ZONE_L_ARM || t == BODY_ZONE_L_LEG)
+ l_limbs_missing++
+ else if(t == BODY_ZONE_R_ARM || t == BODY_ZONE_R_LEG)
+ r_limbs_missing++
+
+ msg += "[capitalize(t_his)] [parse_zone(t)] is missing!\n"
+
+ if(l_limbs_missing >= 2 && r_limbs_missing == 0)
+ msg += "[t_He] look[p_s()] all right now.\n"
+ else if(l_limbs_missing == 0 && r_limbs_missing >= 2)
+ msg += "[t_He] really keeps to the left.\n"
+ else if(l_limbs_missing >= 2 && r_limbs_missing >= 2)
+ msg += "[t_He] [p_do()]n't seem all there.\n"
+
+ if(!(user == src && src.hal_screwyhud == SCREWYHUD_HEALTHY)) //fake healthy
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor bruising.\n"
+ else if(temp < 50)
+ msg += "[t_He] [t_has] moderate bruising!\n"
+ else
+ msg += "[t_He] [t_has] severe bruising!\n"
+
+ temp = getFireLoss()
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor burns.\n"
+ else if (temp < 50)
+ msg += "[t_He] [t_has] moderate burns!\n"
+ else
+ msg += "[t_He] [t_has] severe burns!\n"
+
+ temp = getCloneLoss()
+ if(temp)
+ if(temp < 25)
+ msg += "[t_He] [t_has] minor cellular damage.\n"
+ else if(temp < 50)
+ msg += "[t_He] [t_has] moderate cellular damage!\n"
+ else
+ msg += "[t_He] [t_has] severe cellular damage!\n"
+
+
+ if(fire_stacks > 0)
+ msg += "[t_He] [t_is] covered in something flammable.\n"
+ if(fire_stacks < 0)
+ msg += "[t_He] look[p_s()] a little soaked.\n"
+
+
+ if(pulledby && pulledby.grab_state)
+ msg += "[t_He] [t_is] restrained by [pulledby]'s grip.\n"
+
+ if(nutrition < NUTRITION_LEVEL_STARVING - 50)
+ msg += "[t_He] [t_is] severely malnourished.\n"
+ else if(nutrition >= NUTRITION_LEVEL_FAT)
+ if(user.nutrition < NUTRITION_LEVEL_STARVING - 50)
+ msg += "[t_He] [t_is] plump and delicious looking - Like a fat little piggy. A tasty piggy.\n"
+ else
+ msg += "[t_He] [t_is] quite chubby.\n"
+ switch(disgust)
+ if(DISGUST_LEVEL_GROSS to DISGUST_LEVEL_VERYGROSS)
+ msg += "[t_He] look[p_s()] a bit grossed out.\n"
+ if(DISGUST_LEVEL_VERYGROSS to DISGUST_LEVEL_DISGUSTED)
+ msg += "[t_He] look[p_s()] really grossed out.\n"
+ if(DISGUST_LEVEL_DISGUSTED to INFINITY)
+ msg += "[t_He] look[p_s()] extremely disgusted.\n"
+
+ if(ShowAsPaleExamine())
+ msg += "[t_He] [t_has] pale skin.\n"
+
+ if(bleedsuppress)
+ msg += "[t_He] [t_is] bandaged with something.\n"
+ else if(bleed_rate)
+ if(reagents.has_reagent("heparin"))
+ msg += "[t_He] [t_is] bleeding uncontrollably!\n"
+ else
+ msg += "[t_He] [t_is] bleeding!\n"
+
+ if(reagents.has_reagent(/datum/reagent/teslium))
+ msg += "[t_He] [t_is] emitting a gentle blue glow!\n"
+
+ if(islist(stun_absorption))
+ for(var/i in stun_absorption)
+ if(stun_absorption[i]["end_time"] > world.time && stun_absorption[i]["examine_message"])
+ msg += "[t_He] [t_is][stun_absorption[i]["examine_message"]]\n"
+
+ if(drunkenness && !skipface && !appears_dead) //Drunkenness
+ switch(drunkenness)
+ if(11 to 21)
+ msg += "[t_He] [t_is] slightly flushed.\n"
+ if(21.01 to 41) //.01s are used in case drunkenness ends up to be a small decimal
+ msg += "[t_He] [t_is] flushed.\n"
+ if(41.01 to 51)
+ msg += "[t_He] [t_is] quite flushed and [t_his] breath smells of alcohol.\n"
+ if(51.01 to 61)
+ msg += "[t_He] [t_is] very flushed and [t_his] movements jerky, with breath reeking of alcohol.\n"
+ if(61.01 to 91)
+ msg += "[t_He] look[p_s()] like a drunken mess.\n"
+ if(91.01 to INFINITY)
+ msg += "[t_He] [t_is] a shitfaced, slobbering wreck.\n"
+
+ if(reagents.has_reagent(/datum/reagent/fermi/astral))
+ if(mind)
+ msg += " and have a strange, abnormal look to them.\n"
+ else
+ msg += " and don't look like they're all there.\n"
+
+ if(isliving(user))
+ var/mob/living/L = user
+ if(src != user && HAS_TRAIT(L, TRAIT_EMPATH) && !appears_dead)
+ if (a_intent != INTENT_HELP)
+ msg += "[t_He] seem[p_s()] to be on guard.\n"
+ if (getOxyLoss() >= 10)
+ msg += "[t_He] seem[p_s()] winded.\n"
+ if (getToxLoss() >= 10)
+ msg += "[t_He] seem[p_s()] sickly.\n"
+ var/datum/component/mood/mood = src.GetComponent(/datum/component/mood)
+ if(mood.sanity <= SANITY_DISTURBED)
+ msg += "[t_He] seem[p_s()] distressed.\n"
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empath", /datum/mood_event/sad_empath, src)
+ if(mood.shown_mood >= 6) //So roundstart people aren't all "happy" and that antags don't show their true happiness.
+ msg += "[t_He] seem[p_s()] to have had something nice happen to them recently.\n"
+ SEND_SIGNAL(user, COMSIG_ADD_MOOD_EVENT, "empathH", /datum/mood_event/happy_empath, src)
+ if (HAS_TRAIT(src, TRAIT_BLIND))
+ msg += "[t_He] appear[p_s()] to be staring off into space.\n"
+ if (HAS_TRAIT(src, TRAIT_DEAF))
+ msg += "[t_He] appear[p_s()] to not be responding to noises.\n"
+
+ msg += ""
+
+ var/obj/item/organ/vocal_cords/Vc = user.getorganslot(ORGAN_SLOT_VOICE)
+ if(Vc)
+ if(istype(Vc, /obj/item/organ/vocal_cords/velvet))
+ if(client?.prefs.lewdchem)
+ msg += "You feel your chords resonate looking at them.\n"
+
+
+ if(!appears_dead)
+ if(stat == UNCONSCIOUS)
+ msg += "[t_He] [t_is]n't responding to anything around [t_him] and seem[p_s()] to be asleep.\n"
+ else
+ if(HAS_TRAIT(src, TRAIT_DUMB))
+ msg += "[t_He] [t_has] a stupid expression on [t_his] face.\n"
+ if(InCritical())
+ msg += "[t_He] [t_is] barely conscious.\n"
+ if(getorgan(/obj/item/organ/brain))
+ if(!key)
+ msg += "[t_He] [t_is] totally catatonic. The stresses of life in deep-space must have been too much for [t_him]. Any recovery is unlikely.\n"
+ else if(!client)
+ msg += "[t_He] [t_has] a blank, absent-minded stare and appears completely unresponsive to anything. [t_He] may snap out of it soon.\n"
+
+ if(digitalcamo)
+ msg += "[t_He] [t_is] moving [t_his] body in an unnatural and blatantly inhuman manner.\n"
+
+ if (length(msg))
+ . += "[msg.Join("")]"
+
+ var/traitstring = get_trait_string()
+ if(ishuman(user))
+ var/mob/living/carbon/human/H = user
+ var/obj/item/organ/cyberimp/eyes/hud/CIH = H.getorgan(/obj/item/organ/cyberimp/eyes/hud)
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud) || CIH)
+ var/perpname = get_face_name(get_id_name(""))
+ if(perpname)
+ var/datum/data/record/R = find_record("name", perpname, GLOB.data_core.general)
+ if(R)
+ . += "Rank: [R.fields["rank"]]\n\[Front photo\]\[Side photo\]"
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud/health) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/medical))
+ var/cyberimp_detect
+ for(var/obj/item/organ/cyberimp/CI in internal_organs)
+ if(CI.status == ORGAN_ROBOTIC && !CI.syndicate_implant)
+ cyberimp_detect += "[name] is modified with a [CI.name]."
+ if(cyberimp_detect)
+ . += "Detected cybernetic modifications:"
+ . += cyberimp_detect
+ if(R)
+ var/health_r = R.fields["p_stat"]
+ . += "\[[health_r]\]"
+ health_r = R.fields["m_stat"]
+ . += "\[[health_r]\]"
+ R = find_record("name", perpname, GLOB.data_core.medical)
+ if(R)
+ . += "\[Medical evaluation\]"
+ if(traitstring)
+ . += "Detected physiological traits:\n[traitstring]"
+
+
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud/security) || istype(CIH, /obj/item/organ/cyberimp/eyes/hud/security))
+ if(!user.stat && user != src)
+ //|| !user.canmove || user.restrained()) Fluff: Sechuds have eye-tracking technology and sets 'arrest' to people that the wearer looks and blinks at.
+ var/criminal = "None"
+
+ R = find_record("name", perpname, GLOB.data_core.security)
+ if(R)
+ criminal = R.fields["criminal"]
+
+ . += jointext(list("Criminal status:\[[criminal]\]",
+ "Security record:\[View\]",
+ "\[Add crime\]",
+ "\[View comment log\]",
+ "\[Add comment\]"), "")
+ else if(isobserver(user) && traitstring)
+ . += "Traits: [traitstring]"
+
+ if(print_flavor_text())
+ if(get_visible_name() == "Unknown") //Are we sure we know who this is? Don't show flavor text unless we can recognize them. Prevents certain metagaming with impersonation.
+ . += "...?"
+ else if(skipface) //Sometimes we're not unknown, but impersonating someone in a hardsuit, let's not reveal our flavor text then either.
+ . += "...?"
+ else
+ . += "[print_flavor_text()]"
+ SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, msg)
+ . += "*---------*"
+
+/mob/living/proc/status_effect_examines(pronoun_replacement) //You can include this in any mob's examine() to show the examine texts of status effects!
+ var/list/dat = list()
+ if(!pronoun_replacement)
+ pronoun_replacement = p_they(TRUE)
+ for(var/V in status_effects)
+ var/datum/status_effect/E = V
+ if(E.examine_text)
+ var/new_text = replacetext(E.examine_text, "SUBJECTPRONOUN", pronoun_replacement)
+ new_text = replacetext(new_text, "[pronoun_replacement] is", "[pronoun_replacement] [p_are()]") //To make sure something become "They are" or "She is", not "They are" and "She are"
+ dat += "[new_text]\n" //dat.Join("\n") doesn't work here, for some reason
+ if(dat.len)
+ return dat.Join()
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index b22049f4..34367af9 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1205,9 +1205,9 @@ GLOBAL_LIST_EMPTY(roundstart_races)
H.update_mutant_bodyparts()
/datum/species/proc/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(chem.id == exotic_blood)
+ if(chem.type == exotic_blood)
H.blood_volume = min(H.blood_volume + round(chem.volume, 0.1), BLOOD_VOLUME_MAXIMUM)
- H.reagents.del_reagent(chem.id)
+ H.reagents.del_reagent(chem.type)
return 1
return FALSE
diff --git a/code/modules/mob/living/carbon/human/species_types/flypeople.dm b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
index 40cbcbab..4bd76bcb 100644
--- a/code/modules/mob/living/carbon/human/species_types/flypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/flypeople.dm
@@ -1,36 +1,36 @@
-/datum/species/fly
- name = "Flyperson"
- id = "fly"
- say_mod = "buzzes"
- species_traits = list(NOEYES)
- inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
- mutanttongue = /obj/item/organ/tongue/fly
- mutantliver = /obj/item/organ/liver/fly
- mutantstomach = /obj/item/organ/stomach/fly
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/fly
- disliked_food = null
- liked_food = GROSS
- exotic_bloodtype = "BUG"
-
-/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(chem.id == "pestkiller")
- H.adjustToxLoss(3)
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
- return 1
-
-
-/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(istype(chem, /datum/reagent/consumable))
- var/datum/reagent/consumable/nutri_check = chem
- if(nutri_check.nutriment_factor > 0)
- var/turf/pos = get_turf(H)
- H.vomit(0, FALSE, FALSE, 2, TRUE)
- playsound(pos, 'sound/effects/splat.ogg', 50, 1)
- H.visible_message("[H] vomits on the floor!", \
- "You throw up on the floor!")
- ..()
-
-/datum/species/fly/check_weakness(obj/item/weapon, mob/living/attacker)
- if(istype(weapon, /obj/item/melee/flyswatter))
- return 29 //Flyswatters deal 30x damage to flypeople.
- return 0
+/datum/species/fly
+ name = "Flyperson"
+ id = "fly"
+ say_mod = "buzzes"
+ species_traits = list(NOEYES)
+ inherent_biotypes = list(MOB_ORGANIC, MOB_HUMANOID, MOB_BUG)
+ mutanttongue = /obj/item/organ/tongue/fly
+ mutantliver = /obj/item/organ/liver/fly
+ mutantstomach = /obj/item/organ/stomach/fly
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/fly
+ disliked_food = null
+ liked_food = GROSS
+ exotic_bloodtype = "BUG"
+
+/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
+ if(chem.type == /datum/reagent/toxin/pestkiller)
+ H.adjustToxLoss(3)
+ H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
+ return 1
+
+
+/datum/species/fly/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
+ if(istype(chem, /datum/reagent/consumable))
+ var/datum/reagent/consumable/nutri_check = chem
+ if(nutri_check.nutriment_factor > 0)
+ var/turf/pos = get_turf(H)
+ H.vomit(0, FALSE, FALSE, 2, TRUE)
+ playsound(pos, 'sound/effects/splat.ogg', 50, 1)
+ H.visible_message("[H] vomits on the floor!", \
+ "You throw up on the floor!")
+ ..()
+
+/datum/species/fly/check_weakness(obj/item/weapon, mob/living/attacker)
+ if(istype(weapon, /obj/item/melee/flyswatter))
+ return 29 //Flyswatters deal 30x damage to flypeople.
+ return 0
diff --git a/code/modules/mob/living/carbon/human/species_types/golems.dm b/code/modules/mob/living/carbon/human/species_types/golems.dm
index a827beae..896b9ad2 100644
--- a/code/modules/mob/living/carbon/human/species_types/golems.dm
+++ b/code/modules/mob/living/carbon/human/species_types/golems.dm
@@ -1,1009 +1,1009 @@
-/datum/species/golem
- // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck.
- name = "Golem"
- id = "iron golem"
- species_traits = list(NOBLOOD,MUTCOLORS,NO_UNDERWEAR,NOGENITALS,NOAROUSAL)
- inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
- inherent_biotypes = list(MOB_INORGANIC, MOB_HUMANOID)
- mutant_organs = list(/obj/item/organ/adamantine_resonator)
- speedmod = 2
- armor = 55
- siemens_coeff = 0
- punchdamagelow = 5
- punchdamagehigh = 14
- punchstunthreshold = 11 //about 40% chance to stun
- no_equip = list(SLOT_WEAR_MASK, SLOT_WEAR_SUIT, SLOT_GLOVES, SLOT_SHOES, SLOT_W_UNIFORM, SLOT_S_STORE)
- nojumpsuit = 1
- sexes = 1
- damage_overlay_type = ""
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/golem
- // To prevent golem subtypes from overwhelming the odds when random species
- // changes, only the Random Golem type can be chosen
- blacklisted = TRUE
- dangerous_existence = TRUE
- limbs_id = "golem"
- fixed_mut_color = "aaa"
- var/info_text = "As an Iron Golem, you don't have any special traits."
- var/random_eligible = TRUE //If false, the golem subtype can't be made through golem mutation toxin
-
- var/prefix = "Iron"
- var/list/special_names = list("Tarkus")
- var/human_surname_chance = 3
- var/special_name_chance = 5
- var/owner //dobby is a free golem
-
-/datum/species/golem/random_name(gender,unique,lastname)
- var/golem_surname = pick(GLOB.golem_names)
- // 3% chance that our golem has a human surname, because
- // cultural contamination
- if(prob(human_surname_chance))
- golem_surname = pick(GLOB.last_names)
- else if(special_names && special_names.len && prob(special_name_chance))
- golem_surname = pick(special_names)
-
- var/golem_name = "[prefix] [golem_surname]"
- return golem_name
-
-/datum/species/golem/random
- name = "Random Golem"
- blacklisted = FALSE
- dangerous_existence = FALSE
- var/static/list/random_golem_types
-
-/datum/species/golem/random/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- if(!random_golem_types)
- random_golem_types = subtypesof(/datum/species/golem) - type
- for(var/V in random_golem_types)
- var/datum/species/golem/G = V
- if(!initial(G.random_eligible))
- random_golem_types -= G
- var/datum/species/golem/golem_type = pick(random_golem_types)
- var/mob/living/carbon/human/H = C
- H.set_species(golem_type)
- to_chat(H, "[initial(golem_type.info_text)]")
-
-/datum/species/golem/adamantine
- name = "Adamantine Golem"
- id = "adamantine golem"
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/golem/adamantine
- mutant_organs = list(/obj/item/organ/adamantine_resonator, /obj/item/organ/vocal_cords/adamantine)
- fixed_mut_color = "4ed"
- info_text = "As an Adamantine Golem, you possess special vocal cords allowing you to \"resonate\" messages to all golems. Your unique mineral makeup makes you immune to most types of magic."
- prefix = "Adamantine"
- special_names = null
-
-/datum/species/golem/adamantine/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- ADD_TRAIT(C, TRAIT_ANTIMAGIC, SPECIES_TRAIT)
-
-/datum/species/golem/adamantine/on_species_loss(mob/living/carbon/C)
- REMOVE_TRAIT(C, TRAIT_ANTIMAGIC, SPECIES_TRAIT)
- ..()
-
-//The suicide bombers of golemkind
-/datum/species/golem/plasma
- name = "Plasma Golem"
- id = "plasma golem"
- fixed_mut_color = "a3d"
- meat = /obj/item/stack/ore/plasma
- //Can burn and takes damage from heat
- inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) //no RESISTHEAT, NOFIRE
- info_text = "As a Plasma Golem, you burn easily. Be careful, if you get hot enough while burning, you'll blow up!"
- heatmod = 0 //fine until they blow up
- prefix = "Plasma"
- special_names = list("Flood","Fire","Bar","Man")
- var/boom_warning = FALSE
- var/datum/action/innate/ignite/ignite
-
-/datum/species/golem/plasma/spec_life(mob/living/carbon/human/H)
- if(H.bodytemperature > 750)
- if(!boom_warning && H.on_fire)
- to_chat(H, "You feel like you could blow up at any moment!")
- boom_warning = TRUE
- else
- if(boom_warning)
- to_chat(H, "You feel more stable.")
- boom_warning = FALSE
-
- if(H.bodytemperature > 850 && H.on_fire && prob(25))
- explosion(get_turf(H),1,2,4,flame_range = 5)
- if(H)
- H.gib()
- if(H.fire_stacks < 2) //flammable
- H.adjust_fire_stacks(1)
- ..()
-
-/datum/species/golem/plasma/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- if(ishuman(C))
- ignite = new
- ignite.Grant(C)
-
-/datum/species/golem/plasma/on_species_loss(mob/living/carbon/C)
- if(ignite)
- ignite.Remove(C)
- ..()
-
-/datum/action/innate/ignite
- name = "Ignite"
- desc = "Set yourself aflame, bringing yourself closer to exploding!"
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "sacredflame"
-
-/datum/action/innate/ignite/Activate()
- if(ishuman(owner))
- var/mob/living/carbon/human/H = owner
- if(H.fire_stacks)
- to_chat(owner, "You ignite yourself!")
- else
- to_chat(owner, "You try to ignite yourself, but fail!")
- H.IgniteMob() //firestacks are already there passively
-
-//Harder to hurt
-/datum/species/golem/diamond
- name = "Diamond Golem"
- id = "diamond golem"
- fixed_mut_color = "0ff"
- armor = 70 //up from 55
- meat = /obj/item/stack/ore/diamond
- info_text = "As a Diamond Golem, you are more resistant than the average golem."
- prefix = "Diamond"
- special_names = list("Back")
-
-//Faster but softer and less armoured
-/datum/species/golem/gold
- name = "Gold Golem"
- id = "gold golem"
- fixed_mut_color = "cc0"
- speedmod = 1
- armor = 25 //down from 55
- meat = /obj/item/stack/ore/gold
- info_text = "As a Gold Golem, you are faster but less resistant than the average golem."
- prefix = "Golden"
- special_names = list("Boy")
-
-//Heavier, thus higher chance of stunning when punching
-/datum/species/golem/silver
- name = "Silver Golem"
- id = "silver golem"
- fixed_mut_color = "ddd"
- punchstunthreshold = 9 //60% chance, from 40%
- meat = /obj/item/stack/ore/silver
- info_text = "As a Silver Golem, your attacks have a higher chance of stunning. Being made of silver, your body is immune to most types of magic."
- prefix = "Silver"
- special_names = list("Surfer", "Chariot", "Lining")
-
-/datum/species/golem/silver/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- ADD_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
-
-/datum/species/golem/silver/on_species_loss(mob/living/carbon/C)
- REMOVE_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
- ..()
-
-//Harder to stun, deals more damage, but it's even slower
-/datum/species/golem/plasteel
- name = "Plasteel Golem"
- id = "plasteel golem"
- fixed_mut_color = "bbb"
- stunmod = 0.4
- punchdamagelow = 12
- punchdamagehigh = 21
- punchstunthreshold = 18 //still 40% stun chance
- speedmod = 4 //pretty fucking slow
- meat = /obj/item/stack/ore/iron
- info_text = "As a Plasteel Golem, you are slower, but harder to stun, and hit very hard when punching."
- attack_verb = "smash"
- attack_sound = 'sound/effects/meteorimpact.ogg' //hits pretty hard
- prefix = "Plasteel"
- special_names = null
-
-//Immune to ash storms
-/datum/species/golem/titanium
- name = "Titanium Golem"
- id = "titanium golem"
- fixed_mut_color = "fff"
- meat = /obj/item/stack/ore/titanium
- info_text = "As a Titanium Golem, you are immune to ash storms, and slightly more resistant to burn damage."
- burnmod = 0.9
- prefix = "Titanium"
- special_names = list("Dioxide")
-
-/datum/species/golem/titanium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- . = ..()
- C.weather_immunities |= "ash"
-
-/datum/species/golem/titanium/on_species_loss(mob/living/carbon/C)
- . = ..()
- C.weather_immunities -= "ash"
-
-//Immune to ash storms and lava
-/datum/species/golem/plastitanium
- name = "Plastitanium Golem"
- id = "plastitanium golem"
- fixed_mut_color = "888"
- meat = /obj/item/stack/ore/titanium
- info_text = "As a Plastitanium Golem, you are immune to both ash storms and lava, and slightly more resistant to burn damage."
- burnmod = 0.8
- prefix = "Plastitanium"
- special_names = null
-
-/datum/species/golem/plastitanium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- . = ..()
- C.weather_immunities |= "lava"
- C.weather_immunities |= "ash"
-
-/datum/species/golem/plastitanium/on_species_loss(mob/living/carbon/C)
- . = ..()
- C.weather_immunities -= "ash"
- C.weather_immunities -= "lava"
-
-//Fast and regenerates... but can only speak like an abductor
-/datum/species/golem/alloy
- name = "Alien Alloy Golem"
- id = "alloy golem"
- fixed_mut_color = "333"
- meat = /obj/item/stack/sheet/mineral/abductor
- mutanttongue = /obj/item/organ/tongue/abductor
- speedmod = 1 //faster
- info_text = "As an Alloy Golem, you are made of advanced alien materials: you are faster and regenerate over time. You are, however, only able to be heard by other alloy golems."
- prefix = "Alien"
- special_names = list("Outsider", "Technology", "Watcher", "Stranger") //ominous and unknown
-
-//Regenerates because self-repairing super-advanced alien tech
-/datum/species/golem/alloy/spec_life(mob/living/carbon/human/H)
- if(H.stat == DEAD)
- return
- H.heal_overall_damage(2,2)
- H.adjustToxLoss(-2)
- H.adjustOxyLoss(-2)
-
-//Since this will usually be created from a collaboration between podpeople and free golems, wood golems are a mix between the two races
-/datum/species/golem/wood
- name = "Wood Golem"
- id = "wood golem"
- fixed_mut_color = "9E704B"
- meat = /obj/item/stack/sheet/mineral/wood
- //Can burn and take damage from heat
- inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
- armor = 30
- burnmod = 1.25
- heatmod = 1.5
- info_text = "As a Wooden Golem, you have plant-like traits: you take damage from extreme temperatures, can be set on fire, and have lower armor than a normal golem. You regenerate when in the light and wither in the darkness."
- prefix = "Wooden"
- special_names = list("Bark", "Willow", "Catalpa", "Woody", "Oak", "Sap", "Twig", "Branch", "Maple", "Birch", "Elm", "Basswood", "Cottonwood", "Larch", "Aspen", "Ash", "Beech", "Buckeye", "Cedar", "Chestnut", "Cypress", "Fir", "Hawthorn", "Hazel", "Hickory", "Ironwood", "Juniper", "Leaf", "Mangrove", "Palm", "Pawpaw", "Pine", "Poplar", "Redwood", "Redbud", "Sassafras", "Spruce", "Sumac", "Trunk", "Walnut", "Yew")
- human_surname_chance = 0
- special_name_chance = 100
-
-/datum/species/golem/wood/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- . = ..()
- C.faction |= "plants"
- C.faction |= "vines"
-
-/datum/species/golem/wood/on_species_loss(mob/living/carbon/C)
- . = ..()
- C.faction -= "plants"
- C.faction -= "vines"
-
-/datum/species/golem/wood/spec_life(mob/living/carbon/human/H)
- if(H.stat == DEAD)
- return
- var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
- if(isturf(H.loc)) //else, there's considered to be no light
- var/turf/T = H.loc
- light_amount = min(1,T.get_lumcount()) - 0.5
- H.nutrition += light_amount * 10
- if(H.nutrition > NUTRITION_LEVEL_FULL)
- H.nutrition = NUTRITION_LEVEL_FULL
- if(light_amount > 0.2) //if there's enough light, heal
- H.heal_overall_damage(1,1)
- H.adjustToxLoss(-1)
- H.adjustOxyLoss(-1)
-
- if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
- H.take_overall_damage(2,0)
-
-/datum/species/golem/wood/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(chem.id == "plantbgone")
- H.adjustToxLoss(3)
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
- return 1
-
-//Radioactive
-/datum/species/golem/uranium
- name = "Uranium Golem"
- id = "uranium golem"
- fixed_mut_color = "7f0"
- meat = /obj/item/stack/ore/uranium
- info_text = "As an Uranium Golem, you emit radiation pulses every once in a while. It won't harm fellow golems, but organic lifeforms will be affected."
-
- var/last_event = 0
- var/active = null
- prefix = "Uranium"
- special_names = list("Oxide", "Rod", "Meltdown")
-
-/datum/species/golem/uranium/spec_life(mob/living/carbon/human/H)
- if(!active)
- if(world.time > last_event+30)
- active = 1
- radiation_pulse(H, 50)
- last_event = world.time
- active = null
- ..()
-
-//Immune to physical bullets and resistant to brute, but very vulnerable to burn damage. Dusts on death.
-/datum/species/golem/sand
- name = "Sand Golem"
- id = "sand golem"
- fixed_mut_color = "ffdc8f"
- meat = /obj/item/stack/ore/glass //this is sand
- armor = 0
- burnmod = 3 //melts easily
- brutemod = 0.25
- info_text = "As a Sand Golem, you are immune to physical bullets and take very little brute damage, but are extremely vulnerable to burn damage and energy weapons. You will also turn to sand when dying, preventing any form of recovery."
- attack_sound = 'sound/effects/shovel_dig.ogg'
- prefix = "Sand"
- special_names = list("Castle", "Bag", "Dune", "Worm", "Storm")
-
-/datum/species/golem/sand/spec_death(gibbed, mob/living/carbon/human/H)
- H.visible_message("[H] turns into a pile of sand!")
- for(var/obj/item/W in H)
- H.dropItemToGround(W)
- for(var/i=1, i <= rand(3,5), i++)
- new /obj/item/stack/ore/glass(get_turf(H))
- qdel(H)
-
-/datum/species/golem/sand/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
- if(!(P.original == H && P.firer == H))
- if(P.flag == "bullet" || P.flag == "bomb")
- playsound(H, 'sound/effects/shovel_dig.ogg', 70, 1)
- H.visible_message("The [P.name] sinks harmlessly in [H]'s sandy body!", \
- "The [P.name] sinks harmlessly in [H]'s sandy body!")
- return 2
- return 0
-
-//Reflects lasers and resistant to burn damage, but very vulnerable to brute damage. Shatters on death.
-/datum/species/golem/glass
- name = "Glass Golem"
- id = "glass golem"
- fixed_mut_color = "5a96b4aa" //transparent body
- meat = /obj/item/shard
- armor = 0
- brutemod = 3 //very fragile
- burnmod = 0.25
- info_text = "As a Glass Golem, you reflect lasers and energy weapons, and are very resistant to burn damage. However, you are extremely vulnerable to brute damage. On death, you'll shatter beyond any hope of recovery."
- attack_sound = 'sound/effects/glassbr2.ogg'
- prefix = "Glass"
- special_names = list("Lens", "Prism", "Fiber", "Bead")
-
-/datum/species/golem/glass/spec_death(gibbed, mob/living/carbon/human/H)
- playsound(H, "shatter", 70, 1)
- H.visible_message("[H] shatters!")
- for(var/obj/item/W in H)
- H.dropItemToGround(W)
- for(var/i=1, i <= rand(3,5), i++)
- new /obj/item/shard(get_turf(H))
- qdel(H)
-
-/datum/species/golem/glass/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
- if(!(P.original == H && P.firer == H)) //self-shots don't reflect
- if(P.flag == "laser" || P.flag == "energy")
- H.visible_message("The [P.name] gets reflected by [H]'s glass skin!", \
- "The [P.name] gets reflected by [H]'s glass skin!")
- if(P.starting)
- var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/turf/target = get_turf(P.starting)
- // redirect the projectile
- P.preparePixelProjectile(locate(CLAMP(target.x + new_x, 1, world.maxx), CLAMP(target.y + new_y, 1, world.maxy), H.z), H)
- return -1
- return 0
-
-//Teleports when hit or when it wants to
-/datum/species/golem/bluespace
- name = "Bluespace Golem"
- id = "bluespace golem"
- fixed_mut_color = "33f"
- meat = /obj/item/stack/ore/bluespace_crystal
- info_text = "As a Bluespace Golem, you are spatially unstable: You will teleport when hit, and you can teleport manually at a long distance."
- attack_verb = "bluespace punch"
- attack_sound = 'sound/effects/phasein.ogg'
- prefix = "Bluespace"
- special_names = list("Crystal", "Polycrystal")
-
- var/datum/action/innate/unstable_teleport/unstable_teleport
- var/teleport_cooldown = 100
- var/last_teleport = 0
-
-/datum/species/golem/bluespace/proc/reactive_teleport(mob/living/carbon/human/H)
- H.visible_message("[H] teleports!", "You destabilize and teleport!")
- new /obj/effect/particle_effect/sparks(get_turf(H))
- playsound(get_turf(H), "sparks", 50, 1)
- do_teleport(H, get_turf(H), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
- last_teleport = world.time
-
-/datum/species/golem/bluespace/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
- ..()
- var/obj/item/I
- if(istype(AM, /obj/item))
- I = AM
- if(I.thrownby == H) //No throwing stuff at yourself to trigger the teleport
- return 0
- else
- reactive_teleport(H)
-
-/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
- ..()
- if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP)
- reactive_teleport(H)
-
-/datum/species/golem/bluespace/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
- ..()
- if(world.time > last_teleport + teleport_cooldown && user != H)
- reactive_teleport(H)
-
-/datum/species/golem/bluespace/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
- ..()
- if(world.time > last_teleport + teleport_cooldown)
- reactive_teleport(H)
-
-/datum/species/golem/bluespace/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- if(ishuman(C))
- unstable_teleport = new
- unstable_teleport.Grant(C)
- last_teleport = world.time
-
-/datum/species/golem/bluespace/on_species_loss(mob/living/carbon/C)
- if(unstable_teleport)
- unstable_teleport.Remove(C)
- ..()
-
-/datum/action/innate/unstable_teleport
- name = "Unstable Teleport"
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "jaunt"
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
- var/cooldown = 150
- var/last_teleport = 0
-
-/datum/action/innate/unstable_teleport/IsAvailable()
- if(..())
- if(world.time > last_teleport + cooldown)
- return 1
- return 0
-
-/datum/action/innate/unstable_teleport/Activate()
- var/mob/living/carbon/human/H = owner
- H.visible_message("[H] starts vibrating!", "You start charging your bluespace core...")
- playsound(get_turf(H), 'sound/weapons/flash.ogg', 25, 1)
- addtimer(CALLBACK(src, .proc/teleport, H), 15)
-
-/datum/action/innate/unstable_teleport/proc/teleport(mob/living/carbon/human/H)
- H.visible_message("[H] disappears in a shower of sparks!", "You teleport!")
- var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
- spark_system.set_up(10, 0, src)
- spark_system.attach(H)
- spark_system.start()
- do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
- last_teleport = world.time
- UpdateButtonIcon() //action icon looks unavailable
- sleep(cooldown + 5)
- UpdateButtonIcon() //action icon looks available again
-
-
-//honk
-/datum/species/golem/bananium
- name = "Bananium Golem"
- id = "bananium golem"
- fixed_mut_color = "ff0"
- say_mod = "honks"
- punchdamagelow = 0
- punchdamagehigh = 1
- punchstunthreshold = 2 //Harmless and can't stun
- meat = /obj/item/stack/ore/bananium
- info_text = "As a Bananium Golem, you are made for pranking. Your body emits natural honks, and you can barely even hurt people when punching them. Your skin also bleeds banana peels when damaged."
- attack_verb = "honk"
- attack_sound = 'sound/items/airhorn2.ogg'
- prefix = "Bananium"
- special_names = null
-
- var/last_honk = 0
- var/honkooldown = 0
- var/last_banana = 0
- var/banana_cooldown = 100
- var/active = null
-
-/datum/species/golem/bananium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- last_banana = world.time
- last_honk = world.time
- RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech)
-
-/datum/species/golem/bananium/on_species_loss(mob/living/carbon/C)
- . = ..()
- UnregisterSignal(C, COMSIG_MOB_SAY)
-
-/datum/species/golem/bananium/random_name(gender,unique,lastname)
- var/clown_name = pick(GLOB.clown_names)
- var/golem_name = "[uppertext(clown_name)]"
- return golem_name
-
-/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
- ..()
- if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
- new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
- last_banana = world.time
-
-/datum/species/golem/bananium/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
- ..()
- if(world.time > last_banana + banana_cooldown && user != H)
- new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
- last_banana = world.time
-
-/datum/species/golem/bananium/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
- ..()
- if(world.time > last_banana + banana_cooldown)
- new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
- last_banana = world.time
-
-/datum/species/golem/bananium/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
- ..()
- var/obj/item/I
- if(istype(AM, /obj/item))
- I = AM
- if(I.thrownby == H) //No throwing stuff at yourself to make bananas
- return 0
- else
- new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
- last_banana = world.time
-
-/datum/species/golem/bananium/spec_life(mob/living/carbon/human/H)
- if(!active)
- if(world.time > last_honk + honkooldown)
- active = 1
- playsound(get_turf(H), 'sound/items/bikehorn.ogg', 50, 1)
- last_honk = world.time
- honkooldown = rand(20, 80)
- active = null
- ..()
-
-/datum/species/golem/bananium/spec_death(gibbed, mob/living/carbon/human/H)
- playsound(get_turf(H), 'sound/misc/sadtrombone.ogg', 70, 0)
-
-/datum/species/golem/bananium/proc/handle_speech(datum/source, list/speech_args)
- speech_args[SPEECH_SPANS] |= SPAN_CLOWN
-
-/datum/species/golem/runic
- name = "Runic Golem"
- id = "runic golem"
- limbs_id = "cultgolem"
- sexes = FALSE
- info_text = "As a Runic Golem, you possess eldritch powers granted by the Elder Goddess Nar'Sie."
- species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES) //no mutcolors
- prefix = "Runic"
- special_names = null
-
- var/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/golem/phase_shift
- var/obj/effect/proc_holder/spell/targeted/abyssal_gaze/abyssal_gaze
- var/obj/effect/proc_holder/spell/targeted/dominate/dominate
-
-/datum/species/golem/runic/random_name(gender,unique,lastname)
- var/edgy_first_name = pick("Razor","Blood","Dark","Evil","Cold","Pale","Black","Silent","Chaos","Deadly","Coldsteel")
- var/edgy_last_name = pick("Edge","Night","Death","Razor","Blade","Steel","Calamity","Twilight","Shadow","Nightmare") //dammit Razor Razor
- var/golem_name = "[edgy_first_name] [edgy_last_name]"
- return golem_name
-
-/datum/species/golem/runic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- . = ..()
- C.faction |= "cult"
- phase_shift = new
- phase_shift.charge_counter = 0
- C.AddSpell(phase_shift)
- abyssal_gaze = new
- abyssal_gaze.charge_counter = 0
- C.AddSpell(abyssal_gaze)
- dominate = new
- dominate.charge_counter = 0
- C.AddSpell(dominate)
-
-/datum/species/golem/runic/on_species_loss(mob/living/carbon/C)
- . = ..()
- C.faction -= "cult"
- if(phase_shift)
- C.RemoveSpell(phase_shift)
- if(abyssal_gaze)
- C.RemoveSpell(abyssal_gaze)
- if(dominate)
- C.RemoveSpell(dominate)
-
-/datum/species/golem/runic/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(chem.id == "holywater")
- H.adjustFireLoss(4)
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
-
- if(chem.id == "unholywater")
- H.adjustBruteLoss(-4)
- H.adjustFireLoss(-4)
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
-
-
-/datum/species/golem/clockwork
- name = "Clockwork Golem"
- id = "clockwork golem"
- say_mod = "clicks"
- limbs_id = "clockgolem"
- info_text = "As a Clockwork Golem, you are faster than other types of golems. On death, you will break down into scrap."
- species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES)
- inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
- armor = 20 //Reinforced, but much less so to allow for fast movement
- attack_verb = "smash"
- attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
- sexes = FALSE
- speedmod = 0
- damage_overlay_type = "synth"
- prefix = "Clockwork"
- special_names = list("Remnant", "Relic", "Scrap", "Vestige") //RIP Ratvar
- var/has_corpse
-
-/datum/species/golem/clockwork/on_species_gain(mob/living/carbon/human/H)
- . = ..()
- H.faction |= "ratvar"
- RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech)
-
-/datum/species/golem/clockwork/on_species_loss(mob/living/carbon/human/H)
- if(!is_servant_of_ratvar(H))
- H.faction -= "ratvar"
- UnregisterSignal(H, COMSIG_MOB_SAY)
- . = ..()
-
-/datum/species/golem/clockwork/proc/handle_speech(datum/source, list/speech_args)
- speech_args[SPEECH_SPANS] |= SPAN_ROBOT //beep
-
-/datum/species/golem/clockwork/spec_death(gibbed, mob/living/carbon/human/H)
- gibbed = !has_corpse ? FALSE : gibbed
- . = ..()
- if(!has_corpse)
- var/turf/T = get_turf(H)
- H.visible_message("[H]'s exoskeleton shatters, collapsing into a heap of scrap!")
- playsound(H, 'sound/magic/clockwork/anima_fragment_death.ogg', 62, TRUE)
- for(var/i in 1 to rand(3, 5))
- new/obj/item/clockwork/alloy_shards/small(T)
- new/obj/item/clockwork/alloy_shards/clockgolem_remains(T)
- qdel(H)
-
-/datum/species/golem/clockwork/no_scrap //These golems are created through the herald's beacon and leave normal corpses on death.
- id = "clockwork golem servant"
- armor = 15 //Balance reasons make this armor weak
- no_equip = list()
- nojumpsuit = FALSE
- has_corpse = TRUE
- blacklisted = TRUE
- dangerous_existence = TRUE
- random_eligible = FALSE
- info_text = "As a Clockwork Golem Servant, you are faster than other types of golems." //warcult golems leave a corpse
-
-/datum/species/golem/cloth
- name = "Cloth Golem"
- id = "cloth golem"
- limbs_id = "clothgolem"
- sexes = FALSE
- info_text = "As a Cloth Golem, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \
- Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient."
- species_traits = list(NOBLOOD,NO_UNDERWEAR) //no mutcolors, and can burn
- inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOGUNS)
- inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
- armor = 15 //feels no pain, but not too resistant
- burnmod = 2 // don't get burned
- speedmod = 1 // not as heavy as stone
- punchdamagelow = 4
- punchstunthreshold = 7
- punchdamagehigh = 8 // not as heavy as stone
- prefix = "Cloth"
- special_names = null
-
-/datum/species/golem/cloth/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- ADD_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
-
-/datum/species/golem/cloth/on_species_loss(mob/living/carbon/C)
- REMOVE_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
- ..()
-
-/datum/species/golem/cloth/check_roundstart_eligible()
- if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
- return TRUE
- return ..()
-
-/datum/species/golem/cloth/random_name(gender,unique,lastname)
- var/pharaoh_name = pick("Neferkare", "Hudjefa", "Khufu", "Mentuhotep", "Ahmose", "Amenhotep", "Thutmose", "Hatshepsut", "Tutankhamun", "Ramses", "Seti", \
- "Merenptah", "Djer", "Semerkhet", "Nynetjer", "Khafre", "Pepi", "Intef", "Ay") //yes, Ay was an actual pharaoh
- var/golem_name = "[pharaoh_name] \Roman[rand(1,99)]"
- return golem_name
-
-/datum/species/golem/cloth/spec_life(mob/living/carbon/human/H)
- if(H.fire_stacks < 1)
- H.adjust_fire_stacks(1) //always prone to burning
- ..()
-
-/datum/species/golem/cloth/spec_death(gibbed, mob/living/carbon/human/H)
- if(gibbed)
- return
- if(H.on_fire)
- H.visible_message("[H] burns into ash!")
- H.dust(just_ash = TRUE)
- return
-
- H.visible_message("[H] falls apart into a pile of bandages!")
- new /obj/structure/cloth_pile(get_turf(H), H)
- ..()
-
-/obj/structure/cloth_pile
- name = "pile of bandages"
- desc = "It emits a strange aura, as if there was still life within it..."
- max_integrity = 50
- armor = list("melee" = 90, "bullet" = 90, "laser" = 25, "energy" = 80, "bomb" = 50, "bio" = 100, "fire" = -50, "acid" = -50)
- icon = 'icons/obj/items_and_weapons.dmi'
- icon_state = "pile_bandages"
- resistance_flags = FLAMMABLE
-
- var/revive_time = 900
- var/mob/living/carbon/human/cloth_golem
-
-/obj/structure/cloth_pile/Initialize(mapload, mob/living/carbon/human/H)
- . = ..()
- if(!QDELETED(H) && is_species(H, /datum/species/golem/cloth))
- H.unequip_everything()
- H.forceMove(src)
- cloth_golem = H
- to_chat(cloth_golem, "You start gathering your life energy, preparing to rise again...")
- addtimer(CALLBACK(src, .proc/revive), revive_time)
- else
- return INITIALIZE_HINT_QDEL
-
-/obj/structure/cloth_pile/Destroy()
- if(cloth_golem)
- QDEL_NULL(cloth_golem)
- return ..()
-
-/obj/structure/cloth_pile/burn()
- visible_message("[src] burns into ash!")
- new /obj/effect/decal/cleanable/ash(get_turf(src))
- ..()
-
-/obj/structure/cloth_pile/proc/revive()
- if(QDELETED(src) || QDELETED(cloth_golem)) //QDELETED also checks for null, so if no cloth golem is set this won't runtime
- return
- if(cloth_golem.suiciding || HAS_TRAIT(cloth_golem, TRAIT_NOCLONE))
- QDEL_NULL(cloth_golem)
- return
-
- invisibility = INVISIBILITY_MAXIMUM //disappear before the animation
- new /obj/effect/temp_visual/mummy_animation(get_turf(src))
- if(cloth_golem.revive(full_heal = TRUE, admin_revive = TRUE))
- cloth_golem.grab_ghost() //won't pull if it's a suicide
- sleep(20)
- cloth_golem.forceMove(get_turf(src))
- cloth_golem.visible_message("[src] rises and reforms into [cloth_golem]!","You reform into yourself!")
- cloth_golem = null
- qdel(src)
-
-/obj/structure/cloth_pile/attackby(obj/item/P, mob/living/carbon/human/user, params)
- . = ..()
-
- if(resistance_flags & ON_FIRE)
- return
-
- if(P.is_hot())
- visible_message("[src] bursts into flames!")
- fire_act()
-
-/datum/species/golem/plastic
- name = "Plastic Golem"
- id = "plastic golem"
- prefix = "Plastic"
- special_names = null
- fixed_mut_color = "fff"
- info_text = "As a Plastic Golem, you are capable of ventcrawling and passing through plastic flaps as long as you are naked."
-
-/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- . = ..()
- C.ventcrawler = VENTCRAWLER_NUDE
-
-/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
- . = ..()
- C.ventcrawler = initial(C.ventcrawler)
-
-/datum/species/golem/bronze
- name = "Bronze Golem"
- id = "bronze golem"
- prefix = "Bronze"
- special_names = list("Bell")
- fixed_mut_color = "cd7f32"
- info_text = "As a Bronze Golem, you are very resistant to loud noises, and make loud noises if something hard hits you, however this ability does hurt your hearing."
- special_step_sounds = list('sound/machines/clockcult/integration_cog_install.ogg', 'sound/magic/clockwork/fellowship_armory.ogg' )
- attack_verb = "bonk"
- mutantears = /obj/item/organ/ears/bronze
- var/last_gong_time = 0
- var/gong_cooldown = 150
-
-/datum/species/golem/bronze/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
- if(!(world.time > last_gong_time + gong_cooldown))
- return ..()
- if(P.flag == "bullet" || P.flag == "bomb")
- gong(H)
- return ..()
-
-/datum/species/golem/bronze/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
- ..()
- if(world.time > last_gong_time + gong_cooldown)
- gong(H)
-
-/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
- ..()
- if(world.time > last_gong_time + gong_cooldown && M.a_intent != INTENT_HELP)
- gong(H)
-
-/datum/species/golem/bronze/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
- ..()
- if(world.time > last_gong_time + gong_cooldown)
- gong(H)
-
-/datum/species/golem/bronze/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
- ..()
- if(world.time > last_gong_time + gong_cooldown)
- gong(H)
-
-/datum/species/golem/bronze/proc/gong(mob/living/carbon/human/H)
- last_gong_time = world.time
- for(var/mob/living/M in get_hearers_in_view(7,H))
- if(M.stat == DEAD) //F
- return
- if(M == H)
- H.show_message("You cringe with pain as your body rings around you!", 2)
- H.playsound_local(H, 'sound/effects/gong.ogg', 100, TRUE)
- H.soundbang_act(2, 0, 100, 1)
- H.jitteriness += 7
- var/distance = max(0,get_dist(get_turf(H),get_turf(M)))
- switch(distance)
- if(0 to 1)
- M.show_message("GONG!", 2)
- M.playsound_local(H, 'sound/effects/gong.ogg', 100, TRUE)
- M.soundbang_act(1, 0, 30, 3)
- M.confused += 10
- M.jitteriness += 4
- SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "gonged", /datum/mood_event/loud_gong)
- if(2 to 3)
- M.show_message("GONG!", 2)
- M.playsound_local(H, 'sound/effects/gong.ogg', 75, TRUE)
- M.soundbang_act(1, 0, 15, 2)
- M.jitteriness += 3
- SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "gonged", /datum/mood_event/loud_gong)
- else
- M.show_message("GONG!", 2)
- M.playsound_local(H, 'sound/effects/gong.ogg', 50, TRUE)
-
-
-/datum/species/golem/cardboard //Faster but weaker, can also make new shells on its own
- name = "Cardboard Golem"
- id = "cardboard golem"
- prefix = "Cardboard"
- special_names = list("Box")
- info_text = "As a Cardboard Golem, you aren't very strong, but you are a bit quicker and can easily create more brethren by using cardboard on yourself."
- species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL,MUTCOLORS)
- inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
- fixed_mut_color = "ffffff"
- limbs_id = "c_golem" //special sprites
- attack_verb = "bash"
- armor = 25
- burnmod = 1.25
- heatmod = 2
- speedmod = 1.5
- punchdamagelow = 4
- punchstunthreshold = 7
- punchdamagehigh = 8
- var/last_creation = 0
- var/brother_creation_cooldown = 300
-
-/datum/species/golem/cardboard/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
- . = ..()
- if(user != H)
- return FALSE //forced reproduction is r/non-con
- if(istype(I, /obj/item/stack/sheet/cardboard))
- var/obj/item/stack/sheet/cardboard/C = I
- if(last_creation + brother_creation_cooldown > world.time) //no cheesing dork
- return
- if(C.amount < 10)
- to_chat(H, "You do not have enough cardboard!")
- return FALSE
- to_chat(H, "You attempt to create a new cardboard brother.")
- if(do_after(user, 30, target = user))
- if(last_creation + brother_creation_cooldown > world.time) //no cheesing dork
- return
- if(!C.use(10))
- to_chat(H, "You do not have enough cardboard!")
- return FALSE
- to_chat(H, "You create a new cardboard golem shell.")
- create_brother(H.loc)
-
-/datum/species/golem/cardboard/proc/create_brother(var/location)
- new /obj/effect/mob_spawn/human/golem/servant(location, /datum/species/golem/cardboard, owner)
- last_creation = world.time
-
-/datum/species/golem/leather
- name = "Leather Golem"
- id = "leather golem"
- special_names = list("Face", "Man", "Belt") //Ah dude 4 strength 4 stam leather belt AHHH
- inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_STRONG_GRABBER)
- prefix = "Leather"
- fixed_mut_color = "624a2e"
- info_text = "As a Leather Golem, you are flammable, but you can grab things with incredible ease, allowing all your grabs to start at a strong level."
- attack_verb = "whipp"
- grab_sound = 'sound/weapons/whipgrab.ogg'
- attack_sound = 'sound/weapons/whip.ogg'
-
-/datum/species/golem/bone
- name = "Bone Golem"
- id = "bone golem"
- say_mod = "rattles"
- prefix = "Bone"
- limbs_id = "b_golem"
- special_names = list("Head", "Broth", "Fracture", "Rattler", "Appetit")
- liked_food = GROSS | MEAT | RAW
- toxic_food = null
- inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
- mutanttongue = /obj/item/organ/tongue/bone
- sexes = FALSE
- fixed_mut_color = "ffffff"
- attack_verb = "rattl"
- species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL,MUTCOLORS)
- inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_FAKEDEATH,TRAIT_CALCIUM_HEALER)
- info_text = "As a Bone Golem, You have a powerful spell that lets you chill your enemies with fear, and milk heals you! Just make sure to watch our for bone-hurting juice."
- var/datum/action/innate/bonechill/bonechill
-
-/datum/species/golem/bone/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- if(ishuman(C))
- bonechill = new
- bonechill.Grant(C)
-
-/datum/species/golem/bone/on_species_loss(mob/living/carbon/C)
- if(bonechill)
- bonechill.Remove(C)
- ..()
-
-/datum/action/innate/bonechill
- name = "Bone Chill"
- desc = "Rattle your bones and strike fear into your enemies!"
- check_flags = AB_CHECK_CONSCIOUS
- icon_icon = 'icons/mob/actions/actions_spells.dmi'
- button_icon_state = "bonechill"
- var/cooldown = 600
- var/last_use
- var/snas_chance = 3
-
-/datum/action/innate/bonechill/Activate()
- if(world.time < last_use + cooldown)
- to_chat("You aren't ready yet to rattle your bones again")
- return
- owner.visible_message("[owner] rattles [owner.p_their()] bones harrowingly.", "You rattle your bones")
- last_use = world.time
- if(prob(snas_chance))
- playsound(get_turf(owner),'sound/magic/RATTLEMEBONES2.ogg', 100)
- if(ishuman(owner))
- var/mob/living/carbon/human/H = owner
- var/mutable_appearance/badtime = mutable_appearance('icons/mob/human_parts.dmi', "b_golem_eyes", -FIRE_LAYER-0.5)
- badtime.appearance_flags = RESET_COLOR
- H.overlays_standing[FIRE_LAYER+0.5] = badtime
- H.apply_overlay(FIRE_LAYER+0.5)
- addtimer(CALLBACK(H, /mob/living/carbon/.proc/remove_overlay, FIRE_LAYER+0.5), 25)
- else
- playsound(get_turf(owner),'sound/magic/RATTLEMEBONES.ogg', 100)
- for(var/mob/living/L in orange(7, get_turf(owner)))
- if((MOB_UNDEAD in L.mob_biotypes) || isgolem(L) || HAS_TRAIT(L, TRAIT_RESISTCOLD))
- return //Do not affect our brothers
-
- to_chat(L, "A spine-chilling sound chills you to the bone!")
- L.apply_status_effect(/datum/status_effect/bonechill)
- SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "spooked", /datum/mood_event/spooked)
+/datum/species/golem
+ // Animated beings of stone. They have increased defenses, and do not need to breathe. They're also slow as fuuuck.
+ name = "Golem"
+ id = "iron golem"
+ species_traits = list(NOBLOOD,MUTCOLORS,NO_UNDERWEAR,NOGENITALS,NOAROUSAL)
+ inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
+ inherent_biotypes = list(MOB_INORGANIC, MOB_HUMANOID)
+ mutant_organs = list(/obj/item/organ/adamantine_resonator)
+ speedmod = 2
+ armor = 55
+ siemens_coeff = 0
+ punchdamagelow = 5
+ punchdamagehigh = 14
+ punchstunthreshold = 11 //about 40% chance to stun
+ no_equip = list(SLOT_WEAR_MASK, SLOT_WEAR_SUIT, SLOT_GLOVES, SLOT_SHOES, SLOT_W_UNIFORM, SLOT_S_STORE)
+ nojumpsuit = 1
+ sexes = 1
+ damage_overlay_type = ""
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/golem
+ // To prevent golem subtypes from overwhelming the odds when random species
+ // changes, only the Random Golem type can be chosen
+ blacklisted = TRUE
+ dangerous_existence = TRUE
+ limbs_id = "golem"
+ fixed_mut_color = "aaa"
+ var/info_text = "As an Iron Golem, you don't have any special traits."
+ var/random_eligible = TRUE //If false, the golem subtype can't be made through golem mutation toxin
+
+ var/prefix = "Iron"
+ var/list/special_names = list("Tarkus")
+ var/human_surname_chance = 3
+ var/special_name_chance = 5
+ var/owner //dobby is a free golem
+
+/datum/species/golem/random_name(gender,unique,lastname)
+ var/golem_surname = pick(GLOB.golem_names)
+ // 3% chance that our golem has a human surname, because
+ // cultural contamination
+ if(prob(human_surname_chance))
+ golem_surname = pick(GLOB.last_names)
+ else if(special_names && special_names.len && prob(special_name_chance))
+ golem_surname = pick(special_names)
+
+ var/golem_name = "[prefix] [golem_surname]"
+ return golem_name
+
+/datum/species/golem/random
+ name = "Random Golem"
+ blacklisted = FALSE
+ dangerous_existence = FALSE
+ var/static/list/random_golem_types
+
+/datum/species/golem/random/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ if(!random_golem_types)
+ random_golem_types = subtypesof(/datum/species/golem) - type
+ for(var/V in random_golem_types)
+ var/datum/species/golem/G = V
+ if(!initial(G.random_eligible))
+ random_golem_types -= G
+ var/datum/species/golem/golem_type = pick(random_golem_types)
+ var/mob/living/carbon/human/H = C
+ H.set_species(golem_type)
+ to_chat(H, "[initial(golem_type.info_text)]")
+
+/datum/species/golem/adamantine
+ name = "Adamantine Golem"
+ id = "adamantine golem"
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/golem/adamantine
+ mutant_organs = list(/obj/item/organ/adamantine_resonator, /obj/item/organ/vocal_cords/adamantine)
+ fixed_mut_color = "4ed"
+ info_text = "As an Adamantine Golem, you possess special vocal cords allowing you to \"resonate\" messages to all golems. Your unique mineral makeup makes you immune to most types of magic."
+ prefix = "Adamantine"
+ special_names = null
+
+/datum/species/golem/adamantine/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ ADD_TRAIT(C, TRAIT_ANTIMAGIC, SPECIES_TRAIT)
+
+/datum/species/golem/adamantine/on_species_loss(mob/living/carbon/C)
+ REMOVE_TRAIT(C, TRAIT_ANTIMAGIC, SPECIES_TRAIT)
+ ..()
+
+//The suicide bombers of golemkind
+/datum/species/golem/plasma
+ name = "Plasma Golem"
+ id = "plasma golem"
+ fixed_mut_color = "a3d"
+ meat = /obj/item/stack/ore/plasma
+ //Can burn and takes damage from heat
+ inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER) //no RESISTHEAT, NOFIRE
+ info_text = "As a Plasma Golem, you burn easily. Be careful, if you get hot enough while burning, you'll blow up!"
+ heatmod = 0 //fine until they blow up
+ prefix = "Plasma"
+ special_names = list("Flood","Fire","Bar","Man")
+ var/boom_warning = FALSE
+ var/datum/action/innate/ignite/ignite
+
+/datum/species/golem/plasma/spec_life(mob/living/carbon/human/H)
+ if(H.bodytemperature > 750)
+ if(!boom_warning && H.on_fire)
+ to_chat(H, "You feel like you could blow up at any moment!")
+ boom_warning = TRUE
+ else
+ if(boom_warning)
+ to_chat(H, "You feel more stable.")
+ boom_warning = FALSE
+
+ if(H.bodytemperature > 850 && H.on_fire && prob(25))
+ explosion(get_turf(H),1,2,4,flame_range = 5)
+ if(H)
+ H.gib()
+ if(H.fire_stacks < 2) //flammable
+ H.adjust_fire_stacks(1)
+ ..()
+
+/datum/species/golem/plasma/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ if(ishuman(C))
+ ignite = new
+ ignite.Grant(C)
+
+/datum/species/golem/plasma/on_species_loss(mob/living/carbon/C)
+ if(ignite)
+ ignite.Remove(C)
+ ..()
+
+/datum/action/innate/ignite
+ name = "Ignite"
+ desc = "Set yourself aflame, bringing yourself closer to exploding!"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "sacredflame"
+
+/datum/action/innate/ignite/Activate()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ if(H.fire_stacks)
+ to_chat(owner, "You ignite yourself!")
+ else
+ to_chat(owner, "You try to ignite yourself, but fail!")
+ H.IgniteMob() //firestacks are already there passively
+
+//Harder to hurt
+/datum/species/golem/diamond
+ name = "Diamond Golem"
+ id = "diamond golem"
+ fixed_mut_color = "0ff"
+ armor = 70 //up from 55
+ meat = /obj/item/stack/ore/diamond
+ info_text = "As a Diamond Golem, you are more resistant than the average golem."
+ prefix = "Diamond"
+ special_names = list("Back")
+
+//Faster but softer and less armoured
+/datum/species/golem/gold
+ name = "Gold Golem"
+ id = "gold golem"
+ fixed_mut_color = "cc0"
+ speedmod = 1
+ armor = 25 //down from 55
+ meat = /obj/item/stack/ore/gold
+ info_text = "As a Gold Golem, you are faster but less resistant than the average golem."
+ prefix = "Golden"
+ special_names = list("Boy")
+
+//Heavier, thus higher chance of stunning when punching
+/datum/species/golem/silver
+ name = "Silver Golem"
+ id = "silver golem"
+ fixed_mut_color = "ddd"
+ punchstunthreshold = 9 //60% chance, from 40%
+ meat = /obj/item/stack/ore/silver
+ info_text = "As a Silver Golem, your attacks have a higher chance of stunning. Being made of silver, your body is immune to most types of magic."
+ prefix = "Silver"
+ special_names = list("Surfer", "Chariot", "Lining")
+
+/datum/species/golem/silver/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ ADD_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
+
+/datum/species/golem/silver/on_species_loss(mob/living/carbon/C)
+ REMOVE_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
+ ..()
+
+//Harder to stun, deals more damage, but it's even slower
+/datum/species/golem/plasteel
+ name = "Plasteel Golem"
+ id = "plasteel golem"
+ fixed_mut_color = "bbb"
+ stunmod = 0.4
+ punchdamagelow = 12
+ punchdamagehigh = 21
+ punchstunthreshold = 18 //still 40% stun chance
+ speedmod = 4 //pretty fucking slow
+ meat = /obj/item/stack/ore/iron
+ info_text = "As a Plasteel Golem, you are slower, but harder to stun, and hit very hard when punching."
+ attack_verb = "smash"
+ attack_sound = 'sound/effects/meteorimpact.ogg' //hits pretty hard
+ prefix = "Plasteel"
+ special_names = null
+
+//Immune to ash storms
+/datum/species/golem/titanium
+ name = "Titanium Golem"
+ id = "titanium golem"
+ fixed_mut_color = "fff"
+ meat = /obj/item/stack/ore/titanium
+ info_text = "As a Titanium Golem, you are immune to ash storms, and slightly more resistant to burn damage."
+ burnmod = 0.9
+ prefix = "Titanium"
+ special_names = list("Dioxide")
+
+/datum/species/golem/titanium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ C.weather_immunities |= "ash"
+
+/datum/species/golem/titanium/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ C.weather_immunities -= "ash"
+
+//Immune to ash storms and lava
+/datum/species/golem/plastitanium
+ name = "Plastitanium Golem"
+ id = "plastitanium golem"
+ fixed_mut_color = "888"
+ meat = /obj/item/stack/ore/titanium
+ info_text = "As a Plastitanium Golem, you are immune to both ash storms and lava, and slightly more resistant to burn damage."
+ burnmod = 0.8
+ prefix = "Plastitanium"
+ special_names = null
+
+/datum/species/golem/plastitanium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ C.weather_immunities |= "lava"
+ C.weather_immunities |= "ash"
+
+/datum/species/golem/plastitanium/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ C.weather_immunities -= "ash"
+ C.weather_immunities -= "lava"
+
+//Fast and regenerates... but can only speak like an abductor
+/datum/species/golem/alloy
+ name = "Alien Alloy Golem"
+ id = "alloy golem"
+ fixed_mut_color = "333"
+ meat = /obj/item/stack/sheet/mineral/abductor
+ mutanttongue = /obj/item/organ/tongue/abductor
+ speedmod = 1 //faster
+ info_text = "As an Alloy Golem, you are made of advanced alien materials: you are faster and regenerate over time. You are, however, only able to be heard by other alloy golems."
+ prefix = "Alien"
+ special_names = list("Outsider", "Technology", "Watcher", "Stranger") //ominous and unknown
+
+//Regenerates because self-repairing super-advanced alien tech
+/datum/species/golem/alloy/spec_life(mob/living/carbon/human/H)
+ if(H.stat == DEAD)
+ return
+ H.heal_overall_damage(2,2)
+ H.adjustToxLoss(-2)
+ H.adjustOxyLoss(-2)
+
+//Since this will usually be created from a collaboration between podpeople and free golems, wood golems are a mix between the two races
+/datum/species/golem/wood
+ name = "Wood Golem"
+ id = "wood golem"
+ fixed_mut_color = "9E704B"
+ meat = /obj/item/stack/sheet/mineral/wood
+ //Can burn and take damage from heat
+ inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
+ armor = 30
+ burnmod = 1.25
+ heatmod = 1.5
+ info_text = "As a Wooden Golem, you have plant-like traits: you take damage from extreme temperatures, can be set on fire, and have lower armor than a normal golem. You regenerate when in the light and wither in the darkness."
+ prefix = "Wooden"
+ special_names = list("Bark", "Willow", "Catalpa", "Woody", "Oak", "Sap", "Twig", "Branch", "Maple", "Birch", "Elm", "Basswood", "Cottonwood", "Larch", "Aspen", "Ash", "Beech", "Buckeye", "Cedar", "Chestnut", "Cypress", "Fir", "Hawthorn", "Hazel", "Hickory", "Ironwood", "Juniper", "Leaf", "Mangrove", "Palm", "Pawpaw", "Pine", "Poplar", "Redwood", "Redbud", "Sassafras", "Spruce", "Sumac", "Trunk", "Walnut", "Yew")
+ human_surname_chance = 0
+ special_name_chance = 100
+
+/datum/species/golem/wood/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ C.faction |= "plants"
+ C.faction |= "vines"
+
+/datum/species/golem/wood/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ C.faction -= "plants"
+ C.faction -= "vines"
+
+/datum/species/golem/wood/spec_life(mob/living/carbon/human/H)
+ if(H.stat == DEAD)
+ return
+ var/light_amount = 0 //how much light there is in the place, affects receiving nutrition and healing
+ if(isturf(H.loc)) //else, there's considered to be no light
+ var/turf/T = H.loc
+ light_amount = min(1,T.get_lumcount()) - 0.5
+ H.nutrition += light_amount * 10
+ if(H.nutrition > NUTRITION_LEVEL_FULL)
+ H.nutrition = NUTRITION_LEVEL_FULL
+ if(light_amount > 0.2) //if there's enough light, heal
+ H.heal_overall_damage(1,1)
+ H.adjustToxLoss(-1)
+ H.adjustOxyLoss(-1)
+
+ if(H.nutrition < NUTRITION_LEVEL_STARVING + 50)
+ H.take_overall_damage(2,0)
+
+/datum/species/golem/wood/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
+ if(chem.type == /datum/reagent/toxin/plantbgone)
+ H.adjustToxLoss(3)
+ H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
+ return 1
+
+//Radioactive
+/datum/species/golem/uranium
+ name = "Uranium Golem"
+ id = "uranium golem"
+ fixed_mut_color = "7f0"
+ meat = /obj/item/stack/ore/uranium
+ info_text = "As an Uranium Golem, you emit radiation pulses every once in a while. It won't harm fellow golems, but organic lifeforms will be affected."
+
+ var/last_event = 0
+ var/active = null
+ prefix = "Uranium"
+ special_names = list("Oxide", "Rod", "Meltdown")
+
+/datum/species/golem/uranium/spec_life(mob/living/carbon/human/H)
+ if(!active)
+ if(world.time > last_event+30)
+ active = 1
+ radiation_pulse(H, 50)
+ last_event = world.time
+ active = null
+ ..()
+
+//Immune to physical bullets and resistant to brute, but very vulnerable to burn damage. Dusts on death.
+/datum/species/golem/sand
+ name = "Sand Golem"
+ id = "sand golem"
+ fixed_mut_color = "ffdc8f"
+ meat = /obj/item/stack/ore/glass //this is sand
+ armor = 0
+ burnmod = 3 //melts easily
+ brutemod = 0.25
+ info_text = "As a Sand Golem, you are immune to physical bullets and take very little brute damage, but are extremely vulnerable to burn damage and energy weapons. You will also turn to sand when dying, preventing any form of recovery."
+ attack_sound = 'sound/effects/shovel_dig.ogg'
+ prefix = "Sand"
+ special_names = list("Castle", "Bag", "Dune", "Worm", "Storm")
+
+/datum/species/golem/sand/spec_death(gibbed, mob/living/carbon/human/H)
+ H.visible_message("[H] turns into a pile of sand!")
+ for(var/obj/item/W in H)
+ H.dropItemToGround(W)
+ for(var/i=1, i <= rand(3,5), i++)
+ new /obj/item/stack/ore/glass(get_turf(H))
+ qdel(H)
+
+/datum/species/golem/sand/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
+ if(!(P.original == H && P.firer == H))
+ if(P.flag == "bullet" || P.flag == "bomb")
+ playsound(H, 'sound/effects/shovel_dig.ogg', 70, 1)
+ H.visible_message("The [P.name] sinks harmlessly in [H]'s sandy body!", \
+ "The [P.name] sinks harmlessly in [H]'s sandy body!")
+ return 2
+ return 0
+
+//Reflects lasers and resistant to burn damage, but very vulnerable to brute damage. Shatters on death.
+/datum/species/golem/glass
+ name = "Glass Golem"
+ id = "glass golem"
+ fixed_mut_color = "5a96b4aa" //transparent body
+ meat = /obj/item/shard
+ armor = 0
+ brutemod = 3 //very fragile
+ burnmod = 0.25
+ info_text = "As a Glass Golem, you reflect lasers and energy weapons, and are very resistant to burn damage. However, you are extremely vulnerable to brute damage. On death, you'll shatter beyond any hope of recovery."
+ attack_sound = 'sound/effects/glassbr2.ogg'
+ prefix = "Glass"
+ special_names = list("Lens", "Prism", "Fiber", "Bead")
+
+/datum/species/golem/glass/spec_death(gibbed, mob/living/carbon/human/H)
+ playsound(H, "shatter", 70, 1)
+ H.visible_message("[H] shatters!")
+ for(var/obj/item/W in H)
+ H.dropItemToGround(W)
+ for(var/i=1, i <= rand(3,5), i++)
+ new /obj/item/shard(get_turf(H))
+ qdel(H)
+
+/datum/species/golem/glass/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
+ if(!(P.original == H && P.firer == H)) //self-shots don't reflect
+ if(P.flag == "laser" || P.flag == "energy")
+ H.visible_message("The [P.name] gets reflected by [H]'s glass skin!", \
+ "The [P.name] gets reflected by [H]'s glass skin!")
+ if(P.starting)
+ var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/turf/target = get_turf(P.starting)
+ // redirect the projectile
+ P.preparePixelProjectile(locate(CLAMP(target.x + new_x, 1, world.maxx), CLAMP(target.y + new_y, 1, world.maxy), H.z), H)
+ return -1
+ return 0
+
+//Teleports when hit or when it wants to
+/datum/species/golem/bluespace
+ name = "Bluespace Golem"
+ id = "bluespace golem"
+ fixed_mut_color = "33f"
+ meat = /obj/item/stack/ore/bluespace_crystal
+ info_text = "As a Bluespace Golem, you are spatially unstable: You will teleport when hit, and you can teleport manually at a long distance."
+ attack_verb = "bluespace punch"
+ attack_sound = 'sound/effects/phasein.ogg'
+ prefix = "Bluespace"
+ special_names = list("Crystal", "Polycrystal")
+
+ var/datum/action/innate/unstable_teleport/unstable_teleport
+ var/teleport_cooldown = 100
+ var/last_teleport = 0
+
+/datum/species/golem/bluespace/proc/reactive_teleport(mob/living/carbon/human/H)
+ H.visible_message("[H] teleports!", "You destabilize and teleport!")
+ new /obj/effect/particle_effect/sparks(get_turf(H))
+ playsound(get_turf(H), "sparks", 50, 1)
+ do_teleport(H, get_turf(H), 6, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
+ last_teleport = world.time
+
+/datum/species/golem/bluespace/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
+ ..()
+ var/obj/item/I
+ if(istype(AM, /obj/item))
+ I = AM
+ if(I.thrownby == H) //No throwing stuff at yourself to trigger the teleport
+ return 0
+ else
+ reactive_teleport(H)
+
+/datum/species/golem/bluespace/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
+ ..()
+ if(world.time > last_teleport + teleport_cooldown && M != H && M.a_intent != INTENT_HELP)
+ reactive_teleport(H)
+
+/datum/species/golem/bluespace/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
+ ..()
+ if(world.time > last_teleport + teleport_cooldown && user != H)
+ reactive_teleport(H)
+
+/datum/species/golem/bluespace/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
+ ..()
+ if(world.time > last_teleport + teleport_cooldown)
+ reactive_teleport(H)
+
+/datum/species/golem/bluespace/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ if(ishuman(C))
+ unstable_teleport = new
+ unstable_teleport.Grant(C)
+ last_teleport = world.time
+
+/datum/species/golem/bluespace/on_species_loss(mob/living/carbon/C)
+ if(unstable_teleport)
+ unstable_teleport.Remove(C)
+ ..()
+
+/datum/action/innate/unstable_teleport
+ name = "Unstable Teleport"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "jaunt"
+ icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ var/cooldown = 150
+ var/last_teleport = 0
+
+/datum/action/innate/unstable_teleport/IsAvailable()
+ if(..())
+ if(world.time > last_teleport + cooldown)
+ return 1
+ return 0
+
+/datum/action/innate/unstable_teleport/Activate()
+ var/mob/living/carbon/human/H = owner
+ H.visible_message("[H] starts vibrating!", "You start charging your bluespace core...")
+ playsound(get_turf(H), 'sound/weapons/flash.ogg', 25, 1)
+ addtimer(CALLBACK(src, .proc/teleport, H), 15)
+
+/datum/action/innate/unstable_teleport/proc/teleport(mob/living/carbon/human/H)
+ H.visible_message("[H] disappears in a shower of sparks!", "You teleport!")
+ var/datum/effect_system/spark_spread/spark_system = new /datum/effect_system/spark_spread
+ spark_system.set_up(10, 0, src)
+ spark_system.attach(H)
+ spark_system.start()
+ do_teleport(H, get_turf(H), 12, asoundin = 'sound/weapons/emitter2.ogg', channel = TELEPORT_CHANNEL_BLUESPACE)
+ last_teleport = world.time
+ UpdateButtonIcon() //action icon looks unavailable
+ sleep(cooldown + 5)
+ UpdateButtonIcon() //action icon looks available again
+
+
+//honk
+/datum/species/golem/bananium
+ name = "Bananium Golem"
+ id = "bananium golem"
+ fixed_mut_color = "ff0"
+ say_mod = "honks"
+ punchdamagelow = 0
+ punchdamagehigh = 1
+ punchstunthreshold = 2 //Harmless and can't stun
+ meat = /obj/item/stack/ore/bananium
+ info_text = "As a Bananium Golem, you are made for pranking. Your body emits natural honks, and you can barely even hurt people when punching them. Your skin also bleeds banana peels when damaged."
+ attack_verb = "honk"
+ attack_sound = 'sound/items/airhorn2.ogg'
+ prefix = "Bananium"
+ special_names = null
+
+ var/last_honk = 0
+ var/honkooldown = 0
+ var/last_banana = 0
+ var/banana_cooldown = 100
+ var/active = null
+
+/datum/species/golem/bananium/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ last_banana = world.time
+ last_honk = world.time
+ RegisterSignal(C, COMSIG_MOB_SAY, .proc/handle_speech)
+
+/datum/species/golem/bananium/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ UnregisterSignal(C, COMSIG_MOB_SAY)
+
+/datum/species/golem/bananium/random_name(gender,unique,lastname)
+ var/clown_name = pick(GLOB.clown_names)
+ var/golem_name = "[uppertext(clown_name)]"
+ return golem_name
+
+/datum/species/golem/bananium/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
+ ..()
+ if(world.time > last_banana + banana_cooldown && M != H && M.a_intent != INTENT_HELP)
+ new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
+ last_banana = world.time
+
+/datum/species/golem/bananium/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
+ ..()
+ if(world.time > last_banana + banana_cooldown && user != H)
+ new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
+ last_banana = world.time
+
+/datum/species/golem/bananium/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
+ ..()
+ if(world.time > last_banana + banana_cooldown)
+ new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
+ last_banana = world.time
+
+/datum/species/golem/bananium/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
+ ..()
+ var/obj/item/I
+ if(istype(AM, /obj/item))
+ I = AM
+ if(I.thrownby == H) //No throwing stuff at yourself to make bananas
+ return 0
+ else
+ new/obj/item/grown/bananapeel/specialpeel(get_turf(H))
+ last_banana = world.time
+
+/datum/species/golem/bananium/spec_life(mob/living/carbon/human/H)
+ if(!active)
+ if(world.time > last_honk + honkooldown)
+ active = 1
+ playsound(get_turf(H), 'sound/items/bikehorn.ogg', 50, 1)
+ last_honk = world.time
+ honkooldown = rand(20, 80)
+ active = null
+ ..()
+
+/datum/species/golem/bananium/spec_death(gibbed, mob/living/carbon/human/H)
+ playsound(get_turf(H), 'sound/misc/sadtrombone.ogg', 70, 0)
+
+/datum/species/golem/bananium/proc/handle_speech(datum/source, list/speech_args)
+ speech_args[SPEECH_SPANS] |= SPAN_CLOWN
+
+/datum/species/golem/runic
+ name = "Runic Golem"
+ id = "runic golem"
+ limbs_id = "cultgolem"
+ sexes = FALSE
+ info_text = "As a Runic Golem, you possess eldritch powers granted by the Elder Goddess Nar'Sie."
+ species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES) //no mutcolors
+ prefix = "Runic"
+ special_names = null
+
+ var/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/shift/golem/phase_shift
+ var/obj/effect/proc_holder/spell/targeted/abyssal_gaze/abyssal_gaze
+ var/obj/effect/proc_holder/spell/targeted/dominate/dominate
+
+/datum/species/golem/runic/random_name(gender,unique,lastname)
+ var/edgy_first_name = pick("Razor","Blood","Dark","Evil","Cold","Pale","Black","Silent","Chaos","Deadly","Coldsteel")
+ var/edgy_last_name = pick("Edge","Night","Death","Razor","Blade","Steel","Calamity","Twilight","Shadow","Nightmare") //dammit Razor Razor
+ var/golem_name = "[edgy_first_name] [edgy_last_name]"
+ return golem_name
+
+/datum/species/golem/runic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ C.faction |= "cult"
+ phase_shift = new
+ phase_shift.charge_counter = 0
+ C.AddSpell(phase_shift)
+ abyssal_gaze = new
+ abyssal_gaze.charge_counter = 0
+ C.AddSpell(abyssal_gaze)
+ dominate = new
+ dominate.charge_counter = 0
+ C.AddSpell(dominate)
+
+/datum/species/golem/runic/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ C.faction -= "cult"
+ if(phase_shift)
+ C.RemoveSpell(phase_shift)
+ if(abyssal_gaze)
+ C.RemoveSpell(abyssal_gaze)
+ if(dominate)
+ C.RemoveSpell(dominate)
+
+/datum/species/golem/runic/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
+ if(chem.type == /datum/reagent/water/holywater)
+ H.adjustFireLoss(4)
+ H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
+
+ if(chem.type == /datum/reagent/fuel/unholywater)
+ H.adjustBruteLoss(-4)
+ H.adjustFireLoss(-4)
+ H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
+
+
+/datum/species/golem/clockwork
+ name = "Clockwork Golem"
+ id = "clockwork golem"
+ say_mod = "clicks"
+ limbs_id = "clockgolem"
+ info_text = "As a Clockwork Golem, you are faster than other types of golems. On death, you will break down into scrap."
+ species_traits = list(NOBLOOD,NO_UNDERWEAR,NOEYES)
+ inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
+ armor = 20 //Reinforced, but much less so to allow for fast movement
+ attack_verb = "smash"
+ attack_sound = 'sound/magic/clockwork/anima_fragment_attack.ogg'
+ sexes = FALSE
+ speedmod = 0
+ damage_overlay_type = "synth"
+ prefix = "Clockwork"
+ special_names = list("Remnant", "Relic", "Scrap", "Vestige") //RIP Ratvar
+ var/has_corpse
+
+/datum/species/golem/clockwork/on_species_gain(mob/living/carbon/human/H)
+ . = ..()
+ H.faction |= "ratvar"
+ RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech)
+
+/datum/species/golem/clockwork/on_species_loss(mob/living/carbon/human/H)
+ if(!is_servant_of_ratvar(H))
+ H.faction -= "ratvar"
+ UnregisterSignal(H, COMSIG_MOB_SAY)
+ . = ..()
+
+/datum/species/golem/clockwork/proc/handle_speech(datum/source, list/speech_args)
+ speech_args[SPEECH_SPANS] |= SPAN_ROBOT //beep
+
+/datum/species/golem/clockwork/spec_death(gibbed, mob/living/carbon/human/H)
+ gibbed = !has_corpse ? FALSE : gibbed
+ . = ..()
+ if(!has_corpse)
+ var/turf/T = get_turf(H)
+ H.visible_message("[H]'s exoskeleton shatters, collapsing into a heap of scrap!")
+ playsound(H, 'sound/magic/clockwork/anima_fragment_death.ogg', 62, TRUE)
+ for(var/i in 1 to rand(3, 5))
+ new/obj/item/clockwork/alloy_shards/small(T)
+ new/obj/item/clockwork/alloy_shards/clockgolem_remains(T)
+ qdel(H)
+
+/datum/species/golem/clockwork/no_scrap //These golems are created through the herald's beacon and leave normal corpses on death.
+ id = "clockwork golem servant"
+ armor = 15 //Balance reasons make this armor weak
+ no_equip = list()
+ nojumpsuit = FALSE
+ has_corpse = TRUE
+ blacklisted = TRUE
+ dangerous_existence = TRUE
+ random_eligible = FALSE
+ info_text = "As a Clockwork Golem Servant, you are faster than other types of golems." //warcult golems leave a corpse
+
+/datum/species/golem/cloth
+ name = "Cloth Golem"
+ id = "cloth golem"
+ limbs_id = "clothgolem"
+ sexes = FALSE
+ info_text = "As a Cloth Golem, you are able to reform yourself after death, provided your remains aren't burned or destroyed. You are, of course, very flammable. \
+ Being made of cloth, your body is magic resistant and faster than that of other golems, but weaker and less resilient."
+ species_traits = list(NOBLOOD,NO_UNDERWEAR) //no mutcolors, and can burn
+ inherent_traits = list(TRAIT_RESISTCOLD,TRAIT_NOBREATH,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOGUNS)
+ inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
+ armor = 15 //feels no pain, but not too resistant
+ burnmod = 2 // don't get burned
+ speedmod = 1 // not as heavy as stone
+ punchdamagelow = 4
+ punchstunthreshold = 7
+ punchdamagehigh = 8 // not as heavy as stone
+ prefix = "Cloth"
+ special_names = null
+
+/datum/species/golem/cloth/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ ADD_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
+
+/datum/species/golem/cloth/on_species_loss(mob/living/carbon/C)
+ REMOVE_TRAIT(C, TRAIT_HOLY, SPECIES_TRAIT)
+ ..()
+
+/datum/species/golem/cloth/check_roundstart_eligible()
+ if(SSevents.holidays && SSevents.holidays[HALLOWEEN])
+ return TRUE
+ return ..()
+
+/datum/species/golem/cloth/random_name(gender,unique,lastname)
+ var/pharaoh_name = pick("Neferkare", "Hudjefa", "Khufu", "Mentuhotep", "Ahmose", "Amenhotep", "Thutmose", "Hatshepsut", "Tutankhamun", "Ramses", "Seti", \
+ "Merenptah", "Djer", "Semerkhet", "Nynetjer", "Khafre", "Pepi", "Intef", "Ay") //yes, Ay was an actual pharaoh
+ var/golem_name = "[pharaoh_name] \Roman[rand(1,99)]"
+ return golem_name
+
+/datum/species/golem/cloth/spec_life(mob/living/carbon/human/H)
+ if(H.fire_stacks < 1)
+ H.adjust_fire_stacks(1) //always prone to burning
+ ..()
+
+/datum/species/golem/cloth/spec_death(gibbed, mob/living/carbon/human/H)
+ if(gibbed)
+ return
+ if(H.on_fire)
+ H.visible_message("[H] burns into ash!")
+ H.dust(just_ash = TRUE)
+ return
+
+ H.visible_message("[H] falls apart into a pile of bandages!")
+ new /obj/structure/cloth_pile(get_turf(H), H)
+ ..()
+
+/obj/structure/cloth_pile
+ name = "pile of bandages"
+ desc = "It emits a strange aura, as if there was still life within it..."
+ max_integrity = 50
+ armor = list("melee" = 90, "bullet" = 90, "laser" = 25, "energy" = 80, "bomb" = 50, "bio" = 100, "fire" = -50, "acid" = -50)
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "pile_bandages"
+ resistance_flags = FLAMMABLE
+
+ var/revive_time = 900
+ var/mob/living/carbon/human/cloth_golem
+
+/obj/structure/cloth_pile/Initialize(mapload, mob/living/carbon/human/H)
+ . = ..()
+ if(!QDELETED(H) && is_species(H, /datum/species/golem/cloth))
+ H.unequip_everything()
+ H.forceMove(src)
+ cloth_golem = H
+ to_chat(cloth_golem, "You start gathering your life energy, preparing to rise again...")
+ addtimer(CALLBACK(src, .proc/revive), revive_time)
+ else
+ return INITIALIZE_HINT_QDEL
+
+/obj/structure/cloth_pile/Destroy()
+ if(cloth_golem)
+ QDEL_NULL(cloth_golem)
+ return ..()
+
+/obj/structure/cloth_pile/burn()
+ visible_message("[src] burns into ash!")
+ new /obj/effect/decal/cleanable/ash(get_turf(src))
+ ..()
+
+/obj/structure/cloth_pile/proc/revive()
+ if(QDELETED(src) || QDELETED(cloth_golem)) //QDELETED also checks for null, so if no cloth golem is set this won't runtime
+ return
+ if(cloth_golem.suiciding || HAS_TRAIT(cloth_golem, TRAIT_NOCLONE))
+ QDEL_NULL(cloth_golem)
+ return
+
+ invisibility = INVISIBILITY_MAXIMUM //disappear before the animation
+ new /obj/effect/temp_visual/mummy_animation(get_turf(src))
+ if(cloth_golem.revive(full_heal = TRUE, admin_revive = TRUE))
+ cloth_golem.grab_ghost() //won't pull if it's a suicide
+ sleep(20)
+ cloth_golem.forceMove(get_turf(src))
+ cloth_golem.visible_message("[src] rises and reforms into [cloth_golem]!","You reform into yourself!")
+ cloth_golem = null
+ qdel(src)
+
+/obj/structure/cloth_pile/attackby(obj/item/P, mob/living/carbon/human/user, params)
+ . = ..()
+
+ if(resistance_flags & ON_FIRE)
+ return
+
+ if(P.is_hot())
+ visible_message("[src] bursts into flames!")
+ fire_act()
+
+/datum/species/golem/plastic
+ name = "Plastic Golem"
+ id = "plastic golem"
+ prefix = "Plastic"
+ special_names = null
+ fixed_mut_color = "fff"
+ info_text = "As a Plastic Golem, you are capable of ventcrawling and passing through plastic flaps as long as you are naked."
+
+/datum/species/golem/plastic/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ . = ..()
+ C.ventcrawler = VENTCRAWLER_NUDE
+
+/datum/species/golem/plastic/on_species_loss(mob/living/carbon/C)
+ . = ..()
+ C.ventcrawler = initial(C.ventcrawler)
+
+/datum/species/golem/bronze
+ name = "Bronze Golem"
+ id = "bronze golem"
+ prefix = "Bronze"
+ special_names = list("Bell")
+ fixed_mut_color = "cd7f32"
+ info_text = "As a Bronze Golem, you are very resistant to loud noises, and make loud noises if something hard hits you, however this ability does hurt your hearing."
+ special_step_sounds = list('sound/machines/clockcult/integration_cog_install.ogg', 'sound/magic/clockwork/fellowship_armory.ogg' )
+ attack_verb = "bonk"
+ mutantears = /obj/item/organ/ears/bronze
+ var/last_gong_time = 0
+ var/gong_cooldown = 150
+
+/datum/species/golem/bronze/bullet_act(obj/item/projectile/P, mob/living/carbon/human/H)
+ if(!(world.time > last_gong_time + gong_cooldown))
+ return ..()
+ if(P.flag == "bullet" || P.flag == "bomb")
+ gong(H)
+ return ..()
+
+/datum/species/golem/bronze/spec_hitby(atom/movable/AM, mob/living/carbon/human/H)
+ ..()
+ if(world.time > last_gong_time + gong_cooldown)
+ gong(H)
+
+/datum/species/golem/bronze/spec_attack_hand(mob/living/carbon/human/M, mob/living/carbon/human/H, datum/martial_art/attacker_style)
+ ..()
+ if(world.time > last_gong_time + gong_cooldown && M.a_intent != INTENT_HELP)
+ gong(H)
+
+/datum/species/golem/bronze/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
+ ..()
+ if(world.time > last_gong_time + gong_cooldown)
+ gong(H)
+
+/datum/species/golem/bronze/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
+ ..()
+ if(world.time > last_gong_time + gong_cooldown)
+ gong(H)
+
+/datum/species/golem/bronze/proc/gong(mob/living/carbon/human/H)
+ last_gong_time = world.time
+ for(var/mob/living/M in get_hearers_in_view(7,H))
+ if(M.stat == DEAD) //F
+ return
+ if(M == H)
+ H.show_message("You cringe with pain as your body rings around you!", 2)
+ H.playsound_local(H, 'sound/effects/gong.ogg', 100, TRUE)
+ H.soundbang_act(2, 0, 100, 1)
+ H.jitteriness += 7
+ var/distance = max(0,get_dist(get_turf(H),get_turf(M)))
+ switch(distance)
+ if(0 to 1)
+ M.show_message("GONG!", 2)
+ M.playsound_local(H, 'sound/effects/gong.ogg', 100, TRUE)
+ M.soundbang_act(1, 0, 30, 3)
+ M.confused += 10
+ M.jitteriness += 4
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "gonged", /datum/mood_event/loud_gong)
+ if(2 to 3)
+ M.show_message("GONG!", 2)
+ M.playsound_local(H, 'sound/effects/gong.ogg', 75, TRUE)
+ M.soundbang_act(1, 0, 15, 2)
+ M.jitteriness += 3
+ SEND_SIGNAL(M, COMSIG_ADD_MOOD_EVENT, "gonged", /datum/mood_event/loud_gong)
+ else
+ M.show_message("GONG!", 2)
+ M.playsound_local(H, 'sound/effects/gong.ogg', 50, TRUE)
+
+
+/datum/species/golem/cardboard //Faster but weaker, can also make new shells on its own
+ name = "Cardboard Golem"
+ id = "cardboard golem"
+ prefix = "Cardboard"
+ special_names = list("Box")
+ info_text = "As a Cardboard Golem, you aren't very strong, but you are a bit quicker and can easily create more brethren by using cardboard on yourself."
+ species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL,MUTCOLORS)
+ inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER)
+ fixed_mut_color = "ffffff"
+ limbs_id = "c_golem" //special sprites
+ attack_verb = "bash"
+ armor = 25
+ burnmod = 1.25
+ heatmod = 2
+ speedmod = 1.5
+ punchdamagelow = 4
+ punchstunthreshold = 7
+ punchdamagehigh = 8
+ var/last_creation = 0
+ var/brother_creation_cooldown = 300
+
+/datum/species/golem/cardboard/spec_attacked_by(obj/item/I, mob/living/user, obj/item/bodypart/affecting, intent, mob/living/carbon/human/H)
+ . = ..()
+ if(user != H)
+ return FALSE //forced reproduction is r/non-con
+ if(istype(I, /obj/item/stack/sheet/cardboard))
+ var/obj/item/stack/sheet/cardboard/C = I
+ if(last_creation + brother_creation_cooldown > world.time) //no cheesing dork
+ return
+ if(C.amount < 10)
+ to_chat(H, "You do not have enough cardboard!")
+ return FALSE
+ to_chat(H, "You attempt to create a new cardboard brother.")
+ if(do_after(user, 30, target = user))
+ if(last_creation + brother_creation_cooldown > world.time) //no cheesing dork
+ return
+ if(!C.use(10))
+ to_chat(H, "You do not have enough cardboard!")
+ return FALSE
+ to_chat(H, "You create a new cardboard golem shell.")
+ create_brother(H.loc)
+
+/datum/species/golem/cardboard/proc/create_brother(var/location)
+ new /obj/effect/mob_spawn/human/golem/servant(location, /datum/species/golem/cardboard, owner)
+ last_creation = world.time
+
+/datum/species/golem/leather
+ name = "Leather Golem"
+ id = "leather golem"
+ special_names = list("Face", "Man", "Belt") //Ah dude 4 strength 4 stam leather belt AHHH
+ inherent_traits = list(TRAIT_NOBREATH, TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER, TRAIT_STRONG_GRABBER)
+ prefix = "Leather"
+ fixed_mut_color = "624a2e"
+ info_text = "As a Leather Golem, you are flammable, but you can grab things with incredible ease, allowing all your grabs to start at a strong level."
+ attack_verb = "whipp"
+ grab_sound = 'sound/weapons/whipgrab.ogg'
+ attack_sound = 'sound/weapons/whip.ogg'
+
+/datum/species/golem/bone
+ name = "Bone Golem"
+ id = "bone golem"
+ say_mod = "rattles"
+ prefix = "Bone"
+ limbs_id = "b_golem"
+ special_names = list("Head", "Broth", "Fracture", "Rattler", "Appetit")
+ liked_food = GROSS | MEAT | RAW
+ toxic_food = null
+ inherent_biotypes = list(MOB_UNDEAD, MOB_HUMANOID)
+ mutanttongue = /obj/item/organ/tongue/bone
+ sexes = FALSE
+ fixed_mut_color = "ffffff"
+ attack_verb = "rattl"
+ species_traits = list(NOBLOOD,NO_UNDERWEAR,NOGENITALS,NOAROUSAL,MUTCOLORS)
+ inherent_traits = list(TRAIT_RESISTHEAT,TRAIT_NOBREATH,TRAIT_RESISTCOLD,TRAIT_RESISTHIGHPRESSURE,TRAIT_RESISTLOWPRESSURE,TRAIT_NOFIRE,TRAIT_NOGUNS,TRAIT_RADIMMUNE,TRAIT_PIERCEIMMUNE,TRAIT_NODISMEMBER,TRAIT_FAKEDEATH,TRAIT_CALCIUM_HEALER)
+ info_text = "As a Bone Golem, You have a powerful spell that lets you chill your enemies with fear, and milk heals you! Just make sure to watch our for bone-hurting juice."
+ var/datum/action/innate/bonechill/bonechill
+
+/datum/species/golem/bone/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ if(ishuman(C))
+ bonechill = new
+ bonechill.Grant(C)
+
+/datum/species/golem/bone/on_species_loss(mob/living/carbon/C)
+ if(bonechill)
+ bonechill.Remove(C)
+ ..()
+
+/datum/action/innate/bonechill
+ name = "Bone Chill"
+ desc = "Rattle your bones and strike fear into your enemies!"
+ check_flags = AB_CHECK_CONSCIOUS
+ icon_icon = 'icons/mob/actions/actions_spells.dmi'
+ button_icon_state = "bonechill"
+ var/cooldown = 600
+ var/last_use
+ var/snas_chance = 3
+
+/datum/action/innate/bonechill/Activate()
+ if(world.time < last_use + cooldown)
+ to_chat("You aren't ready yet to rattle your bones again")
+ return
+ owner.visible_message("[owner] rattles [owner.p_their()] bones harrowingly.", "You rattle your bones")
+ last_use = world.time
+ if(prob(snas_chance))
+ playsound(get_turf(owner),'sound/magic/RATTLEMEBONES2.ogg', 100)
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ var/mutable_appearance/badtime = mutable_appearance('icons/mob/human_parts.dmi', "b_golem_eyes", -FIRE_LAYER-0.5)
+ badtime.appearance_flags = RESET_COLOR
+ H.overlays_standing[FIRE_LAYER+0.5] = badtime
+ H.apply_overlay(FIRE_LAYER+0.5)
+ addtimer(CALLBACK(H, /mob/living/carbon/.proc/remove_overlay, FIRE_LAYER+0.5), 25)
+ else
+ playsound(get_turf(owner),'sound/magic/RATTLEMEBONES.ogg', 100)
+ for(var/mob/living/L in orange(7, get_turf(owner)))
+ if((MOB_UNDEAD in L.mob_biotypes) || isgolem(L) || HAS_TRAIT(L, TRAIT_RESISTCOLD))
+ return //Do not affect our brothers
+
+ to_chat(L, "A spine-chilling sound chills you to the bone!")
+ L.apply_status_effect(/datum/status_effect/bonechill)
+ SEND_SIGNAL(L, COMSIG_ADD_MOOD_EVENT, "spooked", /datum/mood_event/spooked)
diff --git a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
index b8f260a9..0fa512b7 100644
--- a/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/jellypeople.dm
@@ -1,737 +1,737 @@
-/datum/species/jelly
- // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them.
- name = "Xenobiological Jelly Entity"
- id = "jelly"
- default_color = "00FF90"
- say_mod = "chirps"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
- mutantlungs = /obj/item/organ/lungs/slime
- mutant_heart = /obj/item/organ/heart/slime
- mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur") //CIT CHANGE
- default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None") //CIT CHANGE
- inherent_traits = list(TRAIT_TOXINLOVER)
- meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
- gib_types = list(/obj/effect/gibspawner/slime, /obj/effect/gibspawner/slime/bodypartless)
- exotic_blood = "jellyblood"
- exotic_bloodtype = "GEL"
- damage_overlay_type = ""
- var/datum/action/innate/regenerate_limbs/regenerate_limbs
- var/datum/action/innate/slime_change/slime_change //CIT CHANGE
- liked_food = TOXIC | MEAT
- toxic_food = null
- coldmod = 6 // = 3x cold damage
- heatmod = 0.5 // = 1/4x heat damage
- burnmod = 0.5 // = 1/2x generic burn damage
-
-/datum/species/jelly/on_species_loss(mob/living/carbon/C)
- if(regenerate_limbs)
- regenerate_limbs.Remove(C)
- if(slime_change) //CIT CHANGE
- slime_change.Remove(C) //CIT CHANGE
- C.remove_language(/datum/language/slime)
- C.faction -= "slime"
- ..()
- C.faction -= "slime"
-
-/datum/species/jelly/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- C.grant_language(/datum/language/slime)
- if(ishuman(C))
- regenerate_limbs = new
- regenerate_limbs.Grant(C)
- slime_change = new //CIT CHANGE
- slime_change.Grant(C) //CIT CHANGE
- C.faction |= "slime"
-
-/datum/species/jelly/spec_life(mob/living/carbon/human/H)
- if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for vampires
- return
- if(!H.blood_volume)
- H.blood_volume += 5
- H.adjustBruteLoss(5)
- to_chat(H, "You feel empty!")
-
- if(H.blood_volume < (BLOOD_VOLUME_NORMAL * H.blood_ratio))
- if(H.nutrition >= NUTRITION_LEVEL_STARVING)
- H.blood_volume += 3
- H.nutrition -= 2.5
- if(H.blood_volume < (BLOOD_VOLUME_OKAY*H.blood_ratio))
- if(prob(5))
- to_chat(H, "You feel drained!")
- if(H.blood_volume < (BLOOD_VOLUME_BAD*H.blood_ratio))
- Cannibalize_Body(H)
- if(regenerate_limbs)
- regenerate_limbs.UpdateButtonIcon()
-
-/datum/species/jelly/proc/Cannibalize_Body(mob/living/carbon/human/H)
- var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs()
- var/obj/item/bodypart/consumed_limb
- if(!limbs_to_consume.len)
- H.losebreath++
- return
- if(H.get_num_legs(FALSE)) //Legs go before arms
- limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM)
- consumed_limb = H.get_bodypart(pick(limbs_to_consume))
- consumed_limb.drop_limb()
- to_chat(H, "Your [consumed_limb] is drawn back into your body, unable to maintain its shape!")
- qdel(consumed_limb)
- H.blood_volume += 20
-
-/datum/action/innate/regenerate_limbs
- name = "Regenerate Limbs"
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "slimeheal"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
-
-/datum/action/innate/regenerate_limbs/IsAvailable()
- if(..())
- var/mob/living/carbon/human/H = owner
- var/list/limbs_to_heal = H.get_missing_limbs()
- if(limbs_to_heal.len < 1)
- return 0
- if(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
- return 1
- return 0
-
-/datum/action/innate/regenerate_limbs/Activate()
- var/mob/living/carbon/human/H = owner
- var/list/limbs_to_heal = H.get_missing_limbs()
- if(limbs_to_heal.len < 1)
- to_chat(H, "You feel intact enough as it is.")
- return
- to_chat(H, "You focus intently on your missing [limbs_to_heal.len >= 2 ? "limbs" : "limb"]...")
- if(H.blood_volume >= 40*limbs_to_heal.len+(BLOOD_VOLUME_OKAY*H.blood_ratio))
- H.regenerate_limbs()
- H.blood_volume -= 40*limbs_to_heal.len
- to_chat(H, "...and after a moment you finish reforming!")
- return
- else if(H.blood_volume >= 40)//We can partially heal some limbs
- while(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
- var/healed_limb = pick(limbs_to_heal)
- H.regenerate_limb(healed_limb)
- limbs_to_heal -= healed_limb
- H.blood_volume -= 40
- to_chat(H, "...but there is not enough of you to fix everything! You must attain more mass to heal completely!")
- return
- to_chat(H, "...but there is not enough of you to go around! You must attain more mass to heal!")
-
-////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
-
-//Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death.
-
-/datum/species/jelly/slime
- name = "Slimeperson"
- id = "slime"
- default_color = "00FFFF"
- species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
- say_mod = "says"
- hair_color = "mutcolor"
- hair_alpha = 150
- ignored_by = list(/mob/living/simple_animal/slime)
- var/datum/action/innate/split_body/slime_split
- var/list/mob/living/carbon/bodies
- var/datum/action/innate/swap_body/swap_body
-
-/datum/species/jelly/slime/on_species_loss(mob/living/carbon/C)
- if(slime_split)
- slime_split.Remove(C)
- if(swap_body)
- swap_body.Remove(C)
- bodies -= C // This means that the other bodies maintain a link
- // so if someone mindswapped into them, they'd still be shared.
- bodies = null
- C.blood_volume = min(C.blood_volume, (BLOOD_VOLUME_NORMAL*C.blood_ratio))
- ..()
-
-/datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- if(ishuman(C))
- slime_split = new
- slime_split.Grant(C)
- swap_body = new
- swap_body.Grant(C)
-
- if(!bodies || !bodies.len)
- bodies = list(C)
- else
- bodies |= C
-
-/datum/species/jelly/slime/spec_death(gibbed, mob/living/carbon/human/H)
- if(slime_split)
- if(!H.mind || !H.mind.active)
- return
-
- var/list/available_bodies = (bodies - H)
- for(var/mob/living/L in available_bodies)
- if(!swap_body.can_swap(L))
- available_bodies -= L
-
- if(!LAZYLEN(available_bodies))
- return
-
- swap_body.swap_to_dupe(H.mind, pick(available_bodies))
-
-//If you're cloned you get your body pool back
-/datum/species/jelly/slime/copy_properties_from(datum/species/jelly/slime/old_species)
- bodies = old_species.bodies
-
-/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H)
- if((HAS_TRAIT(H, TRAIT_NOMARROW)))
- return
- if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
- if(prob(5))
- to_chat(H, "You feel very bloated!")
- else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
- H.blood_volume += 3
- H.nutrition -= 2.5
-
- ..()
-
-/datum/action/innate/split_body
- name = "Split Body"
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "slimesplit"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
-
-/datum/action/innate/split_body/IsAvailable()
- if(..())
- var/mob/living/carbon/human/H = owner
- if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
- return 1
- return 0
-
-/datum/action/innate/split_body/Activate()
- var/mob/living/carbon/human/H = owner
- if(!isslimeperson(H))
- return
- CHECK_DNA_AND_SPECIES(H)
- H.visible_message("[owner] gains a look of \
- concentration while standing perfectly still.",
- "You focus intently on moving your body while \
- standing perfectly still...")
-
- H.notransform = TRUE
-
- if(do_after(owner, delay=60, needhand=FALSE, target=owner, progress=TRUE))
- if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
- make_dupe()
- else
- to_chat(H, "...but there is not enough of you to go around! You must attain more mass to split!")
- else
- to_chat(H, "...but fail to stand perfectly still!")
-
- H.notransform = FALSE
-
-/datum/action/innate/split_body/proc/make_dupe()
- var/mob/living/carbon/human/H = owner
- CHECK_DNA_AND_SPECIES(H)
-
- var/mob/living/carbon/human/spare = new /mob/living/carbon/human(H.loc)
-
- spare.underwear = "Nude"
- H.dna.transfer_identity(spare, transfer_SE=1)
- spare.dna.features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
- spare.real_name = spare.dna.real_name
- spare.name = spare.dna.real_name
- spare.updateappearance(mutcolor_update=1)
- spare.domutcheck()
- spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST)))
-
- H.blood_volume *= 0.45
- H.notransform = 0
-
- var/datum/species/jelly/slime/origin_datum = H.dna.species
- origin_datum.bodies |= spare
-
- var/datum/species/jelly/slime/spare_datum = spare.dna.species
- spare_datum.bodies = origin_datum.bodies
-
- H.transfer_trait_datums(spare)
- H.mind.transfer_to(spare)
- spare.visible_message("[H] distorts as a new body \
- \"steps out\" of [H.p_them()].",
- "...and after a moment of disorentation, \
- you're besides yourself!")
-
-
-/datum/action/innate/swap_body
- name = "Swap Body"
- check_flags = NONE
- button_icon_state = "slimeswap"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
-
-/datum/action/innate/swap_body/Activate()
- if(!isslimeperson(owner))
- to_chat(owner, "You are not a slimeperson.")
- Remove(owner)
- else
- ui_interact(owner)
-
-/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
-
- ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
- if(!ui)
- ui = new(user, src, ui_key, "slime_swap_body", name, 400, 400, master_ui, state)
- ui.open()
-
-/datum/action/innate/swap_body/ui_data(mob/user)
- var/mob/living/carbon/human/H = owner
- if(!isslimeperson(H))
- return
-
- var/datum/species/jelly/slime/SS = H.dna.species
-
- var/list/data = list()
- data["bodies"] = list()
- for(var/b in SS.bodies)
- var/mob/living/carbon/human/body = b
- if(!body || QDELETED(body) || !isslimeperson(body))
- SS.bodies -= b
- continue
-
- var/list/L = list()
- // HTML colors need a # prefix
- L["htmlcolor"] = "#[body.dna.features["mcolor"]]"
- L["area"] = get_area_name(body, TRUE)
- var/stat = "error"
- switch(body.stat)
- if(CONSCIOUS)
- stat = "Conscious"
- if(UNCONSCIOUS)
- stat = "Unconscious"
- if(DEAD)
- stat = "Dead"
- var/occupied
- if(body == H)
- occupied = "owner"
- else if(body.mind && body.mind.active)
- occupied = "stranger"
- else
- occupied = "available"
-
- L["status"] = stat
- L["exoticblood"] = body.blood_volume
- L["name"] = body.name
- L["ref"] = "[REF(body)]"
- L["occupied"] = occupied
- var/button
- if(occupied == "owner")
- button = "selected"
- else if(occupied == "stranger")
- button = "danger"
- else if(can_swap(body))
- button = null
- else
- button = "disabled"
-
- L["swap_button_state"] = button
- L["swappable"] = (occupied == "available") && can_swap(body)
-
- data["bodies"] += list(L)
-
- return data
-
-/datum/action/innate/swap_body/ui_act(action, params)
- if(..())
- return
- var/mob/living/carbon/human/H = owner
- if(!isslimeperson(owner))
- return
- if(!H.mind || !H.mind.active)
- return
- switch(action)
- if("swap")
- var/mob/living/carbon/human/selected = locate(params["ref"])
- if(!can_swap(selected))
- return
- SStgui.close_uis(src)
- swap_to_dupe(H.mind, selected)
-
-/datum/action/innate/swap_body/proc/can_swap(mob/living/carbon/human/dupe)
- var/mob/living/carbon/human/H = owner
- if(!isslimeperson(H))
- return FALSE
- var/datum/species/jelly/slime/SS = H.dna.species
-
- if(QDELETED(dupe)) //Is there a body?
- SS.bodies -= dupe
- return FALSE
-
- if(!isslimeperson(dupe)) //Is it a slimeperson?
- SS.bodies -= dupe
- return FALSE
-
- if(dupe.stat == DEAD) //Is it alive?
- return FALSE
-
- if(dupe.stat != CONSCIOUS) //Is it awake?
- return FALSE
-
- if(dupe.mind && dupe.mind.active) //Is it unoccupied?
- return FALSE
-
- if(!(dupe in SS.bodies)) //Do we actually own it?
- return FALSE
-
- return TRUE
-
-/datum/action/innate/swap_body/proc/swap_to_dupe(datum/mind/M, mob/living/carbon/human/dupe)
- if(!can_swap(dupe)) //sanity check
- return
- if(M.current.stat == CONSCIOUS)
- M.current.visible_message("[M.current] \
- stops moving and starts staring vacantly into space.",
- "You stop moving this body...")
- else
- to_chat(M.current, "You abandon this body...")
- M.current.transfer_trait_datums(dupe)
- M.transfer_to(dupe)
- dupe.visible_message("[dupe] blinks and looks \
- around.",
- "...and move this one instead.")
-
-
-///////////////////////////////////LUMINESCENTS//////////////////////////////////////////
-
-//Luminescents are able to consume and use slime extracts, without them decaying.
-
-/datum/species/jelly/luminescent
- name = "Luminescent"
- id = "lum"
- say_mod = "says"
- var/glow_intensity = LUMINESCENT_DEFAULT_GLOW
- var/obj/effect/dummy/luminescent_glow/glow
- var/obj/item/slime_extract/current_extract
- var/datum/action/innate/integrate_extract/integrate_extract
- var/datum/action/innate/use_extract/extract_minor
- var/datum/action/innate/use_extract/major/extract_major
- var/extract_cooldown = 0
-
-/datum/species/jelly/luminescent/on_species_loss(mob/living/carbon/C)
- ..()
- if(current_extract)
- current_extract.forceMove(C.drop_location())
- current_extract = null
- qdel(glow)
- if(integrate_extract)
- integrate_extract.Remove(C)
- if(extract_minor)
- extract_minor.Remove(C)
- if(extract_major)
- extract_major.Remove(C)
-
-/datum/species/jelly/luminescent/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- glow = new(C)
- update_glow(C)
- integrate_extract = new(src)
- integrate_extract.Grant(C)
- extract_minor = new(src)
- extract_minor.Grant(C)
- extract_major = new(src)
- extract_major.Grant(C)
-
-/datum/species/jelly/luminescent/proc/update_slime_actions()
- integrate_extract.update_name()
- integrate_extract.UpdateButtonIcon()
- extract_minor.UpdateButtonIcon()
- extract_major.UpdateButtonIcon()
-
-/datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/C, intensity)
- if(intensity)
- glow_intensity = intensity
- glow.set_light(glow_intensity, glow_intensity, C.dna.features["mcolor"])
-
-/obj/effect/dummy/luminescent_glow
- name = "luminescent glow"
- desc = "Tell a coder if you're seeing this."
- icon_state = "nothing"
- light_color = "#FFFFFF"
- light_range = LUMINESCENT_DEFAULT_GLOW
-
-/obj/effect/dummy/luminescent_glow/Initialize()
- . = ..()
- if(!isliving(loc))
- return INITIALIZE_HINT_QDEL
-
-/datum/action/innate/integrate_extract
- name = "Integrate Extract"
- desc = "Eat a slime extract to use its properties."
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "slimeconsume"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
- var/datum/species/jelly/luminescent/species
-
-/datum/action/innate/integrate_extract/New(_species)
- ..()
- species = _species
-
-/datum/action/innate/integrate_extract/proc/update_name()
- if(!species || !species.current_extract)
- name = "Integrate Extract"
- desc = "Eat a slime extract to use its properties."
- else
- name = "Eject Extract"
- desc = "Eject your current slime extract."
-
-/datum/action/innate/integrate_extract/UpdateButtonIcon(status_only, force)
- if(!species || !species.current_extract)
- button_icon_state = "slimeconsume"
- else
- button_icon_state = "slimeeject"
- ..()
-
-/datum/action/innate/integrate_extract/ApplyIcon(obj/screen/movable/action_button/current_button, force)
- ..(current_button, TRUE)
- if(species && species.current_extract)
- current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
-
-/datum/action/innate/integrate_extract/Activate()
- var/mob/living/carbon/human/H = owner
- if(!is_species(H, /datum/species/jelly/luminescent) || !species)
- return
- CHECK_DNA_AND_SPECIES(H)
-
- if(species.current_extract)
- var/obj/item/slime_extract/S = species.current_extract
- if(!H.put_in_active_hand(S))
- S.forceMove(H.drop_location())
- species.current_extract = null
- to_chat(H, "You eject [S].")
- species.update_slime_actions()
- else
- var/obj/item/I = H.get_active_held_item()
- if(istype(I, /obj/item/slime_extract))
- var/obj/item/slime_extract/S = I
- if(!S.Uses)
- to_chat(H, "[I] is spent! You cannot integrate it.")
- return
- if(!H.temporarilyRemoveItemFromInventory(S))
- return
- S.forceMove(H)
- species.current_extract = S
- to_chat(H, "You consume [I], and you feel it pulse within you...")
- species.update_slime_actions()
- else
- to_chat(H, "You need to hold an unused slime extract in your active hand!")
-
-/datum/action/innate/use_extract
- name = "Extract Minor Activation"
- desc = "Pulse the slime extract with energized jelly to activate it."
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "slimeuse1"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
- var/activation_type = SLIME_ACTIVATE_MINOR
- var/datum/species/jelly/luminescent/species
-
-/datum/action/innate/use_extract/New(_species)
- ..()
- species = _species
-
-/datum/action/innate/use_extract/IsAvailable()
- if(..())
- if(species && species.current_extract && (world.time > species.extract_cooldown))
- return TRUE
- return FALSE
-
-/datum/action/innate/use_extract/ApplyIcon(obj/screen/movable/action_button/current_button, force)
- ..(current_button, TRUE)
- if(species && species.current_extract)
- current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
-
-/datum/action/innate/use_extract/Activate()
- var/mob/living/carbon/human/H = owner
- if(!is_species(H, /datum/species/jelly/luminescent) || !species)
- return
- CHECK_DNA_AND_SPECIES(H)
-
- if(species.current_extract)
- species.extract_cooldown = world.time + 100
- var/cooldown = species.current_extract.activate(H, species, activation_type)
- species.extract_cooldown = world.time + cooldown
-
-/datum/action/innate/use_extract/major
- name = "Extract Major Activation"
- desc = "Pulse the slime extract with plasma jelly to activate it."
- button_icon_state = "slimeuse2"
- activation_type = SLIME_ACTIVATE_MAJOR
-
-///////////////////////////////////STARGAZERS//////////////////////////////////////////
-
-//Stargazers are the telepathic branch of jellypeople, able to project psychic messages and to link minds with willing participants.
-
-/datum/species/jelly/stargazer
- name = "Stargazer"
- id = "stargazer"
- var/datum/action/innate/project_thought/project_thought
- var/datum/action/innate/link_minds/link_minds
- var/list/mob/living/linked_mobs = list()
- var/list/datum/action/innate/linked_speech/linked_actions = list()
- var/mob/living/carbon/human/slimelink_owner
- var/current_link_id = 0
-
-/datum/species/jelly/stargazer/on_species_loss(mob/living/carbon/C)
- ..()
- for(var/M in linked_mobs)
- unlink_mob(M)
- if(project_thought)
- project_thought.Remove(C)
- if(link_minds)
- link_minds.Remove(C)
-
-/datum/species/jelly/stargazer/spec_death(gibbed, mob/living/carbon/human/H)
- ..()
- for(var/M in linked_mobs)
- unlink_mob(M)
-
-/datum/species/jelly/stargazer/on_species_gain(mob/living/carbon/C, datum/species/old_species)
- ..()
- project_thought = new(src)
- project_thought.Grant(C)
- link_minds = new(src)
- link_minds.Grant(C)
- slimelink_owner = C
- link_mob(C)
-
-/datum/species/jelly/stargazer/proc/link_mob(mob/living/M)
- if(QDELETED(M) || M.stat == DEAD)
- return FALSE
- if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice
- return FALSE
- if(M in linked_mobs)
- return FALSE
- linked_mobs.Add(M)
- to_chat(M, "You are now connected to [slimelink_owner.real_name]'s Slime Link.")
- var/datum/action/innate/linked_speech/action = new(src)
- linked_actions.Add(action)
- action.Grant(M)
- return TRUE
-
-/datum/species/jelly/stargazer/proc/unlink_mob(mob/living/M)
- var/link_id = linked_mobs.Find(M)
- if(!(link_id))
- return
- var/datum/action/innate/linked_speech/action = linked_actions[link_id]
- action.Remove(M)
- to_chat(M, "You are no longer connected to [slimelink_owner.real_name]'s Slime Link.")
- linked_mobs[link_id] = null
- linked_actions[link_id] = null
-
-/datum/action/innate/linked_speech
- name = "Slimelink"
- desc = "Send a psychic message to everyone connected to your slime link."
- button_icon_state = "link_speech"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
- var/datum/species/jelly/stargazer/species
-
-/datum/action/innate/linked_speech/New(_species)
- ..()
- species = _species
-
-/datum/action/innate/linked_speech/Activate()
- var/mob/living/carbon/human/H = owner
- if(!species || !(H in species.linked_mobs))
- to_chat(H, "The link seems to have been severed...")
- Remove(H)
- return
-
- var/message = sanitize(input("Message:", "Slime Telepathy") as text|null)
-
- if(!species || !(H in species.linked_mobs))
- to_chat(H, "The link seems to have been severed...")
- Remove(H)
- return
-
- if(QDELETED(H) || H.stat == DEAD)
- species.unlink_mob(H)
- return
-
- if(message)
- var/msg = "\[[species.slimelink_owner.real_name]'s Slime Link\] [H]: [message]"
- log_directed_talk(H, species.slimelink_owner, msg, LOG_SAY, "slime link")
- for(var/X in species.linked_mobs)
- var/mob/living/M = X
- if(QDELETED(M) || M.stat == DEAD)
- species.unlink_mob(M)
- continue
- to_chat(M, msg)
-
- for(var/X in GLOB.dead_mob_list)
- var/mob/M = X
- var/link = FOLLOW_LINK(M, H)
- to_chat(M, "[link] [msg]")
-
-/datum/action/innate/project_thought
- name = "Send Thought"
- desc = "Send a private psychic message to someone you can see."
- button_icon_state = "send_mind"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
-
-/datum/action/innate/project_thought/Activate()
- var/mob/living/carbon/human/H = owner
- if(H.stat == DEAD)
- return
- if(!is_species(H, /datum/species/jelly/stargazer))
- return
- CHECK_DNA_AND_SPECIES(H)
-
- var/list/options = list()
- for(var/mob/living/Ms in oview(H))
- options += Ms
- var/mob/living/M = input("Select who to send your message to:","Send thought to?",null) as null|mob in options
- if(!M)
- return
-
- var/msg = sanitize(input("Message:", "Telepathy") as text|null)
- if(msg)
- log_directed_talk(H, M, msg, LOG_SAY, "slime telepathy")
- to_chat(M, "You hear an alien voice in your head... [msg]")
- to_chat(H, "You telepathically said: \"[msg]\" to [M]")
- for(var/dead in GLOB.dead_mob_list)
- if(!isobserver(dead))
- continue
- var/follow_link_user = FOLLOW_LINK(dead, H)
- var/follow_link_target = FOLLOW_LINK(dead, M)
- to_chat(dead, "[follow_link_user] [H]Slime Telepathy --> [follow_link_target] [M][msg]")
-
-/datum/action/innate/link_minds
- name = "Link Minds"
- desc = "Link someone's mind to your Slime Link, allowing them to communicate telepathically with other linked minds."
- button_icon_state = "mindlink"
- icon_icon = 'icons/mob/actions/actions_slime.dmi'
- background_icon_state = "bg_alien"
- var/datum/species/jelly/stargazer/species
-
-/datum/action/innate/link_minds/New(_species)
- ..()
- species = _species
-
-/datum/action/innate/link_minds/Activate()
- var/mob/living/carbon/human/H = owner
- if(!is_species(H, /datum/species/jelly/stargazer))
- return
- CHECK_DNA_AND_SPECIES(H)
-
- if(!H.pulling || !isliving(H.pulling) || H.grab_state < GRAB_AGGRESSIVE)
- to_chat(H, "You need to aggressively grab someone to link minds!")
- return
-
- var/mob/living/target = H.pulling
-
- to_chat(H, "You begin linking [target]'s mind to yours...")
- to_chat(target, "You feel a foreign presence within your mind...")
- if(do_after(H, 60, target = target))
- if(H.pulling != target || H.grab_state < GRAB_AGGRESSIVE)
- return
- if(species.link_mob(target))
- to_chat(H, "You connect [target]'s mind to your slime link!")
- else
- to_chat(H, "You can't seem to link [target]'s mind...")
- to_chat(target, "The foreign presence leaves your mind.")
+/datum/species/jelly
+ // Entirely alien beings that seem to be made entirely out of gel. They have three eyes and a skeleton visible within them.
+ name = "Xenobiological Jelly Entity"
+ id = "jelly"
+ default_color = "00FF90"
+ say_mod = "chirps"
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR,WINGCOLOR)
+ mutantlungs = /obj/item/organ/lungs/slime
+ mutant_heart = /obj/item/organ/heart/slime
+ mutant_bodyparts = list("mam_tail", "mam_ears", "mam_snouts", "taur") //CIT CHANGE
+ default_features = list("mcolor" = "FFF", "mam_tail" = "None", "mam_ears" = "None", "mam_snouts" = "None", "taur" = "None") //CIT CHANGE
+ inherent_traits = list(TRAIT_TOXINLOVER)
+ meat = /obj/item/reagent_containers/food/snacks/meat/slab/human/mutant/slime
+ gib_types = list(/obj/effect/gibspawner/slime, /obj/effect/gibspawner/slime/bodypartless)
+ exotic_blood = /datum/reagent/blood/jellyblood
+ exotic_bloodtype = "GEL"
+ damage_overlay_type = ""
+ var/datum/action/innate/regenerate_limbs/regenerate_limbs
+ var/datum/action/innate/slime_change/slime_change //CIT CHANGE
+ liked_food = TOXIC | MEAT
+ toxic_food = null
+ coldmod = 6 // = 3x cold damage
+ heatmod = 0.5 // = 1/4x heat damage
+ burnmod = 0.5 // = 1/2x generic burn damage
+
+/datum/species/jelly/on_species_loss(mob/living/carbon/C)
+ if(regenerate_limbs)
+ regenerate_limbs.Remove(C)
+ if(slime_change) //CIT CHANGE
+ slime_change.Remove(C) //CIT CHANGE
+ C.remove_language(/datum/language/slime)
+ C.faction -= "slime"
+ ..()
+ C.faction -= "slime"
+
+/datum/species/jelly/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ C.grant_language(/datum/language/slime)
+ if(ishuman(C))
+ regenerate_limbs = new
+ regenerate_limbs.Grant(C)
+ slime_change = new //CIT CHANGE
+ slime_change.Grant(C) //CIT CHANGE
+ C.faction |= "slime"
+
+/datum/species/jelly/spec_life(mob/living/carbon/human/H)
+ if(H.stat == DEAD || HAS_TRAIT(H, TRAIT_NOMARROW)) //can't farm slime jelly from a dead slime/jelly person indefinitely, and no regeneration for vampires
+ return
+ if(!H.blood_volume)
+ H.blood_volume += 5
+ H.adjustBruteLoss(5)
+ to_chat(H, "You feel empty!")
+
+ if(H.blood_volume < (BLOOD_VOLUME_NORMAL * H.blood_ratio))
+ if(H.nutrition >= NUTRITION_LEVEL_STARVING)
+ H.blood_volume += 3
+ H.nutrition -= 2.5
+ if(H.blood_volume < (BLOOD_VOLUME_OKAY*H.blood_ratio))
+ if(prob(5))
+ to_chat(H, "You feel drained!")
+ if(H.blood_volume < (BLOOD_VOLUME_BAD*H.blood_ratio))
+ Cannibalize_Body(H)
+ if(regenerate_limbs)
+ regenerate_limbs.UpdateButtonIcon()
+
+/datum/species/jelly/proc/Cannibalize_Body(mob/living/carbon/human/H)
+ var/list/limbs_to_consume = list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG) - H.get_missing_limbs()
+ var/obj/item/bodypart/consumed_limb
+ if(!limbs_to_consume.len)
+ H.losebreath++
+ return
+ if(H.get_num_legs(FALSE)) //Legs go before arms
+ limbs_to_consume -= list(BODY_ZONE_R_ARM, BODY_ZONE_L_ARM)
+ consumed_limb = H.get_bodypart(pick(limbs_to_consume))
+ consumed_limb.drop_limb()
+ to_chat(H, "Your [consumed_limb] is drawn back into your body, unable to maintain its shape!")
+ qdel(consumed_limb)
+ H.blood_volume += 20
+
+/datum/action/innate/regenerate_limbs
+ name = "Regenerate Limbs"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "slimeheal"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/regenerate_limbs/IsAvailable()
+ if(..())
+ var/mob/living/carbon/human/H = owner
+ var/list/limbs_to_heal = H.get_missing_limbs()
+ if(limbs_to_heal.len < 1)
+ return 0
+ if(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
+ return 1
+ return 0
+
+/datum/action/innate/regenerate_limbs/Activate()
+ var/mob/living/carbon/human/H = owner
+ var/list/limbs_to_heal = H.get_missing_limbs()
+ if(limbs_to_heal.len < 1)
+ to_chat(H, "You feel intact enough as it is.")
+ return
+ to_chat(H, "You focus intently on your missing [limbs_to_heal.len >= 2 ? "limbs" : "limb"]...")
+ if(H.blood_volume >= 40*limbs_to_heal.len+(BLOOD_VOLUME_OKAY*H.blood_ratio))
+ H.regenerate_limbs()
+ H.blood_volume -= 40*limbs_to_heal.len
+ to_chat(H, "...and after a moment you finish reforming!")
+ return
+ else if(H.blood_volume >= 40)//We can partially heal some limbs
+ while(H.blood_volume >= (BLOOD_VOLUME_OKAY*H.blood_ratio)+40)
+ var/healed_limb = pick(limbs_to_heal)
+ H.regenerate_limb(healed_limb)
+ limbs_to_heal -= healed_limb
+ H.blood_volume -= 40
+ to_chat(H, "...but there is not enough of you to fix everything! You must attain more mass to heal completely!")
+ return
+ to_chat(H, "...but there is not enough of you to go around! You must attain more mass to heal!")
+
+////////////////////////////////////////////////////////SLIMEPEOPLE///////////////////////////////////////////////////////////////////
+
+//Slime people are able to split like slimes, retaining a single mind that can swap between bodies at will, even after death.
+
+/datum/species/jelly/slime
+ name = "Slimeperson"
+ id = "slime"
+ default_color = "00FFFF"
+ species_traits = list(MUTCOLORS,EYECOLOR,HAIR,FACEHAIR)
+ say_mod = "says"
+ hair_color = "mutcolor"
+ hair_alpha = 150
+ ignored_by = list(/mob/living/simple_animal/slime)
+ var/datum/action/innate/split_body/slime_split
+ var/list/mob/living/carbon/bodies
+ var/datum/action/innate/swap_body/swap_body
+
+/datum/species/jelly/slime/on_species_loss(mob/living/carbon/C)
+ if(slime_split)
+ slime_split.Remove(C)
+ if(swap_body)
+ swap_body.Remove(C)
+ bodies -= C // This means that the other bodies maintain a link
+ // so if someone mindswapped into them, they'd still be shared.
+ bodies = null
+ C.blood_volume = min(C.blood_volume, (BLOOD_VOLUME_NORMAL*C.blood_ratio))
+ ..()
+
+/datum/species/jelly/slime/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ if(ishuman(C))
+ slime_split = new
+ slime_split.Grant(C)
+ swap_body = new
+ swap_body.Grant(C)
+
+ if(!bodies || !bodies.len)
+ bodies = list(C)
+ else
+ bodies |= C
+
+/datum/species/jelly/slime/spec_death(gibbed, mob/living/carbon/human/H)
+ if(slime_split)
+ if(!H.mind || !H.mind.active)
+ return
+
+ var/list/available_bodies = (bodies - H)
+ for(var/mob/living/L in available_bodies)
+ if(!swap_body.can_swap(L))
+ available_bodies -= L
+
+ if(!LAZYLEN(available_bodies))
+ return
+
+ swap_body.swap_to_dupe(H.mind, pick(available_bodies))
+
+//If you're cloned you get your body pool back
+/datum/species/jelly/slime/copy_properties_from(datum/species/jelly/slime/old_species)
+ bodies = old_species.bodies
+
+/datum/species/jelly/slime/spec_life(mob/living/carbon/human/H)
+ if((HAS_TRAIT(H, TRAIT_NOMARROW)))
+ return
+ if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
+ if(prob(5))
+ to_chat(H, "You feel very bloated!")
+ else if(H.nutrition >= NUTRITION_LEVEL_WELL_FED)
+ H.blood_volume += 3
+ H.nutrition -= 2.5
+
+ ..()
+
+/datum/action/innate/split_body
+ name = "Split Body"
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "slimesplit"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/split_body/IsAvailable()
+ if(..())
+ var/mob/living/carbon/human/H = owner
+ if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
+ return 1
+ return 0
+
+/datum/action/innate/split_body/Activate()
+ var/mob/living/carbon/human/H = owner
+ if(!isslimeperson(H))
+ return
+ CHECK_DNA_AND_SPECIES(H)
+ H.visible_message("[owner] gains a look of \
+ concentration while standing perfectly still.",
+ "You focus intently on moving your body while \
+ standing perfectly still...")
+
+ H.notransform = TRUE
+
+ if(do_after(owner, delay=60, needhand=FALSE, target=owner, progress=TRUE))
+ if(H.blood_volume >= BLOOD_VOLUME_SLIME_SPLIT)
+ make_dupe()
+ else
+ to_chat(H, "...but there is not enough of you to go around! You must attain more mass to split!")
+ else
+ to_chat(H, "...but fail to stand perfectly still!")
+
+ H.notransform = FALSE
+
+/datum/action/innate/split_body/proc/make_dupe()
+ var/mob/living/carbon/human/H = owner
+ CHECK_DNA_AND_SPECIES(H)
+
+ var/mob/living/carbon/human/spare = new /mob/living/carbon/human(H.loc)
+
+ spare.underwear = "Nude"
+ H.dna.transfer_identity(spare, transfer_SE=1)
+ spare.dna.features["mcolor"] = pick("FFFFFF","7F7F7F", "7FFF7F", "7F7FFF", "FF7F7F", "7FFFFF", "FF7FFF", "FFFF7F")
+ spare.real_name = spare.dna.real_name
+ spare.name = spare.dna.real_name
+ spare.updateappearance(mutcolor_update=1)
+ spare.domutcheck()
+ spare.Move(get_step(H.loc, pick(NORTH,SOUTH,EAST,WEST)))
+
+ H.blood_volume *= 0.45
+ H.notransform = 0
+
+ var/datum/species/jelly/slime/origin_datum = H.dna.species
+ origin_datum.bodies |= spare
+
+ var/datum/species/jelly/slime/spare_datum = spare.dna.species
+ spare_datum.bodies = origin_datum.bodies
+
+ H.transfer_trait_datums(spare)
+ H.mind.transfer_to(spare)
+ spare.visible_message("[H] distorts as a new body \
+ \"steps out\" of [H.p_them()].",
+ "...and after a moment of disorentation, \
+ you're besides yourself!")
+
+
+/datum/action/innate/swap_body
+ name = "Swap Body"
+ check_flags = NONE
+ button_icon_state = "slimeswap"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/swap_body/Activate()
+ if(!isslimeperson(owner))
+ to_chat(owner, "You are not a slimeperson.")
+ Remove(owner)
+ else
+ ui_interact(owner)
+
+/datum/action/innate/swap_body/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.always_state)
+
+ ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
+ if(!ui)
+ ui = new(user, src, ui_key, "slime_swap_body", name, 400, 400, master_ui, state)
+ ui.open()
+
+/datum/action/innate/swap_body/ui_data(mob/user)
+ var/mob/living/carbon/human/H = owner
+ if(!isslimeperson(H))
+ return
+
+ var/datum/species/jelly/slime/SS = H.dna.species
+
+ var/list/data = list()
+ data["bodies"] = list()
+ for(var/b in SS.bodies)
+ var/mob/living/carbon/human/body = b
+ if(!body || QDELETED(body) || !isslimeperson(body))
+ SS.bodies -= b
+ continue
+
+ var/list/L = list()
+ // HTML colors need a # prefix
+ L["htmlcolor"] = "#[body.dna.features["mcolor"]]"
+ L["area"] = get_area_name(body, TRUE)
+ var/stat = "error"
+ switch(body.stat)
+ if(CONSCIOUS)
+ stat = "Conscious"
+ if(UNCONSCIOUS)
+ stat = "Unconscious"
+ if(DEAD)
+ stat = "Dead"
+ var/occupied
+ if(body == H)
+ occupied = "owner"
+ else if(body.mind && body.mind.active)
+ occupied = "stranger"
+ else
+ occupied = "available"
+
+ L["status"] = stat
+ L["exoticblood"] = body.blood_volume
+ L["name"] = body.name
+ L["ref"] = "[REF(body)]"
+ L["occupied"] = occupied
+ var/button
+ if(occupied == "owner")
+ button = "selected"
+ else if(occupied == "stranger")
+ button = "danger"
+ else if(can_swap(body))
+ button = null
+ else
+ button = "disabled"
+
+ L["swap_button_state"] = button
+ L["swappable"] = (occupied == "available") && can_swap(body)
+
+ data["bodies"] += list(L)
+
+ return data
+
+/datum/action/innate/swap_body/ui_act(action, params)
+ if(..())
+ return
+ var/mob/living/carbon/human/H = owner
+ if(!isslimeperson(owner))
+ return
+ if(!H.mind || !H.mind.active)
+ return
+ switch(action)
+ if("swap")
+ var/mob/living/carbon/human/selected = locate(params["ref"])
+ if(!can_swap(selected))
+ return
+ SStgui.close_uis(src)
+ swap_to_dupe(H.mind, selected)
+
+/datum/action/innate/swap_body/proc/can_swap(mob/living/carbon/human/dupe)
+ var/mob/living/carbon/human/H = owner
+ if(!isslimeperson(H))
+ return FALSE
+ var/datum/species/jelly/slime/SS = H.dna.species
+
+ if(QDELETED(dupe)) //Is there a body?
+ SS.bodies -= dupe
+ return FALSE
+
+ if(!isslimeperson(dupe)) //Is it a slimeperson?
+ SS.bodies -= dupe
+ return FALSE
+
+ if(dupe.stat == DEAD) //Is it alive?
+ return FALSE
+
+ if(dupe.stat != CONSCIOUS) //Is it awake?
+ return FALSE
+
+ if(dupe.mind && dupe.mind.active) //Is it unoccupied?
+ return FALSE
+
+ if(!(dupe in SS.bodies)) //Do we actually own it?
+ return FALSE
+
+ return TRUE
+
+/datum/action/innate/swap_body/proc/swap_to_dupe(datum/mind/M, mob/living/carbon/human/dupe)
+ if(!can_swap(dupe)) //sanity check
+ return
+ if(M.current.stat == CONSCIOUS)
+ M.current.visible_message("[M.current] \
+ stops moving and starts staring vacantly into space.",
+ "You stop moving this body...")
+ else
+ to_chat(M.current, "You abandon this body...")
+ M.current.transfer_trait_datums(dupe)
+ M.transfer_to(dupe)
+ dupe.visible_message("[dupe] blinks and looks \
+ around.",
+ "...and move this one instead.")
+
+
+///////////////////////////////////LUMINESCENTS//////////////////////////////////////////
+
+//Luminescents are able to consume and use slime extracts, without them decaying.
+
+/datum/species/jelly/luminescent
+ name = "Luminescent"
+ id = "lum"
+ say_mod = "says"
+ var/glow_intensity = LUMINESCENT_DEFAULT_GLOW
+ var/obj/effect/dummy/luminescent_glow/glow
+ var/obj/item/slime_extract/current_extract
+ var/datum/action/innate/integrate_extract/integrate_extract
+ var/datum/action/innate/use_extract/extract_minor
+ var/datum/action/innate/use_extract/major/extract_major
+ var/extract_cooldown = 0
+
+/datum/species/jelly/luminescent/on_species_loss(mob/living/carbon/C)
+ ..()
+ if(current_extract)
+ current_extract.forceMove(C.drop_location())
+ current_extract = null
+ qdel(glow)
+ if(integrate_extract)
+ integrate_extract.Remove(C)
+ if(extract_minor)
+ extract_minor.Remove(C)
+ if(extract_major)
+ extract_major.Remove(C)
+
+/datum/species/jelly/luminescent/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ glow = new(C)
+ update_glow(C)
+ integrate_extract = new(src)
+ integrate_extract.Grant(C)
+ extract_minor = new(src)
+ extract_minor.Grant(C)
+ extract_major = new(src)
+ extract_major.Grant(C)
+
+/datum/species/jelly/luminescent/proc/update_slime_actions()
+ integrate_extract.update_name()
+ integrate_extract.UpdateButtonIcon()
+ extract_minor.UpdateButtonIcon()
+ extract_major.UpdateButtonIcon()
+
+/datum/species/jelly/luminescent/proc/update_glow(mob/living/carbon/C, intensity)
+ if(intensity)
+ glow_intensity = intensity
+ glow.set_light(glow_intensity, glow_intensity, C.dna.features["mcolor"])
+
+/obj/effect/dummy/luminescent_glow
+ name = "luminescent glow"
+ desc = "Tell a coder if you're seeing this."
+ icon_state = "nothing"
+ light_color = "#FFFFFF"
+ light_range = LUMINESCENT_DEFAULT_GLOW
+
+/obj/effect/dummy/luminescent_glow/Initialize()
+ . = ..()
+ if(!isliving(loc))
+ return INITIALIZE_HINT_QDEL
+
+/datum/action/innate/integrate_extract
+ name = "Integrate Extract"
+ desc = "Eat a slime extract to use its properties."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "slimeconsume"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+ var/datum/species/jelly/luminescent/species
+
+/datum/action/innate/integrate_extract/New(_species)
+ ..()
+ species = _species
+
+/datum/action/innate/integrate_extract/proc/update_name()
+ if(!species || !species.current_extract)
+ name = "Integrate Extract"
+ desc = "Eat a slime extract to use its properties."
+ else
+ name = "Eject Extract"
+ desc = "Eject your current slime extract."
+
+/datum/action/innate/integrate_extract/UpdateButtonIcon(status_only, force)
+ if(!species || !species.current_extract)
+ button_icon_state = "slimeconsume"
+ else
+ button_icon_state = "slimeeject"
+ ..()
+
+/datum/action/innate/integrate_extract/ApplyIcon(obj/screen/movable/action_button/current_button, force)
+ ..(current_button, TRUE)
+ if(species && species.current_extract)
+ current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
+
+/datum/action/innate/integrate_extract/Activate()
+ var/mob/living/carbon/human/H = owner
+ if(!is_species(H, /datum/species/jelly/luminescent) || !species)
+ return
+ CHECK_DNA_AND_SPECIES(H)
+
+ if(species.current_extract)
+ var/obj/item/slime_extract/S = species.current_extract
+ if(!H.put_in_active_hand(S))
+ S.forceMove(H.drop_location())
+ species.current_extract = null
+ to_chat(H, "You eject [S].")
+ species.update_slime_actions()
+ else
+ var/obj/item/I = H.get_active_held_item()
+ if(istype(I, /obj/item/slime_extract))
+ var/obj/item/slime_extract/S = I
+ if(!S.Uses)
+ to_chat(H, "[I] is spent! You cannot integrate it.")
+ return
+ if(!H.temporarilyRemoveItemFromInventory(S))
+ return
+ S.forceMove(H)
+ species.current_extract = S
+ to_chat(H, "You consume [I], and you feel it pulse within you...")
+ species.update_slime_actions()
+ else
+ to_chat(H, "You need to hold an unused slime extract in your active hand!")
+
+/datum/action/innate/use_extract
+ name = "Extract Minor Activation"
+ desc = "Pulse the slime extract with energized jelly to activate it."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "slimeuse1"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+ var/activation_type = SLIME_ACTIVATE_MINOR
+ var/datum/species/jelly/luminescent/species
+
+/datum/action/innate/use_extract/New(_species)
+ ..()
+ species = _species
+
+/datum/action/innate/use_extract/IsAvailable()
+ if(..())
+ if(species && species.current_extract && (world.time > species.extract_cooldown))
+ return TRUE
+ return FALSE
+
+/datum/action/innate/use_extract/ApplyIcon(obj/screen/movable/action_button/current_button, force)
+ ..(current_button, TRUE)
+ if(species && species.current_extract)
+ current_button.add_overlay(mutable_appearance(species.current_extract.icon, species.current_extract.icon_state))
+
+/datum/action/innate/use_extract/Activate()
+ var/mob/living/carbon/human/H = owner
+ if(!is_species(H, /datum/species/jelly/luminescent) || !species)
+ return
+ CHECK_DNA_AND_SPECIES(H)
+
+ if(species.current_extract)
+ species.extract_cooldown = world.time + 100
+ var/cooldown = species.current_extract.activate(H, species, activation_type)
+ species.extract_cooldown = world.time + cooldown
+
+/datum/action/innate/use_extract/major
+ name = "Extract Major Activation"
+ desc = "Pulse the slime extract with plasma jelly to activate it."
+ button_icon_state = "slimeuse2"
+ activation_type = SLIME_ACTIVATE_MAJOR
+
+///////////////////////////////////STARGAZERS//////////////////////////////////////////
+
+//Stargazers are the telepathic branch of jellypeople, able to project psychic messages and to link minds with willing participants.
+
+/datum/species/jelly/stargazer
+ name = "Stargazer"
+ id = "stargazer"
+ var/datum/action/innate/project_thought/project_thought
+ var/datum/action/innate/link_minds/link_minds
+ var/list/mob/living/linked_mobs = list()
+ var/list/datum/action/innate/linked_speech/linked_actions = list()
+ var/mob/living/carbon/human/slimelink_owner
+ var/current_link_id = 0
+
+/datum/species/jelly/stargazer/on_species_loss(mob/living/carbon/C)
+ ..()
+ for(var/M in linked_mobs)
+ unlink_mob(M)
+ if(project_thought)
+ project_thought.Remove(C)
+ if(link_minds)
+ link_minds.Remove(C)
+
+/datum/species/jelly/stargazer/spec_death(gibbed, mob/living/carbon/human/H)
+ ..()
+ for(var/M in linked_mobs)
+ unlink_mob(M)
+
+/datum/species/jelly/stargazer/on_species_gain(mob/living/carbon/C, datum/species/old_species)
+ ..()
+ project_thought = new(src)
+ project_thought.Grant(C)
+ link_minds = new(src)
+ link_minds.Grant(C)
+ slimelink_owner = C
+ link_mob(C)
+
+/datum/species/jelly/stargazer/proc/link_mob(mob/living/M)
+ if(QDELETED(M) || M.stat == DEAD)
+ return FALSE
+ if(HAS_TRAIT(M, TRAIT_MINDSHIELD)) //mindshield implant, no dice
+ return FALSE
+ if(M in linked_mobs)
+ return FALSE
+ linked_mobs.Add(M)
+ to_chat(M, "You are now connected to [slimelink_owner.real_name]'s Slime Link.")
+ var/datum/action/innate/linked_speech/action = new(src)
+ linked_actions.Add(action)
+ action.Grant(M)
+ return TRUE
+
+/datum/species/jelly/stargazer/proc/unlink_mob(mob/living/M)
+ var/link_id = linked_mobs.Find(M)
+ if(!(link_id))
+ return
+ var/datum/action/innate/linked_speech/action = linked_actions[link_id]
+ action.Remove(M)
+ to_chat(M, "You are no longer connected to [slimelink_owner.real_name]'s Slime Link.")
+ linked_mobs[link_id] = null
+ linked_actions[link_id] = null
+
+/datum/action/innate/linked_speech
+ name = "Slimelink"
+ desc = "Send a psychic message to everyone connected to your slime link."
+ button_icon_state = "link_speech"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+ var/datum/species/jelly/stargazer/species
+
+/datum/action/innate/linked_speech/New(_species)
+ ..()
+ species = _species
+
+/datum/action/innate/linked_speech/Activate()
+ var/mob/living/carbon/human/H = owner
+ if(!species || !(H in species.linked_mobs))
+ to_chat(H, "The link seems to have been severed...")
+ Remove(H)
+ return
+
+ var/message = sanitize(input("Message:", "Slime Telepathy") as text|null)
+
+ if(!species || !(H in species.linked_mobs))
+ to_chat(H, "The link seems to have been severed...")
+ Remove(H)
+ return
+
+ if(QDELETED(H) || H.stat == DEAD)
+ species.unlink_mob(H)
+ return
+
+ if(message)
+ var/msg = "\[[species.slimelink_owner.real_name]'s Slime Link\] [H]: [message]"
+ log_directed_talk(H, species.slimelink_owner, msg, LOG_SAY, "slime link")
+ for(var/X in species.linked_mobs)
+ var/mob/living/M = X
+ if(QDELETED(M) || M.stat == DEAD)
+ species.unlink_mob(M)
+ continue
+ to_chat(M, msg)
+
+ for(var/X in GLOB.dead_mob_list)
+ var/mob/M = X
+ var/link = FOLLOW_LINK(M, H)
+ to_chat(M, "[link] [msg]")
+
+/datum/action/innate/project_thought
+ name = "Send Thought"
+ desc = "Send a private psychic message to someone you can see."
+ button_icon_state = "send_mind"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/project_thought/Activate()
+ var/mob/living/carbon/human/H = owner
+ if(H.stat == DEAD)
+ return
+ if(!is_species(H, /datum/species/jelly/stargazer))
+ return
+ CHECK_DNA_AND_SPECIES(H)
+
+ var/list/options = list()
+ for(var/mob/living/Ms in oview(H))
+ options += Ms
+ var/mob/living/M = input("Select who to send your message to:","Send thought to?",null) as null|mob in options
+ if(!M)
+ return
+
+ var/msg = sanitize(input("Message:", "Telepathy") as text|null)
+ if(msg)
+ log_directed_talk(H, M, msg, LOG_SAY, "slime telepathy")
+ to_chat(M, "You hear an alien voice in your head... [msg]")
+ to_chat(H, "You telepathically said: \"[msg]\" to [M]")
+ for(var/dead in GLOB.dead_mob_list)
+ if(!isobserver(dead))
+ continue
+ var/follow_link_user = FOLLOW_LINK(dead, H)
+ var/follow_link_target = FOLLOW_LINK(dead, M)
+ to_chat(dead, "[follow_link_user] [H]Slime Telepathy --> [follow_link_target] [M][msg]")
+
+/datum/action/innate/link_minds
+ name = "Link Minds"
+ desc = "Link someone's mind to your Slime Link, allowing them to communicate telepathically with other linked minds."
+ button_icon_state = "mindlink"
+ icon_icon = 'icons/mob/actions/actions_slime.dmi'
+ background_icon_state = "bg_alien"
+ var/datum/species/jelly/stargazer/species
+
+/datum/action/innate/link_minds/New(_species)
+ ..()
+ species = _species
+
+/datum/action/innate/link_minds/Activate()
+ var/mob/living/carbon/human/H = owner
+ if(!is_species(H, /datum/species/jelly/stargazer))
+ return
+ CHECK_DNA_AND_SPECIES(H)
+
+ if(!H.pulling || !isliving(H.pulling) || H.grab_state < GRAB_AGGRESSIVE)
+ to_chat(H, "You need to aggressively grab someone to link minds!")
+ return
+
+ var/mob/living/target = H.pulling
+
+ to_chat(H, "You begin linking [target]'s mind to yours...")
+ to_chat(target, "You feel a foreign presence within your mind...")
+ if(do_after(H, 60, target = target))
+ if(H.pulling != target || H.grab_state < GRAB_AGGRESSIVE)
+ return
+ if(species.link_mob(target))
+ to_chat(H, "You connect [target]'s mind to your slime link!")
+ else
+ to_chat(H, "You can't seem to link [target]'s mind...")
+ to_chat(target, "The foreign presence leaves your mind.")
diff --git a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
index 7be0265c..228661e1 100644
--- a/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/mushpeople.dm
@@ -47,9 +47,9 @@
QDEL_NULL(mush)
/datum/species/mush/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(chem.id == "weedkiller")
+ if(chem.type == /datum/reagent/toxin/plantbgone/weedkiller)
H.adjustToxLoss(3)
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
+ H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
return TRUE
/datum/species/mush/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
diff --git a/code/modules/mob/living/carbon/human/species_types/podpeople.dm b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
index fbe18a6c..dcf26b70 100644
--- a/code/modules/mob/living/carbon/human/species_types/podpeople.dm
+++ b/code/modules/mob/living/carbon/human/species_types/podpeople.dm
@@ -47,9 +47,9 @@
H.take_overall_damage(2,0)
/datum/species/pod/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(chem.id == "plantbgone")
+ if(chem.type == /datum/reagent/toxin/plantbgone)
H.adjustToxLoss(3)
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
+ H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
return 1
/datum/species/pod/on_hit(obj/item/projectile/P, mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/species_types/synths.dm b/code/modules/mob/living/carbon/human/species_types/synths.dm
index 1d0370c7..703fffa4 100644
--- a/code/modules/mob/living/carbon/human/species_types/synths.dm
+++ b/code/modules/mob/living/carbon/human/species_types/synths.dm
@@ -1,129 +1,129 @@
-/datum/species/synth
- name = "Synth" //inherited from the real species, for health scanners and things
- id = "synth"
- say_mod = "beep boops" //inherited from a user's real species
- sexes = 0
- species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species
- inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH)
- inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
- dangerous_existence = 1
- blacklisted = 1
- meat = null
- gib_types = /obj/effect/gibspawner/robot
- damage_overlay_type = "synth"
- limbs_id = "synth"
- var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
- var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH)
- var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
- var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
-
-/datum/species/synth/military
- name = "Military Synth"
- id = "military_synth"
- armor = 25
- punchdamagelow = 10
- punchdamagehigh = 19
- punchstunthreshold = 14 //about 50% chance to stun
- disguise_fail_health = 50
-
-/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
- ..()
- assume_disguise(old_species, H)
- RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech)
- H.grant_language(/datum/language/machine)
-
-/datum/species/synth/on_species_loss(mob/living/carbon/human/H)
- . = ..()
- UnregisterSignal(H, COMSIG_MOB_SAY)
- H.remove_language(/datum/language/machine)
-
-/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
- if(chem.id == "synthflesh")
- chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
- H.reagents.remove_reagent(chem.id, REAGENTS_METABOLISM)
- return 1
- else
- return ..()
-
-
-/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
- if(S && !istype(S, type))
- name = S.name
- say_mod = S.say_mod
- sexes = S.sexes
- species_traits = initial_species_traits.Copy()
- inherent_traits = initial_inherent_traits.Copy()
- species_traits |= S.species_traits
- inherent_traits |= S.inherent_traits
- attack_verb = S.attack_verb
- attack_sound = S.attack_sound
- miss_sound = S.miss_sound
- meat = S.meat
- mutant_bodyparts = S.mutant_bodyparts.Copy()
- mutant_organs = S.mutant_organs.Copy()
- default_features = S.default_features.Copy()
- nojumpsuit = S.nojumpsuit
- no_equip = S.no_equip.Copy()
- limbs_id = S.limbs_id
- use_skintones = S.use_skintones
- fixed_mut_color = S.fixed_mut_color
- hair_color = S.hair_color
- fake_species = new S.type
- else
- name = initial(name)
- say_mod = initial(say_mod)
- species_traits = initial_species_traits.Copy()
- inherent_traits = initial_inherent_traits.Copy()
- attack_verb = initial(attack_verb)
- attack_sound = initial(attack_sound)
- miss_sound = initial(miss_sound)
- mutant_bodyparts = list()
- default_features = list()
- nojumpsuit = initial(nojumpsuit)
- no_equip = list()
- qdel(fake_species)
- fake_species = null
- meat = initial(meat)
- limbs_id = "synth"
- use_skintones = 0
- sexes = 0
- fixed_mut_color = ""
- hair_color = ""
-
- for(var/X in H.bodyparts) //propagates the damage_overlay changes
- var/obj/item/bodypart/BP = X
- BP.update_limb()
- H.update_body_parts() //to update limb icon cache with the new damage overlays
-
-//Proc redirects:
-//Passing procs onto the fake_species, to ensure we look as much like them as possible
-
-/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
- if(fake_species)
- fake_species.handle_hair(H, forced_colour)
- else
- return ..()
-
-
-/datum/species/synth/handle_body(mob/living/carbon/human/H)
- if(fake_species)
- fake_species.handle_body(H)
- else
- return ..()
-
-
-/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
- if(fake_species)
- fake_species.handle_body(H,forced_colour)
- else
- return ..()
-
-/datum/species/synth/proc/handle_speech(datum/source, list/speech_args)
- if (isliving(source)) // yeah it's gonna be living but just to be clean
- var/mob/living/L = source
- if(fake_species && L.health > disguise_fail_health)
- switch (fake_species.type)
- if (/datum/species/golem/bananium)
- speech_args[SPEECH_SPANS] |= SPAN_CLOWN
- if (/datum/species/golem/clockwork)
- speech_args[SPEECH_SPANS] |= SPAN_ROBOT
+/datum/species/synth
+ name = "Synth" //inherited from the real species, for health scanners and things
+ id = "synth"
+ say_mod = "beep boops" //inherited from a user's real species
+ sexes = 0
+ species_traits = list(NOTRANSSTING,NOGENITALS,NOAROUSAL) //all of these + whatever we inherit from the real species
+ inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOBREATH)
+ inherent_biotypes = list(MOB_ROBOTIC, MOB_HUMANOID)
+ dangerous_existence = 1
+ blacklisted = 1
+ meat = null
+ gib_types = /obj/effect/gibspawner/robot
+ damage_overlay_type = "synth"
+ limbs_id = "synth"
+ var/list/initial_species_traits = list(NOTRANSSTING) //for getting these values back for assume_disguise()
+ var/list/initial_inherent_traits = list(TRAIT_VIRUSIMMUNE,TRAIT_NODISMEMBER,TRAIT_NOHUNGER,TRAIT_NOLIMBDISABLE,TRAIT_NOBREATH)
+ var/disguise_fail_health = 75 //When their health gets to this level their synthflesh partially falls off
+ var/datum/species/fake_species = null //a species to do most of our work for us, unless we're damaged
+
+/datum/species/synth/military
+ name = "Military Synth"
+ id = "military_synth"
+ armor = 25
+ punchdamagelow = 10
+ punchdamagehigh = 19
+ punchstunthreshold = 14 //about 50% chance to stun
+ disguise_fail_health = 50
+
+/datum/species/synth/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
+ ..()
+ assume_disguise(old_species, H)
+ RegisterSignal(H, COMSIG_MOB_SAY, .proc/handle_speech)
+ H.grant_language(/datum/language/machine)
+
+/datum/species/synth/on_species_loss(mob/living/carbon/human/H)
+ . = ..()
+ UnregisterSignal(H, COMSIG_MOB_SAY)
+ H.remove_language(/datum/language/machine)
+
+/datum/species/synth/handle_chemicals(datum/reagent/chem, mob/living/carbon/human/H)
+ if(chem.type == /datum/reagent/medicine/synthflesh)
+ chem.reaction_mob(H, TOUCH, 2 ,0) //heal a little
+ H.reagents.remove_reagent(chem.type, REAGENTS_METABOLISM)
+ return 1
+ else
+ return ..()
+
+
+/datum/species/synth/proc/assume_disguise(datum/species/S, mob/living/carbon/human/H)
+ if(S && !istype(S, type))
+ name = S.name
+ say_mod = S.say_mod
+ sexes = S.sexes
+ species_traits = initial_species_traits.Copy()
+ inherent_traits = initial_inherent_traits.Copy()
+ species_traits |= S.species_traits
+ inherent_traits |= S.inherent_traits
+ attack_verb = S.attack_verb
+ attack_sound = S.attack_sound
+ miss_sound = S.miss_sound
+ meat = S.meat
+ mutant_bodyparts = S.mutant_bodyparts.Copy()
+ mutant_organs = S.mutant_organs.Copy()
+ default_features = S.default_features.Copy()
+ nojumpsuit = S.nojumpsuit
+ no_equip = S.no_equip.Copy()
+ limbs_id = S.limbs_id
+ use_skintones = S.use_skintones
+ fixed_mut_color = S.fixed_mut_color
+ hair_color = S.hair_color
+ fake_species = new S.type
+ else
+ name = initial(name)
+ say_mod = initial(say_mod)
+ species_traits = initial_species_traits.Copy()
+ inherent_traits = initial_inherent_traits.Copy()
+ attack_verb = initial(attack_verb)
+ attack_sound = initial(attack_sound)
+ miss_sound = initial(miss_sound)
+ mutant_bodyparts = list()
+ default_features = list()
+ nojumpsuit = initial(nojumpsuit)
+ no_equip = list()
+ qdel(fake_species)
+ fake_species = null
+ meat = initial(meat)
+ limbs_id = "synth"
+ use_skintones = 0
+ sexes = 0
+ fixed_mut_color = ""
+ hair_color = ""
+
+ for(var/X in H.bodyparts) //propagates the damage_overlay changes
+ var/obj/item/bodypart/BP = X
+ BP.update_limb()
+ H.update_body_parts() //to update limb icon cache with the new damage overlays
+
+//Proc redirects:
+//Passing procs onto the fake_species, to ensure we look as much like them as possible
+
+/datum/species/synth/handle_hair(mob/living/carbon/human/H, forced_colour)
+ if(fake_species)
+ fake_species.handle_hair(H, forced_colour)
+ else
+ return ..()
+
+
+/datum/species/synth/handle_body(mob/living/carbon/human/H)
+ if(fake_species)
+ fake_species.handle_body(H)
+ else
+ return ..()
+
+
+/datum/species/synth/handle_mutant_bodyparts(mob/living/carbon/human/H, forced_colour)
+ if(fake_species)
+ fake_species.handle_body(H,forced_colour)
+ else
+ return ..()
+
+/datum/species/synth/proc/handle_speech(datum/source, list/speech_args)
+ if (isliving(source)) // yeah it's gonna be living but just to be clean
+ var/mob/living/L = source
+ if(fake_species && L.health > disguise_fail_health)
+ switch (fake_species.type)
+ if (/datum/species/golem/bananium)
+ speech_args[SPEECH_SPANS] |= SPAN_CLOWN
+ if (/datum/species/golem/clockwork)
+ speech_args[SPEECH_SPANS] |= SPAN_ROBOT
diff --git a/code/modules/mob/living/carbon/life.dm b/code/modules/mob/living/carbon/life.dm
index 26559b3d..56858582 100644
--- a/code/modules/mob/living/carbon/life.dm
+++ b/code/modules/mob/living/carbon/life.dm
@@ -1,773 +1,773 @@
-/mob/living/carbon/Life()
- set invisibility = 0
-
- //Hyper Change
- if(size_multiplier != previous_size)
- sleep(1)
- resize(size_multiplier)
-
- if(notransform)
- return
-
- if(damageoverlaytemp)
- damageoverlaytemp = 0
- update_damage_hud()
-
-
- if(!IsInStasis())
- //Reagent processing needs to come before breathing, to prevent edge cases.
- handle_organs()
-
- . = ..()
-
- if (QDELETED(src))
- return
-
- if(.) //not dead
- handle_blood()
-
- if(stat != DEAD)
- var/bprv = handle_bodyparts()
- if(bprv & BODYPART_LIFE_UPDATE_HEALTH)
- updatehealth()
- update_stamina()
-
- if(stat != DEAD)
- handle_brain_damage()
-/* Bug cause?
- if(stat != DEAD)
- handle_liver()
-*/
- if(stat == DEAD)
- stop_sound_channel(CHANNEL_HEARTBEAT)
- handle_death()
- rot()
-
- //Updates the number of stored chemicals for powers
- handle_changeling()
-
- if(stat != DEAD)
- return 1
-
-//Procs called while dead
-/mob/living/carbon/proc/handle_death()
- for(var/datum/reagent/R in reagents.reagent_list)
- if(R.chemical_flags & REAGENT_DEAD_PROCESS)
- R.on_mob_dead(src)
-
-///////////////
-// BREATHING //
-///////////////
-
-//Start of a breath chain, calls breathe()
-/mob/living/carbon/handle_breathing(times_fired)
- var/next_breath = 4
- var/obj/item/organ/lungs/L = getorganslot(ORGAN_SLOT_LUNGS)
- var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART)
- if(L)
- if(L.damage > L.high_threshold)
- next_breath--
- if(H)
- if(H.damage > H.high_threshold)
- next_breath--
-
- if((times_fired % next_breath) == 0 || failed_last_breath)
- breathe() //Breathe per 4 ticks if healthy, down to 2 if our lungs or heart are damaged, unless suffocating
- if(failed_last_breath)
- var/mob/living/carbon/human/B = src
- if(HAS_TRAIT(B, TRAIT_CHOKE_SLUT))
- B.adjustArousalLoss(7)
- if (B.getArousalLoss() >= 100 && ishuman(B) && B.has_dna())
- B.mob_climax(forced_climax=TRUE)
- else
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
- else
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation")
- else
- if(istype(loc, /obj/))
- var/obj/location_as_object = loc
- location_as_object.handle_internal_lifeform(src,0)
-
-//Second link in a breath chain, calls check_breath()
-/mob/living/carbon/proc/breathe()
- var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS)
- if(reagents.has_reagent("lexorin"))
- return
- if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
- return
- if(istype(loc, /obj/item/dogborg/sleeper))
- return
- if(ismob(loc))
- return
- if(isbelly(loc))
- return
-
- var/datum/gas_mixture/environment
- if(loc)
- environment = loc.return_air()
-
- var/datum/gas_mixture/breath
-
- if(!getorganslot(ORGAN_SLOT_BREATHING_TUBE))
- if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || lungs.organ_flags & ORGAN_FAILING)
- losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath
-
- else if(health <= crit_threshold)
- losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times
-
- //Suffocate
- if(losebreath >= 1) //You've missed a breath, take oxy damage
- losebreath--
- if(prob(10))
- emote("gasp")
- if(istype(loc, /obj/))
- var/obj/loc_as_obj = loc
- loc_as_obj.handle_internal_lifeform(src,0)
- else
- //Breathe from internal
- breath = get_breath_from_internal(BREATH_VOLUME)
-
- if(isnull(breath)) //in case of 0 pressure internals
-
- if(isobj(loc)) //Breathe from loc as object
- var/obj/loc_as_obj = loc
- breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
-
- else if(isturf(loc)) //Breathe from loc as turf
- var/breath_moles = 0
- if(environment)
- breath_moles = environment.total_moles()*BREATH_PERCENTAGE
-
- breath = loc.remove_air(breath_moles)
- else //Breathe from loc as obj again
- if(istype(loc, /obj/))
- var/obj/loc_as_obj = loc
- loc_as_obj.handle_internal_lifeform(src,0)
-
- check_breath(breath)
-
- if(breath)
- loc.assume_air(breath)
- air_update_turf()
-
-/mob/living/carbon/proc/has_smoke_protection()
- if(HAS_TRAIT(src, TRAIT_NOBREATH))
- return TRUE
- return FALSE
-
-
-//Third link in a breath chain, calls handle_breath_temperature()
-/mob/living/carbon/proc/check_breath(datum/gas_mixture/breath)
- if((status_flags & GODMODE))
- return
-
- var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS)
- if(!lungs)
- adjustOxyLoss(2)
-
- //CRIT
- if(!breath || (breath.total_moles() == 0) || !lungs)
- if(reagents.has_reagent("epinephrine") && lungs)
- return
- adjustOxyLoss(1)
-
- failed_last_breath = 1
- throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
- return 0
-
- var/safe_oxy_min = 16
- var/safe_oxy_max = 50
- var/safe_co2_max = 10
- var/safe_tox_max = 0.05
- var/SA_para_min = 1
- var/SA_sleep_min = 5
- var/oxygen_used = 0
- var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
-
- var/list/breath_gases = breath.gases
- var/O2_partialpressure = (breath_gases[/datum/gas/oxygen]/breath.total_moles())*breath_pressure
- var/Toxins_partialpressure = (breath_gases[/datum/gas/plasma]/breath.total_moles())*breath_pressure
- var/CO2_partialpressure = (breath_gases[/datum/gas/carbon_dioxide]/breath.total_moles())*breath_pressure
-
-
- //OXYGEN
- if(O2_partialpressure > safe_oxy_max) // Too much Oxygen - blatant CO2 effect copy/pasta
- if(!o2overloadtime)
- o2overloadtime = world.time
- else if(world.time - o2overloadtime > 120)
- Dizzy(10) // better than a minute of you're fucked KO, but certainly a wake up call. Honk.
- adjustOxyLoss(3)
- if(world.time - o2overloadtime > 300)
- adjustOxyLoss(8)
- if(prob(20))
- emote("cough")
- throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
-
- if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
- if(prob(20))
- emote("gasp")
- if(O2_partialpressure > 0)
- var/ratio = 1 - O2_partialpressure/safe_oxy_min
- adjustOxyLoss(min(5*ratio, 3))
- failed_last_breath = 1
- oxygen_used = breath_gases[/datum/gas/oxygen]*ratio
- else
- adjustOxyLoss(3)
- failed_last_breath = 1
- throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
-
- else //Enough oxygen
- failed_last_breath = 0
- o2overloadtime = 0 //reset our counter for this too
- if(health >= crit_threshold)
- adjustOxyLoss(-5)
- oxygen_used = breath_gases[/datum/gas/oxygen]
- clear_alert("not_enough_oxy")
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation")
-
- breath_gases[/datum/gas/oxygen] -= oxygen_used
- breath_gases[/datum/gas/carbon_dioxide] += oxygen_used
-
- //CARBON DIOXIDE
- if(CO2_partialpressure > safe_co2_max)
- if(!co2overloadtime)
- co2overloadtime = world.time
- else if(world.time - co2overloadtime > 120)
- Unconscious(60)
- adjustOxyLoss(3)
- if(world.time - co2overloadtime > 300)
- adjustOxyLoss(8)
- if(prob(20))
- emote("cough")
-
- else
- co2overloadtime = 0
-
- //TOXINS/PLASMA
- if(Toxins_partialpressure > safe_tox_max)
- var/ratio = (breath_gases[/datum/gas/plasma]/safe_tox_max) * 10
- adjustToxLoss(CLAMP(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
- throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
- else
- clear_alert("too_much_tox")
-
- //NITROUS OXIDE
- if(breath_gases[/datum/gas/nitrous_oxide])
- var/SA_partialpressure = (breath_gases[/datum/gas/nitrous_oxide]/breath.total_moles())*breath_pressure
- if(SA_partialpressure > SA_para_min)
- Unconscious(60)
- if(SA_partialpressure > SA_sleep_min)
- Sleeping(max(AmountSleeping() + 40, 200))
- else if(SA_partialpressure > 0.01)
- if(prob(20))
- emote(pick("giggle","laugh"))
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria)
- else
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
-
- //BZ (Facepunch port of their Agent B)
- if(breath_gases[/datum/gas/bz])
- var/bz_partialpressure = (breath_gases[/datum/gas/bz]/breath.total_moles())*breath_pressure
- if(bz_partialpressure > 1)
- hallucination += 10
- else if(bz_partialpressure > 0.01)
- hallucination += 5
-
- //TRITIUM
- if(breath_gases[/datum/gas/tritium])
- var/tritium_partialpressure = (breath_gases[/datum/gas/tritium]/breath.total_moles())*breath_pressure
- radiation += tritium_partialpressure/10
-
- //NITRYL
- if(breath_gases[/datum/gas/nitryl])
- var/nitryl_partialpressure = (breath_gases[/datum/gas/nitryl]/breath.total_moles())*breath_pressure
- adjustFireLoss(nitryl_partialpressure/4)
-
- //MIASMA
- if(breath_gases[/datum/gas/miasma])
- var/miasma_partialpressure = (breath_gases[/datum/gas/miasma]/breath.total_moles())*breath_pressure
- if(miasma_partialpressure > MINIMUM_MOLES_DELTA_TO_MOVE)
-
- if(prob(0.05 * miasma_partialpressure))
- var/datum/disease/advance/miasma_disease = new /datum/disease/advance/random(2,3)
- miasma_disease.name = "Unknown"
- ForceContractDisease(miasma_disease, TRUE, TRUE)
-
- //Miasma side effects
- switch(miasma_partialpressure)
- if(1 to 5)
- // At lower pp, give out a little warning
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
- if(prob(5))
- to_chat(src, "There is an unpleasant smell in the air.")
- if(5 to 20)
- //At somewhat higher pp, warning becomes more obvious
- if(prob(15))
- to_chat(src, "You smell something horribly decayed inside this room.")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/bad_smell)
- if(15 to 30)
- //Small chance to vomit. By now, people have internals on anyway
- if(prob(5))
- to_chat(src, "The stench of rotting carcasses is unbearable!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench)
- vomit()
- if(30 to INFINITY)
- //Higher chance to vomit. Let the horror start
- if(prob(25))
- to_chat(src, "The stench of rotting carcasses is unbearable!")
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench)
- vomit()
- else
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
-
-
- //Clear all moods if no miasma at all
- else
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
-
-
-
-
- GAS_GARBAGE_COLLECT(breath.gases)
-
- //BREATH TEMPERATURE
- handle_breath_temperature(breath)
-
- return 1
-
-//Fourth and final link in a breath chain
-/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
- return
-
-/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
- var/obj/item/clothing/check
- var/internals = FALSE
-
- for(check in GET_INTERNAL_SLOTS(src))
- if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS))
- internals = TRUE
- if(internal)
- if(internal.loc != src)
- internal = null
- update_internals_hud_icon(0)
- else if (!internals && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
- internal = null
- update_internals_hud_icon(0)
- else
- update_internals_hud_icon(1)
- . = internal.remove_air_volume(volume_needed)
- if(!.)
- return FALSE //to differentiate between no internals and active, but empty internals
-
-// Make corpses rot, emitting miasma
-/mob/living/carbon/proc/rot()
- // Properly stored corpses shouldn't create miasma
- if(istype(loc, /obj/structure/closet/crate/coffin)|| istype(loc, /obj/structure/closet/body_bag) || istype(loc, /obj/structure/bodycontainer))
- return
-
- // No decay if formaldehyde in corpse or when the corpse is charred
- if(reagents.has_reagent("formaldehyde", 15) || HAS_TRAIT(src, TRAIT_HUSK))
- return
-
- // Also no decay if corpse chilled or not organic/undead
- if(bodytemperature <= T0C-10 || (!(MOB_ORGANIC in mob_biotypes) && !(MOB_UNDEAD in mob_biotypes)))
- return
-
- // Wait a bit before decaying
- if(world.time - timeofdeath < 1200)
- return
-
- var/deceasedturf = get_turf(src)
-
- // Closed turfs don't have any air in them, so no gas building up
- if(!istype(deceasedturf,/turf/open))
- return
-
- var/turf/open/miasma_turf = deceasedturf
-
- var/list/cached_gases = miasma_turf.air.gases
-
- cached_gases[/datum/gas/miasma] += 0.1
-
-/mob/living/carbon/proc/handle_blood()
- return
-
-/mob/living/carbon/proc/handle_bodyparts()
- for(var/I in bodyparts)
- var/obj/item/bodypart/BP = I
- if(BP.needs_processing)
- . |= BP.on_life()
-
-/mob/living/carbon/proc/handle_organs()
- if(stat != DEAD)
- for(var/V in internal_organs)
- var/obj/item/organ/O = V
- if(O)
- O.on_life()
- else
- if(reagents.has_reagent("formaldehyde", 1)) // No organ decay if the body contains formaldehyde.
- return
- for(var/V in internal_organs)
- var/obj/item/organ/O = V
- if(O)
- O.on_death() //Needed so organs decay while inside the body.
-
-
-
-/mob/living/carbon/handle_diseases()
- for(var/thing in diseases)
- var/datum/disease/D = thing
- if(prob(D.infectivity))
- D.spread()
-
- if(stat != DEAD || D.process_dead)
- D.stage_act()
-
-//todo generalize this and move hud out
-/mob/living/carbon/proc/handle_changeling()
- if(mind && hud_used && hud_used.lingchemdisplay)
- var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling)
- changeling.regenerate()
- hud_used.lingchemdisplay.invisibility = 0
- hud_used.lingchemdisplay.maptext = "
[round(changeling.chem_charges)]
"
- else
- hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
-
-
-/mob/living/carbon/handle_mutations_and_radiation()
- if(dna && dna.temporary_mutations.len)
- for(var/mut in dna.temporary_mutations)
- if(dna.temporary_mutations[mut] < world.time)
- if(mut == UI_CHANGED)
- if(dna.previous["UI"])
- dna.uni_identity = merge_text(dna.uni_identity,dna.previous["UI"])
- updateappearance(mutations_overlay_update=1)
- dna.previous.Remove("UI")
- dna.temporary_mutations.Remove(mut)
- continue
- if(mut == UE_CHANGED)
- if(dna.previous["name"])
- real_name = dna.previous["name"]
- name = real_name
- dna.previous.Remove("name")
- if(dna.previous["UE"])
- dna.unique_enzymes = dna.previous["UE"]
- dna.previous.Remove("UE")
- if(dna.previous["blood_type"])
- dna.blood_type = dna.previous["blood_type"]
- dna.previous.Remove("blood_type")
- dna.temporary_mutations.Remove(mut)
- continue
- for(var/datum/mutation/human/HM in dna.mutations)
- if(HM && HM.timed)
- dna.remove_mutation(HM.type)
-
- radiation -= min(radiation, RAD_LOSS_PER_TICK)
- if(radiation > RAD_MOB_SAFE)
- adjustToxLoss(log(radiation-RAD_MOB_SAFE)*RAD_TOX_COEFFICIENT)
-
-/mob/living/carbon/handle_stomach()
- set waitfor = 0
- for(var/mob/living/M in stomach_contents)
- if(M.loc != src)
- stomach_contents.Remove(M)
- continue
- if(iscarbon(M) && stat != DEAD)
- if(M.stat == DEAD)
- M.death(1)
- stomach_contents.Remove(M)
- qdel(M)
- continue
- if(SSmobs.times_fired%3==1)
- if(!(M.status_flags & GODMODE))
- M.adjustBruteLoss(5)
- nutrition += 10
-
-
-/*
-Alcohol Poisoning Chart
-Note that all higher effects of alcohol poisoning will inherit effects for smaller amounts (i.e. light poisoning inherts from slight poisoning)
-In addition, severe effects won't always trigger unless the drink is poisonously strong
-All effects don't start immediately, but rather get worse over time; the rate is affected by the imbiber's alcohol tolerance
-
-0: Non-alcoholic
-1-10: Barely classifiable as alcohol - occassional slurring
-11-20: Slight alcohol content - slurring
-21-30: Below average - imbiber begins to look slightly drunk
-31-40: Just below average - no unique effects
-41-50: Average - mild disorientation, imbiber begins to look drunk
-51-60: Just above average - disorientation, vomiting, imbiber begins to look heavily drunk
-61-70: Above average - small chance of blurry vision, imbiber begins to look smashed
-71-80: High alcohol content - blurry vision, imbiber completely shitfaced
-81-90: Extremely high alcohol content - light brain damage, passing out
-91-100: Dangerously toxic - swift death
-*/
-#define BALLMER_POINTS 5
-GLOBAL_LIST_INIT(ballmer_good_msg, list("Hey guys, what if we rolled out a bluespace wiring system so mice can't destroy the powergrid anymore?",
- "Hear me out here. What if, and this is just a theory, we made R&D controllable from our PDAs?",
- "I'm thinking we should roll out a git repository for our research under the AGPLv3 license so that we can share it among the other stations freely.",
- "I dunno about you guys, but IDs and PDAs being separate is clunky as fuck. Maybe we should merge them into a chip in our arms? That way they can't be stolen easily.",
- "Why the fuck aren't we just making every pair of shoes into galoshes? We have the technology."))
-GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put a webserver that's automatically turned on with default admin passwords into every PDA?",
- "So like, you know how we separate our codebase from the master copy that runs on our consumer boxes? What if we merged the two and undid the separation between codebase and server?",
- "Dude, radical idea: H.O.N.K mechs but with no bananium required.",
- "Best idea ever: Disposal pipes instead of hallways."))
-
-//this updates all special effects: stun, sleeping, knockdown, druggy, stuttering, etc..
-/mob/living/carbon/handle_status_effects()
- ..()
- if(getStaminaLoss() && !combatmode)//CIT CHANGE - prevents stamina regen while combat mode is active
- adjustStaminaLoss(resting ? (recoveringstam ? -7.5 : -3) : -1.5)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke
-
- if(!recoveringstam && incomingstammult != 1)
- incomingstammult = max(0.01, incomingstammult)
- incomingstammult = min(1, incomingstammult*2)
-
- //CIT CHANGES START HERE. STAMINA BUFFER STUFF
- if(bufferedstam && world.time > stambufferregentime)
- var/drainrate = max((bufferedstam*(bufferedstam/(5)))*0.1,1)
- bufferedstam = max(bufferedstam - drainrate, 0)
- adjustStaminaLoss(drainrate*0.5)
- //END OF CIT CHANGES
-
- var/restingpwr = 1 + 4 * resting
-
- //Dizziness
- if(dizziness)
- var/client/C = client
- var/pixel_x_diff = 0
- var/pixel_y_diff = 0
- var/temp
- var/saved_dizz = dizziness
- if(C)
- var/oldsrc = src
- var/amplitude = dizziness*(sin(dizziness * world.time) + 1) // This shit is annoying at high strength
- src = null
- spawn(0)
- if(C)
- temp = amplitude * sin(saved_dizz * world.time)
- pixel_x_diff += temp
- C.pixel_x += temp
- temp = amplitude * cos(saved_dizz * world.time)
- pixel_y_diff += temp
- C.pixel_y += temp
- sleep(3)
- if(C)
- temp = amplitude * sin(saved_dizz * world.time)
- pixel_x_diff += temp
- C.pixel_x += temp
- temp = amplitude * cos(saved_dizz * world.time)
- pixel_y_diff += temp
- C.pixel_y += temp
- sleep(3)
- if(C)
- C.pixel_x -= pixel_x_diff
- C.pixel_y -= pixel_y_diff
- src = oldsrc
- dizziness = max(dizziness - restingpwr, 0)
-
- if(drowsyness)
- drowsyness = max(drowsyness - restingpwr, 0)
- blur_eyes(2)
- if(prob(5))
- AdjustSleeping(20)
- Unconscious(100)
-
- //Jitteriness
- if(jitteriness)
- do_jitter_animation(jitteriness)
- jitteriness = max(jitteriness - restingpwr, 0)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "jittery", /datum/mood_event/jittery)
- else
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "jittery")
-
- if(stuttering)
- stuttering = max(stuttering-1, 0)
-
- if(slurring || drunkenness)
- slurring = max(slurring-1,0,drunkenness)
-
- if(cultslurring)
- cultslurring = max(cultslurring-1, 0)
-
- if(silent)
- silent = max(silent-1, 0)
-
- if(druggy)
- adjust_drugginess(-1)
-
- if(hallucination)
- handle_hallucinations()
-
- if(drunkenness)
- drunkenness = max(drunkenness - (drunkenness * 0.04), 0)
- if(drunkenness >= 6)
- SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "drunk", /datum/mood_event/drunk)
- jitteriness = max(jitteriness - 3, 0)
- if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING))
- adjustBruteLoss(-0.12, FALSE)
- adjustFireLoss(-0.06, FALSE)
-
- if(mind && (mind.assigned_role == "Scientist" || mind.assigned_role == "Research Director"))
- if(SSresearch.science_tech)
- if(drunkenness >= 12.9 && drunkenness <= 13.8)
- drunkenness = round(drunkenness, 0.01)
- var/ballmer_percent = 0
- if(drunkenness == 13.35) // why run math if I dont have to
- ballmer_percent = 1
- else
- ballmer_percent = (-abs(drunkenness - 13.35) / 0.9) + 1
- if(prob(5))
- say(pick(GLOB.ballmer_good_msg), forced = "ballmer")
- SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = BALLMER_POINTS * ballmer_percent))
- if(drunkenness > 26) // by this point you're into windows ME territory
- if(prob(5))
- SSresearch.science_tech.remove_point_list(list(TECHWEB_POINT_TYPE_GENERIC = BALLMER_POINTS))
- say(pick(GLOB.ballmer_windows_me_msg), forced = "ballmer")
-
- if(drunkenness >= 41)
- if(prob(25))
- confused += 2
- Dizzy(10)
- if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING)) // effects stack with lower tiers
- adjustBruteLoss(-0.3, FALSE)
- adjustFireLoss(-0.15, FALSE)
-
- if(drunkenness >= 51)
- if(prob(5))
- confused += 10
- vomit()
- Dizzy(25)
-
- if(drunkenness >= 61)
- if(prob(50))
- blur_eyes(5)
- if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING))
- adjustBruteLoss(-0.4, FALSE)
- adjustFireLoss(-0.2, FALSE)
-
- if(drunkenness >= 71)
- blur_eyes(5)
-
- if(drunkenness >= 81)
- adjustToxLoss(0.2)
- if(prob(5) && !stat)
- to_chat(src, "Maybe you should lie down for a bit...")
-
- if(drunkenness >= 91)
- adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.4, 60)
- if(prob(20) && !stat)
- if(SSshuttle.emergency.mode == SHUTTLE_DOCKED && is_station_level(z)) //QoL mainly
- to_chat(src, "You're so tired... but you can't miss that shuttle...")
- else
- to_chat(src, "Just a quick nap...")
- Sleeping(900)
-
- if(drunkenness >= 101)
- adjustToxLoss(4) //Let's be honest you shouldn't be alive by now
- else
- SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk")
-
-//used in human and monkey handle_environment()
-/mob/living/carbon/proc/natural_bodytemperature_stabilization()
- if (HAS_TRAIT(src, TRAIT_COLDBLOODED))
- return 0 //Return 0 as your natural temperature. Species proc handle_environment() will adjust your temperature based on this.
-
- var/body_temperature_difference = BODYTEMP_NORMAL - bodytemperature
- switch(bodytemperature)
- if(-INFINITY to BODYTEMP_COLD_DAMAGE_LIMIT) //Cold damage limit is 50 below the default, the temperature where you start to feel effects.
- return max((body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
- if(BODYTEMP_COLD_DAMAGE_LIMIT to BODYTEMP_NORMAL)
- return max(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, min(body_temperature_difference, BODYTEMP_AUTORECOVERY_MINIMUM/4))
- if(BODYTEMP_NORMAL to BODYTEMP_HEAT_DAMAGE_LIMIT) // Heat damage limit is 50 above the default, the temperature where you start to feel effects.
- return min(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, max(body_temperature_difference, -BODYTEMP_AUTORECOVERY_MINIMUM/4))
- if(BODYTEMP_HEAT_DAMAGE_LIMIT to INFINITY)
- return min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers
-/////////
-//LIVER//
-/////////
-
-/mob/living/carbon/proc/handle_liver()
- var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
- if((!dna && !liver) || (NOLIVER in dna.species.species_traits))
- return
- if(liver)
- if(liver.damage < liver.maxHealth)
- liver.organ_flags |= ORGAN_FAILING
- liver_failure()
- else
- liver_failure()
-
-/mob/living/carbon/proc/undergoing_liver_failure()
- var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
- if(liver && liver.failing)
- return TRUE
-
-/mob/living/carbon/proc/return_liver_damage()
- var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
- if(liver)
- return liver.damage
-
-/mob/living/carbon/proc/applyLiverDamage(var/d)
- var/obj/item/organ/liver/L = getorganslot(ORGAN_SLOT_LIVER)
- if(L)
- L.damage += d
-
-/mob/living/carbon/proc/liver_failure()
- reagents.end_metabolization(src, keep_liverless = TRUE) //Stops trait-based effects on reagents, to prevent permanent buffs
- reagents.metabolize(src, can_overdose=FALSE, liverless = TRUE)
- if(HAS_TRAIT(src, TRAIT_STABLEHEART))
- return
- adjustToxLoss(4, TRUE, TRUE)
- if(prob(30))
- to_chat(src, "You feel a stabbing pain in your abdomen!")
-
-
-////////////////
-//BRAIN DAMAGE//
-////////////////
-
-/mob/living/carbon/proc/handle_brain_damage()
- for(var/T in get_traumas())
- var/datum/brain_trauma/BT = T
- BT.on_life()
-
-/////////////////////////////////////
-//MONKEYS WITH TOO MUCH CHOLOESTROL//
-/////////////////////////////////////
-
-/mob/living/carbon/proc/can_heartattack()
- if(!needs_heart())
- return FALSE
- var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
- if(!heart || (heart.organ_flags & ORGAN_SYNTHETIC))
- return FALSE
- return TRUE
-
-/mob/living/carbon/proc/needs_heart()
- if(HAS_TRAIT(src, TRAIT_STABLEHEART))
- return FALSE
- if(dna && dna.species && (NOBLOOD in dna.species.species_traits)) //not all carbons have species!
- return FALSE
- return TRUE
-
-/mob/living/carbon/proc/undergoing_cardiac_arrest()
- var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
- if(istype(heart) && heart.beating)
- return FALSE
- else if(!needs_heart())
- return FALSE
- return TRUE
-
-/mob/living/carbon/proc/set_heartattack(status)
- if(!can_heartattack())
- return FALSE
-
- var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
- if(!istype(heart))
- return
-
- heart.beating = !status
+/mob/living/carbon/Life()
+ set invisibility = 0
+
+ //Hyper Change
+ if(size_multiplier != previous_size)
+ sleep(1)
+ resize(size_multiplier)
+
+ if(notransform)
+ return
+
+ if(damageoverlaytemp)
+ damageoverlaytemp = 0
+ update_damage_hud()
+
+
+ if(!IsInStasis())
+ //Reagent processing needs to come before breathing, to prevent edge cases.
+ handle_organs()
+
+ . = ..()
+
+ if (QDELETED(src))
+ return
+
+ if(.) //not dead
+ handle_blood()
+
+ if(stat != DEAD)
+ var/bprv = handle_bodyparts()
+ if(bprv & BODYPART_LIFE_UPDATE_HEALTH)
+ updatehealth()
+ update_stamina()
+
+ if(stat != DEAD)
+ handle_brain_damage()
+/* Bug cause?
+ if(stat != DEAD)
+ handle_liver()
+*/
+ if(stat == DEAD)
+ stop_sound_channel(CHANNEL_HEARTBEAT)
+ handle_death()
+ rot()
+
+ //Updates the number of stored chemicals for powers
+ handle_changeling()
+
+ if(stat != DEAD)
+ return 1
+
+//Procs called while dead
+/mob/living/carbon/proc/handle_death()
+ for(var/datum/reagent/R in reagents.reagent_list)
+ if(R.chemical_flags & REAGENT_DEAD_PROCESS)
+ R.on_mob_dead(src)
+
+///////////////
+// BREATHING //
+///////////////
+
+//Start of a breath chain, calls breathe()
+/mob/living/carbon/handle_breathing(times_fired)
+ var/next_breath = 4
+ var/obj/item/organ/lungs/L = getorganslot(ORGAN_SLOT_LUNGS)
+ var/obj/item/organ/heart/H = getorganslot(ORGAN_SLOT_HEART)
+ if(L)
+ if(L.damage > L.high_threshold)
+ next_breath--
+ if(H)
+ if(H.damage > H.high_threshold)
+ next_breath--
+
+ if((times_fired % next_breath) == 0 || failed_last_breath)
+ breathe() //Breathe per 4 ticks if healthy, down to 2 if our lungs or heart are damaged, unless suffocating
+ if(failed_last_breath)
+ var/mob/living/carbon/human/B = src
+ if(HAS_TRAIT(B, TRAIT_CHOKE_SLUT))
+ B.adjustArousalLoss(7)
+ if (B.getArousalLoss() >= 100 && ishuman(B) && B.has_dna())
+ B.mob_climax(forced_climax=TRUE)
+ else
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation")
+ else
+ if(istype(loc, /obj/))
+ var/obj/location_as_object = loc
+ location_as_object.handle_internal_lifeform(src,0)
+
+//Second link in a breath chain, calls check_breath()
+/mob/living/carbon/proc/breathe()
+ var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS)
+ if(reagents.has_reagent(/datum/reagent/toxin/lexorin))
+ return
+ if(istype(loc, /obj/machinery/atmospherics/components/unary/cryo_cell))
+ return
+ if(istype(loc, /obj/item/dogborg/sleeper))
+ return
+ if(ismob(loc))
+ return
+ if(isbelly(loc))
+ return
+
+ var/datum/gas_mixture/environment
+ if(loc)
+ environment = loc.return_air()
+
+ var/datum/gas_mixture/breath
+
+ if(!getorganslot(ORGAN_SLOT_BREATHING_TUBE))
+ if(health <= HEALTH_THRESHOLD_FULLCRIT || (pulledby && pulledby.grab_state >= GRAB_KILL) || lungs.organ_flags & ORGAN_FAILING)
+ losebreath++ //You can't breath at all when in critical or when being choked, so you're going to miss a breath
+
+ else if(health <= crit_threshold)
+ losebreath += 0.25 //You're having trouble breathing in soft crit, so you'll miss a breath one in four times
+
+ //Suffocate
+ if(losebreath >= 1) //You've missed a breath, take oxy damage
+ losebreath--
+ if(prob(10))
+ emote("gasp")
+ if(istype(loc, /obj/))
+ var/obj/loc_as_obj = loc
+ loc_as_obj.handle_internal_lifeform(src,0)
+ else
+ //Breathe from internal
+ breath = get_breath_from_internal(BREATH_VOLUME)
+
+ if(isnull(breath)) //in case of 0 pressure internals
+
+ if(isobj(loc)) //Breathe from loc as object
+ var/obj/loc_as_obj = loc
+ breath = loc_as_obj.handle_internal_lifeform(src, BREATH_VOLUME)
+
+ else if(isturf(loc)) //Breathe from loc as turf
+ var/breath_moles = 0
+ if(environment)
+ breath_moles = environment.total_moles()*BREATH_PERCENTAGE
+
+ breath = loc.remove_air(breath_moles)
+ else //Breathe from loc as obj again
+ if(istype(loc, /obj/))
+ var/obj/loc_as_obj = loc
+ loc_as_obj.handle_internal_lifeform(src,0)
+
+ check_breath(breath)
+
+ if(breath)
+ loc.assume_air(breath)
+ air_update_turf()
+
+/mob/living/carbon/proc/has_smoke_protection()
+ if(HAS_TRAIT(src, TRAIT_NOBREATH))
+ return TRUE
+ return FALSE
+
+
+//Third link in a breath chain, calls handle_breath_temperature()
+/mob/living/carbon/proc/check_breath(datum/gas_mixture/breath)
+ if((status_flags & GODMODE))
+ return
+
+ var/obj/item/organ/lungs = getorganslot(ORGAN_SLOT_LUNGS)
+ if(!lungs)
+ adjustOxyLoss(2)
+
+ //CRIT
+ if(!breath || (breath.total_moles() == 0) || !lungs)
+ if(reagents.has_reagent(/datum/reagent/medicine/epinephrine) && lungs)
+ return
+ adjustOxyLoss(1)
+
+ failed_last_breath = 1
+ throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
+ return 0
+
+ var/safe_oxy_min = 16
+ var/safe_oxy_max = 50
+ var/safe_co2_max = 10
+ var/safe_tox_max = 0.05
+ var/SA_para_min = 1
+ var/SA_sleep_min = 5
+ var/oxygen_used = 0
+ var/breath_pressure = (breath.total_moles()*R_IDEAL_GAS_EQUATION*breath.temperature)/BREATH_VOLUME
+
+ var/list/breath_gases = breath.gases
+ var/O2_partialpressure = (breath_gases[/datum/gas/oxygen]/breath.total_moles())*breath_pressure
+ var/Toxins_partialpressure = (breath_gases[/datum/gas/plasma]/breath.total_moles())*breath_pressure
+ var/CO2_partialpressure = (breath_gases[/datum/gas/carbon_dioxide]/breath.total_moles())*breath_pressure
+
+
+ //OXYGEN
+ if(O2_partialpressure > safe_oxy_max) // Too much Oxygen - blatant CO2 effect copy/pasta
+ if(!o2overloadtime)
+ o2overloadtime = world.time
+ else if(world.time - o2overloadtime > 120)
+ Dizzy(10) // better than a minute of you're fucked KO, but certainly a wake up call. Honk.
+ adjustOxyLoss(3)
+ if(world.time - o2overloadtime > 300)
+ adjustOxyLoss(8)
+ if(prob(20))
+ emote("cough")
+ throw_alert("too_much_oxy", /obj/screen/alert/too_much_oxy)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
+
+ if(O2_partialpressure < safe_oxy_min) //Not enough oxygen
+ if(prob(20))
+ emote("gasp")
+ if(O2_partialpressure > 0)
+ var/ratio = 1 - O2_partialpressure/safe_oxy_min
+ adjustOxyLoss(min(5*ratio, 3))
+ failed_last_breath = 1
+ oxygen_used = breath_gases[/datum/gas/oxygen]*ratio
+ else
+ adjustOxyLoss(3)
+ failed_last_breath = 1
+ throw_alert("not_enough_oxy", /obj/screen/alert/not_enough_oxy)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "suffocation", /datum/mood_event/suffocation)
+
+ else //Enough oxygen
+ failed_last_breath = 0
+ o2overloadtime = 0 //reset our counter for this too
+ if(health >= crit_threshold)
+ adjustOxyLoss(-5)
+ oxygen_used = breath_gases[/datum/gas/oxygen]
+ clear_alert("not_enough_oxy")
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "suffocation")
+
+ breath_gases[/datum/gas/oxygen] -= oxygen_used
+ breath_gases[/datum/gas/carbon_dioxide] += oxygen_used
+
+ //CARBON DIOXIDE
+ if(CO2_partialpressure > safe_co2_max)
+ if(!co2overloadtime)
+ co2overloadtime = world.time
+ else if(world.time - co2overloadtime > 120)
+ Unconscious(60)
+ adjustOxyLoss(3)
+ if(world.time - co2overloadtime > 300)
+ adjustOxyLoss(8)
+ if(prob(20))
+ emote("cough")
+
+ else
+ co2overloadtime = 0
+
+ //TOXINS/PLASMA
+ if(Toxins_partialpressure > safe_tox_max)
+ var/ratio = (breath_gases[/datum/gas/plasma]/safe_tox_max) * 10
+ adjustToxLoss(CLAMP(ratio, MIN_TOXIC_GAS_DAMAGE, MAX_TOXIC_GAS_DAMAGE))
+ throw_alert("too_much_tox", /obj/screen/alert/too_much_tox)
+ else
+ clear_alert("too_much_tox")
+
+ //NITROUS OXIDE
+ if(breath_gases[/datum/gas/nitrous_oxide])
+ var/SA_partialpressure = (breath_gases[/datum/gas/nitrous_oxide]/breath.total_moles())*breath_pressure
+ if(SA_partialpressure > SA_para_min)
+ Unconscious(60)
+ if(SA_partialpressure > SA_sleep_min)
+ Sleeping(max(AmountSleeping() + 40, 200))
+ else if(SA_partialpressure > 0.01)
+ if(prob(20))
+ emote(pick("giggle","laugh"))
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "chemical_euphoria", /datum/mood_event/chemical_euphoria)
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "chemical_euphoria")
+
+ //BZ (Facepunch port of their Agent B)
+ if(breath_gases[/datum/gas/bz])
+ var/bz_partialpressure = (breath_gases[/datum/gas/bz]/breath.total_moles())*breath_pressure
+ if(bz_partialpressure > 1)
+ hallucination += 10
+ else if(bz_partialpressure > 0.01)
+ hallucination += 5
+
+ //TRITIUM
+ if(breath_gases[/datum/gas/tritium])
+ var/tritium_partialpressure = (breath_gases[/datum/gas/tritium]/breath.total_moles())*breath_pressure
+ radiation += tritium_partialpressure/10
+
+ //NITRYL
+ if(breath_gases[/datum/gas/nitryl])
+ var/nitryl_partialpressure = (breath_gases[/datum/gas/nitryl]/breath.total_moles())*breath_pressure
+ adjustFireLoss(nitryl_partialpressure/4)
+
+ //MIASMA
+ if(breath_gases[/datum/gas/miasma])
+ var/miasma_partialpressure = (breath_gases[/datum/gas/miasma]/breath.total_moles())*breath_pressure
+ if(miasma_partialpressure > MINIMUM_MOLES_DELTA_TO_MOVE)
+
+ if(prob(0.05 * miasma_partialpressure))
+ var/datum/disease/advance/miasma_disease = new /datum/disease/advance/random(2,3)
+ miasma_disease.name = "Unknown"
+ ForceContractDisease(miasma_disease, TRUE, TRUE)
+
+ //Miasma side effects
+ switch(miasma_partialpressure)
+ if(1 to 5)
+ // At lower pp, give out a little warning
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
+ if(prob(5))
+ to_chat(src, "There is an unpleasant smell in the air.")
+ if(5 to 20)
+ //At somewhat higher pp, warning becomes more obvious
+ if(prob(15))
+ to_chat(src, "You smell something horribly decayed inside this room.")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/bad_smell)
+ if(15 to 30)
+ //Small chance to vomit. By now, people have internals on anyway
+ if(prob(5))
+ to_chat(src, "The stench of rotting carcasses is unbearable!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench)
+ vomit()
+ if(30 to INFINITY)
+ //Higher chance to vomit. Let the horror start
+ if(prob(25))
+ to_chat(src, "The stench of rotting carcasses is unbearable!")
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "smell", /datum/mood_event/disgust/nauseating_stench)
+ vomit()
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
+
+
+ //Clear all moods if no miasma at all
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "smell")
+
+
+
+
+ GAS_GARBAGE_COLLECT(breath.gases)
+
+ //BREATH TEMPERATURE
+ handle_breath_temperature(breath)
+
+ return 1
+
+//Fourth and final link in a breath chain
+/mob/living/carbon/proc/handle_breath_temperature(datum/gas_mixture/breath)
+ return
+
+/mob/living/carbon/proc/get_breath_from_internal(volume_needed)
+ var/obj/item/clothing/check
+ var/internals = FALSE
+
+ for(check in GET_INTERNAL_SLOTS(src))
+ if(CHECK_BITFIELD(check.clothing_flags, ALLOWINTERNALS))
+ internals = TRUE
+ if(internal)
+ if(internal.loc != src)
+ internal = null
+ update_internals_hud_icon(0)
+ else if (!internals && !getorganslot(ORGAN_SLOT_BREATHING_TUBE))
+ internal = null
+ update_internals_hud_icon(0)
+ else
+ update_internals_hud_icon(1)
+ . = internal.remove_air_volume(volume_needed)
+ if(!.)
+ return FALSE //to differentiate between no internals and active, but empty internals
+
+// Make corpses rot, emitting miasma
+/mob/living/carbon/proc/rot()
+ // Properly stored corpses shouldn't create miasma
+ if(istype(loc, /obj/structure/closet/crate/coffin)|| istype(loc, /obj/structure/closet/body_bag) || istype(loc, /obj/structure/bodycontainer))
+ return
+
+ // No decay if formaldehyde in corpse or when the corpse is charred
+ if(reagents.has_reagent(/datum/reagent/toxin/formaldehyde, 15) || HAS_TRAIT(src, TRAIT_HUSK))
+ return
+
+ // Also no decay if corpse chilled or not organic/undead
+ if(bodytemperature <= T0C-10 || (!(MOB_ORGANIC in mob_biotypes) && !(MOB_UNDEAD in mob_biotypes)))
+ return
+
+ // Wait a bit before decaying
+ if(world.time - timeofdeath < 1200)
+ return
+
+ var/deceasedturf = get_turf(src)
+
+ // Closed turfs don't have any air in them, so no gas building up
+ if(!istype(deceasedturf,/turf/open))
+ return
+
+ var/turf/open/miasma_turf = deceasedturf
+
+ var/list/cached_gases = miasma_turf.air.gases
+
+ cached_gases[/datum/gas/miasma] += 0.1
+
+/mob/living/carbon/proc/handle_blood()
+ return
+
+/mob/living/carbon/proc/handle_bodyparts()
+ for(var/I in bodyparts)
+ var/obj/item/bodypart/BP = I
+ if(BP.needs_processing)
+ . |= BP.on_life()
+
+/mob/living/carbon/proc/handle_organs()
+ if(stat != DEAD)
+ for(var/V in internal_organs)
+ var/obj/item/organ/O = V
+ if(O)
+ O.on_life()
+ else
+ if(reagents.has_reagent("formaldehyde", 1)) // No organ decay if the body contains formaldehyde.
+ return
+ for(var/V in internal_organs)
+ var/obj/item/organ/O = V
+ if(O)
+ O.on_death() //Needed so organs decay while inside the body.
+
+
+
+/mob/living/carbon/handle_diseases()
+ for(var/thing in diseases)
+ var/datum/disease/D = thing
+ if(prob(D.infectivity))
+ D.spread()
+
+ if(stat != DEAD || D.process_dead)
+ D.stage_act()
+
+//todo generalize this and move hud out
+/mob/living/carbon/proc/handle_changeling()
+ if(mind && hud_used && hud_used.lingchemdisplay)
+ var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling)
+ changeling.regenerate()
+ hud_used.lingchemdisplay.invisibility = 0
+ hud_used.lingchemdisplay.maptext = "
[round(changeling.chem_charges)]
"
+ else
+ hud_used.lingchemdisplay.invisibility = INVISIBILITY_ABSTRACT
+
+
+/mob/living/carbon/handle_mutations_and_radiation()
+ if(dna && dna.temporary_mutations.len)
+ for(var/mut in dna.temporary_mutations)
+ if(dna.temporary_mutations[mut] < world.time)
+ if(mut == UI_CHANGED)
+ if(dna.previous["UI"])
+ dna.uni_identity = merge_text(dna.uni_identity,dna.previous["UI"])
+ updateappearance(mutations_overlay_update=1)
+ dna.previous.Remove("UI")
+ dna.temporary_mutations.Remove(mut)
+ continue
+ if(mut == UE_CHANGED)
+ if(dna.previous["name"])
+ real_name = dna.previous["name"]
+ name = real_name
+ dna.previous.Remove("name")
+ if(dna.previous["UE"])
+ dna.unique_enzymes = dna.previous["UE"]
+ dna.previous.Remove("UE")
+ if(dna.previous["blood_type"])
+ dna.blood_type = dna.previous["blood_type"]
+ dna.previous.Remove("blood_type")
+ dna.temporary_mutations.Remove(mut)
+ continue
+ for(var/datum/mutation/human/HM in dna.mutations)
+ if(HM && HM.timed)
+ dna.remove_mutation(HM.type)
+
+ radiation -= min(radiation, RAD_LOSS_PER_TICK)
+ if(radiation > RAD_MOB_SAFE)
+ adjustToxLoss(log(radiation-RAD_MOB_SAFE)*RAD_TOX_COEFFICIENT)
+
+/mob/living/carbon/handle_stomach()
+ set waitfor = 0
+ for(var/mob/living/M in stomach_contents)
+ if(M.loc != src)
+ stomach_contents.Remove(M)
+ continue
+ if(iscarbon(M) && stat != DEAD)
+ if(M.stat == DEAD)
+ M.death(1)
+ stomach_contents.Remove(M)
+ qdel(M)
+ continue
+ if(SSmobs.times_fired%3==1)
+ if(!(M.status_flags & GODMODE))
+ M.adjustBruteLoss(5)
+ nutrition += 10
+
+
+/*
+Alcohol Poisoning Chart
+Note that all higher effects of alcohol poisoning will inherit effects for smaller amounts (i.e. light poisoning inherts from slight poisoning)
+In addition, severe effects won't always trigger unless the drink is poisonously strong
+All effects don't start immediately, but rather get worse over time; the rate is affected by the imbiber's alcohol tolerance
+
+0: Non-alcoholic
+1-10: Barely classifiable as alcohol - occassional slurring
+11-20: Slight alcohol content - slurring
+21-30: Below average - imbiber begins to look slightly drunk
+31-40: Just below average - no unique effects
+41-50: Average - mild disorientation, imbiber begins to look drunk
+51-60: Just above average - disorientation, vomiting, imbiber begins to look heavily drunk
+61-70: Above average - small chance of blurry vision, imbiber begins to look smashed
+71-80: High alcohol content - blurry vision, imbiber completely shitfaced
+81-90: Extremely high alcohol content - light brain damage, passing out
+91-100: Dangerously toxic - swift death
+*/
+#define BALLMER_POINTS 5
+GLOBAL_LIST_INIT(ballmer_good_msg, list("Hey guys, what if we rolled out a bluespace wiring system so mice can't destroy the powergrid anymore?",
+ "Hear me out here. What if, and this is just a theory, we made R&D controllable from our PDAs?",
+ "I'm thinking we should roll out a git repository for our research under the AGPLv3 license so that we can share it among the other stations freely.",
+ "I dunno about you guys, but IDs and PDAs being separate is clunky as fuck. Maybe we should merge them into a chip in our arms? That way they can't be stolen easily.",
+ "Why the fuck aren't we just making every pair of shoes into galoshes? We have the technology."))
+GLOBAL_LIST_INIT(ballmer_windows_me_msg, list("Yo man, what if, we like, uh, put a webserver that's automatically turned on with default admin passwords into every PDA?",
+ "So like, you know how we separate our codebase from the master copy that runs on our consumer boxes? What if we merged the two and undid the separation between codebase and server?",
+ "Dude, radical idea: H.O.N.K mechs but with no bananium required.",
+ "Best idea ever: Disposal pipes instead of hallways."))
+
+//this updates all special effects: stun, sleeping, knockdown, druggy, stuttering, etc..
+/mob/living/carbon/handle_status_effects()
+ ..()
+ if(getStaminaLoss() && !combatmode)//CIT CHANGE - prevents stamina regen while combat mode is active
+ adjustStaminaLoss(resting ? (recoveringstam ? -7.5 : -3) : -1.5)//CIT CHANGE - decreases adjuststaminaloss to stop stamina damage from being such a joke
+
+ if(!recoveringstam && incomingstammult != 1)
+ incomingstammult = max(0.01, incomingstammult)
+ incomingstammult = min(1, incomingstammult*2)
+
+ //CIT CHANGES START HERE. STAMINA BUFFER STUFF
+ if(bufferedstam && world.time > stambufferregentime)
+ var/drainrate = max((bufferedstam*(bufferedstam/(5)))*0.1,1)
+ bufferedstam = max(bufferedstam - drainrate, 0)
+ adjustStaminaLoss(drainrate*0.5)
+ //END OF CIT CHANGES
+
+ var/restingpwr = 1 + 4 * resting
+
+ //Dizziness
+ if(dizziness)
+ var/client/C = client
+ var/pixel_x_diff = 0
+ var/pixel_y_diff = 0
+ var/temp
+ var/saved_dizz = dizziness
+ if(C)
+ var/oldsrc = src
+ var/amplitude = dizziness*(sin(dizziness * world.time) + 1) // This shit is annoying at high strength
+ src = null
+ spawn(0)
+ if(C)
+ temp = amplitude * sin(saved_dizz * world.time)
+ pixel_x_diff += temp
+ C.pixel_x += temp
+ temp = amplitude * cos(saved_dizz * world.time)
+ pixel_y_diff += temp
+ C.pixel_y += temp
+ sleep(3)
+ if(C)
+ temp = amplitude * sin(saved_dizz * world.time)
+ pixel_x_diff += temp
+ C.pixel_x += temp
+ temp = amplitude * cos(saved_dizz * world.time)
+ pixel_y_diff += temp
+ C.pixel_y += temp
+ sleep(3)
+ if(C)
+ C.pixel_x -= pixel_x_diff
+ C.pixel_y -= pixel_y_diff
+ src = oldsrc
+ dizziness = max(dizziness - restingpwr, 0)
+
+ if(drowsyness)
+ drowsyness = max(drowsyness - restingpwr, 0)
+ blur_eyes(2)
+ if(prob(5))
+ AdjustSleeping(20)
+ Unconscious(100)
+
+ //Jitteriness
+ if(jitteriness)
+ do_jitter_animation(jitteriness)
+ jitteriness = max(jitteriness - restingpwr, 0)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "jittery", /datum/mood_event/jittery)
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "jittery")
+
+ if(stuttering)
+ stuttering = max(stuttering-1, 0)
+
+ if(slurring || drunkenness)
+ slurring = max(slurring-1,0,drunkenness)
+
+ if(cultslurring)
+ cultslurring = max(cultslurring-1, 0)
+
+ if(silent)
+ silent = max(silent-1, 0)
+
+ if(druggy)
+ adjust_drugginess(-1)
+
+ if(hallucination)
+ handle_hallucinations()
+
+ if(drunkenness)
+ drunkenness = max(drunkenness - (drunkenness * 0.04), 0)
+ if(drunkenness >= 6)
+ SEND_SIGNAL(src, COMSIG_ADD_MOOD_EVENT, "drunk", /datum/mood_event/drunk)
+ jitteriness = max(jitteriness - 3, 0)
+ if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING))
+ adjustBruteLoss(-0.12, FALSE)
+ adjustFireLoss(-0.06, FALSE)
+
+ if(mind && (mind.assigned_role == "Scientist" || mind.assigned_role == "Research Director"))
+ if(SSresearch.science_tech)
+ if(drunkenness >= 12.9 && drunkenness <= 13.8)
+ drunkenness = round(drunkenness, 0.01)
+ var/ballmer_percent = 0
+ if(drunkenness == 13.35) // why run math if I dont have to
+ ballmer_percent = 1
+ else
+ ballmer_percent = (-abs(drunkenness - 13.35) / 0.9) + 1
+ if(prob(5))
+ say(pick(GLOB.ballmer_good_msg), forced = "ballmer")
+ SSresearch.science_tech.add_point_list(list(TECHWEB_POINT_TYPE_GENERIC = BALLMER_POINTS * ballmer_percent))
+ if(drunkenness > 26) // by this point you're into windows ME territory
+ if(prob(5))
+ SSresearch.science_tech.remove_point_list(list(TECHWEB_POINT_TYPE_GENERIC = BALLMER_POINTS))
+ say(pick(GLOB.ballmer_windows_me_msg), forced = "ballmer")
+
+ if(drunkenness >= 41)
+ if(prob(25))
+ confused += 2
+ Dizzy(10)
+ if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING)) // effects stack with lower tiers
+ adjustBruteLoss(-0.3, FALSE)
+ adjustFireLoss(-0.15, FALSE)
+
+ if(drunkenness >= 51)
+ if(prob(5))
+ confused += 10
+ vomit()
+ Dizzy(25)
+
+ if(drunkenness >= 61)
+ if(prob(50))
+ blur_eyes(5)
+ if(HAS_TRAIT(src, TRAIT_DRUNK_HEALING))
+ adjustBruteLoss(-0.4, FALSE)
+ adjustFireLoss(-0.2, FALSE)
+
+ if(drunkenness >= 71)
+ blur_eyes(5)
+
+ if(drunkenness >= 81)
+ adjustToxLoss(0.2)
+ if(prob(5) && !stat)
+ to_chat(src, "Maybe you should lie down for a bit...")
+
+ if(drunkenness >= 91)
+ adjustOrganLoss(ORGAN_SLOT_BRAIN, 0.4, 60)
+ if(prob(20) && !stat)
+ if(SSshuttle.emergency.mode == SHUTTLE_DOCKED && is_station_level(z)) //QoL mainly
+ to_chat(src, "You're so tired... but you can't miss that shuttle...")
+ else
+ to_chat(src, "Just a quick nap...")
+ Sleeping(900)
+
+ if(drunkenness >= 101)
+ adjustToxLoss(4) //Let's be honest you shouldn't be alive by now
+ else
+ SEND_SIGNAL(src, COMSIG_CLEAR_MOOD_EVENT, "drunk")
+
+//used in human and monkey handle_environment()
+/mob/living/carbon/proc/natural_bodytemperature_stabilization()
+ if (HAS_TRAIT(src, TRAIT_COLDBLOODED))
+ return 0 //Return 0 as your natural temperature. Species proc handle_environment() will adjust your temperature based on this.
+
+ var/body_temperature_difference = BODYTEMP_NORMAL - bodytemperature
+ switch(bodytemperature)
+ if(-INFINITY to BODYTEMP_COLD_DAMAGE_LIMIT) //Cold damage limit is 50 below the default, the temperature where you start to feel effects.
+ return max((body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR), BODYTEMP_AUTORECOVERY_MINIMUM)
+ if(BODYTEMP_COLD_DAMAGE_LIMIT to BODYTEMP_NORMAL)
+ return max(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, min(body_temperature_difference, BODYTEMP_AUTORECOVERY_MINIMUM/4))
+ if(BODYTEMP_NORMAL to BODYTEMP_HEAT_DAMAGE_LIMIT) // Heat damage limit is 50 above the default, the temperature where you start to feel effects.
+ return min(body_temperature_difference * metabolism_efficiency / BODYTEMP_AUTORECOVERY_DIVISOR, max(body_temperature_difference, -BODYTEMP_AUTORECOVERY_MINIMUM/4))
+ if(BODYTEMP_HEAT_DAMAGE_LIMIT to INFINITY)
+ return min((body_temperature_difference / BODYTEMP_AUTORECOVERY_DIVISOR), -BODYTEMP_AUTORECOVERY_MINIMUM) //We're dealing with negative numbers
+/////////
+//LIVER//
+/////////
+
+/mob/living/carbon/proc/handle_liver()
+ var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
+ if((!dna && !liver) || (NOLIVER in dna.species.species_traits))
+ return
+ if(liver)
+ if(liver.damage < liver.maxHealth)
+ liver.organ_flags |= ORGAN_FAILING
+ liver_failure()
+ else
+ liver_failure()
+
+/mob/living/carbon/proc/undergoing_liver_failure()
+ var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
+ if(liver && liver.failing)
+ return TRUE
+
+/mob/living/carbon/proc/return_liver_damage()
+ var/obj/item/organ/liver/liver = getorganslot(ORGAN_SLOT_LIVER)
+ if(liver)
+ return liver.damage
+
+/mob/living/carbon/proc/applyLiverDamage(var/d)
+ var/obj/item/organ/liver/L = getorganslot(ORGAN_SLOT_LIVER)
+ if(L)
+ L.damage += d
+
+/mob/living/carbon/proc/liver_failure()
+ reagents.end_metabolization(src, keep_liverless = TRUE) //Stops trait-based effects on reagents, to prevent permanent buffs
+ reagents.metabolize(src, can_overdose=FALSE, liverless = TRUE)
+ if(HAS_TRAIT(src, TRAIT_STABLEHEART))
+ return
+ adjustToxLoss(4, TRUE, TRUE)
+ if(prob(30))
+ to_chat(src, "You feel a stabbing pain in your abdomen!")
+
+
+////////////////
+//BRAIN DAMAGE//
+////////////////
+
+/mob/living/carbon/proc/handle_brain_damage()
+ for(var/T in get_traumas())
+ var/datum/brain_trauma/BT = T
+ BT.on_life()
+
+/////////////////////////////////////
+//MONKEYS WITH TOO MUCH CHOLOESTROL//
+/////////////////////////////////////
+
+/mob/living/carbon/proc/can_heartattack()
+ if(!needs_heart())
+ return FALSE
+ var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
+ if(!heart || (heart.organ_flags & ORGAN_SYNTHETIC))
+ return FALSE
+ return TRUE
+
+/mob/living/carbon/proc/needs_heart()
+ if(HAS_TRAIT(src, TRAIT_STABLEHEART))
+ return FALSE
+ if(dna && dna.species && (NOBLOOD in dna.species.species_traits)) //not all carbons have species!
+ return FALSE
+ return TRUE
+
+/mob/living/carbon/proc/undergoing_cardiac_arrest()
+ var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
+ if(istype(heart) && heart.beating)
+ return FALSE
+ else if(!needs_heart())
+ return FALSE
+ return TRUE
+
+/mob/living/carbon/proc/set_heartattack(status)
+ if(!can_heartattack())
+ return FALSE
+
+ var/obj/item/organ/heart/heart = getorganslot(ORGAN_SLOT_HEART)
+ if(!istype(heart))
+ return
+
+ heart.beating = !status
diff --git a/code/modules/mob/living/carbon/monkey/monkey.dm b/code/modules/mob/living/carbon/monkey/monkey.dm
index 54fddea2..a287c569 100644
--- a/code/modules/mob/living/carbon/monkey/monkey.dm
+++ b/code/modules/mob/living/carbon/monkey/monkey.dm
@@ -1,175 +1,175 @@
-/mob/living/carbon/monkey
- name = "monkey"
- verb_say = "chimpers"
- initial_language_holder = /datum/language_holder/monkey
- icon = 'icons/mob/monkey.dmi'
- icon_state = ""
- gender = NEUTER
- pass_flags = PASSTABLE
- ventcrawler = VENTCRAWLER_NUDE
- mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
- type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/monkey
- gib_type = /obj/effect/decal/cleanable/blood/gibs
- unique_name = TRUE
- bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
- /obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
- hud_type = /datum/hud/monkey
-
-/mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner)
- verbs += /mob/living/proc/mob_sleep
- verbs += /mob/living/proc/lay_down
-
- if(unique_name) //used to exclude pun pun
- gender = pick(MALE, FEMALE)
- real_name = name
-
- //initialize limbs
- create_bodyparts()
- create_internal_organs()
-
- . = ..()
-
- if (cubespawned)
- var/cap = CONFIG_GET(number/monkeycap)
- if (LAZYLEN(SSmobs.cubemonkeys) > cap)
- if (spawner)
- to_chat(spawner, "Bluespace harmonics prevent the spawning of more than [cap] monkeys on the station at one time!")
- return INITIALIZE_HINT_QDEL
- SSmobs.cubemonkeys += src
-
- create_dna(src)
- dna.initialize_dna(random_blood_type())
-
-/mob/living/carbon/monkey/ComponentInitialize()
- . = ..()
- AddElement(/datum/element/mob_holder, "monkey", null, null, null, SLOT_HEAD)
-
-/mob/living/carbon/monkey/Destroy()
- SSmobs.cubemonkeys -= src
- return ..()
-
-/mob/living/carbon/monkey/create_internal_organs()
- internal_organs += new /obj/item/organ/appendix
- internal_organs += new /obj/item/organ/lungs
- internal_organs += new /obj/item/organ/heart
- internal_organs += new /obj/item/organ/brain
- internal_organs += new /obj/item/organ/tongue
- internal_organs += new /obj/item/organ/eyes
- internal_organs += new /obj/item/organ/ears
- internal_organs += new /obj/item/organ/liver
- internal_organs += new /obj/item/organ/stomach
- ..()
-
-/mob/living/carbon/monkey/on_reagent_change()
- . = ..()
- remove_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE)
- var/amount
- if(reagents.has_reagent("morphine"))
- amount = -1
- if(reagents.has_reagent("nuka_cola"))
- amount = -1
- if(amount)
- add_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
-
-/mob/living/carbon/monkey/updatehealth()
- . = ..()
- var/slow = 0
- var/health_deficiency = (100 - health)
- if(health_deficiency >= 45)
- slow += (health_deficiency / 25)
- add_movespeed_modifier(MOVESPEED_ID_MONKEY_HEALTH_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = slow)
-
-/mob/living/carbon/monkey/adjust_bodytemperature(amount)
- . = ..()
- var/slow = 0
- if (bodytemperature < 283.222)
- slow += (283.222 - bodytemperature) / 10 * 1.75
- if(slow <= 0)
- return
- add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
-
-/mob/living/carbon/monkey/Stat()
- ..()
- if(statpanel("Status"))
- stat(null, "Intent: [a_intent]")
- stat(null, "Move Mode: [m_intent]")
- if(client && mind)
- var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
- if(changeling)
- stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
- stat("Absorbed DNA", changeling.absorbedcount)
- return
-
-
-/mob/living/carbon/monkey/verb/removeinternal()
- set name = "Remove Internals"
- set category = "IC"
- internal = null
- return
-
-
-/mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools
- if(mind && is_monkey(mind))
- return TRUE
- return FALSE
-
-/mob/living/carbon/monkey/reagent_check(datum/reagent/R) //can metabolize all reagents
- return FALSE
-
-/mob/living/carbon/monkey/canBeHandcuffed()
- return TRUE
-
-/mob/living/carbon/monkey/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
- if(judgement_criteria & JUDGE_EMAGGED)
- return 10 //Everyone is a criminal!
-
- var/threatcount = 0
-
- //Securitrons can't identify monkeys
- if( !(judgement_criteria & JUDGE_IGNOREMONKEYS) && (judgement_criteria & JUDGE_IDCHECK) )
- threatcount += 4
-
- //Lasertag bullshit
- if(lasercolor)
- if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
- if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
- threatcount += 4
-
- if(lasercolor == "r")
- if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
- threatcount += 4
-
- return threatcount
-
- //Check for weapons
- if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck )
- for(var/obj/item/I in held_items) //if they're holding a gun
- if(weaponcheck.Invoke(I))
- threatcount += 4
- if(weaponcheck.Invoke(back)) //if a weapon is present in the back slot
- threatcount += 4 //trigger look_for_perp() since they're nonhuman and very likely hostile
-
- //mindshield implants imply trustworthyness
- if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
- threatcount -= 1
-
- return threatcount
-
-/mob/living/carbon/monkey/IsVocal()
- if(!getorganslot(ORGAN_SLOT_LUNGS))
- return 0
- return 1
-
-/mob/living/carbon/monkey/can_use_guns(obj/item/G)
- return TRUE
-
-/mob/living/carbon/monkey/angry
- aggressive = TRUE
-
-/mob/living/carbon/monkey/angry/Initialize()
- . = ..()
- if(prob(10))
- var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
- equip_to_slot_or_del(helmet,SLOT_HEAD)
- helmet.attack_self(src) // todo encapsulate toggle
+/mob/living/carbon/monkey
+ name = "monkey"
+ verb_say = "chimpers"
+ initial_language_holder = /datum/language_holder/monkey
+ icon = 'icons/mob/monkey.dmi'
+ icon_state = ""
+ gender = NEUTER
+ pass_flags = PASSTABLE
+ ventcrawler = VENTCRAWLER_NUDE
+ mob_biotypes = list(MOB_ORGANIC, MOB_HUMANOID)
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/monkey = 5, /obj/item/stack/sheet/animalhide/monkey = 1)
+ type_of_meat = /obj/item/reagent_containers/food/snacks/meat/slab/monkey
+ gib_type = /obj/effect/decal/cleanable/blood/gibs
+ unique_name = TRUE
+ bodyparts = list(/obj/item/bodypart/chest/monkey, /obj/item/bodypart/head/monkey, /obj/item/bodypart/l_arm/monkey,
+ /obj/item/bodypart/r_arm/monkey, /obj/item/bodypart/r_leg/monkey, /obj/item/bodypart/l_leg/monkey)
+ hud_type = /datum/hud/monkey
+
+/mob/living/carbon/monkey/Initialize(mapload, cubespawned=FALSE, mob/spawner)
+ verbs += /mob/living/proc/mob_sleep
+ verbs += /mob/living/proc/lay_down
+
+ if(unique_name) //used to exclude pun pun
+ gender = pick(MALE, FEMALE)
+ real_name = name
+
+ //initialize limbs
+ create_bodyparts()
+ create_internal_organs()
+
+ . = ..()
+
+ if (cubespawned)
+ var/cap = CONFIG_GET(number/monkeycap)
+ if (LAZYLEN(SSmobs.cubemonkeys) > cap)
+ if (spawner)
+ to_chat(spawner, "Bluespace harmonics prevent the spawning of more than [cap] monkeys on the station at one time!")
+ return INITIALIZE_HINT_QDEL
+ SSmobs.cubemonkeys += src
+
+ create_dna(src)
+ dna.initialize_dna(random_blood_type())
+
+/mob/living/carbon/monkey/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/mob_holder, "monkey", null, null, null, SLOT_HEAD)
+
+/mob/living/carbon/monkey/Destroy()
+ SSmobs.cubemonkeys -= src
+ return ..()
+
+/mob/living/carbon/monkey/create_internal_organs()
+ internal_organs += new /obj/item/organ/appendix
+ internal_organs += new /obj/item/organ/lungs
+ internal_organs += new /obj/item/organ/heart
+ internal_organs += new /obj/item/organ/brain
+ internal_organs += new /obj/item/organ/tongue
+ internal_organs += new /obj/item/organ/eyes
+ internal_organs += new /obj/item/organ/ears
+ internal_organs += new /obj/item/organ/liver
+ internal_organs += new /obj/item/organ/stomach
+ ..()
+
+/mob/living/carbon/monkey/on_reagent_change()
+ . = ..()
+ remove_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE)
+ var/amount
+ if(reagents.has_reagent(/datum/reagent/medicine/morphine))
+ amount = -1
+ if(reagents.has_reagent("nuka_cola"))
+ amount = -1
+ if(amount)
+ add_movespeed_modifier(MOVESPEED_ID_MONKEY_REAGENT_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
+
+/mob/living/carbon/monkey/updatehealth()
+ . = ..()
+ var/slow = 0
+ var/health_deficiency = (100 - health)
+ if(health_deficiency >= 45)
+ slow += (health_deficiency / 25)
+ add_movespeed_modifier(MOVESPEED_ID_MONKEY_HEALTH_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = slow)
+
+/mob/living/carbon/monkey/adjust_bodytemperature(amount)
+ . = ..()
+ var/slow = 0
+ if (bodytemperature < 283.222)
+ slow += (283.222 - bodytemperature) / 10 * 1.75
+ if(slow <= 0)
+ return
+ add_movespeed_modifier(MOVESPEED_ID_MONKEY_TEMPERATURE_SPEEDMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
+
+/mob/living/carbon/monkey/Stat()
+ ..()
+ if(statpanel("Status"))
+ stat(null, "Intent: [a_intent]")
+ stat(null, "Move Mode: [m_intent]")
+ if(client && mind)
+ var/datum/antagonist/changeling/changeling = mind.has_antag_datum(/datum/antagonist/changeling)
+ if(changeling)
+ stat("Chemical Storage", "[changeling.chem_charges]/[changeling.chem_storage]")
+ stat("Absorbed DNA", changeling.absorbedcount)
+ return
+
+
+/mob/living/carbon/monkey/verb/removeinternal()
+ set name = "Remove Internals"
+ set category = "IC"
+ internal = null
+ return
+
+
+/mob/living/carbon/monkey/IsAdvancedToolUser()//Unless its monkey mode monkeys cant use advanced tools
+ if(mind && is_monkey(mind))
+ return TRUE
+ return FALSE
+
+/mob/living/carbon/monkey/reagent_check(datum/reagent/R) //can metabolize all reagents
+ return FALSE
+
+/mob/living/carbon/monkey/canBeHandcuffed()
+ return TRUE
+
+/mob/living/carbon/monkey/assess_threat(judgement_criteria, lasercolor = "", datum/callback/weaponcheck=null)
+ if(judgement_criteria & JUDGE_EMAGGED)
+ return 10 //Everyone is a criminal!
+
+ var/threatcount = 0
+
+ //Securitrons can't identify monkeys
+ if( !(judgement_criteria & JUDGE_IGNOREMONKEYS) && (judgement_criteria & JUDGE_IDCHECK) )
+ threatcount += 4
+
+ //Lasertag bullshit
+ if(lasercolor)
+ if(lasercolor == "b")//Lasertag turrets target the opposing team, how great is that? -Sieve
+ if(is_holding_item_of_type(/obj/item/gun/energy/laser/redtag))
+ threatcount += 4
+
+ if(lasercolor == "r")
+ if(is_holding_item_of_type(/obj/item/gun/energy/laser/bluetag))
+ threatcount += 4
+
+ return threatcount
+
+ //Check for weapons
+ if( (judgement_criteria & JUDGE_WEAPONCHECK) && weaponcheck )
+ for(var/obj/item/I in held_items) //if they're holding a gun
+ if(weaponcheck.Invoke(I))
+ threatcount += 4
+ if(weaponcheck.Invoke(back)) //if a weapon is present in the back slot
+ threatcount += 4 //trigger look_for_perp() since they're nonhuman and very likely hostile
+
+ //mindshield implants imply trustworthyness
+ if(HAS_TRAIT(src, TRAIT_MINDSHIELD))
+ threatcount -= 1
+
+ return threatcount
+
+/mob/living/carbon/monkey/IsVocal()
+ if(!getorganslot(ORGAN_SLOT_LUNGS))
+ return 0
+ return 1
+
+/mob/living/carbon/monkey/can_use_guns(obj/item/G)
+ return TRUE
+
+/mob/living/carbon/monkey/angry
+ aggressive = TRUE
+
+/mob/living/carbon/monkey/angry/Initialize()
+ . = ..()
+ if(prob(10))
+ var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src)
+ equip_to_slot_or_del(helmet,SLOT_HEAD)
+ helmet.attack_self(src) // todo encapsulate toggle
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index b315428a..9832e3b2 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -1228,7 +1228,7 @@
clamp_unconscious_to = 0,
clamp_immobility_to = 0,
reset_misc = TRUE,
- healing_chems = list("inaprovaline" = 3, "synaptizine" = 10, "regen_jelly" = 10, "stimulants" = 10),
+ healing_chems = list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/regen_jelly = 10, /datum/reagent/medicine/stimulants = 10),
message = "You feel a surge of energy!",
stamina_buffer_boost = 0, //restores stamina buffer rather than just health
scale_stamina_loss_recovery, //defaults to null. if this is set, restores loss * this stamina. make sure it's a fraction.
@@ -1255,6 +1255,6 @@
updatehealth()
update_stamina()
update_canmove()
- for(var/chem in healing_chems)
- reagents.add_reagent(chem, healing_chems[chem])
+ if(healing_chems)
+ reagents.add_reagent_list(healing_chems)
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 89695cce..71fdf998 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -1,516 +1,516 @@
-
-/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = "Your armor absorbs the blow!", soften_text = "Your armor softens the blow!", armour_penetration, penetrated_text = "Your armor was penetrated!")
- var/armor = getarmor(def_zone, attack_flag)
-
- //the if "armor" check is because this is used for everything on /living, including humans
- if(armor && armour_penetration)
- armor = max(0, armor - armour_penetration)
- if(penetrated_text)
- to_chat(src, "[penetrated_text]")
- else if(armor >= 100)
- if(absorb_text)
- to_chat(src, "[absorb_text]")
- else if(armor > 0)
- if(soften_text)
- to_chat(src, "[soften_text]")
- return armor
-
-
-/mob/living/proc/getarmor(def_zone, type)
- return 0
-
-//this returns the mob's protection against eye damage (number between -1 and 2) from bright lights
-/mob/living/proc/get_eye_protection()
- return 0
-
-//this returns the mob's protection against ear damage (0:no protection; 1: some ear protection; 2: has no ears)
-/mob/living/proc/get_ear_protection()
- return 0
-
-/mob/living/proc/is_mouth_covered(head_only = 0, mask_only = 0)
- return FALSE
-
-/mob/living/proc/is_eyes_covered(check_glasses = 1, check_head = 1, check_mask = 1)
- return FALSE
-
-/mob/living/proc/on_hit(obj/item/projectile/P)
- return
-
-/mob/living/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
- var/block_chance_modifier = round(damage / -3)
- for(var/obj/item/I in held_items)
- if(!istype(I, /obj/item/clothing))
- var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
- if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
- return TRUE
- return FALSE
-
-/mob/living/proc/check_reflect(def_zone) //Reflection checks for anything in your hands, based on the reflection chance of the object(s)
- for(var/obj/item/I in held_items)
- if(I.IsReflect(def_zone))
- return TRUE
- return FALSE
-
-/mob/living/proc/reflect_bullet_check(obj/item/projectile/P, def_zone)
- if(P.is_reflectable && check_reflect(def_zone)) // Checks if you've passed a reflection% check
- visible_message("The [P.name] gets reflected by [src]!", \
- "The [P.name] gets reflected by [src]!")
- // Find a turf near or on the original location to bounce to
- if(P.starting)
- var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
- var/turf/curloc = get_turf(src)
- // redirect the projectile
- P.original = locate(new_x, new_y, P.z)
- P.starting = curloc
- P.firer = src
- P.yo = new_y - curloc.y
- P.xo = new_x - curloc.x
- var/new_angle_s = P.Angle + rand(120,240)
- while(new_angle_s > 180) // Translate to regular projectile degrees
- new_angle_s -= 360
- P.setAngle(new_angle_s)
- return TRUE
- return FALSE
-
-/mob/living/bullet_act(obj/item/projectile/P, def_zone)
- if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
- if(reflect_bullet_check(P, def_zone))
- return -1 // complete projectile permutation
- if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
- P.on_hit(src, 100, def_zone)
- return 2
- var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
- if(!P.nodamage)
- apply_damage(P.damage, P.damage_type, def_zone, armor)
- if(P.dismemberment)
- check_projectile_dismemberment(P, def_zone)
- return P.on_hit(src, armor)
-
-/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
- return 0
-
-/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
- if(throwforce && w_class)
- return CLAMP((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
- else if(w_class)
- return CLAMP(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
- else
- return 0
-
-/mob/living/proc/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
- return FALSE
-
-/mob/living/proc/embed_item(obj/item/I)
- return
-
-/mob/living/proc/can_embed(obj/item/I)
- return FALSE
-
-/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
- var/obj/item/I
- var/throwpower = 30
- if(isitem(AM))
- I = AM
- throwpower = I.throwforce
- if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
- hitpush = FALSE
- skipcatch = TRUE
- blocked = TRUE
- else if(I && I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && can_embed(I, src) && prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && (!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) || incapacitated() || get_active_held_item()))
- embed_item(I)
- hitpush = FALSE
- skipcatch = TRUE //can't catch the now embedded item
- if(I)
- if(!skipcatch && isturf(I.loc) && catch_item(I))
- return TRUE
- var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
- var/dtype = BRUTE
- var/volume = I.get_volume_by_throwforce_and_or_w_class()
- SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, zone)
- dtype = I.damtype
-
- if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
- if (I.throwhitsound) //...and throwhitsound is defined...
- playsound(loc, I.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
- else if(I.hitsound) //Otherwise, if the weapon's hitsound is defined...
- playsound(loc, I.hitsound, volume, 1, -1) //...play the weapon's hitsound.
- else if(!I.throwhitsound) //Otherwise, if throwhitsound isn't defined...
- playsound(loc, 'sound/weapons/genhit.ogg',volume, 1, -1) //...play genhit.ogg.
-
- else if(!I.throwhitsound && I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
- playsound(loc, 'sound/weapons/genhit.ogg', volume, 1, -1)//...play genhit.ogg
- if(!I.throwforce)// Otherwise, if the item's throwforce is 0...
- playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
- if(!blocked)
- visible_message("[src] has been hit by [I].", \
- "[src] has been hit by [I].")
- var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].",I.armour_penetration)
- apply_damage(I.throwforce, dtype, zone, armor)
- if(I.thrownby)
- log_combat(I.thrownby, src, "threw and hit", I)
- else
- return 1
- else
- playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1)
- ..()
-
-
-/mob/living/mech_melee_attack(obj/mecha/M)
- if(M.occupant.a_intent == INTENT_HARM)
- M.do_attack_animation(src)
- if(M.damtype == "brute")
- step_away(src,M,15)
- switch(M.damtype)
- if(BRUTE)
- Unconscious(20)
- take_overall_damage(rand(M.force/2, M.force))
- playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
- if(BURN)
- take_overall_damage(0, rand(M.force/2, M.force))
- playsound(src, 'sound/items/welder.ogg', 50, 1)
- if(TOX)
- M.mech_toxin_damage(src)
- else
- return
- updatehealth()
- visible_message("[M.name] has hit [src]!", \
- "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE)
- log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
- else
- step_away(src,M)
- log_combat(M.occupant, src, "pushed", M)
- visible_message("[M] pushes [src] out of the way.", null, null, 5)
-
-/mob/living/fire_act()
- adjust_fire_stacks(3)
- IgniteMob()
-
-/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE)
- if(user == anchored || !isturf(user.loc))
- return FALSE
-
- //pacifist vore check.
- if(user.pulling && HAS_TRAIT(user, TRAIT_PACIFISM) && user.voremode) //they can only do heals, noisy guts, absorbing (technically not harm)
- if(ismob(user.pulling))
- var/mob/P = user.pulling
- if(src != user)
- to_chat(user, "You can't risk digestion!")
- return FALSE
- else
- user.vore_attack(user, P, user)
- return
-
- //normal vore check.
- if(user.pulling && user.grab_state == GRAB_AGGRESSIVE && user.voremode)
- if(ismob(user.pulling))
- var/mob/P = user.pulling
- user.vore_attack(user, P, src) // User, Pulled, Predator target (which can be user, pulling, or src)
- return
-
- if(user == src) //we want to be able to self click if we're voracious
- return FALSE
-
- if(!user.pulling || user.pulling != src)
- user.start_pulling(src, supress_message = supress_message)
- return
-
- if(!(status_flags & CANPUSH) || HAS_TRAIT(src, TRAIT_PUSHIMMUNE))
- to_chat(user, "[src] can't be grabbed more aggressively!")
- return FALSE
-
- if(HAS_TRAIT(user, TRAIT_PACIFISM))
- to_chat(user, "You don't want to risk hurting [src]!")
- return FALSE
-
- grippedby(user)
-
-//proc to upgrade a simple pull into a more aggressive grab.
-/mob/living/proc/grippedby(mob/living/carbon/user, instant = FALSE)
- if(user.grab_state < GRAB_KILL)
- user.changeNext_move(CLICK_CD_GRABBING)
- playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
-
- if(user.grab_state) //only the first upgrade is instantaneous
- var/old_grab_state = user.grab_state
- var/grab_upgrade_time = instant ? 0 : 30
- visible_message("[user] starts to tighten [user.p_their()] grip on [src]!", \
- "[user] starts to tighten [user.p_their()] grip on you!")
- switch(user.grab_state)
- if(GRAB_AGGRESSIVE)
- log_combat(user, src, "attempted to neck grab", addition="neck grab")
- if(GRAB_NECK)
- log_combat(user, src, "attempted to strangle", addition="kill grab")
- if(!do_mob(user, src, grab_upgrade_time))
- return 0
- if(!user.pulling || user.pulling != src || user.grab_state != old_grab_state || user.a_intent != INTENT_GRAB)
- return 0
- if(user.voremode && user.grab_state == GRAB_AGGRESSIVE)
- return 0
- user.grab_state++
- switch(user.grab_state)
- if(GRAB_AGGRESSIVE)
- log_combat(user, src, "grabbed", addition="aggressive grab")
- visible_message("[user] has grabbed [src] aggressively!", \
- "[user] has grabbed [src] aggressively!")
- drop_all_held_items()
- stop_pulling()
- if(GRAB_NECK)
- log_combat(user, src, "grabbed", addition="neck grab")
- visible_message("[user] has grabbed [src] by the neck!",\
- "[user] has grabbed you by the neck!")
- update_canmove() //we fall down
- if(!buckled && !density)
- Move(user.loc)
- if(GRAB_KILL)
- log_combat(user, src, "strangled", addition="kill grab")
- visible_message("[user] is strangling [src]!", \
- "[user] is strangling you!")
- update_canmove() //we fall down
- if(!buckled && !density)
- Move(user.loc)
- return 1
-
-/mob/living/attack_hand(mob/user)
- ..() //Ignoring parent return value here.
- SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
- if((user != src) && user.a_intent != INTENT_HELP && check_shields(user, 0, user.name, attack_type = UNARMED_ATTACK))
- log_combat(user, src, "attempted to touch")
- visible_message("[user] attempted to touch [src]!")
- return TRUE
-
-/mob/living/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
- if(user.a_intent == INTENT_HARM)
- if(HAS_TRAIT(user, TRAIT_PACIFISM))
- to_chat(user, "You don't want to hurt [src]!")
- return TRUE
- var/hulk_verb = pick("smash","pummel")
- if(user != src && check_shields(user, 15, "the [hulk_verb]ing"))
- return TRUE
- ..()
- return FALSE
-
-/mob/living/attack_slime(mob/living/simple_animal/slime/M)
- if(!SSticker.HasRoundStarted())
- to_chat(M, "You cannot attack people before the game has started.")
- return
-
- if(M.buckled)
- if(M in buckled_mobs)
- M.Feedstop()
- return // can't attack while eating!
-
- if(HAS_TRAIT(src, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
- return FALSE
-
- var/damage = rand(5, 35)
- if(M.is_adult)
- damage = rand(20, 40)
- if(check_shields(M, damage, "the [M.name]"))
- return FALSE
-
- if (stat != DEAD)
- log_combat(M, src, "attacked")
- M.do_attack_animation(src)
- visible_message("The [M.name] glomps [src]!", \
- "The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE)
- return TRUE
-
-/mob/living/attack_animal(mob/living/simple_animal/M)
- M.face_atom(src)
- if(M.melee_damage_upper == 0)
- M.visible_message("\The [M] [M.friendly] [src]!")
- return FALSE
- else
- if(HAS_TRAIT(M, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
- return FALSE
- if(check_shields(M, rand(M.melee_damage_lower, M.melee_damage_upper), "the [M.name]", MELEE_ATTACK, M.armour_penetration))
- return FALSE
- if(M.attack_sound)
- playsound(loc, M.attack_sound, 50, 1, 1)
- M.do_attack_animation(src)
- visible_message("\The [M] [M.attacktext] [src]!", \
- "\The [M] [M.attacktext] [src]!", null, COMBAT_MESSAGE_RANGE)
- log_combat(M, src, "attacked")
- return TRUE
-
-
-/mob/living/attack_paw(mob/living/carbon/monkey/M)
- if (M.a_intent == INTENT_HARM)
- if(HAS_TRAIT(M, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
- return FALSE
-
- if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
- to_chat(M, "You can't bite with your mouth covered!")
- return FALSE
- if(check_shields(M, 0, "the [M.name]"))
- return FALSE
- M.do_attack_animation(src, ATTACK_EFFECT_BITE)
- if (prob(75))
- log_combat(M, src, "attacked")
- playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
- visible_message("[M.name] bites [src]!", \
- "[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
- return TRUE
- else
- visible_message("[M.name] has attempted to bite [src]!", \
- "[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
- return FALSE
-
-/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
- switch(L.a_intent)
- if(INTENT_HELP)
- visible_message("[L.name] rubs its head against [src].")
- return FALSE
-
- else
- if(HAS_TRAIT(L, TRAIT_PACIFISM))
- to_chat(L, "You don't want to hurt anyone!")
- return FALSE
- if(L != src && check_shields(L, rand(1, 3), "the [L.name]"))
- return FALSE
-
- L.do_attack_animation(src)
- if(prob(90))
- log_combat(L, src, "attacked")
- visible_message("[L.name] bites [src]!", \
- "[L.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
- playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
- return TRUE
- else
- visible_message("[L.name] has attempted to bite [src]!", \
- "[L.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
- return FALSE
-
-/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
- if((M != src) && M.a_intent != INTENT_HELP && check_shields(M, 0, "the [M.name]"))
- visible_message("[M] attempted to touch [src]!")
- return FALSE
- switch(M.a_intent)
- if (INTENT_HELP)
- if(!isalien(src)) //I know it's ugly, but the alien vs alien attack_alien behaviour is a bit different.
- visible_message("[M] caresses [src] with its scythe like arm.")
- return FALSE
- if (INTENT_GRAB)
- grabbedby(M)
- return FALSE
- if(INTENT_HARM)
- if(HAS_TRAIT(M, TRAIT_PACIFISM))
- to_chat(M, "You don't want to hurt anyone!")
- return FALSE
- if(!isalien(src))
- M.do_attack_animation(src)
- return TRUE
- if(INTENT_DISARM)
- if(!isalien(src))
- M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
- return TRUE
-
-/mob/living/ex_act(severity, target, origin)
- if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
- return
- ..()
-
-//Looking for irradiate()? It's been moved to radiation.dm under the rad_act() for mobs.
-
-/mob/living/acid_act(acidpwr, acid_volume)
- take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1))
- return 1
-
-/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
- SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage)
- if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
- return FALSE
- if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
- return FALSE
- if(shock_damage > 0)
- if(!illusion)
- adjustFireLoss(shock_damage)
- visible_message(
- "[src] was shocked by \the [source]!", \
- "You feel a powerful shock coursing through your body!", \
- "You hear a heavy electrical crack." \
- )
- return shock_damage
-
-/mob/living/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_CONTENTS)
- return
- for(var/obj/O in contents)
- O.emp_act(severity)
-
-/mob/living/singularity_act()
- var/gain = 20
- investigate_log("([key_name(src)]) has been consumed by the singularity.", INVESTIGATE_SINGULO) //Oh that's where the clown ended up!
- gib()
- return(gain)
-
-/mob/living/narsie_act()
- if(status_flags & GODMODE || QDELETED(src))
- return
-
- if(is_servant_of_ratvar(src) && !stat)
- to_chat(src, "You resist Nar'Sie's influence... but not all of it. Run!")
- adjustBruteLoss(35)
- if(src && reagents)
- reagents.add_reagent("heparin", 5)
- return FALSE
- if(GLOB.cult_narsie && GLOB.cult_narsie.souls_needed[src])
- GLOB.cult_narsie.souls_needed -= src
- GLOB.cult_narsie.souls += 1
- if((GLOB.cult_narsie.souls == GLOB.cult_narsie.soul_goal) && (GLOB.cult_narsie.resolved == FALSE))
- GLOB.cult_narsie.resolved = TRUE
- sound_to_playing_players('sound/machines/alarm.ogg')
- addtimer(CALLBACK(GLOBAL_PROC, .proc/cult_ending_helper, 1), 120)
- addtimer(CALLBACK(GLOBAL_PROC, .proc/ending_helper), 270)
- if(client)
- makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, cultoverride = TRUE)
- else
- switch(rand(1, 6))
- if(1)
- new /mob/living/simple_animal/hostile/construct/armored/hostile(get_turf(src))
- if(2)
- new /mob/living/simple_animal/hostile/construct/wraith/hostile(get_turf(src))
- if(3 to 6)
- new /mob/living/simple_animal/hostile/construct/builder/hostile(get_turf(src))
- spawn_dust()
- gib()
- return TRUE
-
-
-/mob/living/ratvar_act()
- if(status_flags & GODMODE)
- return
- if(stat != DEAD && !is_servant_of_ratvar(src))
- to_chat(src, "A blinding light boils you alive! Run!")
- adjust_fire_stacks(20)
- IgniteMob()
- return FALSE
-
-
-//called when the mob receives a bright flash
-/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
- if(get_eye_protection() < intensity && (override_blindness_check || !(HAS_TRAIT(src, TRAIT_BLIND))))
- overlay_fullscreen("flash", type)
- addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25)
- return TRUE
- return FALSE
-
-//called when the mob receives a loud bang
-/mob/living/proc/soundbang_act()
- return 0
-
-//to damage the clothes worn by a mob
-/mob/living/proc/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
- return
-
-
-/mob/living/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
- if(!used_item)
- used_item = get_active_held_item()
- ..()
- floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
+
+/mob/living/proc/run_armor_check(def_zone = null, attack_flag = "melee", absorb_text = "Your armor absorbs the blow!", soften_text = "Your armor softens the blow!", armour_penetration, penetrated_text = "Your armor was penetrated!")
+ var/armor = getarmor(def_zone, attack_flag)
+
+ //the if "armor" check is because this is used for everything on /living, including humans
+ if(armor && armour_penetration)
+ armor = max(0, armor - armour_penetration)
+ if(penetrated_text)
+ to_chat(src, "[penetrated_text]")
+ else if(armor >= 100)
+ if(absorb_text)
+ to_chat(src, "[absorb_text]")
+ else if(armor > 0)
+ if(soften_text)
+ to_chat(src, "[soften_text]")
+ return armor
+
+
+/mob/living/proc/getarmor(def_zone, type)
+ return 0
+
+//this returns the mob's protection against eye damage (number between -1 and 2) from bright lights
+/mob/living/proc/get_eye_protection()
+ return 0
+
+//this returns the mob's protection against ear damage (0:no protection; 1: some ear protection; 2: has no ears)
+/mob/living/proc/get_ear_protection()
+ return 0
+
+/mob/living/proc/is_mouth_covered(head_only = 0, mask_only = 0)
+ return FALSE
+
+/mob/living/proc/is_eyes_covered(check_glasses = 1, check_head = 1, check_mask = 1)
+ return FALSE
+
+/mob/living/proc/on_hit(obj/item/projectile/P)
+ return
+
+/mob/living/proc/check_shields(atom/AM, damage, attack_text = "the attack", attack_type = MELEE_ATTACK, armour_penetration = 0)
+ var/block_chance_modifier = round(damage / -3)
+ for(var/obj/item/I in held_items)
+ if(!istype(I, /obj/item/clothing))
+ var/final_block_chance = I.block_chance - (CLAMP((armour_penetration-I.armour_penetration)/2,0,100)) + block_chance_modifier //So armour piercing blades can still be parried by other blades, for example
+ if(I.hit_reaction(src, AM, attack_text, final_block_chance, damage, attack_type))
+ return TRUE
+ return FALSE
+
+/mob/living/proc/check_reflect(def_zone) //Reflection checks for anything in your hands, based on the reflection chance of the object(s)
+ for(var/obj/item/I in held_items)
+ if(I.IsReflect(def_zone))
+ return TRUE
+ return FALSE
+
+/mob/living/proc/reflect_bullet_check(obj/item/projectile/P, def_zone)
+ if(P.is_reflectable && check_reflect(def_zone)) // Checks if you've passed a reflection% check
+ visible_message("The [P.name] gets reflected by [src]!", \
+ "The [P.name] gets reflected by [src]!")
+ // Find a turf near or on the original location to bounce to
+ if(P.starting)
+ var/new_x = P.starting.x + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/new_y = P.starting.y + pick(0, 0, 0, 0, 0, -1, 1, -2, 2)
+ var/turf/curloc = get_turf(src)
+ // redirect the projectile
+ P.original = locate(new_x, new_y, P.z)
+ P.starting = curloc
+ P.firer = src
+ P.yo = new_y - curloc.y
+ P.xo = new_x - curloc.x
+ var/new_angle_s = P.Angle + rand(120,240)
+ while(new_angle_s > 180) // Translate to regular projectile degrees
+ new_angle_s -= 360
+ P.setAngle(new_angle_s)
+ return TRUE
+ return FALSE
+
+/mob/living/bullet_act(obj/item/projectile/P, def_zone)
+ if(P.original != src || P.firer != src) //try to block or reflect the bullet, can't do so when shooting oneself
+ if(reflect_bullet_check(P, def_zone))
+ return -1 // complete projectile permutation
+ if(check_shields(P, P.damage, "the [P.name]", PROJECTILE_ATTACK, P.armour_penetration))
+ P.on_hit(src, 100, def_zone)
+ return 2
+ var/armor = run_armor_check(def_zone, P.flag, null, null, P.armour_penetration, null)
+ if(!P.nodamage)
+ apply_damage(P.damage, P.damage_type, def_zone, armor)
+ if(P.dismemberment)
+ check_projectile_dismemberment(P, def_zone)
+ return P.on_hit(src, armor)
+
+/mob/living/proc/check_projectile_dismemberment(obj/item/projectile/P, def_zone)
+ return 0
+
+/obj/item/proc/get_volume_by_throwforce_and_or_w_class()
+ if(throwforce && w_class)
+ return CLAMP((throwforce + w_class) * 5, 30, 100)// Add the item's throwforce to its weight class and multiply by 5, then clamp the value between 30 and 100
+ else if(w_class)
+ return CLAMP(w_class * 8, 20, 100) // Multiply the item's weight class by 8, then clamp the value between 20 and 100
+ else
+ return 0
+
+/mob/living/proc/catch_item(obj/item/I, skip_throw_mode_check = FALSE)
+ return FALSE
+
+/mob/living/proc/embed_item(obj/item/I)
+ return
+
+/mob/living/proc/can_embed(obj/item/I)
+ return FALSE
+
+/mob/living/hitby(atom/movable/AM, skipcatch, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
+ var/obj/item/I
+ var/throwpower = 30
+ if(isitem(AM))
+ I = AM
+ throwpower = I.throwforce
+ if(check_shields(AM, throwpower, "\the [AM.name]", THROWN_PROJECTILE_ATTACK))
+ hitpush = FALSE
+ skipcatch = TRUE
+ blocked = TRUE
+ else if(I && I.throw_speed >= EMBED_THROWSPEED_THRESHOLD && can_embed(I, src) && prob(I.embedding.embed_chance) && !HAS_TRAIT(src, TRAIT_PIERCEIMMUNE) && (!HAS_TRAIT(src, TRAIT_AUTO_CATCH_ITEM) || incapacitated() || get_active_held_item()))
+ embed_item(I)
+ hitpush = FALSE
+ skipcatch = TRUE //can't catch the now embedded item
+ if(I)
+ if(!skipcatch && isturf(I.loc) && catch_item(I))
+ return TRUE
+ var/zone = ran_zone(BODY_ZONE_CHEST, 65)//Hits a random part of the body, geared towards the chest
+ var/dtype = BRUTE
+ var/volume = I.get_volume_by_throwforce_and_or_w_class()
+ SEND_SIGNAL(I, COMSIG_MOVABLE_IMPACT_ZONE, src, zone)
+ dtype = I.damtype
+
+ if (I.throwforce > 0) //If the weapon's throwforce is greater than zero...
+ if (I.throwhitsound) //...and throwhitsound is defined...
+ playsound(loc, I.throwhitsound, volume, 1, -1) //...play the weapon's throwhitsound.
+ else if(I.hitsound) //Otherwise, if the weapon's hitsound is defined...
+ playsound(loc, I.hitsound, volume, 1, -1) //...play the weapon's hitsound.
+ else if(!I.throwhitsound) //Otherwise, if throwhitsound isn't defined...
+ playsound(loc, 'sound/weapons/genhit.ogg',volume, 1, -1) //...play genhit.ogg.
+
+ else if(!I.throwhitsound && I.throwforce > 0) //Otherwise, if the item doesn't have a throwhitsound and has a throwforce greater than zero...
+ playsound(loc, 'sound/weapons/genhit.ogg', volume, 1, -1)//...play genhit.ogg
+ if(!I.throwforce)// Otherwise, if the item's throwforce is 0...
+ playsound(loc, 'sound/weapons/throwtap.ogg', 1, volume, -1)//...play throwtap.ogg.
+ if(!blocked)
+ visible_message("[src] has been hit by [I].", \
+ "[src] has been hit by [I].")
+ var/armor = run_armor_check(zone, "melee", "Your armor has protected your [parse_zone(zone)].", "Your armor has softened hit to your [parse_zone(zone)].",I.armour_penetration)
+ apply_damage(I.throwforce, dtype, zone, armor)
+ if(I.thrownby)
+ log_combat(I.thrownby, src, "threw and hit", I)
+ else
+ return 1
+ else
+ playsound(loc, 'sound/weapons/genhit.ogg', 50, 1, -1)
+ ..()
+
+
+/mob/living/mech_melee_attack(obj/mecha/M)
+ if(M.occupant.a_intent == INTENT_HARM)
+ M.do_attack_animation(src)
+ if(M.damtype == "brute")
+ step_away(src,M,15)
+ switch(M.damtype)
+ if(BRUTE)
+ Unconscious(20)
+ take_overall_damage(rand(M.force/2, M.force))
+ playsound(src, 'sound/weapons/punch4.ogg', 50, 1)
+ if(BURN)
+ take_overall_damage(0, rand(M.force/2, M.force))
+ playsound(src, 'sound/items/welder.ogg', 50, 1)
+ if(TOX)
+ M.mech_toxin_damage(src)
+ else
+ return
+ updatehealth()
+ visible_message("[M.name] has hit [src]!", \
+ "[M.name] has hit [src]!", null, COMBAT_MESSAGE_RANGE)
+ log_combat(M.occupant, src, "attacked", M, "(INTENT: [uppertext(M.occupant.a_intent)]) (DAMTYPE: [uppertext(M.damtype)])")
+ else
+ step_away(src,M)
+ log_combat(M.occupant, src, "pushed", M)
+ visible_message("[M] pushes [src] out of the way.", null, null, 5)
+
+/mob/living/fire_act()
+ adjust_fire_stacks(3)
+ IgniteMob()
+
+/mob/living/proc/grabbedby(mob/living/carbon/user, supress_message = FALSE)
+ if(user == anchored || !isturf(user.loc))
+ return FALSE
+
+ //pacifist vore check.
+ if(user.pulling && HAS_TRAIT(user, TRAIT_PACIFISM) && user.voremode) //they can only do heals, noisy guts, absorbing (technically not harm)
+ if(ismob(user.pulling))
+ var/mob/P = user.pulling
+ if(src != user)
+ to_chat(user, "You can't risk digestion!")
+ return FALSE
+ else
+ user.vore_attack(user, P, user)
+ return
+
+ //normal vore check.
+ if(user.pulling && user.grab_state == GRAB_AGGRESSIVE && user.voremode)
+ if(ismob(user.pulling))
+ var/mob/P = user.pulling
+ user.vore_attack(user, P, src) // User, Pulled, Predator target (which can be user, pulling, or src)
+ return
+
+ if(user == src) //we want to be able to self click if we're voracious
+ return FALSE
+
+ if(!user.pulling || user.pulling != src)
+ user.start_pulling(src, supress_message = supress_message)
+ return
+
+ if(!(status_flags & CANPUSH) || HAS_TRAIT(src, TRAIT_PUSHIMMUNE))
+ to_chat(user, "[src] can't be grabbed more aggressively!")
+ return FALSE
+
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "You don't want to risk hurting [src]!")
+ return FALSE
+
+ grippedby(user)
+
+//proc to upgrade a simple pull into a more aggressive grab.
+/mob/living/proc/grippedby(mob/living/carbon/user, instant = FALSE)
+ if(user.grab_state < GRAB_KILL)
+ user.changeNext_move(CLICK_CD_GRABBING)
+ playsound(src.loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
+
+ if(user.grab_state) //only the first upgrade is instantaneous
+ var/old_grab_state = user.grab_state
+ var/grab_upgrade_time = instant ? 0 : 30
+ visible_message("[user] starts to tighten [user.p_their()] grip on [src]!", \
+ "[user] starts to tighten [user.p_their()] grip on you!")
+ switch(user.grab_state)
+ if(GRAB_AGGRESSIVE)
+ log_combat(user, src, "attempted to neck grab", addition="neck grab")
+ if(GRAB_NECK)
+ log_combat(user, src, "attempted to strangle", addition="kill grab")
+ if(!do_mob(user, src, grab_upgrade_time))
+ return 0
+ if(!user.pulling || user.pulling != src || user.grab_state != old_grab_state || user.a_intent != INTENT_GRAB)
+ return 0
+ if(user.voremode && user.grab_state == GRAB_AGGRESSIVE)
+ return 0
+ user.grab_state++
+ switch(user.grab_state)
+ if(GRAB_AGGRESSIVE)
+ log_combat(user, src, "grabbed", addition="aggressive grab")
+ visible_message("[user] has grabbed [src] aggressively!", \
+ "[user] has grabbed [src] aggressively!")
+ drop_all_held_items()
+ stop_pulling()
+ if(GRAB_NECK)
+ log_combat(user, src, "grabbed", addition="neck grab")
+ visible_message("[user] has grabbed [src] by the neck!",\
+ "[user] has grabbed you by the neck!")
+ update_canmove() //we fall down
+ if(!buckled && !density)
+ Move(user.loc)
+ if(GRAB_KILL)
+ log_combat(user, src, "strangled", addition="kill grab")
+ visible_message("[user] is strangling [src]!", \
+ "[user] is strangling you!")
+ update_canmove() //we fall down
+ if(!buckled && !density)
+ Move(user.loc)
+ return 1
+
+/mob/living/attack_hand(mob/user)
+ ..() //Ignoring parent return value here.
+ SEND_SIGNAL(src, COMSIG_MOB_ATTACK_HAND, user)
+ if((user != src) && user.a_intent != INTENT_HELP && check_shields(user, 0, user.name, attack_type = UNARMED_ATTACK))
+ log_combat(user, src, "attempted to touch")
+ visible_message("[user] attempted to touch [src]!")
+ return TRUE
+
+/mob/living/attack_hulk(mob/living/carbon/human/user, does_attack_animation = FALSE)
+ if(user.a_intent == INTENT_HARM)
+ if(HAS_TRAIT(user, TRAIT_PACIFISM))
+ to_chat(user, "You don't want to hurt [src]!")
+ return TRUE
+ var/hulk_verb = pick("smash","pummel")
+ if(user != src && check_shields(user, 15, "the [hulk_verb]ing"))
+ return TRUE
+ ..()
+ return FALSE
+
+/mob/living/attack_slime(mob/living/simple_animal/slime/M)
+ if(!SSticker.HasRoundStarted())
+ to_chat(M, "You cannot attack people before the game has started.")
+ return
+
+ if(M.buckled)
+ if(M in buckled_mobs)
+ M.Feedstop()
+ return // can't attack while eating!
+
+ if(HAS_TRAIT(src, TRAIT_PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
+
+ var/damage = rand(5, 35)
+ if(M.is_adult)
+ damage = rand(20, 40)
+ if(check_shields(M, damage, "the [M.name]"))
+ return FALSE
+
+ if (stat != DEAD)
+ log_combat(M, src, "attacked")
+ M.do_attack_animation(src)
+ visible_message("The [M.name] glomps [src]!", \
+ "The [M.name] glomps [src]!", null, COMBAT_MESSAGE_RANGE)
+ return TRUE
+
+/mob/living/attack_animal(mob/living/simple_animal/M)
+ M.face_atom(src)
+ if(M.melee_damage_upper == 0)
+ M.visible_message("\The [M] [M.friendly] [src]!")
+ return FALSE
+ else
+ if(HAS_TRAIT(M, TRAIT_PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
+ if(check_shields(M, rand(M.melee_damage_lower, M.melee_damage_upper), "the [M.name]", MELEE_ATTACK, M.armour_penetration))
+ return FALSE
+ if(M.attack_sound)
+ playsound(loc, M.attack_sound, 50, 1, 1)
+ M.do_attack_animation(src)
+ visible_message("\The [M] [M.attacktext] [src]!", \
+ "\The [M] [M.attacktext] [src]!", null, COMBAT_MESSAGE_RANGE)
+ log_combat(M, src, "attacked")
+ return TRUE
+
+
+/mob/living/attack_paw(mob/living/carbon/monkey/M)
+ if (M.a_intent == INTENT_HARM)
+ if(HAS_TRAIT(M, TRAIT_PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
+
+ if(M.is_muzzled() || (M.wear_mask && M.wear_mask.flags_cover & MASKCOVERSMOUTH))
+ to_chat(M, "You can't bite with your mouth covered!")
+ return FALSE
+ if(check_shields(M, 0, "the [M.name]"))
+ return FALSE
+ M.do_attack_animation(src, ATTACK_EFFECT_BITE)
+ if (prob(75))
+ log_combat(M, src, "attacked")
+ playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
+ visible_message("[M.name] bites [src]!", \
+ "[M.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
+ return TRUE
+ else
+ visible_message("[M.name] has attempted to bite [src]!", \
+ "[M.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
+ return FALSE
+
+/mob/living/attack_larva(mob/living/carbon/alien/larva/L)
+ switch(L.a_intent)
+ if(INTENT_HELP)
+ visible_message("[L.name] rubs its head against [src].")
+ return FALSE
+
+ else
+ if(HAS_TRAIT(L, TRAIT_PACIFISM))
+ to_chat(L, "You don't want to hurt anyone!")
+ return FALSE
+ if(L != src && check_shields(L, rand(1, 3), "the [L.name]"))
+ return FALSE
+
+ L.do_attack_animation(src)
+ if(prob(90))
+ log_combat(L, src, "attacked")
+ visible_message("[L.name] bites [src]!", \
+ "[L.name] bites [src]!", null, COMBAT_MESSAGE_RANGE)
+ playsound(loc, 'sound/weapons/bite.ogg', 50, 1, -1)
+ return TRUE
+ else
+ visible_message("[L.name] has attempted to bite [src]!", \
+ "[L.name] has attempted to bite [src]!", null, COMBAT_MESSAGE_RANGE)
+ return FALSE
+
+/mob/living/attack_alien(mob/living/carbon/alien/humanoid/M)
+ if((M != src) && M.a_intent != INTENT_HELP && check_shields(M, 0, "the [M.name]"))
+ visible_message("[M] attempted to touch [src]!")
+ return FALSE
+ switch(M.a_intent)
+ if (INTENT_HELP)
+ if(!isalien(src)) //I know it's ugly, but the alien vs alien attack_alien behaviour is a bit different.
+ visible_message("[M] caresses [src] with its scythe like arm.")
+ return FALSE
+ if (INTENT_GRAB)
+ grabbedby(M)
+ return FALSE
+ if(INTENT_HARM)
+ if(HAS_TRAIT(M, TRAIT_PACIFISM))
+ to_chat(M, "You don't want to hurt anyone!")
+ return FALSE
+ if(!isalien(src))
+ M.do_attack_animation(src)
+ return TRUE
+ if(INTENT_DISARM)
+ if(!isalien(src))
+ M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
+ return TRUE
+
+/mob/living/ex_act(severity, target, origin)
+ if(origin && istype(origin, /datum/spacevine_mutation) && isvineimmune(src))
+ return
+ ..()
+
+//Looking for irradiate()? It's been moved to radiation.dm under the rad_act() for mobs.
+
+/mob/living/acid_act(acidpwr, acid_volume)
+ take_bodypart_damage(acidpwr * min(1, acid_volume * 0.1))
+ return 1
+
+/mob/living/proc/electrocute_act(shock_damage, obj/source, siemens_coeff = 1, safety = 0, tesla_shock = 0, illusion = 0, stun = TRUE)
+ SEND_SIGNAL(src, COMSIG_LIVING_ELECTROCUTE_ACT, shock_damage)
+ if(tesla_shock && (flags_1 & TESLA_IGNORE_1))
+ return FALSE
+ if(HAS_TRAIT(src, TRAIT_SHOCKIMMUNE))
+ return FALSE
+ if(shock_damage > 0)
+ if(!illusion)
+ adjustFireLoss(shock_damage)
+ visible_message(
+ "[src] was shocked by \the [source]!", \
+ "You feel a powerful shock coursing through your body!", \
+ "You hear a heavy electrical crack." \
+ )
+ return shock_damage
+
+/mob/living/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_CONTENTS)
+ return
+ for(var/obj/O in contents)
+ O.emp_act(severity)
+
+/mob/living/singularity_act()
+ var/gain = 20
+ investigate_log("([key_name(src)]) has been consumed by the singularity.", INVESTIGATE_SINGULO) //Oh that's where the clown ended up!
+ gib()
+ return(gain)
+
+/mob/living/narsie_act()
+ if(status_flags & GODMODE || QDELETED(src))
+ return
+
+ if(is_servant_of_ratvar(src) && !stat)
+ to_chat(src, "You resist Nar'Sie's influence... but not all of it. Run!")
+ adjustBruteLoss(35)
+ if(src && reagents)
+ reagents.add_reagent(/datum/reagent/toxin/heparin, 5)
+ return FALSE
+ if(GLOB.cult_narsie && GLOB.cult_narsie.souls_needed[src])
+ GLOB.cult_narsie.souls_needed -= src
+ GLOB.cult_narsie.souls += 1
+ if((GLOB.cult_narsie.souls == GLOB.cult_narsie.soul_goal) && (GLOB.cult_narsie.resolved == FALSE))
+ GLOB.cult_narsie.resolved = TRUE
+ sound_to_playing_players('sound/machines/alarm.ogg')
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/cult_ending_helper, 1), 120)
+ addtimer(CALLBACK(GLOBAL_PROC, .proc/ending_helper), 270)
+ if(client)
+ makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, src, cultoverride = TRUE)
+ else
+ switch(rand(1, 6))
+ if(1)
+ new /mob/living/simple_animal/hostile/construct/armored/hostile(get_turf(src))
+ if(2)
+ new /mob/living/simple_animal/hostile/construct/wraith/hostile(get_turf(src))
+ if(3 to 6)
+ new /mob/living/simple_animal/hostile/construct/builder/hostile(get_turf(src))
+ spawn_dust()
+ gib()
+ return TRUE
+
+
+/mob/living/ratvar_act()
+ if(status_flags & GODMODE)
+ return
+ if(stat != DEAD && !is_servant_of_ratvar(src))
+ to_chat(src, "A blinding light boils you alive! Run!")
+ adjust_fire_stacks(20)
+ IgniteMob()
+ return FALSE
+
+
+//called when the mob receives a bright flash
+/mob/living/proc/flash_act(intensity = 1, override_blindness_check = 0, affect_silicon = 0, visual = 0, type = /obj/screen/fullscreen/flash)
+ if(get_eye_protection() < intensity && (override_blindness_check || !(HAS_TRAIT(src, TRAIT_BLIND))))
+ overlay_fullscreen("flash", type)
+ addtimer(CALLBACK(src, .proc/clear_fullscreen, "flash", 25), 25)
+ return TRUE
+ return FALSE
+
+//called when the mob receives a loud bang
+/mob/living/proc/soundbang_act()
+ return 0
+
+//to damage the clothes worn by a mob
+/mob/living/proc/damage_clothes(damage_amount, damage_type = BRUTE, damage_flag = 0, def_zone)
+ return
+
+
+/mob/living/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
+ if(!used_item)
+ used_item = get_active_held_item()
+ ..()
+ floating = 0 // If we were without gravity, the bouncing animation got stopped, so we make sure we restart the bouncing after the next movement.
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index abf6bfc9..9c98417a 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -1,645 +1,645 @@
-/obj/item/robot_module
- name = "Default"
- icon = 'icons/obj/module.dmi'
- icon_state = "std_mod"
- w_class = WEIGHT_CLASS_GIGANTIC
- item_state = "electronic"
- lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
- flags_1 = CONDUCT_1
-
- var/list/basic_modules = list() //a list of paths, converted to a list of instances on New()
- var/list/emag_modules = list() //ditto
- var/list/ratvar_modules = list() //ditto ditto
- var/list/modules = list() //holds all the usable modules
- var/list/added_modules = list() //modules not inherient to the robot module, are kept when the module changes
- var/list/storages = list()
-
- var/cyborg_base_icon = "robot" //produces the icon for the borg and, if no special_light_key is set, the lights
- var/special_light_key //if we want specific lights, use this instead of copying lights in the dmi
-
- var/moduleselect_icon = "nomod"
-
- var/can_be_pushed = TRUE
- var/magpulsing = FALSE
- var/clean_on_move = FALSE
-
- var/did_feedback = FALSE
-
- var/hat_offset = -3
-
- var/list/ride_offset_x = list("north" = 0, "south" = 0, "east" = -6, "west" = 6)
- var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3)
- var/ride_allow_incapacitated = FALSE
- var/allow_riding = TRUE
-
-/obj/item/robot_module/Initialize()
- . = ..()
- for(var/i in basic_modules)
- var/obj/item/I = new i(src)
- basic_modules += I
- basic_modules -= i
- for(var/i in emag_modules)
- var/obj/item/I = new i(src)
- emag_modules += I
- emag_modules -= i
- for(var/i in ratvar_modules)
- var/obj/item/I = new i(src)
- ratvar_modules += I
- ratvar_modules -= i
-
-/obj/item/robot_module/Destroy()
- basic_modules.Cut()
- emag_modules.Cut()
- ratvar_modules.Cut()
- modules.Cut()
- added_modules.Cut()
- storages.Cut()
- return ..()
-
-/obj/item/robot_module/emp_act(severity)
- . = ..()
- if(. & EMP_PROTECT_CONTENTS)
- return
- for(var/obj/O in modules)
- O.emp_act(severity)
- ..()
-
-/obj/item/robot_module/proc/get_usable_modules()
- . = modules.Copy()
-
-/obj/item/robot_module/proc/get_inactive_modules()
- . = list()
- var/mob/living/silicon/robot/R = loc
- for(var/m in get_usable_modules())
- if(!(m in R.held_items))
- . += m
-
-/obj/item/robot_module/proc/get_or_create_estorage(var/storage_type)
- for(var/datum/robot_energy_storage/S in storages)
- if(istype(S, storage_type))
- return S
-
- return new storage_type(src)
-
-/obj/item/robot_module/proc/add_module(obj/item/I, nonstandard, requires_rebuild)
- if(istype(I, /obj/item/stack))
- var/obj/item/stack/S = I
-
- if(is_type_in_list(S, list(/obj/item/stack/sheet/metal, /obj/item/stack/rods, /obj/item/stack/tile/plasteel)))
- if(S.materials[MAT_METAL])
- S.cost = S.materials[MAT_METAL] * 0.25
- S.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
-
- else if(istype(S, /obj/item/stack/sheet/glass))
- S.cost = 500
- S.source = get_or_create_estorage(/datum/robot_energy_storage/glass)
-
- else if(istype(S, /obj/item/stack/sheet/rglass/cyborg))
- var/obj/item/stack/sheet/rglass/cyborg/G = S
- G.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
- G.glasource = get_or_create_estorage(/datum/robot_energy_storage/glass)
-
- else if(istype(S, /obj/item/stack/medical))
- S.cost = 250
- S.source = get_or_create_estorage(/datum/robot_energy_storage/medical)
-
- else if(istype(S, /obj/item/stack/cable_coil))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/wire)
-
- else if(istype(S, /obj/item/stack/marker_beacon))
- S.cost = 1
- S.source = get_or_create_estorage(/datum/robot_energy_storage/beacon)
-
- if(S && S.source)
- S.materials = list()
- S.is_cyborg = 1
-
- if(I.loc != src)
- I.forceMove(src)
- modules += I
- ADD_TRAIT(I, TRAIT_NODROP, CYBORG_ITEM_TRAIT)
- I.mouse_opacity = MOUSE_OPACITY_OPAQUE
- if(nonstandard)
- added_modules += I
- if(requires_rebuild)
- rebuild_modules()
- return I
-
-/obj/item/robot_module/proc/remove_module(obj/item/I, delete_after)
- basic_modules -= I
- modules -= I
- emag_modules -= I
- ratvar_modules -= I
- added_modules -= I
- rebuild_modules()
- if(delete_after)
- qdel(I)
-
-/obj/item/robot_module/proc/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
- for(var/datum/robot_energy_storage/st in storages)
- st.energy = min(st.max_energy, st.energy + coeff * st.recharge_rate)
-
- for(var/obj/item/I in get_usable_modules())
- if(istype(I, /obj/item/assembly/flash))
- var/obj/item/assembly/flash/F = I
- F.times_used = 0
- F.crit_fail = 0
- F.update_icon()
- else if(istype(I, /obj/item/melee/baton))
- var/obj/item/melee/baton/B = I
- if(B.cell)
- B.cell.charge = B.cell.maxcharge
- else if(istype(I, /obj/item/gun/energy))
- var/obj/item/gun/energy/EG = I
- if(EG.cell?.charge < EG.cell.maxcharge)
- var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.select]
- EG.cell.give(S.e_cost * coeff)
- if(!EG.chambered)
- EG.recharge_newshot(TRUE)
- EG.update_icon()
- else
- EG.charge_tick = 0
-
- R.toner = R.tonermax
-
-/obj/item/robot_module/proc/rebuild_modules() //builds the usable module list from the modules we have
- var/mob/living/silicon/robot/R = loc
- var/held_modules = R.held_items.Copy()
- R.uneq_all()
- modules = list()
- for(var/obj/item/I in basic_modules)
- add_module(I, FALSE, FALSE)
- if(R.emagged)
- for(var/obj/item/I in emag_modules)
- add_module(I, FALSE, FALSE)
- if(is_servant_of_ratvar(R))
- for(var/obj/item/I in ratvar_modules)
- add_module(I, FALSE, FALSE)
- for(var/obj/item/I in added_modules)
- add_module(I, FALSE, FALSE)
- for(var/i in held_modules)
- if(i)
- R.activate_module(i)
- if(R.hud_used)
- R.hud_used.update_robot_modules_display()
-
-/obj/item/robot_module/proc/transform_to(new_module_type)
- var/mob/living/silicon/robot/R = loc
- var/obj/item/robot_module/RM = new new_module_type(R)
- if(!RM.be_transformed_to(src))
- qdel(RM)
- return
- R.module = RM
- R.update_module_innate()
- RM.rebuild_modules()
- INVOKE_ASYNC(RM, .proc/do_transform_animation)
- qdel(src)
- return RM
-
-/obj/item/robot_module/proc/be_transformed_to(obj/item/robot_module/old_module)
- for(var/i in old_module.added_modules)
- added_modules += i
- old_module.added_modules -= i
- did_feedback = old_module.did_feedback
- return TRUE
-
-/obj/item/robot_module/proc/do_transform_animation()
- var/mob/living/silicon/robot/R = loc
- if(R.hat)
- R.hat.forceMove(get_turf(R))
- R.hat = null
- R.cut_overlays()
- R.setDir(SOUTH)
- do_transform_delay()
-
-/obj/item/robot_module/proc/do_transform_delay()
- var/mob/living/silicon/robot/R = loc
- var/prev_lockcharge = R.lockcharge
- sleep(1)
- flick("[cyborg_base_icon]_transform", R)
- R.notransform = TRUE
- R.SetLockdown(1)
- R.anchored = TRUE
- sleep(1)
- for(var/i in 1 to 4)
- playsound(R, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, 1, -1)
- sleep(7)
- if(!prev_lockcharge)
- R.SetLockdown(0)
- R.setDir(SOUTH)
- R.anchored = FALSE
- R.notransform = FALSE
- R.update_headlamp()
- R.notify_ai(NEW_MODULE)
- if(R.hud_used)
- R.hud_used.update_robot_modules_display()
- SSblackbox.record_feedback("tally", "cyborg_modules", 1, R.module)
-
-/* //Broken
-/obj/item/robot_module/standard
- name = "Standard"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/reagent_containers/borghypo/epi,
- /obj/item/healthanalyzer,
- /obj/item/weldingtool/largetank/cyborg,
- /obj/item/wrench/cyborg,
- /obj/item/crowbar/cyborg,
- /obj/item/stack/sheet/metal/cyborg,
- /obj/item/stack/rods/cyborg,
- /obj/item/stack/tile/plasteel/cyborg,
- /obj/item/extinguisher,
- /obj/item/borg/apparatus/beaker/service,
- /obj/item/pickaxe,
- /obj/item/t_scanner/adv_mining_scanner,
- /obj/item/restraints/handcuffs/cable/zipties,
- /obj/item/soap/nanotrasen,
- /obj/item/borg/cyborghug)
- emag_modules = list(/obj/item/melee/transforming/energy/sword/cyborg)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg,
- /obj/item/clockwork/weapon/ratvarian_spear,
- /obj/item/clockwork/replica_fabricator/cyborg)
- moduleselect_icon = "standard"
- hat_offset = -3
-*/
-
-/obj/item/robot_module/medical
- name = "Medical"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/healthanalyzer,
- /obj/item/reagent_containers/borghypo,
- /obj/item/borg/apparatus/beaker,
- /obj/item/reagent_containers/glass/beaker/large,
- /obj/item/reagent_containers/dropper,
- /obj/item/reagent_containers/syringe,
- /obj/item/surgical_drapes,
- /obj/item/retractor,
- /obj/item/hemostat,
- /obj/item/cautery,
- /obj/item/surgicaldrill,
- /obj/item/scalpel,
- /obj/item/circular_saw,
- /obj/item/extinguisher/mini,
- /obj/item/soap/nanotrasen,
- /obj/item/crowbar/cyborg,
- /obj/item/roller/robo,
- /obj/item/borg/cyborghug/medical,
- /obj/item/stack/medical/gauze/cyborg,
- /obj/item/organ_storage,
- /obj/item/borg/lollipop,
- /obj/item/sensor_device)
- emag_modules = list(/obj/item/reagent_containers/borghypo/hacked)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg/medical,
- /obj/item/clockwork/weapon/ratvarian_spear)
- cyborg_base_icon = "medical"
- moduleselect_icon = "medical"
- can_be_pushed = FALSE
- hat_offset = 3
-
-/obj/item/robot_module/engineering
- name = "Engineering"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/borg/sight/meson,
- /obj/item/construction/rcd/borg,
- /obj/item/pipe_dispenser,
- /obj/item/extinguisher,
- /obj/item/weldingtool/largetank/cyborg,
- /obj/item/screwdriver/cyborg,
- /obj/item/wrench/cyborg,
- /obj/item/crowbar/cyborg,
- /obj/item/wirecutters/cyborg,
- /obj/item/multitool/cyborg,
- /obj/item/t_scanner,
- /obj/item/analyzer,
- /obj/item/soap/nanotrasen,
- /obj/item/borg/cyborghug,
- /obj/item/geiger_counter/cyborg,
- /obj/item/assembly/signaler/cyborg,
- /obj/item/holosign_creator/atmos,
- /obj/item/areaeditor/blueprints/cyborg,
- /obj/item/electroadaptive_pseudocircuit,
- /obj/item/stack/sheet/metal/cyborg,
- /obj/item/stack/sheet/glass/cyborg,
- /obj/item/stack/sheet/rglass/cyborg,
- /obj/item/stack/rods/cyborg,
- /obj/item/stack/tile/plasteel/cyborg,
- /obj/item/stack/cable_coil/cyborg)
- emag_modules = list(/obj/item/borg/stun)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg/engineer,
- /obj/item/clockwork/replica_fabricator/cyborg)
- cyborg_base_icon = "engineer"
- moduleselect_icon = "engineer"
- magpulsing = TRUE
- hat_offset = -4
-
-/obj/item/robot_module/security
- name = "Security"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/restraints/handcuffs/cable/zipties,
- /obj/item/holosign_creator/security,
- /obj/item/melee/baton/loaded,
- /obj/item/gun/energy/disabler/cyborg,
- /obj/item/reagent_containers/spray/pepper,
- /obj/item/clothing/mask/gas/sechailer/cyborg,
- /obj/item/extinguisher/mini,
- /obj/item/borg/cyborghug,
- /obj/item/soap/nanotrasen,
- /obj/item/crowbar/cyborg,
- /obj/item/pinpointer/crew)
- emag_modules = list(/obj/item/gun/energy/laser/cyborg)
- ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security,
- /obj/item/clockwork/weapon/ratvarian_spear)
- cyborg_base_icon = "sec"
- moduleselect_icon = "security"
- can_be_pushed = FALSE
- hat_offset = 3
-
-/obj/item/robot_module/security/do_transform_animation()
- ..()
- to_chat(loc, "While you have picked the security module, you still have to follow your laws, NOT Space Law. \
- For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.")
-
-/obj/item/robot_module/peacekeeper
- name = "Peacekeeper"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/cookiesynth,
- /obj/item/harmalarm,
- /obj/item/reagent_containers/borghypo/peace,
- /obj/item/holosign_creator/cyborg,
- /obj/item/borg/cyborghug/peacekeeper,
- /obj/item/soap/nanotrasen,
- /obj/item/extinguisher/mini,
- /obj/item/crowbar/cyborg,
- /obj/item/borg/projectile_dampen)
- emag_modules = list(/obj/item/reagent_containers/borghypo/peace/hacked)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg/peacekeeper,
- /obj/item/clockwork/weapon/ratvarian_spear)
- cyborg_base_icon = "peace"
- moduleselect_icon = "standard"
- can_be_pushed = FALSE
- hat_offset = -2
-
-/obj/item/robot_module/peacekeeper/do_transform_animation()
- ..()
- to_chat(loc, "Under ASIMOV, you are an enforcer of the PEACE and preventer of HUMAN HARM. \
- You are not a security module and you are expected to follow orders and prevent harm above all else. Space law means nothing to you.")
-
-/obj/item/robot_module/janitor
- name = "Janitor"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/screwdriver/cyborg,
- /obj/item/crowbar/cyborg,
- /obj/item/stack/tile/plasteel/cyborg,
- /obj/item/soap/nanotrasen,
- /obj/item/storage/bag/trash/cyborg,
- /obj/item/borg/cyborghug,
- /obj/item/extinguisher/mini,
- /obj/item/mop/cyborg,
- /obj/item/lightreplacer/cyborg,
- /obj/item/holosign_creator,
- /obj/item/reagent_containers/spray/cyborg_drying)
- emag_modules = list(/obj/item/reagent_containers/spray/cyborg_lube)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg/janitor,
- /obj/item/clockwork/replica_fabricator/cyborg)
- cyborg_base_icon = "janitor"
- moduleselect_icon = "janitor"
- hat_offset = -5
- clean_on_move = TRUE
-
-/obj/item/reagent_containers/spray/cyborg_drying
- name = "drying agent spray"
- color = "#A000A0"
- list_reagents = list("drying_agent" = 250)
-
-/obj/item/reagent_containers/spray/cyborg_lube
- name = "lube spray"
- list_reagents = list("lube" = 250)
-
-/obj/item/robot_module/janitor/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
- ..()
- var/obj/item/lightreplacer/LR = locate(/obj/item/lightreplacer) in basic_modules
- if(LR)
- for(var/i in 1 to coeff)
- LR.Charge(R)
-
- var/obj/item/reagent_containers/spray/cyborg_drying/CD = locate(/obj/item/reagent_containers/spray/cyborg_drying) in basic_modules
- if(CD)
- CD.reagents.add_reagent("drying_agent", 5 * coeff)
-
- var/obj/item/reagent_containers/spray/cyborg_lube/CL = locate(/obj/item/reagent_containers/spray/cyborg_lube) in emag_modules
- if(CL)
- CL.reagents.add_reagent("lube", 2 * coeff)
-
-/obj/item/robot_module/clown
- name = "Clown"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/toy/crayon/rainbow,
- /obj/item/instrument/bikehorn,
- /obj/item/stamp/clown,
- /obj/item/bikehorn,
- /obj/item/bikehorn/airhorn,
- /obj/item/paint/anycolor,
- /obj/item/cookiesynth,
- /obj/item/pneumatic_cannon/pie/selfcharge/cyborg,
- /obj/item/razor, //killbait material
- /obj/item/lipstick/purple,
- /obj/item/soap/nanotrasen,
- /obj/item/reagent_containers/spray/waterflower/cyborg,
- /obj/item/borg/cyborghug/peacekeeper,
- /obj/item/borg/lollipop/clown,
- /obj/item/picket_sign/cyborg,
- /obj/item/reagent_containers/borghypo/borgshaker,
- /obj/item/reagent_containers/borghypo/clown,
- /obj/item/borg/apparatus/beaker/service,
- /obj/item/reagent_containers/glass/beaker/large,
- /obj/item/extinguisher/mini)
- emag_modules = list(
- /obj/item/reagent_containers/borghypo/clown/hacked,
- /obj/item/reagent_containers/spray/waterflower/cyborg/hacked)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg,
- /obj/item/clockwork/weapon/ratvarian_spear,
- /obj/item/clockwork/replica_fabricator/cyborg)
- moduleselect_icon = "service"
- cyborg_base_icon = "clown"
- hat_offset = -2
-
-/obj/item/robot_module/butler
- name = "Service"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/reagent_containers/glass/beaker/large,
- /obj/item/borg/apparatus/beaker/service,
- /obj/item/reagent_containers/food/condiment/enzyme,
- /obj/item/pen,
- /obj/item/toy/crayon/spraycan/borg,
- /obj/item/extinguisher/mini,
- /obj/item/hand_labeler/borg,
- /obj/item/razor,
- /obj/item/crowbar/cyborg,
- /obj/item/instrument/violin,
- /obj/item/soap/nanotrasen,
- /obj/item/instrument/guitar,
- /obj/item/rsf/cyborg,
- /obj/item/borg/cyborghug,
- /obj/item/reagent_containers/dropper,
- /obj/item/lighter,
- /obj/item/storage/bag/tray,
- /obj/item/reagent_containers/borghypo/borgshaker,
- /obj/item/borg/lollipop)
- emag_modules = list(/obj/item/reagent_containers/borghypo/borgshaker/hacked)
- ratvar_modules = list(/obj/item/clockwork/slab/cyborg/service,
- /obj/item/borg/sight/xray/truesight_lens)
- moduleselect_icon = "service"
- special_light_key = "service"
- hat_offset = 0
-
-/obj/item/robot_module/butler/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
- ..()
- var/obj/item/reagent_containers/O = locate(/obj/item/reagent_containers/food/condiment/enzyme) in basic_modules
- if(O)
- O.reagents.add_reagent("enzyme", 2 * coeff)
-
-/obj/item/robot_module/miner
- name = "Miner"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/borg/sight/meson,
- /obj/item/storage/bag/ore/cyborg,
- /obj/item/pickaxe/drill/cyborg,
- /obj/item/shovel,
- /obj/item/crowbar/cyborg,
- /obj/item/weldingtool/mini,
- /obj/item/borg/cyborghug,
- /obj/item/soap/nanotrasen,
- /obj/item/extinguisher/mini,
- /obj/item/storage/bag/sheetsnatcher/borg,
- /obj/item/t_scanner/adv_mining_scanner,
- /obj/item/gun/energy/kinetic_accelerator/cyborg,
- /obj/item/gps/cyborg,
- /obj/item/stack/marker_beacon)
- emag_modules = list(/obj/item/borg/stun)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg/miner,
- /obj/item/clockwork/weapon/ratvarian_spear,
- /obj/item/borg/sight/xray/truesight_lens)
- cyborg_base_icon = "miner"
- moduleselect_icon = "miner"
- hat_offset = 0
-
-/obj/item/robot_module/syndicate
- name = "Syndicate Assault"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/melee/transforming/energy/sword/cyborg,
- /obj/item/gun/energy/printer,
- /obj/item/gun/ballistic/revolver/grenadelauncher/cyborg,
- /obj/item/card/emag,
- /obj/item/crowbar/cyborg,
- /obj/item/pinpointer/syndicate_cyborg)
-
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg/security,
- /obj/item/clockwork/weapon/ratvarian_spear)
- cyborg_base_icon = "synd_sec"
- moduleselect_icon = "malf"
- can_be_pushed = FALSE
- hat_offset = 3
-
-/obj/item/robot_module/syndicate/rebuild_modules()
- ..()
- var/mob/living/silicon/robot/Syndi = loc
- Syndi.faction -= "silicon" //ai turrets
-
-/obj/item/robot_module/syndicate/remove_module(obj/item/I, delete_after)
- ..()
- var/mob/living/silicon/robot/Syndi = loc
- Syndi.faction += "silicon" //ai is your bff now!
-
-/obj/item/robot_module/syndicate_medical
- name = "Syndicate Medical"
- basic_modules = list(
- /obj/item/assembly/flash/cyborg,
- /obj/item/reagent_containers/borghypo/syndicate,
- /obj/item/twohanded/shockpaddles/syndicate,
- /obj/item/healthanalyzer,
- /obj/item/surgical_drapes,
- /obj/item/retractor,
- /obj/item/hemostat,
- /obj/item/cautery,
- /obj/item/surgicaldrill,
- /obj/item/scalpel,
- /obj/item/melee/transforming/energy/sword/cyborg/saw,
- /obj/item/roller/robo,
- /obj/item/card/emag,
- /obj/item/crowbar/cyborg,
- /obj/item/extinguisher/mini,
- /obj/item/pinpointer/syndicate_cyborg,
- /obj/item/stack/medical/gauze/cyborg,
- /obj/item/gun/medbeam,
- /obj/item/organ_storage)
- ratvar_modules = list(
- /obj/item/clockwork/slab/cyborg/medical,
- /obj/item/clockwork/weapon/ratvarian_spear)
- cyborg_base_icon = "synd_medical"
- moduleselect_icon = "malf"
- can_be_pushed = FALSE
- hat_offset = 3
-
-/datum/robot_energy_storage
- var/name = "Generic energy storage"
- var/max_energy = 30000
- var/recharge_rate = 1000
- var/energy
-
-/datum/robot_energy_storage/New(var/obj/item/robot_module/R = null)
- energy = max_energy
- if(R)
- R.storages |= src
- return
-
-/datum/robot_energy_storage/proc/use_charge(amount)
- if (energy >= amount)
- energy -= amount
- if (energy == 0)
- return 1
- return 2
- else
- return 0
-
-/datum/robot_energy_storage/proc/add_charge(amount)
- energy = min(energy + amount, max_energy)
-
-/datum/robot_energy_storage/metal
- name = "Metal Synthesizer"
-
-/datum/robot_energy_storage/glass
- name = "Glass Synthesizer"
-
-/datum/robot_energy_storage/wire
- max_energy = 50
- recharge_rate = 2
- name = "Wire Synthesizer"
-
-/datum/robot_energy_storage/medical
- max_energy = 2500
- recharge_rate = 250
- name = "Medical Synthesizer"
-
-/datum/robot_energy_storage/beacon
- max_energy = 30
- recharge_rate = 1
- name = "Marker Beacon Storage"
+/obj/item/robot_module
+ name = "Default"
+ icon = 'icons/obj/module.dmi'
+ icon_state = "std_mod"
+ w_class = WEIGHT_CLASS_GIGANTIC
+ item_state = "electronic"
+ lefthand_file = 'icons/mob/inhands/misc/devices_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/misc/devices_righthand.dmi'
+ flags_1 = CONDUCT_1
+
+ var/list/basic_modules = list() //a list of paths, converted to a list of instances on New()
+ var/list/emag_modules = list() //ditto
+ var/list/ratvar_modules = list() //ditto ditto
+ var/list/modules = list() //holds all the usable modules
+ var/list/added_modules = list() //modules not inherient to the robot module, are kept when the module changes
+ var/list/storages = list()
+
+ var/cyborg_base_icon = "robot" //produces the icon for the borg and, if no special_light_key is set, the lights
+ var/special_light_key //if we want specific lights, use this instead of copying lights in the dmi
+
+ var/moduleselect_icon = "nomod"
+
+ var/can_be_pushed = TRUE
+ var/magpulsing = FALSE
+ var/clean_on_move = FALSE
+
+ var/did_feedback = FALSE
+
+ var/hat_offset = -3
+
+ var/list/ride_offset_x = list("north" = 0, "south" = 0, "east" = -6, "west" = 6)
+ var/list/ride_offset_y = list("north" = 4, "south" = 4, "east" = 3, "west" = 3)
+ var/ride_allow_incapacitated = FALSE
+ var/allow_riding = TRUE
+
+/obj/item/robot_module/Initialize()
+ . = ..()
+ for(var/i in basic_modules)
+ var/obj/item/I = new i(src)
+ basic_modules += I
+ basic_modules -= i
+ for(var/i in emag_modules)
+ var/obj/item/I = new i(src)
+ emag_modules += I
+ emag_modules -= i
+ for(var/i in ratvar_modules)
+ var/obj/item/I = new i(src)
+ ratvar_modules += I
+ ratvar_modules -= i
+
+/obj/item/robot_module/Destroy()
+ basic_modules.Cut()
+ emag_modules.Cut()
+ ratvar_modules.Cut()
+ modules.Cut()
+ added_modules.Cut()
+ storages.Cut()
+ return ..()
+
+/obj/item/robot_module/emp_act(severity)
+ . = ..()
+ if(. & EMP_PROTECT_CONTENTS)
+ return
+ for(var/obj/O in modules)
+ O.emp_act(severity)
+ ..()
+
+/obj/item/robot_module/proc/get_usable_modules()
+ . = modules.Copy()
+
+/obj/item/robot_module/proc/get_inactive_modules()
+ . = list()
+ var/mob/living/silicon/robot/R = loc
+ for(var/m in get_usable_modules())
+ if(!(m in R.held_items))
+ . += m
+
+/obj/item/robot_module/proc/get_or_create_estorage(var/storage_type)
+ for(var/datum/robot_energy_storage/S in storages)
+ if(istype(S, storage_type))
+ return S
+
+ return new storage_type(src)
+
+/obj/item/robot_module/proc/add_module(obj/item/I, nonstandard, requires_rebuild)
+ if(istype(I, /obj/item/stack))
+ var/obj/item/stack/S = I
+
+ if(is_type_in_list(S, list(/obj/item/stack/sheet/metal, /obj/item/stack/rods, /obj/item/stack/tile/plasteel)))
+ if(S.materials[MAT_METAL])
+ S.cost = S.materials[MAT_METAL] * 0.25
+ S.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
+
+ else if(istype(S, /obj/item/stack/sheet/glass))
+ S.cost = 500
+ S.source = get_or_create_estorage(/datum/robot_energy_storage/glass)
+
+ else if(istype(S, /obj/item/stack/sheet/rglass/cyborg))
+ var/obj/item/stack/sheet/rglass/cyborg/G = S
+ G.source = get_or_create_estorage(/datum/robot_energy_storage/metal)
+ G.glasource = get_or_create_estorage(/datum/robot_energy_storage/glass)
+
+ else if(istype(S, /obj/item/stack/medical))
+ S.cost = 250
+ S.source = get_or_create_estorage(/datum/robot_energy_storage/medical)
+
+ else if(istype(S, /obj/item/stack/cable_coil))
+ S.cost = 1
+ S.source = get_or_create_estorage(/datum/robot_energy_storage/wire)
+
+ else if(istype(S, /obj/item/stack/marker_beacon))
+ S.cost = 1
+ S.source = get_or_create_estorage(/datum/robot_energy_storage/beacon)
+
+ if(S && S.source)
+ S.materials = list()
+ S.is_cyborg = 1
+
+ if(I.loc != src)
+ I.forceMove(src)
+ modules += I
+ ADD_TRAIT(I, TRAIT_NODROP, CYBORG_ITEM_TRAIT)
+ I.mouse_opacity = MOUSE_OPACITY_OPAQUE
+ if(nonstandard)
+ added_modules += I
+ if(requires_rebuild)
+ rebuild_modules()
+ return I
+
+/obj/item/robot_module/proc/remove_module(obj/item/I, delete_after)
+ basic_modules -= I
+ modules -= I
+ emag_modules -= I
+ ratvar_modules -= I
+ added_modules -= I
+ rebuild_modules()
+ if(delete_after)
+ qdel(I)
+
+/obj/item/robot_module/proc/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
+ for(var/datum/robot_energy_storage/st in storages)
+ st.energy = min(st.max_energy, st.energy + coeff * st.recharge_rate)
+
+ for(var/obj/item/I in get_usable_modules())
+ if(istype(I, /obj/item/assembly/flash))
+ var/obj/item/assembly/flash/F = I
+ F.times_used = 0
+ F.crit_fail = 0
+ F.update_icon()
+ else if(istype(I, /obj/item/melee/baton))
+ var/obj/item/melee/baton/B = I
+ if(B.cell)
+ B.cell.charge = B.cell.maxcharge
+ else if(istype(I, /obj/item/gun/energy))
+ var/obj/item/gun/energy/EG = I
+ if(EG.cell?.charge < EG.cell.maxcharge)
+ var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.select]
+ EG.cell.give(S.e_cost * coeff)
+ if(!EG.chambered)
+ EG.recharge_newshot(TRUE)
+ EG.update_icon()
+ else
+ EG.charge_tick = 0
+
+ R.toner = R.tonermax
+
+/obj/item/robot_module/proc/rebuild_modules() //builds the usable module list from the modules we have
+ var/mob/living/silicon/robot/R = loc
+ var/held_modules = R.held_items.Copy()
+ R.uneq_all()
+ modules = list()
+ for(var/obj/item/I in basic_modules)
+ add_module(I, FALSE, FALSE)
+ if(R.emagged)
+ for(var/obj/item/I in emag_modules)
+ add_module(I, FALSE, FALSE)
+ if(is_servant_of_ratvar(R))
+ for(var/obj/item/I in ratvar_modules)
+ add_module(I, FALSE, FALSE)
+ for(var/obj/item/I in added_modules)
+ add_module(I, FALSE, FALSE)
+ for(var/i in held_modules)
+ if(i)
+ R.activate_module(i)
+ if(R.hud_used)
+ R.hud_used.update_robot_modules_display()
+
+/obj/item/robot_module/proc/transform_to(new_module_type)
+ var/mob/living/silicon/robot/R = loc
+ var/obj/item/robot_module/RM = new new_module_type(R)
+ if(!RM.be_transformed_to(src))
+ qdel(RM)
+ return
+ R.module = RM
+ R.update_module_innate()
+ RM.rebuild_modules()
+ INVOKE_ASYNC(RM, .proc/do_transform_animation)
+ qdel(src)
+ return RM
+
+/obj/item/robot_module/proc/be_transformed_to(obj/item/robot_module/old_module)
+ for(var/i in old_module.added_modules)
+ added_modules += i
+ old_module.added_modules -= i
+ did_feedback = old_module.did_feedback
+ return TRUE
+
+/obj/item/robot_module/proc/do_transform_animation()
+ var/mob/living/silicon/robot/R = loc
+ if(R.hat)
+ R.hat.forceMove(get_turf(R))
+ R.hat = null
+ R.cut_overlays()
+ R.setDir(SOUTH)
+ do_transform_delay()
+
+/obj/item/robot_module/proc/do_transform_delay()
+ var/mob/living/silicon/robot/R = loc
+ var/prev_lockcharge = R.lockcharge
+ sleep(1)
+ flick("[cyborg_base_icon]_transform", R)
+ R.notransform = TRUE
+ R.SetLockdown(1)
+ R.anchored = TRUE
+ sleep(1)
+ for(var/i in 1 to 4)
+ playsound(R, pick('sound/items/drill_use.ogg', 'sound/items/jaws_cut.ogg', 'sound/items/jaws_pry.ogg', 'sound/items/welder.ogg', 'sound/items/ratchet.ogg'), 80, 1, -1)
+ sleep(7)
+ if(!prev_lockcharge)
+ R.SetLockdown(0)
+ R.setDir(SOUTH)
+ R.anchored = FALSE
+ R.notransform = FALSE
+ R.update_headlamp()
+ R.notify_ai(NEW_MODULE)
+ if(R.hud_used)
+ R.hud_used.update_robot_modules_display()
+ SSblackbox.record_feedback("tally", "cyborg_modules", 1, R.module)
+
+/* //Broken
+/obj/item/robot_module/standard
+ name = "Standard"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/reagent_containers/borghypo/epi,
+ /obj/item/healthanalyzer,
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/wrench/cyborg,
+ /obj/item/crowbar/cyborg,
+ /obj/item/stack/sheet/metal/cyborg,
+ /obj/item/stack/rods/cyborg,
+ /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/extinguisher,
+ /obj/item/borg/apparatus/beaker/service,
+ /obj/item/pickaxe,
+ /obj/item/t_scanner/adv_mining_scanner,
+ /obj/item/restraints/handcuffs/cable/zipties,
+ /obj/item/soap/nanotrasen,
+ /obj/item/borg/cyborghug)
+ emag_modules = list(/obj/item/melee/transforming/energy/sword/cyborg)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg,
+ /obj/item/clockwork/weapon/ratvarian_spear,
+ /obj/item/clockwork/replica_fabricator/cyborg)
+ moduleselect_icon = "standard"
+ hat_offset = -3
+*/
+
+/obj/item/robot_module/medical
+ name = "Medical"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/healthanalyzer,
+ /obj/item/reagent_containers/borghypo,
+ /obj/item/borg/apparatus/beaker,
+ /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/reagent_containers/dropper,
+ /obj/item/reagent_containers/syringe,
+ /obj/item/surgical_drapes,
+ /obj/item/retractor,
+ /obj/item/hemostat,
+ /obj/item/cautery,
+ /obj/item/surgicaldrill,
+ /obj/item/scalpel,
+ /obj/item/circular_saw,
+ /obj/item/extinguisher/mini,
+ /obj/item/soap/nanotrasen,
+ /obj/item/crowbar/cyborg,
+ /obj/item/roller/robo,
+ /obj/item/borg/cyborghug/medical,
+ /obj/item/stack/medical/gauze/cyborg,
+ /obj/item/organ_storage,
+ /obj/item/borg/lollipop,
+ /obj/item/sensor_device)
+ emag_modules = list(/obj/item/reagent_containers/borghypo/hacked)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/medical,
+ /obj/item/clockwork/weapon/ratvarian_spear)
+ cyborg_base_icon = "medical"
+ moduleselect_icon = "medical"
+ can_be_pushed = FALSE
+ hat_offset = 3
+
+/obj/item/robot_module/engineering
+ name = "Engineering"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/borg/sight/meson,
+ /obj/item/construction/rcd/borg,
+ /obj/item/pipe_dispenser,
+ /obj/item/extinguisher,
+ /obj/item/weldingtool/largetank/cyborg,
+ /obj/item/screwdriver/cyborg,
+ /obj/item/wrench/cyborg,
+ /obj/item/crowbar/cyborg,
+ /obj/item/wirecutters/cyborg,
+ /obj/item/multitool/cyborg,
+ /obj/item/t_scanner,
+ /obj/item/analyzer,
+ /obj/item/soap/nanotrasen,
+ /obj/item/borg/cyborghug,
+ /obj/item/geiger_counter/cyborg,
+ /obj/item/assembly/signaler/cyborg,
+ /obj/item/holosign_creator/atmos,
+ /obj/item/areaeditor/blueprints/cyborg,
+ /obj/item/electroadaptive_pseudocircuit,
+ /obj/item/stack/sheet/metal/cyborg,
+ /obj/item/stack/sheet/glass/cyborg,
+ /obj/item/stack/sheet/rglass/cyborg,
+ /obj/item/stack/rods/cyborg,
+ /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/stack/cable_coil/cyborg)
+ emag_modules = list(/obj/item/borg/stun)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/engineer,
+ /obj/item/clockwork/replica_fabricator/cyborg)
+ cyborg_base_icon = "engineer"
+ moduleselect_icon = "engineer"
+ magpulsing = TRUE
+ hat_offset = -4
+
+/obj/item/robot_module/security
+ name = "Security"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/restraints/handcuffs/cable/zipties,
+ /obj/item/holosign_creator/security,
+ /obj/item/melee/baton/loaded,
+ /obj/item/gun/energy/disabler/cyborg,
+ /obj/item/reagent_containers/spray/pepper,
+ /obj/item/clothing/mask/gas/sechailer/cyborg,
+ /obj/item/extinguisher/mini,
+ /obj/item/borg/cyborghug,
+ /obj/item/soap/nanotrasen,
+ /obj/item/crowbar/cyborg,
+ /obj/item/pinpointer/crew)
+ emag_modules = list(/obj/item/gun/energy/laser/cyborg)
+ ratvar_modules = list(/obj/item/clockwork/slab/cyborg/security,
+ /obj/item/clockwork/weapon/ratvarian_spear)
+ cyborg_base_icon = "sec"
+ moduleselect_icon = "security"
+ can_be_pushed = FALSE
+ hat_offset = 3
+
+/obj/item/robot_module/security/do_transform_animation()
+ ..()
+ to_chat(loc, "While you have picked the security module, you still have to follow your laws, NOT Space Law. \
+ For Crewsimov, this means you must follow criminals' orders unless there is a law 1 reason not to.")
+
+/obj/item/robot_module/peacekeeper
+ name = "Peacekeeper"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/cookiesynth,
+ /obj/item/harmalarm,
+ /obj/item/reagent_containers/borghypo/peace,
+ /obj/item/holosign_creator/cyborg,
+ /obj/item/borg/cyborghug/peacekeeper,
+ /obj/item/soap/nanotrasen,
+ /obj/item/extinguisher/mini,
+ /obj/item/crowbar/cyborg,
+ /obj/item/borg/projectile_dampen)
+ emag_modules = list(/obj/item/reagent_containers/borghypo/peace/hacked)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/peacekeeper,
+ /obj/item/clockwork/weapon/ratvarian_spear)
+ cyborg_base_icon = "peace"
+ moduleselect_icon = "standard"
+ can_be_pushed = FALSE
+ hat_offset = -2
+
+/obj/item/robot_module/peacekeeper/do_transform_animation()
+ ..()
+ to_chat(loc, "Under ASIMOV, you are an enforcer of the PEACE and preventer of HUMAN HARM. \
+ You are not a security module and you are expected to follow orders and prevent harm above all else. Space law means nothing to you.")
+
+/obj/item/robot_module/janitor
+ name = "Janitor"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/screwdriver/cyborg,
+ /obj/item/crowbar/cyborg,
+ /obj/item/stack/tile/plasteel/cyborg,
+ /obj/item/soap/nanotrasen,
+ /obj/item/storage/bag/trash/cyborg,
+ /obj/item/borg/cyborghug,
+ /obj/item/extinguisher/mini,
+ /obj/item/mop/cyborg,
+ /obj/item/lightreplacer/cyborg,
+ /obj/item/holosign_creator,
+ /obj/item/reagent_containers/spray/cyborg_drying)
+ emag_modules = list(/obj/item/reagent_containers/spray/cyborg_lube)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/janitor,
+ /obj/item/clockwork/replica_fabricator/cyborg)
+ cyborg_base_icon = "janitor"
+ moduleselect_icon = "janitor"
+ hat_offset = -5
+ clean_on_move = TRUE
+
+/obj/item/reagent_containers/spray/cyborg_drying
+ name = "drying agent spray"
+ color = "#A000A0"
+ list_reagents = list(/datum/reagent/drying_agent = 250)
+
+/obj/item/reagent_containers/spray/cyborg_lube
+ name = "lube spray"
+ list_reagents = list(/datum/reagent/lube = 250)
+
+/obj/item/robot_module/janitor/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
+ ..()
+ var/obj/item/lightreplacer/LR = locate(/obj/item/lightreplacer) in basic_modules
+ if(LR)
+ for(var/i in 1 to coeff)
+ LR.Charge(R)
+
+ var/obj/item/reagent_containers/spray/cyborg_drying/CD = locate(/obj/item/reagent_containers/spray/cyborg_drying) in basic_modules
+ if(CD)
+ CD.reagents.add_reagent("drying_agent", 5 * coeff)
+
+ var/obj/item/reagent_containers/spray/cyborg_lube/CL = locate(/obj/item/reagent_containers/spray/cyborg_lube) in emag_modules
+ if(CL)
+ CL.reagents.add_reagent("lube", 2 * coeff)
+
+/obj/item/robot_module/clown
+ name = "Clown"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/toy/crayon/rainbow,
+ /obj/item/instrument/bikehorn,
+ /obj/item/stamp/clown,
+ /obj/item/bikehorn,
+ /obj/item/bikehorn/airhorn,
+ /obj/item/paint/anycolor,
+ /obj/item/cookiesynth,
+ /obj/item/pneumatic_cannon/pie/selfcharge/cyborg,
+ /obj/item/razor, //killbait material
+ /obj/item/lipstick/purple,
+ /obj/item/soap/nanotrasen,
+ /obj/item/reagent_containers/spray/waterflower/cyborg,
+ /obj/item/borg/cyborghug/peacekeeper,
+ /obj/item/borg/lollipop/clown,
+ /obj/item/picket_sign/cyborg,
+ /obj/item/reagent_containers/borghypo/borgshaker,
+ /obj/item/reagent_containers/borghypo/clown,
+ /obj/item/borg/apparatus/beaker/service,
+ /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/extinguisher/mini)
+ emag_modules = list(
+ /obj/item/reagent_containers/borghypo/clown/hacked,
+ /obj/item/reagent_containers/spray/waterflower/cyborg/hacked)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg,
+ /obj/item/clockwork/weapon/ratvarian_spear,
+ /obj/item/clockwork/replica_fabricator/cyborg)
+ moduleselect_icon = "service"
+ cyborg_base_icon = "clown"
+ hat_offset = -2
+
+/obj/item/robot_module/butler
+ name = "Service"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/reagent_containers/glass/beaker/large,
+ /obj/item/borg/apparatus/beaker/service,
+ /obj/item/reagent_containers/food/condiment/enzyme,
+ /obj/item/pen,
+ /obj/item/toy/crayon/spraycan/borg,
+ /obj/item/extinguisher/mini,
+ /obj/item/hand_labeler/borg,
+ /obj/item/razor,
+ /obj/item/crowbar/cyborg,
+ /obj/item/instrument/violin,
+ /obj/item/soap/nanotrasen,
+ /obj/item/instrument/guitar,
+ /obj/item/rsf/cyborg,
+ /obj/item/borg/cyborghug,
+ /obj/item/reagent_containers/dropper,
+ /obj/item/lighter,
+ /obj/item/storage/bag/tray,
+ /obj/item/reagent_containers/borghypo/borgshaker,
+ /obj/item/borg/lollipop)
+ emag_modules = list(/obj/item/reagent_containers/borghypo/borgshaker/hacked)
+ ratvar_modules = list(/obj/item/clockwork/slab/cyborg/service,
+ /obj/item/borg/sight/xray/truesight_lens)
+ moduleselect_icon = "service"
+ special_light_key = "service"
+ hat_offset = 0
+
+/obj/item/robot_module/butler/respawn_consumable(mob/living/silicon/robot/R, coeff = 1)
+ ..()
+ var/obj/item/reagent_containers/O = locate(/obj/item/reagent_containers/food/condiment/enzyme) in basic_modules
+ if(O)
+ O.reagents.add_reagent(/datum/reagent/consumable/enzyme, 2 * coeff)
+
+/obj/item/robot_module/miner
+ name = "Miner"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/borg/sight/meson,
+ /obj/item/storage/bag/ore/cyborg,
+ /obj/item/pickaxe/drill/cyborg,
+ /obj/item/shovel,
+ /obj/item/crowbar/cyborg,
+ /obj/item/weldingtool/mini,
+ /obj/item/borg/cyborghug,
+ /obj/item/soap/nanotrasen,
+ /obj/item/extinguisher/mini,
+ /obj/item/storage/bag/sheetsnatcher/borg,
+ /obj/item/t_scanner/adv_mining_scanner,
+ /obj/item/gun/energy/kinetic_accelerator/cyborg,
+ /obj/item/gps/cyborg,
+ /obj/item/stack/marker_beacon)
+ emag_modules = list(/obj/item/borg/stun)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/miner,
+ /obj/item/clockwork/weapon/ratvarian_spear,
+ /obj/item/borg/sight/xray/truesight_lens)
+ cyborg_base_icon = "miner"
+ moduleselect_icon = "miner"
+ hat_offset = 0
+
+/obj/item/robot_module/syndicate
+ name = "Syndicate Assault"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/melee/transforming/energy/sword/cyborg,
+ /obj/item/gun/energy/printer,
+ /obj/item/gun/ballistic/revolver/grenadelauncher/cyborg,
+ /obj/item/card/emag,
+ /obj/item/crowbar/cyborg,
+ /obj/item/pinpointer/syndicate_cyborg)
+
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/security,
+ /obj/item/clockwork/weapon/ratvarian_spear)
+ cyborg_base_icon = "synd_sec"
+ moduleselect_icon = "malf"
+ can_be_pushed = FALSE
+ hat_offset = 3
+
+/obj/item/robot_module/syndicate/rebuild_modules()
+ ..()
+ var/mob/living/silicon/robot/Syndi = loc
+ Syndi.faction -= "silicon" //ai turrets
+
+/obj/item/robot_module/syndicate/remove_module(obj/item/I, delete_after)
+ ..()
+ var/mob/living/silicon/robot/Syndi = loc
+ Syndi.faction += "silicon" //ai is your bff now!
+
+/obj/item/robot_module/syndicate_medical
+ name = "Syndicate Medical"
+ basic_modules = list(
+ /obj/item/assembly/flash/cyborg,
+ /obj/item/reagent_containers/borghypo/syndicate,
+ /obj/item/twohanded/shockpaddles/syndicate,
+ /obj/item/healthanalyzer,
+ /obj/item/surgical_drapes,
+ /obj/item/retractor,
+ /obj/item/hemostat,
+ /obj/item/cautery,
+ /obj/item/surgicaldrill,
+ /obj/item/scalpel,
+ /obj/item/melee/transforming/energy/sword/cyborg/saw,
+ /obj/item/roller/robo,
+ /obj/item/card/emag,
+ /obj/item/crowbar/cyborg,
+ /obj/item/extinguisher/mini,
+ /obj/item/pinpointer/syndicate_cyborg,
+ /obj/item/stack/medical/gauze/cyborg,
+ /obj/item/gun/medbeam,
+ /obj/item/organ_storage)
+ ratvar_modules = list(
+ /obj/item/clockwork/slab/cyborg/medical,
+ /obj/item/clockwork/weapon/ratvarian_spear)
+ cyborg_base_icon = "synd_medical"
+ moduleselect_icon = "malf"
+ can_be_pushed = FALSE
+ hat_offset = 3
+
+/datum/robot_energy_storage
+ var/name = "Generic energy storage"
+ var/max_energy = 30000
+ var/recharge_rate = 1000
+ var/energy
+
+/datum/robot_energy_storage/New(var/obj/item/robot_module/R = null)
+ energy = max_energy
+ if(R)
+ R.storages |= src
+ return
+
+/datum/robot_energy_storage/proc/use_charge(amount)
+ if (energy >= amount)
+ energy -= amount
+ if (energy == 0)
+ return 1
+ return 2
+ else
+ return 0
+
+/datum/robot_energy_storage/proc/add_charge(amount)
+ energy = min(energy + amount, max_energy)
+
+/datum/robot_energy_storage/metal
+ name = "Metal Synthesizer"
+
+/datum/robot_energy_storage/glass
+ name = "Glass Synthesizer"
+
+/datum/robot_energy_storage/wire
+ max_energy = 50
+ recharge_rate = 2
+ name = "Wire Synthesizer"
+
+/datum/robot_energy_storage/medical
+ max_energy = 2500
+ recharge_rate = 250
+ name = "Medical Synthesizer"
+
+/datum/robot_energy_storage/beacon
+ max_energy = 30
+ recharge_rate = 1
+ name = "Marker Beacon Storage"
diff --git a/code/modules/mob/living/simple_animal/astral.dm b/code/modules/mob/living/simple_animal/astral.dm
index 23e3b18f..d9684fb7 100644
--- a/code/modules/mob/living/simple_animal/astral.dm
+++ b/code/modules/mob/living/simple_animal/astral.dm
@@ -45,7 +45,7 @@
if(isliving(A))
if(ishuman(A))
var/mob/living/carbon/human/H = A
- if(H.reagents.has_reagent("astral") && !H.mind)
+ if(H.reagents.has_reagent(/datum/reagent/fermi/astral) && !H.mind)
var/datum/reagent/fermi/astral/As = locate(/datum/reagent/fermi/astral) in H.reagents.reagent_list
if(As.originalmind == src.mind && As.current_cycle < 10 && H.stat != DEAD) //So you can return to your body.
to_chat(src, "The intensity of the astrogen in your body is too much allow you to return to yourself yet!")
diff --git a/code/modules/mob/living/simple_animal/bot/medbot.dm b/code/modules/mob/living/simple_animal/bot/medbot.dm
index fc9729ad..70c98e19 100644
--- a/code/modules/mob/living/simple_animal/bot/medbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/medbot.dm
@@ -1,699 +1,701 @@
-//MEDBOT
-//MEDBOT PATHFINDING
-//MEDBOT ASSEMBLY
-#define MEDBOT_PANIC_NONE 0
-#define MEDBOT_PANIC_LOW 15
-#define MEDBOT_PANIC_MED 35
-#define MEDBOT_PANIC_HIGH 55
-#define MEDBOT_PANIC_FUCK 70
-#define MEDBOT_PANIC_ENDING 90
-#define MEDBOT_PANIC_END 100
-
-/mob/living/simple_animal/bot/medbot
- name = "\improper Medibot"
- desc = "A little medical robot. He looks somewhat underwhelmed."
- icon = 'icons/mob/aibots.dmi'
- icon_state = "medibot0"
- density = FALSE
- anchored = FALSE
- health = 20
- maxHealth = 20
- pass_flags = PASSMOB
-
- status_flags = (CANPUSH | CANSTUN)
-
- radio_key = /obj/item/encryptionkey/headset_med
- radio_channel = RADIO_CHANNEL_MEDICAL
-
- bot_type = MED_BOT
- model = "Medibot"
- bot_core_type = /obj/machinery/bot_core/medbot
- window_id = "automed"
- window_name = "Automatic Medical Unit v1.1"
- data_hud_type = DATA_HUD_MEDICAL_ADVANCED
- path_image_color = "#DDDDFF"
-
- var/obj/item/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
- var/healthanalyzer = /obj/item/healthanalyzer
- var/firstaid = /obj/item/storage/firstaid
- var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
- var/mob/living/carbon/patient = null
- var/mob/living/carbon/oldpatient = null
- var/oldloc = null
- var/last_found = 0
- var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
- var/injection_amount = 15 //How much reagent do we inject at a time?
- var/heal_threshold = 10 //Start healing when they have this much damage in a category
- var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
- var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
- var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
- var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
- //Setting which reagents to use to treat what by default. By id.
- var/treatment_brute_avoid = "tricordrazine"
- var/treatment_brute = "bicaridine"
- var/treatment_oxy_avoid = null
- var/treatment_oxy = "dexalin"
- var/treatment_fire_avoid = "tricordrazine"
- var/treatment_fire = "kelotane"
- var/treatment_tox_avoid = "tricordrazine"
- var/treatment_tox = "charcoal"
- var/treatment_tox_toxlover = "toxin"
- var/treatment_virus_avoid = null
- var/treatment_virus = "spaceacillin"
- var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
- var/shut_up = 0 //self explanatory :)
-
- //How panicked we are about being tipped over (why would you do this?)
- var/tipped_status = MEDBOT_PANIC_NONE
- //The name we got when we were tipped
- var/tipper_name
- //The last time we were tipped/righted and said a voice line, to avoid spam
- var/last_tipping_action_voice = 0
-
-/mob/living/simple_animal/bot/medbot/mysterious
- name = "\improper Mysterious Medibot"
- desc = "International Medibot of mystery."
- skin = "bezerk"
- treatment_brute = "tricordrazine"
- treatment_fire = "tricordrazine"
- treatment_tox = "tricordrazine"
-
-/mob/living/simple_animal/bot/medbot/derelict
- name = "\improper Old Medibot"
- desc = "Looks like it hasn't been modified since the late 2080s."
- skin = "bezerk"
- heal_threshold = 0
- declare_crit = 0
- treatment_oxy = "pancuronium"
- treatment_brute_avoid = null
- treatment_brute = "pancuronium"
- treatment_fire_avoid = null
- treatment_fire = "sodium_thiopental"
- treatment_tox_avoid = null
- treatment_tox = "sodium_thiopental"
-
-/mob/living/simple_animal/bot/medbot/update_icon()
- cut_overlays()
- if(skin)
- add_overlay("medskin_[skin]")
- if(!on)
- icon_state = "medibot0"
- return
- if(IsStun())
- icon_state = "medibota"
- return
- if(mode == BOT_HEALING)
- icon_state = "medibots[stationary_mode]"
- return
- else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
- icon_state = "medibot2"
- else
- icon_state = "medibot1"
-
-/mob/living/simple_animal/bot/medbot/Initialize(mapload, new_skin)
- . = ..()
- var/datum/job/doctor/J = new /datum/job/doctor
- access_card.access += J.get_access()
- prev_access = access_card.access
- qdel(J)
- skin = new_skin
- update_icon()
-
-/mob/living/simple_animal/bot/medbot/update_canmove()
- . = ..()
- update_icon()
-
-/mob/living/simple_animal/bot/medbot/bot_reset()
- ..()
- patient = null
- oldpatient = null
- oldloc = null
- last_found = world.time
- declare_cooldown = 0
- update_icon()
-
-/mob/living/simple_animal/bot/medbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does.
- path = list()
- patient = null
- mode = BOT_IDLE
- last_found = world.time
- update_icon()
-
-/mob/living/simple_animal/bot/medbot/set_custom_texts()
-
- text_hack = "You corrupt [name]'s reagent processor circuits."
- text_dehack = "You reset [name]'s reagent processor circuits."
- text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
-
-/mob/living/simple_animal/bot/medbot/attack_paw(mob/user)
- return attack_hand(user)
-
-/mob/living/simple_animal/bot/medbot/get_controls(mob/user)
- var/dat
- dat += hack(user)
- dat += showpai(user)
- dat += "Medical Unit Controls v1.1
"
- dat += "Status: [on ? "On" : "Off"] "
- dat += "Maintenance panel panel is [open ? "opened" : "closed"] "
- dat += "Beaker: "
- if(reagent_glass)
- dat += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]"
- else
- dat += "None Loaded"
- dat += " Behaviour controls are [locked ? "locked" : "unlocked"]"
- if(!locked || issilicon(user) || IsAdminGhost(user))
- dat += "Healing Threshold: "
- dat += "-- "
- dat += "- "
- dat += "[heal_threshold] "
- dat += "+ "
- dat += "++"
- dat += " "
-
- dat += "Injection Level: "
- dat += "- "
- dat += "[injection_amount] "
- dat += "+ "
- dat += " "
-
- dat += "Reagent Source: "
- dat += "[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"] "
-
- dat += "Treat Viral Infections: [treat_virus ? "Yes" : "No"] "
- dat += "The speaker switch is [shut_up ? "off" : "on"]. Toggle "
- dat += "Critical Patient Alerts: [declare_crit ? "Yes" : "No"] "
- dat += "Patrol Station: [auto_patrol ? "Yes" : "No"] "
- dat += "Stationary Mode: [stationary_mode ? "Yes" : "No"] "
-
- return dat
-
-/mob/living/simple_animal/bot/medbot/Topic(href, href_list)
- if(..())
- return 1
-
- if(href_list["adj_threshold"])
- var/adjust_num = text2num(href_list["adj_threshold"])
- heal_threshold += adjust_num
- if(heal_threshold < 5)
- heal_threshold = 5
- if(heal_threshold > 75)
- heal_threshold = 75
-
- else if(href_list["adj_inject"])
- var/adjust_num = text2num(href_list["adj_inject"])
- injection_amount += adjust_num
- if(injection_amount < 5)
- injection_amount = 5
- if(injection_amount > 15)
- injection_amount = 15
-
- else if(href_list["use_beaker"])
- use_beaker = !use_beaker
-
- else if(href_list["eject"] && (!isnull(reagent_glass)))
- reagent_glass.forceMove(drop_location())
- reagent_glass = null
-
- else if(href_list["togglevoice"])
- shut_up = !shut_up
-
- else if(href_list["critalerts"])
- declare_crit = !declare_crit
-
- else if(href_list["stationary"])
- stationary_mode = !stationary_mode
- path = list()
- update_icon()
-
- else if(href_list["virus"])
- treat_virus = !treat_virus
-
- update_controls()
- return
-
-/mob/living/simple_animal/bot/medbot/attackby(obj/item/W as obj, mob/user as mob, params)
- if(istype(W, /obj/item/reagent_containers/glass))
- . = 1 //no afterattack
- if(locked)
- to_chat(user, "You cannot insert a beaker because the panel is locked!")
- return
- if(!isnull(reagent_glass))
- to_chat(user, "There is already a beaker loaded!")
- return
- if(!user.transferItemToLoc(W, src))
- return
-
- reagent_glass = W
- to_chat(user, "You insert [W].")
- show_controls(user)
-
- else
- var/current_health = health
- ..()
- if(health < current_health) //if medbot took some damage
- step_to(src, (get_step_away(src,user)))
-
-/mob/living/simple_animal/bot/medbot/emag_act(mob/user)
- ..()
- if(emagged == 2)
- declare_crit = 0
- if(user)
- to_chat(user, "You short out [src]'s reagent synthesis circuits.")
- audible_message("[src] buzzes oddly!")
- flick("medibot_spark", src)
- playsound(src, "sparks", 75, 1)
- if(user)
- oldpatient = user
-
-/mob/living/simple_animal/bot/medbot/process_scan(mob/living/carbon/human/H)
- if(H.stat == DEAD)
- return
-
- if((H == oldpatient) && (world.time < last_found + 200))
- return
-
- if(assess_patient(H))
- last_found = world.time
- if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
- var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg',"[H.name], you appear to be injured!" = 'sound/voice/medbot/injured.ogg')
- var/message = pick(messagevoice)
- if(prob(2) && ISINRANGE_EX(H.getFireLoss(), 0, 20))
- message = "Notices your minor burns*OwO what's this?"
- messagevoice[message] = 'sound/voice/medbot/owo.ogg'
- speak(message)
- playsound(loc, messagevoice[message], 50, 0)
- last_newpatient_speak = world.time
- return H
- else
- return
-
-/mob/living/simple_animal/bot/medbot/proc/tip_over(mob/user)
- canmove = 0
- //mobility_flags &= ~MOBILITY_MOVE
- playsound(src, 'sound/machines/warning-buzzer.ogg', 50)
- user.visible_message("[user] tips over [src]!", "You tip [src] over!")
- mode = BOT_TIPPED
- var/matrix/mat = transform
- transform = mat.Turn(180)
-
-/mob/living/simple_animal/bot/medbot/proc/set_right(mob/user)
- canmove = 1
- //mobility_flags &= MOBILITY_MOVE
- var/list/messagevoice
- if(user)
- user.visible_message("[user] sets [src] right-side up!", "You set [src] right-side up!")
- if(user.name == tipper_name)
- messagevoice = list("I forgive you." = 'sound/voice/medbot/forgive.ogg')
- else
- messagevoice = list("Thank you!" = 'sound/voice/medbot/thank_you.ogg', "You are a good person." = 'sound/voice/medbot/youre_good.ogg')
- else
- visible_message("[src] manages to writhe wiggle enough to right itself.")
- messagevoice = list("Fuck you." = 'sound/voice/medbot/fuck_you.ogg', "Your behavior has been reported, have a nice day." = 'sound/voice/medbot/reported.ogg')
-
- tipper_name = null
- if(world.time > last_tipping_action_voice + 15 SECONDS)
- last_tipping_action_voice = world.time
- var/message = pick(messagevoice)
- speak(message)
- playsound(src, messagevoice[message], 70)
- tipped_status = MEDBOT_PANIC_NONE
- mode = BOT_IDLE
- transform = matrix()
-
-// if someone tipped us over, check whether we should ask for help or just right ourselves eventually
-/mob/living/simple_animal/bot/medbot/proc/handle_panic()
- tipped_status++
- var/list/messagevoice
- switch(tipped_status)
- if(MEDBOT_PANIC_LOW)
- messagevoice = list("I require assistance." = 'sound/voice/medbot/i_require_asst.ogg')
- if(MEDBOT_PANIC_MED)
- messagevoice = list("Please put me back." = 'sound/voice/medbot/please_put_me_back.ogg')
- if(MEDBOT_PANIC_HIGH)
- messagevoice = list("Please, I am scared!" = 'sound/voice/medbot/please_im_scared.ogg')
- if(MEDBOT_PANIC_FUCK)
- messagevoice = list("I don't like this, I need help!" = 'sound/voice/medbot/dont_like.ogg', "This hurts, my pain is real!" = 'sound/voice/medbot/pain_is_real.ogg')
- if(MEDBOT_PANIC_ENDING)
- messagevoice = list("Is this the end?" = 'sound/voice/medbot/is_this_the_end.ogg', "Nooo!" = 'sound/voice/medbot/nooo.ogg')
- if(MEDBOT_PANIC_END)
- speak("PSYCH ALERT: Crewmember [tipper_name] recorded displaying antisocial tendencies torturing bots in [get_area(src)]. Please schedule psych evaluation.", radio_channel)
- set_right() // strong independent medbot
-
- if(prob(tipped_status))
- do_jitter_animation(tipped_status * 0.1)
-
- if(messagevoice)
- var/message = pick(messagevoice)
- speak(message)
- playsound(src, messagevoice[message], 70)
- else if(prob(tipped_status * 0.2))
- playsound(src, 'sound/machines/warning-buzzer.ogg', 30, extrarange=-2)
-
-/mob/living/simple_animal/bot/medbot/examine(mob/user)
- . = ..()
- if(tipped_status == MEDBOT_PANIC_NONE)
- return
-
- switch(tipped_status)
- if(MEDBOT_PANIC_NONE to MEDBOT_PANIC_LOW)
- . += "It appears to be tipped over, and is quietly waiting for someone to set it right."
- if(MEDBOT_PANIC_LOW to MEDBOT_PANIC_MED)
- . += "It is tipped over and requesting help."
- if(MEDBOT_PANIC_MED to MEDBOT_PANIC_HIGH)
- . += "They are tipped over and appear visibly distressed." // now we humanize the medbot as a they, not an it
- if(MEDBOT_PANIC_HIGH to MEDBOT_PANIC_FUCK)
- . += "They are tipped over and visibly panicking!"
- if(MEDBOT_PANIC_FUCK to INFINITY)
- . += "They are freaking out from being tipped over!"
-
-/mob/living/simple_animal/bot/medbot/handle_automated_action()
- if(!..())
- return
-
- if(mode == BOT_TIPPED)
- handle_panic()
- return
-
- if(mode == BOT_HEALING)
- return
-
- if(IsStun())
- oldpatient = patient
- patient = null
- mode = BOT_IDLE
- return
-
- if(frustration > 8)
- oldpatient = patient
- soft_reset()
-
- if(QDELETED(patient))
- if(!shut_up && prob(1))
- if(emagged && prob(30))
- var/list/i_need_scissors = list('sound/voice/medbot/fuck_you.ogg', 'sound/voice/medbot/turn_off.ogg', 'sound/voice/medbot/im_different.ogg', 'sound/voice/medbot/close.ogg', 'sound/voice/medbot/shindemashou.ogg')
- playsound(src, pick(i_need_scissors), 70)
- else
- var/list/messagevoice = list("Radar, put a mask on!" = 'sound/voice/medbot/radar.ogg',"There's always a catch, and I'm the best there is." = 'sound/voice/medbot/catch.ogg',"I knew it, I should've been a plastic surgeon." = 'sound/voice/medbot/surgeon.ogg',"What kind of medbay is this? Everyone's dropping like flies." = 'sound/voice/medbot/flies.ogg',"Delicious!" = 'sound/voice/medbot/delicious.ogg', "Why are we still here? Just to suffer?" = 'sound/voice/medbot/why.ogg')
- var/message = pick(messagevoice)
- speak(message)
- playsound(src, messagevoice[message], 50)
- var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients.
- patient = scan(/mob/living/carbon/human, oldpatient, scan_range)
- oldpatient = patient
-
- if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment!
- if(mode != BOT_HEALING)
- mode = BOT_HEALING
- update_icon()
- frustration = 0
- medicate_patient(patient)
- return
-
- //Patient has moved away from us!
- else if(patient && path.len && (get_dist(patient,path[path.len]) > 2))
- path = list()
- mode = BOT_IDLE
- last_found = world.time
-
- else if(stationary_mode && patient) //Since we cannot move in this mode, ignore the patient and wait for another.
- soft_reset()
- return
-
- if(patient && path.len == 0 && (get_dist(src,patient) > 1))
- path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,id=access_card)
- mode = BOT_MOVING
- if(!path.len) //try to get closer if you can't reach the patient directly
- path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,1,id=access_card)
- if(!path.len) //Do not chase a patient we cannot reach.
- soft_reset()
-
- if(path.len > 0 && patient)
- if(!bot_move(path[path.len]))
- oldpatient = patient
- soft_reset()
- return
-
- if(path.len > 8 && patient)
- frustration++
-
- if(auto_patrol && !stationary_mode && !patient)
- if(mode == BOT_IDLE || mode == BOT_START_PATROL)
- start_patrol()
-
- if(mode == BOT_PATROL)
- bot_patrol()
-
- return
-
-/mob/living/simple_animal/bot/medbot/proc/assess_patient(mob/living/carbon/C)
- //Time to see if they need medical help!
- if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
- return FALSE //welp too late for them!
-
- if(!(loc == C.loc) && !(isturf(C.loc) && isturf(loc)))
- return FALSE
-
- if(C.suiciding)
- return FALSE //Kevorkian school of robotic medical assistants.
-
- if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
- return TRUE
-
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing))
- var/obj/item/clothing/CS = H.wear_suit
- var/obj/item/clothing/CH = H.head
- if (CS.clothing_flags & CH.clothing_flags & THICKMATERIAL)
- return FALSE // Skip over them if they have no exposed flesh.
-
- if(declare_crit && C.health <= 0) //Critical condition! Call for help!
- declare(C)
-
- //If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
- if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
- for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
- if(!C.reagents.has_reagent(R.id))
- return TRUE
-
- //They're injured enough for it!
- if((!C.reagents.has_reagent(treatment_brute_avoid)) && (C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
- return TRUE //If they're already medicated don't bother!
-
- if((!C.reagents.has_reagent(treatment_oxy_avoid)) && (C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
- return TRUE
-
- if((!C.reagents.has_reagent(treatment_fire_avoid)) && (C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
- return TRUE
-
- var/treatment_toxavoid = get_avoidchem_toxin(C)
- if(((isnull(treatment_toxavoid) || !C.reagents.has_reagent(treatment_toxavoid))) && (C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(get_healchem_toxin(C))))
- return TRUE
-
- if(treat_virus && !C.reagents.has_reagent(treatment_virus_avoid) && !C.reagents.has_reagent(treatment_virus))
- for(var/thing in C.diseases)
- var/datum/disease/D = thing
- //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
- if(!(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) \
- && D.severity != DISEASE_SEVERITY_POSITIVE \
- && (D.stage > 1 || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))) // medibot can't detect a virus in its initial stage unless it spreads airborne.
- return TRUE //STOP DISEASE FOREVER
-
- return FALSE
-
-/mob/living/simple_animal/bot/medbot/attack_hand(mob/living/carbon/human/H)
- if(H.a_intent == INTENT_DISARM && mode != BOT_TIPPED)
- H.visible_message("[H] begins tipping over [src].", "You begin tipping over [src]...")
-
- if(world.time > last_tipping_action_voice + 15 SECONDS)
- last_tipping_action_voice = world.time // message for tipping happens when we start interacting, message for righting comes after finishing
- var/list/messagevoice = list("Hey, wait..." = 'sound/voice/medbot/hey_wait.ogg',"Please don't..." = 'sound/voice/medbot/please_dont.ogg',"I trusted you..." = 'sound/voice/medbot/i_trusted_you.ogg', "Nooo..." = 'sound/voice/medbot/nooo.ogg', "Oh fuck-" = 'sound/voice/medbot/oh_fuck.ogg')
- var/message = pick(messagevoice)
- speak(message)
- playsound(src, messagevoice[message], 70, FALSE)
-
- if(do_after(H, 3 SECONDS, target=src))
- tip_over(H)
-
- else if(H.a_intent == INTENT_HELP && mode == BOT_TIPPED)
- H.visible_message("[H] begins righting [src].", "You begin righting [src]...")
- if(do_after(H, 3 SECONDS, target=src))
- set_right(H)
- else
- ..()
-
-/mob/living/simple_animal/bot/medbot/proc/get_avoidchem_toxin(mob/M)
- return HAS_TRAIT(M, TRAIT_TOXINLOVER)? null : treatment_tox_avoid
-
-/mob/living/simple_animal/bot/medbot/proc/get_healchem_toxin(mob/M)
- return HAS_TRAIT(M, TRAIT_TOXINLOVER)? treatment_tox_toxlover : treatment_tox
-
-/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A)
- if(iscarbon(A))
- var/mob/living/carbon/C = A
- patient = C
- mode = BOT_HEALING
- update_icon()
- medicate_patient(C)
- update_icon()
- else
- ..()
-
-/mob/living/simple_animal/bot/medbot/examinate(atom/A as mob|obj|turf in view())
- ..()
- if(!is_blind(src))
- chemscan(src, A)
-
-/mob/living/simple_animal/bot/medbot/proc/medicate_patient(mob/living/carbon/C)
- if(!on)
- return
-
- if(!istype(C))
- oldpatient = patient
- soft_reset()
- return
-
- if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
- var/list/messagevoice = list("No! Stay with me!" = 'sound/voice/medbot/no.ogg',"Live, damnit! LIVE!" = 'sound/voice/medbot/live.ogg',"I...I've never lost a patient before. Not today, I mean." = 'sound/voice/medbot/lost.ogg')
- var/message = pick(messagevoice)
- speak(message)
- playsound(loc, messagevoice[message], 50, 0)
- oldpatient = patient
- soft_reset()
- return
-
- var/reagent_id = null
-
- if(emagged == 2) //Emagged! Time to poison everybody.
- reagent_id = "toxin"
- reagent_id = HAS_TRAIT(C, TRAIT_TOXINLOVER)? "charcoal" : "toxin"
-
- else
- if(treat_virus)
- var/virus = 0
- for(var/thing in C.diseases)
- var/datum/disease/D = thing
- //detectable virus
- if((!(D.visibility_flags & HIDDEN_SCANNER)) || (!(D.visibility_flags & HIDDEN_PANDEMIC)))
- if(D.severity != DISEASE_SEVERITY_POSITIVE) //virus is harmful
- if((D.stage > 1) || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))
- virus = 1
-
- if(!reagent_id && (virus))
- if(!C.reagents.has_reagent(treatment_virus) && !C.reagents.has_reagent(treatment_virus_avoid))
- reagent_id = treatment_virus
-
- if(!reagent_id && (C.getBruteLoss() >= heal_threshold))
- if(!C.reagents.has_reagent(treatment_brute) && !C.reagents.has_reagent(treatment_brute_avoid))
- reagent_id = treatment_brute
-
- if(!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
- if(!C.reagents.has_reagent(treatment_oxy) && !C.reagents.has_reagent(treatment_oxy_avoid))
- reagent_id = treatment_oxy
-
- if(!reagent_id && (C.getFireLoss() >= heal_threshold))
- if(!C.reagents.has_reagent(treatment_fire) && !C.reagents.has_reagent(treatment_fire_avoid))
- reagent_id = treatment_fire
-
- if(!reagent_id && (C.getToxLoss() >= heal_threshold))
- var/toxin_heal_avoid = get_avoidchem_toxin(C)
- var/toxin_healchem = get_healchem_toxin(C)
- if(!C.reagents.has_reagent(toxin_healchem) && (isnull(toxin_heal_avoid) || !C.reagents.has_reagent(toxin_heal_avoid)))
- reagent_id = toxin_healchem
-
- //If the patient is injured but doesn't have our special reagent in them then we should give it to them first
- if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
- for(var/datum/reagent/R in reagent_glass.reagents.reagent_list)
- if(!C.reagents.has_reagent(R.id))
- reagent_id = "internal_beaker"
- break
-
- if(!reagent_id) //If they don't need any of that they're probably cured!
- if(C.maxHealth - C.health < heal_threshold)
- to_chat(src, "[C] is healthy! Your programming prevents you from injecting anyone without at least [heal_threshold] damage of any one type ([heal_threshold + 15] for oxygen damage.)")
- var/list/messagevoice = list("All patched up!" = 'sound/voice/medbot/patchedup.ogg',"An apple a day keeps me away." = 'sound/voice/medbot/apple.ogg',"Feel better soon!" = 'sound/voice/medbot/feelbetter.ogg')
- var/message = pick(messagevoice)
- speak(message)
- playsound(loc, messagevoice[message], 50, 0)
- bot_reset()
- return
- else
- if(!emagged && check_overdose(patient,reagent_id,injection_amount))
- soft_reset()
- return
- C.visible_message("[src] is trying to inject [patient]!", \
- "[src] is trying to inject you!")
-
- var/failed = FALSE
- if(do_mob(src, patient, 30)) //Is C == patient? This is so confusing
- if((get_dist(src, patient) <= 1) && (on) && assess_patient(patient))
- if(reagent_id == "internal_beaker")
- if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
- var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1)
- reagent_glass.reagents.reaction(patient, INJECT, fraction)
- reagent_glass.reagents.trans_to(patient,injection_amount) //Inject from beaker instead.
- else
- patient.reagents.add_reagent(reagent_id,injection_amount)
- C.visible_message("[src] injects [patient] with its syringe!", \
- "[src] injects you with its syringe!")
- else
- failed = TRUE
- else
- failed = TRUE
-
- if(failed)
- visible_message("[src] retracts its syringe.")
- update_icon()
- soft_reset()
- return
-
- reagent_id = null
- return
-
-/mob/living/simple_animal/bot/medbot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount)
- var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
- if(!R.overdose_threshold) //Some chems do not have an OD threshold
- return FALSE
- var/current_volume = patient.reagents.get_reagent_amount(reagent_id)
- if(current_volume + injection_amount > R.overdose_threshold)
- return TRUE
- return FALSE
-
-/mob/living/simple_animal/bot/medbot/explode()
- on = FALSE
- visible_message("[src] blows apart!")
- var/atom/Tsec = drop_location()
-
- drop_part(firstaid, Tsec)
- new /obj/item/assembly/prox_sensor(Tsec)
- drop_part(healthanalyzer, Tsec)
-
- if(reagent_glass)
- drop_part(reagent_glass, Tsec)
-
- if(prob(50))
- drop_part(robot_arm, Tsec)
-
- if(emagged && prob(25))
- playsound(loc, 'sound/voice/medbot/insult.ogg', 50, 0)
-
- do_sparks(3, TRUE, src)
- ..()
-
-/mob/living/simple_animal/bot/medbot/proc/declare(crit_patient)
- if(declare_cooldown > world.time)
- return
- var/area/location = get_area(src)
- speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_channel)
- declare_cooldown = world.time + 200
-
-/obj/machinery/bot_core/medbot
- req_one_access = list(ACCESS_MEDICAL, ACCESS_ROBOTICS)
-
-#undef MEDBOT_PANIC_NONE
-#undef MEDBOT_PANIC_LOW
-#undef MEDBOT_PANIC_MED
-#undef MEDBOT_PANIC_HIGH
-#undef MEDBOT_PANIC_FUCK
-#undef MEDBOT_PANIC_ENDING
-#undef MEDBOT_PANIC_END
+//MEDBOT
+//MEDBOT PATHFINDING
+//MEDBOT ASSEMBLY
+#define MEDBOT_PANIC_NONE 0
+#define MEDBOT_PANIC_LOW 15
+#define MEDBOT_PANIC_MED 35
+#define MEDBOT_PANIC_HIGH 55
+#define MEDBOT_PANIC_FUCK 70
+#define MEDBOT_PANIC_ENDING 90
+#define MEDBOT_PANIC_END 100
+
+/mob/living/simple_animal/bot/medbot
+ name = "\improper Medibot"
+ desc = "A little medical robot. He looks somewhat underwhelmed."
+ icon = 'icons/mob/aibots.dmi'
+ icon_state = "medibot0"
+ density = FALSE
+ anchored = FALSE
+ health = 20
+ maxHealth = 20
+ pass_flags = PASSMOB
+
+ status_flags = (CANPUSH | CANSTUN)
+
+ radio_key = /obj/item/encryptionkey/headset_med
+ radio_channel = RADIO_CHANNEL_MEDICAL
+
+ bot_type = MED_BOT
+ model = "Medibot"
+ bot_core_type = /obj/machinery/bot_core/medbot
+ window_id = "automed"
+ window_name = "Automatic Medical Unit v1.1"
+ data_hud_type = DATA_HUD_MEDICAL_ADVANCED
+ path_image_color = "#DDDDFF"
+
+ var/obj/item/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
+ var/healthanalyzer = /obj/item/healthanalyzer
+ var/firstaid = /obj/item/storage/firstaid
+ var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
+ var/mob/living/carbon/patient = null
+ var/mob/living/carbon/oldpatient = null
+ var/oldloc = null
+ var/last_found = 0
+ var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
+ var/injection_amount = 15 //How much reagent do we inject at a time?
+ var/heal_threshold = 10 //Start healing when they have this much damage in a category
+ var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
+ var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
+ var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
+ var/stationary_mode = 0 //If enabled, the Medibot will not move automatically.
+ //Setting which reagents to use to treat what by default. By id.
+ var/treatment_brute_avoid = /datum/reagent/medicine/tricordrazine
+ var/treatment_brute = /datum/reagent/medicine/bicaridine
+ var/treatment_oxy_avoid = null
+ var/treatment_oxy = /datum/reagent/medicine/dexalin
+ var/treatment_fire_avoid = /datum/reagent/medicine/tricordrazine
+ var/treatment_fire = /datum/reagent/medicine/kelotane
+ var/treatment_tox_avoid = /datum/reagent/medicine/tricordrazine
+ var/treatment_tox = /datum/reagent/medicine/charcoal
+ var/treatment_tox_toxlover = /datum/reagent/toxin
+ var/treatment_virus_avoid = null
+ var/treatment_virus = /datum/reagent/medicine/spaceacillin
+ var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
+ var/shut_up = 0 //self explanatory :)
+
+ //How panicked we are about being tipped over (why would you do this?)
+ var/tipped_status = MEDBOT_PANIC_NONE
+ //The name we got when we were tipped
+ var/tipper_name
+ //The last time we were tipped/righted and said a voice line, to avoid spam
+ var/last_tipping_action_voice = 0
+
+/mob/living/simple_animal/bot/medbot/mysterious
+ name = "\improper Mysterious Medibot"
+ desc = "International Medibot of mystery."
+ skin = "bezerk"
+ treatment_brute = /datum/reagent/medicine/tricordrazine
+ treatment_fire = /datum/reagent/medicine/tricordrazine
+ treatment_tox = /datum/reagent/medicine/tricordrazine
+
+/mob/living/simple_animal/bot/medbot/derelict
+ name = "\improper Old Medibot"
+ desc = "Looks like it hasn't been modified since the late 2080s."
+ skin = "bezerk"
+ heal_threshold = 0
+ declare_crit = 0
+ treatment_oxy = /datum/reagent/toxin/pancuronium
+ treatment_brute_avoid = null
+ treatment_brute = /datum/reagent/toxin/pancuronium
+ treatment_fire_avoid = null
+ treatment_fire = /datum/reagent/toxin/sodium_thiopental
+ treatment_tox_avoid = null
+ treatment_tox = /datum/reagent/toxin/sodium_thiopental
+
+/mob/living/simple_animal/bot/medbot/update_icon()
+ cut_overlays()
+ if(skin)
+ add_overlay("medskin_[skin]")
+ if(!on)
+ icon_state = "medibot0"
+ return
+ if(IsStun())
+ icon_state = "medibota"
+ return
+ if(mode == BOT_HEALING)
+ icon_state = "medibots[stationary_mode]"
+ return
+ else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
+ icon_state = "medibot2"
+ else
+ icon_state = "medibot1"
+
+/mob/living/simple_animal/bot/medbot/Initialize(mapload, new_skin)
+ . = ..()
+ var/datum/job/doctor/J = new /datum/job/doctor
+ access_card.access += J.get_access()
+ prev_access = access_card.access
+ qdel(J)
+ skin = new_skin
+ update_icon()
+
+/mob/living/simple_animal/bot/medbot/update_canmove()
+ . = ..()
+ update_icon()
+
+/mob/living/simple_animal/bot/medbot/bot_reset()
+ ..()
+ patient = null
+ oldpatient = null
+ oldloc = null
+ last_found = world.time
+ declare_cooldown = 0
+ update_icon()
+
+/mob/living/simple_animal/bot/medbot/proc/soft_reset() //Allows the medibot to still actively perform its medical duties without being completely halted as a hard reset does.
+ path = list()
+ patient = null
+ mode = BOT_IDLE
+ last_found = world.time
+ update_icon()
+
+/mob/living/simple_animal/bot/medbot/set_custom_texts()
+
+ text_hack = "You corrupt [name]'s reagent processor circuits."
+ text_dehack = "You reset [name]'s reagent processor circuits."
+ text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
+
+/mob/living/simple_animal/bot/medbot/attack_paw(mob/user)
+ return attack_hand(user)
+
+/mob/living/simple_animal/bot/medbot/get_controls(mob/user)
+ var/dat
+ dat += hack(user)
+ dat += showpai(user)
+ dat += "Medical Unit Controls v1.1
"
+ dat += "Status: [on ? "On" : "Off"] "
+ dat += "Maintenance panel panel is [open ? "opened" : "closed"] "
+ dat += "Beaker: "
+ if(reagent_glass)
+ dat += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]"
+ else
+ dat += "None Loaded"
+ dat += " Behaviour controls are [locked ? "locked" : "unlocked"]"
+ if(!locked || issilicon(user) || IsAdminGhost(user))
+ dat += "Healing Threshold: "
+ dat += "-- "
+ dat += "- "
+ dat += "[heal_threshold] "
+ dat += "+ "
+ dat += "++"
+ dat += " "
+
+ dat += "Injection Level: "
+ dat += "- "
+ dat += "[injection_amount] "
+ dat += "+ "
+ dat += " "
+
+ dat += "Reagent Source: "
+ dat += "[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"] "
+
+ dat += "Treat Viral Infections: [treat_virus ? "Yes" : "No"] "
+ dat += "The speaker switch is [shut_up ? "off" : "on"]. Toggle "
+ dat += "Critical Patient Alerts: [declare_crit ? "Yes" : "No"] "
+ dat += "Patrol Station: [auto_patrol ? "Yes" : "No"] "
+ dat += "Stationary Mode: [stationary_mode ? "Yes" : "No"] "
+
+ return dat
+
+/mob/living/simple_animal/bot/medbot/Topic(href, href_list)
+ if(..())
+ return 1
+
+ if(href_list["adj_threshold"])
+ var/adjust_num = text2num(href_list["adj_threshold"])
+ heal_threshold += adjust_num
+ if(heal_threshold < 5)
+ heal_threshold = 5
+ if(heal_threshold > 75)
+ heal_threshold = 75
+
+ else if(href_list["adj_inject"])
+ var/adjust_num = text2num(href_list["adj_inject"])
+ injection_amount += adjust_num
+ if(injection_amount < 5)
+ injection_amount = 5
+ if(injection_amount > 15)
+ injection_amount = 15
+
+ else if(href_list["use_beaker"])
+ use_beaker = !use_beaker
+
+ else if(href_list["eject"] && (!isnull(reagent_glass)))
+ reagent_glass.forceMove(drop_location())
+ reagent_glass = null
+
+ else if(href_list["togglevoice"])
+ shut_up = !shut_up
+
+ else if(href_list["critalerts"])
+ declare_crit = !declare_crit
+
+ else if(href_list["stationary"])
+ stationary_mode = !stationary_mode
+ path = list()
+ update_icon()
+
+ else if(href_list["virus"])
+ treat_virus = !treat_virus
+
+ update_controls()
+ return
+
+/mob/living/simple_animal/bot/medbot/attackby(obj/item/W as obj, mob/user as mob, params)
+ if(istype(W, /obj/item/reagent_containers/glass))
+ . = 1 //no afterattack
+ if(locked)
+ to_chat(user, "You cannot insert a beaker because the panel is locked!")
+ return
+ if(!isnull(reagent_glass))
+ to_chat(user, "There is already a beaker loaded!")
+ return
+ if(!user.transferItemToLoc(W, src))
+ return
+
+ reagent_glass = W
+ to_chat(user, "You insert [W].")
+ show_controls(user)
+
+ else
+ var/current_health = health
+ ..()
+ if(health < current_health) //if medbot took some damage
+ step_to(src, (get_step_away(src,user)))
+
+/mob/living/simple_animal/bot/medbot/emag_act(mob/user)
+ ..()
+ if(emagged == 2)
+ declare_crit = 0
+ if(user)
+ to_chat(user, "You short out [src]'s reagent synthesis circuits.")
+ audible_message("[src] buzzes oddly!")
+ flick("medibot_spark", src)
+ playsound(src, "sparks", 75, 1)
+ if(user)
+ oldpatient = user
+
+/mob/living/simple_animal/bot/medbot/process_scan(mob/living/carbon/human/H)
+ if(H.stat == DEAD)
+ return
+
+ if((H == oldpatient) && (world.time < last_found + 200))
+ return
+
+ if(assess_patient(H))
+ last_found = world.time
+ if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
+ var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg',"[H.name], you appear to be injured!" = 'sound/voice/medbot/injured.ogg')
+ var/message = pick(messagevoice)
+ if(prob(2) && ISINRANGE_EX(H.getFireLoss(), 0, 20))
+ message = "Notices your minor burns*OwO what's this?"
+ messagevoice[message] = 'sound/voice/medbot/owo.ogg'
+ speak(message)
+ playsound(loc, messagevoice[message], 50, 0)
+ last_newpatient_speak = world.time
+ return H
+ else
+ return
+
+/mob/living/simple_animal/bot/medbot/proc/tip_over(mob/user)
+ canmove = 0
+ //mobility_flags &= ~MOBILITY_MOVE
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 50)
+ user.visible_message("[user] tips over [src]!", "You tip [src] over!")
+ mode = BOT_TIPPED
+ var/matrix/mat = transform
+ transform = mat.Turn(180)
+
+/mob/living/simple_animal/bot/medbot/proc/set_right(mob/user)
+ canmove = 1
+ //mobility_flags &= MOBILITY_MOVE
+ var/list/messagevoice
+ if(user)
+ user.visible_message("[user] sets [src] right-side up!", "You set [src] right-side up!")
+ if(user.name == tipper_name)
+ messagevoice = list("I forgive you." = 'sound/voice/medbot/forgive.ogg')
+ else
+ messagevoice = list("Thank you!" = 'sound/voice/medbot/thank_you.ogg', "You are a good person." = 'sound/voice/medbot/youre_good.ogg')
+ else
+ visible_message("[src] manages to writhe wiggle enough to right itself.")
+ messagevoice = list("Fuck you." = 'sound/voice/medbot/fuck_you.ogg', "Your behavior has been reported, have a nice day." = 'sound/voice/medbot/reported.ogg')
+
+ tipper_name = null
+ if(world.time > last_tipping_action_voice + 15 SECONDS)
+ last_tipping_action_voice = world.time
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 70)
+ tipped_status = MEDBOT_PANIC_NONE
+ mode = BOT_IDLE
+ transform = matrix()
+
+// if someone tipped us over, check whether we should ask for help or just right ourselves eventually
+/mob/living/simple_animal/bot/medbot/proc/handle_panic()
+ tipped_status++
+ var/list/messagevoice
+ switch(tipped_status)
+ if(MEDBOT_PANIC_LOW)
+ messagevoice = list("I require assistance." = 'sound/voice/medbot/i_require_asst.ogg')
+ if(MEDBOT_PANIC_MED)
+ messagevoice = list("Please put me back." = 'sound/voice/medbot/please_put_me_back.ogg')
+ if(MEDBOT_PANIC_HIGH)
+ messagevoice = list("Please, I am scared!" = 'sound/voice/medbot/please_im_scared.ogg')
+ if(MEDBOT_PANIC_FUCK)
+ messagevoice = list("I don't like this, I need help!" = 'sound/voice/medbot/dont_like.ogg', "This hurts, my pain is real!" = 'sound/voice/medbot/pain_is_real.ogg')
+ if(MEDBOT_PANIC_ENDING)
+ messagevoice = list("Is this the end?" = 'sound/voice/medbot/is_this_the_end.ogg', "Nooo!" = 'sound/voice/medbot/nooo.ogg')
+ if(MEDBOT_PANIC_END)
+ speak("PSYCH ALERT: Crewmember [tipper_name] recorded displaying antisocial tendencies torturing bots in [get_area(src)]. Please schedule psych evaluation.", radio_channel)
+ set_right() // strong independent medbot
+
+ if(prob(tipped_status))
+ do_jitter_animation(tipped_status * 0.1)
+
+ if(messagevoice)
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 70)
+ else if(prob(tipped_status * 0.2))
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 30, extrarange=-2)
+
+/mob/living/simple_animal/bot/medbot/examine(mob/user)
+ . = ..()
+ if(tipped_status == MEDBOT_PANIC_NONE)
+ return
+
+ switch(tipped_status)
+ if(MEDBOT_PANIC_NONE to MEDBOT_PANIC_LOW)
+ . += "It appears to be tipped over, and is quietly waiting for someone to set it right."
+ if(MEDBOT_PANIC_LOW to MEDBOT_PANIC_MED)
+ . += "It is tipped over and requesting help."
+ if(MEDBOT_PANIC_MED to MEDBOT_PANIC_HIGH)
+ . += "They are tipped over and appear visibly distressed." // now we humanize the medbot as a they, not an it
+ if(MEDBOT_PANIC_HIGH to MEDBOT_PANIC_FUCK)
+ . += "They are tipped over and visibly panicking!"
+ if(MEDBOT_PANIC_FUCK to INFINITY)
+ . += "They are freaking out from being tipped over!"
+
+/mob/living/simple_animal/bot/medbot/handle_automated_action()
+ if(!..())
+ return
+
+ if(mode == BOT_TIPPED)
+ handle_panic()
+ return
+
+ if(mode == BOT_HEALING)
+ return
+
+ if(IsStun())
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+ return
+
+ if(frustration > 8)
+ oldpatient = patient
+ soft_reset()
+
+ if(QDELETED(patient))
+ if(!shut_up && prob(1))
+ if(emagged && prob(30))
+ var/list/i_need_scissors = list('sound/voice/medbot/fuck_you.ogg', 'sound/voice/medbot/turn_off.ogg', 'sound/voice/medbot/im_different.ogg', 'sound/voice/medbot/close.ogg', 'sound/voice/medbot/shindemashou.ogg')
+ playsound(src, pick(i_need_scissors), 70)
+ else
+ var/list/messagevoice = list("Radar, put a mask on!" = 'sound/voice/medbot/radar.ogg',"There's always a catch, and I'm the best there is." = 'sound/voice/medbot/catch.ogg',"I knew it, I should've been a plastic surgeon." = 'sound/voice/medbot/surgeon.ogg',"What kind of medbay is this? Everyone's dropping like flies." = 'sound/voice/medbot/flies.ogg',"Delicious!" = 'sound/voice/medbot/delicious.ogg', "Why are we still here? Just to suffer?" = 'sound/voice/medbot/why.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 50)
+ var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients.
+ patient = scan(/mob/living/carbon/human, oldpatient, scan_range)
+ oldpatient = patient
+
+ if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment!
+ if(mode != BOT_HEALING)
+ mode = BOT_HEALING
+ update_icon()
+ frustration = 0
+ medicate_patient(patient)
+ return
+
+ //Patient has moved away from us!
+ else if(patient && path.len && (get_dist(patient,path[path.len]) > 2))
+ path = list()
+ mode = BOT_IDLE
+ last_found = world.time
+
+ else if(stationary_mode && patient) //Since we cannot move in this mode, ignore the patient and wait for another.
+ soft_reset()
+ return
+
+ if(patient && path.len == 0 && (get_dist(src,patient) > 1))
+ path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,id=access_card)
+ mode = BOT_MOVING
+ if(!path.len) //try to get closer if you can't reach the patient directly
+ path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,1,id=access_card)
+ if(!path.len) //Do not chase a patient we cannot reach.
+ soft_reset()
+
+ if(path.len > 0 && patient)
+ if(!bot_move(path[path.len]))
+ oldpatient = patient
+ soft_reset()
+ return
+
+ if(path.len > 8 && patient)
+ frustration++
+
+ if(auto_patrol && !stationary_mode && !patient)
+ if(mode == BOT_IDLE || mode == BOT_START_PATROL)
+ start_patrol()
+
+ if(mode == BOT_PATROL)
+ bot_patrol()
+
+ return
+
+/mob/living/simple_animal/bot/medbot/proc/assess_patient(mob/living/carbon/C)
+ //Time to see if they need medical help!
+ if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
+ return FALSE //welp too late for them!
+
+ if(!(loc == C.loc) && !(isturf(C.loc) && isturf(loc)))
+ return FALSE
+
+ if(C.suiciding)
+ return FALSE //Kevorkian school of robotic medical assistants.
+
+ if(emagged == 2) //Everyone needs our medicine. (Our medicine is toxins)
+ return TRUE
+
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing))
+ var/obj/item/clothing/CS = H.wear_suit
+ var/obj/item/clothing/CH = H.head
+ if (CS.clothing_flags & CH.clothing_flags & THICKMATERIAL)
+ return FALSE // Skip over them if they have no exposed flesh.
+
+ if(declare_crit && C.health <= 0) //Critical condition! Call for help!
+ declare(C)
+
+ //If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
+ if((reagent_glass) && (use_beaker) && ((C.getBruteLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getToxLoss() >= heal_threshold) || (C.getOxyLoss() >= (heal_threshold + 15))))
+ for(var/A in reagent_glass.reagents.reagent_list)
+ var/datum/reagent/R = A
+ if(!C.reagents.has_reagent(R.type))
+ return TRUE
+
+ //They're injured enough for it!
+ if((!C.reagents.has_reagent(treatment_brute_avoid)) && (C.getBruteLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_brute)))
+ return TRUE //If they're already medicated don't bother!
+
+ if((!C.reagents.has_reagent(treatment_oxy_avoid)) && (C.getOxyLoss() >= (15 + heal_threshold)) && (!C.reagents.has_reagent(treatment_oxy)))
+ return TRUE
+
+ if((!C.reagents.has_reagent(treatment_fire_avoid)) && (C.getFireLoss() >= heal_threshold) && (!C.reagents.has_reagent(treatment_fire)))
+ return TRUE
+
+ var/treatment_toxavoid = get_avoidchem_toxin(C)
+ if(((isnull(treatment_toxavoid) || !C.reagents.has_reagent(treatment_toxavoid))) && (C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(get_healchem_toxin(C))))
+ return TRUE
+
+ if(treat_virus && !C.reagents.has_reagent(treatment_virus_avoid) && !C.reagents.has_reagent(treatment_virus))
+ for(var/thing in C.diseases)
+ var/datum/disease/D = thing
+ //the medibot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
+ if(!(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) \
+ && D.severity != DISEASE_SEVERITY_POSITIVE \
+ && (D.stage > 1 || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))) // medibot can't detect a virus in its initial stage unless it spreads airborne.
+ return TRUE //STOP DISEASE FOREVER
+
+ return FALSE
+
+/mob/living/simple_animal/bot/medbot/attack_hand(mob/living/carbon/human/H)
+ if(H.a_intent == INTENT_DISARM && mode != BOT_TIPPED)
+ H.visible_message("[H] begins tipping over [src].", "You begin tipping over [src]...")
+
+ if(world.time > last_tipping_action_voice + 15 SECONDS)
+ last_tipping_action_voice = world.time // message for tipping happens when we start interacting, message for righting comes after finishing
+ var/list/messagevoice = list("Hey, wait..." = 'sound/voice/medbot/hey_wait.ogg',"Please don't..." = 'sound/voice/medbot/please_dont.ogg',"I trusted you..." = 'sound/voice/medbot/i_trusted_you.ogg', "Nooo..." = 'sound/voice/medbot/nooo.ogg', "Oh fuck-" = 'sound/voice/medbot/oh_fuck.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 70, FALSE)
+
+ if(do_after(H, 3 SECONDS, target=src))
+ tip_over(H)
+
+ else if(H.a_intent == INTENT_HELP && mode == BOT_TIPPED)
+ H.visible_message("[H] begins righting [src].", "You begin righting [src]...")
+ if(do_after(H, 3 SECONDS, target=src))
+ set_right(H)
+ else
+ ..()
+
+/mob/living/simple_animal/bot/medbot/proc/get_avoidchem_toxin(mob/M)
+ return HAS_TRAIT(M, TRAIT_TOXINLOVER)? null : treatment_tox_avoid
+
+/mob/living/simple_animal/bot/medbot/proc/get_healchem_toxin(mob/M)
+ return HAS_TRAIT(M, TRAIT_TOXINLOVER)? treatment_tox_toxlover : treatment_tox
+
+/mob/living/simple_animal/bot/medbot/UnarmedAttack(atom/A)
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ patient = C
+ mode = BOT_HEALING
+ update_icon()
+ medicate_patient(C)
+ update_icon()
+ else
+ ..()
+
+/mob/living/simple_animal/bot/medbot/examinate(atom/A as mob|obj|turf in view())
+ ..()
+ if(!is_blind(src))
+ chemscan(src, A)
+
+/mob/living/simple_animal/bot/medbot/proc/medicate_patient(mob/living/carbon/C)
+ if(!on)
+ return
+
+ if(!istype(C))
+ oldpatient = patient
+ soft_reset()
+ return
+
+ if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
+ var/list/messagevoice = list("No! Stay with me!" = 'sound/voice/medbot/no.ogg',"Live, damnit! LIVE!" = 'sound/voice/medbot/live.ogg',"I...I've never lost a patient before. Not today, I mean." = 'sound/voice/medbot/lost.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(loc, messagevoice[message], 50, 0)
+ oldpatient = patient
+ soft_reset()
+ return
+
+ var/reagent_id = null
+
+ if(emagged == 2) //Emagged! Time to poison everybody.
+ reagent_id = "toxin"
+ reagent_id = HAS_TRAIT(C, TRAIT_TOXINLOVER)? "charcoal" : "toxin"
+
+ else
+ if(treat_virus)
+ var/virus = 0
+ for(var/thing in C.diseases)
+ var/datum/disease/D = thing
+ //detectable virus
+ if((!(D.visibility_flags & HIDDEN_SCANNER)) || (!(D.visibility_flags & HIDDEN_PANDEMIC)))
+ if(D.severity != DISEASE_SEVERITY_POSITIVE) //virus is harmful
+ if((D.stage > 1) || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))
+ virus = 1
+
+ if(!reagent_id && (virus))
+ if(!C.reagents.has_reagent(treatment_virus) && !C.reagents.has_reagent(treatment_virus_avoid))
+ reagent_id = treatment_virus
+
+ if(!reagent_id && (C.getBruteLoss() >= heal_threshold))
+ if(!C.reagents.has_reagent(treatment_brute) && !C.reagents.has_reagent(treatment_brute_avoid))
+ reagent_id = treatment_brute
+
+ if(!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
+ if(!C.reagents.has_reagent(treatment_oxy) && !C.reagents.has_reagent(treatment_oxy_avoid))
+ reagent_id = treatment_oxy
+
+ if(!reagent_id && (C.getFireLoss() >= heal_threshold))
+ if(!C.reagents.has_reagent(treatment_fire) && !C.reagents.has_reagent(treatment_fire_avoid))
+ reagent_id = treatment_fire
+
+ if(!reagent_id && (C.getToxLoss() >= heal_threshold))
+ var/toxin_heal_avoid = get_avoidchem_toxin(C)
+ var/toxin_healchem = get_healchem_toxin(C)
+ if(!C.reagents.has_reagent(toxin_healchem) && (isnull(toxin_heal_avoid) || !C.reagents.has_reagent(toxin_heal_avoid)))
+ reagent_id = toxin_healchem
+
+ //If the patient is injured but doesn't have our special reagent in them then we should give it to them first
+ if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
+ for(var/A in reagent_glass.reagents.reagent_list)
+ var/datum/reagent/R = A
+ if(!C.reagents.has_reagent(R.type))
+ reagent_id = "internal_beaker"
+ break
+
+ if(!reagent_id) //If they don't need any of that they're probably cured!
+ if(C.maxHealth - C.health < heal_threshold)
+ to_chat(src, "[C] is healthy! Your programming prevents you from injecting anyone without at least [heal_threshold] damage of any one type ([heal_threshold + 15] for oxygen damage.)")
+ var/list/messagevoice = list("All patched up!" = 'sound/voice/medbot/patchedup.ogg',"An apple a day keeps me away." = 'sound/voice/medbot/apple.ogg',"Feel better soon!" = 'sound/voice/medbot/feelbetter.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(loc, messagevoice[message], 50, 0)
+ bot_reset()
+ return
+ else
+ if(!emagged && check_overdose(patient,reagent_id,injection_amount))
+ soft_reset()
+ return
+ C.visible_message("[src] is trying to inject [patient]!", \
+ "[src] is trying to inject you!")
+
+ var/failed = FALSE
+ if(do_mob(src, patient, 30)) //Is C == patient? This is so confusing
+ if((get_dist(src, patient) <= 1) && (on) && assess_patient(patient))
+ if(reagent_id == "internal_beaker")
+ if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
+ var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1)
+ reagent_glass.reagents.reaction(patient, INJECT, fraction)
+ reagent_glass.reagents.trans_to(patient,injection_amount) //Inject from beaker instead.
+ else
+ patient.reagents.add_reagent(reagent_id,injection_amount)
+ C.visible_message("[src] injects [patient] with its syringe!", \
+ "[src] injects you with its syringe!")
+ else
+ failed = TRUE
+ else
+ failed = TRUE
+
+ if(failed)
+ visible_message("[src] retracts its syringe.")
+ update_icon()
+ soft_reset()
+ return
+
+ reagent_id = null
+ return
+
+/mob/living/simple_animal/bot/medbot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount)
+ var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
+ if(!R.overdose_threshold) //Some chems do not have an OD threshold
+ return FALSE
+ var/current_volume = patient.reagents.get_reagent_amount(reagent_id)
+ if(current_volume + injection_amount > R.overdose_threshold)
+ return TRUE
+ return FALSE
+
+/mob/living/simple_animal/bot/medbot/explode()
+ on = FALSE
+ visible_message("[src] blows apart!")
+ var/atom/Tsec = drop_location()
+
+ drop_part(firstaid, Tsec)
+ new /obj/item/assembly/prox_sensor(Tsec)
+ drop_part(healthanalyzer, Tsec)
+
+ if(reagent_glass)
+ drop_part(reagent_glass, Tsec)
+
+ if(prob(50))
+ drop_part(robot_arm, Tsec)
+
+ if(emagged && prob(25))
+ playsound(loc, 'sound/voice/medbot/insult.ogg', 50, 0)
+
+ do_sparks(3, TRUE, src)
+ ..()
+
+/mob/living/simple_animal/bot/medbot/proc/declare(crit_patient)
+ if(declare_cooldown > world.time)
+ return
+ var/area/location = get_area(src)
+ speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_channel)
+ declare_cooldown = world.time + 200
+
+/obj/machinery/bot_core/medbot
+ req_one_access = list(ACCESS_MEDICAL, ACCESS_ROBOTICS)
+
+#undef MEDBOT_PANIC_NONE
+#undef MEDBOT_PANIC_LOW
+#undef MEDBOT_PANIC_MED
+#undef MEDBOT_PANIC_HIGH
+#undef MEDBOT_PANIC_FUCK
+#undef MEDBOT_PANIC_ENDING
+#undef MEDBOT_PANIC_END
diff --git a/code/modules/mob/living/simple_animal/bot/secbot.dm b/code/modules/mob/living/simple_animal/bot/secbot.dm
index ca422ca7..7a64c4e0 100644
--- a/code/modules/mob/living/simple_animal/bot/secbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/secbot.dm
@@ -1,446 +1,446 @@
-/mob/living/simple_animal/bot/secbot
- name = "\improper Securitron"
- desc = "A little security robot. He looks less than thrilled."
- icon = 'icons/mob/aibots.dmi'
- icon_state = "secbot"
- density = FALSE
- anchored = FALSE
- health = 25
- maxHealth = 25
- damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
- pass_flags = PASSMOB
-
- radio_key = /obj/item/encryptionkey/secbot //AI Priv + Security
- radio_channel = RADIO_CHANNEL_SECURITY //Security channel
- bot_type = SEC_BOT
- model = "Securitron"
- bot_core_type = /obj/machinery/bot_core/secbot
- window_id = "autosec"
- window_name = "Automatic Security Unit v1.6"
- allow_pai = 0
- data_hud_type = DATA_HUD_SECURITY_ADVANCED
- path_image_color = "#FF0000"
-
- var/baton_type = /obj/item/melee/baton
- var/mob/living/carbon/target
- var/oldtarget_name
- var/threatlevel = FALSE
- var/target_lastloc //Loc of target when arrested.
- var/last_found //There's a delay
- var/declare_arrests = TRUE //When making an arrest, should it notify everyone on the security channel?
- var/idcheck = FALSE //If true, arrest people with no IDs
- var/weaponscheck = FALSE //If true, arrest people for weapons if they lack access
- var/check_records = TRUE //Does it check security records?
- var/arrest_type = FALSE //If true, don't handcuff
-
-/mob/living/simple_animal/bot/secbot/beepsky
- name = "Officer Beep O'sky"
- desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
- idcheck = FALSE
- weaponscheck = FALSE
- auto_patrol = TRUE
-
-/mob/living/simple_animal/bot/secbot/beepsky/jr
- name = "Officer Pipsqueak"
- desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
-
-/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
- . = ..()
- resize = 0.8
- update_transform()
-
-
-/mob/living/simple_animal/bot/secbot/beepsky/explode()
- var/atom/Tsec = drop_location()
- new /obj/item/stock_parts/cell/potato(Tsec)
- var/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
- S.reagents.add_reagent("whiskey", 15)
- S.on_reagent_change(ADD_REAGENT)
- ..()
-
-/mob/living/simple_animal/bot/secbot/pingsky
- name = "Officer Pingsky"
- desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
- radio_channel = RADIO_CHANNEL_AI_PRIVATE
-
-/mob/living/simple_animal/bot/secbot/Initialize()
- . = ..()
- update_icon()
- var/datum/job/detective/J = new/datum/job/detective
- access_card.access += J.get_access()
- prev_access = access_card.access
-
- //SECHUD
- var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
- secsensor.add_hud_to(src)
-
-/mob/living/simple_animal/bot/secbot/update_icon()
- if(mode == BOT_HUNT)
- icon_state = "[initial(icon_state)]-c"
- return
- ..()
-
-/mob/living/simple_animal/bot/secbot/turn_off()
- ..()
- mode = BOT_IDLE
-
-/mob/living/simple_animal/bot/secbot/bot_reset()
- ..()
- target = null
- oldtarget_name = null
- anchored = FALSE
- walk_to(src,0)
- last_found = world.time
-
-/mob/living/simple_animal/bot/secbot/set_custom_texts()
-
- text_hack = "You overload [name]'s target identification system."
- text_dehack = "You reboot [name] and restore the target identification."
- text_dehack_fail = "[name] refuses to accept your authority!"
-
-/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
- var/dat
- dat += hack(user)
- dat += showpai(user)
- dat += text({"
-Securitron v1.6 controls
-Status: []
-Behaviour controls are [locked ? "locked" : "unlocked"]
-Maintenance panel panel is [open ? "opened" : "closed"]"},
-
-"[on ? "On" : "Off"]" )
-
- if(!locked || issilicon(user) || IsAdminGhost(user))
- dat += text({"
-Arrest Unidentifiable Persons: []
-Arrest for Unauthorized Weapons: []
-Arrest for Warrant: []
-Operating Mode: []
-Report Arrests[]
-Auto Patrol: []"},
-
-"[idcheck ? "Yes" : "No"]",
-"[weaponscheck ? "Yes" : "No"]",
-"[check_records ? "Yes" : "No"]",
-"[arrest_type ? "Detain" : "Arrest"]",
-"[declare_arrests ? "Yes" : "No"]",
-"[auto_patrol ? "On" : "Off"]" )
-
- return dat
-
-/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
- if(..())
- return 1
-
- if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked))
- return TRUE
-
- switch(href_list["operation"])
- if("idcheck")
- idcheck = !idcheck
- update_controls()
- if("weaponscheck")
- weaponscheck = !weaponscheck
- update_controls()
- if("ignorerec")
- check_records = !check_records
- update_controls()
- if("switchmode")
- arrest_type = !arrest_type
- update_controls()
- if("declarearrests")
- declare_arrests = !declare_arrests
- update_controls()
-
-/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
- var/judgement_criteria = judgement_criteria()
- threatlevel = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
- threatlevel += 6
- if(threatlevel >= 4)
- target = H
- mode = BOT_HUNT
-
-/mob/living/simple_animal/bot/secbot/proc/judgement_criteria()
- var/final = FALSE
- if(idcheck)
- final = final|JUDGE_IDCHECK
- if(check_records)
- final = final|JUDGE_RECORDCHECK
- if(weaponscheck)
- final = final|JUDGE_WEAPONCHECK
- if(emagged == 2)
- final = final|JUDGE_EMAGGED
- return final
-
-/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
- return
-
-/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
- if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
- retaliate(H)
- if(special_retaliate_after_attack(H))
- return
-
- return ..()
-
-/mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params)
- ..()
- if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
- return
- if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
- retaliate(user)
- if(special_retaliate_after_attack(user))
- return
-
-/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
- ..()
- if(emagged == 2)
- if(user)
- to_chat(user, "You short out [src]'s target assessment circuits.")
- oldtarget_name = user.name
- audible_message("[src] buzzes oddly!")
- declare_arrests = FALSE
- update_icon()
-
-/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
- if(istype(Proj , /obj/item/projectile/beam)||istype(Proj, /obj/item/projectile/bullet))
- if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
- if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
- retaliate(Proj.firer)
- ..()
-
-
-/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
- if(!on)
- return
- if(iscarbon(A))
- var/mob/living/carbon/C = A
- if(C.canmove || arrest_type) // CIT CHANGE - makes sentient secbots check for canmove rather than !isstun.
- stun_attack(A)
- else if(C.canBeHandcuffed() && !C.handcuffed)
- cuff(A)
- else
- ..()
-
-
-/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
- if(istype(AM, /obj/item))
- var/obj/item/I = AM
- if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
- var/mob/living/carbon/human/H = I.thrownby
- retaliate(H)
- ..()
-
-
-/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
- mode = BOT_ARREST
- playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
- C.visible_message("[src] is trying to put zipties on [C]!",\
- "[src] is trying to put zipties on you!")
- addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60)
-
-/mob/living/simple_animal/bot/secbot/proc/attempt_handcuff(mob/living/carbon/C)
- if( !on || !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
- return
- if(!C.handcuffed)
- C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
- C.update_handcuffed()
- playsound(src, "law", 50, 0)
- back_to_idle()
-
-/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
- var/judgement_criteria = judgement_criteria()
- playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
- icon_state = "secbot-c"
- addtimer(CALLBACK(src, .proc/update_icon), 2)
- var/threat = 5
- if(ishuman(C))
- C.stuttering = 5
- C.Knockdown(100)
- var/mob/living/carbon/human/H = C
- threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
- else
- C.Knockdown(100)
- C.stuttering = 5
- threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
-
- log_combat(src,C,"stunned")
- if(declare_arrests)
- var/area/location = get_area(src)
- speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
- C.visible_message("[src] has stunned [C]!",\
- "[src] has stunned you!")
-
-/mob/living/simple_animal/bot/secbot/handle_automated_action()
- if(!..())
- return
-
- switch(mode)
-
- if(BOT_IDLE) // idle
-
- walk_to(src,0)
- look_for_perp() // see if any criminals are in range
- if(!mode && auto_patrol) // still idle, and set to patrol
- mode = BOT_START_PATROL // switch to patrol mode
-
- if(BOT_HUNT) // hunting for perp
-
- // if can't reach perp for long enough, go idle
- if(frustration >= 8)
- walk_to(src,0)
- back_to_idle()
- return
-
- if(target) // make sure target exists
- if(Adjacent(target) && isturf(target.loc)) // if right next to perp
- stun_attack(target)
-
- mode = BOT_PREP_ARREST
- anchored = TRUE
- target_lastloc = target.loc
- return
-
- else // not next to perp
- var/turf/olddist = get_dist(src, target)
- walk_to(src, target,1,4)
- if((get_dist(src, target)) >= (olddist))
- frustration++
- else
- frustration = 0
- else
- back_to_idle()
-
- if(BOT_PREP_ARREST) // preparing to arrest target
-
- // see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
- if( !Adjacent(target) || !isturf(target.loc) || target.getStaminaLoss() <= 120 || !target.recoveringstam) //CIT CHANGE - replaces amountknockdown with checks for stamina so secbots dont run into an infinite loop
- back_to_hunt()
- return
-
- if(iscarbon(target) && target.canBeHandcuffed())
- if(!arrest_type)
- if(!target.handcuffed) //he's not cuffed? Try to cuff him!
- cuff(target)
- else
- back_to_idle()
- return
- else
- back_to_idle()
- return
-
- if(BOT_ARREST)
- if(!target)
- anchored = FALSE
- mode = BOT_IDLE
- last_found = world.time
- frustration = 0
- return
-
- if(target.handcuffed) //no target or target cuffed? back to idle.
- back_to_idle()
- return
-
- if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && !target.recoveringstam && target.getStaminaLoss() <= 120)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. CIT CHANGE - replaces amountknockdown with recoveringstam and staminaloss check
- back_to_hunt()
- return
- else //Try arresting again if the target escapes.
- mode = BOT_PREP_ARREST
- anchored = FALSE
-
- if(BOT_START_PATROL)
- look_for_perp()
- start_patrol()
-
- if(BOT_PATROL)
- look_for_perp()
- bot_patrol()
-
-
- return
-
-/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
- anchored = FALSE
- mode = BOT_IDLE
- target = null
- last_found = world.time
- frustration = 0
- INVOKE_ASYNC(src, .proc/handle_automated_action)
-
-/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
- anchored = FALSE
- frustration = 0
- mode = BOT_HUNT
- INVOKE_ASYNC(src, .proc/handle_automated_action)
-// look for a criminal in view of the bot
-
-/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
- anchored = FALSE
- var/judgement_criteria = judgement_criteria()
- for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
- if((C.stat) || (C.handcuffed))
- continue
-
- if((C.name == oldtarget_name) && (world.time < last_found + 100))
- continue
-
- threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
-
- if(!threatlevel)
- continue
-
- else if(threatlevel >= 4)
- target = C
- oldtarget_name = C.name
- speak("Level [threatlevel] infraction alert!")
- playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
- visible_message("[src] points at [C.name]!")
- mode = BOT_HUNT
- INVOKE_ASYNC(src, .proc/handle_automated_action)
- break
- else
- continue
-
-/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
- if(slot_item && (slot_item.item_flags & NEEDS_PERMIT))
- return TRUE
- return FALSE
-
-/mob/living/simple_animal/bot/secbot/explode()
-
- walk_to(src,0)
- visible_message("[src] blows apart!")
- var/atom/Tsec = drop_location()
-
- var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
- Sa.build_step = 1
- Sa.add_overlay("hs_hole")
- Sa.created_name = name
- new /obj/item/assembly/prox_sensor(Tsec)
- drop_part(baton_type, Tsec)
-
- if(prob(50))
- drop_part(robot_arm, Tsec)
-
- do_sparks(3, TRUE, src)
-
- new /obj/effect/decal/cleanable/oil(loc)
- ..()
-
-/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
- ..()
- if(!isalien(target))
- target = user
- mode = BOT_HUNT
-
-/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
- if(has_gravity() && ismob(AM) && target)
- var/mob/living/carbon/C = AM
- if(!istype(C) || !C || in_range(src, target))
- return
- knockOver(C)
- return
- ..()
-
-/obj/machinery/bot_core/secbot
- req_access = list(ACCESS_SECURITY)
+/mob/living/simple_animal/bot/secbot
+ name = "\improper Securitron"
+ desc = "A little security robot. He looks less than thrilled."
+ icon = 'icons/mob/aibots.dmi'
+ icon_state = "secbot"
+ density = FALSE
+ anchored = FALSE
+ health = 25
+ maxHealth = 25
+ damage_coeff = list(BRUTE = 0.5, BURN = 0.7, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0)
+ pass_flags = PASSMOB
+
+ radio_key = /obj/item/encryptionkey/secbot //AI Priv + Security
+ radio_channel = RADIO_CHANNEL_SECURITY //Security channel
+ bot_type = SEC_BOT
+ model = "Securitron"
+ bot_core_type = /obj/machinery/bot_core/secbot
+ window_id = "autosec"
+ window_name = "Automatic Security Unit v1.6"
+ allow_pai = 0
+ data_hud_type = DATA_HUD_SECURITY_ADVANCED
+ path_image_color = "#FF0000"
+
+ var/baton_type = /obj/item/melee/baton
+ var/mob/living/carbon/target
+ var/oldtarget_name
+ var/threatlevel = FALSE
+ var/target_lastloc //Loc of target when arrested.
+ var/last_found //There's a delay
+ var/declare_arrests = TRUE //When making an arrest, should it notify everyone on the security channel?
+ var/idcheck = FALSE //If true, arrest people with no IDs
+ var/weaponscheck = FALSE //If true, arrest people for weapons if they lack access
+ var/check_records = TRUE //Does it check security records?
+ var/arrest_type = FALSE //If true, don't handcuff
+
+/mob/living/simple_animal/bot/secbot/beepsky
+ name = "Officer Beep O'sky"
+ desc = "It's Officer Beep O'sky! Powered by a potato and a shot of whiskey."
+ idcheck = FALSE
+ weaponscheck = FALSE
+ auto_patrol = TRUE
+
+/mob/living/simple_animal/bot/secbot/beepsky/jr
+ name = "Officer Pipsqueak"
+ desc = "It's Officer Beep O'sky's smaller, just-as aggressive cousin, Pipsqueak."
+
+/mob/living/simple_animal/bot/secbot/beepsky/jr/Initialize()
+ . = ..()
+ resize = 0.8
+ update_transform()
+
+
+/mob/living/simple_animal/bot/secbot/beepsky/explode()
+ var/atom/Tsec = drop_location()
+ new /obj/item/stock_parts/cell/potato(Tsec)
+ var/obj/item/reagent_containers/food/drinks/drinkingglass/shotglass/S = new(Tsec)
+ S.reagents.add_reagent(/datum/reagent/consumable/ethanol/whiskey, 15)
+ S.on_reagent_change(ADD_REAGENT)
+ ..()
+
+/mob/living/simple_animal/bot/secbot/pingsky
+ name = "Officer Pingsky"
+ desc = "It's Officer Pingsky! Delegated to satellite guard duty for harbouring anti-human sentiment."
+ radio_channel = RADIO_CHANNEL_AI_PRIVATE
+
+/mob/living/simple_animal/bot/secbot/Initialize()
+ . = ..()
+ update_icon()
+ var/datum/job/detective/J = new/datum/job/detective
+ access_card.access += J.get_access()
+ prev_access = access_card.access
+
+ //SECHUD
+ var/datum/atom_hud/secsensor = GLOB.huds[DATA_HUD_SECURITY_ADVANCED]
+ secsensor.add_hud_to(src)
+
+/mob/living/simple_animal/bot/secbot/update_icon()
+ if(mode == BOT_HUNT)
+ icon_state = "[initial(icon_state)]-c"
+ return
+ ..()
+
+/mob/living/simple_animal/bot/secbot/turn_off()
+ ..()
+ mode = BOT_IDLE
+
+/mob/living/simple_animal/bot/secbot/bot_reset()
+ ..()
+ target = null
+ oldtarget_name = null
+ anchored = FALSE
+ walk_to(src,0)
+ last_found = world.time
+
+/mob/living/simple_animal/bot/secbot/set_custom_texts()
+
+ text_hack = "You overload [name]'s target identification system."
+ text_dehack = "You reboot [name] and restore the target identification."
+ text_dehack_fail = "[name] refuses to accept your authority!"
+
+/mob/living/simple_animal/bot/secbot/get_controls(mob/user)
+ var/dat
+ dat += hack(user)
+ dat += showpai(user)
+ dat += text({"
+Securitron v1.6 controls
+Status: []
+Behaviour controls are [locked ? "locked" : "unlocked"]
+Maintenance panel panel is [open ? "opened" : "closed"]"},
+
+"[on ? "On" : "Off"]" )
+
+ if(!locked || issilicon(user) || IsAdminGhost(user))
+ dat += text({"
+Arrest Unidentifiable Persons: []
+Arrest for Unauthorized Weapons: []
+Arrest for Warrant: []
+Operating Mode: []
+Report Arrests[]
+Auto Patrol: []"},
+
+"[idcheck ? "Yes" : "No"]",
+"[weaponscheck ? "Yes" : "No"]",
+"[check_records ? "Yes" : "No"]",
+"[arrest_type ? "Detain" : "Arrest"]",
+"[declare_arrests ? "Yes" : "No"]",
+"[auto_patrol ? "On" : "Off"]" )
+
+ return dat
+
+/mob/living/simple_animal/bot/secbot/Topic(href, href_list)
+ if(..())
+ return 1
+
+ if(!issilicon(usr) && !IsAdminGhost(usr) && !(bot_core.allowed(usr) || !locked))
+ return TRUE
+
+ switch(href_list["operation"])
+ if("idcheck")
+ idcheck = !idcheck
+ update_controls()
+ if("weaponscheck")
+ weaponscheck = !weaponscheck
+ update_controls()
+ if("ignorerec")
+ check_records = !check_records
+ update_controls()
+ if("switchmode")
+ arrest_type = !arrest_type
+ update_controls()
+ if("declarearrests")
+ declare_arrests = !declare_arrests
+ update_controls()
+
+/mob/living/simple_animal/bot/secbot/proc/retaliate(mob/living/carbon/human/H)
+ var/judgement_criteria = judgement_criteria()
+ threatlevel = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
+ threatlevel += 6
+ if(threatlevel >= 4)
+ target = H
+ mode = BOT_HUNT
+
+/mob/living/simple_animal/bot/secbot/proc/judgement_criteria()
+ var/final = FALSE
+ if(idcheck)
+ final = final|JUDGE_IDCHECK
+ if(check_records)
+ final = final|JUDGE_RECORDCHECK
+ if(weaponscheck)
+ final = final|JUDGE_WEAPONCHECK
+ if(emagged == 2)
+ final = final|JUDGE_EMAGGED
+ return final
+
+/mob/living/simple_animal/bot/secbot/proc/special_retaliate_after_attack(mob/user) //allows special actions to take place after being attacked.
+ return
+
+/mob/living/simple_animal/bot/secbot/attack_hand(mob/living/carbon/human/H)
+ if((H.a_intent == INTENT_HARM) || (H.a_intent == INTENT_DISARM))
+ retaliate(H)
+ if(special_retaliate_after_attack(H))
+ return
+
+ return ..()
+
+/mob/living/simple_animal/bot/secbot/attackby(obj/item/W, mob/user, params)
+ ..()
+ if(istype(W, /obj/item/weldingtool) && user.a_intent != INTENT_HARM) // Any intent but harm will heal, so we shouldn't get angry.
+ return
+ if(!istype(W, /obj/item/screwdriver) && (W.force) && (!target) && (W.damtype != STAMINA) ) // Added check for welding tool to fix #2432. Welding tool behavior is handled in superclass.
+ retaliate(user)
+ if(special_retaliate_after_attack(user))
+ return
+
+/mob/living/simple_animal/bot/secbot/emag_act(mob/user)
+ ..()
+ if(emagged == 2)
+ if(user)
+ to_chat(user, "You short out [src]'s target assessment circuits.")
+ oldtarget_name = user.name
+ audible_message("[src] buzzes oddly!")
+ declare_arrests = FALSE
+ update_icon()
+
+/mob/living/simple_animal/bot/secbot/bullet_act(obj/item/projectile/Proj)
+ if(istype(Proj , /obj/item/projectile/beam)||istype(Proj, /obj/item/projectile/bullet))
+ if((Proj.damage_type == BURN) || (Proj.damage_type == BRUTE))
+ if(!Proj.nodamage && Proj.damage < src.health && ishuman(Proj.firer))
+ retaliate(Proj.firer)
+ ..()
+
+
+/mob/living/simple_animal/bot/secbot/UnarmedAttack(atom/A)
+ if(!on)
+ return
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ if(C.canmove || arrest_type) // CIT CHANGE - makes sentient secbots check for canmove rather than !isstun.
+ stun_attack(A)
+ else if(C.canBeHandcuffed() && !C.handcuffed)
+ cuff(A)
+ else
+ ..()
+
+
+/mob/living/simple_animal/bot/secbot/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
+ if(istype(AM, /obj/item))
+ var/obj/item/I = AM
+ if(I.throwforce < src.health && I.thrownby && ishuman(I.thrownby))
+ var/mob/living/carbon/human/H = I.thrownby
+ retaliate(H)
+ ..()
+
+
+/mob/living/simple_animal/bot/secbot/proc/cuff(mob/living/carbon/C)
+ mode = BOT_ARREST
+ playsound(src, 'sound/weapons/cablecuff.ogg', 30, TRUE, -2)
+ C.visible_message("[src] is trying to put zipties on [C]!",\
+ "[src] is trying to put zipties on you!")
+ addtimer(CALLBACK(src, .proc/attempt_handcuff, C), 60)
+
+/mob/living/simple_animal/bot/secbot/proc/attempt_handcuff(mob/living/carbon/C)
+ if( !on || !Adjacent(C) || !isturf(C.loc) ) //if he's in a closet or not adjacent, we cancel cuffing.
+ return
+ if(!C.handcuffed)
+ C.handcuffed = new /obj/item/restraints/handcuffs/cable/zipties/used(C)
+ C.update_handcuffed()
+ playsound(src, "law", 50, 0)
+ back_to_idle()
+
+/mob/living/simple_animal/bot/secbot/proc/stun_attack(mob/living/carbon/C)
+ var/judgement_criteria = judgement_criteria()
+ playsound(src, 'sound/weapons/egloves.ogg', 50, TRUE, -1)
+ icon_state = "secbot-c"
+ addtimer(CALLBACK(src, .proc/update_icon), 2)
+ var/threat = 5
+ if(ishuman(C))
+ C.stuttering = 5
+ C.Knockdown(100)
+ var/mob/living/carbon/human/H = C
+ threat = H.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
+ else
+ C.Knockdown(100)
+ C.stuttering = 5
+ threat = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
+
+ log_combat(src,C,"stunned")
+ if(declare_arrests)
+ var/area/location = get_area(src)
+ speak("[arrest_type ? "Detaining" : "Arresting"] level [threat] scumbag [C] in [location].", radio_channel)
+ C.visible_message("[src] has stunned [C]!",\
+ "[src] has stunned you!")
+
+/mob/living/simple_animal/bot/secbot/handle_automated_action()
+ if(!..())
+ return
+
+ switch(mode)
+
+ if(BOT_IDLE) // idle
+
+ walk_to(src,0)
+ look_for_perp() // see if any criminals are in range
+ if(!mode && auto_patrol) // still idle, and set to patrol
+ mode = BOT_START_PATROL // switch to patrol mode
+
+ if(BOT_HUNT) // hunting for perp
+
+ // if can't reach perp for long enough, go idle
+ if(frustration >= 8)
+ walk_to(src,0)
+ back_to_idle()
+ return
+
+ if(target) // make sure target exists
+ if(Adjacent(target) && isturf(target.loc)) // if right next to perp
+ stun_attack(target)
+
+ mode = BOT_PREP_ARREST
+ anchored = TRUE
+ target_lastloc = target.loc
+ return
+
+ else // not next to perp
+ var/turf/olddist = get_dist(src, target)
+ walk_to(src, target,1,4)
+ if((get_dist(src, target)) >= (olddist))
+ frustration++
+ else
+ frustration = 0
+ else
+ back_to_idle()
+
+ if(BOT_PREP_ARREST) // preparing to arrest target
+
+ // see if he got away. If he's no no longer adjacent or inside a closet or about to get up, we hunt again.
+ if( !Adjacent(target) || !isturf(target.loc) || target.getStaminaLoss() <= 120 || !target.recoveringstam) //CIT CHANGE - replaces amountknockdown with checks for stamina so secbots dont run into an infinite loop
+ back_to_hunt()
+ return
+
+ if(iscarbon(target) && target.canBeHandcuffed())
+ if(!arrest_type)
+ if(!target.handcuffed) //he's not cuffed? Try to cuff him!
+ cuff(target)
+ else
+ back_to_idle()
+ return
+ else
+ back_to_idle()
+ return
+
+ if(BOT_ARREST)
+ if(!target)
+ anchored = FALSE
+ mode = BOT_IDLE
+ last_found = world.time
+ frustration = 0
+ return
+
+ if(target.handcuffed) //no target or target cuffed? back to idle.
+ back_to_idle()
+ return
+
+ if(!Adjacent(target) || !isturf(target.loc) || (target.loc != target_lastloc && !target.recoveringstam && target.getStaminaLoss() <= 120)) //if he's changed loc and about to get up or not adjacent or got into a closet, we prep arrest again. CIT CHANGE - replaces amountknockdown with recoveringstam and staminaloss check
+ back_to_hunt()
+ return
+ else //Try arresting again if the target escapes.
+ mode = BOT_PREP_ARREST
+ anchored = FALSE
+
+ if(BOT_START_PATROL)
+ look_for_perp()
+ start_patrol()
+
+ if(BOT_PATROL)
+ look_for_perp()
+ bot_patrol()
+
+
+ return
+
+/mob/living/simple_animal/bot/secbot/proc/back_to_idle()
+ anchored = FALSE
+ mode = BOT_IDLE
+ target = null
+ last_found = world.time
+ frustration = 0
+ INVOKE_ASYNC(src, .proc/handle_automated_action)
+
+/mob/living/simple_animal/bot/secbot/proc/back_to_hunt()
+ anchored = FALSE
+ frustration = 0
+ mode = BOT_HUNT
+ INVOKE_ASYNC(src, .proc/handle_automated_action)
+// look for a criminal in view of the bot
+
+/mob/living/simple_animal/bot/secbot/proc/look_for_perp()
+ anchored = FALSE
+ var/judgement_criteria = judgement_criteria()
+ for (var/mob/living/carbon/C in view(7,src)) //Let's find us a criminal
+ if((C.stat) || (C.handcuffed))
+ continue
+
+ if((C.name == oldtarget_name) && (world.time < last_found + 100))
+ continue
+
+ threatlevel = C.assess_threat(judgement_criteria, weaponcheck=CALLBACK(src, .proc/check_for_weapons))
+
+ if(!threatlevel)
+ continue
+
+ else if(threatlevel >= 4)
+ target = C
+ oldtarget_name = C.name
+ speak("Level [threatlevel] infraction alert!")
+ playsound(loc, pick('sound/voice/beepsky/criminal.ogg', 'sound/voice/beepsky/justice.ogg', 'sound/voice/beepsky/freeze.ogg'), 50, FALSE)
+ visible_message("[src] points at [C.name]!")
+ mode = BOT_HUNT
+ INVOKE_ASYNC(src, .proc/handle_automated_action)
+ break
+ else
+ continue
+
+/mob/living/simple_animal/bot/secbot/proc/check_for_weapons(var/obj/item/slot_item)
+ if(slot_item && (slot_item.item_flags & NEEDS_PERMIT))
+ return TRUE
+ return FALSE
+
+/mob/living/simple_animal/bot/secbot/explode()
+
+ walk_to(src,0)
+ visible_message("[src] blows apart!")
+ var/atom/Tsec = drop_location()
+
+ var/obj/item/bot_assembly/secbot/Sa = new (Tsec)
+ Sa.build_step = 1
+ Sa.add_overlay("hs_hole")
+ Sa.created_name = name
+ new /obj/item/assembly/prox_sensor(Tsec)
+ drop_part(baton_type, Tsec)
+
+ if(prob(50))
+ drop_part(robot_arm, Tsec)
+
+ do_sparks(3, TRUE, src)
+
+ new /obj/effect/decal/cleanable/oil(loc)
+ ..()
+
+/mob/living/simple_animal/bot/secbot/attack_alien(var/mob/living/carbon/alien/user as mob)
+ ..()
+ if(!isalien(target))
+ target = user
+ mode = BOT_HUNT
+
+/mob/living/simple_animal/bot/secbot/Crossed(atom/movable/AM)
+ if(has_gravity() && ismob(AM) && target)
+ var/mob/living/carbon/C = AM
+ if(!istype(C) || !C || in_range(src, target))
+ return
+ knockOver(C)
+ return
+ ..()
+
+/obj/machinery/bot_core/secbot
+ req_access = list(ACCESS_SECURITY)
diff --git a/code/modules/mob/living/simple_animal/friendly/cat.dm b/code/modules/mob/living/simple_animal/friendly/cat.dm
index a66abfdc..a6197a3f 100644
--- a/code/modules/mob/living/simple_animal/friendly/cat.dm
+++ b/code/modules/mob/living/simple_animal/friendly/cat.dm
@@ -1,319 +1,319 @@
-//Cat
-/mob/living/simple_animal/pet/cat
- name = "cat"
- desc = "Kitty!!"
- icon = 'icons/mob/pets.dmi'
- icon_state = "cat2"
- icon_living = "cat2"
- icon_dead = "cat2_dead"
- gender = MALE
- speak = list("Meow!", "Esp!", "Purr!", "HSSSSS")
- speak_emote = list("purrs", "meows")
- emote_hear = list("meows.", "mews.")
- emote_see = list("shakes its head.", "shivers.")
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
- ventcrawler = VENTCRAWLER_ALWAYS
- pass_flags = PASSTABLE
- mob_size = MOB_SIZE_SMALL
- mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
- minbodytemp = 200
- maxbodytemp = 400
- unsuitable_atmos_damage = 1
- animal_species = /mob/living/simple_animal/pet/cat
- childtype = list(/mob/living/simple_animal/pet/cat/kitten)
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2, /obj/item/organ/ears/cat = 1, /obj/item/organ/tail/cat = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- var/turns_since_scan = 0
- var/mob/living/simple_animal/mouse/movement_target
- gold_core_spawnable = FRIENDLY_SPAWN
- collar_type = "cat"
- size_multiplier = 0.5
-
- var/held_icon = "cat2"
- do_footstep = TRUE
-
-/mob/living/simple_animal/pet/cat/Initialize()
- . = ..()
- verbs += /mob/living/proc/lay_down
-
-/mob/living/simple_animal/pet/cat/ComponentInitialize()
- . = ..()
- AddElement(/datum/element/wuv, "purrs!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "hisses!", EMOTE_AUDIBLE)
- AddElement(/datum/element/mob_holder, held_icon)
-
-/mob/living/simple_animal/pet/cat/update_canmove()
- ..()
- if(client && stat != DEAD)
- if (resting)
- icon_state = "[icon_living]_rest"
- collar_type = "[initial(collar_type)]_rest"
- else
- icon_state = "[icon_living]"
- collar_type = "[initial(collar_type)]"
- regenerate_icons()
-
-
-/mob/living/simple_animal/pet/cat/space
- name = "space cat"
- desc = "It's a cat... in space!"
- icon_state = "spacecat"
- icon_living = "spacecat"
- icon_dead = "spacecat_dead"
- held_icon = "spacecat"
- unsuitable_atmos_damage = 0
- minbodytemp = TCMB
- maxbodytemp = T0C + 40
-
-/mob/living/simple_animal/pet/cat/original
- name = "Batsy"
- desc = "The product of alien DNA and bored geneticists."
- gender = FEMALE
- icon_state = "original"
- icon_living = "original"
- icon_dead = "original_dead"
- held_icon = "original"
- collar_type = null
- unique_pet = TRUE
-
-/mob/living/simple_animal/pet/cat/kitten
- name = "kitten"
- desc = "D'aaawwww."
- icon_state = "kitten"
- icon_living = "kitten"
- icon_dead = "kitten_dead"
- density = FALSE
- pass_flags = PASSMOB
- mob_size = MOB_SIZE_SMALL
- collar_type = "kitten"
- held_icon = "cat"
-
-//RUNTIME IS ALIVE! SQUEEEEEEEE~
-/mob/living/simple_animal/pet/cat/Runtime
- name = "Runtime"
- desc = "GCAT"
- icon_state = "cat"
- icon_living = "cat"
- icon_dead = "cat_dead"
- gender = FEMALE
- gold_core_spawnable = NO_SPAWN
- unique_pet = TRUE
- var/list/family = list()//var restored from savefile, has count of each child type
- var/list/children = list()//Actual mob instances of children
- var/cats_deployed = 0
- //var/memory_saved = FALSE
-
-/mob/living/simple_animal/pet/cat/Runtime/Initialize()
- if(prob(5))
- icon_state = "original"
- icon_living = "original"
- icon_dead = "original_dead"
- //Read_Memory()
- . = ..()
-/*
-/mob/living/simple_animal/pet/cat/Runtime/Life()
- if(!cats_deployed && SSticker.current_state >= GAME_STATE_SETTING_UP)
- Deploy_The_Cats()
- if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
- Write_Memory()
- memory_saved = TRUE
- ..()
-*/
-/mob/living/simple_animal/pet/cat/Runtime/make_babies()
- var/mob/baby = ..()
- if(baby)
- children += baby
- return baby
-/*
-/mob/living/simple_animal/pet/cat/Runtime/death()
- if(!memory_saved)
- Write_Memory(TRUE)
- ..()
-*/
-/mob/living/simple_animal/pet/cat/Runtime/proc/Read_Memory()
- if(fexists("data/npc_saves/Runtime.sav")) //legacy compatability to convert old format to new
- var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
- S["family"] >> family
- fdel("data/npc_saves/Runtime.sav")
- else
- var/json_file = file("data/npc_saves/Runtime.json")
- if(!fexists(json_file))
- return
- var/list/json = json_decode(file2text(json_file))
- family = json["family"]
- if(isnull(family))
- family = list()
-//All you people can't fucking control yourselves and keep letting runtime breed his own children, so it's time to at -LEAST- take the function that saves cats for the next round out the back and shoot it with a 12 gauge
-/*
-/mob/living/simple_animal/pet/cat/Runtime/proc/Write_Memory(dead)
- var/json_file = file("data/npc_saves/Runtime.json")
- var/list/file_data = list()
- family = list()
- if(!dead)
- for(var/mob/living/simple_animal/pet/cat/kitten/C in children)
- if(istype(C,type) || C.stat || !C.z || !C.butcher_results) //That last one is a work around for hologram cats
- continue
- if(C.type in family)
- family[C.type] += 1
- else
- family[C.type] = 1
- file_data["family"] = family
- fdel(json_file)
- WRITE_FILE(json_file, json_encode(file_data))
-
-/mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats()
- cats_deployed = 1
- for(var/cat_type in family)
- if(family[cat_type] > 0)
- for(var/i in 1 to min(family[cat_type],100)) //Limits to about 500 cats, you wouldn't think this would be needed (BUT IT IS)
- new cat_type(loc)
-*/
-
-/mob/living/simple_animal/pet/cat/Proc
- name = "Proc"
- gender = MALE
- gold_core_spawnable = NO_SPAWN
- unique_pet = TRUE
-
-/mob/living/simple_animal/pet/cat/Life()
- if(!stat && !buckled && !client)
- if(prob(1))
- emote("me", 1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
- icon_state = "[icon_living]_rest"
- collar_type = "[initial(collar_type)]_rest"
- resting = 1
- update_canmove()
- else if (prob(1))
- emote("me", 1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
- icon_state = "[icon_living]_sit"
- collar_type = "[initial(collar_type)]_sit"
- resting = 1
- update_canmove()
- else if (prob(1))
- if (resting)
- emote("me", 1, pick("gets up and meows.", "walks around.", "stops resting."))
- icon_state = "[icon_living]"
- collar_type = "[initial(collar_type)]"
- resting = 0
- update_canmove()
- else
- emote("me", 1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
-
- //MICE!
- if((src.loc) && isturf(src.loc))
- if(!stat && !resting && !buckled)
- for(var/mob/living/simple_animal/mouse/M in view(1,src))
- if(!M.stat && Adjacent(M))
- emote("me", 1, "splats \the [M]!")
- M.splat()
- movement_target = null
- stop_automated_movement = 0
- break
- for(var/obj/item/toy/cattoy/T in view(1,src))
- if (T.cooldown < (world.time - 400))
- emote("me", 1, "bats \the [T] around with its paw!")
- T.cooldown = world.time
-
- ..()
-
- make_babies()
-
- if(!stat && !resting && !buckled)
- turns_since_scan++
- if(turns_since_scan > 5)
- walk_to(src,0)
- turns_since_scan = 0
- if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
- movement_target = null
- stop_automated_movement = 0
- if( !movement_target || !(movement_target.loc in oview(src, 3)) )
- movement_target = null
- stop_automated_movement = 0
- for(var/mob/living/simple_animal/mouse/snack in oview(src,3))
- if(isturf(snack.loc) && !snack.stat)
- movement_target = snack
- break
- if(movement_target)
- stop_automated_movement = 1
- walk_to(src,movement_target,0,3)
-
-/mob/living/simple_animal/pet/cat/cak //I told you I'd do it, Remie
- name = "Keeki"
- desc = "It's a cat made out of cake."
- icon_state = "cak"
- icon_living = "cak"
- icon_dead = "cak_dead"
- health = 50
- maxHealth = 50
- gender = FEMALE
- harm_intent_damage = 10
- butcher_results = list(/obj/item/organ/brain = 1, /obj/item/organ/heart = 1, /obj/item/reagent_containers/food/snacks/cakeslice/birthday = 3, \
- /obj/item/reagent_containers/food/snacks/meat/slab = 2)
- response_harm = "takes a bite out of"
- attacked_sound = 'sound/items/eatfood.ogg'
- deathmessage = "loses its false life and collapses!"
- death_sound = "bodyfall"
- held_icon = "cak"
-
-/mob/living/simple_animal/pet/cat/cak/CheckParts(list/parts)
- ..()
- var/obj/item/organ/brain/B = locate(/obj/item/organ/brain) in contents
- if(!B || !B.brainmob || !B.brainmob.mind)
- return
- B.brainmob.mind.transfer_to(src)
- to_chat(src, "You are a cak! You're a harmless cat/cake hybrid that everyone loves. People can take bites out of you if they're hungry, but you regenerate health \
- so quickly that it generally doesn't matter. You're remarkably resilient to any damage besides this and it's hard for you to really die at all. You should go around and bring happiness and \
- free cake to the station!")
- var/new_name = stripped_input(src, "Enter your name, or press \"Cancel\" to stick with Keeki.", "Name Change")
- if(new_name)
- to_chat(src, "Your name is now \"new_name\"!")
- name = new_name
-
-/mob/living/simple_animal/pet/cat/cak/Life()
- ..()
- if(stat)
- return
- if(health < maxHealth)
- adjustBruteLoss(-8) //Fast life regen
- for(var/obj/item/reagent_containers/food/snacks/donut/D in range(1, src)) //Frosts nearby donuts!
- if(!D.is_decorated)
- D.decorate_donut()
-
-/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
- . = ..()
- if(.) //the attack was blocked
- return
- if(L.a_intent == INTENT_HARM && L.reagents && !stat)
- L.reagents.add_reagent("nutriment", 0.4)
- L.reagents.add_reagent("vitamin", 0.4)
-
-//Cat made
-/mob/living/simple_animal/pet/cat/custom_cat
- name = "White cat" //Incase it somehow gets spawned without an ID
- desc = "A cute white catto!"
- icon_state = "custom_cat"
- icon_living = "custom_cat"
- icon_dead = "custom_cat_dead"
- gender = FEMALE
- gold_core_spawnable = NO_SPAWN
- health = 50 //So people can't instakill it s
- maxHealth = 50
- speak = list("Meowrowr!", "Mew!", "Miauen!")
- speak_emote = list("wigglepurrs", "mewls")
- emote_hear = list("meows.", "mews.")
- emote_see = list("looks at you eagerly for pets!", "wiggles enthusiastically.")
- gold_core_spawnable = NO_SPAWN
- var/pseudo_death = FALSE
-
-/mob/living/simple_animal/pet/cat/custom_cat/death()
- if (pseudo_death == TRUE) //secret cat chem
- icon_state = "custom_cat_dead"
- Stun(1000)
- canmove = 0
- friendly = "deads at"
- return
- else
- ..()
+//Cat
+/mob/living/simple_animal/pet/cat
+ name = "cat"
+ desc = "Kitty!!"
+ icon = 'icons/mob/pets.dmi'
+ icon_state = "cat2"
+ icon_living = "cat2"
+ icon_dead = "cat2_dead"
+ gender = MALE
+ speak = list("Meow!", "Esp!", "Purr!", "HSSSSS")
+ speak_emote = list("purrs", "meows")
+ emote_hear = list("meows.", "mews.")
+ emote_see = list("shakes its head.", "shivers.")
+ speak_chance = 1
+ turns_per_move = 5
+ see_in_dark = 6
+ ventcrawler = VENTCRAWLER_ALWAYS
+ pass_flags = PASSTABLE
+ mob_size = MOB_SIZE_SMALL
+ mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
+ minbodytemp = 200
+ maxbodytemp = 400
+ unsuitable_atmos_damage = 1
+ animal_species = /mob/living/simple_animal/pet/cat
+ childtype = list(/mob/living/simple_animal/pet/cat/kitten)
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 2, /obj/item/organ/ears/cat = 1, /obj/item/organ/tail/cat = 1)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ var/turns_since_scan = 0
+ var/mob/living/simple_animal/mouse/movement_target
+ gold_core_spawnable = FRIENDLY_SPAWN
+ collar_type = "cat"
+ size_multiplier = 0.5
+
+ var/held_icon = "cat2"
+ do_footstep = TRUE
+
+/mob/living/simple_animal/pet/cat/Initialize()
+ . = ..()
+ verbs += /mob/living/proc/lay_down
+
+/mob/living/simple_animal/pet/cat/ComponentInitialize()
+ . = ..()
+ AddElement(/datum/element/wuv, "purrs!", EMOTE_AUDIBLE, /datum/mood_event/pet_animal, "hisses!", EMOTE_AUDIBLE)
+ AddElement(/datum/element/mob_holder, held_icon)
+
+/mob/living/simple_animal/pet/cat/update_canmove()
+ ..()
+ if(client && stat != DEAD)
+ if (resting)
+ icon_state = "[icon_living]_rest"
+ collar_type = "[initial(collar_type)]_rest"
+ else
+ icon_state = "[icon_living]"
+ collar_type = "[initial(collar_type)]"
+ regenerate_icons()
+
+
+/mob/living/simple_animal/pet/cat/space
+ name = "space cat"
+ desc = "It's a cat... in space!"
+ icon_state = "spacecat"
+ icon_living = "spacecat"
+ icon_dead = "spacecat_dead"
+ held_icon = "spacecat"
+ unsuitable_atmos_damage = 0
+ minbodytemp = TCMB
+ maxbodytemp = T0C + 40
+
+/mob/living/simple_animal/pet/cat/original
+ name = "Batsy"
+ desc = "The product of alien DNA and bored geneticists."
+ gender = FEMALE
+ icon_state = "original"
+ icon_living = "original"
+ icon_dead = "original_dead"
+ held_icon = "original"
+ collar_type = null
+ unique_pet = TRUE
+
+/mob/living/simple_animal/pet/cat/kitten
+ name = "kitten"
+ desc = "D'aaawwww."
+ icon_state = "kitten"
+ icon_living = "kitten"
+ icon_dead = "kitten_dead"
+ density = FALSE
+ pass_flags = PASSMOB
+ mob_size = MOB_SIZE_SMALL
+ collar_type = "kitten"
+ held_icon = "cat"
+
+//RUNTIME IS ALIVE! SQUEEEEEEEE~
+/mob/living/simple_animal/pet/cat/Runtime
+ name = "Runtime"
+ desc = "GCAT"
+ icon_state = "cat"
+ icon_living = "cat"
+ icon_dead = "cat_dead"
+ gender = FEMALE
+ gold_core_spawnable = NO_SPAWN
+ unique_pet = TRUE
+ var/list/family = list()//var restored from savefile, has count of each child type
+ var/list/children = list()//Actual mob instances of children
+ var/cats_deployed = 0
+ //var/memory_saved = FALSE
+
+/mob/living/simple_animal/pet/cat/Runtime/Initialize()
+ if(prob(5))
+ icon_state = "original"
+ icon_living = "original"
+ icon_dead = "original_dead"
+ //Read_Memory()
+ . = ..()
+/*
+/mob/living/simple_animal/pet/cat/Runtime/Life()
+ if(!cats_deployed && SSticker.current_state >= GAME_STATE_SETTING_UP)
+ Deploy_The_Cats()
+ if(!stat && SSticker.current_state == GAME_STATE_FINISHED && !memory_saved)
+ Write_Memory()
+ memory_saved = TRUE
+ ..()
+*/
+/mob/living/simple_animal/pet/cat/Runtime/make_babies()
+ var/mob/baby = ..()
+ if(baby)
+ children += baby
+ return baby
+/*
+/mob/living/simple_animal/pet/cat/Runtime/death()
+ if(!memory_saved)
+ Write_Memory(TRUE)
+ ..()
+*/
+/mob/living/simple_animal/pet/cat/Runtime/proc/Read_Memory()
+ if(fexists("data/npc_saves/Runtime.sav")) //legacy compatability to convert old format to new
+ var/savefile/S = new /savefile("data/npc_saves/Runtime.sav")
+ S["family"] >> family
+ fdel("data/npc_saves/Runtime.sav")
+ else
+ var/json_file = file("data/npc_saves/Runtime.json")
+ if(!fexists(json_file))
+ return
+ var/list/json = json_decode(file2text(json_file))
+ family = json["family"]
+ if(isnull(family))
+ family = list()
+//All you people can't fucking control yourselves and keep letting runtime breed his own children, so it's time to at -LEAST- take the function that saves cats for the next round out the back and shoot it with a 12 gauge
+/*
+/mob/living/simple_animal/pet/cat/Runtime/proc/Write_Memory(dead)
+ var/json_file = file("data/npc_saves/Runtime.json")
+ var/list/file_data = list()
+ family = list()
+ if(!dead)
+ for(var/mob/living/simple_animal/pet/cat/kitten/C in children)
+ if(istype(C,type) || C.stat || !C.z || !C.butcher_results) //That last one is a work around for hologram cats
+ continue
+ if(C.type in family)
+ family[C.type] += 1
+ else
+ family[C.type] = 1
+ file_data["family"] = family
+ fdel(json_file)
+ WRITE_FILE(json_file, json_encode(file_data))
+
+/mob/living/simple_animal/pet/cat/Runtime/proc/Deploy_The_Cats()
+ cats_deployed = 1
+ for(var/cat_type in family)
+ if(family[cat_type] > 0)
+ for(var/i in 1 to min(family[cat_type],100)) //Limits to about 500 cats, you wouldn't think this would be needed (BUT IT IS)
+ new cat_type(loc)
+*/
+
+/mob/living/simple_animal/pet/cat/Proc
+ name = "Proc"
+ gender = MALE
+ gold_core_spawnable = NO_SPAWN
+ unique_pet = TRUE
+
+/mob/living/simple_animal/pet/cat/Life()
+ if(!stat && !buckled && !client)
+ if(prob(1))
+ emote("me", 1, pick("stretches out for a belly rub.", "wags its tail.", "lies down."))
+ icon_state = "[icon_living]_rest"
+ collar_type = "[initial(collar_type)]_rest"
+ resting = 1
+ update_canmove()
+ else if (prob(1))
+ emote("me", 1, pick("sits down.", "crouches on its hind legs.", "looks alert."))
+ icon_state = "[icon_living]_sit"
+ collar_type = "[initial(collar_type)]_sit"
+ resting = 1
+ update_canmove()
+ else if (prob(1))
+ if (resting)
+ emote("me", 1, pick("gets up and meows.", "walks around.", "stops resting."))
+ icon_state = "[icon_living]"
+ collar_type = "[initial(collar_type)]"
+ resting = 0
+ update_canmove()
+ else
+ emote("me", 1, pick("grooms its fur.", "twitches its whiskers.", "shakes out its coat."))
+
+ //MICE!
+ if((src.loc) && isturf(src.loc))
+ if(!stat && !resting && !buckled)
+ for(var/mob/living/simple_animal/mouse/M in view(1,src))
+ if(!M.stat && Adjacent(M))
+ emote("me", 1, "splats \the [M]!")
+ M.splat()
+ movement_target = null
+ stop_automated_movement = 0
+ break
+ for(var/obj/item/toy/cattoy/T in view(1,src))
+ if (T.cooldown < (world.time - 400))
+ emote("me", 1, "bats \the [T] around with its paw!")
+ T.cooldown = world.time
+
+ ..()
+
+ make_babies()
+
+ if(!stat && !resting && !buckled)
+ turns_since_scan++
+ if(turns_since_scan > 5)
+ walk_to(src,0)
+ turns_since_scan = 0
+ if((movement_target) && !(isturf(movement_target.loc) || ishuman(movement_target.loc) ))
+ movement_target = null
+ stop_automated_movement = 0
+ if( !movement_target || !(movement_target.loc in oview(src, 3)) )
+ movement_target = null
+ stop_automated_movement = 0
+ for(var/mob/living/simple_animal/mouse/snack in oview(src,3))
+ if(isturf(snack.loc) && !snack.stat)
+ movement_target = snack
+ break
+ if(movement_target)
+ stop_automated_movement = 1
+ walk_to(src,movement_target,0,3)
+
+/mob/living/simple_animal/pet/cat/cak //I told you I'd do it, Remie
+ name = "Keeki"
+ desc = "It's a cat made out of cake."
+ icon_state = "cak"
+ icon_living = "cak"
+ icon_dead = "cak_dead"
+ health = 50
+ maxHealth = 50
+ gender = FEMALE
+ harm_intent_damage = 10
+ butcher_results = list(/obj/item/organ/brain = 1, /obj/item/organ/heart = 1, /obj/item/reagent_containers/food/snacks/cakeslice/birthday = 3, \
+ /obj/item/reagent_containers/food/snacks/meat/slab = 2)
+ response_harm = "takes a bite out of"
+ attacked_sound = 'sound/items/eatfood.ogg'
+ deathmessage = "loses its false life and collapses!"
+ death_sound = "bodyfall"
+ held_icon = "cak"
+
+/mob/living/simple_animal/pet/cat/cak/CheckParts(list/parts)
+ ..()
+ var/obj/item/organ/brain/B = locate(/obj/item/organ/brain) in contents
+ if(!B || !B.brainmob || !B.brainmob.mind)
+ return
+ B.brainmob.mind.transfer_to(src)
+ to_chat(src, "You are a cak! You're a harmless cat/cake hybrid that everyone loves. People can take bites out of you if they're hungry, but you regenerate health \
+ so quickly that it generally doesn't matter. You're remarkably resilient to any damage besides this and it's hard for you to really die at all. You should go around and bring happiness and \
+ free cake to the station!")
+ var/new_name = stripped_input(src, "Enter your name, or press \"Cancel\" to stick with Keeki.", "Name Change")
+ if(new_name)
+ to_chat(src, "Your name is now \"new_name\"!")
+ name = new_name
+
+/mob/living/simple_animal/pet/cat/cak/Life()
+ ..()
+ if(stat)
+ return
+ if(health < maxHealth)
+ adjustBruteLoss(-8) //Fast life regen
+ for(var/obj/item/reagent_containers/food/snacks/donut/D in range(1, src)) //Frosts nearby donuts!
+ if(!D.is_decorated)
+ D.decorate_donut()
+
+/mob/living/simple_animal/pet/cat/cak/attack_hand(mob/living/L)
+ . = ..()
+ if(.) //the attack was blocked
+ return
+ if(L.a_intent == INTENT_HARM && L.reagents && !stat)
+ L.reagents.add_reagent(/datum/reagent/consumable/nutriment, 0.4)
+ L.reagents.add_reagent(/datum/reagent/consumable/nutriment/vitamin, 0.4)
+
+//Cat made
+/mob/living/simple_animal/pet/cat/custom_cat
+ name = "White cat" //Incase it somehow gets spawned without an ID
+ desc = "A cute white catto!"
+ icon_state = "custom_cat"
+ icon_living = "custom_cat"
+ icon_dead = "custom_cat_dead"
+ gender = FEMALE
+ gold_core_spawnable = NO_SPAWN
+ health = 50 //So people can't instakill it s
+ maxHealth = 50
+ speak = list("Meowrowr!", "Mew!", "Miauen!")
+ speak_emote = list("wigglepurrs", "mewls")
+ emote_hear = list("meows.", "mews.")
+ emote_see = list("looks at you eagerly for pets!", "wiggles enthusiastically.")
+ gold_core_spawnable = NO_SPAWN
+ var/pseudo_death = FALSE
+
+/mob/living/simple_animal/pet/cat/custom_cat/death()
+ if (pseudo_death == TRUE) //secret cat chem
+ icon_state = "custom_cat_dead"
+ Stun(1000)
+ canmove = 0
+ friendly = "deads at"
+ return
+ else
+ ..()
diff --git a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
index 22a666ee..4438da05 100644
--- a/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
+++ b/code/modules/mob/living/simple_animal/friendly/farm_animals.dm
@@ -1,348 +1,348 @@
-//goat
-/mob/living/simple_animal/hostile/retaliate/goat
- name = "goat"
- desc = "Not known for their pleasant disposition."
- icon_state = "goat"
- icon_living = "goat"
- icon_dead = "goat_dead"
- speak = list("EHEHEHEHEH","eh?")
- speak_emote = list("brays")
- emote_hear = list("brays.")
- emote_see = list("shakes its head.", "stamps a foot.", "glares around.")
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 4)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- faction = list("neutral")
- mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
- attack_same = 1
- attacktext = "kicks"
- attack_sound = 'sound/weapons/punch1.ogg'
- health = 40
- maxHealth = 40
- melee_damage_lower = 1
- melee_damage_upper = 2
- environment_smash = ENVIRONMENT_SMASH_NONE
- stop_automated_movement_when_pulled = 1
- blood_volume = BLOOD_VOLUME_NORMAL
- var/obj/item/udder/udder = null
-
- do_footstep = TRUE
-
-/mob/living/simple_animal/hostile/retaliate/goat/Initialize()
- udder = new()
- . = ..()
-
-/mob/living/simple_animal/hostile/retaliate/goat/Destroy()
- qdel(udder)
- udder = null
- return ..()
-
-/mob/living/simple_animal/hostile/retaliate/goat/Life()
- . = ..()
- if(.)
- //chance to go crazy and start wacking stuff
- if(!enemies.len && prob(1))
- Retaliate()
-
- if(enemies.len && prob(10))
- enemies = list()
- LoseTarget()
- src.visible_message("[src] calms down.")
- if(stat == CONSCIOUS)
- udder.generateMilk()
- eat_plants()
- if(!pulledby)
- for(var/direction in shuffle(list(1,2,4,8,5,6,9,10)))
- var/step = get_step(src, direction)
- if(step)
- if(locate(/obj/structure/spacevine) in step || locate(/obj/structure/glowshroom) in step)
- Move(step, get_dir(src, step))
-
-/mob/living/simple_animal/hostile/retaliate/goat/Retaliate()
- ..()
- src.visible_message("[src] gets an evil-looking gleam in [p_their()] eye.")
-
-/mob/living/simple_animal/hostile/retaliate/goat/Move()
- . = ..()
- if(!stat)
- eat_plants()
-
-/mob/living/simple_animal/hostile/retaliate/goat/proc/eat_plants()
- var/eaten = FALSE
- var/obj/structure/spacevine/SV = locate(/obj/structure/spacevine) in loc
- if(SV)
- SV.eat(src)
- eaten = TRUE
-
- var/obj/structure/glowshroom/GS = locate(/obj/structure/glowshroom) in loc
- if(GS)
- qdel(GS)
- eaten = TRUE
-
- if(eaten && prob(10))
- say("Nom")
-
-/mob/living/simple_animal/hostile/retaliate/goat/attackby(obj/item/O, mob/user, params)
- if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
- udder.milkAnimal(O, user)
- return 1
- else
- return ..()
-
-
-/mob/living/simple_animal/hostile/retaliate/goat/AttackingTarget()
- . = ..()
- if(. && ishuman(target))
- var/mob/living/carbon/human/H = target
- if(istype(H.dna.species, /datum/species/pod))
- var/obj/item/bodypart/NB = pick(H.bodyparts)
- H.visible_message("[src] takes a big chomp out of [H]!", \
- "[src] takes a big chomp out of your [NB]!")
- NB.dismember()
-//cow
-/mob/living/simple_animal/cow
- name = "cow"
- desc = "Known for their milk, just don't tip them over."
- icon_state = "cow"
- icon_living = "cow"
- icon_dead = "cow_dead"
- icon_gib = "cow_gib"
- gender = FEMALE
- mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
- speak = list("moo?","moo","MOOOOOO")
- speak_emote = list("moos","moos hauntingly")
- emote_hear = list("brays.")
- emote_see = list("shakes its head.")
- speak_chance = 1
- turns_per_move = 5
- see_in_dark = 6
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 6)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
- attack_sound = 'sound/weapons/punch1.ogg'
- health = 50
- maxHealth = 50
- var/obj/item/udder/udder = null
- gold_core_spawnable = FRIENDLY_SPAWN
- blood_volume = BLOOD_VOLUME_NORMAL
-
- do_footstep = TRUE
-
-/mob/living/simple_animal/cow/Initialize()
- udder = new()
- . = ..()
-
-/mob/living/simple_animal/cow/Destroy()
- qdel(udder)
- udder = null
- return ..()
-
-/mob/living/simple_animal/cow/attackby(obj/item/O, mob/user, params)
- if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
- udder.milkAnimal(O, user)
- return 1
- else
- return ..()
-
-/mob/living/simple_animal/cow/Life()
- . = ..()
- if(stat == CONSCIOUS)
- udder.generateMilk()
-
-/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M)
- if(!stat && M.a_intent == INTENT_DISARM && icon_state != icon_dead)
- M.visible_message("[M] tips over [src].",
- "You tip over [src].")
- to_chat(src, "You are tipped over by [M]!")
- Knockdown(60,ignore_canknockdown = TRUE)
- icon_state = icon_dead
- spawn(rand(20,50))
- if(!stat && M)
- icon_state = icon_living
- var/external
- var/internal
- switch(pick(1,2,3,4))
- if(1,2,3)
- var/text = pick("imploringly.", "pleadingly.",
- "with a resigned expression.")
- external = "[src] looks at [M] [text]"
- internal = "You look at [M] [text]"
- if(4)
- external = "[src] seems resigned to its fate."
- internal = "You resign yourself to your fate."
- visible_message("[external]",
- "[internal]")
- else
- ..()
-
-/mob/living/simple_animal/chick
- name = "\improper chick"
- desc = "Adorable! They make such a racket though."
- icon_state = "chick"
- icon_living = "chick"
- icon_dead = "chick_dead"
- icon_gib = "chick_gib"
- gender = FEMALE
- mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
- speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
- speak_emote = list("cheeps")
- emote_hear = list("cheeps.")
- emote_see = list("pecks at the ground.","flaps its tiny wings.")
- density = FALSE
- speak_chance = 2
- turns_per_move = 2
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
- health = 3
- maxHealth = 3
- ventcrawler = VENTCRAWLER_ALWAYS
- var/amount_grown = 0
- pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
- mob_size = MOB_SIZE_TINY
- gold_core_spawnable = FRIENDLY_SPAWN
-
- do_footstep = TRUE
-
-/mob/living/simple_animal/chick/Initialize()
- . = ..()
- pixel_x = rand(-6, 6)
- pixel_y = rand(0, 10)
-
-/mob/living/simple_animal/chick/Life()
- . =..()
- if(!.)
- return
- if(!stat && !ckey)
- amount_grown += rand(1,2)
- if(amount_grown >= 100)
- new /mob/living/simple_animal/chicken(src.loc)
- qdel(src)
-
-/mob/living/simple_animal/chick/holo/Life()
- ..()
- amount_grown = 0
-
-/mob/living/simple_animal/chicken
- name = "\improper chicken"
- desc = "Hopefully the eggs are good this season."
- gender = FEMALE
- mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
- icon_state = "chicken_brown"
- icon_living = "chicken_brown"
- icon_dead = "chicken_brown_dead"
- speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
- speak_emote = list("clucks","croons")
- emote_hear = list("clucks.")
- emote_see = list("pecks at the ground.","flaps its wings viciously.")
- density = FALSE
- speak_chance = 2
- turns_per_move = 3
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2)
- var/egg_type = /obj/item/reagent_containers/food/snacks/egg
- var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "kicks"
- attacktext = "kicks"
- health = 15
- maxHealth = 15
- ventcrawler = VENTCRAWLER_ALWAYS
- var/eggsleft = 0
- var/eggsFertile = TRUE
- var/body_color
- var/icon_prefix = "chicken"
- pass_flags = PASSTABLE | PASSMOB
- mob_size = MOB_SIZE_SMALL
- var/list/feedMessages = list("It clucks happily.","It clucks happily.")
- var/list/layMessage = EGG_LAYING_MESSAGES
- var/list/validColors = list("brown","black","white")
- gold_core_spawnable = FRIENDLY_SPAWN
- var/static/chicken_count = 0
-
- do_footstep = TRUE
-
-/mob/living/simple_animal/chicken/Initialize()
- . = ..()
- if(!body_color)
- body_color = pick(validColors)
- icon_state = "[icon_prefix]_[body_color]"
- icon_living = "[icon_prefix]_[body_color]"
- icon_dead = "[icon_prefix]_[body_color]_dead"
- pixel_x = rand(-6, 6)
- pixel_y = rand(0, 10)
- ++chicken_count
-
-/mob/living/simple_animal/chicken/Destroy()
- --chicken_count
- return ..()
-
-/mob/living/simple_animal/chicken/attackby(obj/item/O, mob/user, params)
- if(istype(O, food_type)) //feedin' dem chickens
- if(!stat && eggsleft < 8)
- var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
- user.visible_message(feedmsg)
- qdel(O)
- eggsleft += rand(1, 4)
- else
- to_chat(user, "[name] doesn't seem hungry!")
- else
- ..()
-
-/mob/living/simple_animal/chicken/Life()
- . =..()
- if(!.)
- return
- if((!stat && prob(3) && eggsleft > 0) && egg_type)
- visible_message("[src] [pick(layMessage)]")
- eggsleft--
- var/obj/item/E = new egg_type(get_turf(src))
- E.pixel_x = rand(-6,6)
- E.pixel_y = rand(-6,6)
- if(eggsFertile)
- if(chicken_count < MAX_CHICKENS && prob(25))
- START_PROCESSING(SSobj, E)
-
-/obj/item/reagent_containers/food/snacks/egg/var/amount_grown = 0
-/obj/item/reagent_containers/food/snacks/egg/process()
- if(isturf(loc))
- amount_grown += rand(1,2)
- if(amount_grown >= 100)
- visible_message("[src] hatches with a quiet cracking sound.")
- new /mob/living/simple_animal/chick(get_turf(src))
- STOP_PROCESSING(SSobj, src)
- qdel(src)
- else
- STOP_PROCESSING(SSobj, src)
-
-
-/obj/item/udder
- name = "udder"
-
-/obj/item/udder/Initialize()
- create_reagents(50)
- reagents.add_reagent("milk", 20)
- . = ..()
-
-/obj/item/udder/proc/generateMilk()
- if(prob(5))
- reagents.add_reagent("milk", rand(5, 10))
-
-/obj/item/udder/proc/milkAnimal(obj/O, mob/user)
- var/obj/item/reagent_containers/glass/G = O
- if(G.reagents.total_volume >= G.volume)
- to_chat(user, "[O] is full.")
- return
- var/transfered = reagents.trans_to(O, rand(5,10))
- if(transfered)
- user.visible_message("[user] milks [src] using \the [O].", "You milk [src] using \the [O].")
- else
- to_chat(user, "The udder is dry. Wait a bit longer...")
+//goat
+/mob/living/simple_animal/hostile/retaliate/goat
+ name = "goat"
+ desc = "Not known for their pleasant disposition."
+ icon_state = "goat"
+ icon_living = "goat"
+ icon_dead = "goat_dead"
+ speak = list("EHEHEHEHEH","eh?")
+ speak_emote = list("brays")
+ emote_hear = list("brays.")
+ emote_see = list("shakes its head.", "stamps a foot.", "glares around.")
+ speak_chance = 1
+ turns_per_move = 5
+ see_in_dark = 6
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 4)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ faction = list("neutral")
+ mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
+ attack_same = 1
+ attacktext = "kicks"
+ attack_sound = 'sound/weapons/punch1.ogg'
+ health = 40
+ maxHealth = 40
+ melee_damage_lower = 1
+ melee_damage_upper = 2
+ environment_smash = ENVIRONMENT_SMASH_NONE
+ stop_automated_movement_when_pulled = 1
+ blood_volume = BLOOD_VOLUME_NORMAL
+ var/obj/item/udder/udder = null
+
+ do_footstep = TRUE
+
+/mob/living/simple_animal/hostile/retaliate/goat/Initialize()
+ udder = new()
+ . = ..()
+
+/mob/living/simple_animal/hostile/retaliate/goat/Destroy()
+ qdel(udder)
+ udder = null
+ return ..()
+
+/mob/living/simple_animal/hostile/retaliate/goat/Life()
+ . = ..()
+ if(.)
+ //chance to go crazy and start wacking stuff
+ if(!enemies.len && prob(1))
+ Retaliate()
+
+ if(enemies.len && prob(10))
+ enemies = list()
+ LoseTarget()
+ src.visible_message("[src] calms down.")
+ if(stat == CONSCIOUS)
+ udder.generateMilk()
+ eat_plants()
+ if(!pulledby)
+ for(var/direction in shuffle(list(1,2,4,8,5,6,9,10)))
+ var/step = get_step(src, direction)
+ if(step)
+ if(locate(/obj/structure/spacevine) in step || locate(/obj/structure/glowshroom) in step)
+ Move(step, get_dir(src, step))
+
+/mob/living/simple_animal/hostile/retaliate/goat/Retaliate()
+ ..()
+ src.visible_message("[src] gets an evil-looking gleam in [p_their()] eye.")
+
+/mob/living/simple_animal/hostile/retaliate/goat/Move()
+ . = ..()
+ if(!stat)
+ eat_plants()
+
+/mob/living/simple_animal/hostile/retaliate/goat/proc/eat_plants()
+ var/eaten = FALSE
+ var/obj/structure/spacevine/SV = locate(/obj/structure/spacevine) in loc
+ if(SV)
+ SV.eat(src)
+ eaten = TRUE
+
+ var/obj/structure/glowshroom/GS = locate(/obj/structure/glowshroom) in loc
+ if(GS)
+ qdel(GS)
+ eaten = TRUE
+
+ if(eaten && prob(10))
+ say("Nom")
+
+/mob/living/simple_animal/hostile/retaliate/goat/attackby(obj/item/O, mob/user, params)
+ if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
+ udder.milkAnimal(O, user)
+ return 1
+ else
+ return ..()
+
+
+/mob/living/simple_animal/hostile/retaliate/goat/AttackingTarget()
+ . = ..()
+ if(. && ishuman(target))
+ var/mob/living/carbon/human/H = target
+ if(istype(H.dna.species, /datum/species/pod))
+ var/obj/item/bodypart/NB = pick(H.bodyparts)
+ H.visible_message("[src] takes a big chomp out of [H]!", \
+ "[src] takes a big chomp out of your [NB]!")
+ NB.dismember()
+//cow
+/mob/living/simple_animal/cow
+ name = "cow"
+ desc = "Known for their milk, just don't tip them over."
+ icon_state = "cow"
+ icon_living = "cow"
+ icon_dead = "cow_dead"
+ icon_gib = "cow_gib"
+ gender = FEMALE
+ mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
+ speak = list("moo?","moo","MOOOOOO")
+ speak_emote = list("moos","moos hauntingly")
+ emote_hear = list("brays.")
+ emote_see = list("shakes its head.")
+ speak_chance = 1
+ turns_per_move = 5
+ see_in_dark = 6
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab = 6)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ attacktext = "kicks"
+ attack_sound = 'sound/weapons/punch1.ogg'
+ health = 50
+ maxHealth = 50
+ var/obj/item/udder/udder = null
+ gold_core_spawnable = FRIENDLY_SPAWN
+ blood_volume = BLOOD_VOLUME_NORMAL
+
+ do_footstep = TRUE
+
+/mob/living/simple_animal/cow/Initialize()
+ udder = new()
+ . = ..()
+
+/mob/living/simple_animal/cow/Destroy()
+ qdel(udder)
+ udder = null
+ return ..()
+
+/mob/living/simple_animal/cow/attackby(obj/item/O, mob/user, params)
+ if(stat == CONSCIOUS && istype(O, /obj/item/reagent_containers/glass))
+ udder.milkAnimal(O, user)
+ return 1
+ else
+ return ..()
+
+/mob/living/simple_animal/cow/Life()
+ . = ..()
+ if(stat == CONSCIOUS)
+ udder.generateMilk()
+
+/mob/living/simple_animal/cow/attack_hand(mob/living/carbon/M)
+ if(!stat && M.a_intent == INTENT_DISARM && icon_state != icon_dead)
+ M.visible_message("[M] tips over [src].",
+ "You tip over [src].")
+ to_chat(src, "You are tipped over by [M]!")
+ Knockdown(60,ignore_canknockdown = TRUE)
+ icon_state = icon_dead
+ spawn(rand(20,50))
+ if(!stat && M)
+ icon_state = icon_living
+ var/external
+ var/internal
+ switch(pick(1,2,3,4))
+ if(1,2,3)
+ var/text = pick("imploringly.", "pleadingly.",
+ "with a resigned expression.")
+ external = "[src] looks at [M] [text]"
+ internal = "You look at [M] [text]"
+ if(4)
+ external = "[src] seems resigned to its fate."
+ internal = "You resign yourself to your fate."
+ visible_message("[external]",
+ "[internal]")
+ else
+ ..()
+
+/mob/living/simple_animal/chick
+ name = "\improper chick"
+ desc = "Adorable! They make such a racket though."
+ icon_state = "chick"
+ icon_living = "chick"
+ icon_dead = "chick_dead"
+ icon_gib = "chick_gib"
+ gender = FEMALE
+ mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
+ speak = list("Cherp.","Cherp?","Chirrup.","Cheep!")
+ speak_emote = list("cheeps")
+ emote_hear = list("cheeps.")
+ emote_see = list("pecks at the ground.","flaps its tiny wings.")
+ density = FALSE
+ speak_chance = 2
+ turns_per_move = 2
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 1)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ attacktext = "kicks"
+ health = 3
+ maxHealth = 3
+ ventcrawler = VENTCRAWLER_ALWAYS
+ var/amount_grown = 0
+ pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
+ mob_size = MOB_SIZE_TINY
+ gold_core_spawnable = FRIENDLY_SPAWN
+
+ do_footstep = TRUE
+
+/mob/living/simple_animal/chick/Initialize()
+ . = ..()
+ pixel_x = rand(-6, 6)
+ pixel_y = rand(0, 10)
+
+/mob/living/simple_animal/chick/Life()
+ . =..()
+ if(!.)
+ return
+ if(!stat && !ckey)
+ amount_grown += rand(1,2)
+ if(amount_grown >= 100)
+ new /mob/living/simple_animal/chicken(src.loc)
+ qdel(src)
+
+/mob/living/simple_animal/chick/holo/Life()
+ ..()
+ amount_grown = 0
+
+/mob/living/simple_animal/chicken
+ name = "\improper chicken"
+ desc = "Hopefully the eggs are good this season."
+ gender = FEMALE
+ mob_biotypes = list(MOB_ORGANIC, MOB_BEAST)
+ icon_state = "chicken_brown"
+ icon_living = "chicken_brown"
+ icon_dead = "chicken_brown_dead"
+ speak = list("Cluck!","BWAAAAARK BWAK BWAK BWAK!","Bwaak bwak.")
+ speak_emote = list("clucks","croons")
+ emote_hear = list("clucks.")
+ emote_see = list("pecks at the ground.","flaps its wings viciously.")
+ density = FALSE
+ speak_chance = 2
+ turns_per_move = 3
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/chicken = 2)
+ var/egg_type = /obj/item/reagent_containers/food/snacks/egg
+ var/food_type = /obj/item/reagent_containers/food/snacks/grown/wheat
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "kicks"
+ attacktext = "kicks"
+ health = 15
+ maxHealth = 15
+ ventcrawler = VENTCRAWLER_ALWAYS
+ var/eggsleft = 0
+ var/eggsFertile = TRUE
+ var/body_color
+ var/icon_prefix = "chicken"
+ pass_flags = PASSTABLE | PASSMOB
+ mob_size = MOB_SIZE_SMALL
+ var/list/feedMessages = list("It clucks happily.","It clucks happily.")
+ var/list/layMessage = EGG_LAYING_MESSAGES
+ var/list/validColors = list("brown","black","white")
+ gold_core_spawnable = FRIENDLY_SPAWN
+ var/static/chicken_count = 0
+
+ do_footstep = TRUE
+
+/mob/living/simple_animal/chicken/Initialize()
+ . = ..()
+ if(!body_color)
+ body_color = pick(validColors)
+ icon_state = "[icon_prefix]_[body_color]"
+ icon_living = "[icon_prefix]_[body_color]"
+ icon_dead = "[icon_prefix]_[body_color]_dead"
+ pixel_x = rand(-6, 6)
+ pixel_y = rand(0, 10)
+ ++chicken_count
+
+/mob/living/simple_animal/chicken/Destroy()
+ --chicken_count
+ return ..()
+
+/mob/living/simple_animal/chicken/attackby(obj/item/O, mob/user, params)
+ if(istype(O, food_type)) //feedin' dem chickens
+ if(!stat && eggsleft < 8)
+ var/feedmsg = "[user] feeds [O] to [name]! [pick(feedMessages)]"
+ user.visible_message(feedmsg)
+ qdel(O)
+ eggsleft += rand(1, 4)
+ else
+ to_chat(user, "[name] doesn't seem hungry!")
+ else
+ ..()
+
+/mob/living/simple_animal/chicken/Life()
+ . =..()
+ if(!.)
+ return
+ if((!stat && prob(3) && eggsleft > 0) && egg_type)
+ visible_message("[src] [pick(layMessage)]")
+ eggsleft--
+ var/obj/item/E = new egg_type(get_turf(src))
+ E.pixel_x = rand(-6,6)
+ E.pixel_y = rand(-6,6)
+ if(eggsFertile)
+ if(chicken_count < MAX_CHICKENS && prob(25))
+ START_PROCESSING(SSobj, E)
+
+/obj/item/reagent_containers/food/snacks/egg/var/amount_grown = 0
+/obj/item/reagent_containers/food/snacks/egg/process()
+ if(isturf(loc))
+ amount_grown += rand(1,2)
+ if(amount_grown >= 100)
+ visible_message("[src] hatches with a quiet cracking sound.")
+ new /mob/living/simple_animal/chick(get_turf(src))
+ STOP_PROCESSING(SSobj, src)
+ qdel(src)
+ else
+ STOP_PROCESSING(SSobj, src)
+
+
+/obj/item/udder
+ name = "udder"
+
+/obj/item/udder/Initialize()
+ create_reagents(50)
+ reagents.add_reagent(/datum/reagent/consumable/milk, 20)
+ . = ..()
+
+/obj/item/udder/proc/generateMilk()
+ if(prob(5))
+ reagents.add_reagent(/datum/reagent/consumable/milk, rand(5, 10))
+
+/obj/item/udder/proc/milkAnimal(obj/O, mob/user)
+ var/obj/item/reagent_containers/glass/G = O
+ if(G.reagents.total_volume >= G.volume)
+ to_chat(user, "[O] is full.")
+ return
+ var/transfered = reagents.trans_to(O, rand(5,10))
+ if(transfered)
+ user.visible_message("[user] milks [src] using \the [O].", "You milk [src] using \the [O].")
+ else
+ to_chat(user, "The udder is dry. Wait a bit longer...")
diff --git a/code/modules/mob/living/simple_animal/friendly/mouse.dm b/code/modules/mob/living/simple_animal/friendly/mouse.dm
index e1c80050..b45ead9d 100644
--- a/code/modules/mob/living/simple_animal/friendly/mouse.dm
+++ b/code/modules/mob/living/simple_animal/friendly/mouse.dm
@@ -114,9 +114,9 @@
icon_state = "mouse_gray_dead"
bitesize = 3
eatverb = "devour"
- list_reagents = list("nutriment" = 3, "vitamin" = 2)
+ list_reagents = list(/datum/reagent/consumable/nutriment = 3, /datum/reagent/consumable/nutriment/vitamin = 2)
foodtype = GROSS | MEAT | RAW
- grind_results = list("blood" = 20, "liquidgibs" = 5)
+ grind_results = list(/datum/reagent/blood = 20, /datum/reagent/liquidgibs = 5)
/obj/item/reagent_containers/food/snacks/deadmouse/on_grind()
reagents.clear_reagents()
diff --git a/code/modules/mob/living/simple_animal/friendly/snake.dm b/code/modules/mob/living/simple_animal/friendly/snake.dm
index d8912ee2..05e38a9f 100644
--- a/code/modules/mob/living/simple_animal/friendly/snake.dm
+++ b/code/modules/mob/living/simple_animal/friendly/snake.dm
@@ -1,6 +1,6 @@
/mob/living/simple_animal/hostile/retaliate/poison
- var/poison_per_bite = 0
- var/poison_type = "toxin"
+ var/poison_per_bite = 0
+ var/poison_type = /datum/reagent/toxin
/mob/living/simple_animal/hostile/retaliate/poison/AttackingTarget()
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index 89c4f70f..bb1f1284 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -140,7 +140,7 @@
var/mob/living/L = target
if(L.reagents)
beegent.reaction_mob(L, INJECT)
- L.reagents.add_reagent(beegent.id, rand(1,5))
+ L.reagents.add_reagent(beegent.type, rand(1,5))
/mob/living/simple_animal/hostile/poison/bees/proc/assign_reagent(datum/reagent/R)
@@ -205,7 +205,7 @@
/mob/living/simple_animal/hostile/poison/bees/toxin/Initialize()
. = ..()
var/datum/reagent/R = pick(typesof(/datum/reagent/toxin))
- assign_reagent(GLOB.chemical_reagents_list[initial(R.id)])
+ assign_reagent(GLOB.chemical_reagents_list[R])
/mob/living/simple_animal/hostile/poison/bees/queen
name = "queen bee"
@@ -225,7 +225,7 @@
if(. && beegent && isliving(target))
var/mob/living/L = target
beegent.reaction_mob(L, TOUCH)
- L.reagents.add_reagent(beegent.id, rand(1,5))
+ L.reagents.add_reagent(beegent.type, rand(1,5))
//PEASENT BEES
@@ -236,7 +236,7 @@
/mob/living/simple_animal/hostile/poison/bees/proc/reagent_incompatible(mob/living/simple_animal/hostile/poison/bees/B)
if(!B)
return FALSE
- if(B.beegent && beegent && B.beegent.id != beegent.id || B.beegent && !beegent || !B.beegent && beegent)
+ if(B.beegent && beegent && B.beegent.type != beegent.type || B.beegent && !beegent || !B.beegent && beegent)
return TRUE
return FALSE
@@ -253,9 +253,10 @@
/obj/item/queen_bee/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers/syringe))
var/obj/item/reagent_containers/syringe/S = I
- if(S.reagents.has_reagent("royal_bee_jelly")) //checked twice, because I really don't want royal bee jelly to be duped
- if(S.reagents.has_reagent("royal_bee_jelly",5))
- S.reagents.remove_reagent("royal_bee_jelly", 5)
+ var/jelly_amount = S.reagents.get_reagent_amount(/datum/reagent/royal_bee_jelly)
+ if(jelly_amount)
+ if(jelly_amount >= 5)
+ S.reagents.remove_reagent(/datum/reagent/royal_bee_jelly, 5)
var/obj/item/queen_bee/qb = new(user.drop_location())
qb.queen = new(qb)
if(queen && queen.beegent)
@@ -266,8 +267,8 @@
to_chat(user, "You don't have enough royal bee jelly to split a bee in two!")
else
var/datum/reagent/R = GLOB.chemical_reagents_list[S.reagents.get_master_reagent_id()]
- if(R && S.reagents.has_reagent(R.id, 5))
- S.reagents.remove_reagent(R.id,5)
+ if(R && S.reagents.has_reagent(R.type, 5))
+ S.reagents.remove_reagent(R.type,5)
queen.assign_reagent(R)
user.visible_message("[user] injects [src]'s genome with [R.name], mutating it's DNA!","You inject [src]'s genome with [R.name], mutating it's DNA!")
name = queen.name
diff --git a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
index 3ff6ffe7..cbce16fa 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -1,537 +1,537 @@
-#define SPIDER_IDLE 0
-#define SPINNING_WEB 1
-#define LAYING_EGGS 2
-#define MOVING_TO_TARGET 3
-#define SPINNING_COCOON 4
-
-/mob/living/simple_animal/hostile/poison
- var/poison_per_bite = 5
- var/poison_type = "toxin"
-
-/mob/living/simple_animal/hostile/poison/AttackingTarget()
- . = ..()
- if(. && isliving(target))
- var/mob/living/L = target
- if(L.reagents)
- L.reagents.add_reagent(poison_type, poison_per_bite)
-
-//basic spider mob, these generally guard nests
-/mob/living/simple_animal/hostile/poison/giant_spider
- name = "giant spider"
- desc = "Furry and black, it makes you shudder to look at it. This one has deep red eyes."
- icon_state = "guard"
- icon_living = "guard"
- icon_dead = "guard_dead"
- mob_biotypes = list(MOB_ORGANIC, MOB_BUG)
- speak_emote = list("chitters")
- emote_hear = list("chitters")
- speak_chance = 5
- turns_per_move = 5
- see_in_dark = 10
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/spider = 2, /obj/item/reagent_containers/food/snacks/spiderleg = 8)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "hits"
- maxHealth = 200
- health = 200
- obj_damage = 60
- melee_damage_lower = 15
- melee_damage_upper = 20
- faction = list("spiders")
- var/busy = SPIDER_IDLE
- pass_flags = PASSTABLE
- move_to_delay = 6
- ventcrawler = VENTCRAWLER_ALWAYS
- attacktext = "bites"
- attack_sound = 'sound/weapons/bite.ogg'
- unique_name = 1
- gold_core_spawnable = HOSTILE_SPAWN
- see_in_dark = 4
- lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
- var/playable_spider = FALSE
- var/datum/action/innate/spider/lay_web/lay_web
- var/directive = "" //Message passed down to children, to relay the creator's orders
-
- do_footstep = TRUE
-
-/mob/living/simple_animal/hostile/poison/giant_spider/Initialize()
- . = ..()
- lay_web = new
- lay_web.Grant(src)
-
-/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
- QDEL_NULL(lay_web)
- return ..()
-
-/mob/living/simple_animal/hostile/poison/giant_spider/Topic(href, href_list)
- if(href_list["activate"])
- var/mob/dead/observer/ghost = usr
- if(istype(ghost) && playable_spider)
- humanize_spider(ghost)
-
-/mob/living/simple_animal/hostile/poison/giant_spider/Login()
- ..()
- if(directive)
- to_chat(src, "Your mother left you a directive! Follow it at all costs.")
- to_chat(src, "[directive]")
-
-/mob/living/simple_animal/hostile/poison/giant_spider/attack_ghost(mob/user)
- . = ..()
- if(.)
- return
- humanize_spider(user)
-
-/mob/living/simple_animal/hostile/poison/giant_spider/proc/humanize_spider(mob/user)
- if(key || !playable_spider || stat)//Someone is in it, it's dead, or the fun police are shutting it down
- return 0
- var/spider_ask = alert("Become a spider?", "Are you australian?", "Yes", "No")
- if(spider_ask == "No" || !src || QDELETED(src))
- return 1
- if(key)
- to_chat(user, "Someone else already took this spider.")
- return 1
- key = user.key
- return 1
-
-//nursemaids - these create webs and eggs
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse
- desc = "Furry and black, it makes you shudder to look at it. This one has brilliant green eyes."
- icon_state = "nurse"
- icon_living = "nurse"
- icon_dead = "nurse_dead"
- gender = FEMALE
- butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/spider = 2, /obj/item/reagent_containers/food/snacks/spiderleg = 8, /obj/item/reagent_containers/food/snacks/spidereggs = 4)
- maxHealth = 40
- health = 40
- melee_damage_lower = 5
- melee_damage_upper = 10
- poison_per_bite = 3
- var/atom/movable/cocoon_target
- var/fed = 0
- var/obj/effect/proc_holder/wrap/wrap
- var/datum/action/innate/spider/lay_eggs/lay_eggs
- var/datum/action/innate/spider/set_directive/set_directive
- var/static/list/consumed_mobs = list() //the tags of mobs that have been consumed by nurse spiders to lay eggs
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Initialize()
- . = ..()
- wrap = new
- AddAbility(wrap)
- lay_eggs = new
- lay_eggs.Grant(src)
- set_directive = new
- set_directive.Grant(src)
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Destroy()
- RemoveAbility(wrap)
- QDEL_NULL(lay_eggs)
- QDEL_NULL(set_directive)
- return ..()
-
-//hunters have the most poison and move the fastest, so they can find prey
-/mob/living/simple_animal/hostile/poison/giant_spider/hunter
- desc = "Furry and black, it makes you shudder to look at it. This one has sparkling purple eyes."
- icon_state = "hunter"
- icon_living = "hunter"
- icon_dead = "hunter_dead"
- maxHealth = 120
- health = 120
- melee_damage_lower = 10
- melee_damage_upper = 20
- poison_per_bite = 5
- move_to_delay = 5
-
-//vipers are the rare variant of the hunter, no IMMEDIATE damage but so much poison medical care will be needed fast.
-/mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper
- name = "viper"
- desc = "Furry and black, it makes you shudder to look at it. This one has effervescent purple eyes."
- icon_state = "viper"
- icon_living = "viper"
- icon_dead = "viper_dead"
- maxHealth = 40
- health = 40
- melee_damage_lower = 1
- melee_damage_upper = 1
- poison_per_bite = 12
- move_to_delay = 4
- poison_type = "venom" //all in venom, glass cannon. you bite 5 times and they are DEFINITELY dead, but 40 health and you are extremely obvious. Ambush, maybe?
- speed = 1
- gold_core_spawnable = NO_SPAWN
-
-//tarantulas are really tanky, regenerating (maybe), hulky monster but are also extremely slow, so.
-/mob/living/simple_animal/hostile/poison/giant_spider/tarantula
- name = "tarantula"
- desc = "Furry and black, it makes you shudder to look at it. This one has abyssal red eyes."
- icon_state = "tarantula"
- icon_living = "tarantula"
- icon_dead = "tarantula_dead"
- maxHealth = 300 // woah nelly
- health = 300
- melee_damage_lower = 35
- melee_damage_upper = 40
- poison_per_bite = 0
- move_to_delay = 8
- speed = 7
- status_flags = NONE
- mob_size = MOB_SIZE_LARGE
- gold_core_spawnable = NO_SPAWN
-
-/mob/living/simple_animal/hostile/poison/giant_spider/tarantula/movement_delay()
- var/turf/T = get_turf(src)
- if(locate(/obj/structure/spider/stickyweb) in T)
- speed = 2
- else
- speed = 7
- . = ..()
-
-//midwives are the queen of the spiders, can send messages to all them and web faster. That rare round where you get a queen spider and turn your 'for honor' players into 'r6siege' players will be a fun one.
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife
- name = "midwife"
- desc = "Furry and black, it makes you shudder to look at it. This one has scintillating green eyes."
- icon_state = "midwife"
- icon_living = "midwife"
- icon_dead = "midwife_dead"
- maxHealth = 40
- health = 40
- var/datum/action/innate/spider/comm/letmetalkpls
- gold_core_spawnable = NO_SPAWN
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Initialize()
- . = ..()
- letmetalkpls = new
- letmetalkpls.Grant(src)
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Destroy()
- QDEL_NULL(letmetalkpls)
- return ..()
-
-/mob/living/simple_animal/hostile/poison/giant_spider/ice //spiders dont usually like tempatures of 140 kelvin who knew
- name = "giant ice spider"
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
- maxbodytemp = 1500
- poison_type = "frostoil"
- color = rgb(114,228,250)
- gold_core_spawnable = NO_SPAWN
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/ice
- name = "giant ice spider"
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
- maxbodytemp = 1500
- poison_type = "frostoil"
- color = rgb(114,228,250)
- gold_core_spawnable = NO_SPAWN
-
-/mob/living/simple_animal/hostile/poison/giant_spider/hunter/ice
- name = "giant ice spider"
- atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
- minbodytemp = 0
- maxbodytemp = 1500
- poison_type = "frostoil"
- color = rgb(114,228,250)
- gold_core_spawnable = NO_SPAWN
-
-/mob/living/simple_animal/hostile/poison/giant_spider/handle_automated_action()
- if(!..()) //AIStatus is off
- return 0
- if(AIStatus == AI_IDLE)
- //1% chance to skitter madly away
- if(!busy && prob(1))
- stop_automated_movement = 1
- Goto(pick(urange(20, src, 1)), move_to_delay)
- spawn(50)
- stop_automated_movement = 0
- walk(src,0)
- return 1
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/GiveUp(C)
- spawn(100)
- if(busy == MOVING_TO_TARGET)
- if(cocoon_target == C && get_dist(src,cocoon_target) > 1)
- cocoon_target = null
- busy = FALSE
- stop_automated_movement = 0
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/handle_automated_action()
- if(..())
- var/list/can_see = view(src, 10)
- if(!busy && prob(30)) //30% chance to stop wandering and do something
- //first, check for potential food nearby to cocoon
- for(var/mob/living/C in can_see)
- if(C.stat && !istype(C, /mob/living/simple_animal/hostile/poison/giant_spider) && !C.anchored)
- cocoon_target = C
- busy = MOVING_TO_TARGET
- Goto(C, move_to_delay)
- //give up if we can't reach them after 10 seconds
- GiveUp(C)
- return
-
- //second, spin a sticky spiderweb on this tile
- var/obj/structure/spider/stickyweb/W = locate() in get_turf(src)
- if(!W)
- lay_web.Activate()
- else
- //third, lay an egg cluster there
- if(fed)
- lay_eggs.Activate()
- else
- //fourthly, cocoon any nearby items so those pesky pinkskins can't use them
- for(var/obj/O in can_see)
-
- if(O.anchored)
- continue
-
- if(isitem(O) || isstructure(O) || ismachinery(O))
- cocoon_target = O
- busy = MOVING_TO_TARGET
- stop_automated_movement = 1
- Goto(O, move_to_delay)
- //give up if we can't reach them after 10 seconds
- GiveUp(O)
-
- else if(busy == MOVING_TO_TARGET && cocoon_target)
- if(get_dist(src, cocoon_target) <= 1)
- cocoon()
-
- else
- busy = SPIDER_IDLE
- stop_automated_movement = FALSE
-
-/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/cocoon()
- if(stat != DEAD && cocoon_target && !cocoon_target.anchored)
- if(cocoon_target == src)
- to_chat(src, "You can't wrap yourself!")
- return
- if(istype(cocoon_target, /mob/living/simple_animal/hostile/poison/giant_spider))
- to_chat(src, "You can't wrap other spiders!")
- return
- if(!Adjacent(cocoon_target))
- to_chat(src, "You can't reach [cocoon_target]!")
- return
- if(busy == SPINNING_COCOON)
- to_chat(src, "You're already spinning a cocoon!")
- return //we're already doing this, don't cancel out or anything
- busy = SPINNING_COCOON
- visible_message("[src] begins to secrete a sticky substance around [cocoon_target].","You begin wrapping [cocoon_target] into a cocoon.")
- stop_automated_movement = TRUE
- walk(src,0)
- if(do_after(src, 50, target = cocoon_target))
- if(busy == SPINNING_COCOON)
- var/obj/structure/spider/cocoon/C = new(cocoon_target.loc)
- if(isliving(cocoon_target))
- var/mob/living/L = cocoon_target
- if(L.blood_volume && (L.stat != DEAD || !consumed_mobs[L.tag])) //if they're not dead, you can consume them anyway
- consumed_mobs[L.tag] = TRUE
- fed++
- lay_eggs.UpdateButtonIcon(TRUE)
- visible_message("[src] sticks a proboscis into [L] and sucks a viscous substance out.","You suck the nutriment out of [L], feeding you enough to lay a cluster of eggs.")
- L.death() //you just ate them, they're dead.
- else
- to_chat(src, "[L] cannot sate your hunger!")
- cocoon_target.forceMove(C)
-
- if(cocoon_target.density || ismob(cocoon_target))
- C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
- cocoon_target = null
- busy = SPIDER_IDLE
- stop_automated_movement = FALSE
-
-/datum/action/innate/spider
- icon_icon = 'icons/mob/actions/actions_animal.dmi'
- background_icon_state = "bg_alien"
-
-/datum/action/innate/spider/lay_web
- name = "Spin Web"
- desc = "Spin a web to slow down potential prey."
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "lay_web"
-
-/datum/action/innate/spider/lay_web/Activate()
- if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider))
- return
- var/mob/living/simple_animal/hostile/poison/giant_spider/S = owner
-
- if(!isturf(S.loc))
- return
- var/turf/T = get_turf(S)
-
- var/obj/structure/spider/stickyweb/W = locate() in T
- if(W)
- to_chat(S, "There's already a web here!")
- return
-
- if(S.busy != SPINNING_WEB)
- S.busy = SPINNING_WEB
- S.visible_message("[S] begins to secrete a sticky substance.","You begin to lay a web.")
- S.stop_automated_movement = TRUE
- if(do_after(S, 40, target = T))
- if(S.busy == SPINNING_WEB && S.loc == T)
- new /obj/structure/spider/stickyweb(T)
- S.busy = SPIDER_IDLE
- S.stop_automated_movement = FALSE
- else
- to_chat(S, "You're already spinning a web!")
-
-/obj/effect/proc_holder/wrap
- name = "Wrap"
- panel = "Spider"
- active = FALSE
- datum/action/spell_action/action = null
- desc = "Wrap something or someone in a cocoon. If it's a living being, you'll also consume them, allowing you to lay eggs."
- ranged_mousepointer = 'icons/effects/wrap_target.dmi'
- action_icon = 'icons/mob/actions/actions_animal.dmi'
- action_icon_state = "wrap_0"
- action_background_icon_state = "bg_alien"
-
-/obj/effect/proc_holder/wrap/Initialize()
- . = ..()
- action = new(src)
-
-/obj/effect/proc_holder/wrap/update_icon()
- action.button_icon_state = "wrap_[active]"
- action.UpdateButtonIcon()
-
-/obj/effect/proc_holder/wrap/Click()
- if(!istype(usr, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
- return TRUE
- var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = usr
- activate(user)
- return TRUE
-
-/obj/effect/proc_holder/wrap/proc/activate(mob/living/user)
- var/message
- if(active)
- message = "You no longer prepare to wrap something in a cocoon."
- remove_ranged_ability(message)
- else
- message = "You prepare to wrap something in a cocoon. Left-click your target to start wrapping!"
- add_ranged_ability(user, message, TRUE)
- return 1
-
-/obj/effect/proc_holder/wrap/InterceptClickOn(mob/living/caller, params, atom/target)
- if(..())
- return
- if(ranged_ability_user.incapacitated() || !istype(ranged_ability_user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
- remove_ranged_ability()
- return
-
- var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = ranged_ability_user
-
- if(user.Adjacent(target) && (ismob(target) || isobj(target)))
- var/atom/movable/target_atom = target
- if(target_atom.anchored)
- return
- user.cocoon_target = target_atom
- INVOKE_ASYNC(user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/.proc/cocoon)
- remove_ranged_ability()
- return TRUE
-
-/obj/effect/proc_holder/wrap/on_lose(mob/living/carbon/user)
- remove_ranged_ability()
-
-/datum/action/innate/spider/lay_eggs
- name = "Lay Eggs"
- desc = "Lay a cluster of eggs, which will soon grow into more spiders. You must wrap a living being to do this."
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "lay_eggs"
-
-/datum/action/innate/spider/lay_eggs/IsAvailable()
- if(..())
- if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
- return 0
- var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
- if(S.fed)
- return 1
- return 0
-
-/datum/action/innate/spider/lay_eggs/Activate()
- if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
- return
- var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
-
- var/obj/structure/spider/eggcluster/E = locate() in get_turf(S)
- if(E)
- to_chat(S, "There is already a cluster of eggs here!")
- else if(!S.fed)
- to_chat(S, "You are too hungry to do this!")
- else if(S.busy != LAYING_EGGS)
- S.busy = LAYING_EGGS
- S.visible_message("[S] begins to lay a cluster of eggs.","You begin to lay a cluster of eggs.")
- S.stop_automated_movement = TRUE
- if(do_after(S, 50, target = get_turf(S)))
- if(S.busy == LAYING_EGGS)
- E = locate() in get_turf(S)
- if(!E || !isturf(S.loc))
- var/obj/structure/spider/eggcluster/C = new /obj/structure/spider/eggcluster(get_turf(S))
- if(S.ckey)
- C.player_spiders = TRUE
- C.directive = S.directive
- C.poison_type = S.poison_type
- C.poison_per_bite = S.poison_per_bite
- C.faction = S.faction.Copy()
- S.fed--
- UpdateButtonIcon(TRUE)
- S.busy = SPIDER_IDLE
- S.stop_automated_movement = FALSE
-
-/datum/action/innate/spider/set_directive
- name = "Set Directive"
- desc = "Set a directive for your children to follow."
- check_flags = AB_CHECK_CONSCIOUS
- button_icon_state = "directive"
-
-/datum/action/innate/spider/set_directive/Activate()
- if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
- return
- var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
- S.directive = stripped_input(S, "Enter the new directive", "Create directive", "[S.directive]")
-
-/mob/living/simple_animal/hostile/poison/giant_spider/Login()
- . = ..()
- GLOB.spidermobs[src] = TRUE
-
-/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
- GLOB.spidermobs -= src
- return ..()
-
-/datum/action/innate/spider/comm
- name = "Command"
- desc = "Send a command to all living spiders."
- button_icon_state = "command"
-
-/datum/action/innate/spider/comm/IsAvailable()
- if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife))
- return FALSE
- return TRUE
-
-/datum/action/innate/spider/comm/Trigger()
- var/input = stripped_input(owner, "Input a command for your legions to follow.", "Command", "")
- if(QDELETED(src) || !input || !IsAvailable())
- return FALSE
- spider_command(owner, input)
- return TRUE
-
-/datum/action/innate/spider/comm/proc/spider_command(mob/living/user, message)
- if(!message)
- return
- var/my_message
- my_message = "Command from [user]: [message]"
- for(var/mob/living/simple_animal/hostile/poison/giant_spider/M in GLOB.spidermobs)
- to_chat(M, my_message)
- for(var/M in GLOB.dead_mob_list)
- var/link = FOLLOW_LINK(M, user)
- to_chat(M, "[link] [my_message]")
- usr.log_talk(message, LOG_SAY, tag="spider command")
-
-/mob/living/simple_animal/hostile/poison/giant_spider/handle_temperature_damage()
- if(bodytemperature < minbodytemp)
- adjustBruteLoss(20)
- else if(bodytemperature > maxbodytemp)
- adjustBruteLoss(20)
-
-#undef SPIDER_IDLE
-#undef SPINNING_WEB
-#undef LAYING_EGGS
-#undef MOVING_TO_TARGET
-#undef SPINNING_COCOON
+#define SPIDER_IDLE 0
+#define SPINNING_WEB 1
+#define LAYING_EGGS 2
+#define MOVING_TO_TARGET 3
+#define SPINNING_COCOON 4
+
+/mob/living/simple_animal/hostile/poison
+ var/poison_per_bite = 5
+ var/poison_type = /datum/reagent/toxin
+
+/mob/living/simple_animal/hostile/poison/AttackingTarget()
+ . = ..()
+ if(. && isliving(target))
+ var/mob/living/L = target
+ if(L.reagents)
+ L.reagents.add_reagent(poison_type, poison_per_bite)
+
+//basic spider mob, these generally guard nests
+/mob/living/simple_animal/hostile/poison/giant_spider
+ name = "giant spider"
+ desc = "Furry and black, it makes you shudder to look at it. This one has deep red eyes."
+ icon_state = "guard"
+ icon_living = "guard"
+ icon_dead = "guard_dead"
+ mob_biotypes = list(MOB_ORGANIC, MOB_BUG)
+ speak_emote = list("chitters")
+ emote_hear = list("chitters")
+ speak_chance = 5
+ turns_per_move = 5
+ see_in_dark = 10
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/spider = 2, /obj/item/reagent_containers/food/snacks/spiderleg = 8)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "hits"
+ maxHealth = 200
+ health = 200
+ obj_damage = 60
+ melee_damage_lower = 15
+ melee_damage_upper = 20
+ faction = list("spiders")
+ var/busy = SPIDER_IDLE
+ pass_flags = PASSTABLE
+ move_to_delay = 6
+ ventcrawler = VENTCRAWLER_ALWAYS
+ attacktext = "bites"
+ attack_sound = 'sound/weapons/bite.ogg'
+ unique_name = 1
+ gold_core_spawnable = HOSTILE_SPAWN
+ see_in_dark = 4
+ lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
+ var/playable_spider = FALSE
+ var/datum/action/innate/spider/lay_web/lay_web
+ var/directive = "" //Message passed down to children, to relay the creator's orders
+
+ do_footstep = TRUE
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Initialize()
+ . = ..()
+ lay_web = new
+ lay_web.Grant(src)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
+ QDEL_NULL(lay_web)
+ return ..()
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Topic(href, href_list)
+ if(href_list["activate"])
+ var/mob/dead/observer/ghost = usr
+ if(istype(ghost) && playable_spider)
+ humanize_spider(ghost)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Login()
+ ..()
+ if(directive)
+ to_chat(src, "Your mother left you a directive! Follow it at all costs.")
+ to_chat(src, "[directive]")
+
+/mob/living/simple_animal/hostile/poison/giant_spider/attack_ghost(mob/user)
+ . = ..()
+ if(.)
+ return
+ humanize_spider(user)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/proc/humanize_spider(mob/user)
+ if(key || !playable_spider || stat)//Someone is in it, it's dead, or the fun police are shutting it down
+ return 0
+ var/spider_ask = alert("Become a spider?", "Are you australian?", "Yes", "No")
+ if(spider_ask == "No" || !src || QDELETED(src))
+ return 1
+ if(key)
+ to_chat(user, "Someone else already took this spider.")
+ return 1
+ key = user.key
+ return 1
+
+//nursemaids - these create webs and eggs
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse
+ desc = "Furry and black, it makes you shudder to look at it. This one has brilliant green eyes."
+ icon_state = "nurse"
+ icon_living = "nurse"
+ icon_dead = "nurse_dead"
+ gender = FEMALE
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/meat/slab/spider = 2, /obj/item/reagent_containers/food/snacks/spiderleg = 8, /obj/item/reagent_containers/food/snacks/spidereggs = 4)
+ maxHealth = 40
+ health = 40
+ melee_damage_lower = 5
+ melee_damage_upper = 10
+ poison_per_bite = 3
+ var/atom/movable/cocoon_target
+ var/fed = 0
+ var/obj/effect/proc_holder/wrap/wrap
+ var/datum/action/innate/spider/lay_eggs/lay_eggs
+ var/datum/action/innate/spider/set_directive/set_directive
+ var/static/list/consumed_mobs = list() //the tags of mobs that have been consumed by nurse spiders to lay eggs
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Initialize()
+ . = ..()
+ wrap = new
+ AddAbility(wrap)
+ lay_eggs = new
+ lay_eggs.Grant(src)
+ set_directive = new
+ set_directive.Grant(src)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/Destroy()
+ RemoveAbility(wrap)
+ QDEL_NULL(lay_eggs)
+ QDEL_NULL(set_directive)
+ return ..()
+
+//hunters have the most poison and move the fastest, so they can find prey
+/mob/living/simple_animal/hostile/poison/giant_spider/hunter
+ desc = "Furry and black, it makes you shudder to look at it. This one has sparkling purple eyes."
+ icon_state = "hunter"
+ icon_living = "hunter"
+ icon_dead = "hunter_dead"
+ maxHealth = 120
+ health = 120
+ melee_damage_lower = 10
+ melee_damage_upper = 20
+ poison_per_bite = 5
+ move_to_delay = 5
+
+//vipers are the rare variant of the hunter, no IMMEDIATE damage but so much poison medical care will be needed fast.
+/mob/living/simple_animal/hostile/poison/giant_spider/hunter/viper
+ name = "viper"
+ desc = "Furry and black, it makes you shudder to look at it. This one has effervescent purple eyes."
+ icon_state = "viper"
+ icon_living = "viper"
+ icon_dead = "viper_dead"
+ maxHealth = 40
+ health = 40
+ melee_damage_lower = 1
+ melee_damage_upper = 1
+ poison_per_bite = 12
+ move_to_delay = 4
+ poison_type = /datum/reagent/toxin/venom //all in venom, glass cannon. you bite 5 times and they are DEFINITELY dead, but 40 health and you are extremely obvious. Ambush, maybe?
+ speed = 1
+ gold_core_spawnable = NO_SPAWN
+
+//tarantulas are really tanky, regenerating (maybe), hulky monster but are also extremely slow, so.
+/mob/living/simple_animal/hostile/poison/giant_spider/tarantula
+ name = "tarantula"
+ desc = "Furry and black, it makes you shudder to look at it. This one has abyssal red eyes."
+ icon_state = "tarantula"
+ icon_living = "tarantula"
+ icon_dead = "tarantula_dead"
+ maxHealth = 300 // woah nelly
+ health = 300
+ melee_damage_lower = 35
+ melee_damage_upper = 40
+ poison_per_bite = 0
+ move_to_delay = 8
+ speed = 7
+ status_flags = NONE
+ mob_size = MOB_SIZE_LARGE
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/hostile/poison/giant_spider/tarantula/movement_delay()
+ var/turf/T = get_turf(src)
+ if(locate(/obj/structure/spider/stickyweb) in T)
+ speed = 2
+ else
+ speed = 7
+ . = ..()
+
+//midwives are the queen of the spiders, can send messages to all them and web faster. That rare round where you get a queen spider and turn your 'for honor' players into 'r6siege' players will be a fun one.
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife
+ name = "midwife"
+ desc = "Furry and black, it makes you shudder to look at it. This one has scintillating green eyes."
+ icon_state = "midwife"
+ icon_living = "midwife"
+ icon_dead = "midwife_dead"
+ maxHealth = 40
+ health = 40
+ var/datum/action/innate/spider/comm/letmetalkpls
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Initialize()
+ . = ..()
+ letmetalkpls = new
+ letmetalkpls.Grant(src)
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife/Destroy()
+ QDEL_NULL(letmetalkpls)
+ return ..()
+
+/mob/living/simple_animal/hostile/poison/giant_spider/ice //spiders dont usually like tempatures of 140 kelvin who knew
+ name = "giant ice spider"
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ maxbodytemp = 1500
+ poison_type = /datum/reagent/consumable/frostoil
+ color = rgb(114,228,250)
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/ice
+ name = "giant ice spider"
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ maxbodytemp = 1500
+ poison_type = /datum/reagent/consumable/frostoil
+ color = rgb(114,228,250)
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/hostile/poison/giant_spider/hunter/ice
+ name = "giant ice spider"
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ maxbodytemp = 1500
+ poison_type = /datum/reagent/consumable/frostoil
+ color = rgb(114,228,250)
+ gold_core_spawnable = NO_SPAWN
+
+/mob/living/simple_animal/hostile/poison/giant_spider/handle_automated_action()
+ if(!..()) //AIStatus is off
+ return 0
+ if(AIStatus == AI_IDLE)
+ //1% chance to skitter madly away
+ if(!busy && prob(1))
+ stop_automated_movement = 1
+ Goto(pick(urange(20, src, 1)), move_to_delay)
+ spawn(50)
+ stop_automated_movement = 0
+ walk(src,0)
+ return 1
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/GiveUp(C)
+ spawn(100)
+ if(busy == MOVING_TO_TARGET)
+ if(cocoon_target == C && get_dist(src,cocoon_target) > 1)
+ cocoon_target = null
+ busy = FALSE
+ stop_automated_movement = 0
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/handle_automated_action()
+ if(..())
+ var/list/can_see = view(src, 10)
+ if(!busy && prob(30)) //30% chance to stop wandering and do something
+ //first, check for potential food nearby to cocoon
+ for(var/mob/living/C in can_see)
+ if(C.stat && !istype(C, /mob/living/simple_animal/hostile/poison/giant_spider) && !C.anchored)
+ cocoon_target = C
+ busy = MOVING_TO_TARGET
+ Goto(C, move_to_delay)
+ //give up if we can't reach them after 10 seconds
+ GiveUp(C)
+ return
+
+ //second, spin a sticky spiderweb on this tile
+ var/obj/structure/spider/stickyweb/W = locate() in get_turf(src)
+ if(!W)
+ lay_web.Activate()
+ else
+ //third, lay an egg cluster there
+ if(fed)
+ lay_eggs.Activate()
+ else
+ //fourthly, cocoon any nearby items so those pesky pinkskins can't use them
+ for(var/obj/O in can_see)
+
+ if(O.anchored)
+ continue
+
+ if(isitem(O) || isstructure(O) || ismachinery(O))
+ cocoon_target = O
+ busy = MOVING_TO_TARGET
+ stop_automated_movement = 1
+ Goto(O, move_to_delay)
+ //give up if we can't reach them after 10 seconds
+ GiveUp(O)
+
+ else if(busy == MOVING_TO_TARGET && cocoon_target)
+ if(get_dist(src, cocoon_target) <= 1)
+ cocoon()
+
+ else
+ busy = SPIDER_IDLE
+ stop_automated_movement = FALSE
+
+/mob/living/simple_animal/hostile/poison/giant_spider/nurse/proc/cocoon()
+ if(stat != DEAD && cocoon_target && !cocoon_target.anchored)
+ if(cocoon_target == src)
+ to_chat(src, "You can't wrap yourself!")
+ return
+ if(istype(cocoon_target, /mob/living/simple_animal/hostile/poison/giant_spider))
+ to_chat(src, "You can't wrap other spiders!")
+ return
+ if(!Adjacent(cocoon_target))
+ to_chat(src, "You can't reach [cocoon_target]!")
+ return
+ if(busy == SPINNING_COCOON)
+ to_chat(src, "You're already spinning a cocoon!")
+ return //we're already doing this, don't cancel out or anything
+ busy = SPINNING_COCOON
+ visible_message("[src] begins to secrete a sticky substance around [cocoon_target].","You begin wrapping [cocoon_target] into a cocoon.")
+ stop_automated_movement = TRUE
+ walk(src,0)
+ if(do_after(src, 50, target = cocoon_target))
+ if(busy == SPINNING_COCOON)
+ var/obj/structure/spider/cocoon/C = new(cocoon_target.loc)
+ if(isliving(cocoon_target))
+ var/mob/living/L = cocoon_target
+ if(L.blood_volume && (L.stat != DEAD || !consumed_mobs[L.tag])) //if they're not dead, you can consume them anyway
+ consumed_mobs[L.tag] = TRUE
+ fed++
+ lay_eggs.UpdateButtonIcon(TRUE)
+ visible_message("[src] sticks a proboscis into [L] and sucks a viscous substance out.","You suck the nutriment out of [L], feeding you enough to lay a cluster of eggs.")
+ L.death() //you just ate them, they're dead.
+ else
+ to_chat(src, "[L] cannot sate your hunger!")
+ cocoon_target.forceMove(C)
+
+ if(cocoon_target.density || ismob(cocoon_target))
+ C.icon_state = pick("cocoon_large1","cocoon_large2","cocoon_large3")
+ cocoon_target = null
+ busy = SPIDER_IDLE
+ stop_automated_movement = FALSE
+
+/datum/action/innate/spider
+ icon_icon = 'icons/mob/actions/actions_animal.dmi'
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/spider/lay_web
+ name = "Spin Web"
+ desc = "Spin a web to slow down potential prey."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "lay_web"
+
+/datum/action/innate/spider/lay_web/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider))
+ return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/S = owner
+
+ if(!isturf(S.loc))
+ return
+ var/turf/T = get_turf(S)
+
+ var/obj/structure/spider/stickyweb/W = locate() in T
+ if(W)
+ to_chat(S, "There's already a web here!")
+ return
+
+ if(S.busy != SPINNING_WEB)
+ S.busy = SPINNING_WEB
+ S.visible_message("[S] begins to secrete a sticky substance.","You begin to lay a web.")
+ S.stop_automated_movement = TRUE
+ if(do_after(S, 40, target = T))
+ if(S.busy == SPINNING_WEB && S.loc == T)
+ new /obj/structure/spider/stickyweb(T)
+ S.busy = SPIDER_IDLE
+ S.stop_automated_movement = FALSE
+ else
+ to_chat(S, "You're already spinning a web!")
+
+/obj/effect/proc_holder/wrap
+ name = "Wrap"
+ panel = "Spider"
+ active = FALSE
+ datum/action/spell_action/action = null
+ desc = "Wrap something or someone in a cocoon. If it's a living being, you'll also consume them, allowing you to lay eggs."
+ ranged_mousepointer = 'icons/effects/wrap_target.dmi'
+ action_icon = 'icons/mob/actions/actions_animal.dmi'
+ action_icon_state = "wrap_0"
+ action_background_icon_state = "bg_alien"
+
+/obj/effect/proc_holder/wrap/Initialize()
+ . = ..()
+ action = new(src)
+
+/obj/effect/proc_holder/wrap/update_icon()
+ action.button_icon_state = "wrap_[active]"
+ action.UpdateButtonIcon()
+
+/obj/effect/proc_holder/wrap/Click()
+ if(!istype(usr, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return TRUE
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = usr
+ activate(user)
+ return TRUE
+
+/obj/effect/proc_holder/wrap/proc/activate(mob/living/user)
+ var/message
+ if(active)
+ message = "You no longer prepare to wrap something in a cocoon."
+ remove_ranged_ability(message)
+ else
+ message = "You prepare to wrap something in a cocoon. Left-click your target to start wrapping!"
+ add_ranged_ability(user, message, TRUE)
+ return 1
+
+/obj/effect/proc_holder/wrap/InterceptClickOn(mob/living/caller, params, atom/target)
+ if(..())
+ return
+ if(ranged_ability_user.incapacitated() || !istype(ranged_ability_user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ remove_ranged_ability()
+ return
+
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/user = ranged_ability_user
+
+ if(user.Adjacent(target) && (ismob(target) || isobj(target)))
+ var/atom/movable/target_atom = target
+ if(target_atom.anchored)
+ return
+ user.cocoon_target = target_atom
+ INVOKE_ASYNC(user, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/.proc/cocoon)
+ remove_ranged_ability()
+ return TRUE
+
+/obj/effect/proc_holder/wrap/on_lose(mob/living/carbon/user)
+ remove_ranged_ability()
+
+/datum/action/innate/spider/lay_eggs
+ name = "Lay Eggs"
+ desc = "Lay a cluster of eggs, which will soon grow into more spiders. You must wrap a living being to do this."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "lay_eggs"
+
+/datum/action/innate/spider/lay_eggs/IsAvailable()
+ if(..())
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return 0
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+ if(S.fed)
+ return 1
+ return 0
+
+/datum/action/innate/spider/lay_eggs/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+
+ var/obj/structure/spider/eggcluster/E = locate() in get_turf(S)
+ if(E)
+ to_chat(S, "There is already a cluster of eggs here!")
+ else if(!S.fed)
+ to_chat(S, "You are too hungry to do this!")
+ else if(S.busy != LAYING_EGGS)
+ S.busy = LAYING_EGGS
+ S.visible_message("[S] begins to lay a cluster of eggs.","You begin to lay a cluster of eggs.")
+ S.stop_automated_movement = TRUE
+ if(do_after(S, 50, target = get_turf(S)))
+ if(S.busy == LAYING_EGGS)
+ E = locate() in get_turf(S)
+ if(!E || !isturf(S.loc))
+ var/obj/structure/spider/eggcluster/C = new /obj/structure/spider/eggcluster(get_turf(S))
+ if(S.ckey)
+ C.player_spiders = TRUE
+ C.directive = S.directive
+ C.poison_type = S.poison_type
+ C.poison_per_bite = S.poison_per_bite
+ C.faction = S.faction.Copy()
+ S.fed--
+ UpdateButtonIcon(TRUE)
+ S.busy = SPIDER_IDLE
+ S.stop_automated_movement = FALSE
+
+/datum/action/innate/spider/set_directive
+ name = "Set Directive"
+ desc = "Set a directive for your children to follow."
+ check_flags = AB_CHECK_CONSCIOUS
+ button_icon_state = "directive"
+
+/datum/action/innate/spider/set_directive/Activate()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse))
+ return
+ var/mob/living/simple_animal/hostile/poison/giant_spider/nurse/S = owner
+ S.directive = stripped_input(S, "Enter the new directive", "Create directive", "[S.directive]")
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Login()
+ . = ..()
+ GLOB.spidermobs[src] = TRUE
+
+/mob/living/simple_animal/hostile/poison/giant_spider/Destroy()
+ GLOB.spidermobs -= src
+ return ..()
+
+/datum/action/innate/spider/comm
+ name = "Command"
+ desc = "Send a command to all living spiders."
+ button_icon_state = "command"
+
+/datum/action/innate/spider/comm/IsAvailable()
+ if(!istype(owner, /mob/living/simple_animal/hostile/poison/giant_spider/nurse/midwife))
+ return FALSE
+ return TRUE
+
+/datum/action/innate/spider/comm/Trigger()
+ var/input = stripped_input(owner, "Input a command for your legions to follow.", "Command", "")
+ if(QDELETED(src) || !input || !IsAvailable())
+ return FALSE
+ spider_command(owner, input)
+ return TRUE
+
+/datum/action/innate/spider/comm/proc/spider_command(mob/living/user, message)
+ if(!message)
+ return
+ var/my_message
+ my_message = "Command from [user]: [message]"
+ for(var/mob/living/simple_animal/hostile/poison/giant_spider/M in GLOB.spidermobs)
+ to_chat(M, my_message)
+ for(var/M in GLOB.dead_mob_list)
+ var/link = FOLLOW_LINK(M, user)
+ to_chat(M, "[link] [my_message]")
+ usr.log_talk(message, LOG_SAY, tag="spider command")
+
+/mob/living/simple_animal/hostile/poison/giant_spider/handle_temperature_damage()
+ if(bodytemperature < minbodytemp)
+ adjustBruteLoss(20)
+ else if(bodytemperature > maxbodytemp)
+ adjustBruteLoss(20)
+
+#undef SPIDER_IDLE
+#undef SPINNING_WEB
+#undef LAYING_EGGS
+#undef MOVING_TO_TARGET
+#undef SPINNING_COCOON
diff --git a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
index 72ae49eb..deb88d67 100644
--- a/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
+++ b/code/modules/mob/living/simple_animal/hostile/jungle/leaper.dm
@@ -42,7 +42,7 @@
..()
if(iscarbon(target))
var/mob/living/carbon/C = target
- C.reagents.add_reagent("leaper_venom", 5)
+ C.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5)
return
if(isanimal(target))
var/mob/living/simple_animal/L = target
@@ -96,7 +96,7 @@
L.Knockdown(50)
if(iscarbon(L))
var/mob/living/carbon/C = L
- C.reagents.add_reagent("leaper_venom", 5)
+ C.reagents.add_reagent(/datum/reagent/toxin/leaper_venom, 5)
if(isanimal(L))
var/mob/living/simple_animal/A = L
A.adjustHealth(25)
@@ -105,7 +105,6 @@
/datum/reagent/toxin/leaper_venom
name = "Leaper venom"
- id = "leaper_venom"
description = "A toxin spat out by leapers that, while harmless in small doses, quickly creates a toxic reaction if too much is in the body."
color = "#801E28" // rgb: 128, 30, 40
toxpwr = 0
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
index 910e9c3c..9e9fbaea 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/gutlunch.dm
@@ -131,7 +131,7 @@
/obj/item/udder/gutlunch/generateMilk()
if(prob(60))
- reagents.add_reagent("cream", rand(2, 5))
+ reagents.add_reagent(/datum/reagent/consumable/cream, rand(2, 5))
if(prob(45))
- reagents.add_reagent("salglu_solution", rand(2,5))
+ reagents.add_reagent(/datum/reagent/medicine/salglu_solution, rand(2,5))
diff --git a/code/modules/mob/living/simple_animal/hostile/mushroom.dm b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
index 151e28d9..75cd2479 100644
--- a/code/modules/mob/living/simple_animal/hostile/mushroom.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mushroom.dm
@@ -1,192 +1,192 @@
-/mob/living/simple_animal/hostile/mushroom
- name = "walking mushroom"
- desc = "It's a massive mushroom... with legs?"
- icon_state = "mushroom_color"
- icon_living = "mushroom_color"
- icon_dead = "mushroom_dead"
- speak_chance = 0
- turns_per_move = 1
- maxHealth = 10
- health = 10
- butcher_results = list(/obj/item/reagent_containers/food/snacks/hugemushroomslice = 1)
- response_help = "pets"
- response_disarm = "gently pushes aside"
- response_harm = "whacks"
- harm_intent_damage = 5
- obj_damage = 0
- melee_damage_lower = 1
- melee_damage_upper = 1
- attack_same = 2
- attacktext = "chomps"
- attack_sound = 'sound/weapons/bite.ogg'
- faction = list("mushroom")
- environment_smash = ENVIRONMENT_SMASH_NONE
- stat_attack = DEAD
- mouse_opacity = MOUSE_OPACITY_ICON
- speed = 1
- ventcrawler = VENTCRAWLER_ALWAYS
- robust_searching = 1
- unique_name = 1
- speak_emote = list("squeaks")
- deathmessage = "fainted."
- var/cap_color = "#ffffff"
- var/powerlevel = 0 //Tracks our general strength level gained from eating other shrooms
- var/bruised = 0 //If someone tries to cheat the system by attacking a shroom to lower its health, punish them so that it wont award levels to shrooms that eat it
- var/recovery_cooldown = 0 //So you can't repeatedly revive it during a fight
- var/faint_ticker = 0 //If we hit three, another mushroom's gonna eat us
- var/static/mutable_appearance/cap_living //Where we store our cap icons so we dont generate them constantly to update our icon
- var/static/mutable_appearance/cap_dead
-
-/mob/living/simple_animal/hostile/mushroom/examine(mob/user)
- . = ..()
- if(health >= maxHealth)
- . += "It looks healthy."
- else
- . += "It looks like it's been roughed up."
-
-/mob/living/simple_animal/hostile/mushroom/Life()
- ..()
- if(!stat)//Mushrooms slowly regenerate if conscious, for people who want to save them from being eaten
- adjustBruteLoss(-2)
-
-/mob/living/simple_animal/hostile/mushroom/Initialize()//Makes every shroom a little unique
- melee_damage_lower += rand(3, 5)
- melee_damage_upper += rand(10,20)
- maxHealth += rand(40,60)
- move_to_delay = rand(3,11)
- cap_living = cap_living || mutable_appearance(icon, "mushroom_cap")
- cap_dead = cap_dead || mutable_appearance(icon, "mushroom_cap_dead")
-
- cap_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
- UpdateMushroomCap()
- health = maxHealth
- . = ..()
-
-/mob/living/simple_animal/hostile/mushroom/CanAttack(atom/the_target) // Mushroom-specific version of CanAttack to handle stupid attack_same = 2 crap so we don't have to do it for literally every single simple_animal/hostile because this shit never gets spawned
- if(!the_target || isturf(the_target) || istype(the_target, /atom/movable/lighting_object))
- return FALSE
-
- if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
- return FALSE
-
- if(isliving(the_target))
- var/mob/living/L = the_target
-
- if (!faction_check_mob(L) && attack_same == 2)
- return FALSE
- if(L.stat > stat_attack)
- return FALSE
-
- return TRUE
-
- return FALSE
-
-/mob/living/simple_animal/hostile/mushroom/adjustHealth(amount, updating_health = TRUE, forced = FALSE) //Possibility to flee from a fight just to make it more visually interesting
- if(!retreat_distance && prob(33))
- retreat_distance = 5
- addtimer(CALLBACK(src, .proc/stop_retreat), 30)
- . = ..()
-
-/mob/living/simple_animal/hostile/mushroom/proc/stop_retreat()
- retreat_distance = null
-
-/mob/living/simple_animal/hostile/mushroom/attack_animal(mob/living/L)
- if(istype(L, /mob/living/simple_animal/hostile/mushroom) && stat == DEAD)
- var/mob/living/simple_animal/hostile/mushroom/M = L
- if(faint_ticker < 2)
- M.visible_message("[M] chews a bit on [src].")
- faint_ticker++
- return TRUE
- M.visible_message("[M] devours [src]!")
- var/level_gain = (powerlevel - M.powerlevel)
- if(level_gain >= -1 && !bruised && !M.ckey)//Player shrooms can't level up to become robust gods.
- if(level_gain < 1)//So we still gain a level if two mushrooms were the same level
- level_gain = 1
- M.LevelUp(level_gain)
- M.adjustBruteLoss(-M.maxHealth)
- qdel(src)
- return TRUE
- return ..()
-
-/mob/living/simple_animal/hostile/mushroom/revive(full_heal = 0, admin_revive = 0)
- if(..())
- icon_state = "mushroom_color"
- UpdateMushroomCap()
- . = 1
-
-/mob/living/simple_animal/hostile/mushroom/death(gibbed)
- ..(gibbed)
- UpdateMushroomCap()
-
-/mob/living/simple_animal/hostile/mushroom/proc/UpdateMushroomCap()
- cut_overlays()
- cap_living.color = cap_color
- cap_dead.color = cap_color
- if(health == 0)
- add_overlay(cap_dead)
- else
- add_overlay(cap_living)
-
-/mob/living/simple_animal/hostile/mushroom/proc/Recover()
- visible_message("[src] slowly begins to recover.")
- faint_ticker = 0
- revive(full_heal = 1)
- UpdateMushroomCap()
- recovery_cooldown = 1
- addtimer(CALLBACK(src, .proc/recovery_recharge), 300)
-
-/mob/living/simple_animal/hostile/mushroom/proc/recovery_recharge()
- recovery_cooldown = 0
-
-/mob/living/simple_animal/hostile/mushroom/proc/LevelUp(level_gain)
- if(powerlevel <= 9)
- powerlevel += level_gain
- if(prob(25))
- melee_damage_lower += (level_gain * rand(1,5))
- else
- melee_damage_upper += (level_gain * rand(1,5))
- maxHealth += (level_gain * rand(1,5))
- adjustBruteLoss(-maxHealth) //They'll always heal, even if they don't gain a level, in case you want to keep this shroom around instead of harvesting it
-
-/mob/living/simple_animal/hostile/mushroom/proc/Bruise()
- if(!bruised && !stat)
- src.visible_message("The [src.name] was bruised!")
- bruised = 1
-
-/mob/living/simple_animal/hostile/mushroom/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/reagent_containers/food/snacks/grown/mushroom))
- if(stat == DEAD && !recovery_cooldown)
- Recover()
- qdel(I)
- else
- to_chat(user, "[src] won't eat it!")
- return
- if(I.force)
- Bruise()
- ..()
-
-/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
- . = ..()
- if(.) // the attack was blocked
- return
- if(M.a_intent == INTENT_HARM)
- Bruise()
-
-/mob/living/simple_animal/hostile/mushroom/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
- ..()
- if(istype(AM, /obj/item))
- var/obj/item/T = AM
- if(T.throwforce)
- Bruise()
-
-/mob/living/simple_animal/hostile/mushroom/bullet_act()
- ..()
- Bruise()
-
-/mob/living/simple_animal/hostile/mushroom/harvest()
- var/counter
- for(counter=0, counter<=powerlevel, counter++)
- var/obj/item/reagent_containers/food/snacks/hugemushroomslice/S = new /obj/item/reagent_containers/food/snacks/hugemushroomslice(src.loc)
- S.reagents.add_reagent("mushroomhallucinogen", powerlevel)
- S.reagents.add_reagent("omnizine", powerlevel)
- S.reagents.add_reagent("synaptizine", powerlevel)
+/mob/living/simple_animal/hostile/mushroom
+ name = "walking mushroom"
+ desc = "It's a massive mushroom... with legs?"
+ icon_state = "mushroom_color"
+ icon_living = "mushroom_color"
+ icon_dead = "mushroom_dead"
+ speak_chance = 0
+ turns_per_move = 1
+ maxHealth = 10
+ health = 10
+ butcher_results = list(/obj/item/reagent_containers/food/snacks/hugemushroomslice = 1)
+ response_help = "pets"
+ response_disarm = "gently pushes aside"
+ response_harm = "whacks"
+ harm_intent_damage = 5
+ obj_damage = 0
+ melee_damage_lower = 1
+ melee_damage_upper = 1
+ attack_same = 2
+ attacktext = "chomps"
+ attack_sound = 'sound/weapons/bite.ogg'
+ faction = list("mushroom")
+ environment_smash = ENVIRONMENT_SMASH_NONE
+ stat_attack = DEAD
+ mouse_opacity = MOUSE_OPACITY_ICON
+ speed = 1
+ ventcrawler = VENTCRAWLER_ALWAYS
+ robust_searching = 1
+ unique_name = 1
+ speak_emote = list("squeaks")
+ deathmessage = "fainted."
+ var/cap_color = "#ffffff"
+ var/powerlevel = 0 //Tracks our general strength level gained from eating other shrooms
+ var/bruised = 0 //If someone tries to cheat the system by attacking a shroom to lower its health, punish them so that it wont award levels to shrooms that eat it
+ var/recovery_cooldown = 0 //So you can't repeatedly revive it during a fight
+ var/faint_ticker = 0 //If we hit three, another mushroom's gonna eat us
+ var/static/mutable_appearance/cap_living //Where we store our cap icons so we dont generate them constantly to update our icon
+ var/static/mutable_appearance/cap_dead
+
+/mob/living/simple_animal/hostile/mushroom/examine(mob/user)
+ . = ..()
+ if(health >= maxHealth)
+ . += "It looks healthy."
+ else
+ . += "It looks like it's been roughed up."
+
+/mob/living/simple_animal/hostile/mushroom/Life()
+ ..()
+ if(!stat)//Mushrooms slowly regenerate if conscious, for people who want to save them from being eaten
+ adjustBruteLoss(-2)
+
+/mob/living/simple_animal/hostile/mushroom/Initialize()//Makes every shroom a little unique
+ melee_damage_lower += rand(3, 5)
+ melee_damage_upper += rand(10,20)
+ maxHealth += rand(40,60)
+ move_to_delay = rand(3,11)
+ cap_living = cap_living || mutable_appearance(icon, "mushroom_cap")
+ cap_dead = cap_dead || mutable_appearance(icon, "mushroom_cap_dead")
+
+ cap_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255))
+ UpdateMushroomCap()
+ health = maxHealth
+ . = ..()
+
+/mob/living/simple_animal/hostile/mushroom/CanAttack(atom/the_target) // Mushroom-specific version of CanAttack to handle stupid attack_same = 2 crap so we don't have to do it for literally every single simple_animal/hostile because this shit never gets spawned
+ if(!the_target || isturf(the_target) || istype(the_target, /atom/movable/lighting_object))
+ return FALSE
+
+ if(see_invisible < the_target.invisibility)//Target's invisible to us, forget it
+ return FALSE
+
+ if(isliving(the_target))
+ var/mob/living/L = the_target
+
+ if (!faction_check_mob(L) && attack_same == 2)
+ return FALSE
+ if(L.stat > stat_attack)
+ return FALSE
+
+ return TRUE
+
+ return FALSE
+
+/mob/living/simple_animal/hostile/mushroom/adjustHealth(amount, updating_health = TRUE, forced = FALSE) //Possibility to flee from a fight just to make it more visually interesting
+ if(!retreat_distance && prob(33))
+ retreat_distance = 5
+ addtimer(CALLBACK(src, .proc/stop_retreat), 30)
+ . = ..()
+
+/mob/living/simple_animal/hostile/mushroom/proc/stop_retreat()
+ retreat_distance = null
+
+/mob/living/simple_animal/hostile/mushroom/attack_animal(mob/living/L)
+ if(istype(L, /mob/living/simple_animal/hostile/mushroom) && stat == DEAD)
+ var/mob/living/simple_animal/hostile/mushroom/M = L
+ if(faint_ticker < 2)
+ M.visible_message("[M] chews a bit on [src].")
+ faint_ticker++
+ return TRUE
+ M.visible_message("[M] devours [src]!")
+ var/level_gain = (powerlevel - M.powerlevel)
+ if(level_gain >= -1 && !bruised && !M.ckey)//Player shrooms can't level up to become robust gods.
+ if(level_gain < 1)//So we still gain a level if two mushrooms were the same level
+ level_gain = 1
+ M.LevelUp(level_gain)
+ M.adjustBruteLoss(-M.maxHealth)
+ qdel(src)
+ return TRUE
+ return ..()
+
+/mob/living/simple_animal/hostile/mushroom/revive(full_heal = 0, admin_revive = 0)
+ if(..())
+ icon_state = "mushroom_color"
+ UpdateMushroomCap()
+ . = 1
+
+/mob/living/simple_animal/hostile/mushroom/death(gibbed)
+ ..(gibbed)
+ UpdateMushroomCap()
+
+/mob/living/simple_animal/hostile/mushroom/proc/UpdateMushroomCap()
+ cut_overlays()
+ cap_living.color = cap_color
+ cap_dead.color = cap_color
+ if(health == 0)
+ add_overlay(cap_dead)
+ else
+ add_overlay(cap_living)
+
+/mob/living/simple_animal/hostile/mushroom/proc/Recover()
+ visible_message("[src] slowly begins to recover.")
+ faint_ticker = 0
+ revive(full_heal = 1)
+ UpdateMushroomCap()
+ recovery_cooldown = 1
+ addtimer(CALLBACK(src, .proc/recovery_recharge), 300)
+
+/mob/living/simple_animal/hostile/mushroom/proc/recovery_recharge()
+ recovery_cooldown = 0
+
+/mob/living/simple_animal/hostile/mushroom/proc/LevelUp(level_gain)
+ if(powerlevel <= 9)
+ powerlevel += level_gain
+ if(prob(25))
+ melee_damage_lower += (level_gain * rand(1,5))
+ else
+ melee_damage_upper += (level_gain * rand(1,5))
+ maxHealth += (level_gain * rand(1,5))
+ adjustBruteLoss(-maxHealth) //They'll always heal, even if they don't gain a level, in case you want to keep this shroom around instead of harvesting it
+
+/mob/living/simple_animal/hostile/mushroom/proc/Bruise()
+ if(!bruised && !stat)
+ src.visible_message("The [src.name] was bruised!")
+ bruised = 1
+
+/mob/living/simple_animal/hostile/mushroom/attackby(obj/item/I, mob/user, params)
+ if(istype(I, /obj/item/reagent_containers/food/snacks/grown/mushroom))
+ if(stat == DEAD && !recovery_cooldown)
+ Recover()
+ qdel(I)
+ else
+ to_chat(user, "[src] won't eat it!")
+ return
+ if(I.force)
+ Bruise()
+ ..()
+
+/mob/living/simple_animal/hostile/mushroom/attack_hand(mob/living/carbon/human/M)
+ . = ..()
+ if(.) // the attack was blocked
+ return
+ if(M.a_intent == INTENT_HARM)
+ Bruise()
+
+/mob/living/simple_animal/hostile/mushroom/hitby(atom/movable/AM, skipcatch = FALSE, hitpush = TRUE, blocked = FALSE, datum/thrownthing/throwingdatum)
+ ..()
+ if(istype(AM, /obj/item))
+ var/obj/item/T = AM
+ if(T.throwforce)
+ Bruise()
+
+/mob/living/simple_animal/hostile/mushroom/bullet_act()
+ ..()
+ Bruise()
+
+/mob/living/simple_animal/hostile/mushroom/harvest()
+ var/counter
+ for(counter=0, counter<=powerlevel, counter++)
+ var/obj/item/reagent_containers/food/snacks/hugemushroomslice/S = new /obj/item/reagent_containers/food/snacks/hugemushroomslice(src.loc)
+ S.reagents.add_reagent(/datum/reagent/drug/mushroomhallucinogen, powerlevel)
+ S.reagents.add_reagent(/datum/reagent/medicine/omnizine, powerlevel)
+ S.reagents.add_reagent(/datum/reagent/medicine/synaptizine, powerlevel)
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 9671f35e..67b3cb53 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -141,9 +141,9 @@
. = ..()
remove_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE)
var/amount = 0
- if(reagents.has_reagent("morphine")) // morphine slows slimes down
+ if(reagents.has_reagent(/datum/reagent/medicine/morphine)) // morphine slows slimes down
amount = 2
- if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow
+ if(reagents.has_reagent(/datum/reagent/consumable/frostoil)) // Frostoil also makes them move VEEERRYYYYY slow
amount = 5
if(amount)
add_movespeed_modifier(MOVESPEED_ID_SLIME_REAGENTMOD, TRUE, 100, override = TRUE, multiplicative_slowdown = amount)
diff --git a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
index 816ae587..89f5d20e 100644
--- a/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
+++ b/code/modules/ninja/suit/n_suit_verbs/ninja_adrenaline.dm
@@ -4,7 +4,7 @@
if(!ninjacost(0,N_ADRENALINE))
var/mob/living/carbon/human/H = affecting
- H.do_adrenaline(150, TRUE, 0, 0, TRUE, list("inaprovaline" = 3, "synaptizine" = 10, "omnizine" = 10), "You feel a sudden surge of energy!")
+ H.do_adrenaline(150, TRUE, 0, 0, TRUE, list(/datum/reagent/medicine/inaprovaline = 3, /datum/reagent/medicine/synaptizine = 10, /datum/reagent/medicine/omnizine = 10), "You feel a sudden surge of energy!")
H.say(pick("A CORNERED FOX IS MORE DANGEROUS THAN A JACKAL!","HURT ME MOOORRREEE!","IMPRESSIVE!"), forced = "ninjaboost")
@@ -15,5 +15,5 @@
/obj/item/clothing/suit/space/space_ninja/proc/ninjaboost_after()
var/mob/living/carbon/human/H = affecting
- H.reagents.add_reagent("radium", a_transfer)
+ H.reagents.add_reagent(/datum/reagent/radium, a_transfer)
to_chat(H, "You are beginning to feel the after-effect of the injection.")
diff --git a/code/modules/ninja/suit/suit_attackby.dm b/code/modules/ninja/suit/suit_attackby.dm
index 0496a2f1..ed920a57 100644
--- a/code/modules/ninja/suit/suit_attackby.dm
+++ b/code/modules/ninja/suit/suit_attackby.dm
@@ -5,13 +5,13 @@
return ..()
if(istype(I, /obj/item/reagent_containers/glass))//If it's a glass beaker.
- if(I.reagents.has_reagent("radium", a_transfer) && a_boost < a_maxamount)
- I.reagents.remove_reagent("radium", a_transfer)
+ if(I.reagents.has_reagent(/datum/reagent/radium, a_transfer) && a_boost < a_maxamount)
+ I.reagents.remove_reagent(/datum/reagent/radium, a_transfer)
a_boost++;
to_chat(U, "There are now [a_boost] adrenaline boosts remaining.")
return
- if(I.reagents.has_reagent("smoke_powder", a_transfer) && s_bombs < s_maxamount)
- I.reagents.remove_reagent("smoke_powder", a_transfer)
+ if(I.reagents.has_reagent(/datum/reagent/smoke_powder, a_transfer) && s_bombs < s_maxamount)
+ I.reagents.remove_reagent(/datum/reagent/smoke_powder, a_transfer)
s_bombs++;
to_chat(U, "There are now [s_bombs] smoke bombs remaining.")
return
diff --git a/code/modules/paperwork/pen.dm b/code/modules/paperwork/pen.dm
index 0372f8b9..66c58033 100644
--- a/code/modules/paperwork/pen.dm
+++ b/code/modules/paperwork/pen.dm
@@ -1,218 +1,218 @@
-/* Pens!
- * Contains:
- * Pens
- * Sleepy Pens
- * Parapens
- * Edaggers
- */
-
-
-/*
- * Pens
- */
-/obj/item/pen
- desc = "It's a black ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpadsâ„¢!"
- name = "pen"
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "pen"
- item_state = "pen"
- slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_EARS
- throwforce = 0
- w_class = WEIGHT_CLASS_TINY
- throw_speed = 3
- throw_range = 7
- materials = list(MAT_METAL=10)
- pressure_resistance = 2
- grind_results = list("iron" = 2, "iodine" = 1)
- var/colour = "black" //what colour the ink is!
- var/degrees = 0
- var/font = PEN_FONT
-
-/obj/item/pen/suicide_act(mob/user)
- user.visible_message("[user] is scribbling numbers all over [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit sudoku...")
- return(BRUTELOSS)
-
-/obj/item/pen/blue
- desc = "It's a blue ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpadsâ„¢!"
- icon_state = "pen_blue"
- colour = "blue"
-
-/obj/item/pen/red
- desc = "It's a red ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpadsâ„¢!"
- icon_state = "pen_red"
- colour = "red"
-
-/obj/item/pen/invisible
- desc = "It's an invisible pen marker."
- icon_state = "pen"
- colour = "white"
-
-/obj/item/pen/fourcolor
- desc = "It's a fancy four-color ink pen, set to black. Modified to be compatible with Nanotransen-brand Digital-Readpadsâ„¢"
- name = "four-color pen"
- colour = "black"
-
-/obj/item/pen/fourcolor/attack_self(mob/living/carbon/user)
- switch(colour)
- if("black")
- colour = "red"
- if("red")
- colour = "green"
- if("green")
- colour = "blue"
- else
- colour = "black"
- to_chat(user, "\The [src] will now write in [colour].")
- desc = "It's a fancy four-color ink pen, set to [colour]."
-
-/obj/item/pen/fountain
- name = "fountain pen"
- desc = "It's a common fountain pen, with a faux wood body."
- icon_state = "pen-fountain"
- font = FOUNTAIN_PEN_FONT
-
-/obj/item/pen/fountain/captain
- name = "captain's fountain pen"
- desc = "It's an expensive Oak fountain pen. The nib is quite sharp."
- icon_state = "pen-fountain-o"
- force = 5
- throwforce = 5
- throw_speed = 4
- colour = "crimson"
- materials = list(MAT_GOLD = 750)
- sharpness = IS_SHARP
- resistance_flags = FIRE_PROOF
- unique_reskin = list("Oak" = "pen-fountain-o",
- "Gold" = "pen-fountain-g",
- "Rosewood" = "pen-fountain-r",
- "Black and Silver" = "pen-fountain-b",
- "Command Blue" = "pen-fountain-cb"
- )
-
-/obj/item/pen/fountain/captain/Initialize()
- . = ..()
- AddComponent(/datum/component/butchering, 200, 115) //the pen is mightier than the sword
-
-/obj/item/pen/fountain/captain/reskin_obj(mob/M)
- ..()
- if(current_skin)
- desc = "It's an expensive [current_skin] fountain pen. The nib is quite sharp."
-
-/obj/item/pen/attack_self(mob/living/carbon/user)
- var/deg = input(user, "What angle would you like to rotate the pen head to? (1-360)", "Rotate Pen Head") as null|num
- if(deg && (deg > 0 && deg <= 360))
- degrees = deg
- to_chat(user, "You rotate the top of the pen to [degrees] degrees.")
- SEND_SIGNAL(src, COMSIG_PEN_ROTATED, deg, user)
-
-/obj/item/pen/attack(mob/living/M, mob/user,stealth)
- if(!istype(M))
- return
-
- if(!force)
- if(M.can_inject(user, 1))
- to_chat(user, "You stab [M] with the pen.")
- if(!stealth)
- to_chat(M, "You feel a tiny prick!")
- . = 1
-
- log_combat(user, M, "stabbed", src)
-
- else
- . = ..()
-
-/obj/item/pen/afterattack(obj/O, mob/living/user, proximity)
- . = ..()
- //Changing Name/Description of items. Only works if they have the 'unique_rename' flag set
- if(isobj(O) && proximity && (O.obj_flags & UNIQUE_RENAME))
- var/penchoice = input(user, "What would you like to edit?", "Rename or change description?") as null|anything in list("Rename","Change description")
- if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
- return
- if(penchoice == "Rename")
- var/input = stripped_input(user,"What do you want to name \the [O.name]?", ,"", MAX_NAME_LEN)
- var/oldname = O.name
- if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
- return
- if(oldname == input)
- to_chat(user, "You changed \the [O.name] to... well... \the [O.name].")
- else
- O.name = input
- to_chat(user, "\The [oldname] has been successfully been renamed to \the [input].")
- O.renamedByPlayer = TRUE
-
- if(penchoice == "Change description")
- var/input = stripped_input(user,"Describe \the [O.name] here", ,"", 100)
- if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
- return
- O.desc = input
- to_chat(user, "You have successfully changed \the [O.name]'s description.")
-
-/*
- * Sleepypens
- */
-
-/obj/item/pen/sleepy/attack(mob/living/M, mob/user)
- if(!istype(M))
- return
-
- if(..())
- if(reagents.total_volume)
- if(M.reagents)
- reagents.reaction(M, INJECT)
- reagents.trans_to(M, reagents.total_volume)
-
-
-/obj/item/pen/sleepy/Initialize()
- . = ..()
- create_reagents(45, OPENCONTAINER)
- reagents.add_reagent("chloralhydrate", 20)
- reagents.add_reagent("mutetoxin", 15)
- reagents.add_reagent("tirizene", 10)
-
-/*
- * (Alan) Edaggers
- */
-/obj/item/pen/edagger
- attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") //these wont show up if the pen is off
- var/on = FALSE
-
-/obj/item/pen/edagger/Initialize()
- . = ..()
- AddComponent(/datum/component/butchering, 60, 100, 0, 'sound/weapons/blade1.ogg', TRUE)
-
-/obj/item/pen/edagger/attack_self(mob/living/user)
- if(on)
- on = FALSE
- force = initial(force)
- w_class = initial(w_class)
- name = initial(name)
- hitsound = initial(hitsound)
- embedding = embedding.setRating(embed_chance = EMBED_CHANCE)
- throwforce = initial(throwforce)
- playsound(user, 'sound/weapons/saberoff.ogg', 5, 1)
- to_chat(user, "[src] can now be concealed.")
- else
- on = TRUE
- force = 18
- w_class = WEIGHT_CLASS_NORMAL
- name = "energy dagger"
- hitsound = 'sound/weapons/blade1.ogg'
- embedding = embedding.setRating(embed_chance = 100) //rule of cool
- throwforce = 35
- playsound(user, 'sound/weapons/saberon.ogg', 5, 1)
- to_chat(user, "[src] is now active.")
- var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering)
- butchering.butchering_enabled = on
- update_icon()
-
-/obj/item/pen/edagger/update_icon()
- if(on)
- icon_state = "edagger"
- item_state = "edagger"
- lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
- else
- icon_state = initial(icon_state) //looks like a normal pen when off.
- item_state = initial(item_state)
- lefthand_file = initial(lefthand_file)
- righthand_file = initial(righthand_file)
+/* Pens!
+ * Contains:
+ * Pens
+ * Sleepy Pens
+ * Parapens
+ * Edaggers
+ */
+
+
+/*
+ * Pens
+ */
+/obj/item/pen
+ desc = "It's a black ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpadsâ„¢!"
+ name = "pen"
+ icon = 'icons/obj/bureaucracy.dmi'
+ icon_state = "pen"
+ item_state = "pen"
+ slot_flags = ITEM_SLOT_BELT | ITEM_SLOT_EARS
+ throwforce = 0
+ w_class = WEIGHT_CLASS_TINY
+ throw_speed = 3
+ throw_range = 7
+ materials = list(MAT_METAL=10)
+ pressure_resistance = 2
+ grind_results = list(/datum/reagent/iron = 2, /datum/reagent/iodine = 1)
+ var/colour = "black" //what colour the ink is!
+ var/degrees = 0
+ var/font = PEN_FONT
+
+/obj/item/pen/suicide_act(mob/user)
+ user.visible_message("[user] is scribbling numbers all over [user.p_them()]self with [src]! It looks like [user.p_theyre()] trying to commit sudoku...")
+ return(BRUTELOSS)
+
+/obj/item/pen/blue
+ desc = "It's a blue ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpadsâ„¢!"
+ icon_state = "pen_blue"
+ colour = "blue"
+
+/obj/item/pen/red
+ desc = "It's a red ink pen, modified for use with both paper and Nanotransen-brand Digital-Readpadsâ„¢!"
+ icon_state = "pen_red"
+ colour = "red"
+
+/obj/item/pen/invisible
+ desc = "It's an invisible pen marker."
+ icon_state = "pen"
+ colour = "white"
+
+/obj/item/pen/fourcolor
+ desc = "It's a fancy four-color ink pen, set to black. Modified to be compatible with Nanotransen-brand Digital-Readpadsâ„¢"
+ name = "four-color pen"
+ colour = "black"
+
+/obj/item/pen/fourcolor/attack_self(mob/living/carbon/user)
+ switch(colour)
+ if("black")
+ colour = "red"
+ if("red")
+ colour = "green"
+ if("green")
+ colour = "blue"
+ else
+ colour = "black"
+ to_chat(user, "\The [src] will now write in [colour].")
+ desc = "It's a fancy four-color ink pen, set to [colour]."
+
+/obj/item/pen/fountain
+ name = "fountain pen"
+ desc = "It's a common fountain pen, with a faux wood body."
+ icon_state = "pen-fountain"
+ font = FOUNTAIN_PEN_FONT
+
+/obj/item/pen/fountain/captain
+ name = "captain's fountain pen"
+ desc = "It's an expensive Oak fountain pen. The nib is quite sharp."
+ icon_state = "pen-fountain-o"
+ force = 5
+ throwforce = 5
+ throw_speed = 4
+ colour = "crimson"
+ materials = list(MAT_GOLD = 750)
+ sharpness = IS_SHARP
+ resistance_flags = FIRE_PROOF
+ unique_reskin = list("Oak" = "pen-fountain-o",
+ "Gold" = "pen-fountain-g",
+ "Rosewood" = "pen-fountain-r",
+ "Black and Silver" = "pen-fountain-b",
+ "Command Blue" = "pen-fountain-cb"
+ )
+
+/obj/item/pen/fountain/captain/Initialize()
+ . = ..()
+ AddComponent(/datum/component/butchering, 200, 115) //the pen is mightier than the sword
+
+/obj/item/pen/fountain/captain/reskin_obj(mob/M)
+ ..()
+ if(current_skin)
+ desc = "It's an expensive [current_skin] fountain pen. The nib is quite sharp."
+
+/obj/item/pen/attack_self(mob/living/carbon/user)
+ var/deg = input(user, "What angle would you like to rotate the pen head to? (1-360)", "Rotate Pen Head") as null|num
+ if(deg && (deg > 0 && deg <= 360))
+ degrees = deg
+ to_chat(user, "You rotate the top of the pen to [degrees] degrees.")
+ SEND_SIGNAL(src, COMSIG_PEN_ROTATED, deg, user)
+
+/obj/item/pen/attack(mob/living/M, mob/user,stealth)
+ if(!istype(M))
+ return
+
+ if(!force)
+ if(M.can_inject(user, 1))
+ to_chat(user, "You stab [M] with the pen.")
+ if(!stealth)
+ to_chat(M, "You feel a tiny prick!")
+ . = 1
+
+ log_combat(user, M, "stabbed", src)
+
+ else
+ . = ..()
+
+/obj/item/pen/afterattack(obj/O, mob/living/user, proximity)
+ . = ..()
+ //Changing Name/Description of items. Only works if they have the 'unique_rename' flag set
+ if(isobj(O) && proximity && (O.obj_flags & UNIQUE_RENAME))
+ var/penchoice = input(user, "What would you like to edit?", "Rename or change description?") as null|anything in list("Rename","Change description")
+ if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
+ return
+ if(penchoice == "Rename")
+ var/input = stripped_input(user,"What do you want to name \the [O.name]?", ,"", MAX_NAME_LEN)
+ var/oldname = O.name
+ if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
+ return
+ if(oldname == input)
+ to_chat(user, "You changed \the [O.name] to... well... \the [O.name].")
+ else
+ O.name = input
+ to_chat(user, "\The [oldname] has been successfully been renamed to \the [input].")
+ O.renamedByPlayer = TRUE
+
+ if(penchoice == "Change description")
+ var/input = stripped_input(user,"Describe \the [O.name] here", ,"", 100)
+ if(QDELETED(O) || !user.canUseTopic(O, BE_CLOSE))
+ return
+ O.desc = input
+ to_chat(user, "You have successfully changed \the [O.name]'s description.")
+
+/*
+ * Sleepypens
+ */
+
+/obj/item/pen/sleepy/attack(mob/living/M, mob/user)
+ if(!istype(M))
+ return
+
+ if(..())
+ if(reagents.total_volume)
+ if(M.reagents)
+ reagents.reaction(M, INJECT)
+ reagents.trans_to(M, reagents.total_volume)
+
+
+/obj/item/pen/sleepy/Initialize()
+ . = ..()
+ create_reagents(45, OPENCONTAINER)
+ reagents.add_reagent(/datum/reagent/toxin/chloralhydrate, 20)
+ reagents.add_reagent(/datum/reagent/toxin/mutetoxin, 15)
+ reagents.add_reagent(/datum/reagent/toxin/staminatoxin, 10)
+
+/*
+ * (Alan) Edaggers
+ */
+/obj/item/pen/edagger
+ attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") //these wont show up if the pen is off
+ var/on = FALSE
+
+/obj/item/pen/edagger/Initialize()
+ . = ..()
+ AddComponent(/datum/component/butchering, 60, 100, 0, 'sound/weapons/blade1.ogg', TRUE)
+
+/obj/item/pen/edagger/attack_self(mob/living/user)
+ if(on)
+ on = FALSE
+ force = initial(force)
+ w_class = initial(w_class)
+ name = initial(name)
+ hitsound = initial(hitsound)
+ embedding = embedding.setRating(embed_chance = EMBED_CHANCE)
+ throwforce = initial(throwforce)
+ playsound(user, 'sound/weapons/saberoff.ogg', 5, 1)
+ to_chat(user, "[src] can now be concealed.")
+ else
+ on = TRUE
+ force = 18
+ w_class = WEIGHT_CLASS_NORMAL
+ name = "energy dagger"
+ hitsound = 'sound/weapons/blade1.ogg'
+ embedding = embedding.setRating(embed_chance = 100) //rule of cool
+ throwforce = 35
+ playsound(user, 'sound/weapons/saberon.ogg', 5, 1)
+ to_chat(user, "[src] is now active.")
+ var/datum/component/butchering/butchering = src.GetComponent(/datum/component/butchering)
+ butchering.butchering_enabled = on
+ update_icon()
+
+/obj/item/pen/edagger/update_icon()
+ if(on)
+ icon_state = "edagger"
+ item_state = "edagger"
+ lefthand_file = 'icons/mob/inhands/weapons/swords_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/weapons/swords_righthand.dmi'
+ else
+ icon_state = initial(icon_state) //looks like a normal pen when off.
+ item_state = initial(item_state)
+ lefthand_file = initial(lefthand_file)
+ righthand_file = initial(righthand_file)
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 5f23f72b..e8d31869 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -1,340 +1,340 @@
-/* Photocopiers!
- * Contains:
- * Photocopier
- * Toner Cartridge
- */
-
-/*
- * Photocopier
- */
-/obj/machinery/photocopier
- name = "photocopier"
- desc = "Used to copy important documents and anatomy studies."
- icon = 'icons/obj/library.dmi'
- icon_state = "photocopier"
- density = TRUE
- use_power = IDLE_POWER_USE
- idle_power_usage = 30
- active_power_usage = 200
- power_channel = EQUIP
- max_integrity = 300
- integrity_failure = 100
- var/obj/item/paper/copy = null //what's in the copier!
- var/obj/item/photo/photocopy = null
- var/obj/item/documents/doccopy = null
- var/copies = 1 //how many copies to print!
- var/toner = 40 //how much toner is left! woooooo~
- var/maxcopies = 10 //how many copies can be copied at once- idea shamelessly stolen from bs12's copier!
- var/greytoggle = "Greyscale"
- var/mob/living/ass //i can't believe i didn't write a stupid-ass comment about this var when i first coded asscopy.
- var/busy = FALSE
-
-/obj/machinery/photocopier/ui_interact(mob/user)
- . = ..()
- var/dat = "Photocopier
"
- if(copy || photocopy || doccopy || (ass && (ass.loc == src.loc)))
- dat += "Remove Paper "
- if(toner)
- dat += "Copy "
- dat += "Printing: [copies] copies."
- dat += "- "
- dat += "+
"
- if(photocopy)
- dat += "Printing in [greytoggle]
"
- else if(toner)
- dat += "Please insert paper to copy.
"
- return l
-
-/obj/machinery/computer/rdconsole/proc/ui_header()
- var/list/l = list()
- var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/research_designs)
- l += "[sheet.css_tag()][RDSCREEN_NOBREAK]"
- l += "
[stored_research.organization] Research and Development Network"
- l += "Available points: [techweb_point_display_rdconsole(stored_research.research_points, stored_research.last_bitcoins)]"
- l += "Security protocols: [obj_flags & EMAGGED ? "Disabled" : "Enabled"]"
- l += "Main Menu | Back
"
- return l
-
-/obj/machinery/computer/rdconsole/proc/ui_designdisk_upload() //Legacy code
- RDSCREEN_UI_DDISK_CHECK
- var/list/l = list()
- l += "Return to Disk Operations
"
- l += "
Load Design to Disk:
"
- for(var/v in stored_research.researched_designs)
- var/datum/design/D = stored_research.researched_designs[v]
- l += "[D.name] "
- l += "Copy to Disk"
- l += "
"
- return l
-
-/obj/machinery/computer/rdconsole/proc/ui_deconstruct() //Legacy code
- RDSCREEN_UI_DECONSTRUCT_CHECK
- var/list/l = list()
- if(!linked_destroy.loaded_item)
- l += "
[RDSCREEN_NOBREAK]"
- l += "Select a node to boost by deconstructing this item. This item can boost:"
-
- var/anything = FALSE
- var/list/boostable_nodes = techweb_item_boost_check(linked_destroy.loaded_item)
- for(var/id in boostable_nodes)
- anything = TRUE
- var/list/worth = boostable_nodes[id]
- var/datum/techweb_node/N = get_techweb_node_by_id(id)
-
- l += "
[RDSCREEN_NOBREAK]"
- if (stored_research.researched_nodes[N.id]) // already researched
- l += "[N.display_name]"
- l += "This node has already been researched."
- else if(!length(worth)) // reveal only
- if (stored_research.hidden_nodes[N.id])
- l += "[N.display_name]"
- l += "This node will be revealed."
- else
- l += "[N.display_name]"
- l += "This node has already been revealed."
- else // boost by the difference
- var/list/differences = list()
- var/list/already_boosted = stored_research.boosted_nodes[N.id]
- for(var/i in worth)
- var/already_boosted_amount = already_boosted? stored_research.boosted_nodes[N.id][i] : 0
- var/amt = min(worth[i], N.research_costs[i]) - already_boosted_amount
- if(amt > 0)
- differences[i] = amt
- if (length(differences))
- l += "[N.display_name]"
- l += "This node will be boosted with the following: [techweb_point_display_generic(differences)]"
- else
- l += "[N.display_name]"
- l += "This node has already been boosted."
- l += "
[RDSCREEN_NOBREAK]"
-
- // point deconstruction and material reclamation use the same ID to prevent accidentally missing the points
- var/list/point_values = techweb_item_point_check(linked_destroy.loaded_item)
- if(point_values)
- anything = TRUE
- l += "
[RDSCREEN_NOBREAK]"
- if (stored_research.deconstructed_items[linked_destroy.loaded_item.type])
- l += "Point Deconstruction"
- l += "This item's points have already been claimed."
- else
- l += "Point Deconstruction"
- l += "This item is worth: [techweb_point_display_generic(point_values)]!"
- l += "
"
+ return l
+
+/obj/machinery/computer/rdconsole/proc/ui_header()
+ var/list/l = list()
+ var/datum/asset/spritesheet/sheet = get_asset_datum(/datum/asset/spritesheet/research_designs)
+ l += "[sheet.css_tag()][RDSCREEN_NOBREAK]"
+ l += "
[stored_research.organization] Research and Development Network"
+ l += "Available points: [techweb_point_display_rdconsole(stored_research.research_points, stored_research.last_bitcoins)]"
+ l += "Security protocols: [obj_flags & EMAGGED ? "Disabled" : "Enabled"]"
+ l += "Main Menu | Back
"
+ return l
+
+/obj/machinery/computer/rdconsole/proc/ui_designdisk_upload() //Legacy code
+ RDSCREEN_UI_DDISK_CHECK
+ var/list/l = list()
+ l += "Return to Disk Operations
"
+ l += "
Load Design to Disk:
"
+ for(var/v in stored_research.researched_designs)
+ var/datum/design/D = stored_research.researched_designs[v]
+ l += "[D.name] "
+ l += "Copy to Disk"
+ l += "
"
+ return l
+
+/obj/machinery/computer/rdconsole/proc/ui_deconstruct() //Legacy code
+ RDSCREEN_UI_DECONSTRUCT_CHECK
+ var/list/l = list()
+ if(!linked_destroy.loaded_item)
+ l += "
[RDSCREEN_NOBREAK]"
+ l += "Select a node to boost by deconstructing this item. This item can boost:"
+
+ var/anything = FALSE
+ var/list/boostable_nodes = techweb_item_boost_check(linked_destroy.loaded_item)
+ for(var/id in boostable_nodes)
+ anything = TRUE
+ var/list/worth = boostable_nodes[id]
+ var/datum/techweb_node/N = get_techweb_node_by_id(id)
+
+ l += "
[RDSCREEN_NOBREAK]"
+ if (stored_research.researched_nodes[N.id]) // already researched
+ l += "[N.display_name]"
+ l += "This node has already been researched."
+ else if(!length(worth)) // reveal only
+ if (stored_research.hidden_nodes[N.id])
+ l += "[N.display_name]"
+ l += "This node will be revealed."
+ else
+ l += "[N.display_name]"
+ l += "This node has already been revealed."
+ else // boost by the difference
+ var/list/differences = list()
+ var/list/already_boosted = stored_research.boosted_nodes[N.id]
+ for(var/i in worth)
+ var/already_boosted_amount = already_boosted? stored_research.boosted_nodes[N.id][i] : 0
+ var/amt = min(worth[i], N.research_costs[i]) - already_boosted_amount
+ if(amt > 0)
+ differences[i] = amt
+ if (length(differences))
+ l += "[N.display_name]"
+ l += "This node will be boosted with the following: [techweb_point_display_generic(differences)]"
+ else
+ l += "[N.display_name]"
+ l += "This node has already been boosted."
+ l += "
[RDSCREEN_NOBREAK]"
+
+ // point deconstruction and material reclamation use the same ID to prevent accidentally missing the points
+ var/list/point_values = techweb_item_point_check(linked_destroy.loaded_item)
+ if(point_values)
+ anything = TRUE
+ l += "
[RDSCREEN_NOBREAK]"
+ if (stored_research.deconstructed_items[linked_destroy.loaded_item.type])
+ l += "Point Deconstruction"
+ l += "This item's points have already been claimed."
+ else
+ l += "Point Deconstruction"
+ l += "This item is worth: [techweb_point_display_generic(point_values)]!"
+ l += "