"
diff --git a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
index 2caf268e1f..d1896c03fc 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/monkeyrecycler.dm
@@ -75,7 +75,10 @@
/obj/machinery/monkey_recycler/attack_hand(mob/user)
- if (src.stat != 0) //NOPOWER etc
+ . = ..()
+ if(.)
+ return
+ if(stat != 0) //NOPOWER etc
return
if(grinded >= required_grind)
to_chat(user, "
")
diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
index 6d8797b7a8..1937ee2695 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
@@ -122,6 +122,9 @@
return ..()
/obj/machinery/processor/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(stat & (NOPOWER|BROKEN))
return
if(src.processing)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index d816504bc5..8be93e88bf 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -132,18 +132,9 @@
S.remove_from_storage(O,src)
O.forceMove(src)
-/obj/machinery/smartfridge/attack_paw(mob/user)
- return src.attack_hand(user)
-
/obj/machinery/smartfridge/attack_ai(mob/user)
return FALSE
-/obj/machinery/smartfridge/attack_hand(mob/user)
- user.set_machine(src)
- interact(user)
-
-
-
/obj/machinery/smartfridge/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
diff --git a/code/modules/food_and_drinks/pizzabox.dm b/code/modules/food_and_drinks/pizzabox.dm
index 928cc52fa8..34868a5000 100644
--- a/code/modules/food_and_drinks/pizzabox.dm
+++ b/code/modules/food_and_drinks/pizzabox.dm
@@ -106,17 +106,16 @@
START_PROCESSING(SSobj, src)
update_icon()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/pizzabox/attack_hand(mob/user)
if(user.get_inactive_held_item() != src)
- ..()
- return
+ return ..()
if(open)
if(pizza)
user.put_in_hands(pizza)
to_chat(user, "
")
pizza = null
update_icon()
- return
else if(bomb)
if(wires.is_all_cut() && bomb_defused)
user.put_in_hands(bomb)
@@ -137,7 +136,6 @@
to_chat(user, "
")
update_icon()
- return
else if(boxes.len)
var/obj/item/pizzabox/topbox = boxes[boxes.len]
boxes -= topbox
@@ -146,8 +144,6 @@
topbox.update_icon()
update_icon()
user.regenerate_icons()
- return
- ..()
/obj/item/pizzabox/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/pizzabox))
diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
index acb9b31d2e..6d495d1c79 100644
--- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
+++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_egg.dm
@@ -14,7 +14,7 @@
subcategory = CAT_EGG
/datum/crafting_recipe/food/omelette
- name = "omelette"
+ name = "Omelette"
reqs = list(
/obj/item/reagent_containers/food/snacks/egg = 2,
/obj/item/reagent_containers/food/snacks/cheesewedge = 2
diff --git a/code/modules/games/cas.dm b/code/modules/games/cas.dm
index 39772b1216..9197e3d044 100644
--- a/code/modules/games/cas.dm
+++ b/code/modules/games/cas.dm
@@ -59,6 +59,9 @@
shuffle_inplace(cards) // distribute blank cards throughout deck
/obj/item/toy/cards/deck/cas/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(user.lying)
return
if(cards.len == 0)
diff --git a/code/modules/holodeck/area_copy.dm b/code/modules/holodeck/area_copy.dm
index 4acedb4780..fee60605e3 100644
--- a/code/modules/holodeck/area_copy.dm
+++ b/code/modules/holodeck/area_copy.dm
@@ -1,9 +1,9 @@
//Vars that will not be copied when using /DuplicateObject
-GLOBAL_LIST_INIT(duplicate_forbidden_vars,list("tag","area","type","loc","locs","vars", "parent","parent_type", "verbs","ckey","key","power_supply","contents","reagents","stat","x","y","z","group","atmos_adjacent_turfs"))
+GLOBAL_LIST_INIT(duplicate_forbidden_vars,list("tag", "datum_components", "area","type","loc","locs","vars", "parent","parent_type", "verbs","ckey","key","power_supply","contents","reagents","stat","x","y","z","group","atmos_adjacent_turfs"))
/proc/DuplicateObject(atom/original, perfectcopy = TRUE, sameloc = FALSE, atom/newloc = null, nerf = FALSE, holoitem=FALSE)
if(!original)
- return null
+ return
var/atom/O
if(sameloc)
diff --git a/code/modules/holodeck/holo_effect.dm b/code/modules/holodeck/holo_effect.dm
index b870ad4c30..c83e7d5520 100644
--- a/code/modules/holodeck/holo_effect.dm
+++ b/code/modules/holodeck/holo_effect.dm
@@ -76,7 +76,7 @@
mob = new mobtype(loc)
// these vars are not really standardized but all would theoretically create stuff on death
- for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume") & mob.vars)
+ for(var/v in list("butcher_results","corpse","weapon1","weapon2","blood_volume","vore_organs") & mob.vars) //CITADEL EDIT, maybe stops ghost bellies
mob.vars[v] = null
return mob
diff --git a/code/modules/holodeck/items.dm b/code/modules/holodeck/items.dm
index 1dcab21e16..d967eebd59 100644
--- a/code/modules/holodeck/items.dm
+++ b/code/modules/holodeck/items.dm
@@ -108,6 +108,9 @@
visible_message("
")
/obj/structure/holohoop/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(user.pulling && user.a_intent == INTENT_GRAB && isliving(user.pulling))
var/mob/living/L = user.pulling
if(user.grab_state < GRAB_AGGRESSIVE)
@@ -165,6 +168,9 @@
to_chat(user, "The device is a solid button, there's nothing you can do with it!")
/obj/machinery/readybutton/attack_hand(mob/user as mob)
+ . = ..()
+ if(.)
+ return
if(user.stat || stat & (NOPOWER|BROKEN))
to_chat(user, "
")
return
diff --git a/code/modules/hydroponics/beekeeping/beebox.dm b/code/modules/hydroponics/beekeeping/beebox.dm
index cf12ccb3ce..7075b8502e 100644
--- a/code/modules/hydroponics/beekeeping/beebox.dm
+++ b/code/modules/hydroponics/beekeeping/beebox.dm
@@ -192,8 +192,8 @@
..()
-
-/obj/structure/beebox/attack_hand(mob/user)
+/obj/structure/beebox/interact(mob/user)
+ . = ..()
if(!user.bee_friendly())
//Time to get stung!
var/bees = FALSE
diff --git a/code/modules/hydroponics/biogenerator.dm b/code/modules/hydroponics/biogenerator.dm
index 8939b60138..b69e5e6302 100644
--- a/code/modules/hydroponics/biogenerator.dm
+++ b/code/modules/hydroponics/biogenerator.dm
@@ -151,10 +151,10 @@
else
to_chat(user, "
")
-/obj/machinery/biogenerator/interact(mob/user)
+/obj/machinery/biogenerator/ui_interact(mob/user)
if(stat & BROKEN || panel_open)
return
- user.set_machine(src)
+ . = ..()
var/dat
if(processing)
dat += "
Biogenerator is processing! Please wait...
"
@@ -202,15 +202,11 @@
var/datum/browser/popup = new(user, "biogen", name, 350, 520)
popup.set_content(dat)
popup.open()
- return
-
-/obj/machinery/biogenerator/attack_hand(mob/user)
- interact(user)
/obj/machinery/biogenerator/proc/activate()
- if (usr.stat != 0)
+ if (usr.stat != CONSCIOUS)
return
- if (src.stat != 0) //NOPOWER etc
+ if (src.stat != NONE) //NOPOWER etc
return
if(processing)
to_chat(usr, "
")
@@ -233,7 +229,6 @@
update_icon()
else
menustat = "void"
- return
/obj/machinery/biogenerator/proc/check_cost(list/materials, multiplier = 1, remove_points = 1)
if(materials.len != 1 || materials[1] != MAT_BIOMASS)
diff --git a/code/modules/hydroponics/gene_modder.dm b/code/modules/hydroponics/gene_modder.dm
index 70f6f225ec..6bb000ebe2 100644
--- a/code/modules/hydroponics/gene_modder.dm
+++ b/code/modules/hydroponics/gene_modder.dm
@@ -98,14 +98,8 @@
else
..()
-
-/obj/machinery/plantgenes/attack_hand(mob/user)
- if(..())
- return
- interact(user)
-
-/obj/machinery/plantgenes/interact(mob/user)
- user.set_machine(src)
+/obj/machinery/plantgenes/ui_interact(mob/user)
+ . = ..()
if(!user)
return
diff --git a/code/modules/hydroponics/grown/chili.dm b/code/modules/hydroponics/grown/chili.dm
index 419ab3abad..c01f3ba6ef 100644
--- a/code/modules/hydroponics/grown/chili.dm
+++ b/code/modules/hydroponics/grown/chili.dm
@@ -78,7 +78,9 @@
foodtype = FRUIT
/obj/item/reagent_containers/food/snacks/grown/ghost_chili/attack_hand(mob/user)
- ..()
+ . = ..()
+ if(.)
+ return
if( ismob(loc) )
held_mob = loc
START_PROCESSING(SSobj, src)
diff --git a/code/modules/hydroponics/grown/towercap.dm b/code/modules/hydroponics/grown/towercap.dm
index 1a3db5ef03..73a2ba14f3 100644
--- a/code/modules/hydroponics/grown/towercap.dm
+++ b/code/modules/hydroponics/grown/towercap.dm
@@ -161,6 +161,9 @@
/obj/structure/bonfire/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(burning)
to_chat(user, "
")
return
@@ -173,8 +176,6 @@
new /obj/item/stack/rods(loc, 1)
qdel(src)
return
- ..()
-
/obj/structure/bonfire/proc/CheckOxygen()
if(isopenturf(loc))
diff --git a/code/modules/hydroponics/hydroitemdefines.dm b/code/modules/hydroponics/hydroitemdefines.dm
index c471ba8bb1..1c3509fa4e 100644
--- a/code/modules/hydroponics/hydroitemdefines.dm
+++ b/code/modules/hydroponics/hydroitemdefines.dm
@@ -131,7 +131,7 @@
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_attackby(atom/A, mob/living/user, params)
+/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
diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm
index 2bcf03c595..c3d1b725b8 100644
--- a/code/modules/hydroponics/hydroponics.dm
+++ b/code/modules/hydroponics/hydroponics.dm
@@ -847,6 +847,9 @@
return ..()
/obj/machinery/hydroponics/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(issilicon(user)) //How does AI know what plant is?
return
if(harvest)
diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm
index b79d0652aa..9c1cbb4a11 100644
--- a/code/modules/hydroponics/seed_extractor.dm
+++ b/code/modules/hydroponics/seed_extractor.dm
@@ -119,13 +119,9 @@
src.potency = poten
src.amount = am
-/obj/machinery/seed_extractor/attack_hand(mob/user)
- user.set_machine(src)
- interact(user)
-
-/obj/machinery/seed_extractor/interact(mob/user)
+/obj/machinery/seed_extractor/ui_interact(mob/user)
if (stat)
- return 0
+ return FALSE
var/dat = "
"
diff --git a/code/modules/integrated_electronics/core/assemblies.dm b/code/modules/integrated_electronics/core/assemblies.dm
index 07be1eef78..35c1aff8bf 100644
--- a/code/modules/integrated_electronics/core/assemblies.dm
+++ b/code/modules/integrated_electronics/core/assemblies.dm
@@ -107,8 +107,11 @@
if(!draw_power(IC.power_draw_idle))
IC.power_fail()
-
/obj/item/device/electronic_assembly/interact(mob/user)
+ ui_interact(user)
+
+/obj/item/device/electronic_assembly/ui_interact(mob/user)
+ . = ..()
if(!check_interactivity(user))
return
diff --git a/code/modules/integrated_electronics/core/integrated_circuit.dm b/code/modules/integrated_electronics/core/integrated_circuit.dm
index 1b99b00765..2f309956f9 100644
--- a/code/modules/integrated_electronics/core/integrated_circuit.dm
+++ b/code/modules/integrated_electronics/core/integrated_circuit.dm
@@ -118,6 +118,10 @@ a creative player the means to solve many problems. Circuits are held inside an
displayed_name = input
/obj/item/integrated_circuit/interact(mob/user)
+ ui_interact(user)
+
+/obj/item/integrated_circuit/ui_interact(mob/user)
+ . = ..()
if(!check_interactivity(user))
return
diff --git a/code/modules/integrated_electronics/core/special_pins/list_pin.dm b/code/modules/integrated_electronics/core/special_pins/list_pin.dm
index 8a6f80ea63..e70927fbdd 100644
--- a/code/modules/integrated_electronics/core/special_pins/list_pin.dm
+++ b/code/modules/integrated_electronics/core/special_pins/list_pin.dm
@@ -7,6 +7,7 @@
interact(user)
/datum/integrated_io/lists/proc/interact(mob/user)
+ . = ..()
var/list/my_list = data
var/t = "
"
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 78219629d3..799cc91ba9 100755
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -69,7 +69,7 @@ Head of Personnel
minimal_player_age = 10
exp_requirements = 180
exp_type = EXP_TYPE_CREW
-//exp_type_department = EXP_TYPE_SUPPLY - CITADEL CHANGE
+ exp_type_department = EXP_TYPE_SUPPLY
antag_rep = 20
outfit = /datum/outfit/job/hop
diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm
index 25b091d2c7..de7edc69b1 100644
--- a/code/modules/library/lib_items.dm
+++ b/code/modules/library/lib_items.dm
@@ -117,6 +117,9 @@
/obj/structure/bookcase/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(contents.len)
var/obj/item/book/choice = input("Which book would you like to remove from the shelf?") as null|obj in contents
if(choice)
diff --git a/code/modules/library/lib_machines.dm b/code/modules/library/lib_machines.dm
index 269c6ad13f..9a1fa4ae50 100644
--- a/code/modules/library/lib_machines.dm
+++ b/code/modules/library/lib_machines.dm
@@ -28,13 +28,8 @@
var/SQLquery
clockwork = TRUE //it'd look weird
-/obj/machinery/computer/libraryconsole/attack_hand(mob/user)
- if(..())
- return
- interact(user)
-
-/obj/machinery/computer/libraryconsole/interact(mob/user)
- user.set_machine(src)
+/obj/machinery/computer/libraryconsole/ui_interact(mob/user)
+ . = ..()
var/dat = "" //
switch(screenstate)
if(0)
@@ -201,8 +196,8 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
circuit.name = "Book Inventory Management Console (Machine Board)"
circuit.build_path = /obj/machinery/computer/libraryconsole/bookmanagement
-/obj/machinery/computer/libraryconsole/bookmanagement/interact(mob/user)
- user.set_machine(src)
+/obj/machinery/computer/libraryconsole/bookmanagement/ui_interact(mob/user)
+ . = ..()
var/dat = "" //
switch(screenstate)
if(0)
@@ -511,6 +506,9 @@ GLOBAL_LIST(cachedbooks) // List of our cached book datums
return ..()
/obj/machinery/libraryscanner/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
usr.set_machine(src)
var/dat = "" //
if(cache)
diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm
index 45a203b401..b9dbb42d28 100644
--- a/code/modules/mapping/map_template.dm
+++ b/code/modules/mapping/map_template.dm
@@ -65,6 +65,8 @@
initTemplateBounds(bounds)
log_game("Z-level [name] loaded at at [x],[y],[world.maxz]")
+ return level
+
/datum/map_template/proc/load(turf/T, centered = FALSE)
if(centered)
T = locate(T.x - round(width/2) , T.y - round(height/2) , T.z)
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
index 174fada464..3afbb42420 100644
--- a/code/modules/mining/abandoned_crates.dm
+++ b/code/modules/mining/abandoned_crates.dm
@@ -150,6 +150,7 @@
if(100)
new /obj/item/clothing/head/bearpelt(src)
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/structure/closet/crate/secure/loot/attack_hand(mob/user)
if(locked)
to_chat(user, "
")
@@ -182,7 +183,7 @@
/obj/structure/closet/crate/secure/loot/AltClick(mob/living/user)
if(!user.canUseTopic(src, BE_CLOSE))
return
- attack_hand(user) //this helps you not blow up so easily by overriding unlocking which results in an immediate boom.
+ return attack_hand(user) //this helps you not blow up so easily by overriding unlocking which results in an immediate boom.
/obj/structure/closet/crate/secure/loot/attackby(obj/item/W, mob/user)
if(locked)
diff --git a/code/modules/mining/aux_base.dm b/code/modules/mining/aux_base.dm
index fcb8dc9d1d..ccd9784448 100644
--- a/code/modules/mining/aux_base.dm
+++ b/code/modules/mining/aux_base.dm
@@ -31,11 +31,8 @@ interface with the mining shuttle at the landing site if a mobile beacon is also
. = ..()
locator = new(src)
-/obj/machinery/computer/auxillary_base/attack_hand(mob/user)
- if(..(user))
- return
- add_fingerprint(usr)
-
+/obj/machinery/computer/auxillary_base/ui_interact(mob/user)
+ . = ..()
var/list/options = params2list(possible_destinations)
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
var/dat = "[is_station_level(z) ? "Docking clamps engaged. Standing by." : "Mining Shuttle Uplink: [M ? M.getStatusText() : "*OFFLINE*"]"]
"
@@ -280,6 +277,9 @@ obj/docking_port/stationary/public_mining_dock
var/console_range = 15 //Wifi range of the beacon to find the aux base console
/obj/structure/mining_shuttle_beacon/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(anchored)
to_chat(user, "
")
return
diff --git a/code/modules/mining/equipment/marker_beacons.dm b/code/modules/mining/equipment/marker_beacons.dm
index b1a4d522de..c735c9d637 100644
--- a/code/modules/mining/equipment/marker_beacons.dm
+++ b/code/modules/mining/equipment/marker_beacons.dm
@@ -103,6 +103,9 @@ GLOBAL_LIST_INIT(marker_beacon_colors, list(
set_light(light_range, light_power, GLOB.marker_beacon_colors[picked_color])
/obj/structure/marker_beacon/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
to_chat(user, "
")
if(do_after(user, remove_speed, target = src))
var/obj/item/stack/marker_beacon/M = new(loc)
diff --git a/code/modules/mining/equipment/resonator.dm b/code/modules/mining/equipment/resonator.dm
index ebc4816155..57efc0f7f5 100644
--- a/code/modules/mining/equipment/resonator.dm
+++ b/code/modules/mining/equipment/resonator.dm
@@ -42,7 +42,7 @@
new /obj/effect/temp_visual/resonance(T, user, src, burst_time)
user.changeNext_move(CLICK_CD_MELEE)
-/obj/item/resonator/pre_attackby(atom/target, mob/user, params)
+/obj/item/resonator/pre_attack(atom/target, mob/user, params)
if(check_allowed_items(target, 1))
CreateResonance(target, user)
return TRUE
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index 7ff07d1637..e828d74a11 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -150,6 +150,9 @@
return TRUE
/obj/item/device/gps/computer/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
attack_self(user)
//Bed
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index 78417a56d1..a5b69b1856 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -150,6 +150,9 @@
anchored = TRUE
/obj/machinery/mineral/labor_points_checker/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
user.examinate(src)
/obj/machinery/mineral/labor_points_checker/attackby(obj/item/I, mob/user, params)
diff --git a/code/modules/mining/lavaland/ash_flora.dm b/code/modules/mining/lavaland/ash_flora.dm
index be12f87fe8..988c224279 100644
--- a/code/modules/mining/lavaland/ash_flora.dm
+++ b/code/modules/mining/lavaland/ash_flora.dm
@@ -63,12 +63,13 @@
return ..()
/obj/structure/flora/ash/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(!harvested && !needs_sharp_harvest)
user.visible_message("
")
if(do_after(user, harvest_time, target = src))
harvest(user)
- else
- ..()
/obj/structure/flora/ash/tall_shroom //exists only so that the spawning check doesn't allow these spawning near other things
regrowth_time_low = 4200
diff --git a/code/modules/mining/lavaland/ruins/gym.dm b/code/modules/mining/lavaland/ruins/gym.dm
index a10735f6bb..634c2df859 100644
--- a/code/modules/mining/lavaland/ruins/gym.dm
+++ b/code/modules/mining/lavaland/ruins/gym.dm
@@ -8,10 +8,15 @@
var/list/hit_sounds = list('sound/weapons/genhit1.ogg', 'sound/weapons/genhit2.ogg', 'sound/weapons/genhit3.ogg',\
'sound/weapons/punch1.ogg', 'sound/weapons/punch2.ogg', 'sound/weapons/punch3.ogg', 'sound/weapons/punch4.ogg')
-/obj/structure/punching_bag/attack_hand(mob/living/user)
+/obj/structure/punching_bag/attack_hand(mob/user as mob)
+ . = ..()
+ if(.)
+ return
flick("[icon_state]2", src)
- playsound(src.loc, pick(src.hit_sounds), 25, 1, -1)
- user.apply_status_effect(STATUS_EFFECT_EXERCISED)
+ playsound(loc, pick(hit_sounds), 25, 1, -1)
+ if(isliving(user))
+ var/mob/living/L = user
+ L.apply_status_effect(STATUS_EFFECT_EXERCISED)
/obj/structure/stacklifter
name = "Weight Machine"
@@ -22,6 +27,9 @@
anchored = TRUE
/obj/structure/stacklifter/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
if(obj_flags & IN_USE)
to_chat(user, "It's already in use - wait a bit.")
return
@@ -61,6 +69,9 @@
anchored = TRUE
/obj/structure/weightlifter/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
if(obj_flags & IN_USE)
to_chat(user, "It's already in use - wait a bit.")
return
diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm
index e991fc65aa..bb5347a152 100644
--- a/code/modules/mining/machine_processing.dm
+++ b/code/modules/mining/machine_processing.dm
@@ -30,8 +30,8 @@
else
return INITIALIZE_HINT_QDEL
-/obj/machinery/mineral/processing_unit_console/attack_hand(mob/user)
-
+/obj/machinery/mineral/processing_unit_console/ui_interact(mob/user)
+ . = ..()
if(!machine)
return
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index a9cec0a01b..b3b7bd29d3 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -13,6 +13,7 @@
req_access = list(ACCESS_MINERAL_STOREROOM)
speed_process = TRUE
circuit = /obj/item/circuitboard/machine/ore_redemption
+ layer = BELOW_OBJ_LAYER
var/req_access_reclaim = ACCESS_MINING_STATION
var/obj/item/card/id/inserted_id
var/points = 0
@@ -189,11 +190,6 @@
materials.retrieve_all()
..()
-/obj/machinery/mineral/ore_redemption/attack_hand(mob/user)
- if(..())
- return
- interact(user)
-
/obj/machinery/mineral/ore_redemption/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
diff --git a/code/modules/mining/machine_stacking.dm b/code/modules/mining/machine_stacking.dm
index 44f13d0a4f..e658f69395 100644
--- a/code/modules/mining/machine_stacking.dm
+++ b/code/modules/mining/machine_stacking.dm
@@ -19,8 +19,8 @@
else
qdel(src)
-/obj/machinery/mineral/stacking_unit_console/attack_hand(mob/user)
-
+/obj/machinery/mineral/stacking_unit_console/ui_interact(mob/user)
+ . = ..()
var/obj/item/stack/sheet/s
var/dat
@@ -35,8 +35,6 @@
user << browse(dat, "window=console_stacking_machine")
- return
-
/obj/machinery/mineral/stacking_unit_console/Topic(href, href_list)
if(..())
return
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index e06e4d844a..1fd1ff3e38 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -80,14 +80,9 @@
icon_state = initial(icon_state)
else
icon_state = "[initial(icon_state)]-off"
- return
-/obj/machinery/mineral/equipment_vendor/attack_hand(mob/user)
- if(..())
- return
- interact(user)
-
-/obj/machinery/mineral/equipment_vendor/interact(mob/user)
+/obj/machinery/mineral/equipment_vendor/ui_interact(mob/user)
+ . = ..()
var/dat
dat +="
"
if(istype(inserted_id))
@@ -283,8 +278,7 @@
name = "mining conscription kit"
desc = "A kit containing everything a crewmember needs to support a shaft miner in the field."
-/obj/item/storage/backpack/duffelbag/mining_conscript/Initialize()
- . = ..()
+/obj/item/storage/backpack/duffelbag/mining_conscript/PopulateContents()
new /obj/item/pickaxe/mini(src)
new /obj/item/clothing/glasses/meson(src)
new /obj/item/device/t_scanner/adv_mining_scanner/lesser(src)
diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm
index ba4850eb47..d188ce26aa 100644
--- a/code/modules/mining/mine_items.dm
+++ b/code/modules/mining/mine_items.dm
@@ -74,12 +74,13 @@
no_destination_swap = 1
var/global/list/dumb_rev_heads = list()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/machinery/computer/shuttle/mining/attack_hand(mob/user)
if(is_station_level(user.z) && user.mind && is_head_revolutionary(user) && !(user.mind in dumb_rev_heads))
to_chat(user, "
You get a feeling that leaving the station might be a REALLY dumb idea...")
dumb_rev_heads += user.mind
return
- ..()
+ . = ..()
/**********************Mining car (Crate like thing, not the rail car)**************************/
diff --git a/code/modules/mining/minebot.dm b/code/modules/mining/minebot.dm
index 51358c6818..c2fe407442 100644
--- a/code/modules/mining/minebot.dm
+++ b/code/modules/mining/minebot.dm
@@ -115,6 +115,9 @@
..()
/mob/living/simple_animal/hostile/mining_drone/attack_hand(mob/living/carbon/human/M)
+ . = ..()
+ if(.)
+ return
if(M.a_intent == INTENT_HELP)
toggle_mode()
switch(mode)
@@ -123,7 +126,6 @@
if(MINEDRONE_ATTACK)
to_chat(M, "
[src] has been set to attack hostile wildlife.")
return
- ..()
/mob/living/simple_animal/hostile/mining_drone/CanPass(atom/movable/O)
if(istype(O, /obj/item/projectile/kinetic))
@@ -139,7 +141,7 @@
/mob/living/simple_animal/hostile/mining_drone/proc/SetCollectBehavior()
mode = MINEDRONE_COLLECT
- idle_vision_range = 9
+ vision_range = 9
search_objects = 2
wander = TRUE
ranged = FALSE
@@ -150,7 +152,7 @@
/mob/living/simple_animal/hostile/mining_drone/proc/SetOffenseBehavior()
mode = MINEDRONE_ATTACK
- idle_vision_range = 7
+ vision_range = 7
search_objects = 0
wander = FALSE
ranged = TRUE
diff --git a/code/modules/mining/mint.dm b/code/modules/mining/mint.dm
index ca21456163..ec4c9bd714 100644
--- a/code/modules/mining/mint.dm
+++ b/code/modules/mining/mint.dm
@@ -28,6 +28,9 @@
materials.insert_stack(O, O.amount)
/obj/machinery/mineral/mint/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
var/dat = "
Coin Press"
GET_COMPONENT(materials, /datum/component/material_container)
diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm
index a9c660e554..a12d56fbbb 100644
--- a/code/modules/mining/satchel_ore_boxdm.dm
+++ b/code/modules/mining/satchel_ore_boxdm.dm
@@ -34,6 +34,9 @@
. = ..()
/obj/structure/ore_box/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(Adjacent(user))
show_contents(user)
diff --git a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
index 36ed5ec884..6c42e687a9 100644
--- a/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
+++ b/code/modules/mob/living/carbon/alien/humanoid/humanoid_defense.dm
@@ -62,7 +62,7 @@
-/mob/living/carbon/alien/humanoid/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+/mob/living/carbon/alien/humanoid/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect && !visual_effect_icon)
visual_effect_icon = ATTACK_EFFECT_CLAW
..()
diff --git a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
index 62c00ca8ed..c3cee567a2 100644
--- a/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
+++ b/code/modules/mob/living/carbon/alien/larva/larva_defense.dm
@@ -25,7 +25,7 @@
new /datum/forced_movement(src, get_step_away(user,src, 30), 1)
return 1
-/mob/living/carbon/alien/larva/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+/mob/living/carbon/alien/larva/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!no_effect && !visual_effect_icon)
visual_effect_icon = ATTACK_EFFECT_BITE
..()
diff --git a/code/modules/mob/living/carbon/alien/special/facehugger.dm b/code/modules/mob/living/carbon/alien/special/facehugger.dm
index 20036f2fb2..a5368fc7c0 100644
--- a/code/modules/mob/living/carbon/alien/special/facehugger.dm
+++ b/code/modules/mob/living/carbon/alien/special/facehugger.dm
@@ -53,14 +53,14 @@
return O.attack_obj(src, user)
/obj/item/clothing/mask/facehugger/attack_alien(mob/user) //can be picked up by aliens
- attack_hand(user)
- return
+ return attack_hand(user)
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/clothing/mask/facehugger/attack_hand(mob/user)
if((stat == CONSCIOUS && !sterile) && !isalien(user))
if(Leap(user))
return
- ..()
+ . = ..()
/obj/item/clothing/mask/facehugger/attack(mob/living/M, mob/user)
..()
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index e0c8f04030..89a197104f 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -148,11 +148,11 @@
if(istype(target, /obj/screen))
return
-//CIT CHANGES - makes it impossible to throw while in stamina softcrit
- if(staminaloss >= STAMINA_SOFTCRIT)
+ //CIT CHANGES - makes it impossible to throw while in stamina softcrit
+ if(getStaminaLoss())
to_chat(src, "
You're too exhausted.")
return
-//END OF CIT CHANGES
+ //END OF CIT CHANGES
var/atom/movable/thrown_thing
var/obj/item/I = src.get_active_held_item()
@@ -421,7 +421,7 @@
if(modifier < 100)
dropItemToGround(I)
//END OF CIT CHANGES
-
+
switch(rand(1,100)+modifier) //91-100=Nothing special happens
if(-INFINITY to 0) //attack yourself
I.attack(src,src)
@@ -521,11 +521,14 @@
return
var/total_burn = 0
var/total_brute = 0
+ var/total_stamina = 0
for(var/X in bodyparts) //hardcoded to streamline things a bit
var/obj/item/bodypart/BP = X
total_brute += BP.brute_dam
total_burn += BP.burn_dam
+ total_stamina += BP.stamina_dam
health = maxHealth - getOxyLoss() - getToxLoss() - getCloneLoss() - total_burn - total_brute
+ staminaloss = total_stamina
update_stat()
if(((maxHealth - total_burn) < HEALTH_THRESHOLD_DEAD) && stat == DEAD )
become_husk("burn")
@@ -856,6 +859,16 @@
O.held_index = r_arm_index_next //2, 4, 6, 8...
hand_bodyparts += O
+/mob/living/carbon/do_after_coefficent()
+ . = ..()
+ GET_COMPONENT_FROM(mood, /datum/component/mood, src) //Currently, only carbons or higher use mood, move this once that changes.
+ if(mood)
+ switch(mood.sanity) //Alters do_after delay based on how sane you are
+ if(SANITY_INSANE to SANITY_DISTURBED)
+ . *= 1.25
+ if(SANITY_NEUTRAL to SANITY_GREAT)
+ . *= 0.90
+
/mob/living/carbon/proc/create_internal_organs()
for(var/X in internal_organs)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 54ad7da184..fea154a5c0 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -78,7 +78,7 @@
I.SendSignal(COMSIG_ITEM_ATTACK_ZONE, src, user, affecting)
send_item_attack_message(I, user, affecting.name)
if(I.force)
- //CIT CHANGES START HERE - combatmode and resting checks
+ //CIT CHANGES START HERE - combatmode and resting checks
var/totitemdamage = I.force
if(iscarbon(user))
var/mob/living/carbon/tempcarb = user
@@ -120,6 +120,7 @@
/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)
for(var/thing in diseases)
@@ -270,11 +271,18 @@
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")
M.visible_message("
[M] gives [src] a pat on the head to make [p_them()] feel better!", \
"
You give [src] a pat on the head to make [p_them()] feel better!")
- if(dna && dna.species && ((("tail_lizard" || "tail_human" || "mam_tail") in dna.species.mutant_bodyparts && (dna.features["tail_lizard"] || dna.features["tail_human"] || dna.features["mam_tail"])!= "None")))
+ if(dna && dna.species && ("tail_lizard" in dna.species.mutant_bodyparts) && (dna.features["tail_lizard"])!= "None")
emote("wag") //lewd
+ else if(dna && dna.species && ("tail_human" in dna.species.mutant_bodyparts) && (dna.features["tail_human"])!= "None")
+ emote("wag")
+ else if(dna && dna.species && ("mam_tail" in dna.species.mutant_bodyparts) && (dna.features["mam_tail"])!= "None")
+ emote("wag")
+ SendSignal(COMSIG_ADD_MOOD_EVENT, "headpat", /datum/mood_event/headpat)
+
else
M.visible_message("
[M] hugs [src] to make [p_them()] feel better!", \
"
You hug [src] to make [p_them()] feel better!")
diff --git a/code/modules/mob/living/carbon/damage_procs.dm b/code/modules/mob/living/carbon/damage_procs.dm
index 715b4a2ed9..88a70228db 100644
--- a/code/modules/mob/living/carbon/damage_procs.dm
+++ b/code/modules/mob/living/carbon/damage_procs.dm
@@ -35,13 +35,17 @@
if(CLONE)
adjustCloneLoss(damage * hit_percent)
if(STAMINA)
- adjustStaminaLoss(damage * hit_percent)
+ if(BP)
+ if(BP.receive_damage(0, 0, damage * hit_percent))
+ update_damage_overlays()
+ else
+ adjustStaminaLoss(damage * hit_percent)
if(BRAIN)
adjustBrainLoss(damage * hit_percent)
//citadel code
if(AROUSAL)
adjustArousalLoss(damage * hit_percent)
- return 1
+ return TRUE
//These procs fetch a cumulative total damage from all bodyparts
@@ -64,21 +68,20 @@
if(!forced && (status_flags & GODMODE))
return FALSE
if(amount > 0)
- take_overall_damage(amount, 0, updating_health)
+ take_overall_damage(amount, 0, 0, updating_health)
else
- heal_overall_damage(-amount, 0, 0, 1, updating_health)
+ heal_overall_damage(abs(amount), 0, 0, FALSE, TRUE, updating_health)
return amount
/mob/living/carbon/adjustFireLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && (status_flags & GODMODE))
return FALSE
if(amount > 0)
- take_overall_damage(0, amount, updating_health)
+ take_overall_damage(0, amount, 0, updating_health)
else
- heal_overall_damage(0, -amount, 0, 1, updating_health)
+ heal_overall_damage(0, abs(amount), 0, FALSE, TRUE, updating_health)
return amount
-
/mob/living/carbon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE)
if(!forced && has_trait(TRAIT_TOXINLOVER)) //damage becomes healing and healing becomes damage
amount = -amount
@@ -88,14 +91,36 @@
blood_volume -= amount
return ..()
+/mob/living/carbon/getStaminaLoss()
+ . = 0
+ for(var/X in bodyparts)
+ var/obj/item/bodypart/BP = X
+ . += BP.stamina_dam
+
+/mob/living/carbon/adjustStaminaLoss(amount, updating_health = TRUE, forced = FALSE)
+ if(!forced && (status_flags & GODMODE))
+ return FALSE
+ if(amount > 0)
+ take_overall_damage(0, 0, amount, updating_health)
+ else
+ heal_overall_damage(0, 0, abs(amount), FALSE, FALSE, updating_health)
+ return amount
+
+/mob/living/carbon/setStaminaLoss(amount, updating = TRUE, forced = FALSE)
+ var/current = getStaminaLoss()
+ var/diff = amount - current
+ if(!diff)
+ return
+ adjustStaminaLoss(diff, updating, forced)
+
////////////////////////////////////////////
//Returns a list of damaged bodyparts
-/mob/living/carbon/proc/get_damaged_bodyparts(brute, burn)
+/mob/living/carbon/proc/get_damaged_bodyparts(brute = FALSE, burn = FALSE, stamina = FALSE)
var/list/obj/item/bodypart/parts = list()
for(var/X in bodyparts)
var/obj/item/bodypart/BP = X
- if((brute && BP.brute_dam) || (burn && BP.burn_dam))
+ if((brute && BP.brute_dam) || (burn && BP.burn_dam) || (stamina && BP.stamina_dam))
parts += BP
return parts
@@ -111,90 +136,79 @@
//Heals ONE bodypart randomly selected from damaged ones.
//It automatically updates damage overlays if necessary
//It automatically updates health status
-/mob/living/carbon/heal_bodypart_damage(brute, burn, only_robotic = 0, only_organic = 1)
+/mob/living/carbon/heal_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE, only_robotic = FALSE, only_organic = TRUE)
var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn)
if(!parts.len)
return
var/obj/item/bodypart/picked = pick(parts)
- if(picked.heal_damage(brute, burn, only_robotic, only_organic))
+ if(picked.heal_damage(brute, burn, stamina, only_robotic, only_organic))
update_damage_overlays()
//Damages ONE bodypart randomly selected from damagable ones.
//It automatically updates damage overlays if necessary
//It automatically updates health status
-/mob/living/carbon/take_bodypart_damage(brute, burn)
+/mob/living/carbon/take_bodypart_damage(brute = 0, burn = 0, stamina = 0)
var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
if(!parts.len)
return
var/obj/item/bodypart/picked = pick(parts)
- if(picked.receive_damage(brute,burn))
+ if(picked.receive_damage(brute, burn, stamina))
update_damage_overlays()
-
//Heal MANY bodyparts, in random order
-/mob/living/carbon/heal_overall_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1)
- var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute,burn)
+/mob/living/carbon/heal_overall_damage(brute = 0, burn = 0, stamina = 0, only_robotic = FALSE, only_organic = TRUE, updating_health = TRUE)
+ var/list/obj/item/bodypart/parts = get_damaged_bodyparts(brute, burn, stamina)
- var/update = 0
- while(parts.len && (brute>0 || burn>0) )
+ var/update = NONE
+ while(parts.len && (brute > 0 || burn > 0 || stamina > 0))
var/obj/item/bodypart/picked = pick(parts)
var/brute_was = picked.brute_dam
var/burn_was = picked.burn_dam
+ var/stamina_was = picked.stamina_dam
- update |= picked.heal_damage(brute,burn, only_robotic, only_organic, 0)
+ update |= picked.heal_damage(brute, burn, stamina, only_robotic, only_organic, FALSE)
- brute -= (brute_was-picked.brute_dam)
- burn -= (burn_was-picked.burn_dam)
+ brute -= (brute_was - picked.brute_dam)
+ burn -= (burn_was - picked.burn_dam)
+ stamina -= (stamina_was - picked.stamina_dam)
parts -= picked
if(updating_health)
updatehealth()
if(update)
update_damage_overlays()
+ update_stamina() //CIT CHANGE - makes sure update_stamina() always gets called after a health update
// damage MANY bodyparts, in random order
-/mob/living/carbon/take_overall_damage(brute, burn, updating_health = 1)
+/mob/living/carbon/take_overall_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
if(status_flags & GODMODE)
return //godmode
var/list/obj/item/bodypart/parts = get_damageable_bodyparts()
var/update = 0
- while(parts.len && (brute>0 || burn>0) )
+ while(parts.len && (brute > 0 || burn > 0 || stamina > 0))
var/obj/item/bodypart/picked = pick(parts)
var/brute_per_part = round(brute/parts.len, 0.01)
var/burn_per_part = round(burn/parts.len, 0.01)
+ var/stamina_per_part = round(stamina/parts.len, 0.01)
var/brute_was = picked.brute_dam
var/burn_was = picked.burn_dam
+ var/stamina_was = picked.stamina_dam
- update |= picked.receive_damage(brute_per_part,burn_per_part, 0)
+ update |= picked.receive_damage(brute_per_part, burn_per_part, stamina_per_part, FALSE)
brute -= (picked.brute_dam - brute_was)
burn -= (picked.burn_dam - burn_was)
+ stamina -= (picked.stamina_dam - stamina_was)
parts -= picked
if(updating_health)
updatehealth()
if(update)
update_damage_overlays()
-
-
-
-/mob/living/carbon/adjustStaminaLoss(amount, updating_stamina = 1)
- if(status_flags & GODMODE)
- return 0
- staminaloss = CLAMP(staminaloss + amount, 0, maxHealth*2)
- //if(updating_stamina) CIT CHANGE - makes staminaloss changes always call update_stamina
- update_stamina()
-
-
-/mob/living/carbon/setStaminaLoss(amount, updating_stamina = 1)
- if(status_flags & GODMODE)
- return 0
- staminaloss = amount
- //if(updating_stamina) CIT CHANGE - makes staminaloss changes always call update_stamina
update_stamina()
/mob/living/carbon/getBrainLoss()
@@ -237,3 +251,4 @@
if(B)
var/adjusted_amount = amount - B.get_brain_damage()
B.adjust_brain_damage(adjusted_amount, null)
+
diff --git a/code/modules/mob/living/carbon/emote.dm b/code/modules/mob/living/carbon/emote.dm
index 30fa676500..f224384399 100644
--- a/code/modules/mob/living/carbon/emote.dm
+++ b/code/modules/mob/living/carbon/emote.dm
@@ -23,6 +23,19 @@
restraint_check = TRUE
emote_type = EMOTE_AUDIBLE
+/datum/emote/living/carbon/clap/run_emote(mob/living/user, params)
+ . = ..()
+ if (.)
+ if (ishuman(user))
+ // Need hands to clap
+ if (!user.get_bodypart("l_arm") || !user.get_bodypart("r_arm"))
+ return
+ var/clap = pick('sound/misc/clap1.ogg',
+ 'sound/misc/clap2.ogg',
+ 'sound/misc/clap3.ogg',
+ 'sound/misc/clap4.ogg')
+ playsound(user, clap, 50, 1, -1)
+
/datum/emote/living/carbon/gnarl
key = "gnarl"
key_third_person = "gnarls"
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index fe9bf5ef4a..cdff36a871 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -901,6 +901,10 @@
else
visible_message("
[M] fails to climb onto [src]!")
+/mob/living/carbon/human/do_after_coefficent()
+ . = ..()
+ . *= physiology.do_after_speed
+
/mob/living/carbon/human/species
var/race = null
diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm
index 253a6ed641..e47e7e1b63 100644
--- a/code/modules/mob/living/carbon/human/human_defense.dm
+++ b/code/modules/mob/living/carbon/human/human_defense.dm
@@ -698,8 +698,8 @@
if(bleed_rate)
to_chat(src, "
You are bleeding!")
- if(staminaloss)
- if(staminaloss > 30)
+ if(getStaminaLoss())
+ if(getStaminaLoss() > 30)
to_chat(src, "
You're completely exhausted.")
else
to_chat(src, "
You feel fatigued.")
diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm
index ae78e1e585..e40327c07e 100644
--- a/code/modules/mob/living/carbon/human/human_movement.dm
+++ b/code/modules/mob/living/carbon/human/human_movement.dm
@@ -6,7 +6,9 @@
. += ..() + config_human_delay + dna.species.movement_delay(src)
/mob/living/carbon/human/slip(knockdown_amount, obj/O, lube)
- if(isobj(shoes) && (shoes.flags_1&NOSLIP_1) && !(lube&GALOSHES_DONT_HELP))
+ if(has_trait(TRAIT_NOSLIPALL))
+ return 0
+ if((isobj(shoes) && (shoes.flags_1&NOSLIP_1)) || has_trait(TRAIT_NOSLIPWATER) && !(lube&GALOSHES_DONT_HELP))
return 0
return ..()
diff --git a/code/modules/mob/living/carbon/human/physiology.dm b/code/modules/mob/living/carbon/human/physiology.dm
index 3d1cae8f41..ac9e9fe219 100644
--- a/code/modules/mob/living/carbon/human/physiology.dm
+++ b/code/modules/mob/living/carbon/human/physiology.dm
@@ -1,27 +1,31 @@
//Stores several modifiers in a way that isn't cleared by changing species
/datum/physiology
- var/brute_mod = 1 // % of brute damage taken from all sources
- var/burn_mod = 1 // % of burn damage taken from all sources
- var/tox_mod = 1 // % of toxin damage taken from all sources
- var/oxy_mod = 1 // % of oxygen damage taken from all sources
- var/clone_mod = 1 // % of clone damage taken from all sources
- var/stamina_mod = 1 // % of stamina damage taken from all sources
- var/brain_mod = 1 // % of brain damage taken from all sources
+ var/brute_mod = 1 // % of brute damage taken from all sources
+ var/burn_mod = 1 // % of burn damage taken from all sources
+ var/tox_mod = 1 // % of toxin damage taken from all sources
+ var/oxy_mod = 1 // % of oxygen damage taken from all sources
+ var/clone_mod = 1 // % of clone damage taken from all sources
+ var/stamina_mod = 1 // % of stamina damage taken from all sources
+ var/brain_mod = 1 // % of brain damage taken from all sources
- var/pressure_mod = 1// % of brute damage taken from low or high pressure (stacks with brute_mod)
- var/heat_mod = 1 // % of burn damage taken from heat (stacks with burn_mod)
- var/cold_mod = 1 // % of burn damage taken from cold (stacks with burn_mod)
+ var/pressure_mod = 1 // % of brute damage taken from low or high pressure (stacks with brute_mod)
+ var/heat_mod = 1 // % of burn damage taken from heat (stacks with burn_mod)
+ var/cold_mod = 1 // % of burn damage taken from cold (stacks with burn_mod)
var/damage_resistance = 0 // %damage reduction from all sources
- var/siemens_coeff = 1 // resistance to shocks
+ var/siemens_coeff = 1 // resistance to shocks
- var/stun_mod = 1 // % stun modifier
- var/bleed_mod = 1 // % bleeding modifier
- var/datum/armor/armor // internal armor datum
+ var/stun_mod = 1 // % stun modifier
+ var/bleed_mod = 1 // % bleeding modifier
+ var/datum/armor/armor // internal armor datum
- var/speed_mod = 0 //tick modifier for each step. Positive is slower, negative is faster.
+ var/speed_mod = 0 //tick modifier for each step. Positive is slower, negative is faster.
+
+ var/hunger_mod = 1 //% of hunger rate taken per tick.
+
+ var/do_after_speed = 1 //Speed mod for do_after. Lower is better. If temporarily adjusting, please only modify using *= and /=, so you don't interrupt other calculations.
/datum/physiology/New()
armor = new
diff --git a/code/modules/mob/living/carbon/human/species.dm b/code/modules/mob/living/carbon/human/species.dm
index e7bb35d85e..e77745cd90 100644
--- a/code/modules/mob/living/carbon/human/species.dm
+++ b/code/modules/mob/living/carbon/human/species.dm
@@ -1386,7 +1386,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if((target.stat != DEAD) && damage >= user.dna.species.punchstunthreshold)
target.visible_message("
[user] has knocked [target] down!", \
"
[user] has knocked [target] down!", null, COMBAT_MESSAGE_RANGE)
- target.apply_effect(80, KNOCKDOWN, armor_block)
+ target.apply_effect(80, EFFECT_KNOCKDOWN, armor_block)
target.forcesay(GLOB.hit_appends)
else if(target.lying)
target.forcesay(GLOB.hit_appends)
@@ -1427,7 +1427,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
playsound(target, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
target.visible_message("
[user] has pushed [target]!",
"
[user] has pushed [target]!", null, COMBAT_MESSAGE_RANGE)
- target.apply_effect(40, KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!"))
+ target.apply_effect(40, EFFECT_KNOCKDOWN, target.run_armor_check(affecting, "melee", "Your armor prevents your fall!", "Your armor softens your fall!"))
target.forcesay(GLOB.hit_appends)
add_logs(user, target, "disarmed", " pushing them to the ground")
return*/
@@ -1588,7 +1588,7 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(prob(I.force))
H.visible_message("
[H] has been knocked down!", \
"
[H] has been knocked down!")
- H.apply_effect(60, KNOCKDOWN, armor_block)
+ H.apply_effect(60, EFFECT_KNOCKDOWN, armor_block)
if(bloody)
if(H.wear_suit)
@@ -1640,7 +1640,11 @@ GLOBAL_LIST_EMPTY(roundstart_races)
if(CLONE)
H.adjustCloneLoss(damage * hit_percent * H.physiology.clone_mod)
if(STAMINA)
- H.adjustStaminaLoss(damage * hit_percent * H.physiology.stamina_mod)
+ if(BP)
+ if(BP.receive_damage(0, 0, damage * hit_percent * H.physiology.stamina_mod))
+ H.update_stamina()
+ else
+ H.adjustStaminaLoss(damage * hit_percent * H.physiology.stamina_mod)
if(BRAIN)
H.adjustBrainLoss(damage * hit_percent * H.physiology.brain_mod)
if(AROUSAL) //Citadel edit - arousal
diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm
index ab4e39f922..b0d01d05c1 100644
--- a/code/modules/mob/living/carbon/human/update_icons.dm
+++ b/code/modules/mob/living/carbon/human/update_icons.dm
@@ -633,3 +633,51 @@ generate/load female uniform sprites matching all previously decided variables
if(!observers.len)
observers = null
break
+
+// Only renders the head of the human
+/mob/living/carbon/human/proc/update_body_parts_head_only()
+ if (!dna)
+ return
+
+ if (!dna.species)
+ return
+
+ var/obj/item/bodypart/HD = get_bodypart("head")
+
+ if (!istype(HD))
+ return
+
+ HD.update_limb()
+
+ add_overlay(HD.get_limb_icon())
+ update_damage_overlays()
+
+ if(HD && !(has_trait(TRAIT_HUSK)))
+ // lipstick
+ if(lip_style && (LIPS in dna.species.species_traits))
+ var/mutable_appearance/lip_overlay = mutable_appearance('icons/mob/human_face.dmi', "lips_[lip_style]", -BODY_LAYER)
+ lip_overlay.color = lip_color
+ if(OFFSET_FACE in dna.species.offset_features)
+ lip_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1]
+ lip_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2]
+ add_overlay(lip_overlay)
+
+ // eyes
+ if(!(NOEYES in dna.species.species_traits))
+ var/has_eyes = getorganslot(ORGAN_SLOT_EYES)
+ var/mutable_appearance/eye_overlay
+ if(!has_eyes)
+ eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes_missing", -BODY_LAYER)
+ else
+ eye_overlay = mutable_appearance('icons/mob/human_face.dmi', "eyes", -BODY_LAYER)
+ if((EYECOLOR in dna.species.species_traits) && has_eyes)
+ eye_overlay.color = "#" + eye_color
+ if(OFFSET_FACE in dna.species.offset_features)
+ eye_overlay.pixel_x += dna.species.offset_features[OFFSET_FACE][1]
+ eye_overlay.pixel_y += dna.species.offset_features[OFFSET_FACE][2]
+ add_overlay(eye_overlay)
+
+ dna.species.handle_hair(src)
+
+ update_inv_head()
+ update_inv_wear_mask()
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/monkey/combat.dm b/code/modules/mob/living/carbon/monkey/combat.dm
index e325e9c19e..ed60456b67 100644
--- a/code/modules/mob/living/carbon/monkey/combat.dm
+++ b/code/modules/mob/living/carbon/monkey/combat.dm
@@ -119,10 +119,6 @@
cuff_resist(I)
/mob/living/carbon/monkey/proc/should_target(var/mob/living/L)
-
- if(L == src)
- return FALSE
-
if(has_trait(TRAIT_PACIFISM))
return FALSE
@@ -136,108 +132,57 @@
return FALSE
/mob/living/carbon/monkey/proc/handle_combat()
- // Don't do any AI if inside another mob (devoured)
- if (ismob(loc))
- // Really no idea what needs to be returned but everything else is TRUE
- return TRUE
-
- if(on_fire || buckled || restrained() || (resting && canmove)) //CIT CHANGE - adds (resting && canmove) to make monkey ai attempt to resist out of resting
- if(!resisting && prob(MONKEY_RESIST_PROB))
- resisting = TRUE
- walk_to(src,0)
- resist()
- else
- resisting = FALSE
-
-
- if(IsDeadOrIncap())
- return TRUE
-
- // have we been disarmed
- if(!locate(/obj/item) in held_items)
- best_force = 0
-
- if(restrained() || blacklistItems[pickupTarget] || (pickupTarget && (pickupTarget.flags_1 & NODROP_1)))
- pickupTarget = null
-
- if(!resisting && pickupTarget)
- pickupTimer++
-
- // next to target
- if(Adjacent(pickupTarget) || Adjacent(pickupTarget.loc))
- INVOKE_ASYNC(src, .proc/walk2derpless, pickupTarget.loc)
-
- // who cares about these items, i want that one!
- drop_all_held_items()
-
- // on floor
- if(isturf(pickupTarget.loc))
- equip_item(pickupTarget)
- pickupTarget = null
- pickupTimer = 0
-
- // in someones hand
- else if(ismob(pickupTarget.loc))
- var/mob/M = pickupTarget.loc
- if(!pickpocketing)
- pickpocketing = TRUE
- M.visible_message("[src] starts trying to take [pickupTarget] from [M]", "[src] tries to take [pickupTarget]!")
- INVOKE_ASYNC(src, .proc/pickpocket, M)
-
+ if(pickupTarget)
+ if(restrained() || blacklistItems[pickupTarget] || (pickupTarget.flags_1 & NODROP_1))
+ pickupTarget = null
else
- if(pickupTimer >= 8)
+ pickupTimer++
+ if(pickupTimer >= 4)
blacklistItems[pickupTarget] ++
pickupTarget = null
pickupTimer = 0
else
INVOKE_ASYNC(src, .proc/walk2derpless, pickupTarget.loc)
-
- return TRUE
-
- // nuh uh you don't pull me!
- if(pulledby && (mode != MONKEY_IDLE || prob(MONKEY_PULL_AGGRO_PROB)))
- if(Adjacent(pulledby))
- a_intent = INTENT_DISARM
- monkey_attack(pulledby)
- retaliate(pulledby)
+ if(Adjacent(pickupTarget) || Adjacent(pickupTarget.loc)) // next to target
+ drop_all_held_items() // who cares about these items, i want that one!
+ if(isturf(pickupTarget.loc)) // on floor
+ equip_item(pickupTarget)
+ pickupTarget = null
+ pickupTimer = 0
+ else if(ismob(pickupTarget.loc)) // in someones hand
+ var/mob/M = pickupTarget.loc
+ if(!pickpocketing)
+ pickpocketing = TRUE
+ M.visible_message("[src] starts trying to take [pickupTarget] from [M]", "[src] tries to take [pickupTarget]!")
+ INVOKE_ASYNC(src, .proc/pickpocket, M)
return TRUE
switch(mode)
-
if(MONKEY_IDLE) // idle
-
- var/list/around = view(src, MONKEY_ENEMY_VISION)
- bodyDisposal = locate(/obj/machinery/disposal/) in around
-
- // scan for enemies
- for(var/mob/living/L in around)
- if( should_target(L) )
- if(L.stat == CONSCIOUS)
- battle_screech()
- retaliate(L)
- return TRUE
- else if(bodyDisposal)
- target = L
- mode = MONKEY_DISPOSE
- return TRUE
+ if(enemies.len)
+ var/list/around = view(src, MONKEY_ENEMY_VISION) // scan for enemies
+ for(var/mob/living/L in around)
+ if( should_target(L) )
+ if(L.stat == CONSCIOUS)
+ battle_screech()
+ retaliate(L)
+ return TRUE
+ else
+ bodyDisposal = locate(/obj/machinery/disposal/) in around
+ if(bodyDisposal)
+ target = L
+ mode = MONKEY_DISPOSE
+ return TRUE
// pickup any nearby objects
- if(!pickupTarget && prob(MONKEY_PICKUP_PROB))
- var/obj/item/I = locate(/obj/item/) in oview(5,src)
+ if(!pickupTarget)
+ var/obj/item/I = locate(/obj/item/) in oview(2,src)
if(I && !blacklistItems[I])
pickupTarget = I
-
- // I WANNA STEAL
- if(!pickupTarget && prob(MONKEY_STEAL_PROB))
- var/mob/living/carbon/human/H = locate(/mob/living/carbon/human/) in oview(5,src)
- if(H)
- pickupTarget = pick(H.held_items)
-
- // clear any combat walking
- if(!resisting)
- walk_to(src,0)
-
- return IsStandingStill()
+ else
+ var/mob/living/carbon/human/H = locate(/mob/living/carbon/human/) in oview(2,src)
+ if(H)
+ pickupTarget = pick(H.held_items)
if(MONKEY_HUNT) // hunting for attacker
if(health < MONKEY_FLEE_HEALTH)
@@ -250,6 +195,8 @@
// pickup any nearby weapon
if(!pickupTarget && prob(MONKEY_WEAPON_PROB))
var/obj/item/W = locate(/obj/item/) in oview(2,src)
+ if(!locate(/obj/item) in held_items)
+ best_force = 0
if(W && !blacklistItems[W] && W.force > best_force)
pickupTarget = W
@@ -356,8 +303,6 @@
return TRUE
-
-
return IsStandingStill()
/mob/living/carbon/monkey/proc/pickpocket(var/mob/M)
@@ -423,7 +368,8 @@
/mob/living/carbon/monkey/proc/retaliate(mob/living/L)
mode = MONKEY_HUNT
target = L
- enemies[L] += MONKEY_HATRED_AMOUNT
+ if(L != src)
+ enemies[L] += MONKEY_HATRED_AMOUNT
if(a_intent != INTENT_HARM)
battle_screech()
@@ -485,5 +431,5 @@
monkey_attack(pulledby)
retaliate(pulledby)
return TRUE
-
+
#undef MAX_RANGE_FIND
diff --git a/code/modules/mob/living/carbon/monkey/life.dm b/code/modules/mob/living/carbon/monkey/life.dm
index 3baf5087d6..24baee533a 100644
--- a/code/modules/mob/living/carbon/monkey/life.dm
+++ b/code/modules/mob/living/carbon/monkey/life.dm
@@ -12,11 +12,18 @@
if(..())
if(!client)
- if(stat == CONSCIOUS)
- if(!handle_combat())
- if(prob(33) && canmove && isturf(loc) && !pulledby)
+ if(stat == CONSCIOUS)
+ if(on_fire || buckled || restrained() || (resting && canmove))
+ if(!resisting && prob(MONKEY_RESIST_PROB))
+ resisting = TRUE
+ walk_to(src,0)
+ resist()
+ else if(resisting)
+ resisting = FALSE
+ else if((mode == MONKEY_IDLE && !pickupTarget && !prob(MONKEY_SHENANIGAN_PROB)) || !handle_combat())
+ if(prob(25) && canmove && isturf(loc) && !pulledby)
step(src, pick(GLOB.cardinals))
- if(prob(1))
+ else if(prob(1))
emote(pick("scratch","jump","roll","tail"))
else
walk_to(src,0)
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index 896708a4e3..011fa23230 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -73,7 +73,7 @@
return getArousalLoss()
-/mob/living/proc/apply_damages(brute = 0, burn = 0, tox = 0, oxy = 0, clone = 0, def_zone = null, blocked = FALSE, stamina = 0, arousal = 0, brain = 0)
+/mob/living/proc/apply_damages(brute = 0, burn = 0, tox = 0, oxy = 0, clone = 0, def_zone = null, blocked = FALSE, stamina = 0, brain = 0, arousal = 0)
if(blocked >= 100)
return 0
if(brute)
@@ -97,29 +97,29 @@
-/mob/living/proc/apply_effect(effect = 0,effecttype = STUN, blocked = FALSE)
+/mob/living/proc/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE)
var/hit_percent = (100-blocked)/100
if(!effect || (hit_percent <= 0))
return 0
switch(effecttype)
- if(STUN)
+ if(EFFECT_STUN)
Stun(effect * hit_percent)
- if(KNOCKDOWN)
+ if(EFFECT_KNOCKDOWN)
Knockdown(effect * hit_percent)
- if(UNCONSCIOUS)
+ if(EFFECT_UNCONSCIOUS)
Unconscious(effect * hit_percent)
- if(IRRADIATE)
+ if(EFFECT_IRRADIATE)
radiation += max(effect * hit_percent, 0)
- if(SLUR)
+ if(EFFECT_SLUR)
slurring = max(slurring,(effect * hit_percent))
- if(STUTTER)
+ if(EFFECT_STUTTER)
if((status_flags & CANSTUN) && !has_trait(TRAIT_STUNIMMUNE)) // stun is usually associated with stutter
stuttering = max(stuttering,(effect * hit_percent))
- if(EYE_BLUR)
+ if(EFFECT_EYE_BLUR)
blur_eyes(effect * hit_percent)
- if(DROWSY)
+ if(EFFECT_DROWSY)
drowsyness = max(drowsyness,(effect * hit_percent))
- if(JITTER)
+ if(EFFECT_JITTER)
if((status_flags & CANSTUN) && !has_trait(TRAIT_STUNIMMUNE))
jitteriness = max(jitteriness,(effect * hit_percent))
return 1
@@ -129,25 +129,25 @@
if(blocked >= 100)
return 0
if(stun)
- apply_effect(stun, STUN, blocked)
+ apply_effect(stun, EFFECT_STUN, blocked)
if(knockdown)
- apply_effect(knockdown, KNOCKDOWN, blocked)
+ apply_effect(knockdown, EFFECT_KNOCKDOWN, blocked)
if(unconscious)
- apply_effect(unconscious, UNCONSCIOUS, blocked)
+ apply_effect(unconscious, EFFECT_UNCONSCIOUS, blocked)
if(irradiate)
- apply_effect(irradiate, IRRADIATE, blocked)
+ apply_effect(irradiate, EFFECT_IRRADIATE, blocked)
if(slur)
- apply_effect(slur, SLUR, blocked)
+ apply_effect(slur, EFFECT_SLUR, blocked)
if(stutter)
- apply_effect(stutter, STUTTER, blocked)
+ apply_effect(stutter, EFFECT_STUTTER, blocked)
if(eyeblur)
- apply_effect(eyeblur, EYE_BLUR, blocked)
+ apply_effect(eyeblur, EFFECT_EYE_BLUR, blocked)
if(drowsy)
- apply_effect(drowsy, DROWSY, blocked)
+ apply_effect(drowsy, EFFECT_DROWSY, blocked)
if(stamina)
apply_damage(stamina, STAMINA, null, blocked)
if(jitter)
- apply_effect(jitter, JITTER, blocked)
+ apply_effect(jitter, EFFECT_JITTER, blocked)
return 1
@@ -248,34 +248,41 @@
/mob/living/proc/setStaminaLoss(amount, updating_stamina = TRUE, forced = FALSE)
return
-
// heal ONE external organ, organ gets randomly selected from damaged ones.
-/mob/living/proc/heal_bodypart_damage(brute, burn, updating_health = 1)
- adjustBruteLoss(-brute, 0) //zero as argument for no instant health update
- adjustFireLoss(-burn, 0)
+/mob/living/proc/heal_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
+ adjustBruteLoss(-brute, FALSE) //zero as argument for no instant health update
+ adjustFireLoss(-burn, FALSE)
+ adjustStaminaLoss(-stamina, FALSE)
if(updating_health)
updatehealth()
+ update_stamina()
// damage ONE external organ, organ gets randomly selected from damaged ones.
-/mob/living/proc/take_bodypart_damage(brute, burn, updating_health = 1)
- adjustBruteLoss(brute, 0) //zero as argument for no instant health update
- adjustFireLoss(burn, 0)
+/mob/living/proc/take_bodypart_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
+ adjustBruteLoss(brute, FALSE) //zero as argument for no instant health update
+ adjustFireLoss(burn, FALSE)
+ adjustStaminaLoss(stamina, FALSE)
if(updating_health)
updatehealth()
+ update_stamina()
// heal MANY bodyparts, in random order
-/mob/living/proc/heal_overall_damage(brute, burn, only_robotic = 0, only_organic = 1, updating_health = 1)
- adjustBruteLoss(-brute, 0) //zero as argument for no instant health update
- adjustFireLoss(-burn, 0)
+/mob/living/proc/heal_overall_damage(brute = 0, burn = 0, stamina = 0, only_robotic = FALSE, only_organic = TRUE, updating_health = TRUE)
+ adjustBruteLoss(-brute, FALSE) //zero as argument for no instant health update
+ adjustFireLoss(-burn, FALSE)
+ adjustStaminaLoss(-stamina, FALSE)
if(updating_health)
updatehealth()
+ update_stamina()
// damage MANY bodyparts, in random order
-/mob/living/proc/take_overall_damage(brute, burn, updating_health = 1)
- adjustBruteLoss(brute, 0) //zero as argument for no instant health update
- adjustFireLoss(burn, 0)
+/mob/living/proc/take_overall_damage(brute = 0, burn = 0, stamina = 0, updating_health = TRUE)
+ adjustBruteLoss(brute, FALSE) //zero as argument for no instant health update
+ adjustFireLoss(burn, FALSE)
+ adjustStaminaLoss(stamina, FALSE)
if(updating_health)
updatehealth()
+ update_stamina()
//heal up to amount damage, in a given order
/mob/living/proc/heal_ordered_damage(amount, list/damage_types)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 0b904d0604..eaaa47fe4f 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -138,7 +138,6 @@
if(!(world.time % 5))
to_chat(src, "
[L] is restraining [P], you cannot push past.")
return 1
-
//CIT CHANGES START HERE - makes it so resting stops you from moving through standing folks without a short delay
if(resting && !L.resting)
if(attemptingcrawl)
@@ -159,7 +158,6 @@
attemptingcrawl = FALSE
return TRUE
//END OF CIT CHANGES
-
if(moving_diagonally)//no mob swap during diagonal moves.
return 1
@@ -397,7 +395,6 @@
update_canmove()
/mob/proc/get_contents()
-
/*CIT CHANGE - comments out lay_down proc to be modified in modular_citadel
/mob/living/proc/lay_down()
set name = "Rest"
@@ -407,7 +404,6 @@
to_chat(src, "
You are now [resting ? "resting" : "getting up"].")
update_canmove()
*/
-
//Recursive function to find everything a mob is holding.
/mob/living/get_contents(obj/item/storage/Storage = null)
var/list/L = list()
@@ -456,6 +452,7 @@
if(status_flags & GODMODE)
return
health = maxHealth - getOxyLoss() - getToxLoss() - getFireLoss() - getBruteLoss() - getCloneLoss()
+ staminaloss = getStaminaLoss()
update_stat()
med_hud_set_health()
med_hud_set_status()
@@ -504,7 +501,7 @@
cure_blind()
cure_husk()
hallucination = 0
- heal_overall_damage(100000, 100000, 0, 0, 1) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
+ heal_overall_damage(INFINITY, INFINITY, INFINITY, FALSE, FALSE, TRUE) //heal brute and burn dmg on both organic and robotic limbs, and update health right away.
ExtinguishMob()
fire_stacks = 0
update_canmove()
@@ -729,7 +726,7 @@
clear_alert("weightless")
else
throw_alert("weightless", /obj/screen/alert/weightless)
- if(!override)
+ if(!override && !is_flying())
float(!has_gravity)
/mob/living/float(on)
@@ -892,16 +889,19 @@
return FALSE
return TRUE
-/*CIT CHANGE - comments out update_stamina to be modified in modular_citadel
-/mob/living/carbon/proc/update_stamina()
- if(staminaloss)
- var/total_health = (health - staminaloss)
+
+/mob/living/proc/update_stamina()
+ return
+/*
+/mob/living/carbon/update_stamina()
+ var/stam = getStaminaLoss()
+ if(stam)
+ var/total_health = (health - stam)
if(total_health <= HEALTH_THRESHOLD_CRIT && !stat)
to_chat(src, "
You're too exhausted to keep going...")
Knockdown(100)
- setStaminaLoss(health - 2)
- update_health_hud()
-*/
+ setStaminaLoss(health - 2, FALSE, FALSE)
+ update_health_hud() */ //CITADEL OVERRIDE
/mob/living/carbon/alien/update_stamina()
return
@@ -967,7 +967,7 @@
if(amount > RAD_BURN_THRESHOLD)
apply_damage((amount-RAD_BURN_THRESHOLD)/RAD_BURN_THRESHOLD, BURN, null, blocked)
- apply_effect((amount*RAD_MOB_COEFFICIENT)/max(1, (radiation**2)*RAD_OVERDOSE_REDUCTION), IRRADIATE, blocked)
+ apply_effect((amount*RAD_MOB_COEFFICIENT)/max(1, (radiation**2)*RAD_OVERDOSE_REDUCTION), EFFECT_IRRADIATE, blocked)
/mob/living/proc/fakefireextinguish()
return
@@ -1050,11 +1050,11 @@
var/ko = IsKnockdown() || IsUnconscious() || (stat && (stat != SOFT_CRIT || pulledby)) || (has_trait(TRAIT_FAKEDEATH))
var/move_and_fall = stat == SOFT_CRIT && !pulledby
var/chokehold = pulledby && pulledby.grab_state >= GRAB_NECK
- var/pinned = resting && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE // Cit change - adds pinning for aggressive-grabbing people on the ground
var/buckle_lying = !(buckled && !buckled.buckle_lying)
var/has_legs = get_num_legs()
var/has_arms = get_num_arms()
var/ignore_legs = get_leg_ignore()
+ var/pinned = resting && pulledby && pulledby.grab_state >= GRAB_AGGRESSIVE // Cit change - adds pinning for aggressive-grabbing people on the ground
if(ko || move_and_fall || IsStun() || chokehold) // Cit change - makes resting not force you to drop everything
drop_all_held_items()
unset_machine()
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index 37c2af605e..2b2e0de0b3 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -388,9 +388,7 @@
return
-/mob/living/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
- if(A != src)
- end_pixel_y = get_standard_pixel_y_offset(lying)
+/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()
..()
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 5c030552d3..8f9ffa2180 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -320,6 +320,10 @@
if(C)
C.post_status("shuttle")
+/mob/living/silicon/ai/can_interact_with(atom/A)
+ . = ..()
+ return . || (istype(loc, /obj/item/device/aicard))? (ISINRANGE(A.x, x - interaction_range, x + interaction_range) && ISINRANGE(A.y, y - interaction_range, y + interaction_range)): GLOB.cameranet.checkTurfVis(get_turf(A))
+
/mob/living/silicon/ai/cancel_camera()
view_core()
diff --git a/code/modules/mob/living/silicon/ai/vox_sounds.dm b/code/modules/mob/living/silicon/ai/vox_sounds.dm
index 29b57f8dbc..eb6d0ce991 100644
--- a/code/modules/mob/living/silicon/ai/vox_sounds.dm
+++ b/code/modules/mob/living/silicon/ai/vox_sounds.dm
@@ -975,4 +975,4 @@ GLOBAL_LIST_INIT(vox_sounds, list("abduction" = 'sound/vox_fem/abduction.ogg',
"zombie" = 'sound/vox_fem/zombie.ogg',
"zone" = 'sound/vox_fem/zone.ogg',
"zulu" = 'sound/vox_fem/zulu.ogg'))
-#endif
+#endif
\ No newline at end of file
diff --git a/code/modules/mob/living/silicon/damage_procs.dm b/code/modules/mob/living/silicon/damage_procs.dm
index 0f2c57c4fe..1190a00645 100644
--- a/code/modules/mob/living/silicon/damage_procs.dm
+++ b/code/modules/mob/living/silicon/damage_procs.dm
@@ -14,7 +14,7 @@
return 1
-/mob/living/silicon/apply_effect(effect = 0,effecttype = STUN, blocked = FALSE)
+/mob/living/silicon/apply_effect(effect = 0,effecttype = EFFECT_STUN, blocked = FALSE)
return FALSE //The only effect that can hit them atm is flashes and they still directly edit so this works for now
/mob/living/silicon/adjustToxLoss(amount, updating_health = TRUE, forced = FALSE) //immune to tox damage
diff --git a/code/modules/mob/living/silicon/laws.dm b/code/modules/mob/living/silicon/laws.dm
index 080d2e2b8c..c7aad99892 100644
--- a/code/modules/mob/living/silicon/laws.dm
+++ b/code/modules/mob/living/silicon/laws.dm
@@ -90,4 +90,4 @@
/mob/living/silicon/proc/clear_law_sixsixsix(force, announce = TRUE)
laws_sanity_check()
laws.clear_law_sixsixsix(force)
- post_lawchange(announce)
+ post_lawchange(announce)
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 6fce5a15f3..030a2425ff 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -90,8 +90,6 @@
/obj/item/clothing/head/sombrero,
/obj/item/clothing/head/witchunter_hat)
- var/remote_range = 7 //How far can you interact with machines.
-
can_buckle = TRUE
buckle_lying = FALSE
var/static/list/can_ride_typecache = typecacheof(/mob/living/carbon/human)
@@ -192,6 +190,9 @@
cell = null
return ..()
+/mob/living/silicon/robot/can_interact_with(atom/A)
+ . = ..()
+ return . || in_view_range(src, A)
/mob/living/silicon/robot/proc/pick_module()
if(module.type != /obj/item/robot_module)
@@ -355,6 +356,9 @@
queueAlarm("--- [class] alarm in [A.name] has been cleared.", class, 0)
return !cleared
+/mob/living/silicon/robot/can_interact_with(atom/A)
+ return !low_power_mode && ISINRANGE(A.x, x - interaction_range, x + interaction_range) && ISINRANGE(A.y, y - interaction_range, y + interaction_range)
+
/mob/living/silicon/robot/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/weldingtool) && (user.a_intent != INTENT_HARM || user == src))
user.changeNext_move(CLICK_CD_MELEE)
@@ -600,7 +604,6 @@
/mob/living/silicon/robot/update_icons()
cut_overlays()
icon_state = module.cyborg_base_icon
-
//Citadel changes start here - Allows modules to use different icon files, and allows modules to specify a pixel offset
icon = (module.cyborg_icon_override ? module.cyborg_icon_override : initial(icon))
if(laser)
diff --git a/code/modules/mob/living/silicon/robot/robot_defense.dm b/code/modules/mob/living/silicon/robot/robot_defense.dm
index 38cce8a277..b0be15771c 100644
--- a/code/modules/mob/living/silicon/robot/robot_defense.dm
+++ b/code/modules/mob/living/silicon/robot/robot_defense.dm
@@ -1,13 +1,11 @@
-
-
-/mob/living/silicon/robot/attacked_by(obj/item/I, mob/living/user, def_zone)
+/mob/living/silicon/robot/attackby(obj/item/I, mob/living/user)
if(hat_offset != INFINITY && user.a_intent == INTENT_HELP && is_type_in_typecache(I, equippable_hats))
to_chat(user, "
You begin to place [I] on [src]'s head...")
to_chat(src, "
[user] is placing [I] on your head...")
if(do_after(user, 30, target = src))
- user.temporarilyRemoveItemFromInventory(I, TRUE)
- place_on_head(I)
- return
+ if (user.temporarilyRemoveItemFromInventory(I, TRUE))
+ place_on_head(I)
+ return
if(I.force && I.damtype != STAMINA && stat != DEAD) //only sparks if real damage is dealt.
spark_system.start()
return ..()
@@ -52,6 +50,7 @@
return
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/robot/attack_hand(mob/living/carbon/human/user)
add_fingerprint(user)
if(opened && !wiresexposed && !issilicon(user))
diff --git a/code/modules/mob/living/silicon/robot/robot_modules.dm b/code/modules/mob/living/silicon/robot/robot_modules.dm
index d3d324b5fa..e654a771f8 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules.dm
@@ -318,7 +318,7 @@
cyborg_base_icon = "engineer"
moduleselect_icon = "engineer"
magpulsing = TRUE
- hat_offset = INFINITY // No hats
+ hat_offset = -4
/obj/item/robot_module/security
name = "Security"
diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm
index 92aff74e6a..083ad38caa 100644
--- a/code/modules/mob/living/silicon/silicon.dm
+++ b/code/modules/mob/living/silicon/silicon.dm
@@ -40,6 +40,7 @@
var/updating = FALSE //portable camera camerachunk update
var/hack_software = FALSE //Will be able to use hacking actions
+ var/interaction_range = 7 //wireless control range
/mob/living/silicon/Initialize()
. = ..()
@@ -152,17 +153,17 @@
/mob/living/silicon/can_inject(mob/user, error_msg)
if(error_msg)
to_chat(user, "
Their outer shell is too tough.")
- return 0
+ return FALSE
/mob/living/silicon/IsAdvancedToolUser()
- return 1
+ return TRUE
/proc/islinked(mob/living/silicon/robot/bot, mob/living/silicon/ai/ai)
if(!istype(bot) || !istype(ai))
- return 0
- if (bot.connected_ai == ai)
- return 1
- return 0
+ return FALSE
+ if(bot.connected_ai == ai)
+ return TRUE
+ return FALSE
/mob/living/silicon/Topic(href, href_list)
if (href_list["lawc"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
diff --git a/code/modules/mob/living/silicon/silicon_defense.dm b/code/modules/mob/living/silicon/silicon_defense.dm
index 2f81f73fea..7f34ea3305 100644
--- a/code/modules/mob/living/silicon/silicon_defense.dm
+++ b/code/modules/mob/living/silicon/silicon_defense.dm
@@ -63,6 +63,7 @@
return 1
return 0
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/silicon/attack_hand(mob/living/carbon/human/M)
switch(M.a_intent)
if ("help")
diff --git a/code/modules/mob/living/simple_animal/animal_defense.dm b/code/modules/mob/living/simple_animal/animal_defense.dm
index 08f82c8053..5f2a91519f 100644
--- a/code/modules/mob/living/simple_animal/animal_defense.dm
+++ b/code/modules/mob/living/simple_animal/animal_defense.dm
@@ -142,7 +142,7 @@
adjustBruteLoss(20)
return
-/mob/living/simple_animal/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect, end_pixel_y)
+/mob/living/simple_animal/do_attack_animation(atom/A, visual_effect_icon, used_item, no_effect)
if(!no_effect && !visual_effect_icon && melee_damage_upper)
if(melee_damage_upper < 10)
visual_effect_icon = ATTACK_EFFECT_PUNCH
diff --git a/code/modules/mob/living/simple_animal/bot/cleanbot.dm b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
index fe0789d960..344b516618 100644
--- a/code/modules/mob/living/simple_animal/bot/cleanbot.dm
+++ b/code/modules/mob/living/simple_animal/bot/cleanbot.dm
@@ -180,7 +180,7 @@
/obj/effect/decal/cleanable/flour,
/obj/effect/decal/cleanable/ash,
/obj/effect/decal/cleanable/greenglow,
- ///obj/effect/decal/cleanable/dirt, Cit change - removes dirt from the cleanbot target list to compensate for the mass amount of dirt decals present with footdirt
+ /obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/deadcockroach,
/obj/effect/decal/remains
)
diff --git a/code/modules/mob/living/simple_animal/bot/construction.dm b/code/modules/mob/living/simple_animal/bot/construction.dm
index 274a252cc1..692933f757 100644
--- a/code/modules/mob/living/simple_animal/bot/construction.dm
+++ b/code/modules/mob/living/simple_animal/bot/construction.dm
@@ -234,8 +234,6 @@
to_chat(user, "
They won't fit in, as there is already stuff inside!")
return
if(T.use(10))
- if(user.s_active)
- user.s_active.close(user)
var/obj/item/bot_assembly/floorbot/B = new
B.toolbox = type
user.put_in_hands(B)
@@ -312,7 +310,6 @@
qdel(S)
qdel(src)
-
/obj/item/bot_assembly/medbot/attackby(obj/item/W, mob/user, params)
..()
switch(build_step)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index 20062972ec..c5dd5375d0 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -12,7 +12,7 @@
icon = 'icons/mob/drone.dmi'
icon_state = "drone_maint_hat"//yes reuse the _hat state.
layer = BELOW_MOB_LAYER
-
+
var/drone_type = /mob/living/simple_animal/drone //Type of drone that will be spawned
var/seasonal_hats = TRUE //If TRUE, and there are no default hats, different holidays will grant different hats
var/static/list/possible_seasonal_hats //This is built automatically in build_seasonal_hats() but can also be edited by admins!
@@ -39,6 +39,7 @@
GLOB.poi_list -= src
. = ..()
+//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/item/drone_shell/attack_ghost(mob/user)
if(jobban_isbanned(user,"drone"))
return
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
index 2ee268014b..5e62ec0d4b 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/interaction.dm
@@ -29,6 +29,7 @@
if("Nothing")
return
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/mob/living/simple_animal/drone/attack_hand(mob/user)
if(ishuman(user))
if(stat == DEAD || status_flags & GODMODE || !can_be_held)
diff --git a/code/modules/mob/living/simple_animal/guardian/guardian.dm b/code/modules/mob/living/simple_animal/guardian/guardian.dm
index ddbbf4c30c..87b2812194 100644
--- a/code/modules/mob/living/simple_animal/guardian/guardian.dm
+++ b/code/modules/mob/living/simple_animal/guardian/guardian.dm
@@ -656,11 +656,9 @@ GLOBAL_LIST_EMPTY(parasites) //all currently existing/living guardians
/obj/item/storage/box/syndie_kit/guardian
name = "holoparasite injector kit"
-/obj/item/storage/box/syndie_kit/guardian/Initialize()
- . = ..()
+/obj/item/storage/box/syndie_kit/guardian/PopulateContents()
new /obj/item/guardiancreator/tech/choose/traitor(src)
new /obj/item/paper/guides/antag/guardian(src)
- return
/obj/item/guardiancreator/carp
name = "holocarp fishsticks"
diff --git a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
index 713a71ac9b..841e189002 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/dextrous.dm
@@ -7,17 +7,8 @@
magic_fluff_string = "
..And draw the Drone, a dextrous master of construction and repair."
tech_fluff_string = "
Boot sequence complete. Dextrous combat modules loaded. Holoparasite swarm online."
carp_fluff_string = "
CARP CARP CARP! You caught one! It can hold stuff in its fins, sort of."
- dextrous = 1
+ dextrous = TRUE
held_items = list(null, null)
- environment_target_typecache = list(
- /obj/machinery/door/window,
- /obj/structure/window,
- /obj/structure/closet,
- /obj/structure/table,
- /obj/structure/grille,
- /obj/structure/rack,
- /obj/structure/barricade,
- /obj/machinery/camera) //so we can also attack cameras
var/obj/item/internal_storage //what we're storing within ourself
/mob/living/simple_animal/hostile/guardian/dextrous/death(gibbed)
diff --git a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
index c2595279ff..fc25ec5ac6 100644
--- a/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
+++ b/code/modules/mob/living/simple_animal/guardian/types/explosive.dm
@@ -88,6 +88,7 @@
/obj/guardian_bomb/attackby(mob/living/user)
detonate(user)
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/guardian_bomb/attack_hand(mob/living/user)
detonate(user)
diff --git a/code/modules/mob/living/simple_animal/hostile/bees.dm b/code/modules/mob/living/simple_animal/hostile/bees.dm
index ef2e393a7d..eb13446370 100644
--- a/code/modules/mob/living/simple_animal/hostile/bees.dm
+++ b/code/modules/mob/living/simple_animal/hostile/bees.dm
@@ -35,6 +35,7 @@
environment_smash = ENVIRONMENT_SMASH_NONE
mouse_opacity = MOUSE_OPACITY_OPAQUE
pass_flags = PASSTABLE | PASSGRILLE | PASSMOB
+ density = FALSE
mob_size = MOB_SIZE_TINY
movement_type = FLYING
gold_core_spawnable = HOSTILE_SPAWN
@@ -56,7 +57,7 @@
/mob/living/simple_animal/hostile/poison/bees/Initialize()
. = ..()
generate_bee_visuals()
-
+ AddComponent(/datum/component/swarming)
/mob/living/simple_animal/hostile/poison/bees/Destroy()
if(beehome)
@@ -291,5 +292,5 @@
if(idle >= BEE_IDLE_ROAMING && prob(BEE_PROB_GOROAM))
toggle_ai(AI_ON)
forceMove(beehome.drop_location())
- else
+ else
..()
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 70377e65c8..823b5322d3 100644
--- a/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
+++ b/code/modules/mob/living/simple_animal/hostile/giant_spider.dm
@@ -73,8 +73,10 @@
to_chat(src, "
[directive]")
/mob/living/simple_animal/hostile/poison/giant_spider/attack_ghost(mob/user)
- if(!humanize_spider(user))
- return ..()
+ . = ..()
+ if(.)
+ return
+ humanize_spider(user)
/mob/living/simple_animal/hostile/poison/giant_spider/proc/humanize_spider(mob/user)
if(key || !playable_spider)//Someone is in it or the fun police are shutting it down
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index edb6e47ca8..ce5f3cfb5a 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -14,17 +14,6 @@
var/list/emote_taunt = list()
var/taunt_chance = 0
-//typecache of things this mob will attack in DestroyPathToTarget() if it has environment_smash
- var/list/environment_target_typecache = list(
- /obj/machinery/door/window,
- /obj/structure/window,
- /obj/structure/closet,
- /obj/structure/table,
- /obj/structure/grille,
- /obj/structure/girder,
- /obj/structure/rack,
- /obj/structure/barricade) //turned into a typecache in New()
-
var/ranged_message = "fires" //Fluff text for ranged mobs
var/ranged_cooldown = 0 //What the current cooldown on ranged attacks is, generally world.time + ranged_cooldown_time
var/ranged_cooldown_time = 30 //How long, in deciseconds, the cooldown of ranged attacks is
@@ -38,7 +27,6 @@
var/robust_searching = 0 //By default, mobs have a simple searching method, set this to 1 for the more scrutinous searching (stat_attack, stat_exclusive, etc), should be disabled on most mobs
var/vision_range = 9 //How big of an area to search for targets in, a vision of 9 attempts to find targets as soon as they walk into screen view
var/aggro_vision_range = 9 //If a mob is aggro, we search in this radius. Defaults to 9 to keep in line with original simple mob aggro radius
- var/idle_vision_range = 9 //If a mob is just idling around, it's vision range is limited to this. Defaults to 9 to keep in line with original simple mob aggro radius
var/search_objects = 0 //If we want to consider objects when searching around, set this to 1. If you want to search for objects while also ignoring mobs until hurt, set it to 2. To completely ignore mobs, even when attacked, set it to 3
var/search_objects_timer_id //Timer for regaining our old search_objects value after being attacked
var/search_objects_regain_time = 30 //the delay between being attacked and gaining our old search_objects value back
@@ -58,7 +46,6 @@
if(!targets_from)
targets_from = src
- environment_target_typecache = typecacheof(environment_target_typecache)
wanted_objects = typecacheof(wanted_objects)
@@ -305,7 +292,7 @@
/mob/living/simple_animal/hostile/proc/LoseAggro()
stop_automated_movement = 0
- vision_range = idle_vision_range
+ vision_range = initial(vision_range)
taunt_chance = initial(taunt_chance)
/mob/living/simple_animal/hostile/proc/LoseTarget()
@@ -385,10 +372,9 @@
if(T.Adjacent(targets_from))
if(CanSmashTurfs(T))
T.attack_animal(src)
- for(var/a in T)
- var/atom/A = a
- if(is_type_in_typecache(A, environment_target_typecache) && !A.IsObscured())
- A.attack_animal(src)
+ for(var/obj/O in T)
+ if(O.density && environment_smash >= ENVIRONMENT_SMASH_STRUCTURES && !O.IsObscured())
+ O.attack_animal(src)
return
@@ -510,4 +496,4 @@ mob/living/simple_animal/hostile/proc/DestroySurroundings() // for use with mega
if (isturf(M.loc))
. += M
else if (M.loc.type in hostile_machines)
- . += M.loc
+ . += M.loc
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index 8e285c0b4c..d5ecd0e985 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -129,7 +129,7 @@ Difficulty: Medium
INVOKE_ASYNC(src, .proc/quick_attack_loop)
return TRUE
-/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect, end_pixel_y)
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
if(!used_item && !isturf(A))
used_item = miner_saw
..()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index b7015972fd..b107eec0c0 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -383,7 +383,9 @@ Difficulty: Very Hard
ActivationReaction(speaker, ACTIVATE_SPEECH)
/obj/machinery/anomalous_crystal/attack_hand(mob/user)
- ..()
+ . = ..()
+ if(.)
+ return
ActivationReaction(user, ACTIVATE_TOUCH)
/obj/machinery/anomalous_crystal/attackby(obj/item/I, mob/user, params)
@@ -577,7 +579,9 @@ Difficulty: Very Hard
notify_ghosts("An anomalous crystal has been activated in [get_area(src)]! This crystal can always be used by ghosts hereafter.", enter_link = "
(Click to enter)", ghost_sound = 'sound/effects/ghost2.ogg', source = src, action = NOTIFY_ATTACK)
/obj/machinery/anomalous_crystal/helpers/attack_ghost(mob/dead/observer/user)
- ..()
+ . = ..()
+ if(.)
+ return
if(ready_to_deploy)
var/be_helper = alert("Become a Lightgeist? (Warning, You can no longer be cloned!)",,"Yes","No")
if(be_helper == "Yes" && !QDELETED(src) && isobserver(user))
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
index eba26725a6..52f981f43c 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
@@ -47,7 +47,6 @@ Difficulty: Medium
vision_range = 13
wander = FALSE
elimination = 1
- idle_vision_range = 13
appearance_flags = 0
mouse_opacity = MOUSE_OPACITY_ICON
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index 5e6211da09..3f6fee9935 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -19,22 +19,11 @@
minbodytemp = 0
maxbodytemp = INFINITY
aggro_vision_range = 18
- idle_vision_range = 5
+ vision_range = 5
anchored = TRUE
mob_size = MOB_SIZE_LARGE
layer = LARGE_MOB_LAYER //Looks weird with them slipping under mineral walls and cameras and shit otherwise
mouse_opacity = MOUSE_OPACITY_OPAQUE // Easier to click on in melee, they're giant targets anyway
- environment_target_typecache = list(
- /obj/machinery/door/window,
- /obj/structure/window,
- /obj/structure/closet,
- /obj/structure/table,
- /obj/structure/grille,
- /obj/structure/girder,
- /obj/structure/rack,
- /obj/structure/barricade,
- /obj/machinery/field,
- /obj/machinery/power/emitter)
var/list/crusher_loot
var/medal_type
var/score_type = BOSS_SCORE
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
index faff533cff..972e05b1e5 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/basilisk.dm
@@ -27,8 +27,8 @@
a_intent = INTENT_HARM
speak_emote = list("chitters")
attack_sound = 'sound/weapons/bladeslice.ogg'
+ vision_range = 2
aggro_vision_range = 9
- idle_vision_range = 2
turns_per_move = 5
gold_core_spawnable = HOSTILE_SPAWN
loot = list(/obj/item/stack/ore/diamond{layer = ABOVE_MOB_LAYER},
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
index 951f52d021..cf8a6706e8 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
@@ -9,7 +9,6 @@
move_to_delay = 5
vision_range = 20
aggro_vision_range = 20
- idle_vision_range = 20
maxHealth = 40 //easy to kill, but oh, will you be seeing a lot of them.
health = 40
melee_damage_lower = 10
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
index 0c59a576d9..ea8c817581 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goldgrub.dm
@@ -10,7 +10,6 @@
icon_gib = "syndicate_gib"
vision_range = 2
aggro_vision_range = 9
- idle_vision_range = 2
move_to_delay = 5
friendly = "harmlessly rolls into"
maxHealth = 45
@@ -77,5 +76,5 @@
return
/mob/living/simple_animal/hostile/asteroid/goldgrub/adjustHealth(amount, updating_health = TRUE, forced = FALSE)
- idle_vision_range = 9
+ vision_range = 9
. = ..()
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
index 979c155249..0d9093ac77 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/goliath.dm
@@ -25,8 +25,8 @@
attacktext = "pulverizes"
attack_sound = 'sound/weapons/punch1.ogg'
throw_message = "does nothing to the rocky hide of the"
+ vision_range = 5
aggro_vision_range = 9
- idle_vision_range = 5
anchored = TRUE //Stays anchored until death as to be unpullable
var/pre_attack = 0
var/pre_attack_icon = "Goliath_preattack"
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
index 63462a1133..8e32479be1 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining_mobs/hivelord.dm
@@ -12,7 +12,6 @@
ranged = 1
vision_range = 5
aggro_vision_range = 9
- idle_vision_range = 5
speed = 3
maxHealth = 75
health = 75
@@ -241,7 +240,6 @@
move_to_delay = 14
vision_range = 5
aggro_vision_range = 9
- idle_vision_range = 5
speed = 3
faction = list("mining")
weather_immunities = list("lava","ash")
diff --git a/code/modules/mob/living/simple_animal/hostile/statue.dm b/code/modules/mob/living/simple_animal/hostile/statue.dm
index 5d30a210a8..8df758c0d6 100644
--- a/code/modules/mob/living/simple_animal/hostile/statue.dm
+++ b/code/modules/mob/living/simple_animal/hostile/statue.dm
@@ -38,7 +38,6 @@
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE
vision_range = 12
aggro_vision_range = 12
- idle_vision_range = 12
search_objects = 1 // So that it can see through walls
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 8cfc5784e9..d6e061ffb1 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -160,7 +160,8 @@
desc = "A small, twin-bladed machine capable of inflicting very deadly lacerations."
icon_state = "viscerator_attack"
icon_living = "viscerator_attack"
- pass_flags = PASSTABLE
+ pass_flags = PASSTABLE | PASSMOB
+ a_intent = INTENT_HARM
health = 25
maxHealth = 25
melee_damage_lower = 15
@@ -180,3 +181,7 @@
gold_core_spawnable = HOSTILE_SPAWN
del_on_death = 1
deathmessage = "is smashed into pieces!"
+
+/mob/living/simple_animal/hostile/viscerator/Initialize()
+ . = ..()
+ AddComponent(/datum/component/swarming)
diff --git a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
index 5737f5f4b2..1fcd1c11f8 100644
--- a/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
+++ b/code/modules/mob/living/simple_animal/hostile/wumborian_fugu.dm
@@ -24,8 +24,8 @@
attacktext = "chomps"
attack_sound = 'sound/weapons/punch1.ogg'
throw_message = "is avoided by the"
+ vision_range = 5
aggro_vision_range = 9
- idle_vision_range = 5
mob_size = MOB_SIZE_SMALL
environment_smash = ENVIRONMENT_SMASH_NONE
gold_core_spawnable = HOSTILE_SPAWN
diff --git a/code/modules/mob/living/simple_animal/parrot.dm b/code/modules/mob/living/simple_animal/parrot.dm
index 46e5b4f3b1..f968dc7839 100644
--- a/code/modules/mob/living/simple_animal/parrot.dm
+++ b/code/modules/mob/living/simple_animal/parrot.dm
@@ -299,10 +299,10 @@
return
/mob/living/simple_animal/parrot/attack_paw(mob/living/carbon/monkey/M)
- attack_hand(M)
+ return attack_hand(M)
/mob/living/simple_animal/parrot/attack_alien(mob/living/carbon/alien/M)
- attack_hand(M)
+ return attack_hand(M)
//Simple animals
/mob/living/simple_animal/parrot/attack_animal(mob/living/simple_animal/M)
diff --git a/code/modules/mob/living/simple_animal/slime/slime.dm b/code/modules/mob/living/simple_animal/slime/slime.dm
index 024f24e182..5087825305 100644
--- a/code/modules/mob/living/simple_animal/slime/slime.dm
+++ b/code/modules/mob/living/simple_animal/slime/slime.dm
@@ -74,6 +74,12 @@
"gold", "green", "adamantine", "oil", "light pink", "bluespace",
"cerulean", "sepia", "black", "pyrite")
+ ///////////CORE-CROSSING CODE
+
+ var/effectmod //What core modification is being used.
+ var/applied = 0 //How many extracts of the modtype have been applied.
+
+
/mob/living/simple_animal/slime/Initialize(mapload, new_colour="grey", new_is_adult=FALSE)
var/datum/action/innate/slime/feed/F = new
F.Grant(src)
@@ -226,7 +232,7 @@
var/mob/living/Food = A
if(CanFeedon(Food))
Feedon(Food)
- ..()
+ return ..()
/mob/living/simple_animal/slime/doUnEquip(obj/item/W)
return
@@ -272,8 +278,6 @@
discipline_slime(user)
return ..()
-
-
/mob/living/simple_animal/slime/attack_hand(mob/living/carbon/human/M)
if(buckled)
M.do_attack_animation(src, ATTACK_EFFECT_DISARM)
@@ -343,8 +347,50 @@
force_effect = round(W.force/2)
if(prob(10 + force_effect))
discipline_slime(user)
+ if(istype(W, /obj/item/storage/bag/bio))
+ var/obj/item/storage/P = W
+ if(!effectmod)
+ to_chat(user, "
The slime is not currently being mutated.")
+ return
+ var/hasOutput = FALSE //Have we outputted text?
+ var/hasFound = FALSE //Have we found an extract to be added?
+ for(var/obj/item/slime_extract/S in P.contents)
+ if(S.effectmod == effectmod)
+ P.remove_from_storage(S, get_turf(src))
+ qdel(S)
+ applied++
+ hasFound = TRUE
+ if(applied >= SLIME_EXTRACT_CROSSING_REQUIRED)
+ to_chat(user, "
You feed the slime as many of the extracts from the bag as you can, and it mutates!")
+ playsound(src, 'sound/effects/attackblob.ogg', 50, 1)
+ spawn_corecross()
+ hasOutput = TRUE
+ break
+ if(!hasOutput)
+ if(!hasFound)
+ to_chat(user, "
There are no extracts in the bag that this slime will accept!")
+ else
+ to_chat(user, "
You feed the slime some extracts from the bag.")
+ playsound(src, 'sound/effects/attackblob.ogg', 50, 1)
+ return
..()
+/mob/living/simple_animal/slime/proc/spawn_corecross()
+ var/static/list/crossbreeds = subtypesof(/obj/item/slimecross)
+ visible_message("
[src] shudders, its mutated core consuming the rest of its body!")
+ playsound(src, 'sound/magic/smoke.ogg', 50, 1)
+ var/crosspath
+ for(var/X in crossbreeds)
+ var/obj/item/slimecross/S = X
+ if(initial(S.colour) == colour && initial(S.effect) == effectmod)
+ crosspath = S
+ break
+ if(crosspath)
+ new crosspath(loc)
+ else
+ visible_message("
The mutated core shudders, and collapses into a puddle, unable to maintain its form.")
+ qdel(src)
+
/mob/living/simple_animal/slime/proc/apply_water()
adjustBruteLoss(rand(15,20))
if(!client)
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index f5e5d32428..205eeb4b28 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -207,26 +207,26 @@
//unset redraw_mob to prevent the mob from being redrawn at the end.
/mob/proc/equip_to_slot_if_possible(obj/item/W, slot, qdel_on_fail = FALSE, disable_warning = FALSE, redraw_mob = TRUE, bypass_equip_delay_self = FALSE)
if(!istype(W))
- return 0
+ return FALSE
if(!W.mob_can_equip(src, null, slot, disable_warning, bypass_equip_delay_self))
if(qdel_on_fail)
qdel(W)
else
if(!disable_warning)
- to_chat(src, "
You are unable to equip that!" )
- return 0
+ to_chat(src, "
You are unable to equip that!")
+ return FALSE
equip_to_slot(W, slot, redraw_mob) //This proc should not ever fail.
- return 1
+ return TRUE
-//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't eqip need to be done before! Use mob_can_equip() for that task.
+//This is an UNSAFE proc. It merely handles the actual job of equipping. All the checks on whether you can or can't equip need to be done before! Use mob_can_equip() for that task.
//In most cases you will want to use equip_to_slot_if_possible()
/mob/proc/equip_to_slot(obj/item/W, slot)
return
-//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the rounds tarts and when events happen and such.
+//This is just a commonly used configuration for the equip_to_slot_if_possible() proc, used to equip people when the round starts and when events happen and such.
//Also bypasses equip delay checks, since the mob isn't actually putting it on.
/mob/proc/equip_to_slot_or_del(obj/item/W, slot)
- return equip_to_slot_if_possible(W, slot, 1, 1, 0, 1)
+ return equip_to_slot_if_possible(W, slot, TRUE, TRUE, FALSE, TRUE)
//puts the item "W" into an appropriate slot in a human's inventory
//returns 0 if it cannot, 1 if successful
@@ -369,6 +369,7 @@
use_that_empty_hand() //CIT CHANGE - ditto
update_inv_hands() // CIT CHANGE - ditto.
+
/mob/verb/memory()
set name = "Notes"
set category = "IC"
@@ -494,7 +495,7 @@
return
/mob/MouseDrop(mob/M)
- ..()
+ . = ..()
if(M != usr)
return
if(usr == src)
@@ -742,6 +743,10 @@
/mob/proc/can_unbuckle()
return 1
+//Can the mob interact() with an atom?
+/mob/proc/can_interact_with(atom/A)
+ return IsAdminGhost(src) || Adjacent(A)
+
//Can the mob see reagents inside of containers?
/mob/proc/can_see_reagents()
if(stat == DEAD) //Ghosts and such can always see reagents
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 242e1c8177..8ef39f3b06 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -254,7 +254,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
/proc/shake_camera(mob/M, duration, strength=1)
- if(!M || !M.client || duration <= 0)
+ if(!M || !M.client || duration < 1)
return
var/client/C = M.client
var/oldx = C.pixel_x
@@ -408,7 +408,7 @@ It's fairly easy to fix if dealing with single letters but not so much with comp
else
dam = 0
if((brute_heal > 0 && affecting.brute_dam > 0) || (burn_heal > 0 && affecting.burn_dam > 0))
- if(affecting.heal_damage(brute_heal, burn_heal, 1, 0))
+ if(affecting.heal_damage(brute_heal, burn_heal, 0, TRUE, FALSE))
H.update_damage_overlays()
user.visible_message("[user] has fixed some of the [dam ? "dents on" : "burnt wires in"] [H]'s [affecting.name].", \
"
You fix some of the [dam ? "dents on" : "burnt wires in"] [H]'s [affecting.name].")
diff --git a/code/modules/modular_computers/computers/item/computer.dm b/code/modules/modular_computers/computers/item/computer.dm
index ce8d8ce4b9..e6c96e9f62 100644
--- a/code/modules/modular_computers/computers/item/computer.dm
+++ b/code/modules/modular_computers/computers/item/computer.dm
@@ -161,12 +161,15 @@
var/mob/M = usr
if((!istype(over_object, /obj/screen)) && usr.canUseTopic(src))
return attack_self(M)
- return
+ return ..()
/obj/item/device/modular_computer/attack_ai(mob/user)
return attack_self(user)
/obj/item/device/modular_computer/attack_ghost(mob/dead/observer/user)
+ . = ..()
+ if(.)
+ return
if(enabled)
ui_interact(user)
else if(IsAdminGhost(user))
@@ -207,7 +210,7 @@
// On-click handling. Turns on the computer if it's off and opens the GUI.
-/obj/item/device/modular_computer/attack_self(mob/user)
+/obj/item/device/modular_computer/interact(mob/user)
if(enabled)
ui_interact(user)
else
diff --git a/code/modules/modular_computers/computers/item/computer_ui.dm b/code/modules/modular_computers/computers/item/computer_ui.dm
index 5759a24dc2..fd4e01798c 100644
--- a/code/modules/modular_computers/computers/item/computer_ui.dm
+++ b/code/modules/modular_computers/computers/item/computer_ui.dm
@@ -1,7 +1,7 @@
/obj/item/device/modular_computer/attack_self(mob/user)
. = ..()
ui_interact(user)
-
+
// Operates TGUI
/obj/item/device/modular_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
if(!enabled)
diff --git a/code/modules/modular_computers/computers/item/laptop.dm b/code/modules/modular_computers/computers/item/laptop.dm
index 1618b68478..f0970f3ce0 100644
--- a/code/modules/modular_computers/computers/item/laptop.dm
+++ b/code/modules/modular_computers/computers/item/laptop.dm
@@ -53,6 +53,7 @@
try_toggle_open(usr)
/obj/item/device/modular_computer/laptop/MouseDrop(obj/over_object, src_location, over_location)
+ . = ..()
if(over_object == usr || over_object == src)
try_toggle_open(usr)
else if(istype(over_object, /obj/screen/inventory/hand))
@@ -65,12 +66,12 @@
M.put_in_hand(src, H.held_index)
/obj/item/device/modular_computer/laptop/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(screen_on && isturf(loc))
return attack_self(user)
- return ..()
-
-
/obj/item/device/modular_computer/laptop/proc/try_toggle_open(mob/living/user)
if(issilicon(user))
return
diff --git a/code/modules/modular_computers/computers/machinery/modular_computer.dm b/code/modules/modular_computers/computers/machinery/modular_computer.dm
index 03c39ef277..74ee7b68ea 100644
--- a/code/modules/modular_computers/computers/machinery/modular_computer.dm
+++ b/code/modules/modular_computers/computers/machinery/modular_computer.dm
@@ -37,6 +37,9 @@
return ..()
/obj/machinery/modular_computer/attack_ghost(mob/dead/observer/user)
+ . = ..()
+ if(.)
+ return
if(cpu)
cpu.attack_ghost(user)
@@ -92,16 +95,19 @@
if(cpu)
cpu.AltClick(user)
+//ATTACK HAND IGNORING PARENT RETURN VALUE
// On-click handling. Turns on the computer if it's off and opens the GUI.
-/obj/machinery/modular_computer/attack_hand(mob/user)
+/obj/machinery/modular_computer/interact(mob/user)
if(cpu)
- cpu.attack_self(user) // CPU is an item, that's why we route attack_hand to attack_self
+ return cpu.interact(user) // CPU is an item, that's why we route attack_hand to attack_self
+ else
+ return ..()
// Process currently calls handle_power(), may be expanded in future if more things are added.
/obj/machinery/modular_computer/process()
if(cpu)
// Keep names in sync.
- cpu.name = src.name
+ cpu.name = name
cpu.process()
// Used in following function to reduce copypaste
@@ -114,7 +120,6 @@
stat |= NOPOWER
update_icon()
-
// Modular computers can have battery in them, we handle power in previous proc, so prevent this from messing it up for us.
/obj/machinery/modular_computer/power_change()
if(cpu && cpu.use_power()) // If MC_CPU still has a power source, PC wouldn't go offline.
diff --git a/code/modules/modular_computers/laptop_vendor.dm b/code/modules/modular_computers/laptop_vendor.dm
index 12f7d403c2..55c88fbfcb 100644
--- a/code/modules/modular_computers/laptop_vendor.dm
+++ b/code/modules/modular_computers/laptop_vendor.dm
@@ -222,24 +222,18 @@
return 1
return 0
-/obj/machinery/lapvend/attack_hand(mob/user)
- ui_interact(user)
-
/obj/machinery/lapvend/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
if(stat & (BROKEN | NOPOWER | MAINT))
if(ui)
ui.close()
return 0
-
-
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if (!ui)
ui = new(user, src, ui_key, "computer_fabricator", "Personal Computer Vendor", 500, 400, state = state)
ui.open()
ui.set_autoupdate(state = 1)
-
/obj/machinery/lapvend/attackby(obj/item/I as obj, mob/user as mob)
if(istype(I, /obj/item/stack/spacecash))
var/obj/item/stack/spacecash/c = I
@@ -250,10 +244,8 @@
visible_message("
[usr] inserts [c.value] credits into [src].")
qdel(c)
return
-
return ..()
-
// Simplified payment processing, returns 1 on success.
/obj/machinery/lapvend/proc/process_payment()
if(total_price > credits)
diff --git a/code/modules/paperwork/filingcabinet.dm b/code/modules/paperwork/filingcabinet.dm
index 6f7c99dac8..907fccdc5b 100644
--- a/code/modules/paperwork/filingcabinet.dm
+++ b/code/modules/paperwork/filingcabinet.dm
@@ -65,12 +65,12 @@
return ..()
-/obj/structure/filingcabinet/attack_hand(mob/user)
+/obj/structure/filingcabinet/ui_interact(mob/user)
+ . = ..()
if(contents.len <= 0)
to_chat(user, "
[src] is empty.")
return
- user.set_machine(src)
var/dat = "
"
var/i
for(i=contents.len, i>=1, i--)
@@ -136,7 +136,8 @@
/obj/structure/filingcabinet/security/attack_hand()
populate()
- ..()
+ . = ..()
+
/obj/structure/filingcabinet/security/attack_tk()
populate()
..()
@@ -165,9 +166,12 @@
P.name = "paper - '[G.fields["name"]]'"
virgin = 0 //tabbing here is correct- it's possible for people to try and use it
//before the records have been generated, so we do this inside the loop.
+
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/structure/filingcabinet/medical/attack_hand()
populate()
- ..()
+ . = ..()
+
/obj/structure/filingcabinet/medical/attack_tk()
populate()
..()
@@ -205,14 +209,14 @@ GLOBAL_LIST_EMPTY(employmentCabinets)
/obj/structure/filingcabinet/employment/proc/addFile(mob/living/carbon/human/employee)
new /obj/item/paper/contract/employment(src, employee)
-/obj/structure/filingcabinet/employment/attack_hand(mob/user)
+/obj/structure/filingcabinet/employment/interact(mob/user)
if(!cooldown)
if(virgin)
fillCurrent()
virgin = 0
cooldown = 1
- ..()
sleep(100) // prevents the devil from just instantly emptying the cabinet, ensuring an easy win.
cooldown = 0
else
to_chat(user, "[src] is jammed, give it a few seconds.")
+ ..()
diff --git a/code/modules/paperwork/paper_cutter.dm b/code/modules/paperwork/paper_cutter.dm
index c3ffc14b80..ccc9427349 100644
--- a/code/modules/paperwork/paper_cutter.dm
+++ b/code/modules/paperwork/paper_cutter.dm
@@ -66,8 +66,10 @@
return
..()
-
/obj/item/papercutter/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
add_fingerprint(user)
if(!storedcutter)
to_chat(user, "The cutting blade is gone! You can't use [src] now.")
@@ -88,8 +90,8 @@
new /obj/item/paperslip(get_turf(src))
update_icon()
-
/obj/item/papercutter/MouseDrop(atom/over_object)
+ . = ..()
var/mob/M = usr
if(M.incapacitated() || !Adjacent(M))
return
@@ -102,7 +104,6 @@
M.putItemFromInventoryInHandIfPossible(src, H.held_index)
add_fingerprint(M)
-
/obj/item/paperslip
name = "paper slip"
desc = "A little slip of paper left over after a larger piece was cut. Whoa."
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index 2818f04344..82e7327e8a 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -40,6 +40,7 @@
..()
/obj/item/paper_bin/MouseDrop(atom/over_object)
+ . = ..()
var/mob/living/M = usr
if(!istype(M) || M.incapacitated() || !Adjacent(M))
return
@@ -53,11 +54,10 @@
add_fingerprint(M)
-
/obj/item/paper_bin/attack_paw(mob/user)
return attack_hand(user)
-
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/paper_bin/attack_hand(mob/user)
if(user.lying)
return
@@ -90,9 +90,8 @@
to_chat(user, "You take [P] out of \the [src].")
else
to_chat(user, "[src] is empty!")
-
add_fingerprint(user)
-
+ return ..()
/obj/item/paper_bin/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/paper))
@@ -142,12 +141,15 @@
icon_state = "paper_bundle"
papertype = /obj/item/paper/natural
resistance_flags = FLAMMABLE
+
/obj/item/paper_bin/bundlenatural/attack_hand(mob/user)
..()
if(total_paper < 1)
qdel(src)
+
/obj/item/paper_bin/bundlenatural/fire_act(exposed_temperature, exposed_volume)
qdel(src)
+
/obj/item/paper_bin/bundlenatural/attackby(obj/item/W, mob/user)
if(W.is_sharp())
to_chat(user, "You snip \the [src], spilling paper everywhere.")
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 6fa13fe8c3..5c63c559e3 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -30,15 +30,8 @@
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/attack_ai(mob/user)
- return attack_hand(user)
-
-/obj/machinery/photocopier/attack_paw(mob/user)
- return attack_hand(user)
-
-/obj/machinery/photocopier/attack_hand(mob/user)
- user.set_machine(src)
-
+/obj/machinery/photocopier/ui_interact(mob/user)
+ . = ..()
var/dat = "Photocopier
"
if(copy || photocopy || doccopy || (ass && (ass.loc == src.loc)))
dat += "Remove Paper
"
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index 19a83f9770..31bcc537e9 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -466,7 +466,7 @@
var/mob/M = target
disk.record.caller_name = M.name
disk.record.set_caller_image(M)
- else
+ else
return
else
captureimage(target, user, flag)
@@ -552,6 +552,7 @@
to_chat(user, "\The [src] already contains a photo.")
..()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/wallframe/picture/attack_hand(mob/user)
if(user.get_inactive_held_item() != src)
..()
@@ -562,6 +563,7 @@
to_chat(user, "You carefully remove the photo from \the [src].")
displayed = null
update_icon()
+ return ..()
/obj/item/wallframe/picture/attack_self(mob/user)
user.examinate(src)
@@ -631,6 +633,9 @@
..()
/obj/structure/sign/picture_frame/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(framed)
framed.show(user)
diff --git a/code/modules/power/antimatter/control.dm b/code/modules/power/antimatter/control.dm
index cfbb3d199b..96e35164c4 100644
--- a/code/modules/power/antimatter/control.dm
+++ b/code/modules/power/antimatter/control.dm
@@ -9,6 +9,8 @@
idle_power_usage = 100
active_power_usage = 1000
+ interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT | INTERACT_ATOM_REQUIRES_ANCHORED
+
var/list/obj/machinery/am_shielding/linked_shielding
var/list/obj/machinery/am_shielding/linked_cores
var/obj/item/am_containment/fueljar
@@ -207,10 +209,6 @@
stability -= damage/2
check_stability()
-/obj/machinery/power/am_control_unit/attack_hand(mob/user)
- if(anchored)
- interact(user)
-
/obj/machinery/power/am_control_unit/proc/add_shielding(obj/machinery/am_shielding/AMS, AMS_linking = 0)
if(!istype(AMS))
return 0
@@ -283,13 +281,13 @@
/obj/machinery/power/am_control_unit/proc/reset_stored_core_stability_delay()
stored_core_stability_delay = 0
-/obj/machinery/power/am_control_unit/interact(mob/user)
+/obj/machinery/power/am_control_unit/ui_interact(mob/user)
+ . = ..()
if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER)))
if(!isAI(user))
user.unset_machine()
user << browse(null, "window=AMcontrol")
return
- user.set_machine(src)
var/dat = ""
dat += "AntiMatter Control Panel
"
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 804276548f..f764a38d64 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -49,7 +49,7 @@
max_integrity = 200
integrity_failure = 50
resistance_flags = FIRE_PROOF
- interact_open = TRUE
+ interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON
var/lon_range = 1.5
var/area/area
@@ -381,7 +381,7 @@
/obj/machinery/power/apc/attackby(obj/item/W, mob/living/user, params)
if(issilicon(user) && get_dist(src,user)>1)
- return src.attack_hand(user)
+ return attack_hand(user)
if (istype(W, /obj/item/crowbar)) //Using crowbar
if (opened) // a) on open apc
if (has_electronics==1)
@@ -721,6 +721,9 @@
// attack with hand - remove cell (if cover open) or interact with the APC
/obj/machinery/power/apc/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(!user)
return
if(usr == user && opened && (!issilicon(user)))
@@ -734,7 +737,6 @@
return
if((stat & MAINT) && !opened) //no board; no interface
return
- ..()
/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 289c78b712..94e5f4a28e 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -533,6 +533,9 @@ GLOBAL_LIST_INIT(cable_coil_recipes, list (new/datum/stack_recipe("cable restrai
add_atom_colour(item_color, FIXED_COLOUR_PRIORITY)
/obj/item/stack/cable_coil/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
var/obj/item/stack/cable_coil/new_cable = ..()
if(istype(new_cable))
new_cable.item_color = item_color
diff --git a/code/modules/power/floodlight.dm b/code/modules/power/floodlight.dm
index 74cecf0b1d..62abcdb440 100644
--- a/code/modules/power/floodlight.dm
+++ b/code/modules/power/floodlight.dm
@@ -95,6 +95,9 @@
. = ..()
/obj/machinery/power/floodlight/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
var/current = setting
if(current == 1)
current = light_setting_list.len
@@ -103,10 +106,6 @@
change_setting(current, user)
..()
-/obj/machinery/power/floodlight/attack_ai(mob/user)
- attack_hand(user)
- ..()
-
/obj/machinery/power/floodlight/obj_break(damage_flag)
if(!(flags_1 & NODECONSTRUCT_1))
playsound(loc, 'sound/effects/glassbr3.ogg', 100, 1)
diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm
index 4681eabe20..ce9d2de4db 100644
--- a/code/modules/power/generator.dm
+++ b/code/modules/power/generator.dm
@@ -123,12 +123,6 @@
lastgen -= power_output
..()
-/obj/machinery/power/generator/attack_hand(mob/user)
- if(..())
- user << browse(null, "window=teg")
- return
- interact(user)
-
/obj/machinery/power/generator/proc/get_menu(include_link = 1)
var/t = ""
if(!powernet)
@@ -161,15 +155,12 @@
return t
-/obj/machinery/power/generator/interact(mob/user)
-
- user.set_machine(src)
+/obj/machinery/power/generator/ui_interact(mob/user)
+ . = ..()
var/datum/browser/popup = new(user, "teg", "Thermo-Electric Generator", 460, 300)
popup.set_content(get_menu())
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
- return 1
-
/obj/machinery/power/generator/Topic(href, href_list)
if(..())
diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm
index cb7c9b1a69..29e4a38727 100644
--- a/code/modules/power/gravitygenerator.dm
+++ b/code/modules/power/gravitygenerator.dm
@@ -116,7 +116,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
power_channel = ENVIRON
sprite_number = 8
use_power = IDLE_POWER_USE
- interact_offline = TRUE
+ interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OFFLINE
var/on = TRUE
var/breaker = 1
var/list/parts = list()
@@ -219,12 +219,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne
return
return ..()
-
-/obj/machinery/gravity_generator/main/attack_hand(mob/user)
- if(!..())
- return interact(user)
-
-/obj/machinery/gravity_generator/main/interact(mob/user)
+/obj/machinery/gravity_generator/main/ui_interact(mob/user)
if(stat & BROKEN)
return
var/dat = "Gravity Generator Breaker: "
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index faad79664e..68ac434811 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -568,6 +568,9 @@
// if hands aren't protected and the light is on, burn the player
/obj/machinery/light/attack_hand(mob/living/carbon/human/user)
+ . = ..()
+ if(.)
+ return
user.changeNext_move(CLICK_CD_MELEE)
add_fingerprint(user)
diff --git a/code/modules/power/port_gen.dm b/code/modules/power/port_gen.dm
index dc8e6e0793..cc4000fd42 100644
--- a/code/modules/power/port_gen.dm
+++ b/code/modules/power/port_gen.dm
@@ -17,6 +17,8 @@
var/base_icon = "portgen0"
var/datum/looping_sound/generator/soundloop
+ interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_UI_INTERACT | INTERACT_ATOM_REQUIRES_ANCHORED
+
/obj/machinery/power/port_gen/Initialize()
. = ..()
soundloop = new(list(src), active)
@@ -53,12 +55,6 @@
update_icon()
soundloop.stop()
-/obj/machinery/power/port_gen/attack_hand(mob/user)
- if(..())
- return
- if(!anchored)
- return
-
/obj/machinery/power/port_gen/examine(mob/user)
..()
to_chat(user, "It is[!active?"n't":""] running.")
@@ -211,28 +207,20 @@
obj_flags |= EMAGGED
emp_act(EMP_HEAVY)
-/obj/machinery/power/port_gen/pacman/attack_hand(mob/user)
- ..()
- if (!anchored)
- return
-
- interact(user)
-
/obj/machinery/power/port_gen/pacman/attack_ai(mob/user)
interact(user)
/obj/machinery/power/port_gen/pacman/attack_paw(mob/user)
interact(user)
-/obj/machinery/power/port_gen/pacman/interact(mob/user)
+/obj/machinery/power/port_gen/pacman/ui_interact(mob/user)
+ . = ..()
if (get_dist(src, user) > 1 )
if(!isAI(user))
user.unset_machine()
user << browse(null, "window=port_gen")
return
- user.set_machine(src)
-
var/dat = text("[name]
")
if (active)
dat += text("Generator: On
")
diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm
index f88e713dda..d458fbf7e2 100644
--- a/code/modules/power/rtg.dm
+++ b/code/modules/power/rtg.dm
@@ -46,11 +46,11 @@
return
return ..()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/machinery/power/rtg/attack_hand(mob/user)
if(user.a_intent == INTENT_GRAB && user_buckle_mob(user.pulling, user, check_loc = 0))
return
- ..()
-
+ . = ..()
/obj/machinery/power/rtg/advanced
desc = "An advanced RTG capable of moderating isotope decay, increasing power output but reducing lifetime. It uses plasma-fueled radiation collectors to increase output even further."
diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm
index bd9901460a..fcbb366187 100644
--- a/code/modules/power/singularity/collector.dm
+++ b/code/modules/power/singularity/collector.dm
@@ -69,7 +69,8 @@
last_power-=bitcoins_mined
/obj/machinery/power/rad_collector/attack_hand(mob/user)
- if(..())
+ . = ..()
+ if(.)
return
if(anchored)
if(!src.locked)
diff --git a/code/modules/power/singularity/containment_field.dm b/code/modules/power/singularity/containment_field.dm
index 70772f74f9..c8153b4a89 100644
--- a/code/modules/power/singularity/containment_field.dm
+++ b/code/modules/power/singularity/containment_field.dm
@@ -9,6 +9,8 @@
density = FALSE
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
use_power = NO_POWER_USE
+ interaction_flags_atom = NONE
+ interaction_flags_machine = NONE
light_range = 4
layer = ABOVE_OBJ_LAYER
var/obj/machinery/field/generator/FG1 = null
@@ -19,6 +21,7 @@
FG2.fields -= src
return ..()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/machinery/field/containment/attack_hand(mob/user)
if(get_dist(src, user) > 1)
return FALSE
diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm
index fd1989ebf8..d6a27f1483 100644
--- a/code/modules/power/singularity/emitter.dm
+++ b/code/modules/power/singularity/emitter.dm
@@ -23,6 +23,7 @@
var/shot_number = 0
var/state = 0
var/locked = FALSE
+ var/allow_switch_interact = TRUE
var/projectile_type = /obj/item/projectile/beam/emitter
@@ -101,13 +102,13 @@
icon_state = initial(icon_state)
-/obj/machinery/power/emitter/attack_hand(mob/user)
- src.add_fingerprint(user)
+/obj/machinery/power/emitter/interact(mob/user)
+ add_fingerprint(user)
if(state == 2)
if(!powernet)
to_chat(user, "The emitter isn't connected to a wire!")
return 1
- if(!src.locked)
+ if(!locked && allow_switch_interact)
if(src.active==1)
src.active = 0
to_chat(user, "You turn off \the [src].")
diff --git a/code/modules/power/singularity/field_generator.dm b/code/modules/power/singularity/field_generator.dm
index d160209e0c..0a113859c3 100644
--- a/code/modules/power/singularity/field_generator.dm
+++ b/code/modules/power/singularity/field_generator.dm
@@ -65,6 +65,9 @@ field_generator power level display
calc_power()
/obj/machinery/field/generator/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(state == FG_WELDED)
if(get_dist(src, user) <= 1)//Need to actually touch the thing to turn it on
if(active >= FG_CHARGING)
diff --git a/code/modules/power/singularity/generator.dm b/code/modules/power/singularity/generator.dm
index 4b4ec71eb6..4cc1143c02 100644
--- a/code/modules/power/singularity/generator.dm
+++ b/code/modules/power/singularity/generator.dm
@@ -17,10 +17,11 @@
var/energy = 0
var/creation_type = /obj/singularity
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/machinery/the_singularitygen/attack_hand(mob/user)
if(user.a_intent == INTENT_GRAB && user_buckle_mob(user.pulling, user, check_loc = 0))
return
- ..()
+ . = ..()
/obj/machinery/the_singularitygen/attackby(obj/item/W, mob/user, params)
if(istype(W, /obj/item/wrench))
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index f6b785b3e1..dc6c1c649a 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -93,11 +93,10 @@
/proc/cult_ending_helper(var/no_explosion = 0)
Cinematic(CINEMATIC_CULT,world,CALLBACK(GLOBAL_PROC,.ending_helper))
-
+//ATTACK GHOST IGNORING PARENT RETURN VALUE
/obj/singularity/narsie/large/attack_ghost(mob/dead/observer/user as mob)
makeNewConstruct(/mob/living/simple_animal/hostile/construct/harvester, user, cultoverride = TRUE, loc_override = src.loc)
-
/obj/singularity/narsie/process()
if(clashing)
return
@@ -128,7 +127,7 @@
if(M.stat == CONSCIOUS)
if(!iscultist(M))
to_chat(M, "You feel conscious thought crumble away in an instant as you gaze upon [src.name]...")
- M.apply_effect(60, STUN)
+ M.apply_effect(60, EFFECT_STUN)
/obj/singularity/narsie/consume(atom/A)
diff --git a/code/modules/power/singularity/particle_accelerator/particle_control.dm b/code/modules/power/singularity/particle_accelerator/particle_control.dm
index 9d5ff2dd81..4d4eb73687 100644
--- a/code/modules/power/singularity/particle_accelerator/particle_control.dm
+++ b/code/modules/power/singularity/particle_accelerator/particle_control.dm
@@ -35,6 +35,9 @@
return ..()
/obj/machinery/particle_accelerator/control_box/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
if(construction_state == PA_CONSTRUCTION_COMPLETE)
interact(user)
else if(construction_state == PA_CONSTRUCTION_PANEL_OPEN)
@@ -223,13 +226,13 @@
return 1
-/obj/machinery/particle_accelerator/control_box/interact(mob/user)
+/obj/machinery/particle_accelerator/control_box/ui_interact(mob/user)
+ . = ..()
if((get_dist(src, user) > 1) || (stat & (BROKEN|NOPOWER)))
if(!issilicon(user))
user.unset_machine()
user << browse(null, "window=pacontrol")
return
- user.set_machine(src)
var/dat = ""
dat += "Close
"
diff --git a/code/modules/power/singularity/singularity.dm b/code/modules/power/singularity/singularity.dm
index ad83fb31a2..2a7fd37c65 100644
--- a/code/modules/power/singularity/singularity.dm
+++ b/code/modules/power/singularity/singularity.dm
@@ -58,10 +58,9 @@
last_failed_movement = direct
return 0
-
/obj/singularity/attack_hand(mob/user)
consume(user)
- return 1
+ return TRUE
/obj/singularity/attack_paw(mob/user)
consume(user)
@@ -414,7 +413,7 @@
to_chat(H, "You look directly into the [src.name], good thing you had your protective eyewear on!")
return
- M.apply_effect(60, STUN)
+ M.apply_effect(60, EFFECT_STUN)
M.visible_message("[M] stares blankly at the [src.name]!", \
"You look directly into the [src.name] and feel weak.")
return
diff --git a/code/modules/power/solar.dm b/code/modules/power/solar.dm
index 81cf66c26a..f4c11009d1 100644
--- a/code/modules/power/solar.dm
+++ b/code/modules/power/solar.dm
@@ -189,10 +189,6 @@
var/tracker = 0
var/glass_type = null
-/obj/item/solar_assembly/attack_hand(mob/user)
- if(!anchored && isturf(loc)) // You can't pick it up
- ..()
-
// Give back the glass type we were supplied with
/obj/item/solar_assembly/proc/give_glass(device_broken)
if(device_broken)
@@ -430,7 +426,7 @@
A.anchored = TRUE
qdel(src)
else if(user.a_intent != INTENT_HARM && !(I.flags_1 & NOBLUDGEON_1))
- src.attack_hand(user)
+ attack_hand(user)
else
return ..()
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 5ed6b84a18..6aed2f241b 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -512,6 +512,9 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_shard)
return
/obj/machinery/power/supermatter_shard/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
dust_mob(user, cause = "hand")
/obj/machinery/power/supermatter_shard/proc/dust_mob(mob/living/nom, vis_msg, mob_msg, cause)
@@ -621,7 +624,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_shard)
var/atom/movable/pulled_object = P
if(ishuman(P))
var/mob/living/carbon/human/H = P
- H.apply_effect(40, KNOCKDOWN, 0)
+ H.apply_effect(40, EFFECT_KNOCKDOWN, 0)
if(pulled_object && !pulled_object.anchored && !ishuman(P))
step_towards(pulled_object,center)
step_towards(pulled_object,center)
diff --git a/code/modules/power/tesla/coil.dm b/code/modules/power/tesla/coil.dm
index 1000fa5c8b..32499ace2f 100644
--- a/code/modules/power/tesla/coil.dm
+++ b/code/modules/power/tesla/coil.dm
@@ -25,7 +25,7 @@
/obj/machinery/power/tesla_coil/Initialize()
. = ..()
-// wires = new /datum/wires/tesla_coil(src) //CITADEL EDIT, Kevinz you cheaty fuccboi.
+ // wires = new /datum/wires/tesla_coil(src) //CITADEL EDIT, Kevinz you cheaty fuccboi.
linked_techweb = SSresearch.science_tech
/obj/machinery/power/tesla_coil/RefreshParts()
@@ -71,21 +71,23 @@
return ..()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/machinery/power/tesla_coil/attack_hand(mob/user)
if(user.a_intent == INTENT_GRAB && user_buckle_mob(user.pulling, user, check_loc = 0))
- return
- ..()
+ return ..()
/obj/machinery/power/tesla_coil/tesla_act(var/power)
if(anchored && !panel_open)
obj_flags |= BEING_SHOCKED
+ //don't lose arc power when it's not connected to anything
+ //please place tesla coils all around the station to maximize effectiveness
var/power_produced = powernet ? power / power_loss : power
add_avail(power_produced*input_power_multiplier)
flick("coilhit", src)
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
tesla_zap(src, 5, power_produced)
if(istype(linked_techweb))
- linked_techweb.research_points += min(power_produced, 1)
+ linked_techweb.research_points += min(power_produced, 1) // x4 coils = ~240/m point bonus for R&D
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
tesla_buckle_check(power)
else
@@ -120,7 +122,7 @@
playsound(src.loc, 'sound/magic/lightningshock.ogg', 100, 1, extrarange = 5)
tesla_zap(src, 5, power_produced)
if(istype(linked_techweb))
- linked_techweb.research_points += min(power_produced, 3) // 4 coils makes ~720/m bonus for R&D,
+ linked_techweb.research_points += min(power_produced, 3) // x4 coils with a pulse per second or so = ~720/m point bonus for R&D
addtimer(CALLBACK(src, .proc/reset_shocked), 10)
tesla_buckle_check(power)
else
@@ -178,10 +180,11 @@
return ..()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/machinery/power/grounding_rod/attack_hand(mob/user)
if(user.a_intent == INTENT_GRAB && user_buckle_mob(user.pulling, user, check_loc = 0))
return
- ..()
+ . = ..()
/obj/machinery/power/grounding_rod/tesla_act(var/power)
if(anchored && !panel_open)
diff --git a/code/modules/power/turbine.dm b/code/modules/power/turbine.dm
index d7f78635b0..7e73c1c9c1 100644
--- a/code/modules/power/turbine.dm
+++ b/code/modules/power/turbine.dm
@@ -227,13 +227,6 @@
updateDialog()
-/obj/machinery/power/turbine/attack_hand(mob/user)
-
- if(..())
- return
-
- interact(user)
-
/obj/machinery/power/turbine/attackby(obj/item/I, mob/user, params)
if(default_deconstruction_screwdriver(user, initial(icon_state), initial(icon_state), I))
return
@@ -255,7 +248,7 @@
default_deconstruction_crowbar(I)
-/obj/machinery/power/turbine/interact(mob/user)
+/obj/machinery/power/turbine/ui_interact(mob/user)
if(!Adjacent(user) || (stat & (NOPOWER|BROKEN)) && !issilicon(user))
user.unset_machine(src)
@@ -321,12 +314,6 @@
else
compressor = locate(/obj/machinery/power/compressor) in range(5, src)
-/obj/machinery/computer/turbine_computer/attack_hand(var/mob/user as mob)
- if(..())
- return
-
- ui_interact(user)
-
/obj/machinery/computer/turbine_computer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
datum/tgui/master_ui = null, datum/ui_state/state = GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm
index f83a2d9edd..2c36f14245 100644
--- a/code/modules/projectiles/guns/ballistic.dm
+++ b/code/modules/projectiles/guns/ballistic.dm
@@ -98,13 +98,13 @@
w_class += S.w_class //so pistols do not fit in pockets when suppressed
update_icon()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/gun/ballistic/attack_hand(mob/user)
if(loc == user)
if(suppressed && can_unsuppress)
var/obj/item/suppressor/S = suppressed
if(!user.is_holding(src))
- ..()
- return
+ return ..()
to_chat(user, "You unscrew [suppressed] from [src].")
user.put_in_hands(suppressed)
fire_sound = S.oldsound
@@ -112,7 +112,7 @@
suppressed = null
update_icon()
return
- ..()
+ return ..()
/obj/item/gun/ballistic/attack_self(mob/living/user)
var/obj/item/ammo_casing/AC = chambered //Find chambered round
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index f4194f529f..a174874686 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -320,7 +320,7 @@
..()
update_icon()
-
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/gun/ballistic/automatic/l6_saw/attack_hand(mob/user)
if(loc != user)
..()
@@ -337,7 +337,6 @@
to_chat(user, "You remove the magazine from [src].")
playsound(user, 'sound/weapons/magout.ogg', 60, 1)
-
/obj/item/gun/ballistic/automatic/l6_saw/attackby(obj/item/A, mob/user, params)
if(!cover_open && istype(A, mag_type))
to_chat(user, "[src]'s cover is closed! You can't insert a new mag.")
diff --git a/code/modules/projectiles/guns/ballistic/laser_gatling.dm b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
index 48bda4a86e..cc719f98ee 100644
--- a/code/modules/projectiles/guns/ballistic/laser_gatling.dm
+++ b/code/modules/projectiles/guns/ballistic/laser_gatling.dm
@@ -29,6 +29,7 @@
/obj/item/minigunpack/process()
overheat = max(0, overheat - heat_diffusion)
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/minigunpack/attack_hand(var/mob/living/carbon/user)
if(src.loc == user)
if(!armed)
@@ -57,6 +58,7 @@
user.dropItemToGround(gun, TRUE)
/obj/item/minigunpack/MouseDrop(atom/over_object)
+ . = ..()
if(armed)
return
if(iscarbon(usr))
diff --git a/code/modules/projectiles/projectile/magic/spellcard.dm b/code/modules/projectiles/projectile/magic/spellcard.dm
index 67e3ad374e..1b8f326573 100644
--- a/code/modules/projectiles/projectile/magic/spellcard.dm
+++ b/code/modules/projectiles/projectile/magic/spellcard.dm
@@ -1,6 +1,6 @@
-/obj/item/projectile/spellcard
- name = "enchanted card"
- desc = "A piece of paper enchanted to give it extreme durability and stiffness, along with a very hot burn to anyone unfortunate enough to get hit by a charged one."
- icon_state = "spellcard"
- damage_type = BURN
- damage = 2
+/obj/item/projectile/spellcard
+ name = "enchanted card"
+ desc = "A piece of paper enchanted to give it extreme durability and stiffness, along with a very hot burn to anyone unfortunate enough to get hit by a charged one."
+ icon_state = "spellcard"
+ damage_type = BURN
+ damage = 2
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index d49c4a6fa0..5fcb554c7d 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -51,7 +51,7 @@
var/last_tick = 1
var/addiction_tick = 1
var/list/datum/reagent/addiction_list = new/list()
- var/flags
+ var/reagents_holder_flags
/datum/reagents/New(maximum=100)
maximum_volume = maximum
@@ -315,9 +315,9 @@
/datum/reagents/proc/set_reacting(react = TRUE)
if(react)
- flags &= ~(REAGENT_NOREACT)
+ reagents_holder_flags &= ~(REAGENT_NOREACT)
else
- flags |= REAGENT_NOREACT
+ reagents_holder_flags |= REAGENT_NOREACT
/datum/reagents/proc/conditional_update_move(atom/A, Running = 0)
var/list/cached_reagents = reagent_list
@@ -337,7 +337,7 @@
var/list/cached_reagents = reagent_list
var/list/cached_reactions = GLOB.chemical_reactions_list
var/datum/cached_my_atom = my_atom
- if(flags & REAGENT_NOREACT)
+ if(reagents_holder_flags & REAGENT_NOREACT)
return //Yup, no reactions here. No siree.
var/reaction_occurred = 0
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index ca88930881..e02a228178 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -7,7 +7,7 @@
icon_state = "dispenser"
use_power = IDLE_POWER_USE
idle_power_usage = 40
- interact_offline = TRUE
+ interaction_flags_machine = INTERACT_MACHINE_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OFFLINE
resistance_flags = FIRE_PROOF | ACID_PROOF
circuit = /obj/item/circuitboard/machine/chem_dispenser
var/cell_type = /obj/item/stock_parts/cell/high
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index ed19a87dcf..a6a89d3b90 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -20,7 +20,6 @@
/obj/machinery/chem_master/Initialize()
create_reagents(100)
- add_overlay("waitlight")
. = ..()
/obj/machinery/chem_master/Destroy()
@@ -54,6 +53,9 @@
bottle = null
/obj/machinery/chem_master/update_icon()
+ cut_overlays()
+ if (stat & BROKEN)
+ add_overlay("waitlight")
if(beaker)
icon_state = "mixer1"
else
@@ -300,7 +302,7 @@
adjust_item_drop_location(P)
reagents.trans_to(P, vol_part)
. = TRUE
-
+ //CITADEL ADD Hypospray Vials
if("createvial")
var/many = params["many"]
if(reagents.total_volume == 0)
@@ -328,7 +330,7 @@
adjust_item_drop_location(V)
reagents.trans_to(V, vol_part)
. = TRUE
-
+ //END CITADEL ADDITIONS
if("analyze")
var/datum/reagent/R = GLOB.chemical_reagents_list[params["id"]]
if(R)
diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm
index c6ca72ad4a..5a9efe56d1 100644
--- a/code/modules/reagents/chemistry/machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry/machinery/pandemic.dm
@@ -122,9 +122,9 @@
icon_state = "mixer[(beaker) ? "1" : "0"][powered() ? "" : "_nopower"]"
if(wait)
- cut_overlays()
- else
add_overlay("waitlight")
+ else
+ cut_overlays()
/obj/machinery/computer/pandemic/proc/eject_beaker()
if(beaker)
diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
index 5930260dab..3cdaaa0f5f 100644
--- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
+++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm
@@ -131,17 +131,8 @@
updateUsrDialog()
return FALSE
-/obj/machinery/reagentgrinder/attack_paw(mob/user)
- return attack_hand(user)
-
-/obj/machinery/reagentgrinder/attack_ai(mob/user)
- return FALSE
-
-/obj/machinery/reagentgrinder/attack_hand(mob/user)
- user.set_machine(src)
- interact(user)
-
-/obj/machinery/reagentgrinder/interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave
+/obj/machinery/reagentgrinder/ui_interact(mob/user) // The microwave Menu //I am reasonably certain that this is not a microwave
+ . = ..()
var/is_chamber_empty = FALSE
var/is_beaker_ready = FALSE
var/processing_chamber = ""
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 952678caf7..821fa0510c 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -231,7 +231,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/bilk/on_mob_life(mob/living/M)
if(M.getBruteLoss() && prob(10))
- M.heal_bodypart_damage(1,0, 0)
+ M.heal_bodypart_damage(1)
. = 1
return ..() || .
@@ -1085,7 +1085,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/bananahonk/on_mob_life(mob/living/M)
if((ishuman(M) && M.job in list("Clown") ) || ismonkey(M))
- M.heal_bodypart_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1)
. = 1
return ..() || .
@@ -1403,7 +1403,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/quadruple_sec/on_mob_life(mob/living/M)
if(M.mind && M.mind.assigned_role in list("Security Officer", "Detective", "Head of Security", "Warden", "Lawyer")) //Securidrink in line with the screwderiver for engineers or nothing for mimes.
- M.heal_bodypart_damage (1,1,1)
+ M.heal_bodypart_damage(1, 1)
M.adjustBruteLoss(-2,0)
. = 1
return ..()
@@ -1421,7 +1421,7 @@ All effects don't start immediately, but rather get worse over time; the rate is
/datum/reagent/consumable/ethanol/quintuple_sec/on_mob_life(mob/living/M)
if(M.mind && M.mind.assigned_role in list("Security Officer", "Detective", "Head of Security", "Warden", "Lawyer")) //Securidrink in line with the screwderiver for engineers or nothing for mimes but STRONG..
- M.heal_bodypart_damage (2,2,2)
+ M.heal_bodypart_damage(2,2,2)
M.adjustBruteLoss(-5,0)
M.adjustOxyLoss(-5,0)
M.adjustFireLoss(-5,0)
diff --git a/code/modules/reagents/chemistry/reagents/food_reagents.dm b/code/modules/reagents/chemistry/reagents/food_reagents.dm
index 45838de5e7..4c475fd4c4 100644
--- a/code/modules/reagents/chemistry/reagents/food_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/food_reagents.dm
@@ -685,4 +685,4 @@
description = "The sorrow and melancholy of a thousand bereaved clowns, forever denied their Honkmechs."
nutriment_factor = 5 * REAGENTS_METABOLISM
color = "#eef442" // rgb: 238, 244, 66
- taste_description = "mournful honking"
+ taste_description = "mournful honking"
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
index f6000873f8..b4abc2e4b1 100644
--- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm
@@ -40,7 +40,7 @@
M.setCloneLoss(0, 0)
M.setOxyLoss(0, 0)
M.radiation = 0
- M.heal_bodypart_damage(5,5, 0)
+ M.heal_bodypart_damage(5,5)
M.adjustToxLoss(-5, 0, TRUE)
M.hallucination = 0
M.setBrainLoss(0)
@@ -197,7 +197,7 @@
/datum/reagent/medicine/rezadone/on_mob_life(mob/living/M)
M.setCloneLoss(0) //Rezadone is almost never used in favor of cryoxadone. Hopefully this will change that.
- M.heal_bodypart_damage(1,1, 0)
+ M.heal_bodypart_damage(1,1)
M.remove_trait(TRAIT_DISFIGURED, TRAIT_GENERIC)
..()
. = 1
@@ -1129,7 +1129,7 @@
can_synth = FALSE
/datum/reagent/medicine/miningnanites/on_mob_life(mob/living/M)
- M.heal_bodypart_damage(5,5, 0)
+ M.heal_bodypart_damage(5,5)
..()
. = 1
diff --git a/code/modules/reagents/chemistry/reagents/other_reagents.dm b/code/modules/reagents/chemistry/reagents/other_reagents.dm
index 7f3067cdf2..9eb81e918f 100644
--- a/code/modules/reagents/chemistry/reagents/other_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/other_reagents.dm
@@ -785,7 +785,7 @@
taste_description = "chlorine"
/datum/reagent/chlorine/on_mob_life(mob/living/M)
- M.take_bodypart_damage(1*REM, 0, 0)
+ M.take_bodypart_damage(1*REM, 0, 0, 0)
. = 1
..()
@@ -849,7 +849,7 @@
taste_description = "the colour blue and regret"
/datum/reagent/radium/on_mob_life(mob/living/M)
- M.apply_effect(2*REM/M.metabolism_efficiency,IRRADIATE,0)
+ M.apply_effect(2*REM/M.metabolism_efficiency,EFFECT_IRRADIATE,0)
..()
/datum/reagent/radium/reaction_turf(turf/T, reac_volume)
@@ -932,7 +932,7 @@
taste_description = "the inside of a reactor"
/datum/reagent/uranium/on_mob_life(mob/living/M)
- M.apply_effect(1/M.metabolism_efficiency,IRRADIATE,0)
+ M.apply_effect(1/M.metabolism_efficiency,EFFECT_IRRADIATE,0)
..()
/datum/reagent/uranium/reaction_turf(turf/T, reac_volume)
diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
index e77d87c5b6..2746f311f8 100644
--- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm
@@ -50,7 +50,7 @@
/datum/reagent/toxin/mutagen/on_mob_life(mob/living/carbon/M)
if(istype(M))
- M.apply_effect(5,IRRADIATE,0)
+ M.apply_effect(5,EFFECT_IRRADIATE,0)
return ..()
/datum/reagent/toxin/plasma
@@ -128,7 +128,7 @@
M.adjustToxLoss(rand(20,60)*REM, 0)
. = 1
else if(prob(40))
- M.heal_bodypart_damage(5*REM,0, 0)
+ M.heal_bodypart_damage(5*REM)
. = 1
..()
@@ -843,9 +843,9 @@
acidpwr = 42.0
/datum/reagent/toxin/acid/fluacid/on_mob_life(mob/living/M)
- M.adjustFireLoss(current_cycle/10, 0) // I rode a tank, held a general's rank
- . = 1 // When the blitzkrieg raged and the bodies stank
- ..() // Pleased to meet you, hope you guess my name
+ M.adjustFireLoss(current_cycle/10, 0)
+ . = 1
+ ..()
/datum/reagent/toxin/peaceborg/confuse
name = "Dizzying Solution"
@@ -874,7 +874,7 @@
/datum/reagent/toxin/peaceborg/tire/on_mob_life(mob/living/M)
var/healthcomp = (100 - M.health) //DOES NOT ACCOUNT FOR ADMINBUS THINGS THAT MAKE YOU HAVE MORE THAN 200/210 HEALTH, OR SOMETHING OTHER THAN A HUMAN PROCESSING THIS.
- if(M.staminaloss < (45 - healthcomp)) //At 50 health you would have 200 - 150 health meaning 50 compensation. 60 - 50 = 10, so would only do 10-19 stamina.)
+ if(M.getStaminaLoss() < (45 - healthcomp)) //At 50 health you would have 200 - 150 health meaning 50 compensation. 60 - 50 = 10, so would only do 10-19 stamina.)
M.adjustStaminaLoss(10)
if(prob(30))
to_chat(M, "You should sit down and take a rest...")
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index 23a81a5950..13753db9eb 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -611,14 +611,14 @@
/datum/chemical_reaction/slime/slimeRNG/on_reaction(datum/reagents/holder, created_volume)
if(created_volume >= 5)
- var/obj/item/grenade/clusterbuster/slime/S = new (holder.my_atom.loc)
+ var/obj/item/grenade/clusterbuster/slime/S = new (get_turf(holder.my_atom))
S.visible_message("Infused with plasma, the core begins to expand uncontrollably!")
S.icon_state = "[S.base_state]_active"
S.active = TRUE
addtimer(CALLBACK(S, /obj/item/grenade.proc/prime), rand(15,60))
qdel(holder.my_atom) //deleto
else
- var/mob/living/simple_animal/slime/random/S = new (holder.my_atom.loc)
+ var/mob/living/simple_animal/slime/random/S = new (get_turf(holder.my_atom))
S.visible_message("Infused with plasma, the core begins to quiver and grow, and a new baby slime emerges from it!")
..()
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 62ea18dcd9..3e7cd539d0 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -36,8 +36,9 @@
mode = !mode
update_icon()
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/item/reagent_containers/syringe/attack_hand()
- ..()
+ . = ..()
update_icon()
/obj/item/reagent_containers/syringe/attack_paw(mob/user)
diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm
index f0c0ecfb68..4b4c786987 100644
--- a/code/modules/reagents/reagent_dispenser.dm
+++ b/code/modules/reagents/reagent_dispenser.dm
@@ -146,6 +146,9 @@
to_chat(user, "There are no paper cups left.")
/obj/structure/reagent_dispensers/water_cooler/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
if(!paper_cups)
to_chat(user, "There aren't any cups left!")
return
@@ -154,7 +157,6 @@
user.put_in_hands(S)
paper_cups--
-
/obj/structure/reagent_dispensers/beerkeg
name = "beer keg"
desc = "Beer is liquid bread, it's good for you..."
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index 89d859d36d..759c048ab6 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -1,6 +1,8 @@
//conveyor2 is pretty much like the original, except it supports corners, but not diverters.
//note that corner pieces transfer stuff clockwise when running forward, and anti-clockwise backwards.
+GLOBAL_LIST_EMPTY(conveyors_by_id)
+
/obj/machinery/conveyor
icon = 'icons/obj/recycling.dmi'
icon_state = "conveyor0"
@@ -44,11 +46,27 @@
icon_state = "conveyor[operating * verted]"
// create a conveyor
-/obj/machinery/conveyor/Initialize(mapload, newdir)
+/obj/machinery/conveyor/Initialize(mapload, newdir, newid)
. = ..()
if(newdir)
setDir(newdir)
+ if(newid)
+ id = newid
update_move_direction()
+ LAZYADD(GLOB.conveyors_by_id[id], src)
+
+/obj/machinery/conveyor/Destroy()
+ LAZYREMOVE(GLOB.conveyors_by_id[id], src)
+ . = ..()
+
+/obj/machinery/conveyor/vv_edit_var(var_name, var_value)
+ if (var_name == "id")
+ // if "id" is varedited, update our list membership
+ LAZYREMOVE(GLOB.conveyors_by_id[id], src)
+ . = ..()
+ LAZYADD(GLOB.conveyors_by_id[id], src)
+ else
+ return ..()
/obj/machinery/conveyor/proc/update_move_direction()
switch(dir)
@@ -146,9 +164,11 @@
// attack with hand, move pulled object onto conveyor
/obj/machinery/conveyor/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
user.Move_Pulled(src)
-
// make the conveyor broken
// also propagate inoperability to any connected conveyor with the same ID
/obj/machinery/conveyor/proc/broken()
@@ -198,29 +218,34 @@
var/id = "" // must match conveyor IDs to control them
- var/list/conveyors // the list of converyors that are controlled by this switch
anchored = TRUE
speed_process = TRUE
/obj/machinery/conveyor_switch/Initialize(mapload, newid)
- ..()
- if(!id)
+ . = ..()
+ if (newid)
id = newid
- update()
+ update_icon()
+ LAZYADD(GLOB.conveyors_by_id[id], src)
- return INITIALIZE_HINT_LATELOAD //for machines list
+/obj/machinery/conveyor_switch/Destroy()
+ LAZYREMOVE(GLOB.conveyors_by_id[id], src)
+ . = ..()
-/obj/machinery/conveyor_switch/LateInitialize()
- conveyors = list()
- for(var/obj/machinery/conveyor/C in GLOB.machines)
- if(C.id == id)
- conveyors += C
+/obj/machinery/conveyor_switch/vv_edit_var(var_name, var_value)
+ if (var_name == "id")
+ // if "id" is varedited, update our list membership
+ LAZYREMOVE(GLOB.conveyors_by_id[id], src)
+ . = ..()
+ LAZYADD(GLOB.conveyors_by_id[id], src)
+ else
+ return ..()
// update the icon depending on the position
-/obj/machinery/conveyor_switch/proc/update()
+/obj/machinery/conveyor_switch/update_icon()
if(position<0)
icon_state = "switch-rev"
else if(position>0)
@@ -237,13 +262,16 @@
return
operated = 0
- for(var/obj/machinery/conveyor/C in conveyors)
+ for(var/obj/machinery/conveyor/C in GLOB.conveyors_by_id[id])
C.operating = position
C.update_move_direction()
CHECK_TICK
// attack with hand, switch position
/obj/machinery/conveyor_switch/attack_hand(mob/user)
+ . = ..()
+ if(.)
+ return
add_fingerprint(user)
if(position == 0)
if(convdir) //is it a oneway switch
@@ -260,13 +288,12 @@
position = 0
operated = 1
- update()
+ update_icon()
// find any switches with same id as this one, and set their positions to match us
- for(var/obj/machinery/conveyor_switch/S in GLOB.machines)
- if(S.id == src.id)
- S.position = position
- S.update()
+ for(var/obj/machinery/conveyor_switch/S in GLOB.conveyors_by_id[id])
+ S.position = position
+ S.update_icon()
CHECK_TICK
/obj/machinery/conveyor_switch/attackby(obj/item/I, mob/user, params)
@@ -307,8 +334,7 @@
if(A == user.loc)
to_chat(user, "You cannot place a conveyor belt under yourself.")
return
- var/obj/machinery/conveyor/C = new/obj/machinery/conveyor(A,cdir)
- C.id = id
+ var/obj/machinery/conveyor/C = new/obj/machinery/conveyor(A, cdir, id)
transfer_fingerprints_to(C)
qdel(src)
diff --git a/code/modules/recycling/disposal/bin.dm b/code/modules/recycling/disposal/bin.dm
index 5b9212339a..99c2784ebf 100644
--- a/code/modules/recycling/disposal/bin.dm
+++ b/code/modules/recycling/disposal/bin.dm
@@ -9,7 +9,7 @@
armor = list("melee" = 25, "bullet" = 10, "laser" = 10, "energy" = 100, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
max_integrity = 200
resistance_flags = FIRE_PROOF
- interact_open = TRUE
+ interaction_flags_machine = INTERACT_MACHINE_OPEN
var/datum/gas_mixture/air_contents // internal reservoir
var/full_pressure = FALSE
var/pressure_charging = TRUE
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index a32f5bf576..a669f23dde 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -8,7 +8,7 @@
var/giftwrapped = FALSE
var/sortTag = 0
-/obj/structure/bigDelivery/attack_hand(mob/user)
+/obj/structure/bigDelivery/interact(mob/user)
playsound(src.loc, 'sound/items/poster_ripped.ogg', 50, 1)
qdel(src)
diff --git a/code/modules/research/designs/limbgrower_designs.dm b/code/modules/research/designs/limbgrower_designs.dm
index 6456b380b3..6b81427c32 100644
--- a/code/modules/research/designs/limbgrower_designs.dm
+++ b/code/modules/research/designs/limbgrower_designs.dm
@@ -40,4 +40,4 @@
build_type = LIMBGROWER
reagents_list = list("synthflesh" = 75)
build_path = /obj/item/melee/synthetic_arm_blade
- category = list("special")
\ No newline at end of file
+ category = list("other","emagged")
\ No newline at end of file
diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm
index c3f9f91430..21acdae01c 100644
--- a/code/modules/research/designs/weapon_designs.dm
+++ b/code/modules/research/designs/weapon_designs.dm
@@ -2,6 +2,42 @@
/////////////////Weapons/////////////////
/////////////////////////////////////////
+/datum/design/c38/sec
+ id = "sec_38"
+ build_type = PROTOLATHE
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/rubbershot/sec
+ id = "sec_rshot"
+ build_type = PROTOLATHE
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/shotgun_slug/sec
+ id = "sec_slug"
+ build_type = PROTOLATHE
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/buckshot_shell/sec
+ id = "sec_bshot"
+ build_type = PROTOLATHE
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/shotgun_dart/sec
+ id = "sec_dart"
+ build_type = PROTOLATHE
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
+/datum/design/incendiary_slug/sec
+ id = "sec_Islug"
+ build_type = PROTOLATHE
+ category = list("Ammo")
+ departmental_flags = DEPARTMENTAL_FLAG_SECURITY
+
/datum/design/pin_testing
name = "Test-Range Firing Pin"
desc = "This safety firing pin allows firearms to be operated within proximity to a firing range."
diff --git a/code/modules/research/experimentor.dm b/code/modules/research/experimentor.dm
index 0e66644c6f..2125d808ab 100644
--- a/code/modules/research/experimentor.dm
+++ b/code/modules/research/experimentor.dm
@@ -69,7 +69,6 @@
if(initial(tempCheck.icon_state) != null)
critical_items += I
-
/obj/machinery/rnd/experimentor/Initialize()
. = ..()
@@ -109,8 +108,7 @@
ejectItem()
. = ..(O)
-/obj/machinery/rnd/experimentor/attack_hand(mob/user)
- user.set_machine(src)
+/obj/machinery/rnd/experimentor/ui_interact(mob/user)
var/list/dat = list("")
if(!linked_console)
dat += "Scan for R&D Console"
diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm
index 6810b3a821..76712dd55e 100644
--- a/code/modules/research/machinery/_production.dm
+++ b/code/modules/research/machinery/_production.dm
@@ -2,7 +2,7 @@
name = "technology fabricator"
desc = "Makes researched and prototype items with materials and energy."
container_type = OPENCONTAINER
-
+ layer = BELOW_OBJ_LAYER
var/consoleless_interface = FALSE //Whether it can be used without a console.
var/efficiency_coeff = 1 //Materials needed / coeff = actual.
var/list/categories = list()
diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm
index 96903c93de..b8c539b587 100644
--- a/code/modules/research/rdconsole.dm
+++ b/code/modules/research/rdconsole.dm
@@ -1012,13 +1012,8 @@ doesn't have toxins access.
updateUsrDialog()
-/obj/machinery/computer/rdconsole/attack_hand(mob/user)
- if(..())
- return
- interact(user)
-
-/obj/machinery/computer/rdconsole/interact(mob/user)
- user.set_machine(src)
+/obj/machinery/computer/rdconsole/ui_interact(mob/user)
+ . = ..()
var/datum/browser/popup = new(user, "rndconsole", name, 900, 600)
popup.add_stylesheet("techwebs", 'html/browser/techwebs.css')
popup.set_content(generate_ui())
diff --git a/code/modules/research/rdmachines.dm b/code/modules/research/rdmachines.dm
index 0a8659c795..0ce53f0e07 100644
--- a/code/modules/research/rdmachines.dm
+++ b/code/modules/research/rdmachines.dm
@@ -13,7 +13,6 @@
var/console_link = TRUE //allow console link.
var/requires_console = TRUE
var/disabled = FALSE
- var/shocked = FALSE
var/obj/machinery/computer/rdconsole/linked_console
var/obj/item/loaded_item = null //the item loaded inside the machine (currently only used by experimentor and destructive analyzer)
@@ -39,17 +38,7 @@
else
return FALSE
-/obj/machinery/rnd/attack_hand(mob/user)
- if(shocked)
- if(shock(user,50))
- return
- if(panel_open)
- wires.interact(user)
-
/obj/machinery/rnd/attackby(obj/item/O, mob/user, params)
- if (shocked)
- if(shock(user,50))
- return TRUE
if (default_deconstruction_screwdriver(user, "[initial(icon_state)]_t", initial(icon_state), O))
if(linked_console)
disconnect_console()
diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm
index 833bcfaeae..98da69b646 100644
--- a/code/modules/research/server.dm
+++ b/code/modules/research/server.dm
@@ -80,13 +80,6 @@
env.merge(removed)
air_update_turf()
-/obj/machinery/rnd/server/attack_hand(mob/user as mob) // I guess only exists to stop ninjas or hell does it even work I dunno. See also ninja gloves.
- if (disabled)
- return
- if (shocked)
- shock(user,50)
- return
-
/proc/fix_noid_research_servers()
var/list/no_id_servers = list()
var/list/server_ids = list()
@@ -138,10 +131,8 @@
updateUsrDialog()
return
-/obj/machinery/computer/rdservercontrol/attack_hand(mob/user)
- if(..())
- return
- user.set_machine(src)
+/obj/machinery/computer/rdservercontrol/ui_interact(mob/user)
+ . = ..()
var/dat = ""
switch(screen)
@@ -149,8 +140,7 @@
dat += "Connected Servers:
"
for(var/obj/machinery/rnd/server/S in GLOB.machines)
- dat += "[S.name] || "
- dat += "
"
+ dat += "[S.name]
"
//Mining status here
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index ca026b04a4..24dee05559 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -9,7 +9,8 @@
description = "NT default research technologies."
design_ids = list("basic_matter_bin", "basic_cell", "basic_scanning", "basic_capacitor", "basic_micro_laser", "micro_mani",
"destructive_analyzer", "circuit_imprinter", "experimentor", "rdconsole", "design_disk", "tech_disk", "rdserver", "rdservercontrol", "mechfab",
- "space_heater","xlarge_beaker") //Default research tech, prevents bricking
+ "space_heater", "xlarge_beaker", "sec_rshot", "sec_bshot", "sec_slug", "sec_Islug", "sec_dart", "sec_38") //Default research tech, prevents bricking
+
/////////////////////////Biotech/////////////////////////
/datum/techweb_node/biotech
diff --git a/code/modules/research/xenobiology/crossbreeding/_corecross.dm b/code/modules/research/xenobiology/crossbreeding/_corecross.dm
new file mode 100644
index 0000000000..e735139426
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_corecross.dm
@@ -0,0 +1,182 @@
+//////////////////////////////////////////////
+////////// SLIME CROSSBREEDS //////////
+//////////////////////////////////////////////
+// A system of combining two extract types. //
+// Performed by feeding a slime 20 of an //
+// extract color. //
+//////////////////////////////////////////////
+/*==========================================*\
+To add a crossbreed:
+ The file name is automatically selected
+ by the crossbreeding effect, which uses
+ the format slimecross/[modifier]/[color].
+
+ If a crossbreed doesn't exist, don't
+ worry. If no file is found at that
+ location, it will simple display that
+ the crossbreed was too unstable.
+
+ As a result, do not feel the need to
+ try to add all of the crossbred
+ effects at once, if you're here and
+ trying to make a new slime type. Just
+ get your slimetype in the codebase and
+ get around to the crossbreeds eventually!
+\*==========================================*/
+
+/obj/item/slimecross //The base type for crossbred extracts. Mostly here for posterity, and to set base case things.
+ name = "crossbred slime extract"
+ desc = "An extremely potent slime extract, formed through crossbreeding."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "base"
+ var/colour = "null"
+ var/effect = "null"
+ force = 0
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 0
+ throw_speed = 3
+ throw_range = 6
+
+/obj/item/slimecross/Initialize()
+ ..()
+ name = colour + " " + name
+ var/itemcolor = "#FFFFFF"
+ switch(colour)
+ if("orange")
+ itemcolor = "#FFA500"
+ if("purple")
+ itemcolor = "#B19CD9"
+ if("blue")
+ itemcolor = "#ADD8E6"
+ if("metal")
+ itemcolor = "#7E7E7E"
+ if("yellow")
+ itemcolor = "#FFFF00"
+ if("dark purple")
+ itemcolor = "#551A8B"
+ if("dark blue")
+ itemcolor = "#0000FF"
+ if("silver")
+ itemcolor = "#D3D3D3"
+ if("bluespace")
+ itemcolor = "#32CD32"
+ if("sepia")
+ itemcolor = "#704214"
+ if("cerulean")
+ itemcolor = "#2956B2"
+ if("pyrite")
+ itemcolor = "#FAFAD2"
+ if("red")
+ itemcolor = "#FF0000"
+ if("green")
+ itemcolor = "#00FF00"
+ if("pink")
+ itemcolor = "#FF69B4"
+ if("gold")
+ itemcolor = "#FFD700"
+ if("oil")
+ itemcolor = "#505050"
+ if("black")
+ itemcolor = "#000000"
+ if("light pink")
+ itemcolor = "#FFB6C1"
+ if("adamantine")
+ itemcolor = "#008B8B"
+ add_atom_colour(itemcolor, FIXED_COLOUR_PRIORITY)
+
+/obj/item/slimecrossbeaker //To be used as a result for extract reactions that make chemicals.
+ name = "result extract"
+ desc = "You shouldn't see this."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "base"
+ var/del_on_empty = TRUE
+ container_type = INJECTABLE | DRAWABLE
+ var/list/list_reagents
+
+/obj/item/slimecrossbeaker/Initialize()
+ ..()
+ create_reagents(50)
+ if(list_reagents)
+ for(var/reagent in list_reagents)
+ reagents.add_reagent(reagent, list_reagents[reagent])
+ if(del_on_empty)
+ START_PROCESSING(SSobj,src)
+
+/obj/item/slimecrossbeaker/Destroy()
+ STOP_PROCESSING(SSobj,src)
+ return ..()
+
+/obj/item/slimecrossbeaker/process()
+ if(!reagents.total_volume)
+ visible_message("[src] has been drained completely, and melts away.")
+ qdel(src)
+
+/obj/item/slimecrossbeaker/bloodpack //Pack of 50u blood. Deletes on empty.
+ name = "blood extract"
+ desc = "A sphere of liquid blood, somehow managing to stay together."
+ color = "#FF0000"
+ list_reagents = list("blood" = 50)
+
+/obj/item/slimecrossbeaker/pax //5u synthpax.
+ name = "peace-inducing extract"
+ desc = "A small blob of synthetic pax."
+ color = "#FFCCCC"
+ list_reagents = list("synthpax" = 5)
+
+/obj/item/slimecrossbeaker/omnizine //15u omnizine.
+ name = "healing extract"
+ desc = "A gelatinous extract of pure omnizine."
+ color = "#FF00FF"
+ list_reagents = list("omnizine" = 15)
+
+/obj/item/slimecrossbeaker/autoinjector //As with the above, but automatically injects whomever it is used on with contents.
+ container_type = DRAWABLE //Cannot be refilled, since it's basically an autoinjector!
+ var/ignore_flags = FALSE
+ var/self_use_only = FALSE
+
+/obj/item/slimecrossbeaker/autoinjector/attack(mob/living/M, mob/user)
+ if(!reagents.total_volume)
+ to_chat(user, "[src] is empty!")
+ return
+ if(!iscarbon(M))
+ return
+ if(self_use_only && M != user)
+ to_chat(user, "This can only be used on yourself.")
+ return
+ if(reagents.total_volume && (ignore_flags || M.can_inject(user, 1)))
+ reagents.trans_to(M, reagents.total_volume)
+ if(user != M)
+ to_chat(M, "[user] presses [src] against you!")
+ to_chat(user, "You press [src] against [M], injecting them.")
+ else
+ to_chat(user, "You press [src] against yourself, and it flattens against you!")
+ else
+ to_chat(user, "There's no place to stick [src]!")
+
+/obj/item/slimecrossbeaker/autoinjector/regenpack
+ ignore_flags = TRUE //It is, after all, intended to heal.
+ name = "mending solution"
+ desc = "A strange glob of sweet-smelling semifluid, which seems to stick to skin rather easily."
+ color = "#FF00FF"
+ list_reagents = list("regen_jelly" = 20)
+
+/obj/item/slimecrossbeaker/autoinjector/slimejelly //Primarily for slimepeople, but you do you.
+ self_use_only = TRUE
+ ignore_flags = TRUE
+ name = "slime jelly bubble"
+ desc = "A sphere of slime jelly. It seems to stick to your skin, but avoids other surfaces."
+ color = "#00FF00"
+ list_reagents = list("slimejelly" = 50)
+
+/obj/item/slimecrossbeaker/autoinjector/peaceandlove
+ container_type = null //It won't be *that* easy to get your hands on pax.
+ name = "peaceful distillation"
+ desc = "A light pink gooey sphere. Simply touching it makes you a little dizzy."
+ color = "#DDAAAA"
+ list_reagents = list("synthpax" = 10, "space_drugs" = 15) //Peace, dudes
+
+/obj/item/slimecrossbeaker/autoinjector/slimestimulant
+ name = "invigorating gel"
+ desc = "A bubbling purple mixture, designed to heal and boost movement."
+ color = "#FF00FF"
+ list_reagents = list("regen_jelly" = 30, "methamphetamine" = 9)
diff --git a/code/modules/research/xenobiology/crossbreeding/_status_effects.dm b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
new file mode 100644
index 0000000000..62928774bf
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/_status_effects.dm
@@ -0,0 +1,798 @@
+/obj/screen/alert/status_effect/rainbow_protection
+ name = "Rainbow Protection"
+ desc = "You are defended from harm, but so are those you might seek to injure!"
+ icon_state = "slime_rainbowshield"
+
+/datum/status_effect/rainbow_protection
+ id = "rainbow_protection"
+ duration = 100
+ alert_type = /obj/screen/alert/status_effect/rainbow_protection
+ var/originalcolor
+
+/datum/status_effect/rainbow_protection/on_apply()
+ owner.status_flags |= GODMODE
+ owner.add_trait(TRAIT_PACIFISM, "slimestatus")
+ owner.visible_message("[owner] shines with a brilliant rainbow light.",
+ "You feel protected by an unknown force!")
+ originalcolor = owner.color
+ return ..()
+
+/datum/status_effect/rainbow_protection/tick()
+ owner.color = rgb(rand(0,255),rand(0,255),rand(0,255))
+ return ..()
+
+/datum/status_effect/rainbow_protection/on_remove()
+ owner.status_flags &= ~GODMODE
+ owner.color = originalcolor
+ owner.remove_trait(TRAIT_PACIFISM, "slimestatus")
+ owner.visible_message("[owner] stops glowing, the rainbow light fading away.",
+ "You no longer feel protected...")
+
+/obj/screen/alert/status_effect/slimeskin
+ name = "Adamantine Slimeskin"
+ desc = "You are covered in a thick, non-neutonian gel."
+ icon_state = "slime_stoneskin"
+
+/datum/status_effect/slimeskin
+ id = "slimeskin"
+ duration = 300
+ alert_type = /obj/screen/alert/status_effect/slimeskin
+ var/originalcolor
+
+/datum/status_effect/slimeskin/on_apply()
+ originalcolor = owner.color
+ owner.color = "#3070CC"
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.damage_resistance += 10
+ owner.visible_message("[owner] is suddenly covered in a strange, blue-ish gel!",
+ "You are covered in a thick, rubbery gel.")
+ return ..()
+
+/datum/status_effect/slimeskin/on_remove()
+ owner.color = originalcolor
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.damage_resistance -= 10
+ owner.visible_message("[owner]'s gel coating liquefies and dissolves away.",
+ "Your gel second-skin dissolves!")
+
+///////////////////////////////////////////////////////
+//////////////////CONSUMING EXTRACTS///////////////////
+///////////////////////////////////////////////////////
+
+/datum/status_effect/firecookie
+ id = "firecookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 100
+
+/datum/status_effect/firecookie/on_apply()
+ owner.add_trait(TRAIT_RESISTCOLD,"firecookie")
+ owner.adjust_bodytemperature(110)
+ return ..()
+
+/datum/status_effect/firecookie/on_remove()
+ owner.remove_trait(TRAIT_RESISTCOLD,"firecookie")
+
+/datum/status_effect/watercookie
+ id = "watercookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 100
+
+/datum/status_effect/watercookie/on_apply()
+ owner.add_trait(TRAIT_NOSLIPWATER,"watercookie")
+ return ..()
+
+/datum/status_effect/watercookie/tick()
+ for(var/turf/open/T in range(get_turf(owner),1))
+ T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = 5)
+
+/datum/status_effect/watercookie/on_remove()
+ owner.remove_trait(TRAIT_NOSLIPWATER,"watercookie")
+
+/datum/status_effect/metalcookie
+ id = "metalcookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 100
+
+/datum/status_effect/metalcookie/on_apply()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.brute_mod *= 0.9
+ return ..()
+
+/datum/status_effect/metalcookie/on_remove()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.brute_mod /= 0.9
+
+/datum/status_effect/sparkcookie
+ id = "sparkcookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 300
+ var/original_coeff
+
+/datum/status_effect/sparkcookie/on_apply()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ original_coeff = H.physiology.siemens_coeff
+ H.physiology.siemens_coeff = 0
+ return ..()
+
+/datum/status_effect/sparkcookie/on_remove()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.siemens_coeff = original_coeff
+
+/datum/status_effect/toxincookie
+ id = "toxincookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 600
+
+/datum/status_effect/toxincookie/on_apply()
+ owner.add_trait(TRAIT_TOXINLOVER,"toxincookie")
+ return ..()
+
+/datum/status_effect/toxincookie/on_remove()
+ owner.remove_trait(TRAIT_TOXINLOVER,"toxincookie")
+
+/datum/status_effect/timecookie
+ id = "timecookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 600
+
+/datum/status_effect/timecookie/on_apply()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H
+ H.physiology.do_after_speed *= 0.95
+ return ..()
+
+/datum/status_effect/timecookie/on_remove()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H
+ H.physiology.do_after_speed /= 0.95
+
+/datum/status_effect/lovecookie
+ id = "lovecookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 300
+
+/datum/status_effect/lovecookie/tick()
+ if(owner.stat != CONSCIOUS)
+ return
+ if(iscarbon(owner))
+ var/mob/living/carbon/C = owner
+ if(C.handcuffed)
+ return
+ var/list/huggables = list()
+ for(var/mob/living/carbon/L in range(get_turf(owner),1))
+ if(L != owner)
+ huggables += L
+ if(length(huggables))
+ var/mob/living/carbon/hugged = pick(huggables)
+ owner.visible_message("[owner] hugs [hugged]!", "You hug [hugged]!")
+
+/datum/status_effect/tarcookie
+ id = "tarcookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 100
+
+/datum/status_effect/tarcookie/tick()
+ for(var/mob/living/carbon/human/L in range(get_turf(owner),1))
+ if(L != owner)
+ L.apply_status_effect(/datum/status_effect/tarfoot)
+
+/datum/status_effect/tarfoot
+ id = "tarfoot"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 30
+
+/datum/status_effect/tarfoot/on_apply()
+ var/mob/living/carbon/human/H = owner
+ if(istype(H))
+ H.physiology.speed_mod += 0.5
+ return ..()
+
+/datum/status_effect/tarfoot/on_remove()
+ var/mob/living/carbon/human/H = owner
+ if(istype(H))
+ H.physiology.speed_mod -= 0.5
+
+/datum/status_effect/spookcookie
+ id = "spookcookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 300
+
+/datum/status_effect/spookcookie/on_apply()
+ var/image/I = image(icon = 'icons/mob/simple_human.dmi', icon_state = "skeleton", layer = ABOVE_MOB_LAYER, loc = owner)
+ I.override = 1
+ owner.add_alt_appearance(/datum/atom_hud/alternate_appearance/basic/everyone, "spookyscary", I)
+ return ..()
+
+/datum/status_effect/spookcookie/on_remove()
+ owner.remove_alt_appearance("spookyscary")
+
+/datum/status_effect/peacecookie
+ id = "peacecookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 100
+
+/datum/status_effect/peacecookie/tick()
+ for(var/mob/living/L in range(get_turf(owner),1))
+ L.apply_status_effect(/datum/status_effect/plur)
+
+/datum/status_effect/plur
+ id = "plur"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 30
+
+/datum/status_effect/plur/on_apply()
+ owner.add_trait(TRAIT_PACIFISM, "peacecookie")
+ return ..()
+
+/datum/status_effect/plur/on_remove()
+ owner.remove_trait(TRAIT_PACIFISM, "peacecookie")
+
+/datum/status_effect/adamantinecookie
+ id = "adamantinecookie"
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ duration = 100
+
+/datum/status_effect/adamantinecookie/on_apply()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.burn_mod *= 0.9
+ return ..()
+
+/datum/status_effect/adamantinecookie/on_remove()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.burn_mod /= 0.9
+
+///////////////////////////////////////////////////////
+//////////////////STABILIZED EXTRACTS//////////////////
+///////////////////////////////////////////////////////
+
+/datum/status_effect/stabilized //The base stabilized extract effect, has no effect of its' own.
+ id = "stabilizedbase"
+ duration = -1
+ alert_type = null
+ var/obj/item/slimecross/stabilized/linked_extract
+ var/colour = "null"
+
+/datum/status_effect/stabilized/tick()
+ if(!linked_extract || !linked_extract.loc) //Sanity checking
+ qdel(src)
+ return
+ if(linked_extract && linked_extract.loc != owner && linked_extract.loc.loc != owner)
+ linked_extract.linked_effect = null
+ if(!QDELETED(linked_extract))
+ linked_extract.owner = null
+ START_PROCESSING(SSobj,linked_extract)
+ qdel(src)
+ return ..()
+
+/datum/status_effect/stabilized/null //This shouldn't ever happen, but just in case.
+ id = "stabilizednull"
+
+
+//Stabilized effects start below.
+/datum/status_effect/stabilized/grey
+ id = "stabilizedgrey"
+ colour = "grey"
+
+/datum/status_effect/stabilized/grey/tick()
+ for(var/mob/living/simple_animal/slime/S in range(1, get_turf(owner)))
+ if(!(owner in S.Friends))
+ to_chat(owner, "[linked_extract] pulses gently as it communicates with [S]")
+ S.Friends[owner] = 1
+ return ..()
+
+/datum/status_effect/stabilized/orange
+ id = "stabilizedorange"
+ colour = "orange"
+
+/datum/status_effect/stabilized/orange/tick()
+ var/body_temperature_difference = BODYTEMP_NORMAL - owner.bodytemperature
+ owner.adjust_bodytemperature(min(5,body_temperature_difference))
+ return ..()
+
+/datum/status_effect/stabilized/purple
+ id = "stabilizedpurple"
+ colour = "purple"
+
+/datum/status_effect/stabilized/purple/tick()
+ var/is_healing = FALSE
+ if(owner.getBruteLoss() > 0)
+ owner.adjustBruteLoss(-0.2)
+ is_healing = TRUE
+ if(owner.getFireLoss() > 0)
+ owner.adjustFireLoss(-0.2)
+ is_healing = TRUE
+ if(owner.getToxLoss() > 0)
+ owner.adjustToxLoss(-0.2, forced = TRUE) //Slimepeople should also get healed.
+ is_healing = TRUE
+ if(is_healing)
+ examine_text = "SUBJECTPRONOUN is regenerating slowly, purplish goo filling in small injuries!"
+ new /obj/effect/temp_visual/heal(get_turf(owner), "#FF0000")
+ else
+ examine_text = null
+ ..()
+
+/datum/status_effect/stabilized/blue
+ id = "stabilizedblue"
+ colour = "blue"
+
+/datum/status_effect/stabilized/blue/on_apply()
+ owner.add_trait(TRAIT_NOSLIPWATER, "slimestatus")
+ return ..()
+
+datum/status_effect/stabilized/blue/on_remove()
+ owner.remove_trait(TRAIT_NOSLIPWATER, "slimestatus")
+
+/datum/status_effect/stabilized/metal
+ id = "stabilizedmetal"
+ colour = "metal"
+ var/cooldown = 30
+ var/max_cooldown = 30
+
+/datum/status_effect/stabilized/metal/tick()
+ if(cooldown > 0)
+ cooldown--
+ else
+ cooldown = max_cooldown
+ var/list/sheets = list()
+ for(var/obj/item/stack/sheet/S in owner.GetAllContents())
+ if(S.amount < S.max_amount)
+ sheets += S
+
+ if(sheets.len > 0)
+ var/obj/item/stack/sheet/S = pick(sheets)
+ S.amount++
+ to_chat(owner, "[linked_extract] adds a layer of slime to [S], which metamorphosizes into another sheet of material!")
+ return ..()
+
+
+/datum/status_effect/stabilized/yellow
+ id = "stabilizedyellow"
+ colour = "yellow"
+ var/cooldown = 10
+ var/max_cooldown = 10
+ examine_text = "Nearby electronics seem just a little more charged wherever SUBJECTPRONOUN goes."
+
+/datum/status_effect/stabilized/yellow/tick()
+ if(cooldown > 0)
+ cooldown--
+ return ..()
+ cooldown = max_cooldown
+ var/list/batteries = list()
+ for(var/obj/item/stock_parts/cell/C in owner.GetAllContents())
+ if(C.charge < C.maxcharge)
+ batteries += C
+ if(batteries.len)
+ var/obj/item/stock_parts/cell/ToCharge = pick(batteries)
+ ToCharge.charge += min(ToCharge.maxcharge - ToCharge.charge, ToCharge.maxcharge/10) //10% of the cell, or to maximum.
+ to_chat(owner, "[linked_extract] discharges some energy into a device you have.")
+ return ..()
+
+/obj/item/hothands
+ name = "burning fingertips"
+ desc = "You shouldn't see this."
+
+/obj/item/hothands/is_hot()
+ return 290 //Below what's required to ignite plasma.
+
+/datum/status_effect/stabilized/darkpurple
+ id = "stabilizeddarkpurple"
+ colour = "dark purple"
+ var/obj/item/hothands/fire
+ examine_text = "Their fingertips burn brightly!"
+
+/datum/status_effect/stabilized/darkpurple/on_apply()
+ owner.add_trait(TRAIT_RESISTHEATHANDS, "slimestatus")
+ fire = new(owner)
+ return ..()
+
+/datum/status_effect/stabilized/darkpurple/tick()
+ var/obj/item/I = owner.get_active_held_item()
+ var/obj/item/reagent_containers/food/snacks/F = I
+ if(istype(F))
+ if(F.cooked_type)
+ to_chat(owner, "[linked_extract] flares up brightly, and your hands alone are enough cook [F]!")
+ F.microwave_act()
+ else
+ I.attackby(fire, owner)
+ return ..()
+
+/datum/status_effect/stabilized/darkpurple/on_remove()
+ owner.remove_trait(TRAIT_RESISTHEATHANDS, "slimestatus")
+ qdel(fire)
+
+/datum/status_effect/stabilized/darkblue
+ id = "stabilizeddarkblue"
+ colour = "dark blue"
+
+/datum/status_effect/stabilized/darkblue/tick()
+ if(owner.fire_stacks > 0 && prob(80))
+ owner.fire_stacks--
+ if(owner.fire_stacks <= 0)
+ to_chat(owner, "[linked_extract] coats you in a watery goo, extinguishing the flames.")
+ var/obj/O = owner.get_active_held_item()
+ O.extinguish() //All shamelessly copied from water's reaction_obj, since I didn't seem to be able to get it here for some reason.
+ O.acid_level = 0
+ // Monkey cube
+ if(istype(O, /obj/item/reagent_containers/food/snacks/monkeycube))
+ to_chat(owner, "[linked_extract] kept your hands wet! It makes [O] expand!")
+ var/obj/item/reagent_containers/food/snacks/monkeycube/cube = O
+ cube.Expand()
+
+ // Dehydrated carp
+ else if(istype(O, /obj/item/toy/plush/carpplushie/dehy_carp))
+ to_chat(owner, "[linked_extract] kept your hands wet! It makes [O] expand!")
+ var/obj/item/toy/plush/carpplushie/dehy_carp/dehy = O
+ dehy.Swell() // Makes a carp
+
+ else if(istype(O, /obj/item/stack/sheet/hairlesshide))
+ to_chat(owner, "[linked_extract] kept your hands wet! It wets [O]!")
+ var/obj/item/stack/sheet/hairlesshide/HH = O
+ var/obj/item/stack/sheet/wetleather/WL = new(get_turf(HH))
+ WL.amount = HH.amount
+ qdel(HH)
+ ..()
+
+/datum/status_effect/stabilized/silver
+ id = "stabilizedsilver"
+ colour = "silver"
+
+/datum/status_effect/stabilized/silver/on_apply()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.hunger_mod *= 0.8 //20% buff
+ return ..()
+
+/datum/status_effect/stabilized/silver/on_remove()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.hunger_mod /= 0.8
+
+//Bluespace has an icon because it's kinda active.
+/obj/screen/alert/status_effect/bluespaceslime
+ name = "Stabilized Bluespace Extract"
+ desc = "You shouldn't see this, since we set it to change automatically!"
+ icon_state = "slime_bluespace_on"
+
+/datum/status_effect/bluespacestabilization
+ id = "stabilizedbluespacecooldown"
+ duration = 1200
+ alert_type = null
+
+/datum/status_effect/stabilized/bluespace
+ id = "stabilizedbluespace"
+ colour = "bluespace"
+ alert_type = /obj/screen/alert/status_effect/bluespaceslime
+ var/healthcheck
+
+/datum/status_effect/stabilized/bluespace/tick()
+ if(owner.has_status_effect(/datum/status_effect/bluespacestabilization))
+ linked_alert.desc = "The stabilized bluespace extract is still aligning you with the bluespace axis."
+ linked_alert.icon_state = "slime_bluespace_off"
+ return ..()
+ else
+ linked_alert.desc = "The stabilized bluespace extract will try to redirect you from harm!"
+ linked_alert.icon_state = "slime_bluespace_on"
+
+ if(healthcheck && (healthcheck - owner.health) > 5)
+ owner.visible_message("[linked_extract] notices the sudden change in [owner]'s physical health, and activates!")
+ do_sparks(5,FALSE,owner)
+ var/F = find_safe_turf(zlevels = owner.z, extended_safety_checks = TRUE)
+ var/range = 0
+ if(!F)
+ F = get_turf(owner)
+ range = 50
+ if(do_teleport(owner, F, range))
+ to_chat(owner, "[linked_extract] will take some time to re-align you on the bluespace axis.")
+ do_sparks(5,FALSE,owner)
+ owner.apply_status_effect(/datum/status_effect/bluespacestabilization)
+ healthcheck = owner.health
+ return ..()
+
+/datum/status_effect/stabilized/sepia
+ id = "stabilizedsepia"
+ colour = "sepia"
+ var/mod = 0
+
+/datum/status_effect/stabilized/sepia/tick()
+ if(prob(50) && mod > -1)
+ mod--
+ var/mob/living/carbon/human/H = owner
+ if(istype(H))
+ H.physiology.speed_mod--
+ else if(mod < 1)
+ mod++
+ var/mob/living/carbon/human/H = owner
+ if(istype(H))
+ H.physiology.speed_mod++
+ return ..()
+
+/datum/status_effect/stabilized/sepia/on_remove()
+ var/mob/living/carbon/human/H = owner
+ if(istype(H))
+ H.physiology.speed_mod += -mod //Reset the changes.
+
+/datum/status_effect/stabilized/cerulean
+ id = "stabilizedcerulean"
+ colour = "cerulean"
+ var/mob/living/clone
+
+/datum/status_effect/stabilized/cerulean/on_apply()
+ var/typepath = owner.type
+ clone = new typepath(owner.loc)
+ var/mob/living/carbon/O = owner
+ var/mob/living/carbon/C = clone
+ if(istype(C) && istype(O))
+ C.real_name = O.real_name
+ O.dna.transfer_identity(C)
+ C.updateappearance(mutcolor_update=1)
+ return ..()
+
+/datum/status_effect/stabilized/cerulean/tick()
+ if(owner.stat == DEAD)
+ if(clone && clone.stat != DEAD)
+ owner.visible_message("[owner] blazes with brilliant light, [linked_extract] whisking [owner.p_their()] soul away.",
+ "You feel a warm glow from [linked_extract], and you open your eyes... elsewhere.")
+ if(owner.mind)
+ owner.mind.transfer_to(clone)
+ clone = null
+ qdel(linked_extract)
+ if(!clone || clone.stat == DEAD)
+ to_chat(owner, "[linked_extract] desperately tries to move your soul to a living body, but can't find one!")
+ qdel(linked_extract)
+ ..()
+
+/datum/status_effect/stabilized/cerulean/on_remove()
+ if(clone)
+ clone.visible_message("[clone] dissolves into a puddle of goo!")
+ qdel(clone)
+
+/datum/status_effect/stabilized/pyrite
+ id = "stabilizedpyrite"
+ colour = "pyrite"
+ var/originalcolor
+
+/datum/status_effect/stabilized/pyrite/on_apply()
+ originalcolor = owner.color
+ return ..()
+
+/datum/status_effect/stabilized/pyrite/tick()
+ owner.color = rgb(rand(0,255),rand(0,255),rand(0,255))
+ return ..()
+
+/datum/status_effect/stabilized/pyrite/on_remove()
+ owner.color = originalcolor
+
+/datum/status_effect/stabilized/red
+ id = "stabilizedred"
+ colour = "red"
+
+/datum/status_effect/stabilized/red/on_apply()
+ owner.add_trait(TRAIT_IGNORESLOWDOWN,"slimestatus")
+ return ..()
+
+/datum/status_effect/stabilized/red/on_remove()
+ owner.remove_trait(TRAIT_IGNORESLOWDOWN,"slimestatus")
+
+/datum/status_effect/stabilized/green
+ id = "stabilizedgreen"
+ colour = "green"
+ var/datum/dna/originalDNA
+ var/originalname
+
+/datum/status_effect/stabilized/green/on_apply()
+ to_chat(owner, "You feel different...")
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ originalDNA = new H.dna.type
+ originalname = H.real_name
+ H.dna.copy_dna(originalDNA)
+ randomize_human(H)
+ return ..()
+
+/datum/status_effect/stabilized/green/tick() //Only occasionally give examiners a warning.
+ if(prob(50))
+ examine_text = "SUBJECTPRONOUN looks a bit green and gooey..."
+ else
+ examine_text = null
+ return ..()
+
+/datum/status_effect/stabilized/green/on_remove()
+ to_chat(owner, "You feel more like yourself.")
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ originalDNA.transfer_identity(H)
+ H.real_name = originalname
+ H.updateappearance(mutcolor_update=1)
+
+/datum/status_effect/brokenpeace
+ id = "brokenpeace"
+ duration = 1200
+ alert_type = null
+
+/datum/status_effect/pinkdamagetracker
+ id = "pinkdamagetracker"
+ duration = -1
+ alert_type = null
+ var/damage = 0
+ var/lasthealth
+
+/datum/status_effect/pinkdamagetracker/tick()
+ if((lasthealth - owner.health) > 0)
+ damage += (lasthealth - owner.health)
+ lasthealth = owner.health
+
+/datum/status_effect/stabilized/pink
+ id = "stabilizedpink"
+ colour = "pink"
+ var/list/mobs = list()
+ var/faction_name
+
+/datum/status_effect/stabilized/pink/on_apply()
+ faction_name = owner.real_name
+ return ..()
+
+/datum/status_effect/stabilized/pink/tick()
+ for(var/mob/living/simple_animal/M in view(7,get_turf(owner)))
+ if(!(M in mobs))
+ mobs += M
+ M.apply_status_effect(/datum/status_effect/pinkdamagetracker)
+ M.faction |= faction_name
+ for(var/mob/living/simple_animal/M in mobs)
+ if(!(M in view(7,get_turf(owner))))
+ M.faction -= faction_name
+ M.remove_status_effect(/datum/status_effect/pinkdamagetracker)
+ mobs -= M
+ var/datum/status_effect/pinkdamagetracker/C = M.has_status_effect(/datum/status_effect/pinkdamagetracker)
+ if(istype(C) && C.damage > 0)
+ C.damage = 0
+ owner.apply_status_effect(/datum/status_effect/brokenpeace)
+ var/HasFaction = FALSE
+ for(var/i in owner.faction)
+ if(i == faction_name)
+ HasFaction = TRUE
+
+ if(HasFaction && owner.has_status_effect(/datum/status_effect/brokenpeace))
+ owner.faction -= faction_name
+ to_chat(owner, "The peace has been broken! Hostile creatures will now react to you!")
+ if(!HasFaction && !owner.has_status_effect(/datum/status_effect/brokenpeace))
+ to_chat(owner, "[linked_extract] pulses, generating a fragile aura of peace.")
+ owner.faction |= faction_name
+ return ..()
+
+/datum/status_effect/stabilized/pink/on_remove()
+ for(var/mob/living/simple_animal/M in mobs)
+ M.faction -= faction_name
+ M.remove_status_effect(/datum/status_effect/pinkdamagetracker)
+ for(var/i in owner.faction)
+ if(i == faction_name)
+ owner.faction -= faction_name
+
+/datum/status_effect/stabilized/oil
+ id = "stabilizedoil"
+ colour = "oil"
+ examine_text = "SUBJECTPRONOUN smells of sulfer and oil!"
+
+/datum/status_effect/stabilized/oil/tick()
+ if(owner.stat == DEAD)
+ explosion(get_turf(owner),1,2,4,flame_range = 5)
+ return ..()
+
+/datum/status_effect/stabilized/black
+ id = "stabilizedblack"
+ colour = "black"
+ var/messagedelivered = FALSE
+ var/heal_amount = 1
+
+/datum/status_effect/stabilized/black/tick()
+ if(owner.pulling && isliving(owner.pulling) && owner.grab_state == GRAB_KILL)
+ var/mob/living/M = owner.pulling
+ if(M.stat == DEAD)
+ return
+ if(!messagedelivered)
+ to_chat(owner,"You feel your hands melt around [M]'s neck and start to drain them of life.")
+ to_chat(owner.pulling, "[owner]'s hands melt around your neck, and you can feel your life starting to drain away!")
+ messagedelivered = TRUE
+ examine_text = "SUBJECTPRONOUN is draining health from [owner.pulling]!"
+ var/list/healing_types = list()
+ if(owner.getBruteLoss() > 0)
+ healing_types += BRUTE
+ if(owner.getFireLoss() > 0)
+ healing_types += BURN
+ if(owner.getToxLoss() > 0)
+ healing_types += TOX
+ if(owner.getCloneLoss() > 0)
+ healing_types += CLONE
+
+ owner.apply_damage_type(-heal_amount, damagetype=pick(healing_types))
+ owner.nutrition += 3
+ M.adjustCloneLoss(heal_amount * 1.2) //This way, two people can't just convert each other's damage away.
+ else
+ messagedelivered = FALSE
+ examine_text = null
+ return ..()
+
+/datum/status_effect/stabilized/lightpink
+ id = "stabilizedlightpink"
+ colour = "light pink"
+
+/datum/status_effect/stabilized/lightpink/on_apply()
+ owner.add_trait(TRAIT_GOTTAGOFAST,"slimestatus")
+ return ..()
+
+/datum/status_effect/stabilized/lightpink/tick()
+ for(var/mob/living/carbon/human/H in range(1, get_turf(owner)))
+ if(H != owner && H.stat != DEAD && H.health <= 0 && !H.reagents.has_reagent("epinephrine"))
+ to_chat(owner, "[linked_extract] pulses in sync with [H]'s heartbeat, trying to keep them alive.")
+ H.reagents.add_reagent("epinephrine",5)
+ return ..()
+
+/datum/status_effect/stabilized/lightpink/on_remove()
+ owner.remove_trait(TRAIT_GOTTAGOFAST,"slimestatus")
+
+/datum/status_effect/stabilized/adamantine
+ id = "stabilizedadamantine"
+ colour = "adamantine"
+ examine_text = "SUBJECTPRONOUN has a strange metallic coating on their skin."
+
+/datum/status_effect/stabilized/gold
+ id = "stabilizedgold"
+ colour = "gold"
+ var/mob/living/simple_animal/familiar
+
+/datum/status_effect/stabilized/gold/tick()
+ if(!familiar)
+ familiar = create_random_mob(get_turf(owner.loc), FRIENDLY_SPAWN)
+ familiar.del_on_death = TRUE
+ return ..()
+
+/datum/status_effect/stabilized/gold/on_remove()
+ if(familiar)
+ qdel(familiar)
+
+/datum/status_effect/stabilized/adamantine/on_apply()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.damage_resistance += 5
+ return ..()
+
+/datum/status_effect/stabilized/adamantine/on_remove()
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.physiology.damage_resistance += 5
+
+/datum/status_effect/stabilized/rainbow
+ id = "stabilizedrainbow"
+ colour = "rainbow"
+
+/datum/status_effect/stabilized/rainbow/tick()
+ if(owner.health <= 0)
+ var/obj/item/slimecross/stabilized/rainbow/X = linked_extract
+ if(istype(X))
+ if(X.regencore)
+ X.regencore.afterattack(owner,owner,TRUE)
+ X.regencore = null
+ owner.visible_message("[owner] flashes a rainbow of colors, and [owner.p_their()] skin is coated in a milky regenerative goo!")
+ qdel(src)
+ qdel(linked_extract)
+ return ..()
diff --git a/code/modules/research/xenobiology/crossbreeding/burning.dm b/code/modules/research/xenobiology/crossbreeding/burning.dm
new file mode 100644
index 0000000000..ab0000626c
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/burning.dm
@@ -0,0 +1,420 @@
+/*
+Burning extracts:
+ Have a unique, primarily offensive effect when
+ filled with 10u plasma and activated in-hand.
+*/
+/obj/item/slimecross/burning
+ name = "burning extract"
+ desc = "It's boiling over with barely-contained energy."
+ effect = "burning"
+ container_type = INJECTABLE | DRAWABLE
+ icon_state = "burning"
+
+/obj/item/slimecross/burning/Initialize()
+ ..()
+ create_reagents(10)
+
+/obj/item/slimecross/burning/attack_self(mob/user)
+ if(!reagents.has_reagent("plasma",10))
+ to_chat(user, "This extract needs to be full of plasma to activate!")
+ return
+ reagents.remove_reagent("plasma",10)
+ to_chat(user, "You squeeze the extract, and it absorbs the plasma!")
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ playsound(src, 'sound/magic/fireball.ogg', 50, 1)
+ do_effect(user)
+
+/obj/item/slimecross/burning/proc/do_effect(mob/user) //If, for whatever reason, you don't want to delete the extract, don't do ..()
+ qdel(src)
+ return
+
+/obj/item/slimecross/burning/grey
+ colour = "grey"
+
+/obj/item/slimecross/burning/grey/do_effect(mob/user)
+ var/mob/living/simple_animal/slime/S = new(get_turf(user),"grey")
+ S.visible_message("A baby slime emerges from [src], and it nuzzles [user] before burbling hungrily!")
+ S.Friends[user] = 20 //Gas, gas, gas
+ S.bodytemperature = T0C + 400 //We gonna step on the gas.
+ S.nutrition = S.get_hunger_nutrition() //Tonight, we fight!
+ ..()
+
+/obj/item/slimecross/burning/orange
+ colour = "orange"
+
+/obj/item/slimecross/burning/orange/do_effect(mob/user)
+ user.visible_message("[src] boils over with a caustic gas!")
+ var/datum/reagents/R = new/datum/reagents(100)
+ R.add_reagent("condensedcapsaicin", 100)
+
+ var/datum/effect_system/smoke_spread/chem/smoke = new
+ smoke.set_up(R, 7, get_turf(user))
+ smoke.start()
+ ..()
+
+/obj/item/slimecross/burning/purple
+ colour = "purple"
+
+/obj/item/slimecross/burning/purple/do_effect(mob/user)
+ user.visible_message("[src] fills with a bubbling liquid!")
+ new /obj/item/slimecrossbeaker/autoinjector/slimestimulant(get_turf(user))
+ ..()
+
+/obj/item/slimecross/burning/blue
+ colour = "blue"
+
+/obj/item/slimecross/burning/blue/do_effect(mob/user)
+ user.visible_message("[src] flash-freezes the area!")
+ for(var/turf/open/T in range(3, get_turf(user)))
+ T.MakeSlippery(TURF_WET_PERMAFROST, min_wet_time = 10, wet_time_to_add = 5)
+ for(var/mob/living/carbon/M in range(5, get_turf(user)))
+ if(M != user)
+ M.bodytemperature = BODYTEMP_COLD_DAMAGE_LIMIT + 10 //Not quite cold enough to hurt.
+ to_chat(M, "You feel a chill run down your spine, and the floor feels a bit slippery with frost...")
+ ..()
+
+/obj/item/slimecross/burning/metal
+ colour = "metal"
+
+/obj/item/slimecross/burning/metal/do_effect(mob/user)
+ for(var/turf/closed/wall/W in range(1,get_turf(user)))
+ W.dismantle_wall(1)
+ playsound(W, 'sound/effects/break_stone.ogg', 50, 1)
+ user.visible_message("[src] pulses violently, and shatters the walls around it!")
+ ..()
+
+/obj/item/slimecross/burning/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/burning/yellow/do_effect(mob/user)
+ user.visible_message("[src] explodes into an electrical field!")
+ playsound(get_turf(src), 'sound/weapons/zapbang.ogg', 50, 1)
+ for(var/mob/living/M in range(4,get_turf(user)))
+ if(M != user)
+ var/mob/living/carbon/C = M
+ if(istype(C))
+ C.electrocute_act(25,src)
+ else
+ M.adjustFireLoss(25)
+ to_chat(M, "You feel a sharp electrical pulse!")
+ ..()
+
+/obj/item/slimecross/burning/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/burning/darkpurple/do_effect(mob/user)
+ user.visible_message("[src] sublimates into a cloud of plasma!")
+ var/turf/T = get_turf(user)
+ T.atmos_spawn_air("plasma=60")
+ ..()
+
+/obj/item/slimecross/burning/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/burning/darkblue/do_effect(mob/user)
+ user.visible_message("[src] releases a burst of chilling smoke!")
+ var/datum/reagents/R = new/datum/reagents(100)
+ R.add_reagent("frostoil", 40)
+ user.reagents.add_reagent("cryoxadone",10)
+ var/datum/effect_system/smoke_spread/chem/smoke = new
+ smoke.set_up(R, 7, get_turf(user))
+ smoke.start()
+ ..()
+
+/obj/item/slimecross/burning/silver
+ colour = "silver"
+
+/obj/item/slimecross/burning/silver/do_effect(mob/user)
+ var/amount = rand(3,6)
+ var/list/turfs = list()
+ for(var/turf/open/T in range(1,get_turf(user)))
+ turfs += T
+ for(var/i = 0, i < amount, i++)
+ var/path = get_random_food()
+ var/obj/item/O = new path(pick(turfs))
+ O.reagents.add_reagent("slimejelly",5) //Oh god it burns
+ if(prob(50))
+ O.desc += " It smells strange..."
+ user.visible_message("[src] produces a few pieces of food!")
+ ..()
+
+/obj/item/slimecross/burning/bluespace
+ colour = "bluespace"
+
+/obj/item/slimecross/burning/bluespace/do_effect(mob/user)
+ user.visible_message("[src] sparks, and lets off a shockwave of bluespace energy!")
+ for(var/mob/living/L in range(1, get_turf(user)))
+ if(L != user)
+ do_teleport(L, get_turf(L), 6, asoundin = 'sound/effects/phasein.ogg') //Somewhere between the effectiveness of fake and real BS crystal
+ new /obj/effect/particle_effect/sparks(get_turf(L))
+ playsound(get_turf(L), "sparks", 50, 1)
+ ..()
+
+/obj/item/slimecross/burning/sepia
+ colour = "sepia"
+
+/obj/item/slimecross/burning/sepia/do_effect(mob/user)
+ user.visible_message("[src] shapes itself into a camera!")
+ new /obj/item/device/camera/timefreeze(get_turf(user))
+ ..()
+
+/obj/item/slimecross/burning/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/burning/cerulean/do_effect(mob/user)
+ user.visible_message("[src] produces a potion!")
+ new /obj/item/slimepotion/extract_cloner(get_turf(user))
+ ..()
+
+/obj/item/slimecross/burning/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/burning/pyrite/do_effect(mob/user)
+ user.visible_message("[src] releases a colorful wave of energy, which shatters the lights!")
+ var/area/A = get_area(user.loc)
+ for(var/obj/machinery/light/L in A) //Shamelessly copied from the APC effect.
+ L.on = TRUE
+ L.break_light_tube()
+ L.on = FALSE
+ stoplag()
+ ..()
+
+/obj/item/slimecross/burning/red
+ colour = "red"
+
+/obj/item/slimecross/burning/red/do_effect(mob/user)
+ user.visible_message("[src] pulses a hazy red aura for a moment, which wraps around [user]!")
+ for(var/mob/living/simple_animal/slime/S in view(7, get_turf(user)))
+ if(user in S.Friends)
+ var/friendliness = S.Friends[user]
+ S.Friends = list()
+ S.Friends[user] = friendliness
+ else
+ S.Friends = list()
+ S.rabid = 1
+ S.visible_message("The [S] is driven into a dangerous frenzy!")
+ ..()
+
+/obj/item/slimecross/burning/green
+ colour = "green"
+
+/obj/item/slimecross/burning/green/do_effect(mob/user)
+ var/which_hand = "l_hand"
+ if(!(user.active_hand_index % 2))
+ which_hand = "r_hand"
+ var/mob/living/L = user
+ if(!istype(user))
+ return
+ var/obj/item/held = L.get_active_held_item() //This should be itself, but just in case...
+ L.dropItemToGround(held)
+ var/obj/item/melee/arm_blade/slime/blade = new(user)
+ if(!L.put_in_hands(blade))
+ qdel(blade)
+ user.visible_message("[src] melts onto [user]'s arm, boiling the flesh horribly!")
+ else
+ user.visible_message("[src] sublimates the flesh around [user]'s arm, transforming the bone into a gruesome blade!")
+ user.emote("scream")
+ L.apply_damage(30,BURN,which_hand)
+ ..()
+
+/obj/item/slimecross/burning/pink
+ colour = "pink"
+
+/obj/item/slimecross/burning/pink/do_effect(mob/user)
+ user.visible_message("[src] shrinks into a small, gel-filled pellet!")
+ new /obj/item/slimecrossbeaker/pax(get_turf(user))
+ ..()
+
+/obj/item/slimecross/burning/gold
+ colour = "gold"
+
+/obj/item/slimecross/burning/gold/do_effect(mob/user)
+ user.visible_message("[src] shudders violently, and summons an army for [user]!")
+ for(var/i in 1 to 3) //Less than gold normally does, since it's safer and faster.
+ var/mob/living/simple_animal/S = create_random_mob(get_turf(user), HOSTILE_SPAWN)
+ S.faction |= "[REF(user)]"
+ if(prob(50))
+ for(var/j = 1, j <= rand(1, 3), j++)
+ step(S, pick(NORTH,SOUTH,EAST,WEST))
+ ..()
+
+/obj/item/slimecross/burning/oil
+ colour = "oil"
+
+/obj/item/slimecross/burning/oil/do_effect(mob/user)
+ user.visible_message("[src] begins to shake with rapidly increasing force!")
+ addtimer(CALLBACK(src, .proc/boom), 50)
+
+/obj/item/slimecross/burning/oil/proc/boom()
+ explosion(get_turf(src), 2, 4, 4) //Same area as normal oils, but increased high-impact values by one each, then decreased light by 2.
+ qdel(src)
+
+/obj/item/slimecross/burning/black
+ colour = "black"
+
+/obj/item/slimecross/burning/black/do_effect(mob/user)
+ var/mob/living/L = user
+ if(!istype(L))
+ return
+ user.visible_message("[src] absorbs [user], transforming them into a slime!")
+ var/obj/effect/proc_holder/spell/targeted/shapeshift/slimeform/S = new()
+ S.remove_on_restore = TRUE
+ user.mind.AddSpell(S)
+ S.cast(list(user),user)
+ ..()
+
+/obj/item/slimecross/burning/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/burning/lightpink/do_effect(mob/user)
+ user.visible_message("[src] lets off a hypnotizing pink glow!")
+ for(var/mob/living/carbon/C in view(7, get_turf(user)))
+ C.reagents.add_reagent("pax",5)
+ ..()
+
+/obj/item/slimecross/burning/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/burning/adamantine/do_effect(mob/user)
+ user.visible_message("[src] crystallizes into a large shield!")
+ new /obj/item/twohanded/required/adamantineshield(get_turf(user))
+ ..()
+
+/obj/item/slimecross/burning/rainbow
+ colour = "rainbow"
+
+/obj/item/slimecross/burning/rainbow/do_effect(mob/user)
+ user.visible_message("[src] flattens into a glowing rainbow blade.")
+ new /obj/item/kitchen/knife/rainbowknife(get_turf(user))
+ ..()
+
+//Misc. things added
+
+/obj/item/device/camera/timefreeze
+ name = "sepia-tinted camera"
+ desc = "They say a picture is like a moment stopped in time."
+ pictures_left = 1
+ pictures_max = 1
+
+/obj/item/device/camera/timefreeze/afterattack(atom/target, mob/user, flag)
+ if(!on || !pictures_left || !isturf(target.loc))
+ return
+ new /obj/effect/timestop(get_turf(target), 2, 50, list(user))
+ ..()
+ var/text = "The camera fades away"
+ if(disk)
+ text += ", leaving the disk behind!"
+ user.put_in_hands(disk)
+ else
+ text += "!"
+ to_chat(user,"[text]")
+ qdel(src)
+
+/obj/item/slimepotion/extract_cloner
+ name = "extract cloning potion"
+ desc = "An more powerful version of the extract enhancer potion, capable of cloning regular slime extracts."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potpurple"
+
+/obj/item/slimepotion/extract_cloner/afterattack(obj/item/target, mob/user , proximity)
+ if(!proximity)
+ return
+ if(istype(target, /obj/item/reagent_containers))
+ return ..(target, user, proximity)
+ if(istype(target, /obj/item/slimecross))
+ to_chat(user, "[target] is too complex for the potion to clone!")
+ return
+ if(!istype(target, /obj/item/slime_extract))
+ return
+ var/obj/item/slime_extract/S = target
+ if(S.recurring)
+ to_chat(user, "[target] is too complex for the potion to clone!")
+ return
+ var/path = S.type
+ var/obj/item/slime_extract/C = new path(get_turf(target))
+ C.Uses = S.Uses
+ to_chat(user, "You pour the potion onto [target], and the fluid solidifies into a copy of it!")
+ qdel(src)
+ return
+
+/obj/item/melee/arm_blade/slime
+ name = "slimy boneblade"
+ desc = "What remains of the bones in your arm. Incredibly sharp, and painful for both you and your opponents."
+ force = 15
+ force_string = "painful"
+
+/obj/item/melee/arm_blade/slime/attack(mob/living/L, mob/user)
+ . = ..()
+ if(prob(20))
+ user.emote("scream")
+
+/obj/item/kitchen/knife/rainbowknife
+ name = "rainbow knife"
+ desc = "A strange, transparent knife which constantly shifts color. It hums slightly when moved."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "rainbowknife"
+ force = 15
+ throwforce = 15
+ damtype = BRUTE
+
+/obj/item/kitchen/knife/rainbowknife/afterattack(atom/O, mob/user, proximity)
+ if(proximity && istype(O, /mob/living))
+ damtype = pick(BRUTE, BURN, TOX, OXY, CLONE)
+ switch(damtype)
+ if(BRUTE)
+ hitsound = 'sound/weapons/bladeslice.ogg'
+ attack_verb = list("slashed","sliced","cut")
+ if(BURN)
+ hitsound = 'sound/weapons/sear.ogg'
+ attack_verb = list("burned","singed","heated")
+ if(TOX)
+ hitsound = 'sound/weapons/pierce.ogg'
+ attack_verb = list("poisoned","dosed","toxified")
+ if(OXY)
+ hitsound = 'sound/effects/space_wind.ogg'
+ attack_verb = list("suffocated","winded","vacuumed")
+ if(CLONE)
+ hitsound = 'sound/items/geiger/ext1.ogg'
+ attack_verb = list("irradiated","mutated","maligned")
+ return ..()
+
+/obj/item/twohanded/required/adamantineshield
+ name = "adamantine shield"
+ desc = "A gigantic shield made of solid adamantium."
+ icon = 'icons/obj/slimecrossing.dmi'
+ icon_state = "adamshield"
+ item_state = "adamshield"
+ w_class = WEIGHT_CLASS_HUGE
+ armor = list("melee" = 50, "bullet" = 50, "laser" = 50, "energy" = 0, "bomb" = 30, "bio" = 0, "rad" = 0, "fire" = 80, "acid" = 70)
+ slot_flags = SLOT_BACK
+ block_chance = 75
+ throw_range = 1 //How far do you think you're gonna throw a solid crystalline shield...?
+ throw_speed = 2
+ force = 15 //Heavy, but hard to wield.
+ attack_verb = list("bashed","pounded","slammed")
+ flags_2 = SLOWS_WHILE_IN_HAND_2
+
+
+/obj/effect/proc_holder/spell/targeted/shapeshift/slimeform
+ name = "Slime Transformation"
+ desc = "Transform from a human to a slime, or back again!"
+ action_icon_state = "transformslime"
+ cooldown_min = 0
+ charge_max = 0
+ invocation_type = "none"
+ shapeshift_type = /mob/living/simple_animal/slime/transformedslime
+ convert_damage = TRUE
+ convert_damage_type = CLONE
+ var/remove_on_restore = FALSE
+
+/obj/effect/proc_holder/spell/targeted/shapeshift/slimeform/Restore(mob/living/M)
+ if(remove_on_restore)
+ if(M.mind)
+ M.mind.RemoveSpell(src)
+ ..()
+
+/mob/living/simple_animal/slime/transformedslime
+
+/mob/living/simple_animal/slime/transformedslime/Reproduce() //Just in case.
+ to_chat(src, "I can't reproduce...")
+ return
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/charged.dm b/code/modules/research/xenobiology/crossbreeding/charged.dm
new file mode 100644
index 0000000000..bc2bbe4c57
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/charged.dm
@@ -0,0 +1,433 @@
+/*
+Charged extracts:
+ Have a unique, effect when filled with
+ 10u plasma and activated in-hand, related to their
+ normal extract effect.
+*/
+/obj/item/slimecross/charged
+ name = "charged extract"
+ desc = "It sparks with electric power."
+ effect = "charged"
+ container_type = INJECTABLE | DRAWABLE
+ icon_state = "charged"
+
+/obj/item/slimecross/charged/Initialize()
+ ..()
+ create_reagents(10)
+
+/obj/item/slimecross/charged/attack_self(mob/user)
+ if(!reagents.has_reagent("plasma",10))
+ to_chat(user, "This extract needs to be full of plasma to activate!")
+ return
+ reagents.remove_reagent("plasma",10)
+ to_chat(user, "You squeeze the extract, and it absorbs the plasma!")
+ playsound(src, 'sound/effects/bubbles.ogg', 50, 1)
+ playsound(src, 'sound/effects/light_flicker.ogg', 50, 1)
+ do_effect(user)
+
+/obj/item/slimecross/charged/proc/do_effect(mob/user) //If, for whatever reason, you don't want to delete the extract, don't do ..()
+ qdel(src)
+ return
+
+/obj/item/slimecross/charged/grey
+ colour = "grey"
+
+/obj/item/slimecross/charged/grey/do_effect(mob/user)
+ new /obj/item/slimepotion/slime_reviver(get_turf(user))
+ user.visible_message("[src] distills into a potion!")
+ ..()
+
+/obj/item/slimecross/charged/orange
+ colour = "orange"
+
+/obj/item/slimecross/charged/orange/do_effect(mob/user)
+ for(var/turf/turf in range(5,get_turf(user)))
+ if(!locate(/obj/effect/hotspot) in turf)
+ new /obj/effect/hotspot(turf)
+ ..()
+
+/obj/item/slimecross/charged/purple
+ colour = "purple"
+
+/obj/item/slimecross/charged/purple/do_effect(mob/user)
+ new /obj/item/slimecrossbeaker/omnizine(get_turf(user))
+ user.visible_message("[src] sparks, and floods with a regenerative solution!")
+ ..()
+
+/obj/item/slimecross/charged/blue
+ colour = "blue"
+
+/obj/item/slimecross/charged/blue/do_effect(mob/user)
+ new /obj/item/slimepotion/slime/chargedstabilizer(get_turf(user))
+ user.visible_message("[src] distills into a potion!")
+ ..()
+
+/obj/item/slimecross/charged/metal
+ colour = "metal"
+
+/obj/item/slimecross/charged/metal/do_effect(mob/user)
+ var/obj/item/stack/sheet/metal/M = new(get_turf(user))
+ M.amount = 25
+ var/obj/item/stack/sheet/plasteel/P = new(get_turf(user))
+ P.amount = 10
+ user.visible_message("[src] grows into a plethora of metals!")
+ ..()
+
+/obj/item/slimecross/charged/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/charged/yellow/do_effect(mob/user)
+ new /obj/item/stock_parts/cell/high/slime/hypercharged(get_turf(user))
+ user.visible_message("[src] sparks violently, and swells with electric power!")
+ ..()
+
+/obj/item/slimecross/charged/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/charged/darkpurple/do_effect(mob/user)
+ var/obj/item/stack/sheet/mineral/plasma/M = new(get_turf(user))
+ M.amount = 10
+ user.visible_message("[src] produces a large amount of plasma!")
+ ..()
+
+/obj/item/slimecross/charged/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/charged/darkblue/do_effect(mob/user)
+ new /obj/item/slimepotion/spaceproof(get_turf(user))
+ user.visible_message("[src] distills into a potion!")
+ ..()
+
+/obj/item/slimecross/charged/silver
+ colour = "silver"
+
+/obj/item/slimecross/charged/silver/do_effect(mob/user)
+ new /obj/item/reagent_containers/food/snacks/store/cake/slimecake(get_turf(user))
+ for(var/i in 1 to 10)
+ var/drink_type = get_random_drink()
+ new drink_type(get_turf(user))
+ user.visible_message("[src] produces a party's worth of cake and drinks!")
+ ..()
+
+/obj/item/slimecross/charged/bluespace
+ colour = "bluespace"
+
+/obj/item/slimecross/charged/bluespace/do_effect(mob/user)
+ var/obj/item/stack/sheet/bluespace_crystal/M = new(get_turf(user))
+ M.amount = 10
+ user.visible_message("[src] produces several sheets of polycrystal!")
+ ..()
+
+/obj/item/slimecross/charged/sepia
+ colour = "sepia"
+
+/obj/item/slimecross/charged/sepia/do_effect(mob/user)
+ new /obj/item/device/camera/spooky(get_turf(user))
+ user.visible_message("[src] flickers in a strange, ethereal manner, and produces a camera!")
+ ..()
+
+/obj/item/slimecross/charged/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/charged/cerulean/do_effect(mob/user)
+ new /obj/item/slimepotion/enhancer/max(get_turf(user))
+ user.visible_message("[src] distills into a potion!")
+ ..()
+
+/obj/item/slimecross/charged/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/charged/pyrite/do_effect(mob/user)
+ var/obj/item/stack/sheet/mineral/bananium/M = new(get_turf(user))
+ M.amount = 10
+ user.visible_message("[src] solidifies with a horrifying banana stench!")
+ ..()
+
+/obj/item/slimecross/charged/red
+ colour = "red"
+
+/obj/item/slimecross/charged/red/do_effect(mob/user)
+ new /obj/item/slimepotion/lavaproof(get_turf(user))
+ user.visible_message("[src] distills into a potion!")
+ ..()
+
+/obj/item/slimecross/charged/green
+ colour = "green"
+
+/obj/item/slimecross/charged/green/do_effect(mob/user)
+ var/mob/living/carbon/human/H = user
+ if(!istype(H))
+ to_chat(user, "You must be a humanoid to use this!")
+ return
+ var/racechoice = input(H, "Choose your slime subspecies.", "Slime Selection") as null|anything in subtypesof(/datum/species/jelly)
+ if(!racechoice)
+ to_chat(user, "You decide not to become a slime for now.")
+ return
+ if(!user.canUseTopic(src, BE_CLOSE))
+ return
+ H.set_species(racechoice, icon_update=1)
+ H.visible_message("[H] suddenly shifts form as [src] dissolves into [H.p_their()] skin!")
+ ..()
+
+/obj/item/slimecross/charged/pink
+ colour = "pink"
+
+/obj/item/slimecross/charged/pink/do_effect(mob/user)
+ new /obj/item/slimepotion/lovepotion(get_turf(user))
+ user.visible_message("[src] distills into a potion!")
+ ..()
+
+/obj/item/slimecross/charged/gold
+ colour = "gold"
+ var/max_spawn = 10
+ var/spawned = 0
+
+/obj/item/slimecross/charged/gold/do_effect(mob/user)
+ user.visible_message("[src] starts shuddering violently!")
+ addtimer(CALLBACK(src, .proc/startTimer), 50)
+
+/obj/item/slimecross/charged/gold/proc/startTimer()
+ START_PROCESSING(SSobj, src)
+
+/obj/item/slimecross/charged/gold/process()
+ visible_message("[src] lets off a spark, and produces a living creature!")
+ new /obj/effect/particle_effect/sparks(get_turf(src))
+ playsound(get_turf(src), "sparks", 50, 1)
+ create_random_mob(get_turf(src), HOSTILE_SPAWN)
+ spawned++
+ if(spawned >= max_spawn)
+ visible_message("[src] collapses into a puddle of goo.")
+ qdel(src)
+
+/obj/item/slimecross/charged/gold/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ ..()
+
+/obj/item/slimecross/charged/oil
+ colour = "oil"
+
+/obj/item/slimecross/charged/oil/do_effect(mob/user)
+ user.visible_message("[src] begins to shake with rapidly increasing force!")
+ addtimer(CALLBACK(src, .proc/boom), 50)
+
+/obj/item/slimecross/charged/oil/proc/boom()
+ explosion(get_turf(src), 3, 2, 1) //Much smaller effect than normal oils, but devastatingly strong where it does hit.
+ qdel(src)
+
+/obj/item/slimecross/charged/black
+ colour = "black"
+
+/obj/item/slimecross/charged/black/do_effect(mob/user)
+ var/mob/living/carbon/human/H = user
+ if(!istype(H))
+ to_chat(user, "You have to be able to have a species to get your species changed.")
+ return
+ var/list/allowed_species = list()
+ for(var/X in subtypesof(/datum/species))
+ var/datum/species/temp = X
+ if(!initial(temp.blacklisted))
+ allowed_species += X
+ var/datum/species/changed = pick(allowed_species)
+ if(changed)
+ H.set_species(changed, icon_update = 1)
+ to_chat(H, "You feel very different!")
+ ..()
+
+/obj/item/slimecross/charged/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/charged/lightpink/do_effect(mob/user)
+ new /obj/item/slimepotion/peacepotion(get_turf(user))
+ user.visible_message("[src] distills into a potion!")
+ ..()
+
+/obj/item/slimecross/charged/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/charged/adamantine/do_effect(mob/user)
+ user.visible_message("[src] produces a fully formed golem shell!")
+ new /obj/effect/mob_spawn/human/golem/servant(get_turf(src), /datum/species/golem/adamantine, user)
+ ..()
+
+/obj/item/slimecross/charged/rainbow
+ colour = "rainbow"
+
+/obj/item/slimecross/charged/rainbow/do_effect(mob/user)
+ user.visible_message("[src] swells and splits into three new slimes!")
+ for(var/i in 1 to 3)
+ var/mob/living/simple_animal/slime/S = new(get_turf(user))
+ S.random_colour()
+ ..()
+
+////////////Unique things.
+
+/obj/item/slimepotion/slime_reviver
+ name = "slime revival potion"
+ desc = "Infused with plasma and compressed gel, this brings dead slimes back to life."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potsilver"
+
+/obj/item/slimepotion/slime_reviver/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!isslime(M))
+ to_chat(user, "The potion only works on slimes!")
+ return ..()
+ if(M.stat != DEAD)
+ to_chat(user, "The slime is still alive!")
+ return
+ if(M.maxHealth <= 0)
+ to_chat(user, "The slime is too unstable to return!")
+ M.revive(full_heal = 1)
+ M.stat = CONSCIOUS
+ M.visible_message("[M] is filled with renewed vigor and blinks awake!")
+ M.maxHealth -= 10 //Revival isn't healthy.
+ M.health -= 10
+ M.regenerate_icons()
+ qdel(src)
+
+/obj/item/slimepotion/slime/chargedstabilizer
+ name = "slime omnistabilizer"
+ desc = "An extremely potent chemical mix that will stop a slime from mutating completely."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potcyan"
+
+/obj/item/slimepotion/slime/chargedstabilizer/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!isslime(M))
+ to_chat(user, "The stabilizer only works on slimes!")
+ return ..()
+ if(M.stat)
+ to_chat(user, "The slime is dead!")
+ return
+ if(M.mutation_chance == 0)
+ to_chat(user, "The slime already has no chance of mutating!")
+ return
+
+ to_chat(user, "You feed the slime the omnistabilizer. It will not mutate this cycle!")
+ M.mutation_chance = 0
+ qdel(src)
+
+/obj/item/stock_parts/cell/high/slime/hypercharged
+ name = "hypercharged slime core"
+ desc = "A charged yellow slime extract, infused with even more plasma. It almost hurts to touch."
+ rating = 7 //Roughly 1.5 times the original.
+ maxcharge = 20000 //2 times the normal one.
+ chargerate = 2250 //1.5 times the normal rate.
+
+/obj/item/slimepotion/spaceproof
+ name = "slime pressurization potion"
+ desc = "A potent chemical sealant that will render any article of clothing airtight. Has two uses."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potblue"
+ var/uses = 2
+
+/obj/item/slimepotion/spaceproof/afterattack(obj/item/clothing/C, mob/user, proximity)
+ ..()
+ if(!uses)
+ qdel(src)
+ return
+ if(!proximity)
+ return
+ if(!istype(C))
+ to_chat(user, "The potion can only be used on clothing!")
+ return
+ if(C.min_cold_protection_temperature == SPACE_SUIT_MIN_TEMP_PROTECT && STOPSPRESSUREDMAGE_1 in C.flags_1)
+ to_chat(user, "The [C] is already pressure-resistant!")
+ return ..()
+ to_chat(user, "You slather the blue gunk over the [C], making it airtight.")
+ C.name = "pressure-resistant [C.name]"
+ C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ C.add_atom_colour("#000080", FIXED_COLOUR_PRIORITY)
+ C.min_cold_protection_temperature = SPACE_SUIT_MIN_TEMP_PROTECT
+ C.cold_protection = C.body_parts_covered
+ C.flags_1 |= STOPSPRESSUREDMAGE_1
+ uses--
+ if(!uses)
+ qdel(src)
+
+/obj/item/slimepotion/enhancer/max
+ name = "extract maximizer"
+ desc = "An extremely potent chemical mix that will maximize a slime extract's uses."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potpurple"
+
+/obj/item/slimepotion/lavaproof
+ name = "slime lavaproofing potion"
+ desc = "A strange, reddish goo said to repel lava as if it were water, without reducing flammability. Has two uses."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potred"
+ var/uses = 2
+
+/obj/item/slimepotion/lavaproof/afterattack(obj/item/C, mob/user, proximity)
+ ..()
+ if(!uses)
+ qdel(src)
+ return ..()
+ if(!proximity)
+ return ..()
+ if(!istype(C))
+ to_chat(user, "You can't coat this with lavaproofing fluid!")
+ return ..()
+ to_chat(user, "You slather the red gunk over the [C], making it lavaproof.")
+ C.name = "lavaproof [C.name]"
+ C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ C.add_atom_colour("#800000", FIXED_COLOUR_PRIORITY)
+ C.resistance_flags |= LAVA_PROOF
+ C.flags_2 |= LAVA_PROTECT_2
+ uses--
+ if(!uses)
+ qdel(src)
+
+/obj/item/slimepotion/lovepotion
+ name = "love potion"
+ desc = "A pink chemical mix thought to inspire feelings of love."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potpink"
+
+/obj/item/slimepotion/lovepotion/attack(mob/living/M, mob/user)
+ if(!isliving(M) || M.stat == DEAD)
+ to_chat(user, "The love potion only works on living things, sicko!")
+ return ..()
+ if(user == M)
+ to_chat(user, "You can't drink the love potion. What are you, a narcissist?")
+ return ..()
+
+ M.visible_message("[user] starts to feed [M] a love potion!",
+ "[user] starts to feed you a love potion!")
+
+ if(!do_after(user, 50, target = M))
+ return
+ to_chat(user, "You feed [M] the love potion!")
+ to_chat(M, "You develop feelings for [user], and anyone [p_they(user)] like.")
+ if(!("[REF(user)]" in M.faction) && M.mind)
+ M.mind.store_memory("You have strong feelings for [user].")
+ M.faction |= "[REF(user)]"
+ qdel(src)
+
+/obj/item/slimepotion/peacepotion
+ name = "pacification potion"
+ desc = "A light pink solution of chemicals, smelling like liquid peace. And mercury salts."
+ icon = 'icons/obj/chemical.dmi'
+ icon_state = "potlightpink"
+
+/obj/item/slimepotion/peacepotion/attack(mob/living/M, mob/user)
+ if(!isliving(M) || M.stat == DEAD)
+ to_chat(user, "The pacification potion only works on the living.")
+ return ..()
+ if(M != user)
+ M.visible_message("[user] starts to feed [M] a pacification potion!",
+ "[user] starts to feed you a love potion!")
+ else
+ M.visible_message("[user] starts to drink the pacification potion!",
+ "You start to drink the pacification potion!")
+
+ if(!do_after(user, 100, target = M))
+ return
+ if(M != user)
+ to_chat(user, "You feed [M] the pacification potion!")
+ else
+ to_chat(user, "You drink the pacification potion!")
+ if(isanimal(M))
+ M.add_trait(TRAIT_PACIFISM, MAGIC_TRAIT)
+ else if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ C.gain_trauma(/datum/brain_trauma/severe/pacifism, TRAUMA_RESILIENCE_SURGERY)
+ qdel(src)
diff --git a/code/modules/research/xenobiology/crossbreeding/consuming.dm b/code/modules/research/xenobiology/crossbreeding/consuming.dm
new file mode 100644
index 0000000000..a7c306c69c
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/consuming.dm
@@ -0,0 +1,426 @@
+/*
+Consuming extracts:
+ Can eat food items.
+ After consuming enough, produces special cookies.
+*/
+/obj/item/slimecross/consuming
+ name = "consuming extract"
+ desc = "It hungers... for more." //My slimecross has finally decided to eat... my buffet!
+ icon_state = "consuming"
+ effect = "consuming"
+ var/nutriment_eaten = 0
+ var/nutriment_required = 10
+ var/cooldown = 600 //1 minute.
+ var/last_produced = 0
+ var/cookies = 5 //Number of cookies to spawn
+ var/cookietype = /obj/item/slime_cookie
+
+/obj/item/slimecross/consuming/attackby(obj/item/O, mob/user)
+ if(istype(O,/obj/item/reagent_containers/food/snacks))
+ if(last_produced + cooldown > world.time)
+ to_chat(user, "[src] is still digesting after its last meal!")
+ return
+ var/datum/reagent/N = O.reagents.has_reagent("nutriment")
+ if(N)
+ nutriment_eaten += N.volume
+ to_chat(user, "[src] opens up and swallows [O] whole!")
+ qdel(O)
+ playsound(src, 'sound/items/eatfood.ogg', 20, 1)
+ else
+ to_chat(user, "[src] burbles unhappily at the offering.")
+ if(nutriment_eaten >= nutriment_required)
+ nutriment_eaten = 0
+ user.visible_message("[src] swells up and produces a small pile of cookies!")
+ playsound(src, 'sound/effects/splat.ogg', 40, 1)
+ last_produced = world.time
+ for(var/i in 1 to cookies)
+ var/obj/item/S = spawncookie()
+ S.pixel_x = rand(-5, 5)
+ S.pixel_y = rand(-5, 5)
+ return
+ ..()
+
+/obj/item/slimecross/consuming/proc/spawncookie()
+ return new cookietype(get_turf(src))
+
+/obj/item/slime_cookie //While this technically acts like food, it's so removed from it that I made it its' own type.
+ name = "error cookie"
+ desc = "A weird slime cookie. You shouldn't see this."
+ icon = 'icons/obj/food/slimecookies.dmi'
+ var/taste = "error"
+ var/nutrition = 5
+ icon_state = "base"
+ force = 0
+ w_class = WEIGHT_CLASS_TINY
+ throwforce = 0
+ throw_speed = 3
+ throw_range = 6
+
+/obj/item/slime_cookie/proc/do_effect(mob/living/M, mob/user)
+ return
+
+/obj/item/slime_cookie/attack(mob/living/M, mob/user)
+ var/fed = FALSE
+ if(M == user)
+ M.visible_message("[user] eats [src]!", "You eat [src].")
+ fed = TRUE
+ else
+ M.visible_message("[user] tries to force [M] to eat [src]!", "[user] tries to force you to eat [src]!")
+ if(do_after(user, 20, target = M))
+ fed = TRUE
+ M.visible_message("[user] forces [M] to eat [src]!", "[user] forces you to eat [src].")
+ if(fed)
+ to_chat(M, "Tastes like [taste].")
+ playsound(get_turf(M), 'sound/items/eatfood.ogg', 20, 1)
+ if(nutrition)
+ M.reagents.add_reagent("nutriment",nutrition)
+ do_effect(M, user)
+ qdel(src)
+ return
+ ..()
+
+/obj/item/slimecross/consuming/grey
+ colour = "grey"
+ cookietype = /obj/item/slime_cookie/grey
+
+/obj/item/slime_cookie/grey
+ name = "slime cookie"
+ desc = "A grey-ish transparent cookie. Nutritious, probably."
+ icon_state = "grey"
+ taste = "goo"
+ nutrition = 15
+
+/obj/item/slimecross/consuming/orange
+ colour = "orange"
+ cookietype = /obj/item/slime_cookie/orange
+
+/obj/item/slime_cookie/orange
+ name = "fiery cookie"
+ desc = "A orange cookie with a fiery pattern. Feels warm."
+ icon_state = "orange"
+ taste = "cinnamon and burning"
+
+/obj/item/slime_cookie/orange/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/firecookie)
+
+/obj/item/slimecross/consuming/purple
+ colour = "purple"
+ cookietype = /obj/item/slime_cookie/purple
+
+/obj/item/slime_cookie/purple
+ name = "health cookie"
+ desc = "A purple cookie with a cross pattern. Soothing."
+ icon_state = "purple"
+ taste = "fruit jam and cough medicine"
+
+/obj/item/slime_cookie/purple/do_effect(mob/living/M, mob/user)
+ M.adjustBruteLoss(-5)
+ M.adjustFireLoss(-5)
+ M.adjustToxLoss(-5, forced=1) //To heal slimepeople.
+ M.adjustOxyLoss(-5)
+ M.adjustCloneLoss(-5)
+ M.adjustBrainLoss(-5)
+
+/obj/item/slimecross/consuming/blue
+ colour = "blue"
+ cookietype = /obj/item/slime_cookie/blue
+
+/obj/item/slime_cookie/blue
+ name = "water cookie"
+ desc = "A transparent blue cookie. Constantly dripping wet."
+ icon_state = "blue"
+ taste = "water"
+
+/obj/item/slime_cookie/blue/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/watercookie)
+
+/obj/item/slimecross/consuming/metal
+ colour = "metal"
+ cookietype = /obj/item/slime_cookie/metal
+
+/obj/item/slime_cookie/metal
+ name = "metallic cookie"
+ desc = "A shiny grey cookie. Hard to the touch."
+ icon_state = "metal"
+ taste = "copper"
+
+/obj/item/slime_cookie/metal/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/metalcookie)
+
+/obj/item/slimecross/consuming/yellow
+ colour = "yellow"
+ cookietype = /obj/item/slime_cookie/yellow
+
+/obj/item/slime_cookie/yellow
+ name = "sparking cookie"
+ desc = "A yellow cookie with a lightning pattern. Has a rubbery texture."
+ icon_state = "yellow"
+ taste = "lemon cake and rubber gloves"
+
+/obj/item/slime_cookie/yellow/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/sparkcookie)
+
+/obj/item/slimecross/consuming/darkpurple
+ colour = "dark purple"
+ cookietype = /obj/item/slime_cookie/darkpurple
+
+/obj/item/slime_cookie/darkpurple
+ name = "toxic cookie"
+ desc = "A dark purple cookie, stinking of plasma."
+ icon_state = "darkpurple"
+ taste = "slime jelly and toxins"
+
+/obj/item/slime_cookie/darkpurple/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/toxincookie)
+
+/obj/item/slimecross/consuming/darkblue
+ colour = "dark blue"
+ cookietype = /obj/item/slime_cookie/darkblue
+
+/obj/item/slime_cookie/darkblue
+ name = "frosty cookie"
+ desc = "A dark blue cookie with a snowflake pattern. Feels cold."
+ icon_state = "darkblue"
+ taste = "mint and bitter cold"
+
+/obj/item/slime_cookie/darkblue/do_effect(mob/living/M, mob/user)
+ M.adjust_bodytemperature(-110)
+ M.ExtinguishMob()
+
+/obj/item/slimecross/consuming/silver
+ colour = "silver"
+ cookietype = /obj/item/slime_cookie/silver
+
+/obj/item/slime_cookie/silver
+ name = "waybread cookie"
+ desc = "A warm, crispy cookie, sparkling silver in the light. Smells wonderful."
+ icon_state = "silver"
+ taste = "masterful elven baking"
+ nutrition = 0 //We don't want normal nutriment
+
+/obj/item/slime_cookie/silver/do_effect(mob/living/M, mob/user)
+ M.reagents.add_reagent("stabilizednutriment",10)
+
+/obj/item/slimecross/consuming/bluespace
+ colour = "bluespace"
+ cookietype = /obj/item/slime_cookie/bluespace
+
+/obj/item/slime_cookie/bluespace
+ name = "space cookie"
+ desc = "A white cookie with green icing. Surprisingly hard to hold."
+ icon_state = "bluespace"
+ taste = "sugar and starlight"
+
+/obj/item/slime_cookie/bluespace/do_effect(mob/living/M, mob/user)
+ var/list/L = list()
+ for(var/turf/T in get_area_turfs(get_area(get_turf(M))))
+ if(!T.density)
+ var/clear = 1
+ for(var/obj/O in T)
+ if(O.density)
+ clear = 0
+ break
+ if(clear)
+ L+=T
+ if(length(L))
+ do_teleport(M, pick(L), 0, asoundin = 'sound/effects/phasein.ogg')
+ new /obj/effect/particle_effect/sparks(get_turf(M))
+ playsound(get_turf(M), "sparks", 50, 1)
+
+/obj/item/slimecross/consuming/sepia
+ colour = "sepia"
+ cookietype = /obj/item/slime_cookie/sepia
+
+/obj/item/slime_cookie/sepia
+ name = "time cookie"
+ desc = "A light brown cookie with a clock pattern. Takes some time to chew."
+ icon_state = "sepia"
+ taste = "brown sugar and a metronome"
+
+/obj/item/slime_cookie/sepia/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/timecookie)
+
+/obj/item/slimecross/consuming/cerulean
+ colour = "cerulean"
+ cookietype = /obj/item/slime_cookie/cerulean
+ cookies = 3 //You're gonna get more.
+
+/obj/item/slime_cookie/cerulean
+ name = "duplicookie"
+ desc = "A cerulean cookie with strange proportions. It feels like it could break apart easily."
+ icon_state = "cerulean"
+ taste = "a sugar cookie"
+
+/obj/item/slime_cookie/cerulean/do_effect(mob/living/M, mob/user)
+ if(prob(50))
+ to_chat(M, "A piece of [src] breaks off while you chew, and falls to the ground.")
+ var/obj/item/slime_cookie/cerulean/C = new(get_turf(M))
+ C.taste = taste + " and a sugar cookie"
+
+/obj/item/slimecross/consuming/pyrite
+ colour = "pyrite"
+ cookietype = /obj/item/slime_cookie/pyrite
+
+/obj/item/slime_cookie/pyrite
+ name = "color cookie"
+ desc = "A yellow cookie with rainbow-colored icing. Reflects the light strangely."
+ icon_state = "pyrite"
+ taste = "vanilla and " //Randomly selected color dye.
+ var/colour = "#FFFFFF"
+
+/obj/item/slime_cookie/pyrite/Initialize()
+ ..()
+ var/tastemessage = "paint remover"
+ switch(rand(1,7))
+ if(1)
+ tastemessage = "red dye"
+ colour = "#FF0000"
+ if(2)
+ tastemessage = "orange dye"
+ colour = "#FFA500"
+ if(3)
+ tastemessage = "yellow dye"
+ colour = "#FFFF00"
+ if(4)
+ tastemessage = "green dye"
+ colour = "#00FF00"
+ if(5)
+ tastemessage = "blue dye"
+ colour = "#0000FF"
+ if(6)
+ tastemessage = "indigo dye"
+ colour = "#4B0082"
+ if(7)
+ tastemessage = "violet dye"
+ colour = "#FF00FF"
+ taste += tastemessage
+
+/obj/item/slime_cookie/pyrite/do_effect(mob/living/M, mob/user)
+ M.add_atom_colour(colour,WASHABLE_COLOUR_PRIORITY)
+
+/obj/item/slimecross/consuming/red
+ colour = "red"
+ cookietype = /obj/item/slime_cookie/red
+
+/obj/item/slime_cookie/red
+ name = "blood cookie"
+ desc = "A red cookie, oozing a thick red fluid. Vampires might enjoy it."
+ icon_state = "red"
+ taste = "red velvet and iron"
+
+/obj/item/slime_cookie/red/do_effect(mob/living/M, mob/user)
+ new /obj/effect/decal/cleanable/blood(get_turf(M))
+ playsound(get_turf(M), 'sound/effects/splat.ogg', 10, 1)
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ C.blood_volume += 25 //Half a vampire drain.
+
+/obj/item/slimecross/consuming/green
+ colour = "green"
+ cookietype = /obj/item/slime_cookie/green
+
+/obj/item/slime_cookie/green
+ name = "gross cookie"
+ desc = "A disgusting green cookie, seeping with pus. You kind of feel ill just looking at it."
+ icon_state = "green"
+ taste = "the contents of your stomach"
+
+/obj/item/slime_cookie/green/do_effect(mob/living/M, mob/user)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.vomit(25)
+ M.reagents.remove_all()
+
+/obj/item/slimecross/consuming/pink
+ colour = "pink"
+ cookietype = /obj/item/slime_cookie/pink
+
+/obj/item/slime_cookie/pink
+ name = "love cookie"
+ desc = "A pink cookie with an icing heart. D'aww."
+ icon_state = "pink"
+ taste = "love and hugs"
+
+/obj/item/slime_cookie/pink/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/lovecookie)
+
+/obj/item/slimecross/consuming/gold
+ colour = "gold"
+ cookietype = /obj/item/slime_cookie/gold
+
+/obj/item/slime_cookie/gold
+ name = "gilded cookie"
+ desc = "A buttery golden cookie, closer to a bread than anything. May good fortune find you."
+ icon_state = "gold"
+ taste = "sweet cornbread and wealth"
+
+/obj/item/slime_cookie/gold/do_effect(mob/living/M, mob/user)
+ var/obj/item/held = M.get_active_held_item() //This should be itself, but just in case...
+ M.dropItemToGround(held)
+ var/newcoin = /obj/item/coin/gold
+ var/obj/item/coin/C = new newcoin(get_turf(M))
+ playsound(get_turf(C), 'sound/items/coinflip.ogg', 50, 1)
+ M.put_in_hand(C)
+
+/obj/item/slimecross/consuming/oil
+ colour = "oil"
+ cookietype = /obj/item/slime_cookie/oil
+
+/obj/item/slime_cookie/oil
+ name = "tar cookie"
+ desc = "An oily black cookie, which sticks to your hands. Smells like chocolate."
+ icon_state = "oil"
+ taste = "rich molten chocolate and tar"
+
+/obj/item/slime_cookie/oil/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/tarcookie)
+
+/obj/item/slimecross/consuming/black
+ colour = "black"
+ cookietype = /obj/item/slime_cookie/black
+
+/obj/item/slime_cookie/black
+ name = "spooky cookie"
+ desc = "A pitch black cookie with an icing ghost on the front. Spooky!"
+ icon_state = "black"
+ taste = "ghosts and stuff"
+
+/obj/item/slime_cookie/black/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/spookcookie)
+
+/obj/item/slimecross/consuming/lightpink
+ colour = "light pink"
+ cookietype = /obj/item/slime_cookie/lightpink
+
+/obj/item/slime_cookie/lightpink
+ name = "peace cookie"
+ desc = "A light pink cookie with a peace symbol in the icing. Lovely!"
+ icon_state = "lightpink"
+ taste = "strawberry icing and P.L.U.R" //Literal candy raver.
+
+/obj/item/slime_cookie/lightpink/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/peacecookie)
+
+/obj/item/slimecross/consuming/adamantine
+ colour = "adamantine"
+ cookietype = /obj/item/slime_cookie/adamantine
+
+/obj/item/slime_cookie/adamantine
+ name = "crystal cookie"
+ desc = "A translucent rock candy in the shape of a cookie. Surprisingly chewy."
+ icon_state = "adamantine"
+ taste = "crystalline sugar and metal"
+
+/obj/item/slime_cookie/adamantine/do_effect(mob/living/M, mob/user)
+ M.apply_status_effect(/datum/status_effect/adamantinecookie)
+
+/obj/item/slimecross/consuming/rainbow
+ colour = "rainbow"
+
+/obj/item/slimecross/consuming/rainbow/spawncookie()
+ var/cookie_type = pick(subtypesof(/obj/item/slime_cookie))
+ var/obj/item/slime_cookie/S = new cookie_type(get_turf(src))
+ S.name = "rainbow cookie"
+ S.desc = "A beautiful rainbow cookie, constantly shifting colors in the light."
+ S.icon_state = "rainbow"
+ return S
diff --git a/code/modules/research/xenobiology/crossbreeding/industrial.dm b/code/modules/research/xenobiology/crossbreeding/industrial.dm
new file mode 100644
index 0000000000..6d563efa5c
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/industrial.dm
@@ -0,0 +1,189 @@
+/*
+Industrial extracts:
+ Slowly consume plasma, produce items with it.
+*/
+/obj/item/slimecross/industrial
+ name = "industrial extract"
+ desc = "A gel-like, sturdy extract, fond of plasma and industry."
+ container_type = INJECTABLE | DRAWABLE
+ effect = "industrial"
+ icon_state = "industrial_still"
+ var/plasmarequired = 2 //Units of plasma required to be consumed to produce item.
+ var/itempath = /obj/item //The item produced by the extract.
+ var/plasmaabsorbed = 0 //Units of plasma aborbed by the extract already. Absorbs at a rate of 2u/obj tick.
+ var/itemamount = 1 //How many items to spawn
+
+/obj/item/slimecross/industrial/examine(mob/user)
+ ..()
+ to_chat(user, "It currently has [plasmaabsorbed] units of plasma floating inside the outer shell, out of [plasmarequired] units.")
+
+/obj/item/slimecross/industrial/proc/do_after_spawn(obj/item/spawned)
+ return
+
+/obj/item/slimecross/industrial/Initialize()
+ ..()
+ create_reagents(100)
+ START_PROCESSING(SSobj,src)
+
+/obj/item/slimecross/industrial/Destroy()
+ STOP_PROCESSING(SSobj,src)
+ return ..()
+
+/obj/item/slimecross/industrial/process()
+ var/IsWorking = FALSE
+ if(reagents.has_reagent("plasma",amount = 2) && plasmarequired > 1) //Can absorb as much as 2
+ IsWorking = TRUE
+ reagents.remove_reagent("plasma",2)
+ plasmaabsorbed += 2
+ else if(reagents.has_reagent("plasma",amount = 1)) //Can absorb as little as 1
+ IsWorking = TRUE
+ reagents.remove_reagent("plasma",1)
+ plasmaabsorbed += 1
+
+ if(plasmaabsorbed >= plasmarequired)
+ playsound(src, 'sound/effects/attackblob.ogg', 50, 1)
+ plasmaabsorbed -= plasmarequired
+ for(var/i = 0, i < itemamount, i++)
+ do_after_spawn(new itempath(get_turf(src)))
+ else if(IsWorking)
+ playsound(src, 'sound/effects/bubbles.ogg', 5, 1)
+ if(IsWorking)
+ icon_state = "industrial"
+ else
+ icon_state = "industrial_still"
+
+/obj/item/slimecross/industrial/grey
+ colour = "grey"
+ itempath = /obj/item/reagent_containers/food/snacks/monkeycube
+ itemamount = 5
+
+/obj/item/slimecross/industrial/orange
+ colour = "orange"
+ plasmarequired = 6
+ itempath = /obj/item/lighter/slime
+
+/obj/item/slimecross/industrial/purple
+ colour = "purple"
+ plasmarequired = 5
+ itempath = /obj/item/slimecrossbeaker/autoinjector/regenpack
+
+/obj/item/slimecross/industrial/blue
+ colour = "blue"
+ plasmarequired = 10
+ itempath = /obj/item/extinguisher
+
+/obj/item/slimecross/industrial/metal
+ colour = "metal"
+ plasmarequired = 3
+ itempath = /obj/item/stack/sheet/metal
+
+/obj/item/slimecross/industrial/metal/do_after_spawn(obj/item/spawned)
+ var/obj/item/stack/sheet/metal/M = spawned
+ if(istype(M))
+ M.amount = 10
+
+/obj/item/slimecross/industrial/yellow
+ colour = "yellow"
+ plasmarequired = 5
+ itempath = /obj/item/stock_parts/cell/high
+
+/obj/item/slimecross/industrial/yellow/do_after_spawn(obj/item/spawned)
+ var/obj/item/stock_parts/cell/high/C = spawned
+ if(istype(C))
+ C.charge = rand(0,C.maxcharge/2)
+
+/obj/item/slimecross/industrial/darkpurple
+ colour = "dark purple"
+ plasmarequired = 10
+ itempath = /obj/item/stack/sheet/mineral/plasma
+
+/obj/item/slimecross/industrial/darkblue
+ colour = "dark blue"
+ plasmarequired = 6
+ itempath = /obj/item/slimepotion/fireproof
+
+/obj/item/slimecross/industrial/darkblue/do_after_spawn(obj/item/spawned)
+ var/obj/item/slimepotion/fireproof/potion = spawned
+ if(istype(potion))
+ potion.uses = 1
+
+/obj/item/slimecross/industrial/silver
+ colour = "silver"
+ plasmarequired = 1
+ //Item picked below.
+
+/obj/item/slimecross/industrial/silver/process()
+ itempath = pick(list(get_random_food(), get_random_drink()))
+ ..()
+
+/obj/item/slimecross/industrial/bluespace
+ colour = "bluespace"
+ plasmarequired = 7
+ itempath = /obj/item/stack/ore/bluespace_crystal/artificial
+
+/obj/item/slimecross/industrial/sepia
+ colour = "sepia"
+ plasmarequired = 2
+ itempath = /obj/item/device/camera
+
+/obj/item/slimecross/industrial/cerulean
+ colour = "cerulean"
+ plasmarequired = 5
+ itempath = /obj/item/slimepotion/enhancer
+
+/obj/item/slimecross/industrial/pyrite
+ colour = "pyrite"
+ plasmarequired = 2
+ itempath = /obj/item/toy/crayon/spraycan
+
+/obj/item/slimecross/industrial/red
+ colour = "red"
+ plasmarequired = 5
+ itempath = /obj/item/slimecrossbeaker/bloodpack
+
+/obj/item/slimecross/industrial/green
+ colour = "green"
+ plasmarequired = 7
+ itempath = /obj/item/slimecrossbeaker/autoinjector/slimejelly
+
+/obj/item/slimecross/industrial/pink
+ colour = "pink"
+ plasmarequired = 6
+ itempath = /obj/item/slimecrossbeaker/autoinjector/peaceandlove
+
+/obj/item/slimecross/industrial/gold
+ colour = "gold"
+ plasmarequired = 10
+
+/obj/item/slimecross/industrial/gold/process()
+ itempath = pick(/obj/item/coin/silver, /obj/item/coin/iron, /obj/item/coin/gold, /obj/item/coin/diamond, /obj/item/coin/plasma, /obj/item/coin/uranium)
+ ..()
+
+/obj/item/slimecross/industrial/oil
+ colour = "oil"
+ plasmarequired = 4
+ itempath = /obj/item/grenade/iedcasing
+
+/obj/item/slimecross/industrial/black //What does this have to do with black slimes? No clue! Fun, though
+ colour = "black"
+ plasmarequired = 6
+ itempath = /obj/item/storage/fancy/cigarettes/cigpack_xeno
+
+/obj/item/slimecross/industrial/lightpink
+ colour = "light pink"
+ plasmarequired = 3
+ itempath = /obj/item/storage/fancy/heart_box
+
+/obj/item/slimecross/industrial/adamantine
+ colour = "adamantine"
+ plasmarequired = 10
+ itempath = /obj/item/stack/sheet/mineral/adamantine
+
+/obj/item/slimecross/industrial/rainbow
+ colour = "rainbow"
+ plasmarequired = 5
+ //Item picked below.
+
+/obj/item/slimecross/industrial/rainbow/process()
+ itempath = pick(subtypesof(/obj/item/slime_extract))
+ ..()
diff --git a/code/modules/research/xenobiology/crossbreeding/prismatic.dm b/code/modules/research/xenobiology/crossbreeding/prismatic.dm
new file mode 100644
index 0000000000..41063de3d1
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/prismatic.dm
@@ -0,0 +1,122 @@
+/*
+Prismatic extracts:
+ Becomes an infinite-use paintbrush.
+*/
+/obj/item/slimecross/prismatic
+ name = "prismatic extract"
+ desc = "It's constantly wet with a semi-transparent, colored goo."
+ effect = "prismatic"
+ icon_state = "prismatic"
+ var/paintcolor = "#FFFFFF"
+
+/obj/item/slimecross/prismatic/afterattack(turf/target, mob/user, proximity)
+ if(!proximity)
+ return
+ if(!istype(target) || isspaceturf(target))
+ return
+ target.add_atom_colour(paintcolor, WASHABLE_COLOUR_PRIORITY)
+ playsound(target, 'sound/effects/slosh.ogg', 20, 1)
+
+/obj/item/slimecross/prismatic/grey/
+ colour = "grey"
+ desc = "It's constantly wet with a pungent-smelling, clear chemical."
+
+/obj/item/slimecross/prismatic/grey/afterattack(turf/target, mob/user, proximity)
+ if(!proximity)
+ return
+ if(istype(target) && target.color != initial(target.color))
+ target.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ playsound(target, 'sound/effects/slosh.ogg', 20, 1)
+
+/obj/item/slimecross/prismatic/orange
+ paintcolor = "#FFA500"
+ colour = "orange"
+
+/obj/item/slimecross/prismatic/purple
+ paintcolor = "#B19CD9"
+ colour = "purple"
+
+/obj/item/slimecross/prismatic/blue
+ paintcolor = "#ADD8E6"
+ colour = "blue"
+
+/obj/item/slimecross/prismatic/metal
+ paintcolor = "#7E7E7E"
+ colour = "metal"
+
+/obj/item/slimecross/prismatic/yellow
+ paintcolor = "#FFFF00"
+ colour = "yellow"
+
+/obj/item/slimecross/prismatic/darkpurple
+ paintcolor = "#551A8B"
+ colour = "dark purple"
+
+/obj/item/slimecross/prismatic/darkblue
+ paintcolor = "#0000FF"
+ colour = "dark blue"
+
+/obj/item/slimecross/prismatic/silver
+ paintcolor = "#D3D3D3"
+ colour = "silver"
+
+/obj/item/slimecross/prismatic/bluespace
+ paintcolor = "#32CD32"
+ colour = "bluespace"
+
+/obj/item/slimecross/prismatic/sepia
+ paintcolor = "#704214"
+ colour = "sepia"
+
+/obj/item/slimecross/prismatic/cerulean
+ paintcolor = "#2956B2"
+ colour = "cerulean"
+
+/obj/item/slimecross/prismatic/pyrite
+ paintcolor = "#FAFAD2"
+ colour = "pyrite"
+
+/obj/item/slimecross/prismatic/red
+ paintcolor = "#FF0000"
+ colour = "red"
+
+/obj/item/slimecross/prismatic/green
+ paintcolor = "#00FF00"
+ colour = "green"
+
+/obj/item/slimecross/prismatic/pink
+ paintcolor = "#FF69B4"
+ colour = "pink"
+
+/obj/item/slimecross/prismatic/gold
+ paintcolor = "#FFD700"
+ colour = "gold"
+
+/obj/item/slimecross/prismatic/oil
+ paintcolor = "#505050"
+ colour = "oil"
+
+/obj/item/slimecross/prismatic/black
+ paintcolor = "#000000"
+ colour = "black"
+
+/obj/item/slimecross/prismatic/lightpink
+ paintcolor = "#FFB6C1"
+ colour = "light pink"
+
+/obj/item/slimecross/prismatic/adamantine
+ paintcolor = "#008B8B"
+ colour = "adamantine"
+
+/obj/item/slimecross/prismatic/rainbow
+ paintcolor = "#FFFFFF"
+ colour = "rainbow"
+
+/obj/item/slimecross/prismatic/rainbow/attack_self(mob/user)
+ var/newcolor = input(user, "Choose the slime color:", "Color change",paintcolor) as color|null
+ if ((user.get_active_held_item() != src || user.stat || user.restrained()))
+ return
+ if(!newcolor)
+ return
+ paintcolor = newcolor
+ return
diff --git a/code/modules/research/xenobiology/crossbreeding/recurring.dm b/code/modules/research/xenobiology/crossbreeding/recurring.dm
new file mode 100644
index 0000000000..cc36bbb215
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/recurring.dm
@@ -0,0 +1,137 @@
+/*
+Recurring extracts:
+ Generates a new charge every few seconds.
+ If depleted of its' last charge, stops working.
+*/
+/obj/item/slimecross/recurring
+ name = "recurring extract"
+ desc = "A tiny, glowing core, wrapped in several layers of goo."
+ effect = "recurring"
+ icon_state = "recurring"
+ var/extract_type
+ var/obj/item/slime_extract/extract
+ var/cooldown = 0
+ var/max_cooldown = 5 //In sets of 2 seconds.
+
+/obj/item/slimecross/recurring/Initialize()
+ ..()
+ extract = new extract_type(src.loc)
+ visible_message("[src] wraps a layer of goo around itself!")
+ extract.name = name
+ extract.desc = desc
+ extract.icon = icon
+ extract.icon_state = icon_state
+ extract.recurring = TRUE
+ src.forceMove(extract)
+ START_PROCESSING(SSobj,src)
+
+/obj/item/slimecross/recurring/process()
+ if(cooldown > 0)
+ cooldown--
+ else if(extract.Uses < 10 && extract.Uses > 0)
+ extract.Uses++
+ cooldown = max_cooldown
+ else if(extract.Uses <= 0)
+ extract.visible_message("The light inside [extract] flickers and dies out.")
+ extract.desc = "A tiny, inert core, bleeding dark, cerulean-colored goo."
+ extract.icon_state = "prismatic"
+ qdel(src)
+
+/obj/item/slimecross/recurring/Destroy()
+ ..()
+ STOP_PROCESSING(SSobj,src)
+
+/obj/item/slimecross/recurring/grey
+ extract_type = /obj/item/slime_extract/grey
+ colour = "grey"
+
+/obj/item/slimecross/recurring/orange
+ extract_type = /obj/item/slime_extract/orange
+ colour = "orange"
+
+/obj/item/slimecross/recurring/purple
+ extract_type = /obj/item/slime_extract/purple
+ colour = "purple"
+
+/obj/item/slimecross/recurring/blue
+ extract_type = /obj/item/slime_extract/blue
+ colour = "blue"
+
+/obj/item/slimecross/recurring/metal
+ extract_type = /obj/item/slime_extract/metal
+ colour = "metal"
+ max_cooldown = 10
+
+/obj/item/slimecross/recurring/yellow
+ extract_type = /obj/item/slime_extract/yellow
+ colour = "yellow"
+ max_cooldown = 10
+
+/obj/item/slimecross/recurring/darkpurple
+ extract_type = /obj/item/slime_extract/darkpurple
+ colour = "dark purple"
+ max_cooldown = 10
+
+/obj/item/slimecross/recurring/darkblue
+ extract_type = /obj/item/slime_extract/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/recurring/silver
+ extract_type = /obj/item/slime_extract/silver
+ colour = "silver"
+
+/obj/item/slimecross/recurring/bluespace
+ extract_type = /obj/item/slime_extract/bluespace
+ colour = "bluespace"
+
+/obj/item/slimecross/recurring/sepia
+ extract_type = /obj/item/slime_extract/sepia
+ colour = "sepia"
+ max_cooldown = 18 //No infinite timestop for you!
+
+/obj/item/slimecross/recurring/cerulean
+ extract_type = /obj/item/slime_extract/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/recurring/pyrite
+ extract_type = /obj/item/slime_extract/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/recurring/red
+ extract_type = /obj/item/slime_extract/red
+ colour = "red"
+
+/obj/item/slimecross/recurring/green
+ extract_type = /obj/item/slime_extract/green
+ colour = "green"
+
+/obj/item/slimecross/recurring/pink
+ extract_type = /obj/item/slime_extract/pink
+ colour = "pink"
+
+/obj/item/slimecross/recurring/gold
+ extract_type = /obj/item/slime_extract/gold
+ colour = "gold"
+ max_cooldown = 15
+
+/obj/item/slimecross/recurring/oil
+ extract_type = /obj/item/slime_extract/oil
+ colour = "oil" //Why would you want this?
+
+/obj/item/slimecross/recurring/black
+ extract_type = /obj/item/slime_extract/black
+ colour = "black"
+
+/obj/item/slimecross/recurring/lightpink
+ extract_type = /obj/item/slime_extract/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/recurring/adamantine
+ extract_type = /obj/item/slime_extract/adamantine
+ colour = "adamantine"
+ max_cooldown = 10
+
+/obj/item/slimecross/recurring/rainbow
+ extract_type = /obj/item/slime_extract/rainbow
+ colour = "rainbow"
+ max_cooldown = 20 //It's pretty powerful.
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/regenerative.dm b/code/modules/research/xenobiology/crossbreeding/regenerative.dm
new file mode 100644
index 0000000000..3d3c35b4de
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/regenerative.dm
@@ -0,0 +1,254 @@
+/*
+Regenerative extracts:
+ Work like a legion regenerative core.
+ Has a unique additional effect.
+*/
+/obj/item/slimecross/regenerative
+ name = "regenerative extract"
+ desc = "It's filled with a milky substance, and pulses like a heartbeat."
+ effect = "regenerative"
+ icon_state = "regenerative"
+
+/obj/item/slimecross/regenerative/proc/core_effect(mob/living/carbon/human/target, mob/user)
+ return
+/obj/item/slimecross/regenerative/proc/core_effect_before(mob/living/carbon/human/target, mob/user)
+ return
+
+
+/obj/item/slimecross/regenerative/afterattack(atom/target,mob/user,prox)
+ if(!prox || !isliving(target))
+ return
+ var/mob/living/H = target
+ if(H.stat == DEAD)
+ to_chat(user, "[src] will not work on the dead!")
+ return
+ if(H != user)
+ user.visible_message("[user] crushes the [src] over [H], the milky goo quickly regenerating all of [H.p_their()] injuries!",
+ "You squeeze the [src], and it bursts over [H], the milky goo regenerating [H.p_their()] injuries.")
+ else
+ user.visible_message("[user] crushes the [src] over [user.p_them()]self, the milky goo quickly regenerating all of [user.p_their()] injuries!",
+ "You squeeze the [src], and it bursts in your hand, splashing you with milky goo which quickly regenerates your injuries!")
+ core_effect_before(H, user)
+ H.revive(full_heal = 1)
+ core_effect(H, user)
+ playsound(target, 'sound/effects/splat.ogg', 40, 1)
+ qdel(src)
+
+/obj/item/slimecross/regenerative/grey
+ colour = "grey" //Has no bonus effect.
+
+/obj/item/slimecross/regenerative/orange
+ colour = "orange"
+
+/obj/item/slimecross/regenerative/orange/core_effect_before(mob/living/target, mob/user)
+ target.visible_message("The [src] boils over!")
+ for(var/turf/turf in range(1,target))
+ if(!locate(/obj/effect/hotspot) in turf)
+ new /obj/effect/hotspot(turf)
+
+/obj/item/slimecross/regenerative/purple
+ colour = "purple"
+
+/obj/item/slimecross/regenerative/purple/core_effect(mob/living/target, mob/user)
+ target.reagents.add_reagent("regen_jelly",10)
+
+/obj/item/slimecross/regenerative/blue
+ colour = "blue"
+
+/obj/item/slimecross/regenerative/blue/core_effect(mob/living/target, mob/user)
+ if(isturf(target.loc))
+ var/turf/open/T = get_turf(target)
+ T.MakeSlippery(TURF_WET_WATER, min_wet_time = 10, wet_time_to_add = 5)
+ target.visible_message("The milky goo in the extract gets all over the floor!")
+
+/obj/item/slimecross/regenerative/metal
+ colour = "metal"
+
+/obj/item/slimecross/regenerative/metal/core_effect(mob/living/target, mob/user)
+ target.visible_message("The milky goo hardens and reshapes itself, encasing [target]!")
+ var/obj/structure/closet/C = new /obj/structure/closet(target.loc)
+ C.name = "slimy closet"
+ C.desc = "Looking closer, it seems to be made of a sort of solid, opaque, metal-like goo."
+ target.forceMove(C)
+
+/obj/item/slimecross/regenerative/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/regenerative/yellow/core_effect(mob/living/target, mob/user)
+ var/list/batteries = list()
+ for(var/obj/item/stock_parts/cell/C in target.GetAllContents())
+ if(C.charge < C.maxcharge)
+ batteries += C
+ if(batteries.len)
+ var/obj/item/stock_parts/cell/ToCharge = pick(batteries)
+ ToCharge.charge = ToCharge.maxcharge
+ to_chat(target, "You feel a strange electrical pulse, and one of your electrical items was recharged.")
+
+/obj/item/slimecross/regenerative/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/regenerative/darkpurple/core_effect(mob/living/target, mob/user)
+ var/equipped = 0
+ equipped += target.equip_to_slot_or_del(new /obj/item/clothing/shoes/sneakers/purple(null), slot_shoes)
+ equipped += target.equip_to_slot_or_del(new /obj/item/clothing/under/color/lightpurple(null), slot_w_uniform)
+ equipped += target.equip_to_slot_or_del(new /obj/item/clothing/gloves/color/purple(null), slot_gloves)
+ equipped += target.equip_to_slot_or_del(new /obj/item/clothing/head/soft/purple(null), slot_head)
+ if(equipped > 0)
+ target.visible_message("The milky goo congeals into clothing!")
+
+/obj/item/slimecross/regenerative/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/regenerative/darkblue/core_effect(mob/living/target, mob/user)
+ if(!ishuman(target))
+ return
+ var/mob/living/carbon/human/H = target
+ var/fireproofed = FALSE
+ if(H.get_item_by_slot(slot_wear_suit))
+ fireproofed = TRUE
+ var/obj/item/clothing/C = H.get_item_by_slot(slot_wear_suit)
+ fireproof(C)
+ if(H.get_item_by_slot(slot_head))
+ fireproofed = TRUE
+ var/obj/item/clothing/C = H.get_item_by_slot(slot_head)
+ fireproof(C)
+ if(fireproofed)
+ target.visible_message("Some of [target]'s clothing gets coated in the goo, and turns blue!")
+
+/obj/item/slimecross/regenerative/darkblue/proc/fireproof(obj/item/clothing/C)
+ C.name = "fireproofed [C.name]"
+ C.remove_atom_colour(WASHABLE_COLOUR_PRIORITY)
+ C.add_atom_colour("#000080", FIXED_COLOUR_PRIORITY)
+ C.max_heat_protection_temperature = FIRE_IMMUNITY_SUIT_MAX_TEMP_PROTECT
+ C.heat_protection = C.body_parts_covered
+ C.resistance_flags |= FIRE_PROOF
+
+/obj/item/slimecross/regenerative/silver
+ colour = "silver"
+
+/obj/item/slimecross/regenerative/silver/core_effect(mob/living/target, mob/user)
+ target.nutrition = NUTRITION_LEVEL_FULL - 1
+ to_chat(target, "You feel satiated.")
+
+/obj/item/slimecross/regenerative/bluespace
+ colour = "bluespace"
+ var/turf/open/T
+
+/obj/item/slimecross/regenerative/bluespace/core_effect(mob/living/target, mob/user)
+ target.visible_message("[src] disappears in a shower of sparks!","The milky goo teleports you somewhere it remembers!")
+ do_sparks(5,FALSE,target)
+ target.forceMove(T)
+ do_sparks(5,FALSE,target)
+
+/obj/item/slimecross/regenerative/bluespace/Initialize()
+ ..()
+ T = get_turf(src)
+
+/obj/item/slimecross/regenerative/sepia
+ colour = "sepia"
+
+/obj/item/slimecross/regenerative/sepia/core_effect(mob/living/target, mob/user)
+ new /obj/effect/timestop(get_turf(target), 2, 50, list(user,target))
+
+/obj/item/slimecross/regenerative/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/regenerative/cerulean/core_effect(mob/living/target, mob/user)
+ src.forceMove(user.loc)
+ var/obj/item/slimecross/X = new /obj/item/slimecross/regenerative(user.loc)
+ X.name = name
+ X.desc = desc
+ user.put_in_active_hand(X)
+ to_chat(user, "Some of the milky goo congeals in your hand!")
+
+/obj/item/slimecross/regenerative/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/regenerative/pyrite/core_effect(mob/living/target, mob/user)
+ target.visible_message("The milky goo coating [target] leaves [target.p_them()] a different color!")
+ target.add_atom_colour(rgb(rand(0,255),rand(0,255),rand(0,255)),WASHABLE_COLOUR_PRIORITY)
+
+/obj/item/slimecross/regenerative/red
+ colour = "red"
+
+/obj/item/slimecross/regenerative/red/core_effect(mob/living/target, mob/user)
+ to_chat(target, "You feel... faster.")
+ target.reagents.add_reagent("ephedrine",3)
+
+/obj/item/slimecross/regenerative/green
+ colour = "green"
+
+/obj/item/slimecross/regenerative/green/core_effect(mob/living/target, mob/user)
+ if(isslime(target))
+ target.visible_message("The [target] suddenly changes color!")
+ var/mob/living/simple_animal/slime/S = target
+ S.random_colour()
+ if(isjellyperson(target))
+ target.reagents.add_reagent("slime_toxin",5)
+
+
+/obj/item/slimecross/regenerative/pink
+ colour = "pink"
+
+/obj/item/slimecross/regenerative/pink/core_effect(mob/living/target, mob/user)
+ to_chat(target, "You feel more calm.")
+ target.reagents.add_reagent("krokodil",4)
+
+/obj/item/slimecross/regenerative/gold
+ colour = "gold"
+
+/obj/item/slimecross/regenerative/gold/core_effect(mob/living/target, mob/user)
+ var/newcoin = pick(/obj/item/coin/silver, /obj/item/coin/iron, /obj/item/coin/gold, /obj/item/coin/diamond, /obj/item/coin/plasma, /obj/item/coin/uranium)
+ var/obj/item/coin/C = new newcoin(target.loc)
+ playsound(C, 'sound/items/coinflip.ogg', 50, 1)
+ target.put_in_hand(C)
+
+/obj/item/slimecross/regenerative/oil
+ colour = "oil"
+
+/obj/item/slimecross/regenerative/oil/core_effect(mob/living/target, mob/user)
+ playsound(src, 'sound/weapons/flash.ogg', 100, 1)
+ for(var/mob/living/L in view(user,7))
+ L.flash_act()
+
+/obj/item/slimecross/regenerative/black
+ colour = "black"
+
+/obj/item/slimecross/regenerative/black/core_effect_before(mob/living/target, mob/user)
+ var/dummytype = target.type
+ var/mob/living/dummy = new dummytype(target.loc)
+ to_chat(target, "The milky goo flows from your skin, forming an imperfect copy of you.")
+ if(iscarbon(target))
+ var/mob/living/carbon/T = target
+ var/mob/living/carbon/D = dummy
+ T.dna.transfer_identity(D)
+ D.updateappearance(mutcolor_update=1)
+ D.real_name = T.real_name
+ dummy.adjustBruteLoss(target.getBruteLoss())
+ dummy.adjustFireLoss(target.getFireLoss())
+ dummy.adjustToxLoss(target.getToxLoss())
+ dummy.adjustOxyLoss(200)
+
+/obj/item/slimecross/regenerative/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/regenerative/lightpink/core_effect(mob/living/target, mob/user)
+ if(!isliving(user))
+ return
+ if(target == user)
+ return
+ var/mob/living/U = user
+ U.revive(full_heal = 1)
+ to_chat(U, "Some of the milky goo sprays onto you, as well!")
+
+/obj/item/slimecross/regenerative/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/regenerative/adamantine/core_effect(mob/living/target, mob/user) //WIP - Find out why this doesn't work.
+ target.apply_status_effect(STATUS_EFFECT_SLIMESKIN)
+
+/obj/item/slimecross/regenerative/rainbow
+ colour = "rainbow"
+
+/obj/item/slimecross/regenerative/rainbow/core_effect(mob/living/target, mob/user)
+ target.apply_status_effect(STATUS_EFFECT_RAINBOWPROTECTION)
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/reproductive.dm b/code/modules/research/xenobiology/crossbreeding/reproductive.dm
new file mode 100644
index 0000000000..17e33a9c41
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/reproductive.dm
@@ -0,0 +1,132 @@
+/*
+Reproductive extracts:
+ When fed three monkey cubes, produces between
+ 1 and 4 normal slime extracts of the same colour.
+*/
+/obj/item/slimecross/reproductive
+ name = "reproductive extract"
+ desc = "It pulses with a strange hunger."
+ icon_state = "reproductive"
+ effect = "reproductive"
+ var/extract_type = /obj/item/slime_extract/
+ var/cubes_eaten = 0
+ var/last_produce = 0
+ var/cooldown = 30 // 3 seconds.
+
+/obj/item/slimecross/reproductive/attackby(obj/item/O, mob/user)
+ if((last_produce + cooldown) > world.time)
+ to_chat(user, "[src] is still digesting!")
+ return
+ if(istype(O, /obj/item/storage/bag/bio))
+ var/obj/item/storage/P = O
+ var/obj/item/reagent_containers/food/snacks/monkeycube/M
+ for(var/obj/item/X in P.contents)
+ M = X
+ if(M && istype(M))
+ break
+ if(M && istype(M))
+ P.remove_from_storage(M, get_turf(src))
+ attackby(M,user)
+ else
+ to_chat(user, "There are no monkey cubes in the bio bag!")
+ if(istype(O,/obj/item/reagent_containers/food/snacks/monkeycube))
+ qdel(O)
+ cubes_eaten++
+ to_chat(user, "You feed [O] to [src], and it pulses gently.")
+ playsound(src, 'sound/items/eatfood.ogg', 20, 1)
+ if(cubes_eaten >= 3)
+ var/cores = rand(1,4)
+ visible_message("[src] briefly swells to a massive size, and expels [cores] extract[cores > 1 ? "s":""]!")
+ playsound(src, 'sound/effects/splat.ogg', 40, 1)
+ last_produce = world.time
+ for(var/i = 0, i < cores, i++)
+ new extract_type(get_turf(loc))
+ cubes_eaten = 0
+
+/obj/item/slimecross/reproductive/grey
+ extract_type = /obj/item/slime_extract/grey
+ colour = "grey"
+
+/obj/item/slimecross/reproductive/orange
+ extract_type = /obj/item/slime_extract/orange
+ colour = "orange"
+
+/obj/item/slimecross/reproductive/purple
+ extract_type = /obj/item/slime_extract/purple
+ colour = "purple"
+
+/obj/item/slimecross/reproductive/blue
+ extract_type = /obj/item/slime_extract/blue
+ colour = "blue"
+
+/obj/item/slimecross/reproductive/metal
+ extract_type = /obj/item/slime_extract/metal
+ colour = "metal"
+
+/obj/item/slimecross/reproductive/yellow
+ extract_type = /obj/item/slime_extract/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/reproductive/darkpurple
+ extract_type = /obj/item/slime_extract/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/reproductive/darkblue
+ extract_type = /obj/item/slime_extract/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/reproductive/silver
+ extract_type = /obj/item/slime_extract/silver
+ colour = "silver"
+
+/obj/item/slimecross/reproductive/bluespace
+ extract_type = /obj/item/slime_extract/bluespace
+ colour = "bluespace"
+
+/obj/item/slimecross/reproductive/sepia
+ extract_type = /obj/item/slime_extract/sepia
+ colour = "sepia"
+
+/obj/item/slimecross/reproductive/cerulean
+ extract_type = /obj/item/slime_extract/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/reproductive/pyrite
+ extract_type = /obj/item/slime_extract/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/reproductive/red
+ extract_type = /obj/item/slime_extract/red
+ colour = "red"
+
+/obj/item/slimecross/reproductive/green
+ extract_type = /obj/item/slime_extract/green
+ colour = "green"
+
+/obj/item/slimecross/reproductive/pink
+ extract_type = /obj/item/slime_extract/pink
+ colour = "pink"
+
+/obj/item/slimecross/reproductive/gold
+ extract_type = /obj/item/slime_extract/gold
+ colour = "gold"
+
+/obj/item/slimecross/reproductive/oil
+ extract_type = /obj/item/slime_extract/oil
+ colour = "oil"
+
+/obj/item/slimecross/reproductive/black
+ extract_type = /obj/item/slime_extract/black
+ colour = "black"
+
+/obj/item/slimecross/reproductive/lightpink
+ extract_type = /obj/item/slime_extract/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/reproductive/adamantine
+ extract_type = /obj/item/slime_extract/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/reproductive/rainbow
+ extract_type = /obj/item/slime_extract/rainbow
+ colour = "rainbow"
diff --git a/code/modules/research/xenobiology/crossbreeding/selfsustaining.dm b/code/modules/research/xenobiology/crossbreeding/selfsustaining.dm
new file mode 100644
index 0000000000..7bb723bc3d
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/selfsustaining.dm
@@ -0,0 +1,142 @@
+/*
+Self-sustaining extracts:
+ Produces 4 extracts that do not need reagents.
+*/
+/obj/item/slimecross/selfsustaining
+ name = "self-sustaining extract"
+ effect = "selfsustaining"
+ icon_state = "selfsustaining"
+ var/extract_type = /obj/item/slime_extract
+
+/obj/item/autoslime
+ name = "autoslime"
+ desc = "It resembles a normal slime extract, but seems filled with a strange, multi-colored fluid."
+ var/obj/item/slime_extract/extract
+
+//Just divides into the actual item.
+/obj/item/slimecross/selfsustaining/Initialize()
+ . = ..()
+ visible_message("The [src] shudders, and splits into four smaller extracts.")
+ for(var/i = 0, i < 4, i++)
+ var/obj/item/autoslime/A = new /obj/item/autoslime(src.loc)
+ var/obj/item/slime_extract/X = new extract_type(A)
+ A.extract = X
+ A.icon = icon
+ A.icon_state = icon_state
+ qdel(src)
+
+/obj/item/autoslime/Initialize()
+ name = "self-sustaining " + extract.name
+ ..()
+
+/obj/item/autoslime/attack_self(mob/user)
+ var/reagentselect = input(user, "Choose the reagent the extract will produce.", "Self-sustaining Reaction") as null|anything in extract.activate_reagents
+ var/amount = 5
+ var/secondary
+
+ if ((user.get_active_held_item() != src || user.stat || user.restrained()))
+ return
+ if(!reagentselect)
+ return
+ if(reagentselect == "lesser plasma")
+ amount = 4
+ reagentselect = "plasma"
+ if(reagentselect == "holy water and uranium")
+ reagentselect = "holywater"
+ secondary = "uranium"
+ extract.forceMove(user.drop_location())
+ qdel(src)
+ user.put_in_active_hand(extract)
+ extract.reagents.add_reagent(reagentselect,amount)
+ if(secondary)
+ extract.reagents.add_reagent(secondary,amount)
+
+//Different types.
+
+/obj/item/slimecross/selfsustaining/grey
+ extract_type = /obj/item/slime_extract/grey
+ colour = "grey"
+
+/obj/item/slimecross/selfsustaining/orange
+ extract_type = /obj/item/slime_extract/orange
+ colour = "orange"
+
+/obj/item/slimecross/selfsustaining/purple
+ extract_type = /obj/item/slime_extract/purple
+ colour = "purple"
+
+/obj/item/slimecross/selfsustaining/blue
+ extract_type = /obj/item/slime_extract/blue
+ colour = "blue"
+
+/obj/item/slimecross/selfsustaining/metal
+ extract_type = /obj/item/slime_extract/metal
+ colour = "metal"
+
+/obj/item/slimecross/selfsustaining/yellow
+ extract_type = /obj/item/slime_extract/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/selfsustaining/darkpurple
+ extract_type = /obj/item/slime_extract/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/selfsustaining/darkblue
+ extract_type = /obj/item/slime_extract/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/selfsustaining/silver
+ extract_type = /obj/item/slime_extract/silver
+ colour = "silver"
+
+/obj/item/slimecross/selfsustaining/bluespace
+ extract_type = /obj/item/slime_extract/bluespace
+ colour = "bluespace"
+
+/obj/item/slimecross/selfsustaining/sepia
+ extract_type = /obj/item/slime_extract/sepia
+ colour = "sepia"
+
+/obj/item/slimecross/selfsustaining/cerulean
+ extract_type = /obj/item/slime_extract/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/selfsustaining/pyrite
+ extract_type = /obj/item/slime_extract/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/selfsustaining/red
+ extract_type = /obj/item/slime_extract/red
+ colour = "red"
+
+/obj/item/slimecross/selfsustaining/green
+ extract_type = /obj/item/slime_extract/green
+ colour = "green"
+
+/obj/item/slimecross/selfsustaining/pink
+ extract_type = /obj/item/slime_extract/pink
+ colour = "pink"
+
+/obj/item/slimecross/selfsustaining/gold
+ extract_type = /obj/item/slime_extract/gold
+ colour = "gold"
+
+/obj/item/slimecross/selfsustaining/oil
+ extract_type = /obj/item/slime_extract/oil
+ colour = "oil"
+
+/obj/item/slimecross/selfsustaining/black
+ extract_type = /obj/item/slime_extract/black
+ colour = "black"
+
+/obj/item/slimecross/selfsustaining/lightpink
+ extract_type = /obj/item/slime_extract/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/selfsustaining/adamantine
+ extract_type = /obj/item/slime_extract/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/selfsustaining/rainbow
+ extract_type = /obj/item/slime_extract/rainbow
+ colour = "rainbow"
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/crossbreeding/stabilized.dm b/code/modules/research/xenobiology/crossbreeding/stabilized.dm
new file mode 100644
index 0000000000..aea4f47576
--- /dev/null
+++ b/code/modules/research/xenobiology/crossbreeding/stabilized.dm
@@ -0,0 +1,123 @@
+/*
+Stabilized extracts:
+ Provides a passive buff to the holder.
+*/
+
+//To add: Create an effect in crossbreeding/_status_effects.dm with the name "/datum/status_effect/stabilized/[color]"
+//Status effect will automatically be applied while held, and lost on drop.
+
+/obj/item/slimecross/stabilized
+ name = "stabilized extract"
+ desc = "It seems inert, but anything it touches glows softly..."
+ effect = "stabilized"
+ icon_state = "stabilized"
+ var/datum/status_effect/linked_effect
+ var/mob/living/owner
+
+/obj/item/slimecross/stabilized/Initialize()
+ ..()
+ START_PROCESSING(SSobj,src)
+
+/obj/item/slimecross/stabilized/Destroy()
+ STOP_PROCESSING(SSobj,src)
+ qdel(linked_effect)
+ return ..()
+
+/obj/item/slimecross/stabilized/process()
+ var/humanfound = null
+ if(ishuman(loc))
+ humanfound = loc
+ if(ishuman(loc.loc)) //Check if in backpack.
+ humanfound = (loc.loc)
+ if(!humanfound)
+ return
+ var/mob/living/carbon/human/H = humanfound
+ var/effectpath = /datum/status_effect/stabilized
+ var/static/list/effects = subtypesof(/datum/status_effect/stabilized)
+ for(var/X in effects)
+ var/datum/status_effect/stabilized/S = X
+ if(initial(S.colour) == colour)
+ effectpath = S
+ break
+ if(!H.has_status_effect(effectpath))
+ var/datum/status_effect/stabilized/S = H.apply_status_effect(effectpath)
+ owner = H
+ S.linked_extract = src
+ STOP_PROCESSING(SSobj,src)
+
+//Colors and subtypes:
+/obj/item/slimecross/stabilized/grey
+ colour = "grey"
+
+/obj/item/slimecross/stabilized/orange
+ colour = "orange"
+
+/obj/item/slimecross/stabilized/purple
+ colour = "purple"
+
+/obj/item/slimecross/stabilized/blue
+ colour = "blue"
+
+/obj/item/slimecross/stabilized/metal
+ colour = "metal"
+
+/obj/item/slimecross/stabilized/yellow
+ colour = "yellow"
+
+/obj/item/slimecross/stabilized/darkpurple
+ colour = "dark purple"
+
+/obj/item/slimecross/stabilized/darkblue
+ colour = "dark blue"
+
+/obj/item/slimecross/stabilized/silver
+ colour = "silver"
+
+/obj/item/slimecross/stabilized/bluespace
+ colour = "bluespace"
+
+/obj/item/slimecross/stabilized/sepia
+ colour = "sepia"
+
+/obj/item/slimecross/stabilized/cerulean
+ colour = "cerulean"
+
+/obj/item/slimecross/stabilized/pyrite
+ colour = "pyrite"
+
+/obj/item/slimecross/stabilized/red
+ colour = "red"
+
+/obj/item/slimecross/stabilized/green
+ colour = "green"
+
+/obj/item/slimecross/stabilized/pink
+ colour = "pink"
+
+/obj/item/slimecross/stabilized/gold
+ colour = "gold"
+
+/obj/item/slimecross/stabilized/oil
+ colour = "oil"
+
+/obj/item/slimecross/stabilized/black
+ colour = "black"
+
+/obj/item/slimecross/stabilized/lightpink
+ colour = "light pink"
+
+/obj/item/slimecross/stabilized/adamantine
+ colour = "adamantine"
+
+/obj/item/slimecross/stabilized/rainbow
+ colour = "rainbow"
+ var/obj/item/slimecross/regenerative/regencore
+
+/obj/item/slimecross/stabilized/rainbow/attackby(obj/item/O, mob/user)
+ var/obj/item/slimecross/regenerative/regen = O
+ if(istype(O) && !regencore)
+ to_chat(user, "You place the [O] in the [src], prepping the extract for automatic application!")
+ regencore = regen
+ regen.forceMove(src)
+ return
+ return ..()
\ No newline at end of file
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index cfd32150fa..19f553f2b6 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -87,13 +87,13 @@
return
else if(istype(O, /obj/item/storage/bag) && (upgradetier & XENOBIO_UPGRADE_MONKEYS)) //CIT CHANGE - makes monkey-related actions require XENOBIO_UPGRADE_MONKEYS
var/obj/item/storage/P = O
- var/loaded = 0
+ var/loaded = FALSE
for(var/obj/G in P.contents)
if(istype(G, /obj/item/reagent_containers/food/snacks/monkeycube))
- loaded = 1
+ loaded = TRUE
monkeys++
qdel(G)
- if (loaded)
+ if(loaded)
to_chat(user, "You fill [src] with the monkey cubes stored in [O]. [src] now has [monkeys] monkey cubes stored.")
return
else if(istype(O, /obj/item/slimepotion/slime) && (upgradetier & XENOBIO_UPGRADE_SLIMEADV)) // CIT CHANGE - makes giving slimes potions via console require XENOBIO_UPGRADE_SLIMEADV
diff --git a/code/modules/research/xenobiology/xenobiology.dm b/code/modules/research/xenobiology/xenobiology.dm
index 92517591e5..31c76bd53f 100644
--- a/code/modules/research/xenobiology/xenobiology.dm
+++ b/code/modules/research/xenobiology/xenobiology.dm
@@ -1,4 +1,3 @@
-
/// Slime Extracts ///
/obj/item/slime_extract
@@ -6,7 +5,7 @@
desc = "Goo extracted from a slime. Legends claim these to have \"magical powers\"."
icon = 'icons/mob/slimes.dmi'
icon_state = "grey slime extract"
- force = 1
+ force = 0
w_class = WEIGHT_CLASS_TINY
throwforce = 0
throw_speed = 3
@@ -15,14 +14,26 @@
grind_results = list()
var/Uses = 1 // uses before it goes inert
var/qdel_timer = null // deletion timer, for delayed reactions
+ var/effectmod
+ var/list/activate_reagents = list() //Reagents required for activation
+ var/recurring = FALSE
+
+/obj/item/slime_extract/examine(mob/user)
+ ..()
+ if(Uses > 1)
+ to_chat(user,"It has [Uses] uses remaining.")
/obj/item/slime_extract/attackby(obj/item/O, mob/user)
if(istype(O, /obj/item/slimepotion/enhancer))
- if(Uses >= 5)
+ if(Uses >= 5 || recurring)
to_chat(user, "You cannot enhance this extract further!")
return ..()
- to_chat(user, "You apply the enhancer to the slime extract. It may now be reused one more time.")
- Uses++
+ if(O.type == /obj/item/slimepotion/enhancer) //Seriously, why is this defined here...?
+ to_chat(user, "You apply the enhancer to the slime extract. It may now be reused one more time.")
+ Uses++
+ if(O.type == /obj/item/slimepotion/enhancer/max)
+ to_chat(user, "You dump the maximizer on the slime extract. It can now be used a total of 5 times!")
+ Uses = 5
qdel(O)
..()
@@ -39,9 +50,36 @@
to_chat(user, "Nothing happened... This slime extract cannot be activated this way.")
return 0
+//Core-crossing: Feeding adult slimes extracts to obtain a much more powerful, single extract.
+/obj/item/slime_extract/attack(mob/living/simple_animal/slime/M, mob/user)
+ if(!isslime(M))
+ return ..()
+ if(M.stat)
+ to_chat(user, "The slime is dead!")
+ return
+ if(!M.is_adult)
+ to_chat(user, "The slime must be an adult to cross it's core!")
+ return
+ if(M.effectmod && M.effectmod != effectmod)
+ to_chat(user, "The slime is already being crossed with a different extract!")
+ return
+
+ if(!M.effectmod)
+ M.effectmod = effectmod
+
+ M.applied++
+ qdel(src)
+ to_chat(user, "You feed the slime [src], [M.applied == 1 ? "starting to mutate its core." : "further mutating its core."]")
+ playsound(M, 'sound/effects/attackblob.ogg', 50, 1)
+
+ if(M.applied >= SLIME_EXTRACT_CROSSING_REQUIRED)
+ M.spawn_corecross()
+
/obj/item/slime_extract/grey
name = "grey slime extract"
icon_state = "grey slime extract"
+ effectmod = "reproductive"
+ activate_reagents = list("blood","plasma","water")
/obj/item/slime_extract/grey/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -65,6 +103,8 @@
/obj/item/slime_extract/gold
name = "gold slime extract"
icon_state = "gold slime extract"
+ effectmod = "symbiont"
+ activate_reagents = list("blood","plasma","water")
/obj/item/slime_extract/gold/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -92,6 +132,8 @@
/obj/item/slime_extract/silver
name = "silver slime extract"
icon_state = "silver slime extract"
+ effectmod = "consuming"
+ activate_reagents = list("plasma","water")
/obj/item/slime_extract/silver/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -115,6 +157,8 @@
/obj/item/slime_extract/metal
name = "metal slime extract"
icon_state = "metal slime extract"
+ effectmod = "industrial"
+ activate_reagents = list("plasma","water")
/obj/item/slime_extract/metal/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -137,6 +181,8 @@
/obj/item/slime_extract/purple
name = "purple slime extract"
icon_state = "purple slime extract"
+ effectmod = "regenerative"
+ activate_reagents = list("blood","plasma")
/obj/item/slime_extract/purple/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -154,6 +200,8 @@
/obj/item/slime_extract/darkpurple
name = "dark purple slime extract"
icon_state = "dark purple slime extract"
+ effectmod = "self-sustaining"
+ activate_reagents = list("plasma")
/obj/item/slime_extract/darkpurple/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -175,6 +223,8 @@
/obj/item/slime_extract/orange
name = "orange slime extract"
icon_state = "orange slime extract"
+ effectmod = "burning"
+ activate_reagents = list("blood","plasma","water")
/obj/item/slime_extract/orange/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -193,6 +243,8 @@
/obj/item/slime_extract/yellow
name = "yellow slime extract"
icon_state = "yellow slime extract"
+ effectmod = "charged"
+ activate_reagents = list("blood","plasma","water")
/obj/item/slime_extract/yellow/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -214,6 +266,8 @@
/obj/item/slime_extract/red
name = "red slime extract"
icon_state = "red slime extract"
+ effectmod = "sanguine"
+ activate_reagents = list("blood","plasma","water")
/obj/item/slime_extract/red/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -232,6 +286,8 @@
/obj/item/slime_extract/blue
name = "blue slime extract"
icon_state = "blue slime extract"
+ effectmod = "stabilized"
+ activate_reagents = list("blood","plasma","water")
/obj/item/slime_extract/blue/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -254,6 +310,8 @@
/obj/item/slime_extract/darkblue
name = "dark blue slime extract"
icon_state = "dark blue slime extract"
+ effectmod = "chilling"
+ activate_reagents = list("plasma","water")
/obj/item/slime_extract/darkblue/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -275,6 +333,8 @@
/obj/item/slime_extract/pink
name = "pink slime extract"
icon_state = "pink slime extract"
+ effectmod = "gentle"
+ activate_reagents = list("blood","plasma")
/obj/item/slime_extract/pink/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -301,6 +361,8 @@
/obj/item/slime_extract/green
name = "green slime extract"
icon_state = "green slime extract"
+ effectmod = "mutative"
+ activate_reagents = list("blood","plasma","radium")
/obj/item/slime_extract/green/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -323,6 +385,8 @@
/obj/item/slime_extract/lightpink
name = "light pink slime extract"
icon_state = "light pink slime extract"
+ effectmod = "loyal"
+ activate_reagents = list("plasma")
/obj/item/slime_extract/lightpink/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -345,6 +409,8 @@
/obj/item/slime_extract/black
name = "black slime extract"
icon_state = "black slime extract"
+ effectmod = "transformative"
+ activate_reagents = list("plasma")
/obj/item/slime_extract/black/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -364,6 +430,8 @@
/obj/item/slime_extract/oil
name = "oil slime extract"
icon_state = "oil slime extract"
+ effectmod = "detonating"
+ activate_reagents = list("blood","plasma")
/obj/item/slime_extract/oil/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -385,6 +453,8 @@
/obj/item/slime_extract/adamantine
name = "adamantine slime extract"
icon_state = "adamantine slime extract"
+ effectmod = "crystalline"
+ activate_reagents = list("plasma")
/obj/item/slime_extract/adamantine/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -412,6 +482,8 @@
/obj/item/slime_extract/bluespace
name = "bluespace slime extract"
icon_state = "bluespace slime extract"
+ effectmod = "warping"
+ activate_reagents = list("blood","plasma")
var/teleport_ready = FALSE
var/teleport_x = 0
var/teleport_y = 0
@@ -446,6 +518,8 @@
/obj/item/slime_extract/pyrite
name = "pyrite slime extract"
icon_state = "pyrite slime extract"
+ effectmod = "prismatic"
+ activate_reagents = list("blood","plasma")
/obj/item/slime_extract/pyrite/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -470,6 +544,8 @@
/obj/item/slime_extract/cerulean
name = "cerulean slime extract"
icon_state = "cerulean slime extract"
+ effectmod = "recurring"
+ activate_reagents = list("blood","plasma")
/obj/item/slime_extract/cerulean/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -488,6 +564,8 @@
/obj/item/slime_extract/sepia
name = "sepia slime extract"
icon_state = "sepia slime extract"
+ effectmod = "lengthened"
+ activate_reagents = list("blood","plasma","water")
/obj/item/slime_extract/sepia/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
@@ -508,6 +586,8 @@
/obj/item/slime_extract/rainbow
name = "rainbow slime extract"
icon_state = "rainbow slime extract"
+ effectmod = "hyperchromatic"
+ activate_reagents = list("blood","plasma","lesser plasma","slimejelly","holy water and uranium") //Curse this snowflake reagent list.
/obj/item/slime_extract/rainbow/activate(mob/living/carbon/human/user, datum/species/jelly/luminescent/species, activation_type)
switch(activation_type)
diff --git a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm
index e5c36d09c4..cf45b91dfe 100644
--- a/code/modules/ruins/objects_and_mobs/necropolis_gate.dm
+++ b/code/modules/ruins/objects_and_mobs/necropolis_gate.dm
@@ -84,11 +84,13 @@
else
return QDEL_HINT_LETMELIVE
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/structure/necropolis_gate/attack_hand(mob/user)
if(locked)
to_chat(user, "It's [open ? "stuck open":"locked"].")
return
toggle_the_gate(user)
+ return ..()
/obj/structure/necropolis_gate/proc/toggle_the_gate(mob/user, legion_damaged)
if(changing_openness)
@@ -151,6 +153,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
else
return QDEL_HINT_LETMELIVE
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/structure/necropolis_gate/legion_gate/attack_hand(mob/user)
if(!open && !changing_openness)
var/safety = alert(user, "You think this might be a bad idea...", "Knock on the door?", "Proceed", "Abort")
@@ -159,7 +162,7 @@ GLOBAL_DATUM(necropolis_gate, /obj/structure/necropolis_gate/legion_gate)
user.visible_message("[user] knocks on [src]...", "You tentatively knock on [src]...")
playsound(user.loc, 'sound/effects/shieldbash.ogg', 100, 1)
sleep(50)
- ..()
+ return ..()
/obj/structure/necropolis_gate/legion_gate/toggle_the_gate(mob/user, legion_damaged)
if(open)
diff --git a/code/modules/ruins/objects_and_mobs/sin_ruins.dm b/code/modules/ruins/objects_and_mobs/sin_ruins.dm
index 5bcc58ff87..91a1b20018 100644
--- a/code/modules/ruins/objects_and_mobs/sin_ruins.dm
+++ b/code/modules/ruins/objects_and_mobs/sin_ruins.dm
@@ -9,7 +9,7 @@
density = TRUE
var/win_prob = 5
-/obj/structure/cursed_slot_machine/attack_hand(mob/living/carbon/human/user)
+/obj/structure/cursed_slot_machine/interact(mob/living/carbon/human/user)
if(!istype(user))
return
if(obj_flags & IN_USE)
@@ -58,6 +58,9 @@
qdel(src)
/obj/structure/cursed_money/attack_hand(mob/living/user)
+ . = ..()
+ if(.)
+ return
user.visible_message("[user] opens the bag and \
and removes a die. The bag then vanishes.",
"You open the bag...!\n\
diff --git a/code/modules/shuttle/computer.dm b/code/modules/shuttle/computer.dm
index 4f2d932b1f..ee491f17be 100644
--- a/code/modules/shuttle/computer.dm
+++ b/code/modules/shuttle/computer.dm
@@ -10,11 +10,8 @@
var/admin_controlled
var/no_destination_swap = 0
-/obj/machinery/computer/shuttle/attack_hand(mob/user)
- if(..(user))
- return
- add_fingerprint(usr)
-
+/obj/machinery/computer/shuttle/ui_interact(mob/user)
+ . = ..()
var/list/options = params2list(possible_destinations)
var/obj/docking_port/mobile/M = SSshuttle.getShuttle(shuttleId)
var/dat = "Status: [M ? M.getStatusText() : "*Missing*"]
"
diff --git a/code/modules/shuttle/emergency.dm b/code/modules/shuttle/emergency.dm
index de669df143..249cd57f18 100644
--- a/code/modules/shuttle/emergency.dm
+++ b/code/modules/shuttle/emergency.dm
@@ -528,9 +528,6 @@
else
to_chat(usr, "The storage unit will only unlock during a Red or Delta security alert.")
-/obj/item/storage/pod/attack_hand(mob/user)
- return MouseDrop(user)
-
/obj/docking_port/mobile/emergency/backup
name = "backup shuttle"
id = "backup"
diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm
index ea603039bc..fdf054720f 100644
--- a/code/modules/shuttle/special.dm
+++ b/code/modules/shuttle/special.dm
@@ -11,6 +11,7 @@
icon_state = "wabbajack_statue"
icon_state_on = "wabbajack_statue_on"
active = FALSE
+ allow_switch_interact = FALSE
var/list/active_tables = list()
var/tables_required = 2
@@ -40,10 +41,6 @@
active = FALSE
update_icon()
-
-/obj/machinery/power/emitter/energycannon/magical/attack_hand(mob/user)
- return
-
/obj/machinery/power/emitter/energycannon/magical/attackby(obj/item/W, mob/user, params)
return
diff --git a/code/modules/spells/spell_types/shapeshift.dm b/code/modules/spells/spell_types/shapeshift.dm
index 8a377c6c3a..88c6ce175f 100644
--- a/code/modules/spells/spell_types/shapeshift.dm
+++ b/code/modules/spells/spell_types/shapeshift.dm
@@ -13,6 +13,8 @@
var/revert_on_death = TRUE
var/die_with_shapeshifted_form = TRUE
+ var/convert_damage = FALSE //If you want to convert the caster's health to the shift, and vice versa.
+ var/convert_damage_type = BRUTE //Since simplemobs don't have advanced damagetypes, what to convert damage back into.
var/shapeshift_type
var/list/possible_shapes = list(/mob/living/simple_animal/mouse,\
@@ -41,7 +43,7 @@
if(!shapeshift_type) //If you aren't gonna decide I am!
shapeshift_type = pick(animal_list)
shapeshift_type = animal_list[shapeshift_type]
-
+
var/obj/shapeshift_holder/S = locate() in M
if(S)
Restore(M)
@@ -65,7 +67,7 @@
var/obj/shapeshift_holder/H = locate() in shape
if(!H)
return
-
+
H.restore()
clothes_req = initial(clothes_req)
@@ -99,6 +101,9 @@
stored.mind.transfer_to(shape)
stored.forceMove(src)
stored.notransform = TRUE
+ if(source.convert_damage)
+ var/damapply = (stored.maxHealth - (stored.health + stored.maxHealth)/2) //Carbons go from -100 to 100 naturally, while simplemobs only go from 0 to 100. Can't do a direct conversion.
+ shape.apply_damage(damapply, source.convert_damage_type)
slink = soullink(/datum/soullink/shapeshift, stored , shape)
slink.source = src
@@ -146,6 +151,10 @@
shape.mind.transfer_to(stored)
if(death)
stored.death()
+ else if(source.convert_damage)
+ stored.revive(full_heal = TRUE)
+ var/damapply = (shape.maxHealth - 2*shape.health) //Since we halved incoming damage, double outgoing.
+ stored.apply_damage(damapply, source.convert_damage_type)
qdel(shape)
qdel(src)
diff --git a/code/modules/spells/spell_types/spacetime_distortion.dm b/code/modules/spells/spell_types/spacetime_distortion.dm
index eebff54d6b..c46e931aa7 100644
--- a/code/modules/spells/spell_types/spacetime_distortion.dm
+++ b/code/modules/spells/spell_types/spacetime_distortion.dm
@@ -111,6 +111,7 @@
else
walk_link(user)
+//ATTACK HAND IGNORING PARENT RETURN VALUE
/obj/effect/cross_action/spacetime_dist/attack_hand(mob/user)
walk_link(user)
diff --git a/code/modules/stock_market/computer.dm b/code/modules/stock_market/computer.dm
index a6429834be..0db040bb51 100644
--- a/code/modules/stock_market/computer.dm
+++ b/code/modules/stock_market/computer.dm
@@ -8,6 +8,7 @@
var/vmode = 1
circuit = /obj/item/circuitboard/computer/stockexchange
clockwork = TRUE //it'd look weird
+ interaction_flags_atom = INTERACT_ATOM_REQUIRES_DEXTERITY | INTERACT_ATOM_UI_INTERACT | INTERACT_ATOM_ATTACK_HAND | INTERACT_ATOM_REQUIRES_ANCHORED
light_color = LIGHT_COLOR_GREEN
@@ -20,17 +21,8 @@
return 0
return SSshuttle.points
-/obj/machinery/computer/stockexchange/attack_ai(mob/user)
- return attack_hand(user)
-
-/obj/machinery/computer/stockexchange/attack_robot(mob/user)
- return attack_hand(user)
-
-/obj/machinery/computer/stockexchange/attack_hand(var/mob/user)
- if(..())
- return
- user.machine = src
-
+/obj/machinery/computer/stockexchange/ui_interact(mob/user)
+ . = ..()
var/css={"