diff --git a/code/datums/components/nanites.dm b/code/datums/components/nanites.dm
index 3db861d0f0..50ac5e5cc5 100644
--- a/code/datums/components/nanites.dm
+++ b/code/datums/components/nanites.dm
@@ -214,7 +214,6 @@
/datum/component/nanites/proc/check_viral_prevention()
return SEND_SIGNAL(src, COMSIG_NANITE_INTERNAL_VIRAL_PREVENTION_CHECK)
-//Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
///Syncs the nanite component to another, making it so programs are the same with the same programming (except activation status)
/datum/component/nanites/proc/sync(datum/signal_source, datum/component/nanites/source, full_overwrite = TRUE, copy_activation = FALSE)
var/list/programs_to_remove = programs.Copy() - permanent_programs
@@ -274,10 +273,9 @@
///Modifies the current nanite volume, then checks if the nanites are depleted or exceeding the maximum amount
/datum/component/nanites/proc/adjust_nanites(datum/source, amount)
- nanite_volume = clamp(nanite_volume + amount, 0, max_nanites)
SIGNAL_HANDLER
- nanite_volume += amount
+ nanite_volume = max(nanite_volume + amount, 0) //Lets not have negative nanite counts on permanent ones.
if(nanite_volume > max_nanites)
reject_excess_nanites()
if(nanite_volume <= 0) //oops we ran out
@@ -407,7 +405,6 @@
nanite_volume = clamp(amount, 0, max_nanites)
/datum/component/nanites/proc/set_max_volume(datum/source, amount)
- max_nanites = max(1, max_nanites)
SIGNAL_HANDLER
max_nanites = max(1, amount)
diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm
index 9af78b0090..f21b3acc31 100644
--- a/code/datums/wires/airlock.dm
+++ b/code/datums/wires/airlock.dm
@@ -106,12 +106,7 @@
A.aiControlDisabled = 1
else if(A.aiControlDisabled == -1)
A.aiControlDisabled = 2
- sleep(10)
- if(A)
- if(A.aiControlDisabled == 1)
- A.aiControlDisabled = 0
- else if(A.aiControlDisabled == 2)
- A.aiControlDisabled = -1
+ addtimer(CALLBACK(A, /obj/machinery/door/airlock.proc/reset_ai_wire), 1 SECONDS)
if(WIRE_SHOCK) // Pulse to shock the door for 10 ticks.
if(!A.secondsElectrified)
A.set_electrified(30, usr)
@@ -125,6 +120,12 @@
A.lights = !A.lights
A.update_icon()
+/obj/machinery/door/airlock/proc/reset_ai_wire()
+ if(aiControlDisabled == 1)
+ aiControlDisabled = 0
+ else if(aiControlDisabled == 2)
+ aiControlDisabled = -1
+
/datum/wires/airlock/on_cut(wire, mend)
var/obj/machinery/door/airlock/A = holder
if(usr && !A.hasSiliconAccessInArea(usr) && A.isElectrified() && A.shock(usr, 100))
diff --git a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
index 025306dae4..5fc2a0ab63 100644
--- a/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
+++ b/code/modules/antagonists/clockcult/clock_structures/ark_of_the_clockwork_justicar.dm
@@ -181,9 +181,15 @@
make_glow()
glow.icon_state = "clockwork_gateway_disrupted"
resistance_flags |= INDESTRUCTIBLE
- sleep(27)
- explosion(src, 1, 3, 8, 8)
- sound_to_playing_players('sound/effects/explosion_distant.ogg', volume = 50)
+ addtimer(CALLBACK(src, .proc/go_boom), 2.7 SECONDS)
+ return
+ qdel(src)
+
+/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/go_boom()
+ if(QDELETED(src))
+ return
+ explosion(src, 1, 3, 8, 8)
+ sound_to_playing_players('sound/effects/explosion_distant.ogg', volume = 50)
qdel(src)
/obj/structure/destructible/clockwork/massive/celestial_gateway/proc/make_glow()
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index a0beb07fab..bfa57269a6 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -503,7 +503,7 @@
return ..()
/mob/living/carbon/proc/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1)
- if((HAS_TRAIT(src, TRAIT_NOHUNGER) || HAS_TRAIT(src, TRAIT_TOXINLOVER)) && !force)
+ if(HAS_TRAIT(src, TRAIT_NOHUNGER) && !force)
return TRUE
if(nutrition < 100 && !blood && !force)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 9b9c86f471..ce311039fd 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -841,7 +841,7 @@
..()
/mob/living/carbon/human/vomit(lost_nutrition = 10, blood = FALSE, stun = TRUE, distance = 1, message = TRUE, vomit_type = VOMIT_TOXIC, harm = TRUE, force = FALSE, purge_ratio = 0.1)
- if(blood && dna?.species && (NOBLOOD in dna.species.species_traits) && !HAS_TRAIT(src, TRAIT_TOXINLOVER))
+ if(blood && dna?.species && (NOBLOOD in dna.species.species_traits))
if(message)
visible_message("[src] dry heaves!", \
"You try to throw up, but there's nothing in your stomach!")
diff --git a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
index 177b1c70bc..7151481a4f 100644
--- a/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/alcohol_reagents.dm
@@ -2516,19 +2516,101 @@ All effects don't start immediately, but rather get worse over time; the rate is
color = "#FFFFFF"
boozepwr = 35
quality = DRINK_GOOD
- taste_description = "a delightful softened punch"
- glass_icon_state = "godfather"
- glass_name = "Godfather"
- glass_desc = "A classic from old Italy and enjoyed by gangsters, pray the orange peel doesnt end up in your mouth."
+ taste_description = "bad coding"
+ can_synth = FALSE
+ var/list/names = list("null fruit" = 1) //Names of the fruits used. Associative list where name is key, value is the percentage of that fruit.
+ var/list/tastes = list("bad coding" = 1) //List of tastes. See above.
+ pH = 4
-/datum/reagent/consumable/ethanol/godmother
- name = "Godmother"
- description = "A twist on a classic, liked more by mature women."
- boozepwr = 50
- color = "#E68F00"
- quality = DRINK_GOOD
- taste_description = "sweetness and a zesty twist"
- glass_icon_state = "godmother"
- glass_name = "Godmother"
- glass_desc = "A lovely fresh smelling cocktail, a true Sicilian delight."
+/datum/reagent/consumable/ethanol/fruit_wine/on_new(list/data)
+ names = data["names"]
+ tastes = data["tastes"]
+ boozepwr = data["boozepwr"]
+ color = data["color"]
+ generate_data_info(data)
+/datum/reagent/consumable/ethanol/fruit_wine/on_merge(list/data, amount)
+ var/diff = (amount/volume)
+ if(diff < 1)
+ color = BlendRGB(color, data["color"], diff/2) //The percentage difference over two, so that they take average if equal.
+ else
+ color = BlendRGB(color, data["color"], (1/diff)/2) //Adjust so it's always blending properly.
+ var/oldvolume = volume-amount
+
+ var/list/cachednames = data["names"]
+ for(var/name in names | cachednames)
+ names[name] = ((names[name] * oldvolume) + (cachednames[name] * amount)) / volume
+
+ var/list/cachedtastes = data["tastes"]
+ for(var/taste in tastes | cachedtastes)
+ tastes[taste] = ((tastes[taste] * oldvolume) + (cachedtastes[taste] * amount)) / volume
+
+ boozepwr *= oldvolume
+ var/newzepwr = data["boozepwr"] * amount
+ boozepwr += newzepwr
+ boozepwr /= volume //Blending boozepwr to volume.
+ generate_data_info(data)
+
+/datum/reagent/consumable/ethanol/fruit_wine/proc/generate_data_info(list/data)
+ var/minimum_percent = 0.15 //Percentages measured between 0 and 1.
+ var/list/primary_tastes = list()
+ var/list/secondary_tastes = list()
+ glass_name = "glass of [name]"
+ glass_desc = description
+ for(var/taste in tastes)
+ switch(tastes[taste])
+ if(minimum_percent*2 to INFINITY)
+ primary_tastes += taste
+ if(minimum_percent to minimum_percent*2)
+ secondary_tastes += taste
+
+ var/minimum_name_percent = 0.35
+ name = ""
+ var/list/names_in_order = sortTim(names, /proc/cmp_numeric_dsc, TRUE)
+ var/named = FALSE
+ for(var/fruit_name in names)
+ if(names[fruit_name] >= minimum_name_percent)
+ name += "[fruit_name] "
+ named = TRUE
+ if(named)
+ name += "wine"
+ else
+ name = "mixed [names_in_order[1]] wine"
+
+ var/alcohol_description
+ switch(boozepwr)
+ if(120 to INFINITY)
+ alcohol_description = "suicidally strong"
+ if(90 to 120)
+ alcohol_description = "rather strong"
+ if(70 to 90)
+ alcohol_description = "strong"
+ if(40 to 70)
+ alcohol_description = "rich"
+ if(20 to 40)
+ alcohol_description = "mild"
+ if(0 to 20)
+ alcohol_description = "sweet"
+ else
+ alcohol_description = "watery" //How the hell did you get negative boozepwr?
+
+ var/list/fruits = list()
+ if(names_in_order.len <= 3)
+ fruits = names_in_order
+ else
+ for(var/i in 1 to 3)
+ fruits += names_in_order[i]
+ fruits += "other plants"
+ var/fruit_list = english_list(fruits)
+ description = "A [alcohol_description] wine brewed from [fruit_list]."
+
+ var/flavor = ""
+ if(!primary_tastes.len)
+ primary_tastes = list("[alcohol_description] alcohol")
+ flavor += english_list(primary_tastes)
+ if(secondary_tastes.len)
+ flavor += ", with a hint of "
+ flavor += english_list(secondary_tastes)
+ taste_description = flavor
+ if(holder.my_atom)
+ holder.my_atom.on_reagent_change()
\ No newline at end of file
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 070d5cb269..2301473c48 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -72,7 +72,6 @@
R.stun(20)
R.reveal(100)
R.adjustHealth(50)
- sleep(20)
for(var/mob/living/carbon/C in get_hearers_in_view(round(multiplier/48,1),get_turf(holder.my_atom)))
if(iscultist(C))
to_chat(C, "The divine explosion sears you!")
@@ -433,20 +432,24 @@
var/T1 = multiplier * 20 //100 units : Zap 3 times, with powers 2000/5000/12000. Tesla revolvers have a power of 10000 for comparison.
var/T2 = multiplier * 50
var/T3 = multiplier * 120
- sleep(5)
+ var/added_delay = 0.5 SECONDS
if(multiplier >= 75)
- tesla_zap(holder.my_atom, 7, T1, zap_flags)
- playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
- sleep(15)
+ addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T1), added_delay)
+ added_delay += 1.5 SECONDS
if(multiplier >= 40)
- tesla_zap(holder.my_atom, 7, T2, zap_flags)
- playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
- sleep(15)
+ addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T2), added_delay)
+ added_delay += 1.5 SECONDS
if(multiplier >= 10) //10 units minimum for lightning, 40 units for secondary blast, 75 units for tertiary blast.
- tesla_zap(holder.my_atom, 7, T3, zap_flags)
- playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, 1)
+ addtimer(CALLBACK(src, .proc/zappy_zappy, holder, T3), added_delay)
..()
+
+/datum/chemical_reaction/reagent_explosion/teslium_lightning/proc/zappy_zappy(datum/reagents/holder, power)
+ if(QDELETED(holder.my_atom))
+ return
+ tesla_zap(holder.my_atom, 7, power, zap_flags)
+ playsound(holder.my_atom, 'sound/machines/defib_zap.ogg', 50, TRUE)
+
/datum/chemical_reaction/reagent_explosion/teslium_lightning/heat
id = "teslium_lightning2"
required_temp = 474
diff --git a/code/modules/reagents/chemistry/recipes/slime_extracts.dm b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
index 1e78d81f24..53c2ce2ee3 100644
--- a/code/modules/reagents/chemistry/recipes/slime_extracts.dm
+++ b/code/modules/reagents/chemistry/recipes/slime_extracts.dm
@@ -3,6 +3,9 @@
var/deletes_extract = TRUE
/datum/chemical_reaction/slime/on_reaction(datum/reagents/holder)
+ use_slime_core(holder)
+
+/datum/chemical_reaction/slime/proc/use_slime_core(datum/reagents/holder)
SSblackbox.record_feedback("tally", "slime_cores_used", 1, "type")
if(deletes_extract)
delete_extract(holder)
@@ -570,7 +573,9 @@
required_other = TRUE
/datum/chemical_reaction/slime/slimestop/on_reaction(datum/reagents/holder)
- sleep(50)
+ addtimer(CALLBACK(src, .proc/slime_stop, holder), 5 SECONDS)
+
+/datum/chemical_reaction/slime/slimestop/proc/slime_stop(datum/reagents/holder)
var/obj/item/slime_extract/sepia/extract = holder.my_atom
var/turf/T = get_turf(holder.my_atom)
new /obj/effect/timestop(T, null, null, null)
@@ -579,8 +584,7 @@
var/mob/lastheld = get_mob_by_key(holder.my_atom.fingerprintslast)
if(lastheld && !lastheld.equip_to_slot_if_possible(extract, SLOT_HANDS, disable_warning = TRUE))
extract.forceMove(get_turf(lastheld))
-
- ..()
+ use_slime_core(holder)
/datum/chemical_reaction/slime/slimecamera
name = "Slime Camera"
diff --git a/code/modules/research/nanites/nanite_programs.dm b/code/modules/research/nanites/nanite_programs.dm
index 4b6416ecb8..6a2c8bf4fd 100644
--- a/code/modules/research/nanites/nanite_programs.dm
+++ b/code/modules/research/nanites/nanite_programs.dm
@@ -292,7 +292,7 @@
switch(type)
if(1)
host_mob.investigate_log("[src] nanite program was deleted by software error.", INVESTIGATE_NANITES)
- qdel(src) //kill switch
+ self_destruct() //kill switch
return
if(2) //deprogram codes
if(corruptable)
@@ -306,7 +306,7 @@
toggle() //enable/disable
host_mob.investigate_log("[src] nanite program was toggled by software error.", INVESTIGATE_NANITES)
if(4)
- if(can_trigger)
+ if(error_flicking && can_trigger)
host_mob.investigate_log("[src] nanite program was triggered by software error.", INVESTIGATE_NANITES)
trigger()
if(5) //Program is scrambled and does something different
@@ -315,7 +315,7 @@
var/datum/nanite_program/rogue = new rogue_type
host_mob.investigate_log("[src] nanite program was converted into [rogue.name] by software error.", INVESTIGATE_NANITES)
nanites.add_program(null, rogue, src)
- self_destruct(src)
+ self_destruct()
/datum/nanite_program/proc/receive_signal(code, source)
if(activation_code && code == activation_code && !activated)
diff --git a/code/modules/research/nanites/nanite_programs/weapon.dm b/code/modules/research/nanites/nanite_programs/weapon.dm
index 5c9754ec41..66f6c140f2 100644
--- a/code/modules/research/nanites/nanite_programs/weapon.dm
+++ b/code/modules/research/nanites/nanite_programs/weapon.dm
@@ -87,8 +87,11 @@
addtimer(CALLBACK(src, .proc/boom), clamp((nanites.nanite_volume * 0.35), 25, 150))
/datum/nanite_program/explosive/proc/boom()
- dyn_explosion(get_turf(host_mob), nanites.nanite_volume / 50)
- qdel(nanites)
+ var/nanite_amount = nanites.nanite_volume
+ var/heavy_range = FLOOR(nanite_amount/100, 1) - 1
+ var/light_range = FLOOR(nanite_amount/50, 1) - 1
+ explosion(host_mob, 0, heavy_range, light_range)
+ nanites.delete_nanites()
//TODO make it defuse if triggered again